dsh-linked-workspace 0.0.0-stage → 0.5.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,143 @@
1
+ # Changelog
2
+
3
+ ## 0.5.12 — 2026-11-04
4
+
5
+ - Published as **dsh-linked-workspace** on npm (public).
6
+ - Added the `v*` tag release workflow: it verifies the tag against `package.json`, skips an already-published version, and otherwise publishes to npm with provenance.
7
+ - Added repository metadata, `dsh-plugin` topic, and marketplace submission files.
8
+
9
+ ## 0.5.11 — 2026-11-04
10
+
11
+ - Documentation: added an **English README** (`README.en.md`) with language links; refreshed stale Chinese README details (read-only remote directories, bidirectional transfer, local-workspace form, lazy `.local`).
12
+
13
+ - **Fixed remote directory file viewing**: read-only tabs now render the file content (gutter, syntax colors, status bar with 只读 chip) instead of only showing a “只读” message. Binary/oversized files still show the read-only notice.
14
+ - **Fixed Settings → 连接 open actions**: “打开工作区” now navigates to the linked workspace and closes settings; remote directory “打开” now opens the remote-directory tab (was opening the linked tab type) and closes settings. Tab metadata pins the requested linked workspace / remote directory.
15
+ - Save keys remain disabled in read-only views.
16
+
17
+ ## 0.5.10 — 2026-11-04
18
+
19
+ - The add-workspace **本地工作区** tab now behaves like the linked tab: the local directory is an input plus a **浏览…** button, and the directory picker opens only after clicking browse (picking a folder collapses it again).
20
+ - Removed the **打开右侧栏** button from Settings → 连接.
21
+
22
+ ## 0.5.9 — 2026-11-04
23
+
24
+ - Ctrl+O / add-workspace linked flow: the inner card no longer renders its own 取消/添加联动工作区 buttons; the modal footer now shows **取消 + 创建**.
25
+ - Settings: the linked action is now **创建联动工作区**; its form title is **创建联动工作区** and the submit button is **创建**.
26
+ - Settings: adding a remote directory now submits with the **添加** button.
27
+
28
+ ## 0.5.8 — 2026-11-04
29
+
30
+ - Add-form titles now match the action: **添加联动工作区** / **添加远程目录** instead of the generic 添加工作区.
31
+ - The Ctrl+O / add-workspace flow's first tab is renamed **本地工作区**; it now has a real form with **1. 本地目录** and **2. 工作区名称** (directory picker no longer closes the flow on pick; the footer creates the workspace).
32
+ - New host API `localWorkspace.create` registers a plain local DSH workspace by path + optional name.
33
+ - Tests: host API suite now 24 steps (localWorkspace.create).
34
+
35
+ ## 0.5.7 — 2026-11-04
36
+
37
+ - Adding a **linked workspace** now locks the form to linked mode: no “远程目录 / 联动工作区” switch inside the add card (both settings and the Ctrl+O directory flow).
38
+ - Adding a **remote directory** locks the form to remote mode: no linked switch and **no workspace-name field**; the workspace name is derived from the path.
39
+ - Existing name field remains for linked workspaces, where it titles the DSH workspace.
40
+
41
+ ## 0.5.6 — 2026-11-04
42
+
43
+ - Wording: the direct-remote section now reads **直接浏览远端目录(只读)**.
44
+ - **Bidirectional transfer**: the linked-workspace transfer button/context menu works for both sides. Remote → local copies only into the local `.remote` directory; local → remote preserves the path relative to the linked local root. The queue records the direction.
45
+ - **No eager `.local`**: creating or updating a linked workspace no longer creates `.local` (or `.remote`); plugin metadata is created lazily only when mirror sync needs it.
46
+ - **Local path picker supports all drives**: `local.browse` returns Windows drive roots and the browser shows C:/D:/E: chips; this also fixes adding normal local workspaces and linked local folders on non-C drives.
47
+ - **Remote breadcrumb**: no more doubled leading slash (//home → /home).
48
+ - Tests: host API suite still 23 steps (drive roots, local→remote transfer, no eager `.local`).
49
+
50
+ ## 0.5.5 — 2026-11-04
51
+
52
+ - The right-sidebar start page now offers **联动工作区目录 only for sessions of a linked workspace**, and the opened panel is bound to that session's own linked workspace (never another one). Non-linked sessions no longer register the linked tab at all (dynamic registration via `session.info`).
53
+ - **远程目录** is a separate tab type, offered in every session as soon as at least one remote directory is configured; it is **read-only** — tree browsing, file viewing, download/copy path/properties, no editing, no transfer/rename/delete/new actions. Only linked-workspace tabs are editable.
54
+ - The empty remote-directory wording is now **还没有远程目录**.
55
+ - Host API `session.info` (sessionId → cwd/running) added for the dynamic tab availability.
56
+ - Tests: host API suite still 23 steps (now also checks `session.info`).
57
+
58
+ ## 0.5.4 — 2026-11-04
59
+
60
+ - Hidden files are **shown by default** when the linked-workspace directory opens (including `.local`/`.remote`), and the directory panel is open by default; the eye button still hides them.
61
+ - Internal file tabs no longer show a file-type icon for either remote or local files (only the file name).
62
+ - The internal editor header (path, reload/save buttons) is removed; saving stays on Ctrl/Cmd+S. Unsaved changes now show as a small gray dot in front of the file name in the tab strip.
63
+
64
+ ## 0.5.3 — 2026-11-04
65
+
66
+ - **Theme families (9 cards)**: GitHub, Solarized, One, Dracula, Monokai, Nord, VS Code, Xcode and Catppuccin each keep both a light and a dark variant on one card; the preview follows the selected mode (System follows the DSH light/dark scheme). The three mode cards no longer carry preview strips.
67
+ - **Workspace layout**: the linked-workspace directory is now a fixed **right-side panel** (never its own tab) with a toolbar button to show/hide it. Between the conversation and that panel sits the **file content panel** with its own internal tabs; with nothing open it shows the “打开文件 / 从工作区目录树中选择文件” placeholder.
68
+ - **Local files are editable in the content panel** via new `local.read`/`local.write` host APIs; local file tabs show no icon and no longer depend on the native editor.
69
+ - Clicking a tree row still only selects; double-click expands a folder or opens a file in the internal content panel while the directory panel stays visible.
70
+ - Tests: host API suite now 23 steps (local read/write + theme-family settings).
71
+
72
+ ## 0.5.2 — 2026-11-04
73
+
74
+ - **Local tree hidden toggle**: `.local`/`.remote` are no longer filtered unconditionally; the show/hide-hidden-files button now governs both the remote and the local tree (showing the linkage directories when enabled).
75
+ - **Single click selects, double click opens**: tree rows select on one click; double-click expands folders or opens files. Files open as a background tab (via `reveal: false` + re-activating the directory tab), so the panel keeps showing the linked-workspace directories until the new tab is clicked.
76
+ - **Theme distinction**: the three mode cards now carry light/dark preview strips (system is split), and every specific theme shows a 浅色/深色 badge; light themes render with their true light palette (verified GitHub Light / Xcode Light).
77
+ - **Settings buttons swapped**: 添加联动工作区 now precedes 添加远程目录.
78
+ - Toolbar transfer-file and show-hidden-files buttons remain as in 0.5.1.
79
+
80
+ ## 0.5.1 — 2026-11-04
81
+
82
+ - **Editor theme modes**: 系统 / 浅色 / 深色, default **系统**. System follows the current DSH light/dark theme; Light/Dark force the matching palette; the specific-theme grid is still available and picking one switches to its mode.
83
+ - **Running workspace icon**: linked-workspace rows whose local directory currently owns a running Session turn **blue** (host reads running Session cwds via the session controller; the client refreshes the icon styles every 5 s).
84
+ - **Local skills bridge**: linked sessions run in the local directory, so locally installed skills (user + project) stay available. New tool `linked_skills` (list/read) and host APIs `skills.list` / `skills.read` expose them; the prompt section explicitly says not to install skills into the remote project. The earlier transfer-file/hidden-file toolbar buttons remain.
85
+ - Host API `linked.list` now returns `running` per link; `settings` carries `editorThemeMode`.
86
+ - Tests: host API suite 22 steps (local skill discovery/read + running flag included).
87
+
88
+ ## 0.5.0 — 2026-11-04
89
+
90
+ - **GitHub Light is the default editor theme.** Settings written by older versions that still carry the old implicit dark default are migrated once; an explicitly chosen theme is kept.
91
+ - **Mirror sync is opt-in and defaults off.** Existing records created under the old default are switched off once; when enabled, the first check starts immediately and a background consistency check then runs every five minutes (downloads changed/missing files, removes mirror files whose remote counterpart disappeared, skips unchanged files via the manifest, per-file timeout, cancel on demand).
92
+ - **Context menu in the directory panel** (right-click a file, folder or root row): transfer the selection to `.remote`, download to the OS Downloads folder, transfer queue, open, edit in Notepad, copy/paste, copy path, rename, delete, change permissions, new folder/file, properties. The transfer queue runs one SFTP transfer at a time with live state.
93
+ - **Toolbar additions**: a transfer button for the selected remote file/folder, a show/hide-hidden-files toggle, plus the existing tree modes, search, open-with menu and refresh.
94
+ - **Several remote files can be open in separate tabs at once** (12 hidden page kinds act as file slots; reopening the same file focuses its tab, closing it frees the slot).
95
+ - The settings page title is now **连接与联动工作区** / Connections & Linked Workspaces.
96
+ - New host APIs: `fs.transfer`, `fs.download`, `fs.edit`, `fs.copy`, `fs.chmod`, recursive `fs.delete`, `local.stat/rename/delete/copy/newFile/chmod/edit`.
97
+ - Tests: host API suite now 21 steps (transfer/download/copy/chmod/recursive delete included).
98
+
99
+ ## 0.4.0 — 2026-11-03
100
+
101
+ - Sidebar tab renamed **联动工作区目录**: for a linked workspace the panel shows the remote tree on top and the local tree below (root row "所有文件"); clicking a file opens a new tab, the directory panel stays in place.
102
+ - Toolbar: **切换文件树** (所有文件 / 已更改的文件 / 所有更改 via git status on both sides), **在文件中搜索** (remote `find` + local walk, debounced), **打开选项菜单** (editor / system default app / copy path) and refresh. The chosen open mode is persisted in settings.
103
+ - Linked workspace rows now show a real link icon instead of the "⇄" title prefix: the host strips the old prefix from existing workspaces and the client replaces the folder glyph via a scoped stylesheet (documented safe degradation).
104
+ - **Sync no longer times out**: `linked.sync` now starts a background job with progress polling (`linked.syncStatus` / `linked.syncCancel`), skips unchanged files via a mirror manifest, excludes VCS/dependency directories, stops at the caps and uses a per-file timeout. The settings card shows live progress and a cancel action.
105
+ - Host additions: `RemoteHost.exec`, `git.status`, `fs.search`, `local.list`, `fs.openExternal`, `local.openExternal`, plus `fileOpenMode` in settings.
106
+ - Tests: 10 new git/search tests (local temp repos + read-only remote checks); host API suite now 20 steps.
107
+
108
+ ## 0.3.0 — 2026-11-03
109
+
110
+ - Renamed the plugin from `dsh-remote-workspace` to **`dsh-linked-workspace`** (bundle row id `linked-workspace-ui`, HTTP route `/dsh-linked-workspace/api`, client module id `dsh-linked-workspace`).
111
+ - Data directory renamed from `$DSH_HOME/remote-workspace` to `$DSH_HOME/linked-workspace`; the first start after the upgrade migrates the old directory (rename, copy fallback) so existing remote directories, linked workspaces, settings and trusted host keys survive.
112
+ - Environment knob renamed to `DSH_LINKED_WORKSPACE_HOME` (the old `DSH_REMOTE_WORKSPACE_HOME` still works).
113
+ - Settings section id is now `linked-workspaces` (nav label unchanged: 连接 / Connections).
114
+ - Tabs persisted before the rename keep the old type ids; hidden legacy aliases (`dsh-remote-workspace`, `dsh-remote-workspace:file`) restore them after a page reload instead of showing an empty view.
115
+
116
+ ## 0.2.0 — 2026-11-03
117
+
118
+ - **Linked workspaces** (local ⇄ remote): the sidebar/hero "add workspace" hole now offers a local folder or a linked workspace. Creating one writes `.local/linked.json` + `.local/session/`, optionally `.remote/`, registers a real DSH workspace titled `⇄ <name>`, and exposes the `linked_workspace` agent tool (list/info/list_dir/read/write/replace/stat/mkdir/rename/delete/sync) plus a system-prompt section so sessions edit remote files directly.
119
+ - **Editor themes**: 10 built-in themes (GitHub Dark/Light, One Dark, Dracula, Monokai, Nord, Solarized Dark/Light, VS Code Dark+, Xcode Light) selectable in Settings → Connections; the remote editor background/text/gutter/selection/token colors follow the choice.
120
+ - **Syntax highlighting**: a dependency-free tokenizer powers an overlay highlighter in the remote editor (strings, comments, keywords, numbers, functions…), with a plain-text fallback for very large files.
121
+ - **Split workbench**: the sidebar tab is now a split view — remote directory tree on the left, editor on the right; files open in place, with "open in tab" as an escape hatch. Tab renamed to 远程目录 / Remote Directory.
122
+ - **File-type icons**: colored glyph icons per extension and well-known file names, plus a distinct link icon for linked workspaces (sidebar group, cards, tree).
123
+ - **Settings → Connections** reorganized into editor theme / linked workspaces / remote directories, with mirror toggle + sync, safe removal options, and local directory browsing (system picker included).
124
+ - Host: `settings.get/update`, `local.browse/mkdir`, `linked.create/list/update/remove/sync`; every `fs.*` method now accepts `linkedId` as well as `workspaceId`; reads/writes of linked workspaces mirror into `.remote` and every write is atomic.
125
+ - Build: `src/client.js` + `src/parts/{themes,highlight,file-icons}.js` are inlined by `scripts/build-client.mjs` into `lib/client.js`.
126
+
127
+ ## 0.1.0 — 2026-11-03
128
+
129
+ First release.
130
+
131
+ - Settings → **连接** page: list, test, open and remove remote workspaces; an
132
+ `添加工作区` flow that picks an existing SSH connection and a remote
133
+ directory (with a remote directory browser).
134
+ - Sidebar (dsh-better-sidebar) pages: a lazy remote file tree per workspace and
135
+ an editor tab with line numbers, dirty marker, `Ctrl/Cmd+S`, conflict
136
+ detection, binary/large-file read-only protection and a UTF-8/LF/CRLF status
137
+ bar.
138
+ - Host: JSON API on the DSH web server, persisted workspace registry, one SSH
139
+ connection per host, SFTP reads/writes with atomic replace, path containment,
140
+ 8 MB save cap, trust-on-first-use host-key pinning.
141
+ - Host discovery reuses the `dsh-ssh-tunnel` SSH Manager store and
142
+ `~/.ssh/config`; credentials never cross the client boundary.
143
+ - zh/en UI following the DSH locale; DSH theme tokens only.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Huangjh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.en.md ADDED
@@ -0,0 +1,145 @@
1
+ # dsh-linked-workspace
2
+
3
+ English · [简体中文](README.md)
4
+
5
+ Turn existing SSH connections into **remote directories** or **linked workspaces** in DeepSeek Harness:
6
+
7
+ - **Remote directory**: Settings → Connections → Add remote directory. Pick a host and a remote folder, then browse and read its files from the right sidebar. Remote-directory views are **read-only**.
8
+ - **Linked workspace**: Add a workspace (or Settings → Connections → Create linked workspace) to pair a **local folder** with a **remote folder**. The local folder becomes a real DSH workspace; sessions in it read and edit remote files through the `linked_workspace` tool. The remote host only needs SSH, not a DSH plugin. The right sidebar shows both trees: remote on top, local below.
9
+
10
+ > Built for DSH 0.2.1-rc.4. Sidebar pages require `dsh-better-sidebar` (v0.24+). Without it the plugin still loads (Settings works), but sidebar entries are unavailable.
11
+
12
+ ## Features
13
+
14
+ ### Connections and settings (Settings → Connections)
15
+
16
+ - SSH hosts come from the `dsh-ssh-tunnel` SSH Manager (`~/.dsh/ssh-tunnel/hosts.json`) and from `~/.ssh/config`. Passwords and private keys stay inside the Host process and are never returned to the page or the model.
17
+ - Remote-directory list: add (host + remote folder browser), test, open, remove.
18
+ - Linked-workspace list: local ⇄ remote paths, mirror switch (**off by default**), background sync (archive into `.remote`, show file count/size progress, cancellable), remove (optionally remove the DSH workspace and delete `.local`/`.remote`). With mirroring enabled, the first check runs immediately, then **every 5 minutes**: download new/changed files, remove mirror files that no longer exist remotely, skip unchanged files (`.local/mirror-manifest.json`), and exclude `.git`/`node_modules`/cache folders. With mirroring off, both sides may differ freely.
19
+ - **Editor themes**: appearance modes **System / Light / Dark** (default System, following DSH); nine theme families (GitHub, Solarized, One, Dracula, Monokai, Nord, VS Code, Xcode, Catppuccin), each with light and dark variants on one card. The preview follows the selected mode.
20
+ - Remote-directory and linked-workspace creation share one form.
21
+ - File-open behavior (editor / system default app / copy path) is selected from the sidebar toolbar and persisted.
22
+ - The Settings → Connections page has **Create linked workspace** and **Add remote directory** actions; the old “Open sidebar” button is gone.
23
+
24
+ ### Add workspace
25
+
26
+ The plugin takes over the directory-selection hole used by the DSH sidebar and empty-session hero. The dialog has two tabs:
27
+
28
+ 1. **Local workspace**: enter or browse for a local directory (C:/D:/E: drive chips on Windows), set a workspace name, then create a normal DSH workspace.
29
+ 2. **Linked workspace**: SSH host + remote folder + local folder + optional mirror. Creating it also registers the local folder as a DSH workspace. The local directory is **not** pre-populated with `.local`/`.remote`; those are created lazily when mirroring or transfers need them.
30
+
31
+ ### Right-sidebar entries
32
+
33
+ - **Linked workspace directory**: appears only in sessions of a linked workspace, and opens the linked workspace bound to that session. Remote and local files are editable.
34
+ - **Remote directories**: available in any workspace session once at least one remote directory is configured. Browsing and files are **read-only**; editing, transfers, rename/delete and other mutations are disabled.
35
+ - Both entries are opened from the right-sidebar start page. Non-linked sessions do not show the linked-workspace entry.
36
+
37
+ ### Right-sidebar linked-workspace directory
38
+
39
+ - The directory is a fixed panel at the far right of the sidebar: **remote tree on top, local tree below**, both rooted at “All files”. Plugin internals (`.local`/`.remote`) are hidden by default but can be shown with the hidden-files toggle.
40
+ - **Single click selects, double click opens**: a single click highlights a row; double-clicking a folder expands/collapses it; double-clicking a file opens it in the content panel while the directory panel stays visible.
41
+ - **Layout**: conversation → content panel (internal file tabs) → directory panel. The content panel shows “Open a file / Select a file from the workspace directory tree” when nothing is open. A toolbar button shows/hides the directory panel.
42
+ - Toolbar:
43
+ - **Tree switch**: all files / changed files / all changes (git status from remote and local sides).
44
+ - **Search in files**: at least two characters; remote uses `find`, local walks the tree. Results are grouped by remote/local.
45
+ - **Open options menu**: editor / system default app / copy path.
46
+ - **Transfer**: bidirectional. Select a remote file/folder to copy it into the local `.remote/` folder; select a local file/folder to copy it to the corresponding relative remote path. Jobs run one at a time through a queue.
47
+ - **Show/hide hidden files**: applies to both trees.
48
+ - **Refresh**: reload roots, git status and search.
49
+ - File-type icons for JS/TS/Python/JSON/Markdown/Shell/YAML/images/archives/config files, etc.
50
+ - Editor: line numbers, syntax highlighting (layered rendering), theme colors, `Ctrl/Cmd+S` save, conflict prompt (reload/force save), read-only protection for binary and >2 MB files, UTF-8/LF/CRLF/line-count status bar. The embedded content panel hides the path/save header; unsaved changes show a gray dot in the file tab. Read-only tabs render the file content but cannot be edited or saved.
51
+ - Multiple files can be open at once (up to 12 slots). Local files use the same internal editor and can be edited and saved.
52
+
53
+ ### Running indicator and local skills
54
+
55
+ - When a linked workspace has a running session, its link icon turns **blue** in the left workspace list (polled about every 5 seconds).
56
+ - Linked sessions run in the **local directory**, so local skills (`~/.dsh/skills`, `~/.agents/skills`, `<local>/.dsh/skills`, `<local>/.agents/skills`) are available without installing them on the remote host. The model can use `linked_skills` to `list`/`read` them, and the system prompt explains this.
57
+
58
+ ### Context menu (files, folders, roots)
59
+
60
+ Transfer (download to `.remote` / upload to remote), download to the default folder, queue, open, edit with Notepad, copy, paste, copy path, rename, delete, change permissions, new folder/file, properties. Remote operations use SFTP; local operations use the local filesystem. The transfer queue runs one job at a time.
61
+
62
+ ### Linked-workspace layout
63
+
64
+ ```
65
+ <local>/
66
+ .local/ # created lazily (mirror manifest when needed)
67
+ mirror-manifest.json
68
+ .remote/ # optional: remote mirror archive
69
+ ```
70
+
71
+ The remote side is not modified by mirroring. The `linked_workspace` tool supports `list`, `info`, `list_dir`, `read`, `write`, `replace`, `stat`, `mkdir`, `rename`, `delete`, and `sync` (start a background mirror job). `path` is relative to the remote root (or an absolute path inside it). Writes are atomic and support `if_modified_since` optimistic concurrency. The workspace is resolved from the session cwd; use the `workspace` parameter to target another linked workspace.
72
+
73
+ ## Screenshots
74
+
75
+ [![Settings → Connections](https://github.com/jiahui-huang1/dsh-linked-workspace/raw/main/docs/screenshots/settings-connections.png)](https://github.com/jiahui-huang1/dsh-linked-workspace/blob/main/docs/screenshots/settings-connections.png)
76
+
77
+ [![Linked workspace directory: remote on top, local below](https://github.com/jiahui-huang1/dsh-linked-workspace/raw/main/docs/screenshots/linked-directories.png)](https://github.com/jiahui-huang1/dsh-linked-workspace/blob/main/docs/screenshots/linked-directories.png)
78
+
79
+ [![Open a file in the content panel](https://github.com/jiahui-huang1/dsh-linked-workspace/raw/main/docs/screenshots/file-editor.png)](https://github.com/jiahui-huang1/dsh-linked-workspace/blob/main/docs/screenshots/file-editor.png)
80
+
81
+ [![Read-only remote file with content visible](https://github.com/jiahui-huang1/dsh-linked-workspace/raw/main/docs/screenshots/remote-readonly-view.png)](https://github.com/jiahui-huang1/dsh-linked-workspace/blob/main/docs/screenshots/remote-readonly-view.png)
82
+
83
+ ## Installation
84
+
85
+ ```
86
+ dsh plugin --profile "$DSH_PROFILE" add "file:$PWD/dsh-linked-workspace"
87
+ ```
88
+
89
+ Or use `plugin_manager` → `install_bundle` with the absolute path of this directory. Restart the DSH desktop app after installing (new Host plugins load at process start; session history is preserved). Then:
90
+
91
+ 1. Account menu → Settings → **Connections**;
92
+ 2. Or use the workspace “Add workspace” button and choose the linked-workspace tab.
93
+
94
+ ## Upgrading from 0.2.x
95
+
96
+ Since 0.3.0 the plugin is named `dsh-linked-workspace`. On first start after installing the new package, the old `$DSH_HOME/remote-workspace` data directory is migrated to `$DSH_HOME/linked-workspace` (remote directories, linked workspaces, theme settings and known host fingerprints are preserved). The old `dsh-remote-workspace` package can then be uninstalled.
97
+
98
+ Old “Remote directories” tabs are restored after refresh through hidden legacy tab-type aliases; their titles are updated to “Linked workspace directory”, while new tabs use the new type.
99
+
100
+ See [CHANGELOG.md](CHANGELOG.md) for the full version history.
101
+
102
+ ## Releases and marketplace updates
103
+
104
+ - The npm package is `dsh-linked-workspace`. To release, bump `package.json` and push a `v*` tag; `.github/workflows/release.yml` runs `npm publish --access public` (set an `NPM_TOKEN` repository secret).
105
+ - awesome-dsh-plugin (the DSH community market) reads the npm latest version and repository metadata, so published upgrades appear automatically without resubmitting the entry. A ready-to-submit entry is kept at `market/awesome-dsh-plugin-entry.yml`.
106
+ - dsh-plugin.org (DSH Plugin Hub) periodically scans public repositories with the `dsh-plugin` topic and their npm packages; new versions refresh automatically after publication.
107
+ - Before releasing, check the package with `npm run build && npm pack --dry-run`.
108
+
109
+ ## Security
110
+
111
+ - Credentials live only in the Host process; the API returns only host names, addresses and workspace paths.
112
+ - Host-key TOFU: the SHA256 fingerprint is recorded on first connection and connections are refused if it changes.
113
+ - Direct remote directories are read-only and confined to their configured root; linked-workspace tool operations are confined to the remote root.
114
+ - Single-file saves are capped at 8 MB. Mirroring runs in the background with defaults of at most 500 files / 50 MB per pass; oversized files are skipped. `.git`, `node_modules` and caches are excluded; single-file reads time out after 30 s. A manual transfer/download handles at most 150 files / 15 MB per run and reports when the limit is hit.
115
+ - The HTTP API only accepts loopback, same-origin requests. For remote deployments it falls back to DSH `connection` host/origin authentication.
116
+
117
+ ## Architecture and development
118
+
119
+ ```
120
+ Client (browser) Host (DSH process)
121
+ Settings / right-sidebar workbench → POST /dsh-linked-workspace/api
122
+ themes + highlighting + file icons workspace registry + linked registry + SSH pool
123
+ ```
124
+
125
+ - `lib/index.js` — Host API, connection pool, linked workspaces, `linked_workspace` tool, prompt section.
126
+ - `lib/ssh.js` — SSH/SFTP, remote exec, host discovery, TOFU fingerprints.
127
+ - `lib/git.js` — remote/local git status (porcelain) and filename search.
128
+ - `lib/linked.js` — linked persistence, `.local`/`.remote` layout, mirror I/O.
129
+ - `src/client.js` + `src/parts/*` → `scripts/build-client.mjs` → `lib/client.js` (single browser bundle).
130
+ - `docs/API.md` — API contract; `docs/VERIFY.md` — manual test checklist.
131
+
132
+ ```
133
+ node scripts/build-client.mjs # rebuild lib/client.js
134
+ node --check lib/index.js lib/ssh.js lib/linked.js
135
+ node test/linked.test.mjs # linked filesystem unit tests (node --test)
136
+ node test/parts.test.mjs # theme/highlight/icon unit tests
137
+ node test/client-smoke.mjs # client bundle registration smoke test
138
+ node test/git.test.mjs # git status/search (includes a real SSH read-only check)
139
+ node test/ssh-smoke.mjs # real SSH transfer smoke test
140
+ node test/host-api.mjs # full Host API over real SSH (24 steps)
141
+ ```
142
+
143
+ ## License
144
+
145
+ MIT © 2026 Huangjh
package/README.md CHANGED
@@ -1,3 +1,192 @@
1
- # Temporary Holding Version
1
+ # dsh-linked-workspace
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 简体中文 · [English](README.en.md)
4
+
5
+ 把已经建立好的 SSH 连接变成 DeepSeek Harness 里的**远程目录**或**联动工作区**:
6
+
7
+ - **远程目录**:设置 → 连接 → 添加远程目录,选主机和远端目录,右侧栏即可只读浏览目录与文件;远程目录视图不允许编辑,需要编辑请创建联动工作区。
8
+ - **联动工作区**:左侧「添加工作区」(或设置 → 连接 → 添加联动工作区)把**本地目录**与**远端目录**配对。该本地目录会注册成真正的 DSH 工作区,里面的会话通过 `linked_workspace` 工具直接读取、编辑远端文件;远端服务器只需 SSH,不需要安装任何 DSH 插件。右侧栏的「联动工作区目录」同时展示远端树(上)与本地树(下)。
9
+
10
+ > 面向 DSH 0.2.1-rc.4;侧边栏页面依赖 `dsh-better-sidebar`(v0.24+)。没有它时插件仍会加载(设置页可用),但侧边栏入口不会出现。
11
+
12
+ ## 功能
13
+
14
+ ### 连接与设置(设置 → 连接)
15
+
16
+ - SSH 主机来自 `dsh-ssh-tunnel` 的 SSH Manager(`~/.dsh/ssh-tunnel/hosts.json`),也支持 `~/.ssh/config`;密码/私钥只在 Host 进程内使用,永不返回给页面或模型。
17
+ - 远程目录列表:添加(选主机 + 浏览远端目录)、测试、打开、移除。
18
+ - 联动工作区列表:本地 ⇄ 远端路径、镜像开关(**默认关闭**)、后台同步(归档到 `.remote`,显示文件数/体积进度,可取消)、移除(可选同时移除 DSH 工作区、删除 `.local`/`.remote`)。开启镜像后首次立即检查,之后**每 5 分钟**自动比较远端与 `.remote`:下载新增/变更文件、删除远端已不存在的镜像文件、跳过未变更文件(`.local/mirror-manifest.json`),并排除 `.git`/`node_modules`/缓存目录;关闭镜像时允许两侧存在版本和文件差异。
19
+ - **编辑器主题**:显示模式分 **系统 / 浅色 / 深色**(默认系统:跟随 DSH 当前主题);指定主题为 **9 张卡片**(GitHub、Solarized、One、Dracula、Monokai、Nord、VS Code、Xcode、Catppuccin),每张卡同时包含浅色/深色版本,预览随模式卡选择实时切换。
20
+ - 添加远程目录 / 添加联动工作区共用同一个表单,可在两处入口使用。
21
+ - 文件打开方式(编辑器 / 系统默认应用 / 复制路径)由右侧栏工具栏的「打开选项菜单」切换并持久化。
22
+
23
+ ### 左侧「添加工作区」
24
+
25
+ 插件接管了 DSH 侧边栏/空白会话的目录选择 hole,弹窗提供两种模式:
26
+
27
+ 1. **本地工作区**:填写或浏览本地目录(Windows 支持 C:/D:/E: 等盘符),填写工作区名称后创建普通 DSH 工作区。
28
+ 2. **远程联动**:SSH 主机 + 远端目录 + 本地目录 + 镜像开关,创建后本地目录成为 DSH 工作区。
29
+
30
+ > 左侧工作区行不再带 `⇄` 标题前缀:插件用一份按 `data-row-key` 定位的样式表,把联动工作区行的宿主文件夹图标替换成**链环图标**(普通本地工作区不受影响)。这是对宿主行结构的唯一 DOM 级适配;如果 DSH 以后更改行结构,选择器会自然失配并回退到原来的文件夹图标,不破坏其他功能。
31
+
32
+ ### 右侧栏入口
33
+
34
+ - **联动工作区目录**:只在联动工作区的会话中出现;点开后绑定该会话对应的联动工作区(不会打开另一个联动工作区),可编辑远程与本地文件。
35
+ - **远程目录**:只要设置 → 连接中至少添加了一个远程目录,任何工作区会话都能打开;只读浏览目录与文件,不允许编辑、传输、重命名或删除。
36
+ - 两种入口都由右侧栏开始页的 + 菜单进入;非联动会话不会出现联动工作区目录选项。
37
+
38
+ ### 右侧栏「联动工作区目录」
39
+
40
+ - 面板固定在右侧栏最右边:**上方远程目录树,下方本地目录树**,两棵树根部都显示「所有文件」;本地树自动隐藏插件的 `.local`/`.remote` 内部目录。
41
+ - **单击选中,双击打开**:单击行只选中(高亮),双击文件夹展开/折叠,双击文件在**文件内容面板**的新标签中打开;目录面板固定在最右侧,始终可见。
42
+ - **面板布局**:目录树是右侧固定面板(带工具栏按钮开/关,不再是标签页);会话面板与目录面板之间是文件内容面板,没有打开文件时显示「打开文件 / 从工作区目录树中选择文件」占位。
43
+ - 工具栏(右键栏右上角):
44
+ - **切换文件树**:所有文件 / 已更改的文件 / 所有更改。更改列表来自远端与本地的 `git status`(分支、状态、暂存标记;删除项置灰)。
45
+ - **在文件中搜索**:搜索框输入 ≥2 个字符后,远端用 `find`、本地用目录遍历按文件名过滤,结果分「远程目录 / 本地目录」列出。
46
+ - **打开选项菜单**:编辑器 / 系统默认应用(把远端文件下载到临时目录后交给本机应用打开)/ 复制路径。
47
+ - **传输按钮(双向)**:选中远端文件/文件夹时传输到本地 `.remote`;选中本地文件/文件夹时传输到远端对应相对路径(进入传输队列,一次一个任务并显示状态)。
48
+ - **显示/隐藏隐藏文件**:同时约束远程目录和本地目录;打开目录时默认显示隐藏项(包括 `.local`/`.remote`),可用按钮隐藏。
49
+ - **刷新**:重新拉取根目录、git 状态与搜索。
50
+ - 不同文件类型使用不同彩色图标(JS/TS/Python/JSON/Markdown/Shell/YAML/图片/压缩包/配置文件等)。
51
+ - 编辑器:行号、语法高亮(叠层渲染)、主题配色、`Ctrl/Cmd+S` 保存、冲突提示(重新加载/强制保存)、二进制与 >2 MB 文件只读保护、UTF-8/LF/CRLF/行数状态栏;内嵌内容面板不显示文件路径/保存工具条,未保存修改在文件标签前显示灰点。
52
+ - **多个文件同时打开**:文件内容面板内最多同时打开 12 个标签;点文件新增标签,重复点同一文件聚焦原标签;本地文件与远端文件共用内部编辑器,本地文件可编辑保存。
53
+
54
+ ### 运行中图标 / 本地技能
55
+
56
+ - 联动工作区下若有正在运行的会话(本地会话 turn 进行中),左侧工作区的链环图标会变成**蓝色**;刷新间隔约 5 秒。
57
+ - 联动会话运行在**本地目录**,因此本机安装的技能(`~/.dsh/skills`、`~/.agents/skills`、`<local>/.dsh/skills`、`<local>/.agents/skills`)可直接使用,**不需要安装到远程目录**。模型可用 `linked_skills` 工具 `list`/`read`,提示词也会明确说明。
58
+
59
+ ### 右键菜单(文件/文件夹/根节点)
60
+
61
+ 传输(下载到 `.remote`)、下载到默认文件夹、队列、打开、用记事本编辑、复制、粘贴、复制路径、重命名、删除、更改权限、新建(文件夹/文件)、属性。远端操作走 SFTP;本地目录的同类操作走本机文件系统。传输队列一次执行一个任务并显示排队/传输中/完成/失败状态。
62
+
63
+ ### 联动工作区结构
64
+
65
+ ```
66
+ <local>/
67
+ .local/ # 按需创建(镜像清单等)
68
+ mirror-manifest.json
69
+ .remote/ # 可选:远端文件镜像存档(读取/保存时自动归档,可手动全量同步)
70
+ ```
71
+
72
+ 会话中的模型工具 `linked_workspace` 支持:
73
+ `list`(列出联动工作区)、`info`、`list_dir`、`read`、`write`、`replace`、`stat`、`mkdir`、`rename`、`delete`、`sync`(启动后台镜像任务)。
74
+ `path` 相对远端根目录(或根内绝对路径);写入原子化,可用 `if_modified_since` 做乐观并发控制;会话工作目录落在某个联动工作区时会自动解析,跨工作区可用 `workspace` 参数指定。
75
+
76
+ ## 界面
77
+
78
+ ![设置 → 连接](docs/screenshots/settings-connections.png)
79
+
80
+ ![联动工作区目录:上远程、下本地](docs/screenshots/linked-directories.png)
81
+
82
+ ![点击文件在新标签页打开远端编辑器](docs/screenshots/file-editor.png)
83
+
84
+ ## 安装
85
+
86
+ ```bash
87
+ dsh plugin --profile "$DSH_PROFILE" add "file:$PWD/dsh-linked-workspace"
88
+ ```
89
+
90
+ 或在 DSH 里使用 `plugin_manager` 的 `install_bundle`,目标填本目录绝对路径。安装后**重启 DSH 桌面应用**(新 Host 插件在进程启动时加载;会话记录保留)。之后:
91
+
92
+ 1. 左下角「账号菜单」→ 设置 →「连接」;
93
+ 2. 或直接点左侧工作区的「添加工作区」,选「远程联动」。
94
+
95
+ ## 从 0.2.x 升级
96
+
97
+ 0.3.0 起插件改名为 `dsh-linked-workspace`。安装新包后,首次启动会把旧的 `$DSH_HOME/remote-workspace` 数据目录迁移到 `$DSH_HOME/linked-workspace`(远程目录、联动工作区、主题设置、已知主机指纹都会保留);随后卸载旧包 `dsh-remote-workspace` 即可。
98
+
99
+ 已打开的旧右侧栏「远程目录」标签页会在刷新后自动恢复(插件保留了两个隐藏的旧 tab 类型别名),标签标题也会自动改成「联动工作区目录」,新开的标签使用新的 `dsh-linked-workspace` 类型。
100
+
101
+ ### 0.5.11 变化
102
+
103
+ 远程目录的只读文件现在能看到代码内容;设置里「打开工作区」会跳转并关闭设置,远程目录「打开」会打开对应远程标签。
104
+
105
+ ### 0.5.10 变化
106
+
107
+ 本地工作区页签改为「输入框 + 浏览…」再展开目录选择;设置→连接移除「打开右侧栏」按钮。
108
+
109
+ ### 0.5.9 变化
110
+
111
+ 添加工作区弹窗的联动表单改用底部「取消 + 创建」;设置里的「创建联动工作区」表单标题/按钮同步,远程目录按钮改为「添加」。
112
+
113
+ ### 0.5.8 变化
114
+
115
+ 添加表单标题随类型显示「添加联动工作区」/「添加远程目录」;Ctrl+O/添加工作区的「本地工作区」页签提供本地目录 + 工作区名称两项并可创建普通本地工作区。
116
+
117
+ ### 0.5.7 变化
118
+
119
+ 点击“添加联动工作区”时表单锁定为联动模式,不再显示远程目录切换;点击“添加远程目录”时锁定为远程模式、不再显示联动切换和“工作区名称”字段。
120
+
121
+ ### 0.5.6 变化
122
+
123
+ 文案改为「直接浏览远端目录(只读)」;传输按钮支持远程→本地 `.remote` 与本地→远程双向;创建联动工作区不再强制生成 `.local`;本地路径选择器支持 C/D/E 等所有盘符;修复远程面包屑双斜杠。
124
+
125
+ ### 0.5.5 变化
126
+
127
+ 联动工作区目录只在联动会话出现并绑定当前工作区;远程目录成为独立的只读标签,任何会话只要配置了远程目录即可打开;空远程目录提示改为「还没有远程目录」。
128
+
129
+ ### 0.5.4 变化
130
+
131
+ 打开目录默认显示隐藏文件、目录面板默认开启;内嵌文件标签不再显示图标;去掉内容面板的路径/保存头部,未保存修改以灰点显示在标签前。
132
+
133
+ ### 0.5.3 变化
134
+
135
+ 主题改为 9 个主题家族(同名主题一张卡,浅/深版本随模式预览);右侧栏改为「文件内容面板 + 最右侧目录面板」布局,目录面板有开关、不再占标签页;本地文件可在内容面板内直接编辑(`local.read`/`local.write`),本地标签不显示图标。
136
+
137
+ ### 0.5.2 变化
138
+
139
+ 本地树的隐藏文件开关同时控制 `.local`/`.remote`;目录行改为单击选中、双击展开/打开,文件以后台标签打开且面板保持目录;主题模式卡与主题卡增加浅色/深色预览和标注;设置页「添加联动工作区」移到「添加远程目录」前面。
140
+
141
+ ### 0.5.1 变化
142
+
143
+ 编辑器主题改为 系统/浅色/深色 三模式(默认系统);联动工作区有运行中会话时链环图标变蓝;新增 `linked_skills` 本地技能桥与 `skills.list/read` API,联动会话直接使用本机技能,不需要装到远端。
144
+
145
+ ### 0.5.0 变化
146
+
147
+ 默认 GitHub 浅色主题;镜像同步默认关闭,开启后每 5 分钟自动检查远端与 `.remote` 差异;右侧栏新增传输按钮、显示/隐藏隐藏文件、右键菜单(传输/下载/记事本/复制粘贴/重命名/删除/权限/新建/属性)与传输队列;多个远端文件可同时以独立标签页打开。详见 [CHANGELOG.md](CHANGELOG.md)。
148
+
149
+ ## 发布与市场更新
150
+
151
+ - npm 包名 `dsh-linked-workspace`;发布新版本只需提升 `package.json` 的 version,然后推送 `v*` 标签。仓库内的 `.github/workflows/release.yml` 会在标签推送时自动执行 `npm publish --access public`(需要在 GitHub 仓库 Secrets 中配置 `NPM_TOKEN`)。
152
+ - awesome-dsh-plugin(DSH 社区插件市场)读取 npm 的 latest 版本与仓库元数据;已收录后的版本升级会自动反映,无需重新提交条目。本仓库保留了可直接提交的 `market/awesome-dsh-plugin-entry.yml`。
153
+ - dsh-plugin.org(DSH Plugin Hub)会定期扫描带 `dsh-plugin` topic 的公开仓库并读取 npm 包;发布新版本后同样自动刷新,无需重新登记。
154
+ - 发布前可本地执行 `npm run build && npm pack --dry-run` 检查包内容。
155
+
156
+ ## 安全
157
+
158
+ - 凭据只存在于 Host 进程;API 只返回主机名、地址和工作区路径。
159
+ - 主机指纹 TOFU:首次连接记录 SHA256,变化即拒绝。
160
+ - 直接远程目录的读写限制在该目录内;联动工作区的工具限制在远端根目录内。
161
+ - 单文件保存上限 8 MB;镜像同步在后台执行,默认最多 500 文件 / 50 MB(跳过超大文件),默认排除 `.git`/`node_modules`/各类缓存目录,单文件读取 30 s 超时,不再阻塞 HTTP 请求。右键「传输」与「下载到默认文件夹」单次最多 150 文件 / 15 MB(超限会提示未全部传输)。
162
+ - 页面 HTTP API 只接受本机回环同源请求(远程部署时回落到 DSH `connection` 服务的 Host/Origin 鉴权)。
163
+
164
+ ## 架构与开发
165
+
166
+ ```
167
+ Client (浏览器) Host (DSH 进程)
168
+ 设置→连接 / 右侧栏双树工作台 / 目录选择弹窗 → POST /dsh-linked-workspace/api
169
+ 主题 + 高亮 + 文件图标(src/parts/*) 工作区注册表 + 联动注册表 + SSH 连接池
170
+ ```
171
+
172
+ - `lib/index.js` — Host API、连接池、联动工作区、`linked_workspace` 工具、提示词段。
173
+ - `lib/ssh.js` — SSH/SFTP、远端命令执行(`exec`)、主机发现、TOFU 指纹。
174
+ - `lib/git.js` — 远端/本地 git status(porcelain 解析)与文件名搜索。
175
+ - `lib/linked.js` — 联动工作区持久化、`.local`/`.remote` 布局、镜像读写。
176
+ - `src/client.js` + `src/parts/*` → `scripts/build-client.mjs` → `lib/client.js`(单文件浏览器 bundle)。
177
+ - `docs/API.md` — API 契约;`docs/VERIFY.md` — 手测清单。
178
+
179
+ ```bash
180
+ node scripts/build-client.mjs # 重新生成 lib/client.js
181
+ node --check lib/index.js lib/ssh.js lib/linked.js
182
+ node test/linked.test.mjs # 联动文件系统单测(node --test)
183
+ node test/parts.test.mjs # 主题/高亮/图标单测
184
+ node test/client-smoke.mjs # 客户端 bundle 注册自检
185
+ node test/git.test.mjs # 远端/本地 git 状态与搜索(含真实 SSH 只读检查)
186
+ node test/ssh-smoke.mjs # 真实 SSH 传输自检
187
+ node test/host-api.mjs # 真实 SSH 下的完整 Host API(21 步,含后台同步与右键操作)
188
+ ```
189
+
190
+ ## License
191
+
192
+ MIT © 2026 Huangjh
@@ -0,0 +1,9 @@
1
+ # dsh-linked-workspace bundle mount
2
+ #
3
+ # The row id is deliberately NOT `dsh-linked-workspace`: that id is already
4
+ # used by the profile's own patch layer for the unrelated
5
+ # `@goodandready/dsh-remote-workspace` SSH tooling row, and reusing it would
6
+ # override that row's config. Keep this bundle's row id unique.
7
+ - insert:
8
+ - id: linked-workspace-ui
9
+ name: dsh-linked-workspace