dsh-side-chat-plus 0.3.1
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/LICENSE +21 -0
- package/README.md +317 -0
- package/README.zh.md +261 -0
- package/cordis.patch.yml +8 -0
- package/dsh.plugin.json +16 -0
- package/lib/client-registry.js +2949 -0
- package/lib/client-registry.js.map +1 -0
- package/lib/client.js +2949 -0
- package/lib/client.js.map +1 -0
- package/lib/index.js +840 -0
- package/lib/types/client/api.d.ts +218 -0
- package/lib/types/client/attachments/AttachmentRail.d.ts +39 -0
- package/lib/types/client/attachments/DropOverlay.d.ts +18 -0
- package/lib/types/client/attachments/ImageLightbox.d.ts +20 -0
- package/lib/types/client/attachments/MessageImage.d.ts +38 -0
- package/lib/types/client/attachments/index.d.ts +18 -0
- package/lib/types/client/index.d.ts +6 -0
- package/lib/types/client/locales.d.ts +178 -0
- package/lib/types/context-types.d.ts +390 -0
- package/lib/types/index.d.ts +7 -0
- package/lib/types/settings-shared.d.ts +24 -0
- package/lib/types/trust-fence.d.ts +20 -0
- package/lib/types/wire.d.ts +25 -0
- package/package.json +114 -0
- package/src/client/api.ts +112 -0
- package/src/client/attachments/AttachmentRail.module.css +89 -0
- package/src/client/attachments/AttachmentRail.tsx +173 -0
- package/src/client/attachments/DropOverlay.module.css +38 -0
- package/src/client/attachments/DropOverlay.tsx +62 -0
- package/src/client/attachments/ImageLightbox.module.css +44 -0
- package/src/client/attachments/ImageLightbox.tsx +58 -0
- package/src/client/attachments/MessageImage.module.css +61 -0
- package/src/client/attachments/MessageImage.tsx +120 -0
- package/src/client/attachments/index.ts +19 -0
- package/src/client/client.module.css +1032 -0
- package/src/client/index.tsx +1966 -0
- package/src/client/layout.css +16 -0
- package/src/client/locales.ts +181 -0
- package/src/context-types.ts +384 -0
- package/src/css-modules.d.ts +10 -0
- package/src/index.ts +840 -0
- package/src/settings-shared.ts +33 -0
- package/src/trust-fence.ts +70 -0
- package/src/wire.ts +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-sub-chats contributors
|
|
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.md
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# dsh-side-chat — 侧边聊天 (Side chat)
|
|
2
|
+
|
|
3
|
+
An **enhanced version of a Codex-style side chat** for
|
|
4
|
+
[DSH](https://www.deepseek.com): a dedicated, agentic chat in a right-side
|
|
5
|
+
panel, scoped to the conversation it was started from and aware of its
|
|
6
|
+
workspace. Select part of a conversation and ask about it in the side chat; the
|
|
7
|
+
side chat inherits the main conversation's toolset, model, and permission
|
|
8
|
+
preset, and its AI replies can be **brought back to the main conversation**
|
|
9
|
+
(directly or as a summary, into the composer draft or as a collapsed context
|
|
10
|
+
row).
|
|
11
|
+
|
|
12
|
+
On top of the Codex-style base, it adds one extra capability: when the main
|
|
13
|
+
agent asks you a **question dialog**, you can side-chat about the question and
|
|
14
|
+
its options **without interrupting the flow** — let the AI help you think it
|
|
15
|
+
through first, then bring the answer back and answer the dialog.
|
|
16
|
+
|
|
17
|
+
> 中文文档见 [README.zh.md](./README.zh.md).
|
|
18
|
+
|
|
19
|
+
## What it does
|
|
20
|
+
|
|
21
|
+
- **Select text → ask in a side chat.** Select any part of a message and a
|
|
22
|
+
floating button *"Ask in side chat"* appears. The selected text is carried
|
|
23
|
+
into the side chat automatically.
|
|
24
|
+
- **Per-conversation isolation.** Each side chat is a hidden ordinary DSH
|
|
25
|
+
session (`meta.parentSession` links it to the conversation that started it,
|
|
26
|
+
and the session is archived so it never appears in the main session list).
|
|
27
|
+
Every conversation gets its own side chat.
|
|
28
|
+
- **Inherits main-conversation context.** The side chat is aware of the
|
|
29
|
+
conversation it was started from and its working directory, and inherits the
|
|
30
|
+
main conversation's toolset, model, thinking effort, and permission preset by
|
|
31
|
+
default — so it can act on the same workspace as the main conversation.
|
|
32
|
+
- **Model / effort / permission are adjustable.** A two-level model menu
|
|
33
|
+
(provider → model → effort) and a permission menu are copied from the main
|
|
34
|
+
conversation, so each side chat can be tuned independently.
|
|
35
|
+
- **"Look up workspace / parent when needed" switch** (default off). When on,
|
|
36
|
+
the side chat may read files from the workspace and the parent conversation
|
|
37
|
+
when it needs more information.
|
|
38
|
+
- **Normal conversation capabilities.** Markdown replies, thinking/reasoning
|
|
39
|
+
display, image attachments (paste / drag-and-drop), send/stop controls, and
|
|
40
|
+
thinking-duration display — all reuse the same UI primitives as the main
|
|
41
|
+
conversation.
|
|
42
|
+
- **Bring AI replies back to the main conversation.** Every assistant reply in
|
|
43
|
+
the side chat can be brought into the current main conversation: select part
|
|
44
|
+
of it with the mouse, or insert the whole reply in one click. Either way you
|
|
45
|
+
can choose **"Insert directly"** (verbatim) or **"Summarize & insert"** (the
|
|
46
|
+
side chat's inherited model summarizes it first). Where it lands is
|
|
47
|
+
configurable: **into the composer draft**, or **as a collapsed context row**
|
|
48
|
+
(injected as context — not into the composer, never sent).
|
|
49
|
+
- **Ask about the current question dialog — without interrupting the flow.**
|
|
50
|
+
When the main conversation shows a question dialog (the agent asking you
|
|
51
|
+
something), the side panel automatically lists the question and each option
|
|
52
|
+
(no manual text selection needed). Each question has "Bring all" and each
|
|
53
|
+
option has "Bring", both offering to **continue an existing side chat** or
|
|
54
|
+
**start a new one**. The list can be **collapsed / expanded**, and items can
|
|
55
|
+
be **deleted individually or all at once** (deleted items stay gone).
|
|
56
|
+
- **Deletable side chats.** Each entry in the side-chat list can be deleted
|
|
57
|
+
individually, or all of them at once via "Delete all".
|
|
58
|
+
- **Resolution-aware, resizable, collapsible panel.** Drag to resize
|
|
59
|
+
(280–720 px); the width is automatically capped to keep the panel within
|
|
60
|
+
~40% of the window and to leave the main chat usable, re-adapts when the
|
|
61
|
+
window is resized (different monitor, zoom), and is remembered across
|
|
62
|
+
reloads. Collapse and expand; no close button.
|
|
63
|
+
- **Language-aware.** The plugin follows DSH's language setting (Chinese /
|
|
64
|
+
English).
|
|
65
|
+
|
|
66
|
+
## Codex-style side chat, enhanced
|
|
67
|
+
|
|
68
|
+
This plugin is an **enhanced version of a Codex-style side chat**: a second,
|
|
69
|
+
agentic chat that works beside the main conversation — plus an extra capability
|
|
70
|
+
on top of the Codex-style base: side-chatting about the current **question
|
|
71
|
+
dialog** without interrupting the flow.
|
|
72
|
+
|
|
73
|
+
**The Codex-style base.** The side chat is a real DSH agent session, not a
|
|
74
|
+
scratchpad:
|
|
75
|
+
|
|
76
|
+
- It **inherits the main conversation's setup** — toolset, permission preset,
|
|
77
|
+
model / thinking effort, and working directory — so it can read and work with
|
|
78
|
+
the same workspace as the main conversation, subject to the permission preset
|
|
79
|
+
you choose for it.
|
|
80
|
+
- The **"Look up workspace / parent when needed"** switch (default off) lets it
|
|
81
|
+
read workspace files and the parent conversation's records when the task needs
|
|
82
|
+
more context.
|
|
83
|
+
- **Model / thinking effort / permission preset are adjustable per chat**, so a
|
|
84
|
+
hard task can be handed to a stronger model without touching the main
|
|
85
|
+
conversation.
|
|
86
|
+
- The final reply (or a summary of it) can be **brought back** into the main
|
|
87
|
+
conversation — into the composer draft or as a collapsed context row — the
|
|
88
|
+
Codex-style "hand the result over" without copy-pasting.
|
|
89
|
+
|
|
90
|
+
**The enhancement: question-dialog side chat, no flow interruption.** When the
|
|
91
|
+
main agent asks you something, the flow normally stops until you answer. This
|
|
92
|
+
plugin lets you keep moving: the side panel automatically lists the question and
|
|
93
|
+
every option; bring the whole question or any single option into a side chat
|
|
94
|
+
(new or existing), let the AI analyze it for you, then bring the answer back and
|
|
95
|
+
answer the dialog. The main conversation simply waits — nothing is interrupted,
|
|
96
|
+
and you never have to answer before you're ready.
|
|
97
|
+
|
|
98
|
+
## Requirements
|
|
99
|
+
|
|
100
|
+
- [Node.js](https://nodejs.org) ≥ 20
|
|
101
|
+
- [pnpm](https://pnpm.io)
|
|
102
|
+
- DSH ≥ `0.1.0-rc.6` (the harness `engines.dsh` constraint)
|
|
103
|
+
|
|
104
|
+
## Build
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
pnpm install
|
|
108
|
+
pnpm build
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
`pnpm build` clears `lib/`, runs `tsc -p tsconfig.build.json` for type
|
|
112
|
+
declarations, then bundles the host (`lib/index.js`) and client
|
|
113
|
+
(`lib/client.js` + `lib/client-registry.js`) with tsdown.
|
|
114
|
+
|
|
115
|
+
## CI and publishing
|
|
116
|
+
|
|
117
|
+
[GitHub Actions](.github/workflows) covers two jobs:
|
|
118
|
+
|
|
119
|
+
- **[`ci.yml`](.github/workflows/ci.yml)** runs on every push to `main` and on
|
|
120
|
+
pull requests: it installs dependencies, typechecks, builds, runs the test
|
|
121
|
+
script, and packs the tarball (uploaded as an artifact) for Node 20 and 22.
|
|
122
|
+
- **[`publish.yml`](.github/workflows/publish.yml)** fires when a `v*` tag is
|
|
123
|
+
pushed: it builds and publishes the package to **npm** as
|
|
124
|
+
[`dsh-side-chat-plus`](https://www.npmjs.com/package/dsh-side-chat-plus),
|
|
125
|
+
authenticated with the `NPM_TOKEN` repository secret.
|
|
126
|
+
|
|
127
|
+
The package name is `dsh-side-chat-plus` (the plain `dsh-side-chat` name on npm
|
|
128
|
+
belongs to a different maintainer, so the release is published under the
|
|
129
|
+
`-plus` name).
|
|
130
|
+
|
|
131
|
+
> **Registry dependencies.** The harness packages this plugin targets (the DSH
|
|
132
|
+
> `0.1.2` API line) are published to npm as prereleases (`0.1.2-rc.1`) and, in a
|
|
133
|
+
> few cases, declare internal dependencies with a plain `>=0.1.2` range that
|
|
134
|
+
> npm/pnpm refuses to match against a prerelease. The developer `pnpm-workspace.yaml`
|
|
135
|
+
> therefore points the `@deepseek-ai/dsh-*` packages at a local harness checkout
|
|
136
|
+
> (absolute `D:/code/...` paths that exist only on the maintainer's machine). CI
|
|
137
|
+
> swaps that file for one whose overrides pin every `@deepseek-ai/dsh-*`
|
|
138
|
+
> dependency to `0.1.2-rc.1`, so installs resolve from the registry. On another
|
|
139
|
+
> machine, point the overrides at your own harness clone or use the CI workspace
|
|
140
|
+
> file as a template.
|
|
141
|
+
|
|
142
|
+
## Deploy
|
|
143
|
+
|
|
144
|
+
DSH web loads external plugins from the active profile. This package is a
|
|
145
|
+
**bundle**: its `package.json` declares `dsh.bundle.patch` →
|
|
146
|
+
[`cordis.patch.yml`](./cordis.patch.yml), whose `insert` row mounts the plugin.
|
|
147
|
+
That declaration is what lets `dsh plugin add` install the package *and*
|
|
148
|
+
activate it in one step.
|
|
149
|
+
|
|
150
|
+
### Install from GitHub
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:heartmove/dsh-side-chat-plus
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
`dsh plugin` forwards to pnpm inside `~/.dsh/profiles/web/`, then reconciles the
|
|
157
|
+
bundle into the profile's `dsh.profile.bundles` layer list. A git install
|
|
158
|
+
fetches sources, so pnpm runs the package's `prepare` script (`tsdown`) to build
|
|
159
|
+
`lib/` from `src/` after checkout.
|
|
160
|
+
|
|
161
|
+
pnpm ≥ 10 refuses to run a git dependency's `prepare` script until it is
|
|
162
|
+
allowlisted, so the first `add` fails with an "Ignored build scripts" hint. Copy
|
|
163
|
+
the exact package key pnpm printed into the profile's `pnpm-workspace.yaml`
|
|
164
|
+
(`~/.dsh/profiles/web/pnpm-workspace.yaml`):
|
|
165
|
+
|
|
166
|
+
```yaml
|
|
167
|
+
allowBuilds:
|
|
168
|
+
dsh-side-chat-plus: true
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
then re-run the `add`. That allowance means "run this package's code on my
|
|
172
|
+
machine at install time" — only allow packages whose source you trust, and pin a
|
|
173
|
+
commit (`github:heartmove/dsh-side-chat-plus#<sha>`) so a later push cannot
|
|
174
|
+
silently change what runs.
|
|
175
|
+
|
|
176
|
+
Restart `dsh web`, then hard-refresh the page (Ctrl/Cmd+Shift+R).
|
|
177
|
+
|
|
178
|
+
### Install from npm
|
|
179
|
+
|
|
180
|
+
The built package is published to npm as [`dsh-side-chat-plus`](https://www.npmjs.com/package/dsh-side-chat-plus). Installed from the registry, the tarball ships the prebuilt `lib/` (plus `cordis.patch.yml` and `dsh.plugin.json`), so no source build is needed:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npx -p @deepseek-ai/dsh dsh plugin --profile web add dsh-side-chat-plus
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Version falls out of the tagged release (see below).
|
|
187
|
+
|
|
188
|
+
### Install from a local checkout
|
|
189
|
+
|
|
190
|
+
From the directory that contains this checkout:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npx -p @deepseek-ai/dsh dsh plugin --profile web add ./dsh-side-chat
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
pnpm links the checkout and `dsh` activates the bundle the same way.
|
|
197
|
+
|
|
198
|
+
### Manual link
|
|
199
|
+
|
|
200
|
+
To manage the profile by hand, link the package and list it as a bundle in
|
|
201
|
+
`~/.dsh/profiles/web/package.json` (the bundle's own `cordis.patch.yml` supplies
|
|
202
|
+
the loader row, so no `insert` entry is needed):
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{
|
|
206
|
+
"dependencies": {
|
|
207
|
+
"dsh-side-chat-plus": "link:D:\\path\\to\\dsh-side-chat-plus"
|
|
208
|
+
},
|
|
209
|
+
"dsh": {
|
|
210
|
+
"profile": {
|
|
211
|
+
"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-side-chat-plus"]
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
(On POSIX systems use `link:/path/to/dsh-side-chat-plus`.) Then run `pnpm install`
|
|
218
|
+
in the profile directory and restart `dsh web`.
|
|
219
|
+
|
|
220
|
+
## Usage
|
|
221
|
+
|
|
222
|
+
1. Select part of any message in the main conversation.
|
|
223
|
+
2. A floating **"Ask in side chat"** button appears — click it.
|
|
224
|
+
- If a side chat already exists for this conversation, you'll also see
|
|
225
|
+
**"Continue active side chat"**.
|
|
226
|
+
3. The right-side panel opens (or expands) with the selected text staged in the
|
|
227
|
+
composer.
|
|
228
|
+
4. Adjust **model / effort** and **permission**, and toggle **"Look up workspace
|
|
229
|
+
/ parent when needed"** as desired.
|
|
230
|
+
5. Send. The reply streams back with markdown rendering and, where applicable,
|
|
231
|
+
a "Think" row for the model's reasoning.
|
|
232
|
+
6. Drag the panel's left edge to resize, or use the collapse/expand control.
|
|
233
|
+
|
|
234
|
+
### Sending behavior
|
|
235
|
+
|
|
236
|
+
By default (`sendImmediately` on), selecting text **sends it immediately** and
|
|
237
|
+
appends your configured **default prompt**. Turn `sendImmediately` off in
|
|
238
|
+
settings to stage the selection as an attachment instead, so you can review and
|
|
239
|
+
edit before sending.
|
|
240
|
+
|
|
241
|
+
### Bring replies back to the main conversation
|
|
242
|
+
|
|
243
|
+
Assistant replies in the side chat can be brought into the current main
|
|
244
|
+
conversation (**never sent**):
|
|
245
|
+
|
|
246
|
+
1. **Bring a selection.** Select part of an assistant reply in the side chat,
|
|
247
|
+
then choose **"Insert directly"** (verbatim) or **"Summarize & insert"** (the
|
|
248
|
+
side chat's inherited model summarizes it first) from the floating menu.
|
|
249
|
+
2. **Bring the whole reply.** Each assistant reply has **"Insert directly"** and
|
|
250
|
+
**"Summarize & insert"** buttons under its text, for inserting the full reply
|
|
251
|
+
(or its summary) in one click.
|
|
252
|
+
3. Per the **bring-back target** setting, the content is either **appended to
|
|
253
|
+
the main composer draft** (edit before sending) or **injected as a collapsed
|
|
254
|
+
context row** (source-tagged, not into the composer; the model sees it next
|
|
255
|
+
turn).
|
|
256
|
+
|
|
257
|
+

|
|
258
|
+
|
|
259
|
+
### Ask about the current question dialog
|
|
260
|
+
|
|
261
|
+
When the main conversation shows a question dialog, the side panel automatically
|
|
262
|
+
lists the question and its options:
|
|
263
|
+
|
|
264
|
+
1. While the panel is closed, a **floating entry** appears beside the dialog's
|
|
265
|
+
header — click it to open the panel.
|
|
266
|
+
2. Each question has "Bring all" and each option has "Bring", both offering to
|
|
267
|
+
**continue an existing side chat** or **start a new one**.
|
|
268
|
+
3. The list can be **collapsed / expanded**, and items can be **deleted
|
|
269
|
+
individually or all at once** (deleted items stay gone).
|
|
270
|
+
|
|
271
|
+
The main conversation keeps waiting on the dialog — nothing is interrupted; do
|
|
272
|
+
the research in the side chat first, then bring the answer back and answer the
|
|
273
|
+
dialog.
|
|
274
|
+
|
|
275
|
+

|
|
276
|
+
|
|
277
|
+
### Delete side chats
|
|
278
|
+
|
|
279
|
+
Each entry in the side-chat list has a "×" delete button; "Delete all" at the
|
|
280
|
+
top-right removes every side chat of the current conversation.
|
|
281
|
+
|
|
282
|
+
## Settings
|
|
283
|
+
|
|
284
|
+
Open DSH **Settings → 侧边聊天 (Side chat)** to configure:
|
|
285
|
+
|
|
286
|
+
| Setting | Default | Description |
|
|
287
|
+
| --- | --- | --- |
|
|
288
|
+
| `lookupDefault` | off | Whether the "look up workspace / parent" switch is on by default for new side chats. |
|
|
289
|
+
| `sendImmediately` | on | Whether selecting text sends it immediately, or stages it as an attachment. |
|
|
290
|
+
| `defaultPrompt` | *(empty)* | Extra prompt appended when the selection is sent immediately. |
|
|
291
|
+
| `bringMode` | `draft` | Where brought-back content lands: `draft` into the composer, or `context` as a collapsed context row. |
|
|
292
|
+
|
|
293
|
+
Preferences are stored in the DSH settings namespace `dsh-side-chat`.
|
|
294
|
+
|
|
295
|
+
## Project layout
|
|
296
|
+
|
|
297
|
+
```
|
|
298
|
+
src/
|
|
299
|
+
index.ts host plugin (routes, session/agent lifecycle, transcript folding)
|
|
300
|
+
wire.ts request/response helpers
|
|
301
|
+
trust-fence.ts loopback / trusted-API request guard
|
|
302
|
+
settings-shared.ts preference vocabulary shared by host and client
|
|
303
|
+
context-types.ts Cordis Context type augmentation
|
|
304
|
+
client/
|
|
305
|
+
index.tsx client plugin (panel, composer, settings section, floating buttons)
|
|
306
|
+
api.ts client↔host API types
|
|
307
|
+
locales.ts zh/en dictionaries
|
|
308
|
+
client.module.css panel/composer/settings styles
|
|
309
|
+
layout.css #root margin-right driven by panel width
|
|
310
|
+
cordis.patch.yml bundle patch layer (inserts the loader row; dsh.bundle.patch)
|
|
311
|
+
dsh.plugin.json external plugin manifest
|
|
312
|
+
tsdown.config.ts bundle config (client externals + CSS inlining)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## License
|
|
316
|
+
|
|
317
|
+
[MIT](./LICENSE)
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
# dsh-side-chat — 侧边聊天(Side chat)
|
|
2
|
+
|
|
3
|
+
一个 [DSH](https://www.deepseek.com) 网页插件,**Codex 式侧边聊天的强化版本**:
|
|
4
|
+
在右侧面板提供按主会话隔离的独立聊天,具备 Codex 式的智能体能力——继承主会话的
|
|
5
|
+
工具集、模型、思考难度与权限预设,能感知所在工作目录;选中对话内容即可提问,AI 回复
|
|
6
|
+
也能**带回主会话**(直接带回或摘要后带回,写入草稿或注入为折叠提示行)。
|
|
7
|
+
|
|
8
|
+
在 Codex 式能力之上,它额外支持:当主会话的智能体弹出**问题弹框**向你提问时,可以
|
|
9
|
+
把问题与各个选项带入侧边聊天、让 AI 帮你分析,**不必打断当前流程**——想清楚后把答案
|
|
10
|
+
带回,再回答弹框即可。
|
|
11
|
+
|
|
12
|
+
> English docs: [README.md](./README.md).
|
|
13
|
+
|
|
14
|
+
## 功能
|
|
15
|
+
|
|
16
|
+
- **选中内容 → 侧边聊天提问。** 选中任意消息文本后,会浮出「在侧边聊天中提问」按钮,
|
|
17
|
+
选中的内容会自动带入侧边聊天。
|
|
18
|
+
- **按主会话隔离。** 每个侧边聊天都是一个隐藏的普通 DSH 会话(通过
|
|
19
|
+
`meta.parentSession` 关联发起它的主会话,并被归档,因此不会出现在主会话列表中)。
|
|
20
|
+
每个主会话各自拥有自己的侧边聊天。
|
|
21
|
+
- **继承主会话上下文。** 侧边聊天能感知它的发起会话与所在工作目录,并默认继承主会话的
|
|
22
|
+
工具集、模型、思考难度与权限预设,可以像主会话一样作用于同一个工作区。
|
|
23
|
+
- **模型 / 思考难度 / 权限可调。** 复刻主会话的二级模型菜单(服务商 → 模型 → 思考难度)
|
|
24
|
+
与权限菜单,每个侧边聊天可独立调整。
|
|
25
|
+
- **「需要时从工作区 / 主会话查信息」开关**(默认关闭)。开启后,侧边聊天在需要更多信息
|
|
26
|
+
时,可读取工作区文件与主会话内容。
|
|
27
|
+
- **与正常对话一致的能力。** Markdown 回复、思考(推理)过程展示、图片附件(粘贴 /
|
|
28
|
+
拖拽)、发送/停止按钮、思考时长显示 —— 均复用主会话同款 UI 组件。
|
|
29
|
+
- **AI 回复带回主会话。** 侧边聊天里的每条 AI 回复都能带回当前主会话:可鼠标选中
|
|
30
|
+
部分内容后带回,或一键带回整段;两种方式都可选择 **「直接带回」**(原文)或
|
|
31
|
+
**「摘要后带回」**(先用侧边聊天继承的模型生成摘要再带回)。带回的落地方式可在设置里
|
|
32
|
+
选择:**写入输入框草稿**,或**注入为折叠提示行**(作为上下文,不写草稿、不发送)。
|
|
33
|
+
- **针对问题弹框答疑(不打断流程)。** 当主会话弹出「问题弹框」(智能体向用户提问)时,
|
|
34
|
+
侧边面板会自动逐项列出问题和各个选项(无需手动选中文字)。每个问题可「带入全部」、每个
|
|
35
|
+
选项可「带入」,且都支持 **继续已有侧边聊天** 或 **新建侧边聊天** 两种方式,让 AI 帮你
|
|
36
|
+
分析后再回答——主会话静静等待,**流程不会被打断**。列表支持 **折叠 / 展开**,以及
|
|
37
|
+
**删除单个 / 删除全部**(删除后不再出现)。
|
|
38
|
+
- **侧边聊天可删除。** 侧边聊天列表里的每个会话可单独删除,也可一次性「删除全部」。
|
|
39
|
+
- **自适应分辨率、可拖拽、可收起的面板。** 拖拽左边缘调整宽度(280–720 px);面板宽度会
|
|
40
|
+
自动钳制在窗口的约 40% 以内、并为主聊天区留出可用空间;窗口尺寸变化(换显示器、调整
|
|
41
|
+
缩放)时会自动重新适配,上次的宽度也会被记住。可收起/展开;没有关闭按钮。
|
|
42
|
+
- **跟随语言设置。** 插件会跟随 DSH 的语言设置切换中文 / 英文界面。
|
|
43
|
+
|
|
44
|
+
## Codex 式侧边聊天(强化版)
|
|
45
|
+
|
|
46
|
+
本插件是 **Codex 式侧边聊天的强化版本**:在主会话旁边提供第二个智能体聊天;并在
|
|
47
|
+
Codex 式能力之上,额外支持针对当前**问题弹框**的侧边聊天——**全程不打断流程**。
|
|
48
|
+
|
|
49
|
+
**Codex 式基础能力。** 侧边聊天是一个真正的 DSH 智能体会话,而不是便签:
|
|
50
|
+
|
|
51
|
+
- **继承主会话的配置**:工具集、权限预设、模型 / 思考难度、工作目录,可以像主会话
|
|
52
|
+
一样读写同一个工作区——受你为它选择的权限预设约束。
|
|
53
|
+
- **「需要时从工作区 / 主会话查信息」开关**(默认关闭):任务需要更多上下文时,
|
|
54
|
+
它可以读取工作区文件与主会话记录。
|
|
55
|
+
- **模型 / 思考难度 / 权限预设可按聊天调整**:难任务可以交给更强的模型,完全
|
|
56
|
+
不影响主会话。
|
|
57
|
+
- **最终回复(或其摘要)可带回主会话**——写入输入框草稿,或注入为折叠提示行,像
|
|
58
|
+
Codex 那样「把结果交接回去」,无需手动复制粘贴。
|
|
59
|
+
|
|
60
|
+
**强化点:问题弹框侧边聊天,不打断流程。** 主会话智能体向你提问时,常规流程会停在
|
|
61
|
+
原地等你回答。本插件让你继续推进:侧边面板自动列出问题与每个选项;把整个问题或任意
|
|
62
|
+
一个选项带入侧边聊天(新建或继续),让 AI 帮你分析,再把答案带回、回答弹框。主会话
|
|
63
|
+
只是静静等待——流程不被中断,你也不必在准备好之前被迫作答。
|
|
64
|
+
|
|
65
|
+
## 环境要求
|
|
66
|
+
|
|
67
|
+
- [Node.js](https://nodejs.org) ≥ 20
|
|
68
|
+
- [pnpm](https://pnpm.io)
|
|
69
|
+
- DSH ≥ `0.1.0-rc.6`(即 `engines.dsh` 声明的约束)
|
|
70
|
+
|
|
71
|
+
## 构建
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pnpm install
|
|
75
|
+
pnpm build
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`pnpm build` 会先清空 `lib/`,再执行 `tsc -p tsconfig.build.json` 生成类型声明,
|
|
79
|
+
最后用 tsdown 打包出 host 端(`lib/index.js`)与 client 端
|
|
80
|
+
(`lib/client.js` + `lib/client-registry.js`)。
|
|
81
|
+
|
|
82
|
+
## CI 与发布
|
|
83
|
+
|
|
84
|
+
[GitHub Actions](.github/workflows) 覆盖两条流水线:
|
|
85
|
+
|
|
86
|
+
- **[`ci.yml`](.github/workflows/ci.yml)**:每次 push 到 `main` 及 pull request 时触发——
|
|
87
|
+
安装依赖、类型检查、构建、运行测试脚本,并在 Node 20 / 22 下打包 tarball(作为 artifact 上传)。
|
|
88
|
+
- **[`publish.yml`](.github/workflows/publish.yml)**:推送 `v*` 标签时触发——构建并把包发布到
|
|
89
|
+
**npm**,即 [`dsh-side-chat-plus`](https://www.npmjs.com/package/dsh-side-chat-plus),
|
|
90
|
+
用仓库的 `NPM_TOKEN` secret 鉴权。
|
|
91
|
+
|
|
92
|
+
包名为 `dsh-side-chat-plus`(npm 上的裸名 `dsh-side-chat` 属于另一维护者,因此发布以 `-plus` 命名)。
|
|
93
|
+
|
|
94
|
+
> **registry 依赖说明。** 本插件所依赖的 harness 包(DSH `0.1.2` 这一代 API)在 npm 上以预发布
|
|
95
|
+
> (`0.1.2-rc.1`)发布,且个别包内部用普通 `>=0.1.2` 范围引用同系列包,npm/pnpm 不会把
|
|
96
|
+
> 预发布版本当作满足该范围。因此开发用的 `pnpm-workspace.yaml` 把 `@deepseek-ai/dsh-*` 指向
|
|
97
|
+
> 本地 harness checkout(绝对路径 `D:/code/...`,仅存在于维护者本机)。CI 会把该文件替换成
|
|
98
|
+
> overrides 将每个 `@deepseek-ai/dsh-*` 依赖固定到 `0.1.2-rc.1` 的版本,从而让安装从 registry
|
|
99
|
+
> 解析。在其他机器上,把 overrides 指向你自己的 harness 克隆,或直接以 CI 的 workspace 文件为模板。
|
|
100
|
+
|
|
101
|
+
## 部署
|
|
102
|
+
|
|
103
|
+
DSH web 从当前 profile 加载外部插件。本包是一个 **bundle**:它的
|
|
104
|
+
`package.json` 声明了 `dsh.bundle.patch` → [`cordis.patch.yml`](./cordis.patch.yml),
|
|
105
|
+
其中的 `insert` 条目用于挂载插件。正是这个声明让 `dsh plugin add` 能一步完成
|
|
106
|
+
「安装 + 激活」。
|
|
107
|
+
|
|
108
|
+
### 从 GitHub 安装
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:heartmove/dsh-side-chat-plus
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
`dsh plugin` 会把命令转发到 `~/.dsh/profiles/web/` 下的 pnpm,然后把 bundle
|
|
115
|
+
对账进该 profile 的 `dsh.profile.bundles` 层列表。git 安装拉取的是源码,因此
|
|
116
|
+
pnpm 会在 checkout 之后运行包的 `prepare` 脚本(`tsdown`),从 `src/` 构建出
|
|
117
|
+
`lib/`。
|
|
118
|
+
|
|
119
|
+
pnpm ≥ 10 在把 git 依赖加入白名单之前,会拒绝运行它的 `prepare` 脚本,因此首次
|
|
120
|
+
`add` 会失败并给出「Ignored build scripts」提示。把 pnpm 打印的确切包名键复制到
|
|
121
|
+
该 profile 的 `pnpm-workspace.yaml`(`~/.dsh/profiles/web/pnpm-workspace.yaml`):
|
|
122
|
+
|
|
123
|
+
```yaml
|
|
124
|
+
allowBuilds:
|
|
125
|
+
dsh-side-chat-plus: true
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
然后重新执行 `add`。这个白名单意味着「允许该包的代码在安装时于本机运行」——
|
|
129
|
+
只放行你信任其源码的包,并固定到某个 commit
|
|
130
|
+
(`github:heartmove/dsh-side-chat-plus#<sha>`),这样之后的推送无法悄悄改变实际运行的代码。
|
|
131
|
+
|
|
132
|
+
重启 `dsh web`,然后在浏览器中强制刷新页面(Ctrl/Cmd+Shift+R)。
|
|
133
|
+
|
|
134
|
+
### 从 npm 安装
|
|
135
|
+
|
|
136
|
+
构建好的包已发布到 npm,名为 [`dsh-side-chat-plus`](https://www.npmjs.com/package/dsh-side-chat-plus)。
|
|
137
|
+
从 registry 安装时,tarball 自带预构建的 `lib/`(以及 `cordis.patch.yml`、`dsh.plugin.json`),无需源码构建:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
npx -p @deepseek-ai/dsh dsh plugin --profile web add dsh-side-chat-plus
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
版本号随打出的 tag 确定(见下文发布说明)。
|
|
144
|
+
|
|
145
|
+
### 从本地 checkout 安装
|
|
146
|
+
|
|
147
|
+
在包含本项目 checkout 的目录下执行:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
npx -p @deepseek-ai/dsh dsh plugin --profile web add ./dsh-side-chat
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
pnpm 会链接该 checkout,`dsh` 以同样方式激活这个 bundle。
|
|
154
|
+
|
|
155
|
+
### 手动链接
|
|
156
|
+
|
|
157
|
+
如果你想手动管理 profile,可在 `~/.dsh/profiles/web/package.json` 里链接该包并
|
|
158
|
+
把它列为 bundle(bundle 自带的 `cordis.patch.yml` 已提供加载器条目,因此无需再
|
|
159
|
+
写 `insert`):
|
|
160
|
+
|
|
161
|
+
```json
|
|
162
|
+
{
|
|
163
|
+
"dependencies": {
|
|
164
|
+
"dsh-side-chat-plus": "link:D:\\path\\to\\dsh-side-chat-plus"
|
|
165
|
+
},
|
|
166
|
+
"dsh": {
|
|
167
|
+
"profile": {
|
|
168
|
+
"bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "dsh-side-chat-plus"]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
(在 POSIX 系统上使用 `link:/path/to/dsh-side-chat-plus`。)然后在 profile 目录执行
|
|
175
|
+
`pnpm install` 并重启 `dsh web`。
|
|
176
|
+
|
|
177
|
+
## 使用
|
|
178
|
+
|
|
179
|
+
1. 在主对话中选中某条消息的部分文本。
|
|
180
|
+
2. 点击浮出的 **「在侧边聊天中提问」** 按钮。
|
|
181
|
+
- 若当前会话已有侧边聊天,还会出现 **「继续在激活的侧边聊天中提问」**。
|
|
182
|
+
3. 右侧面板会打开(或展开),选中的文本已带入输入框。
|
|
183
|
+
4. 按需调整 **模型 / 思考难度**、**权限**,以及 **「需要时从工作区 / 主会话查信息」**
|
|
184
|
+
开关。
|
|
185
|
+
5. 发送。回复会以流式返回,带 Markdown 渲染,并在需要时显示「思考」折叠行展示模型推理过程。
|
|
186
|
+
6. 拖动面板左边缘可调整宽度,或使用收起/展开控件。
|
|
187
|
+
|
|
188
|
+
### 发送行为
|
|
189
|
+
|
|
190
|
+
默认(`sendImmediately` 开启)时,选中内容会**立即发送**,并自动附加你配置的
|
|
191
|
+
**默认提示词**。在设置里关闭 `sendImmediately` 后,选中的内容会先作为附件放入输入框,
|
|
192
|
+
由你确认、编辑后再发送。
|
|
193
|
+
|
|
194
|
+
### 带回主会话
|
|
195
|
+
|
|
196
|
+
侧边聊天里的 AI 回复可以带回当前主会话(**不会立即发送**):
|
|
197
|
+
|
|
198
|
+
1. **带回选中片段。** 在侧边聊天里用鼠标选中 AI 回复的一部分文本,浮出的菜单里选择
|
|
199
|
+
**「直接带回」**(原文)或 **「摘要后带回」**(先用侧边聊天继承的模型生成摘要)。
|
|
200
|
+
2. **带回整段。** 每条 AI 回复正文下方有 **「直接带回」** 与 **「摘要后带回」** 两个按钮,
|
|
201
|
+
一键把该条回复的完整正文(或其摘要)带回。
|
|
202
|
+
3. 根据设置里的 **带回内容的方式**,带回的内容要么**追加进主会话输入框草稿**(可编辑后再
|
|
203
|
+
发送),要么**注入为主会话里一条折叠的提示行**(带来源标记,作为上下文、不写草稿,
|
|
204
|
+
下次对话时模型可见)。
|
|
205
|
+
|
|
206
|
+

|
|
207
|
+
|
|
208
|
+
### 针对问题弹框
|
|
209
|
+
|
|
210
|
+
当主会话弹出「问题弹框」时,侧边面板会自动列出问题和选项:
|
|
211
|
+
|
|
212
|
+
1. 面板关闭时,会先在弹框标题旁出现一个**浮动入口按钮**,点击即可打开面板查看。
|
|
213
|
+
2. 每个问题可「带入全部」、每个选项可「带入」,且都支持 **继续已有侧边聊天** 或
|
|
214
|
+
**新建侧边聊天** 两种方式。
|
|
215
|
+
3. 列表左上角可 **折叠 / 展开**;每个问题项可 **删除**,也可 **删除全部**(删除后不再出现)。
|
|
216
|
+
|
|
217
|
+
主会话会一直等待弹框的回答——先在侧边聊天里研究,再把答案带回、回答弹框,全程不打断流程。
|
|
218
|
+
|
|
219
|
+

|
|
220
|
+
|
|
221
|
+
### 删除侧边聊天
|
|
222
|
+
|
|
223
|
+
侧边聊天列表里每个条目有「×」删除按钮;右上角「删除全部」可一次性删除当前主会话的所有
|
|
224
|
+
侧边聊天。
|
|
225
|
+
|
|
226
|
+
## 设置
|
|
227
|
+
|
|
228
|
+
打开 DSH **设置 → 侧边聊天(Side chat)**,可配置:
|
|
229
|
+
|
|
230
|
+
| 设置项 | 默认值 | 说明 |
|
|
231
|
+
| --- | --- | --- |
|
|
232
|
+
| `lookupDefault` | 关 | 新建侧边聊天时,「需要时从工作区 / 主会话查信息」开关是否默认开启。 |
|
|
233
|
+
| `sendImmediately` | 开 | 选中内容后立即发送,还是先作为附件放入输入框。 |
|
|
234
|
+
| `defaultPrompt` | *(空)* | 「立即发送」开启时,附加在选中内容后的额外提示词。 |
|
|
235
|
+
| `bringMode` | `draft` | 带回内容的落地方式:`draft` 写入输入框草稿,`context` 注入为折叠提示行。 |
|
|
236
|
+
|
|
237
|
+
偏好设置保存在 DSH 设置命名空间 `dsh-side-chat` 下。
|
|
238
|
+
|
|
239
|
+
## 项目结构
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
src/
|
|
243
|
+
index.ts host 插件(路由、会话/Agent 生命周期、转录折叠)
|
|
244
|
+
wire.ts 请求/响应辅助
|
|
245
|
+
trust-fence.ts 环回 / 可信 API 请求守卫
|
|
246
|
+
settings-shared.ts host 与 client 共用的偏好设置词汇
|
|
247
|
+
context-types.ts Cordis Context 类型扩展
|
|
248
|
+
client/
|
|
249
|
+
index.tsx client 插件(面板、输入框、设置分区、悬浮按钮)
|
|
250
|
+
api.ts client↔host API 类型
|
|
251
|
+
locales.ts 中英文词典
|
|
252
|
+
client.module.css 面板/输入框/设置样式
|
|
253
|
+
layout.css 由面板宽度驱动的 #root margin-right
|
|
254
|
+
cordis.patch.yml bundle patch 层(插入加载器条目;dsh.bundle.patch 指向它)
|
|
255
|
+
dsh.plugin.json 外部插件清单
|
|
256
|
+
tsdown.config.ts 打包配置(client 外部依赖 + CSS 内联)
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## 许可证
|
|
260
|
+
|
|
261
|
+
[MIT](./LICENSE)
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# Bundle patch layer for dsh-side-chat. This file is referenced by the
|
|
2
|
+
# package.json `dsh.bundle.patch` declaration, so `dsh plugin add` reconciles
|
|
3
|
+
# this package into the profile's bundle list and this row mounts the plugin.
|
|
4
|
+
# `name` is the package name: the Loader resolves it from the profile's
|
|
5
|
+
# node_modules (where pnpm installs the checkout / git dependency).
|
|
6
|
+
- insert:
|
|
7
|
+
- id: dsh-side-chat-plus
|
|
8
|
+
name: dsh-side-chat-plus
|
package/dsh.plugin.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "dsh-external/dsh-side-chat-plus",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"main": "./lib/index.js",
|
|
5
|
+
"description": "选中对话内容 → 在侧边聊天中提问:按主会话隔离的隐藏普通会话,继承模型/思考难度/权限(可调),带「需要时查工作区/主会话」开关。",
|
|
6
|
+
"engines": {
|
|
7
|
+
"dsh": "^0.1.0-rc.6 || ^0.1.1-0 || ^0.1.2-0"
|
|
8
|
+
},
|
|
9
|
+
"contributes": {
|
|
10
|
+
"tools": [],
|
|
11
|
+
"skills": []
|
|
12
|
+
},
|
|
13
|
+
"client": {
|
|
14
|
+
"main": "./lib/client-registry.js"
|
|
15
|
+
}
|
|
16
|
+
}
|