@shendeguize/dsh-agent-sidecar 0.1.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/LICENSE +21 -0
- package/README.md +167 -0
- package/cordis.patch.yml +10 -0
- package/lib/client.js +8062 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +396 -0
- package/lib/index.js +4166 -0
- package/package.json +101 -0
- package/src/analysis.ts +782 -0
- package/src/bridge.ts +841 -0
- package/src/client/analysis/AnalysisPanel.tsx +191 -0
- package/src/client/analysis/analysis.module.css +183 -0
- package/src/client/analysis-glue.ts +331 -0
- package/src/client/api.ts +380 -0
- package/src/client/board/Board.tsx +214 -0
- package/src/client/board/board.module.css +302 -0
- package/src/client/board/logic.ts +556 -0
- package/src/client/board/project-view-logic.ts +361 -0
- package/src/client/board/project-view.module.css +307 -0
- package/src/client/board/project-view.tsx +189 -0
- package/src/client/board/strings.ts +112 -0
- package/src/client/commands.ts +484 -0
- package/src/client/controller.ts +360 -0
- package/src/client/css-modules.d.ts +11 -0
- package/src/client/detail/SessionDetail.tsx +270 -0
- package/src/client/detail/detail.module.css +433 -0
- package/src/client/detail/logic.ts +779 -0
- package/src/client/detail/strings.ts +98 -0
- package/src/client/detail/transport.ts +175 -0
- package/src/client/detail-glue.ts +397 -0
- package/src/client/detail-view.module.css +79 -0
- package/src/client/detail-view.tsx +233 -0
- package/src/client/dsh-tools/LineageTree.tsx +210 -0
- package/src/client/dsh-tools/SearchPanel.tsx +169 -0
- package/src/client/dsh-tools/dsh-tools.module.css +374 -0
- package/src/client/dsh-tools/logic.ts +596 -0
- package/src/client/dsh-tools/strings.ts +90 -0
- package/src/client/index.ts +315 -0
- package/src/client/inject/InjectPanel.tsx +482 -0
- package/src/client/inject/inject.module.css +446 -0
- package/src/client/inject/logic.ts +516 -0
- package/src/client/inject/overlay.module.css +22 -0
- package/src/client/inject-glue.ts +171 -0
- package/src/client/locales/command.ts +48 -0
- package/src/client/locales/en.ts +385 -0
- package/src/client/locales/index.ts +123 -0
- package/src/client/locales/zh.ts +402 -0
- package/src/client/m3-transport.ts +151 -0
- package/src/client/mount.tsx +307 -0
- package/src/client/project-glue.ts +134 -0
- package/src/client/search-glue.ts +143 -0
- package/src/client/settings-card.module.css +359 -0
- package/src/client/settings-card.tsx +565 -0
- package/src/client/settings-glue.ts +130 -0
- package/src/client/sidebar-tab.tsx +494 -0
- package/src/client/sse.ts +366 -0
- package/src/client/widget.tsx +80 -0
- package/src/config.ts +193 -0
- package/src/dsh-inject.ts +240 -0
- package/src/fusion.ts +988 -0
- package/src/guard.ts +274 -0
- package/src/index.ts +950 -0
- package/src/inject-gateway.ts +574 -0
- package/src/routes.ts +1133 -0
- package/src/send-cli.ts +340 -0
- package/src/session-store.ts +184 -0
- package/src/skills-provider.ts +293 -0
- package/src/supervisor.ts +463 -0
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill path two (design §7): register the `agent-sidecar` skill on dsh's
|
|
3
|
+
* `ctx.skills` registry via `registerProvider`, so installing the plugin
|
|
4
|
+
* yields the skill without running `scripts/install-skill.sh`.
|
|
5
|
+
*
|
|
6
|
+
* Coexistence with the filesystem path (design risk 8, resolved 2026-08-25
|
|
7
|
+
* by live test + source, recorded in
|
|
8
|
+
* `.local/tasks/make_dsh_mode/design/env_facts.md`): dsh's SkillRegistry
|
|
9
|
+
* natively resolves same-name skills to a SINGLE catalog entry — the merged
|
|
10
|
+
* catalog is a by-name Map, so a double listing is structurally impossible
|
|
11
|
+
* — and the filesystem copy always wins when present, via two mechanisms:
|
|
12
|
+
* within one layer, candidates sort by rank (lower wins) and same-name
|
|
13
|
+
* losers are dropped with a warn log (source `collectLayer`; filesystem
|
|
14
|
+
* roots rank 100-500 vs BUNDLED_SKILL_RANK 600); across layers, the
|
|
15
|
+
* nearest scope layer replaces farther ones outright — which is the
|
|
16
|
+
* operative rule in dsh-web compositions, where skill-filesystem is
|
|
17
|
+
* host-disabled and mounted per agent-preset scope while this provider
|
|
18
|
+
* sits in the global layer (live-verified: with `~/.dsh/skills/
|
|
19
|
+
* agent-sidecar` present the RPC catalog showed exactly one entry, the
|
|
20
|
+
* filesystem one; removing it flipped the same entry to this provider's
|
|
21
|
+
* without a restart). The yield rule therefore needs no filesystem
|
|
22
|
+
* probing: registering at BUNDLED_SKILL_RANK (600, the sanctioned rank for
|
|
23
|
+
* packaged providers, installed d.ts:16) is the complete, TOCTOU-free
|
|
24
|
+
* yield marker in every topology.
|
|
25
|
+
*
|
|
26
|
+
* The skill body is a dsh-scene condensation of the canonical
|
|
27
|
+
* `skills/agent-sidecar/SKILL.md` (same repo): observation flows through
|
|
28
|
+
* the CLI and this plugin's web board, injection flows through the plugin
|
|
29
|
+
* panel (sidecar `send` is `unsupported_dsh` for dsh sessions), and the
|
|
30
|
+
* S5/S6 wording — send only on an explicit same-turn request, never retry
|
|
31
|
+
* `delivery: "unknown"` — is preserved verbatim in spirit. The body is
|
|
32
|
+
* embedded (not read from disk) so the npm package needs no extra assets;
|
|
33
|
+
* `resourceBase` is `opaque` pointing readers at the canonical repo docs.
|
|
34
|
+
*
|
|
35
|
+
* Faces below are structural on purpose (repo rule: the plugin's type
|
|
36
|
+
* surface stays on the devDependency SDKs; service packages resolve at
|
|
37
|
+
* runtime from the dsh profile tree).
|
|
38
|
+
*
|
|
39
|
+
* @module
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/** Invocation controls mirrored from @deepseek-ai/dsh-skill (d.ts:37-42). */
|
|
43
|
+
export interface SkillInvocationFace {
|
|
44
|
+
readonly modelInvocable: boolean
|
|
45
|
+
readonly userInvocable: boolean
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Provider-declared resource base (opaque flavor only; d.ts:32-35). */
|
|
49
|
+
export interface SkillResourceBaseFace {
|
|
50
|
+
readonly kind: 'opaque'
|
|
51
|
+
readonly description: string
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Catalog candidate returned by `provider.list()` (d.ts:61-70). */
|
|
55
|
+
export interface SkillCandidateFace {
|
|
56
|
+
readonly name: string
|
|
57
|
+
readonly description: string
|
|
58
|
+
readonly whenToUse?: string
|
|
59
|
+
readonly invocation: SkillInvocationFace
|
|
60
|
+
readonly source: string
|
|
61
|
+
readonly provider: string
|
|
62
|
+
readonly resourceBase?: SkillResourceBaseFace
|
|
63
|
+
/** Lower ranks win same-name duplicates within one layer (d.ts:62-63). */
|
|
64
|
+
readonly rank: number
|
|
65
|
+
/** Opaque provider-owned handle passed back to `provider.get()`. */
|
|
66
|
+
readonly locator: unknown
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Full definition returned by `provider.get()` (d.ts:71-79). */
|
|
70
|
+
export interface SkillDefinitionFace {
|
|
71
|
+
readonly name: string
|
|
72
|
+
readonly description: string
|
|
73
|
+
readonly invocation: SkillInvocationFace
|
|
74
|
+
readonly source: string
|
|
75
|
+
readonly provider: string
|
|
76
|
+
readonly resourceBase?: SkillResourceBaseFace
|
|
77
|
+
readonly content: string
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Lookup options are borrowed opaquely; this provider is context-free. */
|
|
81
|
+
export interface SkillLookupOptionsFace {
|
|
82
|
+
readonly cwd?: string | undefined
|
|
83
|
+
readonly signal?: AbortSignal | undefined
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** One same-process skill source (d.ts:168-188). */
|
|
87
|
+
export interface SkillProviderFace {
|
|
88
|
+
readonly name: string
|
|
89
|
+
readonly list: (
|
|
90
|
+
options: SkillLookupOptionsFace,
|
|
91
|
+
) => Promise<readonly SkillCandidateFace[]>
|
|
92
|
+
readonly get: (
|
|
93
|
+
candidate: SkillCandidateFace,
|
|
94
|
+
options: SkillLookupOptionsFace,
|
|
95
|
+
) => Promise<SkillDefinitionFace | undefined>
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Registration-scoped lifecycle control handed to the factory (d.ts:189-195). */
|
|
99
|
+
export interface SkillProviderControlFace {
|
|
100
|
+
readonly signal: AbortSignal
|
|
101
|
+
readonly invalidate: () => void
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* `ctx.skills` face (provider registration only). Source: installed
|
|
106
|
+
* @deepseek-ai/dsh-skill 0.1.1-rc.2 lib/types/index.d.ts:249 —
|
|
107
|
+
* `registerProvider(create): () => void`. Registration is synchronous
|
|
108
|
+
* during plugin apply, rides the CALLER's fiber (duplicate provider names
|
|
109
|
+
* in one layer throw), and the returned disposer is the exact cordis
|
|
110
|
+
* effect disposer that unregisters the provider.
|
|
111
|
+
*/
|
|
112
|
+
export interface SkillsServiceFace {
|
|
113
|
+
registerProvider(
|
|
114
|
+
create: (control: SkillProviderControlFace) => SkillProviderFace,
|
|
115
|
+
): () => void
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Log face shared with the rest of the host half. */
|
|
119
|
+
export type SkillsProviderLog = (
|
|
120
|
+
level: 'debug' | 'info' | 'warn' | 'error',
|
|
121
|
+
msg: string,
|
|
122
|
+
meta?: Record<string, unknown>,
|
|
123
|
+
) => void
|
|
124
|
+
|
|
125
|
+
/** Registry name of this provider (distinct from the skill it serves). */
|
|
126
|
+
export const SKILL_PROVIDER_NAME = 'agent-sidecar-plugin'
|
|
127
|
+
|
|
128
|
+
/** The one skill this provider serves (same name as the filesystem copy). */
|
|
129
|
+
export const SIDECAR_SKILL_NAME = 'agent-sidecar'
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* BUNDLED_SKILL_RANK, pinned from @deepseek-ai/dsh-skill 0.1.1-rc.2
|
|
133
|
+
* (lib/types/index.d.ts:16, "Standard precedence rank for packaged skill
|
|
134
|
+
* providers and local bundled roots"). This IS the yield rule: filesystem
|
|
135
|
+
* roots rank 100/200/300/400/500, all lower, so any user-managed copy of
|
|
136
|
+
* the skill shadows this packaged one (live-verified 2026-08-25).
|
|
137
|
+
*/
|
|
138
|
+
export const SIDECAR_SKILL_RANK = 600
|
|
139
|
+
|
|
140
|
+
/** Routing description; aligned with skills/agent-sidecar/SKILL.md frontmatter. */
|
|
141
|
+
export const SIDECAR_SKILL_DESCRIPTION =
|
|
142
|
+
'Monitors readonly local AI agent sessions (claude/codex/cursor/dsh/kimi/copilot) and reports ' +
|
|
143
|
+
'their state and progress via the agent-sidecar CLI and the Sidecar board in dsh web. Use when ' +
|
|
144
|
+
'the user asks for agent status, session progress, to monitor agents, which agent is waiting or ' +
|
|
145
|
+
'working, or explicitly asks to send a message or feedback to an agent.'
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* dsh-scene skill body: semantically consistent with the canonical
|
|
149
|
+
* `skills/agent-sidecar/SKILL.md`, condensed for the plugin context —
|
|
150
|
+
* observation goes CLI/board, injection goes the plugin panel (design §7
|
|
151
|
+
* path two: "dsh 会话注入应引导走插件通路而非 send,因 unsupported_dsh").
|
|
152
|
+
*/
|
|
153
|
+
export const SIDECAR_SKILL_CONTENT = `# Agent Sidecar (dsh plugin edition)
|
|
154
|
+
|
|
155
|
+
This dsh composition runs the \`dsh-agent-sidecar\` plugin. Observation is
|
|
156
|
+
the default; every mutation needs an explicit user request in the same turn.
|
|
157
|
+
|
|
158
|
+
## Observe
|
|
159
|
+
|
|
160
|
+
1. Check \`command -v agent-sidecar\`. If missing, do not install anything
|
|
161
|
+
unless the user explicitly asks; point them at the agent_sidecar repo
|
|
162
|
+
install options instead.
|
|
163
|
+
2. Run \`agent-sidecar status --json\` first; summarize sessions by agent,
|
|
164
|
+
status, title, project, and age from \`updated_at\`.
|
|
165
|
+
3. Other observation commands, only when they match the request:
|
|
166
|
+
\`list --json\` (48h window), \`list --all --json\`, \`ps --json\`,
|
|
167
|
+
\`watch <session-prefix> --json\`, \`watch --all --json\`, \`tui\`.
|
|
168
|
+
4. The plugin also serves a live multi-agent board in dsh web (the
|
|
169
|
+
"Sidecar" conversation tab). Prefer pointing the user there for
|
|
170
|
+
continuous monitoring instead of polling the CLI yourself.
|
|
171
|
+
5. Treat \`working\`/\`waiting\` as inferred observations from persisted
|
|
172
|
+
data, not control-plane guarantees; Cursor IDE can report \`waiting\`
|
|
173
|
+
several minutes late.
|
|
174
|
+
|
|
175
|
+
## Inject (explicit request only)
|
|
176
|
+
|
|
177
|
+
- For **dsh sessions**, \`agent-sidecar send\` is unsupported
|
|
178
|
+
(\`unsupported_dsh\`: DSH has neither session resume nor stdin prompt
|
|
179
|
+
transport). Route the user to the plugin's inject panel on the Sidecar
|
|
180
|
+
board, which injects in-process (queue/steer) behind the plugin's
|
|
181
|
+
\`inject.enabled\` gate and confirmation dialog.
|
|
182
|
+
- For **claude / codex / cursor-cli** sessions in \`waiting\`/\`idle\`, use
|
|
183
|
+
the plugin panel, or run \`send\` only when the user explicitly requests
|
|
184
|
+
the exact message or action in the same turn. Never infer consent from a
|
|
185
|
+
request to observe, watch, report, or wait. That explicit same-turn
|
|
186
|
+
request is the permission required to use \`--allow-write\`; never add it
|
|
187
|
+
otherwise:
|
|
188
|
+
|
|
189
|
+
\`\`\`sh
|
|
190
|
+
agent-sidecar send <session-prefix> "<exact-message>" --allow-write --request-id "<stable-unique-id>" --json
|
|
191
|
+
\`\`\`
|
|
192
|
+
|
|
193
|
+
- Preserve the returned \`request_id\` and \`replayed\` fields. Never send
|
|
194
|
+
to remote, \`working\`, \`dead\`, child, or unsupported-agent sessions
|
|
195
|
+
(\`cursor-ide\`, \`copilot\`, \`kimi\`, \`dsh\`).
|
|
196
|
+
- Never retry \`failed\`, \`timed_out\`, \`request_pending\`,
|
|
197
|
+
\`audit_error\`, \`cleanup_incomplete\`, or any result with
|
|
198
|
+
\`delivery: "unknown"\` — the agent may already have received the
|
|
199
|
+
message. Report the unknown state plainly and ask the user what to do.
|
|
200
|
+
- The audit store is fail-closed; never run \`agent-sidecar audit reset\`
|
|
201
|
+
automatically.
|
|
202
|
+
|
|
203
|
+
## Reference
|
|
204
|
+
|
|
205
|
+
Full schemas, exit codes, and boundaries: \`skills/agent-sidecar/SKILL.md\`
|
|
206
|
+
and \`reference.md\` in the agent_sidecar repository (also installable as a
|
|
207
|
+
filesystem skill via \`scripts/install-skill.sh\`; a filesystem copy under
|
|
208
|
+
\`~/.dsh/skills/\` automatically shadows this plugin-provided one).`
|
|
209
|
+
|
|
210
|
+
const RESOURCE_BASE: SkillResourceBaseFace = {
|
|
211
|
+
kind: 'opaque',
|
|
212
|
+
description:
|
|
213
|
+
'Self-contained skill provided by the dsh-agent-sidecar plugin; the canonical long-form ' +
|
|
214
|
+
'reference (SKILL.md + reference.md) lives in the agent_sidecar repository under skills/agent-sidecar/.',
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const INVOCATION: SkillInvocationFace = { modelInvocable: true, userInvocable: true }
|
|
218
|
+
|
|
219
|
+
/** The single catalog candidate this provider lists (skill-badge template). */
|
|
220
|
+
export const SIDECAR_SKILL_CANDIDATE: SkillCandidateFace = {
|
|
221
|
+
name: SIDECAR_SKILL_NAME,
|
|
222
|
+
description: SIDECAR_SKILL_DESCRIPTION,
|
|
223
|
+
invocation: INVOCATION,
|
|
224
|
+
source: 'bundled',
|
|
225
|
+
provider: SKILL_PROVIDER_NAME,
|
|
226
|
+
resourceBase: RESOURCE_BASE,
|
|
227
|
+
rank: SIDECAR_SKILL_RANK,
|
|
228
|
+
locator: SIDECAR_SKILL_NAME,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Dependencies of {@link registerSidecarSkillProvider}. */
|
|
232
|
+
export interface SkillsProviderDeps {
|
|
233
|
+
/** The bound `ctx.skills` registry. */
|
|
234
|
+
skills: SkillsServiceFace
|
|
235
|
+
/** Config gate `skill.provide` (read once at apply; restart semantics). */
|
|
236
|
+
provide: boolean
|
|
237
|
+
log: SkillsProviderLog
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** The provider instance: one static candidate, embedded body. */
|
|
241
|
+
const provider: SkillProviderFace = {
|
|
242
|
+
name: SKILL_PROVIDER_NAME,
|
|
243
|
+
list: () => Promise.resolve([SIDECAR_SKILL_CANDIDATE]),
|
|
244
|
+
get: (candidate) =>
|
|
245
|
+
Promise.resolve(
|
|
246
|
+
candidate.name === SIDECAR_SKILL_NAME
|
|
247
|
+
? {
|
|
248
|
+
name: SIDECAR_SKILL_NAME,
|
|
249
|
+
description: SIDECAR_SKILL_DESCRIPTION,
|
|
250
|
+
invocation: INVOCATION,
|
|
251
|
+
source: 'bundled',
|
|
252
|
+
provider: SKILL_PROVIDER_NAME,
|
|
253
|
+
resourceBase: RESOURCE_BASE,
|
|
254
|
+
content: SIDECAR_SKILL_CONTENT,
|
|
255
|
+
}
|
|
256
|
+
: undefined,
|
|
257
|
+
),
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Register the agent-sidecar skill provider on `ctx.skills`.
|
|
262
|
+
*
|
|
263
|
+
* Yield rule (per live test, env_facts.md): none needed beyond the rank —
|
|
264
|
+
* dsh's registry dedupes same-name skills natively, and this provider's
|
|
265
|
+
* BUNDLED rank (600) loses to every filesystem root, so a filesystem copy
|
|
266
|
+
* always shadows the plugin copy and the catalog shows exactly one entry
|
|
267
|
+
* either way. `provide=false` skips registration entirely.
|
|
268
|
+
*
|
|
269
|
+
* @param deps - registry face, config gate, and log sink.
|
|
270
|
+
* @returns the registry's unregister disposer, or `null` when the gate is
|
|
271
|
+
* off or registration failed (duplicate provider name in this layer —
|
|
272
|
+
* only reachable if the plugin is mounted twice in one scope).
|
|
273
|
+
*/
|
|
274
|
+
export function registerSidecarSkillProvider(
|
|
275
|
+
deps: SkillsProviderDeps,
|
|
276
|
+
): (() => void) | null {
|
|
277
|
+
if (!deps.provide) {
|
|
278
|
+
deps.log('debug', 'skill provider disabled (skill.provide=false)')
|
|
279
|
+
return null
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
const dispose = deps.skills.registerProvider(() => provider)
|
|
283
|
+
deps.log('debug', 'skill provider registered', {
|
|
284
|
+
provider: SKILL_PROVIDER_NAME,
|
|
285
|
+
skill: SIDECAR_SKILL_NAME,
|
|
286
|
+
rank: SIDECAR_SKILL_RANK,
|
|
287
|
+
})
|
|
288
|
+
return dispose
|
|
289
|
+
} catch (err) {
|
|
290
|
+
deps.log('warn', `skill provider registration failed: ${String(err)}`)
|
|
291
|
+
return null
|
|
292
|
+
}
|
|
293
|
+
}
|