From d6e35e47b7e45f73cfa4c4191b74ea26529bbc88 Mon Sep 17 00:00:00 2001 From: Zc <67127738@qq.com> Date: Mon, 31 Aug 2026 15:17:27 +0800 Subject: [PATCH] feat(webui): add workspace file tree with preview and chat attach Add a sidebar file tree for browsing the session workspace, a workbench preview panel backed by Monaco, and the ability to attach files or text selections to the conversation composer. - Gateway: new files API (list/read workspace files) registered in the gateway app, with MemoryError guards returning 500 - WebUI: new WorkspaceFiles domain module plus a Gateway Adapter over the private HTTP transport; the sidebar store, preview panel, and chat attach flow consume the seam instead of raw authenticated fetches - Preview: idempotent Monaco editor lifecycle (v-show container), reload keyed by path/workspace/openNonce, right-click context menu for copy / add-to-composer, no flicker during streaming turns - Tabs: file tabs join the 8-tab workbench eviction limit; an overflow dropdown exposes tabs hidden by compression; the collapse button is removed in favor of the dropdown and single-tab row - i18n: full key parity across en, zh-Hans, ja, fr, de, es - Tests: fileTreeModel, fileTree store, WorkspaceFiles adapter, Workbench Host, preview panel, workbench store, and gateway workspace files API --- THIRD_PARTY_NOTICES.md | 39 ++ opensquilla-webui/package-lock.json | 27 + opensquilla-webui/package.json | 1 + opensquilla-webui/src/App.vue | 68 ++- .../adapters/gateway/gatewayAdapters.test.ts | 1 + .../src/adapters/gateway/gatewayAdapters.ts | 4 + .../adapters/gateway/workspaceFiles.test.ts | 113 ++++ .../src/adapters/gateway/workspaceFiles.ts | 151 +++++ .../src/components/SidebarConversations.vue | 21 + .../src/components/SidebarFileTree.vue | 441 ++++++++++++++ .../src/components/workbench/AppWorkbench.vue | 3 + .../workbench/WorkbenchHost.test.ts | 39 +- .../components/workbench/WorkbenchHost.vue | 216 ++++++- .../WorkspaceFilePreviewPanel.test.ts | 306 ++++++++++ .../workbench/WorkspaceFilePreviewPanel.vue | 541 ++++++++++++++++++ .../workspaceFileWorkbenchProvider.ts | 41 ++ .../src/lib/fileTreeModel.test.ts | 82 +++ opensquilla-webui/src/lib/fileTreeModel.ts | 123 ++++ opensquilla-webui/src/locales/de.json | 453 +++++++++++---- opensquilla-webui/src/locales/en.json | 299 +++++++--- opensquilla-webui/src/locales/es.json | 453 +++++++++++---- opensquilla-webui/src/locales/fr.json | 453 +++++++++++---- opensquilla-webui/src/locales/ja.json | 453 +++++++++++---- opensquilla-webui/src/locales/zh-Hans.json | 299 +++++++--- opensquilla-webui/src/main.ts | 2 + .../src/modules/workspaceFiles.ts | 66 +++ opensquilla-webui/src/stores/fileTree.test.ts | 198 +++++++ opensquilla-webui/src/stores/fileTree.ts | 255 +++++++++ opensquilla-webui/src/views/ChatView.vue | 56 ++ opensquilla-webui/src/workbench/store.test.ts | 33 ++ opensquilla-webui/src/workbench/store.ts | 21 +- .../src/workbench/workspaceFileAttachEvent.ts | 23 + .../src/workbench/workspaceFileItems.ts | 56 ++ src/opensquilla/gateway/app.py | 9 + src/opensquilla/gateway/files_api.py | 438 ++++++++++++++ .../test_gateway/test_workspace_files_api.py | 365 ++++++++++++ 36 files changed, 5566 insertions(+), 583 deletions(-) create mode 100644 opensquilla-webui/src/adapters/gateway/workspaceFiles.test.ts create mode 100644 opensquilla-webui/src/adapters/gateway/workspaceFiles.ts create mode 100644 opensquilla-webui/src/components/SidebarFileTree.vue create mode 100644 opensquilla-webui/src/components/workbench/WorkspaceFilePreviewPanel.test.ts create mode 100644 opensquilla-webui/src/components/workbench/WorkspaceFilePreviewPanel.vue create mode 100644 opensquilla-webui/src/components/workbench/workspaceFileWorkbenchProvider.ts create mode 100644 opensquilla-webui/src/lib/fileTreeModel.test.ts create mode 100644 opensquilla-webui/src/lib/fileTreeModel.ts create mode 100644 opensquilla-webui/src/modules/workspaceFiles.ts create mode 100644 opensquilla-webui/src/stores/fileTree.test.ts create mode 100644 opensquilla-webui/src/stores/fileTree.ts create mode 100644 opensquilla-webui/src/workbench/workspaceFileAttachEvent.ts create mode 100644 opensquilla-webui/src/workbench/workspaceFileItems.ts create mode 100644 src/opensquilla/gateway/files_api.py create mode 100644 tests/test_gateway/test_workspace_files_api.py diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 9c85c53f1e..ab719f961a 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -3,6 +3,10 @@ This file records third-party attribution for assets bundled with OpenSquilla. It covers: +- The workspace file-tree features in `opensquilla-webui/` (file tree model, + lazy per-directory loading store, and virtualized row layout), which are + adapted from anomalyco/opencode (MIT) — see the section below. + - The bundled skill descriptors under `src/opensquilla/skills/bundled/`, which include OpenClaw-derived MIT descriptors and OpenSquilla-original descriptors. - The bundled pptx skill references the python-pptx and PptxGenJS libraries; @@ -648,3 +652,38 @@ The SquillaRouter bundle contains `.pkl` and `.joblib` artifacts used by the current V4 Phase 3 runtime. Treat these artifacts as executable-code-equivalent inputs: load only assets shipped with a trusted OpenSquilla release or assets whose checksums match `artifact_manifest.json`. + +## Workspace File Tree (adapted from anomalyco/opencode) + +The Web UI's workspace file-tree model, virtualized row layout, and lazy +per-directory loading store are adapted (re-implemented for Vue 3 / Pinia and +OpenSquilla types) from [anomalyco/opencode](https://github.com/anomalyco/opencode), +MIT License, Copyright (c) 2025 opencode: + +- `opensquilla-webui/src/lib/fileTreeModel.ts` ← `packages/app/src/components/file-tree-v2-model.ts` +- `opensquilla-webui/src/stores/fileTree.ts` ← `packages/app/src/context/file/tree-store.ts` +- `opensquilla-webui/src/components/SidebarFileTree.vue` ← `packages/app/src/components/file-tree-v2.tsx` (render approach) + +Full MIT license text: + + MIT License + + Copyright (c) 2025 opencode + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. diff --git a/opensquilla-webui/package-lock.json b/opensquilla-webui/package-lock.json index 379b122545..9c9aac6066 100644 --- a/opensquilla-webui/package-lock.json +++ b/opensquilla-webui/package-lock.json @@ -8,6 +8,7 @@ "name": "opensquilla-webui", "version": "0.2.1", "dependencies": { + "@tanstack/vue-virtual": "^3.13.36", "@types/dompurify": "^3.0.5", "dompurify": "^3.4.12", "highlight.js": "^11.11.1", @@ -503,6 +504,32 @@ "dev": true, "license": "MIT" }, + "node_modules/@tanstack/virtual-core": { + "version": "3.17.8", + "resolved": "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.17.8.tgz", + "integrity": "sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/vue-virtual": { + "version": "3.13.36", + "resolved": "https://registry.npmmirror.com/@tanstack/vue-virtual/-/vue-virtual-3.13.36.tgz", + "integrity": "sha512-gKpExv4RbB9luVG+SucTXoqPZv/gzu/Yvz6BNO+8kpNxJ2x+I/ulryzl5W9BRciahZGp5Tls3Dp5XP1ztVGbMw==", + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.17.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vue": "^2.7.0 || ^3.0.0" + } + }, "node_modules/@tybys/wasm-util": { "version": "0.10.2", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", diff --git a/opensquilla-webui/package.json b/opensquilla-webui/package.json index bed6b98aaf..4ed32a85b7 100644 --- a/opensquilla-webui/package.json +++ b/opensquilla-webui/package.json @@ -24,6 +24,7 @@ "node": ">=22.12.0" }, "dependencies": { + "@tanstack/vue-virtual": "^3.13.36", "@types/dompurify": "^3.0.5", "dompurify": "^3.4.12", "highlight.js": "^11.11.1", diff --git a/opensquilla-webui/src/App.vue b/opensquilla-webui/src/App.vue index 35f05c7b86..a11389af0c 100644 --- a/opensquilla-webui/src/App.vue +++ b/opensquilla-webui/src/App.vue @@ -77,8 +77,10 @@ - + + + + +
{{ store.activeItem?.title }} +
+
+ + +