dsh-coding-sidebar 1.0.2 → 1.0.3
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 +3 -3
- package/lib/client-editor.js +411 -358
- package/lib/client-mermaid.js +294 -271
- package/lib/client-registry.js +339 -339
- package/lib/client-terminal.js +206 -206
- package/lib/client.js +341 -341
- package/lib/index.js +20 -12
- package/lib/types/context-types.d.ts +19 -10
- package/package.json +26 -27
- package/src/client/SideCardSection.module.css +2 -2
- package/src/client/SideChatView.module.css +12 -12
- package/src/context-types.ts +12 -7
- package/src/index.ts +5 -4
- package/src/jobs-routes.ts +3 -2
- package/src/sidechat-routes.ts +13 -8
- package/src/subagent-live-route.ts +2 -1
package/lib/index.js
CHANGED
|
@@ -2962,7 +2962,7 @@ const MIRROR_MAX_ENTRIES = 200;
|
|
|
2962
2962
|
* The live job_output mirror: subscribes to the session append feed and
|
|
2963
2963
|
* caches the job_output traces the session store's own log can lag behind
|
|
2964
2964
|
* (after a host restart the store session stays frozen at its rehydration
|
|
2965
|
-
* boundary, so
|
|
2965
|
+
* boundary, so a stale snapshot misses everything appended since — the very
|
|
2966
2966
|
* reads the pane exists to show). Zero DSH writes: the api-proxy pushes the
|
|
2967
2967
|
* same feed to browsers.
|
|
2968
2968
|
*/
|
|
@@ -3025,7 +3025,8 @@ function buildJobsApi(ctx, outputLimit) {
|
|
|
3025
3025
|
const sessionId = requireString(payload, "sessionId");
|
|
3026
3026
|
const id = requireString(payload, "id");
|
|
3027
3027
|
const bySeq = /* @__PURE__ */ new Map();
|
|
3028
|
-
|
|
3028
|
+
const store = ctx.sessions.get(sessionId);
|
|
3029
|
+
for (const event of (store?.snapshotEvents !== void 0 ? store.snapshotEvents() : []) ?? []) {
|
|
3029
3030
|
const trace = traceOf(event);
|
|
3030
3031
|
if (trace !== void 0) bySeq.set(trace.seq, trace);
|
|
3031
3032
|
}
|
|
@@ -3420,7 +3421,8 @@ function buildSubagentLiveApi(ctx) {
|
|
|
3420
3421
|
if (entry.kind !== "child" || entry.activity !== "running") continue;
|
|
3421
3422
|
if (entry.label?.startsWith("Side: ") ?? false) continue;
|
|
3422
3423
|
try {
|
|
3423
|
-
const
|
|
3424
|
+
const stored = ctx.sessions.get(entry.id);
|
|
3425
|
+
const activity = lastActivity(stored?.snapshotEvents !== void 0 ? stored.snapshotEvents() : [], 12);
|
|
3424
3426
|
if (activity.text !== void 0 || activity.tool !== void 0) live[entry.id] = activity;
|
|
3425
3427
|
} catch {}
|
|
3426
3428
|
}
|
|
@@ -3480,8 +3482,10 @@ async function composeChildSetup(ctx, presetId) {
|
|
|
3480
3482
|
async function composePersistedSetup(ctx, childId) {
|
|
3481
3483
|
const persistence = ctx.get("sessionPersistence");
|
|
3482
3484
|
if (persistence === void 0) return () => Promise.resolve();
|
|
3483
|
-
const
|
|
3484
|
-
const
|
|
3485
|
+
const handle = await persistence.open(childId, "read");
|
|
3486
|
+
const { events } = await handle.read();
|
|
3487
|
+
const presetId = resolvePresetId(handle.header, events);
|
|
3488
|
+
await handle.close();
|
|
3485
3489
|
const presets = ctx.get("agentPresets");
|
|
3486
3490
|
if (presets === void 0 || presetId === void 0) return () => Promise.resolve();
|
|
3487
3491
|
const resolved = await presets.resolve(presetId);
|
|
@@ -3542,8 +3546,8 @@ function buildSidechatApi(ctx) {
|
|
|
3542
3546
|
const parent = liveThreadAgent(ctx, sessionId);
|
|
3543
3547
|
if (parent === void 0) throw new SidebarError("sidechat-error", `parent session "${sessionId}" is not running`, 409);
|
|
3544
3548
|
const parentSession = parent.session;
|
|
3545
|
-
const inheritance = buildSidechatInheritance(parentSession.
|
|
3546
|
-
const { agentPreset, setup } = await composeChildSetup(ctx, resolvePresetId(parentSession.header, parentSession.
|
|
3549
|
+
const inheritance = buildSidechatInheritance(parentSession.snapshotEvents());
|
|
3550
|
+
const { agentPreset, setup } = await composeChildSetup(ctx, resolvePresetId(parentSession.header, parentSession.snapshotEvents()));
|
|
3547
3551
|
const childId = `session-${randomUUID()}`;
|
|
3548
3552
|
const label = question === "" ? SIDE_NEW_THREAD_TITLE : sideLabel(question);
|
|
3549
3553
|
const descriptor = snapshotSubagentDescriptor({
|
|
@@ -3565,7 +3569,7 @@ function buildSidechatApi(ctx) {
|
|
|
3565
3569
|
meta: {
|
|
3566
3570
|
...parentSession.header.cwd === void 0 ? {} : { cwd: parentSession.header.cwd },
|
|
3567
3571
|
parentSession: parentSession.id,
|
|
3568
|
-
|
|
3572
|
+
isSeeded: seed.length > 0,
|
|
3569
3573
|
origin: "subagent",
|
|
3570
3574
|
delegationDepth: (parentSession.header.delegationDepth ?? 0) + 1,
|
|
3571
3575
|
...agentPreset === void 0 ? {} : { agentPreset }
|
|
@@ -3622,7 +3626,7 @@ function buildSidechatApi(ctx) {
|
|
|
3622
3626
|
throw new SidebarError("sidechat-error", `thread resume failed: ${error instanceof Error ? error.message : String(error)}`, 500);
|
|
3623
3627
|
}
|
|
3624
3628
|
}
|
|
3625
|
-
if (boundaryDelivered(agent.session.
|
|
3629
|
+
if (boundaryDelivered(agent.session.snapshotEvents())) admitFollowup(agent, textPrompt(text));
|
|
3626
3630
|
else {
|
|
3627
3631
|
const parts = [SIDE_BOUNDARY_PROMPT];
|
|
3628
3632
|
const snapshot = pendingSnapshots.get(childId);
|
|
@@ -3668,8 +3672,10 @@ function buildSidechatApi(ctx) {
|
|
|
3668
3672
|
}
|
|
3669
3673
|
const persistence = ctx.get("sessionPersistence");
|
|
3670
3674
|
if (persistence !== void 0) try {
|
|
3671
|
-
const
|
|
3672
|
-
const
|
|
3675
|
+
const handle = await persistence.open(childId, "read");
|
|
3676
|
+
const { events } = await handle.read();
|
|
3677
|
+
const preset = resolvePresetId(handle.header, events);
|
|
3678
|
+
await handle.close();
|
|
3673
3679
|
return {
|
|
3674
3680
|
live: false,
|
|
3675
3681
|
...preset === void 0 ? {} : { preset }
|
|
@@ -3749,7 +3755,9 @@ async function sessionCwdOf(ctx, sessionId, clientCwd) {
|
|
|
3749
3755
|
}
|
|
3750
3756
|
const persistence = ctx.get("sessionPersistence");
|
|
3751
3757
|
if (persistence !== void 0) {
|
|
3752
|
-
const
|
|
3758
|
+
const handle = await persistence.open(sessionId, "read");
|
|
3759
|
+
const metaCwd = handle.header.cwd;
|
|
3760
|
+
await handle.close();
|
|
3753
3761
|
if (metaCwd !== void 0 && metaCwd !== "") try {
|
|
3754
3762
|
return requireAbsolute(metaCwd);
|
|
3755
3763
|
} catch {
|
|
@@ -78,11 +78,11 @@ export interface SidebarSessionStore {
|
|
|
78
78
|
get(id: string): {
|
|
79
79
|
header: SidebarSessionHeader;
|
|
80
80
|
/**
|
|
81
|
-
* The live session's
|
|
81
|
+
* The live session's immutable event snapshot (0.1.5 Session API; absent
|
|
82
82
|
* on sessions the runtime has not hydrated). Read-only access — the
|
|
83
83
|
* jobs.output route replays `job_output` tool/result rows from it.
|
|
84
84
|
*/
|
|
85
|
-
|
|
85
|
+
snapshotEvents?(fromSeq?: number, toSeqExclusive?: number): readonly SidebarSessionEvent[];
|
|
86
86
|
} | undefined;
|
|
87
87
|
}
|
|
88
88
|
/**
|
|
@@ -276,16 +276,25 @@ export interface SidebarSessionTitleService {
|
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
/** The host session-persistence face (mirror of the sessionPersistence
|
|
279
|
-
* service
|
|
280
|
-
* recorded preset when a Side Chat
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
279
|
+
* service, 0.1.5 handle-seam form): a short-lived read handle over one
|
|
280
|
+
* persisted session, used to compose the recorded preset when a Side Chat
|
|
281
|
+
* thread cold-resumes. */
|
|
282
|
+
export interface SidebarSessionPersistenceHandle {
|
|
283
|
+
readonly header: {
|
|
284
|
+
cwd?: string;
|
|
285
|
+
agentPreset?: string;
|
|
286
|
+
};
|
|
287
|
+
read(fromSeq?: number, toSeqExclusive?: number, options?: {
|
|
288
|
+
signal?: AbortSignal;
|
|
289
|
+
}): Promise<{
|
|
287
290
|
events: readonly SidebarSessionEvent[];
|
|
288
291
|
}>;
|
|
292
|
+
close(): Promise<void>;
|
|
293
|
+
}
|
|
294
|
+
export interface SidebarSessionPersistenceService {
|
|
295
|
+
open(sessionId: string, access: 'read', options?: {
|
|
296
|
+
signal?: AbortSignal;
|
|
297
|
+
}): Promise<SidebarSessionPersistenceHandle>;
|
|
289
298
|
}
|
|
290
299
|
/** RPC result slot mirror (`RpcResult<T>` on the wire). */
|
|
291
300
|
export type SidebarRpcResult<T> = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-coding-sidebar",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "DSH web plugin: a VSCode-like right sidebar (explorer / editor / terminal / git / browser), isolated per conversation session. Exposes the betterSidebar service for other plugins to register sidebar tabs and file viewers. KCoder-maintained fork of DSH-better-sidebar 0.17.2 (bottom panel removed, upstream-decoupled release line).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -85,19 +85,18 @@
|
|
|
85
85
|
"license": "MIT",
|
|
86
86
|
"peerDependencies": {
|
|
87
87
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
88
|
-
"@deepseek-ai/dsh-agent": "^0.1.
|
|
89
|
-
"@deepseek-ai/dsh-client-locale": "^0.1.
|
|
90
|
-
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.
|
|
91
|
-
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.
|
|
92
|
-
"@deepseek-ai/dsh-client-ui-settings": "^0.1.
|
|
93
|
-
"@deepseek-ai/dsh-client-ui-slots": "^0.1.
|
|
94
|
-
"@deepseek-ai/dsh-host-webserver": "^0.1.
|
|
95
|
-
"@deepseek-ai/dsh-
|
|
96
|
-
"@deepseek-ai/dsh-
|
|
97
|
-
"@deepseek-ai/dsh-
|
|
98
|
-
"@deepseek-ai/dsh-
|
|
99
|
-
"@deepseek-ai/dsh-
|
|
100
|
-
"@deepseek-ai/dsh-tools": "^0.1.0-rc.8",
|
|
88
|
+
"@deepseek-ai/dsh-agent": "^0.1.5-rc.1",
|
|
89
|
+
"@deepseek-ai/dsh-client-locale": "^0.1.5-rc.1",
|
|
90
|
+
"@deepseek-ai/dsh-client-ui-conversation": "^0.1.5-rc.1",
|
|
91
|
+
"@deepseek-ai/dsh-client-ui-primitives": "^0.1.5-rc.1",
|
|
92
|
+
"@deepseek-ai/dsh-client-ui-settings": "^0.1.5-rc.1",
|
|
93
|
+
"@deepseek-ai/dsh-client-ui-slots": "^0.1.5-rc.1",
|
|
94
|
+
"@deepseek-ai/dsh-host-webserver": "^0.1.5-rc.1",
|
|
95
|
+
"@deepseek-ai/dsh-llm": "^0.1.5-rc.1",
|
|
96
|
+
"@deepseek-ai/dsh-session": "^0.1.5-rc.1",
|
|
97
|
+
"@deepseek-ai/dsh-settings": "^0.1.5-rc.1",
|
|
98
|
+
"@deepseek-ai/dsh-subagent": "^0.1.5-rc.1",
|
|
99
|
+
"@deepseek-ai/dsh-tools": "^0.1.5-rc.1",
|
|
101
100
|
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
|
|
102
101
|
"react": "^18.2.0",
|
|
103
102
|
"react-dom": "^18.2.0"
|
|
@@ -140,20 +139,20 @@
|
|
|
140
139
|
"ws": "^8.18.0"
|
|
141
140
|
},
|
|
142
141
|
"devDependencies": {
|
|
142
|
+
"@deepseek-ai/dsh-invariants": "0.1.5-rc.1",
|
|
143
143
|
"@cordisjs/plugin-loader": "^1.0.0-rc.5",
|
|
144
|
-
"@deepseek-ai/dsh-agent": "0.1.
|
|
145
|
-
"@deepseek-ai/dsh-client-locale": "0.1.
|
|
146
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.
|
|
147
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.
|
|
148
|
-
"@deepseek-ai/dsh-client-ui-settings": "0.1.
|
|
149
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.
|
|
150
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.
|
|
151
|
-
"@deepseek-ai/dsh-
|
|
152
|
-
"@deepseek-ai/dsh-
|
|
153
|
-
"@deepseek-ai/dsh-
|
|
154
|
-
"@deepseek-ai/dsh-
|
|
155
|
-
"@deepseek-ai/dsh-
|
|
156
|
-
"@deepseek-ai/dsh-tools": "0.1.2-alpha.2",
|
|
144
|
+
"@deepseek-ai/dsh-agent": "0.1.5-rc.1",
|
|
145
|
+
"@deepseek-ai/dsh-client-locale": "0.1.5-rc.1",
|
|
146
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.5-rc.1",
|
|
147
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.5-rc.1",
|
|
148
|
+
"@deepseek-ai/dsh-client-ui-settings": "0.1.5-rc.1",
|
|
149
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.5-rc.1",
|
|
150
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.5-rc.1",
|
|
151
|
+
"@deepseek-ai/dsh-llm": "0.1.5-rc.1",
|
|
152
|
+
"@deepseek-ai/dsh-session": "0.1.5-rc.1",
|
|
153
|
+
"@deepseek-ai/dsh-settings": "0.1.5-rc.1",
|
|
154
|
+
"@deepseek-ai/dsh-subagent": "0.1.5-rc.1",
|
|
155
|
+
"@deepseek-ai/dsh-tools": "0.1.5-rc.1",
|
|
157
156
|
"@huanlin/dsh-plugin-better-locale": "^0.1.0",
|
|
158
157
|
"@types/node": "^24.0.0",
|
|
159
158
|
"@types/react": "~18.3.1",
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
.count {
|
|
77
77
|
padding: 1px 8px;
|
|
78
78
|
border-radius: 999px;
|
|
79
|
-
background: var(--dsw-alias-
|
|
79
|
+
background: var(--dsw-alias-bg-layer-2);
|
|
80
80
|
font-size: 11px;
|
|
81
81
|
line-height: 16px;
|
|
82
82
|
font-weight: 500;
|
|
@@ -836,7 +836,7 @@
|
|
|
836
836
|
.versionBadgeTag {
|
|
837
837
|
padding: 1px 8px;
|
|
838
838
|
border-radius: 999px;
|
|
839
|
-
background: var(--dsw-alias-
|
|
839
|
+
background: var(--dsw-alias-border-l2);
|
|
840
840
|
color: var(--dsw-alias-label-secondary);
|
|
841
841
|
font-variant-numeric: tabular-nums;
|
|
842
842
|
}
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
gap: 4px;
|
|
24
24
|
min-height: 36px;
|
|
25
25
|
padding: 4px 8px 4px 12px;
|
|
26
|
-
border-bottom: 1px solid var(--dsw-alias-
|
|
26
|
+
border-bottom: 1px solid var(--dsw-alias-border-l);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
.sidechatHeaderDot {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
flex: none;
|
|
40
40
|
max-width: 55%;
|
|
41
41
|
padding: 1px 8px;
|
|
42
|
-
border: 1px solid var(--dsw-alias-
|
|
42
|
+
border: 1px solid var(--dsw-alias-border-l);
|
|
43
43
|
border-radius: 999px;
|
|
44
44
|
font: var(--dsw-font-xxs-12);
|
|
45
45
|
color: var(--dsw-alias-label-tertiary);
|
|
@@ -108,9 +108,9 @@
|
|
|
108
108
|
padding: 6px 14px;
|
|
109
109
|
border: none;
|
|
110
110
|
border-radius: 999px;
|
|
111
|
-
background: var(--dsw-alias-button-info-fill, var(--dsw-alias-
|
|
112
|
-
color:
|
|
113
|
-
font: var(--dsw-font-s-
|
|
111
|
+
background: var(--dsw-alias-button-info-fill, var(--dsw-alias-interactive-bg-hover-solid));
|
|
112
|
+
color: #fff;
|
|
113
|
+
font: var(--dsw-font-s-14);
|
|
114
114
|
cursor: pointer;
|
|
115
115
|
transition: opacity 100ms ease-out;
|
|
116
116
|
}
|
|
@@ -135,7 +135,7 @@
|
|
|
135
135
|
flex: none;
|
|
136
136
|
padding: 4px 12px;
|
|
137
137
|
font: var(--dsw-font-xxs-12);
|
|
138
|
-
color:
|
|
138
|
+
color: #d5304d;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
/* ── transcript ─────────────────────────────────────────────────────── */
|
|
@@ -246,13 +246,13 @@
|
|
|
246
246
|
|
|
247
247
|
.sidechatRowFailed .sidechatRowLabel,
|
|
248
248
|
.sidechatRowFailed .sidechatRowMeta {
|
|
249
|
-
color:
|
|
249
|
+
color: #d5304d;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
.sidechatRowBody {
|
|
253
253
|
margin: 2px 0 4px 7px;
|
|
254
254
|
padding: 2px 0 2px 10px;
|
|
255
|
-
border-left: 1px solid var(--dsw-alias-
|
|
255
|
+
border-left: 1px solid var(--dsw-alias-border-l);
|
|
256
256
|
}
|
|
257
257
|
|
|
258
258
|
.sidechatRowProse {
|
|
@@ -277,7 +277,7 @@
|
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
.sidechatRowCode + .sidechatRowCode {
|
|
280
|
-
border-top: 1px solid var(--dsw-alias-
|
|
280
|
+
border-top: 1px solid var(--dsw-alias-border-l);
|
|
281
281
|
}
|
|
282
282
|
|
|
283
283
|
/* Shimmer sweep text: generating (streaming row labels, creating hero). */
|
|
@@ -328,7 +328,7 @@
|
|
|
328
328
|
gap: 4px;
|
|
329
329
|
margin: 0 8px 8px;
|
|
330
330
|
padding: 8px 8px 6px 14px;
|
|
331
|
-
border: 1px solid var(--dsw-alias-border-l2-darkmode-thin, var(--dsw-alias-
|
|
331
|
+
border: 1px solid var(--dsw-alias-border-l2-darkmode-thin, var(--dsw-alias-border-l));
|
|
332
332
|
border-radius: 16px;
|
|
333
333
|
background: var(--dsw-specific-input-major, var(--dsw-alias-bg-base));
|
|
334
334
|
box-shadow: var(--dsw-shadow-lv2, none);
|
|
@@ -380,8 +380,8 @@
|
|
|
380
380
|
padding: 0;
|
|
381
381
|
border: none;
|
|
382
382
|
border-radius: 50%;
|
|
383
|
-
background: var(--dsw-alias-button-info-fill, var(--dsw-alias-
|
|
384
|
-
color:
|
|
383
|
+
background: var(--dsw-alias-button-info-fill, var(--dsw-alias-interactive-bg-hover-solid));
|
|
384
|
+
color: #fff;
|
|
385
385
|
cursor: pointer;
|
|
386
386
|
/* send ⇄ stop swap: keyed remount plays this, hover only fades. */
|
|
387
387
|
animation: sidechatBtnIn 120ms ease-out;
|
package/src/context-types.ts
CHANGED
|
@@ -87,11 +87,11 @@ export interface SidebarSessionStore {
|
|
|
87
87
|
get(id: string): {
|
|
88
88
|
header: SidebarSessionHeader
|
|
89
89
|
/**
|
|
90
|
-
* The live session's
|
|
90
|
+
* The live session's immutable event snapshot (0.1.5 Session API; absent
|
|
91
91
|
* on sessions the runtime has not hydrated). Read-only access — the
|
|
92
92
|
* jobs.output route replays `job_output` tool/result rows from it.
|
|
93
93
|
*/
|
|
94
|
-
|
|
94
|
+
snapshotEvents?(fromSeq?: number, toSeqExclusive?: number): readonly SidebarSessionEvent[]
|
|
95
95
|
} | undefined
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -295,13 +295,18 @@ export interface SidebarSessionTitleService {
|
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
/** The host session-persistence face (mirror of the sessionPersistence
|
|
298
|
-
* service
|
|
299
|
-
* recorded preset when a Side Chat
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
298
|
+
* service, 0.1.5 handle-seam form): a short-lived read handle over one
|
|
299
|
+
* persisted session, used to compose the recorded preset when a Side Chat
|
|
300
|
+
* thread cold-resumes. */
|
|
301
|
+
export interface SidebarSessionPersistenceHandle {
|
|
302
|
+
readonly header: { cwd?: string; agentPreset?: string }
|
|
303
|
+
read(fromSeq?: number, toSeqExclusive?: number, options?: { signal?: AbortSignal }): Promise<{
|
|
303
304
|
events: readonly SidebarSessionEvent[]
|
|
304
305
|
}>
|
|
306
|
+
close(): Promise<void>
|
|
307
|
+
}
|
|
308
|
+
export interface SidebarSessionPersistenceService {
|
|
309
|
+
open(sessionId: string, access: 'read', options?: { signal?: AbortSignal }): Promise<SidebarSessionPersistenceHandle>
|
|
305
310
|
}
|
|
306
311
|
|
|
307
312
|
/** RPC result slot mirror (`RpcResult<T>` on the wire). */
|
package/src/index.ts
CHANGED
|
@@ -18,7 +18,7 @@ import { basename, dirname, extname, isAbsolute, join } from 'node:path'
|
|
|
18
18
|
import type { IncomingMessage } from 'node:http'
|
|
19
19
|
import type { Duplex } from 'node:stream'
|
|
20
20
|
import { WebSocket, WebSocketServer } from 'ws'
|
|
21
|
-
import type { Context, SidebarHttpRequest } from './context-types.ts'
|
|
21
|
+
import type { Context, SidebarHttpRequest, SidebarSessionPersistenceService } from './context-types.ts'
|
|
22
22
|
import {
|
|
23
23
|
Config,
|
|
24
24
|
PrefsSchema,
|
|
@@ -126,10 +126,11 @@ async function sessionCwdOf(ctx: Context, sessionId: string, clientCwd?: string)
|
|
|
126
126
|
throw new SidebarError('bad-request', `invalid working directory "${clientCwd}"`)
|
|
127
127
|
}
|
|
128
128
|
}
|
|
129
|
-
const persistence = ctx.get('sessionPersistence')
|
|
129
|
+
const persistence = ctx.get('sessionPersistence') as SidebarSessionPersistenceService | undefined
|
|
130
130
|
if (persistence !== undefined) {
|
|
131
|
-
const
|
|
132
|
-
const metaCwd =
|
|
131
|
+
const handle = await persistence.open(sessionId, 'read')
|
|
132
|
+
const metaCwd = handle.header.cwd
|
|
133
|
+
await handle.close()
|
|
133
134
|
if (metaCwd !== undefined && metaCwd !== '') {
|
|
134
135
|
try {
|
|
135
136
|
return requireAbsolute(metaCwd)
|
package/src/jobs-routes.ts
CHANGED
|
@@ -135,7 +135,7 @@ const MIRROR_MAX_ENTRIES = 200
|
|
|
135
135
|
* The live job_output mirror: subscribes to the session append feed and
|
|
136
136
|
* caches the job_output traces the session store's own log can lag behind
|
|
137
137
|
* (after a host restart the store session stays frozen at its rehydration
|
|
138
|
-
* boundary, so
|
|
138
|
+
* boundary, so a stale snapshot misses everything appended since — the very
|
|
139
139
|
* reads the pane exists to show). Zero DSH writes: the api-proxy pushes the
|
|
140
140
|
* same feed to browsers.
|
|
141
141
|
*/
|
|
@@ -211,7 +211,8 @@ export function buildJobsApi(ctx: Context, outputLimit: number): SidebarJobsRout
|
|
|
211
211
|
// Merge the store's event log (durable seed + whatever it received)
|
|
212
212
|
// with the live mirror, deduped by seq — a trace never double-counts.
|
|
213
213
|
const bySeq = new Map<number, JobOutputTrace>()
|
|
214
|
-
|
|
214
|
+
const store = ctx.sessions.get(sessionId)
|
|
215
|
+
for (const event of (store?.snapshotEvents !== undefined ? store.snapshotEvents() : []) ?? []) {
|
|
215
216
|
const trace = traceOf(event)
|
|
216
217
|
if (trace !== undefined) bySeq.set(trace.seq, trace)
|
|
217
218
|
}
|
package/src/sidechat-routes.ts
CHANGED
|
@@ -26,6 +26,7 @@ import type { Agent, AgentSetup, CreateAgentOptions, ResumeAgentOptions } from '
|
|
|
26
26
|
import { snapshotSubagentDescriptor } from '@deepseek-ai/dsh-subagent'
|
|
27
27
|
import type { Context as CordisContext } from '@deepseek-ai/cordis'
|
|
28
28
|
import type { SessionEvent, SessionId } from '@deepseek-ai/dsh-session'
|
|
29
|
+
import type { SidebarSessionEvent } from './context-types.ts'
|
|
29
30
|
import type {
|
|
30
31
|
Context,
|
|
31
32
|
SidebarAgentPresetsService,
|
|
@@ -104,8 +105,10 @@ async function composePersistedSetup(
|
|
|
104
105
|
if (persistence === undefined) {
|
|
105
106
|
return () => Promise.resolve()
|
|
106
107
|
}
|
|
107
|
-
const
|
|
108
|
-
const
|
|
108
|
+
const handle = await persistence.open(childId, 'read')
|
|
109
|
+
const { events } = await handle.read()
|
|
110
|
+
const presetId = resolvePresetId(handle.header as never, events as unknown as readonly SidebarSessionEvent[])
|
|
111
|
+
await handle.close()
|
|
109
112
|
const presets = ctx.get('agentPresets') as SidebarAgentPresetsService | undefined
|
|
110
113
|
if (presets === undefined || presetId === undefined) {
|
|
111
114
|
return () => Promise.resolve()
|
|
@@ -166,11 +169,11 @@ export function buildSidechatApi(ctx: Context): SidechatRoutes {
|
|
|
166
169
|
}
|
|
167
170
|
const parentSession = parent.session
|
|
168
171
|
const inheritance = buildSidechatInheritance(
|
|
169
|
-
parentSession.
|
|
172
|
+
parentSession.snapshotEvents() as unknown as readonly SidechatLogEvent[],
|
|
170
173
|
)
|
|
171
174
|
const { agentPreset, setup } = await composeChildSetup(
|
|
172
175
|
ctx,
|
|
173
|
-
resolvePresetId(parentSession.header, parentSession.
|
|
176
|
+
resolvePresetId(parentSession.header, parentSession.snapshotEvents()),
|
|
174
177
|
)
|
|
175
178
|
const childId = `session-${randomUUID()}` as SessionId
|
|
176
179
|
const label = question === '' ? SIDE_NEW_THREAD_TITLE : sideLabel(question)
|
|
@@ -198,7 +201,7 @@ export function buildSidechatApi(ctx: Context): SidechatRoutes {
|
|
|
198
201
|
meta: {
|
|
199
202
|
...(parentSession.header.cwd === undefined ? {} : { cwd: parentSession.header.cwd }),
|
|
200
203
|
parentSession: parentSession.id,
|
|
201
|
-
|
|
204
|
+
isSeeded: seed.length > 0,
|
|
202
205
|
origin: 'subagent',
|
|
203
206
|
delegationDepth: (parentSession.header.delegationDepth ?? 0) + 1,
|
|
204
207
|
...(agentPreset === undefined ? {} : { agentPreset }),
|
|
@@ -267,7 +270,7 @@ export function buildSidechatApi(ctx: Context): SidechatRoutes {
|
|
|
267
270
|
throw new SidebarError('sidechat-error', `thread resume failed: ${error instanceof Error ? error.message : String(error)}`, 500)
|
|
268
271
|
}
|
|
269
272
|
}
|
|
270
|
-
if (boundaryDelivered(agent.session.
|
|
273
|
+
if (boundaryDelivered(agent.session.snapshotEvents() as unknown as readonly SidechatLogEvent[])) {
|
|
271
274
|
admitFollowup(agent, textPrompt(text))
|
|
272
275
|
} else {
|
|
273
276
|
// First message of an immediately-created thread: it carries the
|
|
@@ -331,8 +334,10 @@ export function buildSidechatApi(ctx: Context): SidechatRoutes {
|
|
|
331
334
|
const persistence = ctx.get('sessionPersistence') as SidebarSessionPersistenceService | undefined
|
|
332
335
|
if (persistence !== undefined) {
|
|
333
336
|
try {
|
|
334
|
-
const
|
|
335
|
-
const
|
|
337
|
+
const handle = await persistence.open(childId, 'read')
|
|
338
|
+
const { events } = await handle.read()
|
|
339
|
+
const preset = resolvePresetId(handle.header as never, events as unknown as readonly SidebarSessionEvent[])
|
|
340
|
+
await handle.close()
|
|
336
341
|
return { live: false, ...(preset === undefined ? {} : { preset }) }
|
|
337
342
|
} catch {
|
|
338
343
|
// Unknown/gone session: report a bare cold info.
|
|
@@ -76,8 +76,9 @@ export function buildSubagentLiveApi(ctx: Context): SidebarSubagentLiveRoutes {
|
|
|
76
76
|
// never topology — keep them out of the live map too.
|
|
77
77
|
if (entry.label?.startsWith(SIDE_LABEL_PREFIX) ?? false) continue
|
|
78
78
|
try {
|
|
79
|
+
const stored = ctx.sessions.get(entry.id)
|
|
79
80
|
const activity = lastActivity(
|
|
80
|
-
|
|
81
|
+
stored?.snapshotEvents !== undefined ? stored.snapshotEvents() : [],
|
|
81
82
|
LIVE_WINDOW_MESSAGES,
|
|
82
83
|
)
|
|
83
84
|
if (activity.text !== undefined || activity.tool !== undefined) {
|