dsh-coding-sidebar 1.0.1 → 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 +5 -5
- package/lib/client-editor.js +416 -355
- package/lib/client-mermaid.js +304 -273
- package/lib/client-registry.js +555 -421
- package/lib/client-terminal.js +216 -208
- package/lib/client.js +557 -423
- package/lib/index.js +20 -12
- package/lib/types/client/locales.d.ts +4 -0
- 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/client/SubagentView.module.css +41 -0
- package/src/client/SubagentView.tsx +63 -7
- package/src/client/locales-ar.ts +4 -0
- package/src/client/locales-de.ts +4 -0
- package/src/client/locales-fr.ts +4 -0
- package/src/client/locales-hi.ts +4 -0
- package/src/client/locales-id.ts +4 -0
- package/src/client/locales-it.ts +4 -0
- package/src/client/locales-ja.ts +4 -0
- package/src/client/locales-ko.ts +4 -0
- package/src/client/locales-nl.ts +4 -0
- package/src/client/locales-pl.ts +4 -0
- package/src/client/locales-pt.ts +4 -0
- package/src/client/locales-ru.ts +4 -0
- package/src/client/locales-sv.ts +4 -0
- package/src/client/locales-th.ts +4 -0
- package/src/client/locales-tr.ts +4 -0
- package/src/client/locales-vi.ts +4 -0
- package/src/client/locales-zh-HK.ts +4 -0
- package/src/client/locales-zh-MO.ts +4 -0
- package/src/client/locales-zh-TW.ts +4 -0
- package/src/client/locales.ts +8 -0
- 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 {
|
|
@@ -302,6 +302,8 @@ export declare const zh: {
|
|
|
302
302
|
subagentDiagUnsupported: string;
|
|
303
303
|
subagentDiagUnavailable: string;
|
|
304
304
|
subagentThinking: string;
|
|
305
|
+
subagentShowHistory: string;
|
|
306
|
+
subagentHideHistory: string;
|
|
305
307
|
sideChat: string;
|
|
306
308
|
sideChatNew: string;
|
|
307
309
|
sideChatUntitled: string;
|
|
@@ -329,6 +331,8 @@ export declare const zh: {
|
|
|
329
331
|
jobs: string;
|
|
330
332
|
jobsCount: string;
|
|
331
333
|
jobsCountRunning: string;
|
|
334
|
+
jobsShowHistory: string;
|
|
335
|
+
jobsHideHistory: string;
|
|
332
336
|
jobStatusRunning: string;
|
|
333
337
|
jobStatusStopping: string;
|
|
334
338
|
jobStatusCompleted: string;
|
|
@@ -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;
|
|
@@ -274,6 +274,47 @@
|
|
|
274
274
|
color: var(--dsw-alias-label-primary);
|
|
275
275
|
}
|
|
276
276
|
|
|
277
|
+
/* ── History collapse toggle (shared: topology levels + jobs list) ─────── */
|
|
278
|
+
|
|
279
|
+
/* The "show earlier rows" disclosure between the header and the collapsed
|
|
280
|
+
rows; full-width like a row, but visually quieter (tertiary, small). */
|
|
281
|
+
.historyToggle {
|
|
282
|
+
display: flex;
|
|
283
|
+
align-items: center;
|
|
284
|
+
gap: 5px;
|
|
285
|
+
width: 100%;
|
|
286
|
+
box-sizing: border-box;
|
|
287
|
+
min-height: 26px;
|
|
288
|
+
padding: 3px 8px 3px 11px;
|
|
289
|
+
border: none;
|
|
290
|
+
border-radius: 8px;
|
|
291
|
+
background: transparent;
|
|
292
|
+
font: var(--dsw-font-xxxs-strong-11);
|
|
293
|
+
color: var(--dsw-alias-label-tertiary);
|
|
294
|
+
text-align: left;
|
|
295
|
+
cursor: pointer;
|
|
296
|
+
outline: none;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.historyToggle:hover {
|
|
300
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
301
|
+
color: var(--dsw-alias-label-secondary);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
.historyToggle:focus-visible {
|
|
305
|
+
background: var(--dsw-alias-interactive-bg-hover);
|
|
306
|
+
color: var(--dsw-alias-label-secondary);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.historyToggle svg {
|
|
310
|
+
flex: none;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/* The jobs section's toggle sits right under its list. */
|
|
314
|
+
.jobs .historyToggle {
|
|
315
|
+
margin-top: 2px;
|
|
316
|
+
}
|
|
317
|
+
|
|
277
318
|
/* ── Background-job section (below the topology tree) ────────────────── */
|
|
278
319
|
|
|
279
320
|
.jobs {
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
* highlighted in place. Every branch is expanded automatically (lazy
|
|
13
13
|
* catalogs hydrate on demand and consume live membership while visible).
|
|
14
14
|
*
|
|
15
|
+
* To keep long histories browsable, each catalog level shows only its
|
|
16
|
+
* LATEST {@link SUBAGENT_VISIBLE} children by default — earlier rows fold
|
|
17
|
+
* behind a history toggle — and the jobs section shows its latest
|
|
18
|
+
* {@link JOBS_VISIBLE} rows the same way. Collapsing is view-only: the
|
|
19
|
+
* header counts, the output dock and live observation still see every row.
|
|
20
|
+
*
|
|
15
21
|
* Each node card carries live status (state dot, durable label, mode and
|
|
16
22
|
* activity); while a child RUNS, its card additionally shows the LAST text
|
|
17
23
|
* output and LAST tool call pulled from its history tail, auto-refreshing
|
|
@@ -23,6 +29,7 @@ import { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent }
|
|
|
23
29
|
import { useSyncExternalStore } from 'react'
|
|
24
30
|
import clsx from 'clsx'
|
|
25
31
|
import {
|
|
32
|
+
IconChevronDownOutline14, IconChevronRightOutline14,
|
|
26
33
|
IconRefreshOutline14, StateDot,
|
|
27
34
|
} from '@deepseek-ai/dsh-client-ui-primitives'
|
|
28
35
|
import type {
|
|
@@ -65,6 +72,15 @@ const ARGS_PREVIEW = 60
|
|
|
65
72
|
const JOB_POLL_MS = 2000
|
|
66
73
|
/** How long the kill button stays armed before it needs re-confirming. */
|
|
67
74
|
const JOB_KILL_ARM_MS = 3000
|
|
75
|
+
/**
|
|
76
|
+
* How many of the LATEST rows stay visible by default before the earlier
|
|
77
|
+
* (history) rows collapse behind a toggle: {@link SUBAGENT_VISIBLE} for the
|
|
78
|
+
* topology's child rows, {@link JOBS_VISIBLE} for the background-job list.
|
|
79
|
+
* Collapsing is view-only — counts, the output dock and live observation
|
|
80
|
+
* keep seeing every entry.
|
|
81
|
+
*/
|
|
82
|
+
const SUBAGENT_VISIBLE = 5
|
|
83
|
+
const JOBS_VISIBLE = 3
|
|
68
84
|
|
|
69
85
|
/** The direct subagent children of one parent (durable `origin` rows;
|
|
70
86
|
* Side Chat threads ride the same origin but are tab-strip conversations,
|
|
@@ -244,7 +260,12 @@ interface RowsProps {
|
|
|
244
260
|
refresh: (parentSessionId: string) => void
|
|
245
261
|
}
|
|
246
262
|
|
|
247
|
-
/**
|
|
263
|
+
/**
|
|
264
|
+
* Render one topology level; branches are always expanded (lazy catalogs).
|
|
265
|
+
* When a level lists more than {@link SUBAGENT_VISIBLE} children, only the
|
|
266
|
+
* LATEST ones render by default — the earlier rows collapse behind a
|
|
267
|
+
* history toggle (per-level state; a fresh catalog page collapses again).
|
|
268
|
+
*/
|
|
248
269
|
function CatalogRows({
|
|
249
270
|
parentSessionId, catalog, catalogs, byId, level, currentSessionId, live,
|
|
250
271
|
openChild, refresh,
|
|
@@ -258,6 +279,10 @@ function CatalogRows({
|
|
|
258
279
|
if (entry.kind === 'child') return !(entry.label?.startsWith(SIDE_LABEL_PREFIX) ?? false)
|
|
259
280
|
return !(byId[entry.id]?.displayTitle.startsWith(SIDE_LABEL_PREFIX) ?? false)
|
|
260
281
|
})
|
|
282
|
+
const [historyOpen, setHistoryOpen] = useState(false)
|
|
283
|
+
const historyCount = visibleEntries.length - SUBAGENT_VISIBLE
|
|
284
|
+
const collapsed = historyCount > 0 && !historyOpen
|
|
285
|
+
const renderEntries = collapsed ? visibleEntries.slice(-SUBAGENT_VISIBLE) : visibleEntries
|
|
261
286
|
return (
|
|
262
287
|
<>
|
|
263
288
|
{emptyLoading && (
|
|
@@ -276,7 +301,18 @@ function CatalogRows({
|
|
|
276
301
|
</button>
|
|
277
302
|
</div>
|
|
278
303
|
)}
|
|
279
|
-
{
|
|
304
|
+
{historyCount > 0 && (
|
|
305
|
+
<button
|
|
306
|
+
type="button"
|
|
307
|
+
className={css.historyToggle}
|
|
308
|
+
aria-expanded={historyOpen}
|
|
309
|
+
onClick={() => { setHistoryOpen(open => !open) }}
|
|
310
|
+
>
|
|
311
|
+
{historyOpen ? <IconChevronDownOutline14 /> : <IconChevronRightOutline14 />}
|
|
312
|
+
{historyOpen ? t('subagentHideHistory') : t('subagentShowHistory', { count: historyCount })}
|
|
313
|
+
</button>
|
|
314
|
+
)}
|
|
315
|
+
{renderEntries.map((entry) => {
|
|
280
316
|
if (entry.kind === 'diagnostic') {
|
|
281
317
|
return (
|
|
282
318
|
<div key={entry.id} className={css.subagentNode}>
|
|
@@ -467,10 +503,12 @@ function JobOutputPane(props: {
|
|
|
467
503
|
/**
|
|
468
504
|
* The background-job section of the Subagent page: every job of the whole
|
|
469
505
|
* current tree (main agent + subagents, owner-labeled), fed by the harness
|
|
470
|
-
* `session/jobs` push mirror.
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
506
|
+
* `session/jobs` push mirror. When more than {@link JOBS_VISIBLE} jobs
|
|
507
|
+
* exist, only the head of the standard order (live rows, then newest
|
|
508
|
+
* settled) stays visible — earlier rows collapse behind a history toggle.
|
|
509
|
+
* Clicking a row feeds its model-read output to the shared bottom dock
|
|
510
|
+
* (event replay — never the model's cursor); live rows carry a
|
|
511
|
+
* two-click-confirm kill button. Renders nothing while the tree has no jobs.
|
|
474
512
|
*/
|
|
475
513
|
function JobsSection(props: {
|
|
476
514
|
byId: SidebarSessionList['byId']
|
|
@@ -485,6 +523,7 @@ function JobsSection(props: {
|
|
|
485
523
|
[byId, jobsBySession, rootId],
|
|
486
524
|
)
|
|
487
525
|
const [selectedId, setSelectedId] = useState<string | undefined>(undefined)
|
|
526
|
+
const [historyOpen, setHistoryOpen] = useState(false)
|
|
488
527
|
const [armedId, setArmedId] = useState<string | undefined>(undefined)
|
|
489
528
|
const [killingId, setKillingId] = useState<string | undefined>(undefined)
|
|
490
529
|
const [killErrorId, setKillErrorId] = useState<string | undefined>(undefined)
|
|
@@ -547,6 +586,12 @@ function JobsSection(props: {
|
|
|
547
586
|
? t('jobsCountRunning', { count: rows.length, running: liveCount })
|
|
548
587
|
: t('jobsCount', { count: rows.length })
|
|
549
588
|
|
|
589
|
+
// Collapsed view: the head of the standard order stays visible (all live
|
|
590
|
+
// rows up to the cap, then newest settled); the header count still
|
|
591
|
+
// reports the full totals, and a hidden job's dock keeps working.
|
|
592
|
+
const historyCount = rows.length - JOBS_VISIBLE
|
|
593
|
+
const visibleRows = historyCount > 0 && !historyOpen ? rows.slice(0, JOBS_VISIBLE) : rows
|
|
594
|
+
|
|
550
595
|
return (
|
|
551
596
|
<>
|
|
552
597
|
<section className={css.jobs} aria-label={t('jobs')}>
|
|
@@ -555,7 +600,7 @@ function JobsSection(props: {
|
|
|
555
600
|
<span className={css.jobsCount}>{countLabel}</span>
|
|
556
601
|
</div>
|
|
557
602
|
<ul className={css.jobsList} aria-label={t('jobs')}>
|
|
558
|
-
{
|
|
603
|
+
{visibleRows.map((row) => {
|
|
559
604
|
const { job } = row
|
|
560
605
|
const live = isJobLive(job)
|
|
561
606
|
const selected = selectedId === job.id
|
|
@@ -617,6 +662,17 @@ function JobsSection(props: {
|
|
|
617
662
|
)
|
|
618
663
|
})}
|
|
619
664
|
</ul>
|
|
665
|
+
{historyCount > 0 && (
|
|
666
|
+
<button
|
|
667
|
+
type="button"
|
|
668
|
+
className={css.historyToggle}
|
|
669
|
+
aria-expanded={historyOpen}
|
|
670
|
+
onClick={() => { setHistoryOpen(open => !open) }}
|
|
671
|
+
>
|
|
672
|
+
{historyOpen ? <IconChevronDownOutline14 /> : <IconChevronRightOutline14 />}
|
|
673
|
+
{historyOpen ? t('jobsHideHistory') : t('jobsShowHistory', { count: historyCount })}
|
|
674
|
+
</button>
|
|
675
|
+
)}
|
|
620
676
|
</section>
|
|
621
677
|
{selectedRow !== undefined && (
|
|
622
678
|
<JobOutputPane
|
package/src/client/locales-ar.ts
CHANGED
|
@@ -297,6 +297,8 @@ export const ar: Record<string, string> = {
|
|
|
297
297
|
subagentDiagUnsupported: 'غير مدعوم',
|
|
298
298
|
subagentDiagUnavailable: 'غير متاح',
|
|
299
299
|
subagentThinking: 'جارٍ التفكير…',
|
|
300
|
+
subagentShowHistory: 'عرض {count} من الوكلاء الفرعيين الأقدم',
|
|
301
|
+
subagentHideHistory: 'طي الوكلاء الفرعيين الأقدم',
|
|
300
302
|
sideChat: 'محادثة جانبية (تجريبية)',
|
|
301
303
|
sideChatNew: 'خيط جديد',
|
|
302
304
|
sideChatUntitled: 'خيط جديد',
|
|
@@ -324,6 +326,8 @@ export const ar: Record<string, string> = {
|
|
|
324
326
|
jobs: 'المهام الخلفية',
|
|
325
327
|
jobsCount: '{count} مهمة خلفية',
|
|
326
328
|
jobsCountRunning: '{count} مهمة خلفية · {running} قيد التشغيل',
|
|
329
|
+
jobsShowHistory: 'عرض {count} من المهام الخلفية الأقدم',
|
|
330
|
+
jobsHideHistory: 'طي المهام الخلفية الأقدم',
|
|
327
331
|
jobStatusRunning: 'قيد التشغيل',
|
|
328
332
|
jobStatusStopping: 'جارٍ الإيقاف',
|
|
329
333
|
jobStatusCompleted: 'اكتمل',
|
package/src/client/locales-de.ts
CHANGED
|
@@ -282,6 +282,8 @@ export const de: Record<string, string> = {
|
|
|
282
282
|
subagentDiagUnsupported: 'Nicht unterstützt',
|
|
283
283
|
subagentDiagUnavailable: 'Nicht verfügbar',
|
|
284
284
|
subagentThinking: 'Denkt nach…',
|
|
285
|
+
subagentShowHistory: '{count} ältere Subagenten anzeigen',
|
|
286
|
+
subagentHideHistory: 'Ältere Subagenten einklappen',
|
|
285
287
|
sideChat: 'Seitenchat (beta)',
|
|
286
288
|
sideChatNew: 'Neuer Thread',
|
|
287
289
|
sideChatUntitled: 'Neuer Thread',
|
|
@@ -309,6 +311,8 @@ export const de: Record<string, string> = {
|
|
|
309
311
|
jobs: 'Hintergrundaufgaben',
|
|
310
312
|
jobsCount: '{count} Hintergrundaufgaben',
|
|
311
313
|
jobsCountRunning: '{count} Hintergrundaufgaben · {running} läuft',
|
|
314
|
+
jobsShowHistory: '{count} ältere Hintergrundaufgaben anzeigen',
|
|
315
|
+
jobsHideHistory: 'Ältere Hintergrundaufgaben einklappen',
|
|
312
316
|
jobStatusRunning: 'Läuft',
|
|
313
317
|
jobStatusStopping: 'Wird beendet',
|
|
314
318
|
jobStatusCompleted: 'Abgeschlossen',
|
package/src/client/locales-fr.ts
CHANGED
|
@@ -289,6 +289,8 @@ export const fr: Record<string, string> = {
|
|
|
289
289
|
subagentDiagUnsupported: 'Entrée non prise en charge',
|
|
290
290
|
subagentDiagUnavailable: 'Indisponible',
|
|
291
291
|
subagentThinking: 'Réflexion…',
|
|
292
|
+
subagentShowHistory: 'Afficher {count} sous-agents plus anciens',
|
|
293
|
+
subagentHideHistory: 'Réduire les sous-agents plus anciens',
|
|
292
294
|
sideChat: 'Discussion latérale (bêta)',
|
|
293
295
|
sideChatNew: 'Nouvelle discussion',
|
|
294
296
|
sideChatUntitled: 'Nouvelle discussion',
|
|
@@ -316,6 +318,8 @@ export const fr: Record<string, string> = {
|
|
|
316
318
|
jobs: 'Tâches d’arrière-plan',
|
|
317
319
|
jobsCount: '{count} tâche(s) d’arrière-plan',
|
|
318
320
|
jobsCountRunning: '{count} tâche(s) d’arrière-plan · {running} en cours',
|
|
321
|
+
jobsShowHistory: 'Afficher {count} tâches d’arrière-plan plus anciennes',
|
|
322
|
+
jobsHideHistory: 'Réduire les tâches d’arrière-plan plus anciennes',
|
|
319
323
|
jobStatusRunning: 'En cours',
|
|
320
324
|
jobStatusStopping: 'Arrêt en cours',
|
|
321
325
|
jobStatusCompleted: 'Terminée',
|
package/src/client/locales-hi.ts
CHANGED
|
@@ -296,6 +296,8 @@ export const hi: Record<string, string> = {
|
|
|
296
296
|
subagentDiagUnsupported: 'असमर्थित',
|
|
297
297
|
subagentDiagUnavailable: 'अनुपलब्ध',
|
|
298
298
|
subagentThinking: 'सोच रहा…',
|
|
299
|
+
subagentShowHistory: 'पुराने {count} सबएजेंट दिखाएँ',
|
|
300
|
+
subagentHideHistory: 'पुराने सबएजेंट छिपाएँ',
|
|
299
301
|
sideChat: 'साइड चैट (बीटा)',
|
|
300
302
|
sideChatNew: 'नया थ्रेड',
|
|
301
303
|
sideChatUntitled: 'नया थ्रेड',
|
|
@@ -323,6 +325,8 @@ export const hi: Record<string, string> = {
|
|
|
323
325
|
jobs: 'बैकग्राउंड कार्य',
|
|
324
326
|
jobsCount: '{count} बैकग्राउंड कार्य',
|
|
325
327
|
jobsCountRunning: '{count} बैकग्राउंड कार्य · {running} चल रहे',
|
|
328
|
+
jobsShowHistory: 'पुराने {count} बैकग्राउंड कार्य दिखाएँ',
|
|
329
|
+
jobsHideHistory: 'पुराने बैकग्राउंड कार्य छिपाएँ',
|
|
326
330
|
jobStatusRunning: 'चल रहा',
|
|
327
331
|
jobStatusStopping: 'रुक रहा',
|
|
328
332
|
jobStatusCompleted: 'पूर्ण',
|
package/src/client/locales-id.ts
CHANGED
|
@@ -294,6 +294,8 @@ export const id: Record<string, string> = {
|
|
|
294
294
|
subagentDiagUnsupported: 'Tidak didukung',
|
|
295
295
|
subagentDiagUnavailable: 'Tidak tersedia',
|
|
296
296
|
subagentThinking: 'Berpikir…',
|
|
297
|
+
subagentShowHistory: 'Tampilkan {count} subagen sebelumnya',
|
|
298
|
+
subagentHideHistory: 'Ciutkan subagen sebelumnya',
|
|
297
299
|
sideChat: 'Side Chat (beta)',
|
|
298
300
|
sideChatNew: 'Thread baru',
|
|
299
301
|
sideChatUntitled: 'Thread baru',
|
|
@@ -321,6 +323,8 @@ export const id: Record<string, string> = {
|
|
|
321
323
|
jobs: 'Tugas latar',
|
|
322
324
|
jobsCount: '{count} tugas latar',
|
|
323
325
|
jobsCountRunning: '{count} tugas latar · {running} berjalan',
|
|
326
|
+
jobsShowHistory: 'Tampilkan {count} tugas latar sebelumnya',
|
|
327
|
+
jobsHideHistory: 'Ciutkan tugas latar sebelumnya',
|
|
324
328
|
jobStatusRunning: 'Berjalan',
|
|
325
329
|
jobStatusStopping: 'Menghentikan',
|
|
326
330
|
jobStatusCompleted: 'Selesai',
|
package/src/client/locales-it.ts
CHANGED
|
@@ -287,6 +287,8 @@ export const it: Record<string, string> = {
|
|
|
287
287
|
subagentDiagUnsupported: 'Non supportato',
|
|
288
288
|
subagentDiagUnavailable: 'Non disponibile',
|
|
289
289
|
subagentThinking: 'In pensiero…',
|
|
290
|
+
subagentShowHistory: 'Mostra {count} sottoagenti precedenti',
|
|
291
|
+
subagentHideHistory: 'Comprimi sottoagenti precedenti',
|
|
290
292
|
sideChat: 'Chat laterale (beta)',
|
|
291
293
|
sideChatNew: 'Nuova conversazione',
|
|
292
294
|
sideChatUntitled: 'Nuova conversazione',
|
|
@@ -314,6 +316,8 @@ export const it: Record<string, string> = {
|
|
|
314
316
|
jobs: 'Attività in background',
|
|
315
317
|
jobsCount: '{count} attività in background',
|
|
316
318
|
jobsCountRunning: '{count} attività in background · {running} in esecuzione',
|
|
319
|
+
jobsShowHistory: 'Mostra {count} attività in background precedenti',
|
|
320
|
+
jobsHideHistory: 'Comprimi attività in background precedenti',
|
|
317
321
|
jobStatusRunning: 'In esecuzione',
|
|
318
322
|
jobStatusStopping: 'Arresto in corso',
|
|
319
323
|
jobStatusCompleted: 'Completata',
|