dsh-vscode-bridge-he 1.0.4 → 1.0.5
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 +100 -53
- package/client.js +76 -2
- package/index.js +6 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,53 +1,100 @@
|
|
|
1
|
-
# DSH VSCode Bridge
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
-
|
|
51
|
-
-
|
|
52
|
-
|
|
53
|
-
|
|
1
|
+
# DSH VSCode Bridge
|
|
2
|
+
|
|
3
|
+
Send a VS Code selection or a file path into the conversation you already have open in
|
|
4
|
+
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) (DSH) — as an `@path`
|
|
5
|
+
reference, inserted at the composer caret. It does **not** send the message for you.
|
|
6
|
+
|
|
7
|
+
> **This package is only the DSH half.** It needs the companion VS Code extension to do
|
|
8
|
+
> anything; installing this alone gives you an idle bridge. Both halves are in the
|
|
9
|
+
> [repository](https://github.com/heyitaowml-ctrl/dsh-vscode-bridge):
|
|
10
|
+
> `dsh-vscode-bridge/` (this package) and `vscode-dsh-bridge/` (the extension).
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
**1 · DSH half** — one command, then refresh the DSH page once:
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
dsh plugin --profile <profile> add dsh-vscode-bridge-he
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**2 · VS Code half** — pick one:
|
|
21
|
+
|
|
22
|
+
- **Extensions view:** open VS Code → Extensions → `…` → **Install from VSIX…** → choose
|
|
23
|
+
[`dist/dsh-vscode-bridge.vsix`](https://github.com/heyitaowml-ctrl/dsh-vscode-bridge/raw/master/dist/dsh-vscode-bridge.vsix)
|
|
24
|
+
- **Terminal:**
|
|
25
|
+
```sh
|
|
26
|
+
code --install-extension dsh-vscode-bridge.vsix
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Reload the VS Code window afterwards (`Ctrl+Shift+P` → **Developer: Reload Window**); the
|
|
30
|
+
commands appear under **DSH** in the editor and Explorer context menus.
|
|
31
|
+
|
|
32
|
+
The extension discovers the Host by itself: DSH writes its endpoint and token to
|
|
33
|
+
`~/.dsh/vscode-bridge.json` (override with `DSH_VSCODE_BRIDGE_FILE`) on every start, so
|
|
34
|
+
there is no token to copy by hand.
|
|
35
|
+
|
|
36
|
+
### Finding out whether the extension is connected
|
|
37
|
+
|
|
38
|
+
The composer shows a small `⚠ VS Code 未连接` pill until the extension has sent its first
|
|
39
|
+
reference. It disappears on first use and stays hidden afterwards; the `×` dismisses it for
|
|
40
|
+
the current page.
|
|
41
|
+
|
|
42
|
+
Zero references is the only signal the Host has, so the pill cannot tell "extension not
|
|
43
|
+
installed" apart from "installed but never used" — it deliberately says *not connected*
|
|
44
|
+
rather than *not installed*. If you have just installed the extension and the pill stays,
|
|
45
|
+
reload the VS Code window.
|
|
46
|
+
|
|
47
|
+
## Usage
|
|
48
|
+
|
|
49
|
+
- Select lines, right-click in the editor → **DSH: 发送选中代码到 DSH 对话**
|
|
50
|
+
- Right-click a file or folder in the Explorer → **DSH: 发送文件路径到 DSH 对话**
|
|
51
|
+
- Switch back to DSH: the reference is already at the caret, and nothing has been sent.
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
@C:\project\src\main.ts (lines 12-28)
|
|
55
|
+
@C:\project\src\main.ts
|
|
56
|
+
@"C:\project\my folder\main.ts" (line 7)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Line markers are inclusive and 1-based; the prompt section `vscode-references` tells the
|
|
60
|
+
model to read that range rather than guess.
|
|
61
|
+
|
|
62
|
+
## Architecture
|
|
63
|
+
|
|
64
|
+
```text
|
|
65
|
+
VS Code extension
|
|
66
|
+
└─ HTTP POST /dsh-vscode/attach (Bearer token)
|
|
67
|
+
└─ DSH Host plugin (this package)
|
|
68
|
+
└─ SSE /dsh-vscode/events
|
|
69
|
+
└─ DSH browser plugin
|
|
70
|
+
└─ conversation.input.left → InputActions.insertText()
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
When no DSH conversation is open, attachments are queued in memory and flushed to the next
|
|
74
|
+
browser session that connects.
|
|
75
|
+
|
|
76
|
+
## Endpoints
|
|
77
|
+
|
|
78
|
+
| Method | Path | Auth | Purpose |
|
|
79
|
+
| --- | --- | --- | --- |
|
|
80
|
+
| POST | `/dsh-vscode/attach` | Bearer token | Queue or deliver one reference |
|
|
81
|
+
| GET | `/dsh-vscode/events` | `token` + `channel` query | SSE stream consumed by the browser half |
|
|
82
|
+
| GET | `/dsh-vscode/config` | same-origin page | Supplies the browser half with the current token/channel |
|
|
83
|
+
| GET | `/dsh-vscode/health` | none | Connection, queue and `attachments` count for the status command |
|
|
84
|
+
|
|
85
|
+
`/health` and the SSE `hello` frame both report `attachments` (how many references the
|
|
86
|
+
extension has ever sent to this Host instance) and `lastAttachAt`. That pair drives the
|
|
87
|
+
composer hint above.
|
|
88
|
+
|
|
89
|
+
## Notes
|
|
90
|
+
|
|
91
|
+
- Paths are sent absolute, so DSH does not have to share a workspace with VS Code.
|
|
92
|
+
- The browser half renders nothing except the connection hint.
|
|
93
|
+
- **The bridge is loopback-only by design.** The Host binds locally, every request carries a
|
|
94
|
+
per-process bearer token, and the token file is regenerated on each start.
|
|
95
|
+
- This package is unrelated to [`dsh-vscode-bridge`](https://www.npmjs.com/package/dsh-vscode-bridge)
|
|
96
|
+
on npm, which is a different plugin by a different author.
|
|
97
|
+
|
|
98
|
+
## License
|
|
99
|
+
|
|
100
|
+
MulanPSL-2.0
|
package/client.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
window.__ModuleLoader__.load({
|
|
2
|
-
id: '
|
|
2
|
+
id: 'dsh-vscode-bridge-he',
|
|
3
3
|
factory(require) {
|
|
4
4
|
const React = require('react');
|
|
5
5
|
|
|
6
6
|
const RETRY_MS = 500;
|
|
7
7
|
const MAX_SEEN = 200;
|
|
8
|
+
// Where the install hint points. Kept in sync with the README's Install section.
|
|
9
|
+
const INSTALL_DOC_URL = 'https://github.com/heyitaowml-ctrl/dsh-vscode-bridge#install';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Invisible composer participant: it owns the SSE subscription for the
|
|
@@ -26,6 +28,14 @@ window.__ModuleLoader__.load({
|
|
|
26
28
|
// insertion add a separator only when the current draft needs one.
|
|
27
29
|
const draft = props.useInput((snapshot) => snapshot.draft);
|
|
28
30
|
|
|
31
|
+
// How many references the VS Code extension has ever sent to this Host
|
|
32
|
+
// instance. `null` means the SSE handshake has not answered yet.
|
|
33
|
+
// Zero is the only honest signal we have: it cannot tell "extension not
|
|
34
|
+
// installed" apart from "installed but never used", so the hint says
|
|
35
|
+
// 未连接 (not connected) rather than 未安装 (not installed).
|
|
36
|
+
const [attachments, setAttachments] = React.useState(null);
|
|
37
|
+
const [dismissed, setDismissed] = React.useState(false);
|
|
38
|
+
|
|
29
39
|
const queueRef = React.useRef([]);
|
|
30
40
|
const seenRef = React.useRef(new Set());
|
|
31
41
|
const timerRef = React.useRef(null);
|
|
@@ -130,6 +140,7 @@ window.__ModuleLoader__.load({
|
|
|
130
140
|
}
|
|
131
141
|
}
|
|
132
142
|
queueRef.current.push(item.text);
|
|
143
|
+
setAttachments((current) => (current === null ? 1 : current + 1));
|
|
133
144
|
flushRef.current();
|
|
134
145
|
} catch (error) {
|
|
135
146
|
console.warn('[dsh-vscode-bridge] invalid attachment event', error);
|
|
@@ -139,6 +150,12 @@ window.__ModuleLoader__.load({
|
|
|
139
150
|
try {
|
|
140
151
|
const hello = JSON.parse(event.data);
|
|
141
152
|
console.info('[dsh-vscode-bridge] connected', hello);
|
|
153
|
+
const reported = Number(hello?.attachments ?? 0);
|
|
154
|
+
setAttachments((current) => {
|
|
155
|
+
const known = Number.isFinite(reported) && reported > 0 ? reported : 0;
|
|
156
|
+
if (current === null) return known;
|
|
157
|
+
return Math.max(current, known);
|
|
158
|
+
});
|
|
142
159
|
} catch {
|
|
143
160
|
// A malformed hello is not worth surfacing.
|
|
144
161
|
}
|
|
@@ -163,7 +180,64 @@ window.__ModuleLoader__.load({
|
|
|
163
180
|
};
|
|
164
181
|
}, [sessionId]);
|
|
165
182
|
|
|
166
|
-
return null;
|
|
183
|
+
if (dismissed || attachments === null || attachments > 0) return null;
|
|
184
|
+
|
|
185
|
+
// Small, theme-neutral pill: it inherits the surrounding text colour and
|
|
186
|
+
// only lowers its own opacity, so it stays readable in light and dark.
|
|
187
|
+
return React.createElement(
|
|
188
|
+
'span',
|
|
189
|
+
{
|
|
190
|
+
style: {
|
|
191
|
+
display: 'inline-flex',
|
|
192
|
+
alignItems: 'center',
|
|
193
|
+
gap: 2,
|
|
194
|
+
height: 22,
|
|
195
|
+
padding: '0 2px 0 8px',
|
|
196
|
+
marginRight: 4,
|
|
197
|
+
fontSize: 11,
|
|
198
|
+
lineHeight: '22px',
|
|
199
|
+
borderRadius: 999,
|
|
200
|
+
border: '1px solid currentColor',
|
|
201
|
+
opacity: 0.6,
|
|
202
|
+
whiteSpace: 'nowrap',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
React.createElement(
|
|
206
|
+
'a',
|
|
207
|
+
{
|
|
208
|
+
href: INSTALL_DOC_URL,
|
|
209
|
+
target: '_blank',
|
|
210
|
+
rel: 'noreferrer noopener',
|
|
211
|
+
title: '还没收到过 VS Code 扩展发来的引用。没装过就点这里看安装步骤;装过的话,请在 VS Code 里执行 Developer: Reload Window。',
|
|
212
|
+
style: { color: 'inherit', textDecoration: 'none', cursor: 'pointer' },
|
|
213
|
+
onClick: (event) => event.stopPropagation(),
|
|
214
|
+
},
|
|
215
|
+
'⚠ VS Code 未连接',
|
|
216
|
+
),
|
|
217
|
+
React.createElement(
|
|
218
|
+
'button',
|
|
219
|
+
{
|
|
220
|
+
type: 'button',
|
|
221
|
+
title: '不再提示',
|
|
222
|
+
'aria-label': 'dismiss the VS Code extension hint',
|
|
223
|
+
onClick: (event) => {
|
|
224
|
+
event.preventDefault();
|
|
225
|
+
event.stopPropagation();
|
|
226
|
+
setDismissed(true);
|
|
227
|
+
},
|
|
228
|
+
style: {
|
|
229
|
+
border: 'none',
|
|
230
|
+
background: 'transparent',
|
|
231
|
+
color: 'inherit',
|
|
232
|
+
cursor: 'pointer',
|
|
233
|
+
fontSize: 13,
|
|
234
|
+
lineHeight: '18px',
|
|
235
|
+
padding: '0 4px',
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
'×',
|
|
239
|
+
),
|
|
240
|
+
);
|
|
167
241
|
}
|
|
168
242
|
|
|
169
243
|
return {
|
package/index.js
CHANGED
|
@@ -206,6 +206,7 @@ export function apply(ctx) {
|
|
|
206
206
|
let sequence = 0;
|
|
207
207
|
let lastClientId;
|
|
208
208
|
let lastSessionId;
|
|
209
|
+
let lastAttachAt;
|
|
209
210
|
let published = false;
|
|
210
211
|
let publishing = false;
|
|
211
212
|
let publishAttempts = 0;
|
|
@@ -386,6 +387,7 @@ export function apply(ctx) {
|
|
|
386
387
|
...attachment,
|
|
387
388
|
};
|
|
388
389
|
item.text = formatAttachmentText(item);
|
|
390
|
+
lastAttachAt = item.receivedAt;
|
|
389
391
|
const outcome = deliver(item);
|
|
390
392
|
void publishBridgeFile();
|
|
391
393
|
info(`attachment ${item.id}: ${item.kind} ${item.absolutePath}${item.startLine === undefined ? '' : ` lines ${item.startLine}-${item.endLine}`} delivered=${String(outcome.delivered)}`);
|
|
@@ -455,6 +457,8 @@ export function apply(ctx) {
|
|
|
455
457
|
connected: true,
|
|
456
458
|
sessionId: sessionId ?? null,
|
|
457
459
|
queued: queue.length,
|
|
460
|
+
attachments: sequence,
|
|
461
|
+
lastAttachAt: lastAttachAt ?? null,
|
|
458
462
|
})}\n\n`);
|
|
459
463
|
} catch {
|
|
460
464
|
removeClient(client.id);
|
|
@@ -518,6 +522,8 @@ export function apply(ctx) {
|
|
|
518
522
|
queued: queue.length,
|
|
519
523
|
sessionId: lastSessionId ?? null,
|
|
520
524
|
configFetches,
|
|
525
|
+
attachments: sequence,
|
|
526
|
+
lastAttachAt: lastAttachAt ?? null,
|
|
521
527
|
});
|
|
522
528
|
};
|
|
523
529
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
{
|
|
2
2
|
"name": "dsh-vscode-bridge-he",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Send a VS Code selection or file path into the open DSH conversation as an @path reference, without sending the message.",
|
|
6
6
|
"license": "MulanPSL-2.0",
|