@achasoft/dsh-advanced-sidebar 0.1.0 → 0.3.0
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/README.md +279 -128
- package/cordis.patch.yml +31 -3
- package/lib/client.js +2803 -466
- package/lib/client.js.map +1 -1
- package/lib/host.js +2071 -418
- package/lib/index.js +6 -2
- package/lib/preview-content-BVUQ5oOR.js +465 -0
- package/lib/remote.js +330 -25
- package/lib/typert.host.js +330 -25
- package/lib/ui-preview.js +352 -0
- package/package.json +8 -2
- package/types/client/ActionMenu.d.ts +16 -1
- package/types/client/LogDownloadDialog.d.ts +24 -0
- package/types/client/contract.d.ts +57 -1
- package/types/client/index.d.ts +4 -2
- package/types/client/locales.d.ts +100 -0
- package/types/client/log-download.d.ts +179 -0
- package/types/client/panels/PreviewPanel.d.ts +20 -15
- package/types/client/panels/preview-file.d.ts +61 -0
- package/types/client/panels/preview-mode.d.ts +67 -0
- package/types/client/panels/preview-scratchpad.d.ts +53 -0
- package/types/client/panels/preview-url.d.ts +17 -0
- package/types/client/panels/shared.d.ts +15 -2
- package/types/client/preview-driver.d.ts +121 -0
- package/types/client/preview-storage.d.ts +43 -0
- package/types/client/preview-types.d.ts +21 -0
- package/types/client/preview-values.d.ts +43 -0
- package/types/host/deletion.d.ts +32 -23
- package/types/host/git.d.ts +94 -8
- package/types/host/index.d.ts +97 -5
- package/types/host/preview-content.d.ts +179 -0
- package/types/host/preview-serve.d.ts +242 -0
- package/types/host/settings-section.d.ts +49 -0
- package/types/host/types.d.ts +341 -0
- package/types/host/ui-bridge.d.ts +197 -0
- package/types/host/ui-preview-tool.d.ts +60 -0
- package/types/index.d.ts +6 -2
- package/types/ui-preview.d.ts +11 -0
package/README.md
CHANGED
|
@@ -1,204 +1,355 @@
|
|
|
1
1
|
# @achasoft/dsh-advanced-sidebar
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A session menu and a resizable side dock for the [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) Web Client. The **⋯** menu in the session header opens these panels in a column to the right of the conversation:
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
- **Changes**: git status, diffs, staging, commit, a model-written commit message, and push;
|
|
6
|
+
- **Terminal**: your own shells, in tabs;
|
|
7
|
+
- **Files**: a file browser with text preview;
|
|
8
|
+
- **Preview**: dev servers, workspace files, URLs, or a scratchpad;
|
|
9
|
+
- **Background tasks**: the session's jobs.
|
|
6
10
|
|
|
7
|
-
|
|
11
|
+
The same menu has **Open in**, **Download session log**, **Archive**, and **Delete**. Work the browser cannot do itself (running git, opening a pseudo-terminal, launching an editor) runs on the host through this plugin's own RPC namespace. One optional model tool, `ui_preview`, lets the agent inspect and drive the Preview panel.
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
```sh
|
|
12
|
-
dsh plugin --profile web add /abs/path/to/dsh-advanced-sidebar
|
|
13
|
-
dsh web
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
From a harness source checkout instead:
|
|
17
|
-
|
|
18
|
-
```sh
|
|
19
|
-
pnpm dsh plugin --profile web add ../dsh-plugins/dsh-advanced-sidebar
|
|
20
|
-
pnpm dsh web
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Build the plugin first (`pnpm install && pnpm run build`); the Web Client refuses to start when a composed plugin has no built `lib/client.js`.
|
|
24
|
-
|
|
25
|
-
## The menu
|
|
13
|
+

|
|
26
14
|
|
|
27
|
-
|
|
15
|
+
## Features
|
|
28
16
|
|
|
29
|
-
|
|
30
|
-
|---|---|---|
|
|
31
|
-
| Changes | Uncommitted changes in the session's working directory, each file's patch, staging, commit, a model-written commit message, and push | `git` on PATH, `ctx.subprocess`, `ctx.fs`, and `ctx.llm` + `ctx.agentDefaultModel` for the message |
|
|
32
|
-
| Terminal | Interactive shells of your own, on a tab strip, in that directory | `ctx.subprocess`, `ctx.fs` |
|
|
33
|
-
| Files | That directory, one level at a time, with a text preview | `ctx.fs` |
|
|
34
|
-
| Preview | The workspace's dev server, started and shown in a frame, with its logs | `ctx.subprocess`, `ctx.fs` |
|
|
35
|
-
| Background tasks | This session's `ctx.jobs` records, with Stop and the output of a settled one | `ctx.jobs` |
|
|
36
|
-
| Open in ▸ | A second browser window, a configured editor, or the operating system's file manager | `ctx.subprocess` for the editors |
|
|
37
|
-
| Archive | Hides the session; its log and its accounting slot remain | `ctx.workspaceRegistry` |
|
|
38
|
-
| Delete | Archives, and — in `purge` mode — removes the durable session log | `ctx.workspaceRegistry`, `ctx.sessionPersistence` |
|
|
17
|
+
### Session menu
|
|
39
18
|
|
|
40
|
-
|
|
19
|
+
A **⋯** button in the open session's header. It acts on that session, using the session's own working directory, or its workspace path when the session has none.
|
|
41
20
|
|
|
42
|
-
|
|
21
|
+
| Entry | What it does |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| Changes, Terminal, Files, Preview, Background tasks | Opens that panel in the dock. The open panel's entry has a check mark, and choosing it again closes the dock. |
|
|
24
|
+
| Open in ▸ | **New window** (a second tab of the Web Client), each configured editor, and the OS file manager: Finder, File Explorer, or `xdg-open` on Linux. |
|
|
25
|
+
| Download session log | Exports the session as a ZIP through the harness's own exporter. See the note below. |
|
|
26
|
+
| Archive | Hides the session. Its log stays on disk. |
|
|
27
|
+
| Delete | Asks for confirmation, then archives. See [Known limitations](#known-limitations). |
|
|
43
28
|
|
|
44
|
-
|
|
29
|
+
When the host cannot serve an entry (git not installed, an editor command not found, no subprocess capability), the entry stays in the menu, disabled, with the reason next to it. An entry switched off in settings is not shown at all. The menu asks the host again each time it opens, so installing git or an editor shows up without a restart.
|
|
45
30
|
|
|
46
|
-
|
|
31
|
+
**Download session log.** The harness package `@deepseek-ai/dsh-session-log-export` adds its own **⋯** button, with that single entry, to the same header row. This plugin hides that button: it registers an entry with the same id (`session-log-download`) at priority `-1`, and moves the entry into its own menu. Exporting still uses the harness's controller and dialog, so `/export` keeps working. If the harness package is absent or its controller has a different shape, nothing is hidden and the menu has no Download entry.
|
|
47
32
|
|
|
48
|
-
|
|
33
|
+

|
|
49
34
|
|
|
50
|
-
|
|
35
|
+
### The dock
|
|
51
36
|
|
|
52
|
-
|
|
37
|
+
Panels open in a column on the right of the app frame. The conversation narrows to make room, so the dock does not cover it.
|
|
53
38
|
|
|
54
|
-
|
|
39
|
+
- **Resizing.** Drag the left edge, use Left and Right on the focused handle, or double-click the handle to return to the configured width.
|
|
40
|
+
- **Width limits.** The width is kept between 280 px and 960 px, and never leaves the conversation less than 400 px.
|
|
41
|
+
- **Narrow windows.** When even the minimum width would squeeze the conversation below 400 px, the dock floats over the conversation instead.
|
|
55
42
|
|
|
56
|
-
|
|
43
|
+
### Changes
|
|
57
44
|
|
|
58
|
-
|
|
45
|
+
- **Status.** The working directory's status, grouped as Staged, Not staged, Untracked, and Conflicted, with branch, ahead, and behind counts. Click a file to see its patch, with **Copy patch**.
|
|
46
|
+
- **Staging.** **Stage** / **Unstage** a file, or a whole group with **Stage all** / **Unstage all**.
|
|
47
|
+
- **Commit.** **Commit** records what is staged, with an optional **Amend the previous commit**. The author git would record (`git var GIT_AUTHOR_IDENT`) is shown under the message box, so a missing `user.email` is visible before you commit.
|
|
48
|
+
- **Generate.** Writes a commit message with the model the composer is currently set to. The model sees only the staged patch, up to `commitMessageMaxBytes`. The message goes into the box for you to edit, and nothing is committed automatically.
|
|
49
|
+
- **Push.** Pushes the current branch to its upstream (`git push` with no arguments). A branch with no upstream shows **Publish** instead, which pushes to `origin`, or to the first remote if there is no `origin`, and sets the upstream. Force push, a remote picker, and custom refspecs are not offered.
|
|
50
|
+
- **No discard.** There is no way to discard changes from this panel. Use the Terminal panel.
|
|
59
51
|
|
|
60
|
-
|
|
52
|
+
### Terminal
|
|
61
53
|
|
|
62
|
-
**
|
|
54
|
+
- **Your own shells.** Interactive shells in the session's working directory, in tabs, up to `maxTerminals`. They are separate from the model's terminals.
|
|
55
|
+
- **Controls.** **Interrupt** and Ctrl+C send SIGINT to the foreground process group. **Clear** clears the screen, and **Restart** starts a new shell.
|
|
56
|
+
- **Shells keep running.** Closing the dock or switching panels leaves them running. Reopening a tab replays the output the host kept (`terminalScrollback`). Closing a tab ends its shell, and so does archiving or deleting the session.
|
|
57
|
+
- **Emulator.** The screen is `@xterm/xterm`, so colors, line editing, and full-screen programs work.
|
|
63
58
|
|
|
64
|
-
|
|
59
|
+

|
|
65
60
|
|
|
66
|
-
|
|
61
|
+
### Files
|
|
67
62
|
|
|
68
|
-
**
|
|
63
|
+
- **Browsing.** The working directory, one level at a time. Hidden entries are excluded unless `filesShowHidden` is on.
|
|
64
|
+
- **Preview.** A text preview up to `filesMaxPreviewBytes`. Binary files show their size.
|
|
65
|
+
- **Actions.** **Open with the default application** and **Show in file manager**.
|
|
69
66
|
|
|
70
|
-
|
|
67
|
+

|
|
71
68
|
|
|
72
|
-
|
|
69
|
+
### Preview
|
|
73
70
|
|
|
74
|
-
|
|
75
|
-
- The message crosses as one argument to `-m`, so no shell sees it and nothing in it can become an option. A message of `--amend --author=someone` commits that text.
|
|
76
|
-
- The author is read with `git var GIT_AUTHOR_IDENT` — git's own answer to "who would this commit be by" — and shown under the box, so a missing `user.email` is visible *before* the button is pressed.
|
|
77
|
-
- Committing has its own timeout (`gitCommitTimeoutMs`, default 2 minutes) because it runs the repository's `pre-commit` hook, which can far outlast any reading; killing one mid-run leaves a stale `index.lock`. Hooks run, and a hook's stderr comes back verbatim rather than summarized.
|
|
71
|
+
Four modes, with a viewport picker (Desktop, Tablet, Mobile, Custom) in every mode.
|
|
78
72
|
|
|
79
|
-
|
|
73
|
+
| Mode | What it shows |
|
|
74
|
+
| --- | --- |
|
|
75
|
+
| **Server** | Launch configurations from the workspace's `.claude/launch.json` (Claude Code's format) and the `previews` setting. The file wins when both define the same name. **Start** and **Stop** a server, view **Logs** (these open automatically when a start fails), **Open in a new window**, or **Open inspectable**, which hands the URL to URL mode. |
|
|
76
|
+
| **File** | A workspace file, rendered by type: HTML and SVG in a frame, Markdown rendered, images, audio, video, PDF, and plain text. The panel reloads when the file changes. Files over `previewMaxFileBytes`, or of unknown types, offer **Open with the default application**. |
|
|
77
|
+
| **URL** | Any `http(s)` address. A `localhost`, `127.x.x.x`, or `[::1]` address is loaded through the host's proxy, so the frame is same-origin and its DOM and console can be read. Other addresses are framed directly and labeled cross-origin. |
|
|
78
|
+
| **Scratchpad** | HTML you type, rendered from a host route. The text is saved per workspace in this browser's `localStorage`. |
|
|
80
79
|
|
|
81
|
-
|
|
80
|
+
For a launch configuration, readiness means the configured `port` accepts a TCP connection, checked until `previewReadyTimeoutMs`. The child process gets `PORT`, `NO_COLOR=1`, and `FORCE_COLOR=0`. Stopping sends SIGTERM to the process tree, then SIGKILL after `previewGraceMs`.
|
|
82
81
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
The screen is a real terminal emulator (`@xterm/xterm`), and that is why the browser bundle is large. It is not a preference: an interactive shell redraws its prompt with cursor addressing on every keystroke, and a hand-rolled screen model renders a login shell's prompt as overwritten fragments — verified, then replaced. Colour, line editing, history recall, and full-screen programs come with the emulator. Ctrl+C is intercepted and delivered as a **signal to the foreground process group** rather than as a byte, which is the difference between interrupting a running command and doing nothing.
|
|
86
|
-
|
|
87
|
-
Output is polled, not pushed: an out-of-tree plugin has no host-to-client push channel, so the panel holds the whole-stream offset it has already written into the emulator and asks for whatever came after it. That offset is also what makes a reopened panel replay the retained scrollback.
|
|
88
|
-
|
|
89
|
-
There is no resize: the subprocess seam exposes none. The emulator follows the dock so rendered rows stay readable, but the *shell* keeps the size it was allocated at; **Restart** allocates one at the new size.
|
|
90
|
-
|
|
91
|
-
[`src/client/terminal-screen.ts`](src/client/terminal-screen.ts) survives as the log renderer for the Preview and Background tasks panels, which show plain output rather than an interactive screen.
|
|
92
|
-
|
|
93
|
-
**Files** lists through this plugin's own endpoint rather than the Web Client's `listDirectory`, because the Host's browse capability returns directories only — its one shipped caller is a workspace picker. Every path is resolved through `ctx.fs` and proved to sit inside the workspace before anything reads it.
|
|
94
|
-
|
|
95
|
-
**Preview** runs what you are building and shows it beside the conversation.
|
|
96
|
-
|
|
97
|
-
Launch configurations are read from the workspace's own **`.claude/launch.json`** — Claude Code's file, unchanged — and from the `previews` settings rows, in that order; a name declared in both is taken from the repository's file, because a repository is the authority on how to run itself. A row with a `runtimeExecutable` starts a process; a row with only a `url` is attach-only and simply points the frame at something already running.
|
|
82
|
+
`.claude/launch.json` example:
|
|
98
83
|
|
|
99
84
|
```json
|
|
100
85
|
{
|
|
101
86
|
"version": "0.0.1",
|
|
102
87
|
"configurations": [
|
|
103
|
-
{ "name": "web", "runtimeExecutable": "npm", "runtimeArgs": ["run", "dev"], "port": 3000 }
|
|
104
|
-
{ "name": "docs", "runtimeExecutable": "pnpm", "runtimeArgs": ["docs:dev"], "port": 5173, "cwd": "website" }
|
|
88
|
+
{ "name": "web", "runtimeExecutable": "npm", "runtimeArgs": ["run", "dev"], "port": 3000 }
|
|
105
89
|
]
|
|
106
90
|
}
|
|
107
91
|
```
|
|
108
92
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
The frame is a plain `<iframe>` with viewport presets (desktop, tablet, mobile) scaled to the dock, and an editable address bar so you can navigate into a route rather than only the root. Two controls are permanent rather than error states:
|
|
93
|
+

|
|
112
94
|
|
|
113
|
-
|
|
114
|
-
- **Open in a new window** — a page can refuse to be framed (`X-Frame-Options`, `frame-ancestors`), and cross-origin framing gives the panel no way to detect that: the load event fires either way. The escape hatch is therefore always present instead of appearing after a failure nothing can observe.
|
|
95
|
+
### Background tasks
|
|
115
96
|
|
|
116
|
-
|
|
97
|
+
- **List.** The session's background jobs, filtered by text, status, and start date, with duration and status.
|
|
98
|
+
- **Stop.** Requires `allowTaskKill`. Stopping a task also suppresses the completion notice the model would otherwise receive.
|
|
99
|
+
- **Output.** Requires `showTaskOutput`, and appears only after the task has finished and its completion has been reported. Reading output earlier would consume the output the model reads.
|
|
117
100
|
|
|
118
|
-
|
|
101
|
+
### Settings card
|
|
119
102
|
|
|
120
|
-
|
|
103
|
+
**Settings → Plugins → Advanced sidebar** edits most settings and shows, for each Open in target and preview configuration, whether it is available on this host. See [Configuration](#configuration).
|
|
121
104
|
|
|
122
|
-
|
|
123
|
-
- **Output** is served only once a task has settled **and** its completion has been reported. `ctx.jobs.read()` consumes the same cursor the model reads from, so draining a live task's stream would silently delete output the model was about to receive. Text already drained is retained Host-side, so reopening the panel shows it again instead of an empty second read.
|
|
105
|
+

|
|
124
106
|
|
|
125
|
-
|
|
107
|
+
## Requirements
|
|
126
108
|
|
|
127
|
-
**
|
|
109
|
+
- **DeepSeek Harness 0.1.5-rc.2** with the `web` profile. This is the version the plugin is tested against. Node `^22.19 || >=24`.
|
|
110
|
+
- **pnpm** on `PATH`, because `dsh plugin` runs pnpm.
|
|
111
|
+
- **git 2.23 or newer** on the host `PATH` for Changes, because unstaging uses `git restore --staged`.
|
|
112
|
+
- Harness capabilities, each optional. A missing one disables only the entries that need it, with the reason shown:
|
|
128
113
|
|
|
129
|
-
|
|
130
|
-
|
|
114
|
+
| Capability | Needed by |
|
|
115
|
+
| --- | --- |
|
|
116
|
+
| `subprocess` | Changes, Terminal, Preview servers, Open in |
|
|
117
|
+
| `fs` | Changes, Terminal, Files, Preview |
|
|
118
|
+
| `jobs` | Background tasks (Stop and Output) |
|
|
119
|
+
| `workspaceRegistry` | Delete; Preview File mode (files are served only from registered workspaces) |
|
|
120
|
+
| `llm` + `agentDefaultModel` | **Generate** commit message |
|
|
121
|
+
| `connection` (with `requestRejection`) + `webServer` | Preview's same-origin routes: File mode, the loopback proxy, Scratchpad |
|
|
122
|
+
| `tools` | The `ui_preview` model tool |
|
|
123
|
+
| `sessionLogDownload` (from `@deepseek-ai/dsh-session-log-export`) | Download session log |
|
|
131
124
|
|
|
132
|
-
|
|
125
|
+
- **OS:** developed and tested on macOS. The code has Windows and Linux branches (shell fallback, file-manager command) that are not verified.
|
|
133
126
|
|
|
134
|
-
##
|
|
127
|
+
## Install
|
|
135
128
|
|
|
136
|
-
|
|
129
|
+
```bash
|
|
130
|
+
dsh plugin --profile web add @achasoft/dsh-advanced-sidebar
|
|
131
|
+
dsh web
|
|
132
|
+
```
|
|
137
133
|
|
|
138
|
-
`
|
|
134
|
+
`dsh plugin --profile <name> …` runs pnpm with the remaining arguments in `$DSH_HOME/profiles/<name>` (default `~/.dsh/profiles/web`). Afterwards, dsh adds every dependency whose `package.json` declares `dsh.bundle` to `dsh.profile.bundles`. This package declares `"dsh": { "bundle": { "patch": "./cordis.patch.yml" } }`, so it is enabled with no manual edit. Restart `dsh web` after installing.
|
|
139
135
|
|
|
140
|
-
|
|
136
|
+
To uninstall, remove the package. dsh also drops it from `dsh.profile.bundles`:
|
|
141
137
|
|
|
142
|
-
|
|
138
|
+
```bash
|
|
139
|
+
dsh plugin --profile web remove @achasoft/dsh-advanced-sidebar
|
|
140
|
+
```
|
|
143
141
|
|
|
144
|
-
|
|
142
|
+
### How `cordis.patch.yml` is applied
|
|
145
143
|
|
|
146
|
-
|
|
147
|
-
- insert:
|
|
148
|
-
- id: advanced-sidebar
|
|
149
|
-
name: '@achasoft/dsh-advanced-sidebar/host'
|
|
150
|
-
config: { ... }
|
|
151
|
-
- id: advanced-sidebar-ui
|
|
152
|
-
name: '@achasoft/dsh-advanced-sidebar'
|
|
153
|
-
```
|
|
144
|
+
At boot, dsh builds the configuration from patch layers, in this order:
|
|
154
145
|
|
|
155
|
-
|
|
146
|
+
1. Each bundle's `cordis.patch.yml`, in `dsh.profile.bundles` order.
|
|
147
|
+
2. `$DSH_HOME/profiles/<name>/cordis.patch.yml`.
|
|
148
|
+
3. `$DSH_HOME/cordis.patch.yml`.
|
|
149
|
+
4. Any `--patch <file>` overlays.
|
|
156
150
|
|
|
157
|
-
|
|
151
|
+
Later layers override earlier ones by row `id`. This package inserts three rows:
|
|
158
152
|
|
|
159
|
-
|
|
153
|
+
| id | name | Role |
|
|
154
|
+
| --- | --- | --- |
|
|
155
|
+
| `advanced-sidebar` | `@achasoft/dsh-advanced-sidebar/host` | Host service, RPC namespace `advancedSidebar`, the `advanced-sidebar` settings section, and the preview routes. |
|
|
156
|
+
| `advanced-sidebar-ui` | `@achasoft/dsh-advanced-sidebar` | Browser half. It must be the bare package name, because the Web Client finds browser code by resolving `<row name>/package.json`. |
|
|
157
|
+
| `advanced-sidebar-ui-preview` | `@achasoft/dsh-advanced-sidebar/ui-preview` | The `ui_preview` model tool. |
|
|
160
158
|
|
|
161
|
-
|
|
159
|
+
To keep the sidebar but not give the model a tool, disable the third row in your profile's `cordis.patch.yml`:
|
|
162
160
|
|
|
163
|
-
|
|
161
|
+
```yaml
|
|
162
|
+
- id: advanced-sidebar-ui-preview
|
|
163
|
+
disabled: true
|
|
164
|
+
```
|
|
164
165
|
|
|
165
|
-
|
|
166
|
+
To see the composed result:
|
|
166
167
|
|
|
167
|
-
```
|
|
168
|
-
|
|
168
|
+
```bash
|
|
169
|
+
dsh --profile web --dump-config
|
|
169
170
|
```
|
|
170
171
|
|
|
171
|
-
|
|
172
|
+
## Configuration
|
|
173
|
+
|
|
174
|
+
All keys below are in the `config` of the `advanced-sidebar` row. A patch replaces a row's whole `config`, so an override must restate every key. Copy the row from this package's `cordis.patch.yml` and edit it.
|
|
175
|
+
|
|
176
|
+
The host schema declares no defaults, and every key except `commitMessagePrompt` and `terminalShell` is required. The defaults listed are the values `cordis.patch.yml` ships. Changes saved from the settings card are stored as a user layer over the patch value. **Card** marks keys the card can edit. On a Web Client that is not on loopback the harness settings scope is unavailable, so the card and menu show the host's values read-only.
|
|
177
|
+
|
|
178
|
+
**Menu and behavior**
|
|
179
|
+
|
|
180
|
+
| Key | Default | Card | What it does |
|
|
181
|
+
| --- | --- | --- | --- |
|
|
182
|
+
| `showInSessionHeader` | `true` | yes | Shows the ⋯ menu in the session header. When off, the button still appears if needed to offer Download session log, and nothing else. |
|
|
183
|
+
| `showChanges`, `showTerminal`, `showFiles`, `showTasks`, `showPreview`, `showOpenIn`, `showArchive` | `true` | yes | Shows each menu entry. |
|
|
184
|
+
| `showDelete` | `true` | yes | Shows Delete. When off, the host also refuses `deleteSession`. |
|
|
185
|
+
| `panelWidth` | `460` | yes | Dock width in px (schema allows 280–1400; the dock uses at most 960). Dragging the edge saves here when the scope is writable. |
|
|
186
|
+
| `deleteMode` | `archive` | yes | `archive` or `purge`. `purge` is unavailable on this harness; see limitations. |
|
|
187
|
+
| `confirmDelete` | `true` | yes | Asks before Delete. Must be `true` when `deleteMode` is `purge`. |
|
|
188
|
+
| `allowTaskKill` | `true` | yes | Offers Stop, enforced by the host. |
|
|
189
|
+
| `showTaskOutput` | `true` | yes | Offers Output for finished tasks, enforced by the host. |
|
|
190
|
+
|
|
191
|
+
**git (Changes panel)**
|
|
192
|
+
|
|
193
|
+
| Key | Default | Card | What it does |
|
|
194
|
+
| --- | --- | --- | --- |
|
|
195
|
+
| `gitMaxFiles` | `500` | yes | Most files in one status reading. |
|
|
196
|
+
| `gitDiffMaxBytes` | `262144` | no | Largest patch returned for one file. |
|
|
197
|
+
| `gitTimeoutMs` | `20000` | yes | Time limit for each read-only git command. |
|
|
198
|
+
| `allowGitStaging` | `true` | yes | Stage and unstage, enforced by the host. |
|
|
199
|
+
| `allowGitCommit` | `true` | yes | Commit, enforced by the host. Also requires staging. |
|
|
200
|
+
| `gitCommitTimeoutMs` | `120000` | yes | Time limit for `git commit`, which runs hooks. |
|
|
201
|
+
| `allowGitPush` | `true` | yes | Push and Publish, enforced by the host. |
|
|
202
|
+
| `gitPushTimeoutMs` | `180000` | yes | Time limit for a push. |
|
|
203
|
+
| `allowCommitMessageDraft` | `true` | yes | **Generate**, enforced by the host. Also requires commit. |
|
|
204
|
+
| `commitMessagePrompt` | `''` | no | Replaces the built-in commit-message instruction. Empty uses the built-in one. |
|
|
205
|
+
| `commitMessageMaxBytes` | `65536` | yes | Largest staged patch sent to the model. A longer patch is truncated, and the model is told it was cut. |
|
|
206
|
+
|
|
207
|
+
**Terminal and Files**
|
|
208
|
+
|
|
209
|
+
| Key | Default | Card | What it does |
|
|
210
|
+
| --- | --- | --- | --- |
|
|
211
|
+
| `terminalShell` | `''` | yes | Shell to run. Empty uses `$SHELL`, then `/bin/sh` (`%COMSPEC%` or `powershell.exe` on Windows). |
|
|
212
|
+
| `terminalScrollback` | `200000` | no | Characters of output kept per terminal for replay. |
|
|
213
|
+
| `maxTerminals` | `4` | yes | Most panel terminals open at once (1–32). |
|
|
214
|
+
| `terminalGraceMs` | `3000` | no | Delay between TERM and KILL when a terminal closes. |
|
|
215
|
+
| `filesMaxPreviewBytes` | `262144` | no | Largest file shown in the Files preview. |
|
|
216
|
+
| `filesMaxEntries` | `2000` | no | Most entries listed per directory. |
|
|
217
|
+
| `filesShowHidden` | `false` | no | Lists dot-files. |
|
|
218
|
+
|
|
219
|
+
**Preview**
|
|
220
|
+
|
|
221
|
+
| Key | Default | Card | What it does |
|
|
222
|
+
| --- | --- | --- | --- |
|
|
223
|
+
| `previewsFromLaunchFile` | `true` | yes | Reads `.claude/launch.json`. |
|
|
224
|
+
| `previews` | `[]` | no (listed) | Extra launch rows: `name`, `runtimeExecutable`, `runtimeArgs`, `port`, `url`, `cwd`. An empty `runtimeExecutable` makes the row attach-only: it points the frame at `url` and starts nothing. |
|
|
225
|
+
| `maxPreviews` | `3` | yes | Most dev servers running at once. |
|
|
226
|
+
| `previewReadyTimeoutMs` | `60000` | yes | How long to wait for the port to accept connections. |
|
|
227
|
+
| `previewScrollback` | `200000` | no | Log characters kept per server. |
|
|
228
|
+
| `previewGraceMs` | `3000` | no | Delay between TERM and KILL when a server stops. |
|
|
229
|
+
| `previewMaxFileBytes` | `33554432` | no | Largest workspace file served to the frame. |
|
|
230
|
+
| `previewProxyTimeoutMs` | `30000` | no | Time limit for one proxied request to a loopback server. |
|
|
231
|
+
| `previewCommandTimeoutMs` | `15000` | no | How long a `ui_preview` command other than `open` waits for the panel. |
|
|
232
|
+
| `previewBindTtlMs` | `6000` | no | How long a panel counts as open after its last poll. |
|
|
233
|
+
|
|
234
|
+
**Open in**
|
|
235
|
+
|
|
236
|
+
| Key | Default | Card | What it does |
|
|
237
|
+
| --- | --- | --- | --- |
|
|
238
|
+
| `editors` | VS Code (`code`), Cursor (`cursor`), Zed (`zed`) | no (availability listed) | Rows of `id`, `label`, `command`, `args`. `args` go before the path. `id` must match `^[a-z][a-z0-9-]*$`, be unique, and not be `reveal`. |
|
|
239
|
+
|
|
240
|
+
The host refuses a configuration at load when:
|
|
241
|
+
|
|
242
|
+
- an editor id is invalid or duplicated, or an editor command is empty;
|
|
243
|
+
- a preview name is empty or duplicated;
|
|
244
|
+
- a preview row has no command, no URL, and no port;
|
|
245
|
+
- `deleteMode` is `purge` while `confirmDelete` is `false`.
|
|
246
|
+
|
|
247
|
+
The `advanced-sidebar-ui-preview` row has one key, `commandTimeoutMs` (default `15000`, range 1000–600000). It is the default wait for `ui_preview open` when the call passes no `waitMs`.
|
|
248
|
+
|
|
249
|
+
## Model tool and RPC
|
|
250
|
+
|
|
251
|
+
### `ui_preview`
|
|
252
|
+
|
|
253
|
+
Registered only when the `advanced-sidebar-ui-preview` row is composed. It works only while the Preview panel is open in the same session. Otherwise it returns immediately with a message telling the model to open the panel.
|
|
254
|
+
|
|
255
|
+
| Action | Arguments | Result |
|
|
256
|
+
| --- | --- | --- |
|
|
257
|
+
| `open` | `url` or `path`; optional `workspace`, `waitMs` | Points the panel at an http(s) URL or a workspace file, and reports whether the page can be inspected. |
|
|
258
|
+
| `dom` | optional `selector` | The rendered DOM: tags, ids and classes, text, display, and box metrics, plus the page text, viewport, and URL. |
|
|
259
|
+
| `eval` | `expression` | Runs JavaScript in the frame and returns the value as JSON. |
|
|
260
|
+
| `console` | optional `cursor` | Console messages, uncaught errors, and unhandled rejections logged since `cursor`. |
|
|
261
|
+
| `click` | `selector` | Dispatches `click()` on the element. |
|
|
262
|
+
| `type` | `selector`, `text`, optional `key` | Sets the element's value, dispatches `input` and `change`, then optionally the key. |
|
|
263
|
+
| `reload` | none | Reloads the frame. |
|
|
264
|
+
| `resize` | `width`, `height` | Sets the frame viewport size. |
|
|
265
|
+
| `close` | none | Closes the preview. |
|
|
266
|
+
|
|
267
|
+
`dom`, `eval`, `click`, and `type` refuse a cross-origin frame by name instead of returning nothing.
|
|
268
|
+
|
|
269
|
+
### RPC namespace `advancedSidebar`
|
|
270
|
+
|
|
271
|
+
The browser half calls these endpoints over the harness's client connection:
|
|
272
|
+
|
|
273
|
+
- `describe`
|
|
274
|
+
- `gitStatus`, `gitDiff`, `gitStage`, `gitUnstage`, `gitCommit`, `gitPush`, `gitCommitMessage`
|
|
275
|
+
- `terminalOpen`, `terminalRead`, `terminalWrite`, `terminalSignal`, `terminalClose`
|
|
276
|
+
- `listEntries`, `readFile`
|
|
277
|
+
- `previewList`, `previewStart`, `previewStop`, `previewLogs`, `previewFileInfo`, `previewPoll`, `previewResult`, `previewRelease`
|
|
278
|
+
- `openIn`
|
|
279
|
+
- `taskKill`, `taskOutput`
|
|
280
|
+
- `deleteSession`
|
|
281
|
+
|
|
282
|
+
Every endpoint returns a result value with a failure code instead of throwing. The root export re-exports the types.
|
|
283
|
+
|
|
284
|
+
## Security notes
|
|
285
|
+
|
|
286
|
+
- **git does not run programs the repository configures.**
|
|
287
|
+
- Every git command passes `-c core.fsmonitor=false`.
|
|
288
|
+
- Every `git diff` passes `--no-ext-diff --no-textconv`.
|
|
289
|
+
- Read-only commands (status, diff, log, identity, remote list) switch off `filter.<driver>.clean`/`process` from the repository's local and per-worktree config. Global and system filters, such as git-lfs, still run. A driver name that cannot be disabled this way, because it contains `=`, makes the reading fail instead.
|
|
290
|
+
- Stage, commit, and push are explicit user actions and keep git's normal behavior, including hooks and filters.
|
|
291
|
+
- **No option injection.**
|
|
292
|
+
- Paths are checked to be inside the repository and passed after `--`.
|
|
293
|
+
- The commit message is a single `-m` argument.
|
|
294
|
+
- Publish checks the branch with `git check-ref-format --branch`, checks the remote as `refs/remotes/<remote>/HEAD`, and pushes `-- <remote> refs/heads/<b>:refs/heads/<b>`.
|
|
295
|
+
- Credential prompts are disabled (`GIT_TERMINAL_PROMPT=0`), so a push that needs credentials fails instead of hanging.
|
|
296
|
+
- **Host-enforced switches.** `allowGitStaging`, `allowGitCommit`, `allowGitPush`, `allowCommitMessageDraft`, `allowTaskKill`, `showTaskOutput`, and `showDelete` are checked by the host, not only hidden in the UI.
|
|
297
|
+
- **Paths stay inside the workspace.** Files, Preview File mode, and `ui_preview` file arguments are resolved through the harness filesystem's containment check, so symlinks cannot escape.
|
|
298
|
+
- **Panel terminals are separate from the model's terminals.** They are allocated with `ctx.subprocess.spawnTerminal`, not the agent's terminal registry, so your keystrokes never reach a terminal the model controls.
|
|
299
|
+
- **Preview routes are gated.** The routes `/advanced-sidebar/preview-file`, `/advanced-sidebar/preview-proxy` (plus its websocket upgrade), and `/advanced-sidebar/preview-scratchpad` each call the harness connection's `requestRejection` first. That is the same host/origin check and signed `dsh-auth-*` cookie check that guards `/api`, and it answers `401`/`403` otherwise. If the connection has no such gate, the routes are not registered at all.
|
|
300
|
+
- **Loopback only.** The proxy forwards only to literal loopback hosts (`localhost`, `127.0.0.0/8`, `[::1]`). A hostname that merely resolves to loopback is refused.
|
|
301
|
+
- **No credential forwarding.** The harness's `dsh-auth-*` cookie is stripped from forwarded requests and from upstream `Set-Cookie` headers.
|
|
302
|
+
- **Registered workspaces only.** The file route serves only files inside a workspace in `workspaceRegistry`.
|
|
303
|
+
- **Scratchpad size.** Scratchpad documents are limited to 1 MiB.
|
|
304
|
+
- **No caching.** Responses are sent with `no-store`.
|
|
305
|
+
- **A proxied page runs as the Web Client's origin.** Its scripts can call the harness API with your session. Only preview dev servers you trust as much as a browser tab signed in to the harness.
|
|
306
|
+
- **`ui_preview open` accepts any http(s) URL**, like the address bar. Only loopback URLs become same-origin and inspectable.
|
|
307
|
+
|
|
308
|
+
## Known limitations
|
|
309
|
+
|
|
310
|
+
- **Delete only archives.** The harness's session persistence API (0.1.5-rc.2) has no way to remove a session. So `deleteMode: purge` is reported unavailable, the card will not select it, and a configured `purge` archives and returns the reason the log was kept.
|
|
311
|
+
- **No push channel.** An out-of-tree plugin cannot add wire frames, so terminal output, preview logs, and `ui_preview` commands are polled.
|
|
312
|
+
- The command poll runs every 600 ms while there is work and every 2 s when idle.
|
|
313
|
+
- A watched preview file is checked every 900 ms.
|
|
314
|
+
- Background tasks are the exception: they use the harness's existing `session/jobs` push.
|
|
315
|
+
- **No terminal resize.** The subprocess API has no resize call. The emulator follows the dock, but the shell keeps its starting size until you **Restart** it.
|
|
316
|
+
- **Server mode frames are cross-origin.** A started dev server's own URL is framed directly. Use **Open inspectable** to load it through the proxy.
|
|
317
|
+
- **Websocket proxying works only at the proxy root.** A dev server that opens its live-reload socket on a subpath is not tunneled. The page still renders, and HTTP streaming (including SSE) is proxied.
|
|
318
|
+
- **`ui_preview eval` runs as a function body.** Declarations do not persist between calls.
|
|
319
|
+
- **Console capture sees only the page's `console` and error events**, not network failures or workers.
|
|
320
|
+
- **Byte-range requests need `fs.readByteRange`.** Without it, the file route answers a full `200`, so media plays but cannot seek.
|
|
321
|
+
- **The dock depends on the frame's DOM.** It reserves width by setting a CSS property and a data attribute on the `shell.overlay` frame element. A harness layout change could require an update.
|
|
322
|
+
- **Large browser bundle.** The terminal emulator makes up most of it, and the harness serves one file per plugin, so it cannot be loaded lazily.
|
|
323
|
+
- **Generate costs model tokens.** Each press calls the deployment's provider. Set `allowCommitMessageDraft: false` to remove it.
|
|
324
|
+
- **Stopping a task hides its completion from the model.** Set `allowTaskKill: false` to remove Stop.
|
|
172
325
|
|
|
173
326
|
## Development
|
|
174
327
|
|
|
175
|
-
|
|
328
|
+
The dev dependencies are `link:` specifiers to a DeepSeek Harness source checkout at `../../deepseek-harness`, relative to this directory. Clone the harness there before installing.
|
|
329
|
+
|
|
330
|
+
```bash
|
|
176
331
|
pnpm install
|
|
177
|
-
pnpm run build # tsc emit -> tsdown two-half bundle
|
|
178
332
|
pnpm run typecheck
|
|
179
|
-
pnpm test
|
|
333
|
+
pnpm test # checks generated/ against src/host, then runs vitest
|
|
334
|
+
pnpm run build # tsc -p tsconfig.build.json, then tsdown -> lib/
|
|
180
335
|
```
|
|
181
336
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
## Known limitations
|
|
337
|
+
`generated/` is the committed Typert RPC contract, written by `scripts/emit-typert.mjs` in the harness generator's format. If you change `src/host/types.ts` or the `@Remote` methods, update that script's spec and regenerate:
|
|
185
338
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
- **The commit-message draft spends model tokens on a human's press.** It is not a session event and the model that writes it never sees the conversation, but it is a real call against the deployment's provider; `allowCommitMessageDraft: false` removes it.
|
|
191
|
-
- **Push has no force, no remote picker, and no refspec.** Those are the verbs that lose work or push somewhere unintended, and the Terminal panel is one keystroke away for them.
|
|
192
|
-
- **Stopping a task suppresses its model notice.** See Background tasks above; `allowTaskKill: false` removes the verb.
|
|
193
|
-
- **Purge removes one artifact.** Exactly the path the persistence backend reported for that session — a sidecar the backend owns is the backend's to remove, and a recursive delete here could take a directory.
|
|
194
|
-
- **The browser bundle is ~1 MB (205 KB gzipped).** The emulator is most of it. The client module loader serves one file per plugin with no code splitting, so it cannot be deferred until the Terminal panel opens.
|
|
195
|
-
- **`--dsw-alias-label-error` is not used here.** ui-theme declares no such token, though three harness stylesheets reference it; this package uses `--dsw-alias-state-error-primary`, and `tests/styles.spec.ts` fails on any token ui-theme does not declare.
|
|
339
|
+
```bash
|
|
340
|
+
pnpm run regen:typert # rewrites generated/ and its fingerprint
|
|
341
|
+
pnpm run check:typert # the same check pnpm test runs first
|
|
342
|
+
```
|
|
196
343
|
|
|
197
|
-
|
|
344
|
+
To load your checkout into a local profile, build it, then add it by path:
|
|
198
345
|
|
|
199
|
-
|
|
346
|
+
```bash
|
|
347
|
+
pnpm run build
|
|
348
|
+
dsh plugin --profile web add "$(pwd)"
|
|
349
|
+
dsh web
|
|
350
|
+
```
|
|
200
351
|
|
|
201
|
-
|
|
352
|
+
The profile loads the built `lib/` output, so build first. After changing browser code, rebuild and reload the page. After changing anything under `src/host/`, or regenerating `generated/`, restart `dsh web`.
|
|
202
353
|
|
|
203
354
|
## License
|
|
204
355
|
|
package/cordis.patch.yml
CHANGED
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
panelWidth: 460
|
|
38
38
|
|
|
39
39
|
# What Delete does. `archive` hides the session and keeps its log — reversible in principle,
|
|
40
|
-
# since the durable slot is preserved. `purge`
|
|
41
|
-
#
|
|
42
|
-
#
|
|
40
|
+
# since the durable slot is preserved. `purge` asks for the session log to be removed too,
|
|
41
|
+
# but the harness (0.1.5-rc.2) has no supported removal verb, so it is unavailable: the
|
|
42
|
+
# settings card says so, and a Delete under `purge` archives and reports why the log was kept.
|
|
43
43
|
deleteMode: archive
|
|
44
44
|
confirmDelete: true
|
|
45
45
|
|
|
@@ -118,6 +118,18 @@
|
|
|
118
118
|
previewReadyTimeoutMs: 60000
|
|
119
119
|
previewScrollback: 200000
|
|
120
120
|
previewGraceMs: 3000
|
|
121
|
+
# Same-origin preview serving. `previewMaxFileBytes` bounds one workspace file handed to the
|
|
122
|
+
# frame — a video legitimately dwarfs any text preview, which is why the cap is separate
|
|
123
|
+
# from filesMaxPreviewBytes — and `previewProxyTimeoutMs` bounds one proxied request to a
|
|
124
|
+
# loopback dev server.
|
|
125
|
+
previewMaxFileBytes: 33554432
|
|
126
|
+
previewProxyTimeoutMs: 30000
|
|
127
|
+
# The agent channel behind `ui_preview`. `previewCommandTimeoutMs` is how long one command
|
|
128
|
+
# waits for the panel to answer before the tool reports a timeout instead of holding the
|
|
129
|
+
# model's turn open; `previewBindTtlMs` is how long a panel is trusted after its last poll,
|
|
130
|
+
# which is what turns a closed tab into "no preview surface" rather than a silent wait.
|
|
131
|
+
previewCommandTimeoutMs: 15000
|
|
132
|
+
previewBindTtlMs: 6000
|
|
121
133
|
previews: []
|
|
122
134
|
# Example rows — uncomment and adapt, or put the same thing in .claude/launch.json:
|
|
123
135
|
# previews:
|
|
@@ -156,3 +168,19 @@
|
|
|
156
168
|
# `<row name>/package.json`, so a subpath row here would leave every seat silently unserved.
|
|
157
169
|
- id: advanced-sidebar-ui
|
|
158
170
|
name: '@achasoft/dsh-advanced-sidebar'
|
|
171
|
+
|
|
172
|
+
# The agent-facing `ui_preview` tool. Its own row, so a deployment can mount the sidebar without
|
|
173
|
+
# giving a model a verb on it — drop this row and the tool does not exist. The row declares
|
|
174
|
+
# `inject: ['tools', 'advancedSidebar']`, which is what makes it wait for the service it calls
|
|
175
|
+
# instead of racing the Host row that provides it.
|
|
176
|
+
#
|
|
177
|
+
# Trust boundary: `open` with a path and every file argument are contained to the session
|
|
178
|
+
# workspace, `open` with a URL accepts only http(s) (the same latitude the panel's address bar
|
|
179
|
+
# gives a person), and the Host's reverse proxy refuses every non-loopback host on its own — so
|
|
180
|
+
# this tool cannot turn the GUI into an open proxy. `commandTimeoutMs` here is how long `open`
|
|
181
|
+
# waits for the browser to load the page; every other action waits for the Host's own
|
|
182
|
+
# `previewCommandTimeoutMs` instead.
|
|
183
|
+
- id: advanced-sidebar-ui-preview
|
|
184
|
+
name: '@achasoft/dsh-advanced-sidebar/ui-preview'
|
|
185
|
+
config:
|
|
186
|
+
commandTimeoutMs: 15000
|