@norman-else/dsh-claude 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/INSTALL.md +58 -0
- package/LICENSE +21 -0
- package/README.md +184 -0
- package/cordis.patch.yml +5 -0
- package/lib/bin.d.mts +1 -0
- package/lib/bin.mjs +116 -0
- package/lib/bin.mjs.map +1 -0
- package/lib/client.d.ts +84 -0
- package/lib/client.js +1417 -0
- package/lib/client.js.map +1 -0
- package/lib/events-qlmU1KrH.mjs +186 -0
- package/lib/events-qlmU1KrH.mjs.map +1 -0
- package/lib/index.d.mts +230 -0
- package/lib/index.mjs +2272 -0
- package/lib/index.mjs.map +1 -0
- package/lib/presenters-DbfG-9KQ.mjs +302 -0
- package/lib/presenters-DbfG-9KQ.mjs.map +1 -0
- package/lib/preset-installer-DUVN1J6P.mjs +291 -0
- package/lib/preset-installer-DUVN1J6P.mjs.map +1 -0
- package/lib/preset-route.d.mts +11 -0
- package/lib/preset-route.mjs +24 -0
- package/lib/preset-route.mjs.map +1 -0
- package/package.json +124 -0
- package/preset/agent.cordis.yml +14 -0
- package/preset/preset.yml +4 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,1417 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-claude",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
module.exports;
|
|
6
|
+
var { useCallback, useEffect, useMemo, useState, useSyncExternalStore } = require("react");
|
|
7
|
+
var { Fragment, jsx, jsxs } = require("react/jsx-runtime");
|
|
8
|
+
var { DisclosureRow, IconApiOutline14, IconThinkOutline14, StateDot } = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
9
|
+
function isClaudeProvider(value) {
|
|
10
|
+
return value === "claude" || value === "claude-code-cli";
|
|
11
|
+
}
|
|
12
|
+
/** Claude's subagent dispatch tools; rendered as plugin-owned group cards
|
|
13
|
+
* gathering subagent activity instead of native tool cards. */
|
|
14
|
+
const TASK_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
|
|
15
|
+
const CLAUDE_DOCTOR_PATH = "/plugins/dsh-claude/doctor";
|
|
16
|
+
const CLAUDE_PROJECTION_PATH = "/plugins/dsh-claude/projection";
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/client/conversation-sidecar.ts
|
|
19
|
+
function isTaskActivity(value) {
|
|
20
|
+
return (value.kind === "tool-call" || value.kind === "tool-result") && value.toolName !== void 0 && TASK_TOOL_NAMES.has(value.toolName);
|
|
21
|
+
}
|
|
22
|
+
function presentable(activity) {
|
|
23
|
+
if (isTaskActivity(activity)) return true;
|
|
24
|
+
if (activity.kind === "tool-call" || activity.kind === "tool-result") return false;
|
|
25
|
+
if (activity.isError === true) return true;
|
|
26
|
+
if (activity.title?.startsWith("Unknown Claude SDK message") === true) return false;
|
|
27
|
+
switch (activity.kind) {
|
|
28
|
+
case "subagent":
|
|
29
|
+
case "permission":
|
|
30
|
+
case "warning":
|
|
31
|
+
case "error": return true;
|
|
32
|
+
case "thinking": return activity.summary !== void 0 && activity.summary.length > 0;
|
|
33
|
+
default: return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function running(activity) {
|
|
37
|
+
return activity.phase === "started" || activity.phase === "updated";
|
|
38
|
+
}
|
|
39
|
+
function subcallOf(value) {
|
|
40
|
+
if (value.kind !== "subagent" || value.toolUseId === void 0) return void 0;
|
|
41
|
+
return {
|
|
42
|
+
toolUseId: value.toolUseId,
|
|
43
|
+
...value.toolName === void 0 ? {} : { toolName: value.toolName },
|
|
44
|
+
...value.phase === void 0 ? {} : { phase: value.phase },
|
|
45
|
+
...value.summary === void 0 ? {} : { summary: value.summary },
|
|
46
|
+
...value.isError === void 0 ? {} : { isError: value.isError }
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/** Fold raw sidecar activity into the same lifecycle cards the old event projection rendered. */
|
|
50
|
+
function activityRows(activities, accepts, tasks = []) {
|
|
51
|
+
const rows = [];
|
|
52
|
+
const byId = /* @__PURE__ */ new Map();
|
|
53
|
+
for (const value of activities) {
|
|
54
|
+
if (!accepts(value)) continue;
|
|
55
|
+
const existingTaskId = value.toolUseId === void 0 ? void 0 : `task-${value.toolUseId}`;
|
|
56
|
+
const updatesExistingTask = value.kind === "tool-result" && existingTaskId !== void 0 && byId.has(existingTaskId);
|
|
57
|
+
if (!presentable(value) && !updatesExistingTask) continue;
|
|
58
|
+
let id;
|
|
59
|
+
if ((isTaskActivity(value) || updatesExistingTask) && existingTaskId !== void 0) id = existingTaskId;
|
|
60
|
+
else if (value.kind === "subagent" && value.parentToolUseId !== void 0) id = `task-${value.parentToolUseId}`;
|
|
61
|
+
else if (value.kind === "subagent" && value.toolUseId !== void 0) id = `call-${value.toolUseId}`;
|
|
62
|
+
else id = `act-${value.turn}-${value.step}-${value.ordinal}`;
|
|
63
|
+
const index = byId.get(id);
|
|
64
|
+
if (index === void 0) {
|
|
65
|
+
byId.set(id, rows.length);
|
|
66
|
+
rows.push({
|
|
67
|
+
activity: value,
|
|
68
|
+
running: running(value),
|
|
69
|
+
subcalls: []
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const previous = rows[index];
|
|
74
|
+
if (previous === void 0) continue;
|
|
75
|
+
if (value.kind === "subagent" && value.parentToolUseId !== void 0) {
|
|
76
|
+
const nested = subcallOf(value);
|
|
77
|
+
if (nested === void 0) continue;
|
|
78
|
+
const nestedIndex = previous.subcalls.findIndex((item) => item.toolUseId === nested.toolUseId);
|
|
79
|
+
const subcalls = nestedIndex === -1 ? [...previous.subcalls, nested] : previous.subcalls.map((item, position) => position === nestedIndex ? {
|
|
80
|
+
...item,
|
|
81
|
+
...nested
|
|
82
|
+
} : item);
|
|
83
|
+
rows[index] = {
|
|
84
|
+
...previous,
|
|
85
|
+
subcalls
|
|
86
|
+
};
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
rows[index] = {
|
|
90
|
+
activity: {
|
|
91
|
+
...value,
|
|
92
|
+
...value.toolName === void 0 && previous.activity.toolName !== void 0 ? { toolName: previous.activity.toolName } : {}
|
|
93
|
+
},
|
|
94
|
+
running: running(value),
|
|
95
|
+
subcalls: previous.subcalls
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
const taskStatus = new Map(tasks.map((task) => [task.taskId, task.status]));
|
|
99
|
+
return rows.map((row) => {
|
|
100
|
+
const taskId = row.activity.taskId;
|
|
101
|
+
const status = taskId === void 0 ? void 0 : taskStatus.get(taskId);
|
|
102
|
+
if (status === void 0 || status === "running") return row;
|
|
103
|
+
const failed = status === "failed" || status === "stopped" || status === "killed";
|
|
104
|
+
const settledTitle = row.activity.title?.replace(/^Running\s+/u, "");
|
|
105
|
+
return {
|
|
106
|
+
...row,
|
|
107
|
+
running: false,
|
|
108
|
+
activity: {
|
|
109
|
+
...row.activity,
|
|
110
|
+
phase: failed ? "failed" : "completed",
|
|
111
|
+
...settledTitle === void 0 ? {} : { title: settledTitle },
|
|
112
|
+
...failed ? { isError: true } : {}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function activityRowsForStep(activities, turn, step, tasks = []) {
|
|
118
|
+
return activityRows(activities, (activity) => activity.turn === turn && activity.step === step, tasks);
|
|
119
|
+
}
|
|
120
|
+
/** Anchor one sidecar-backed activity group immediately before its Claude assistant step. */
|
|
121
|
+
const claudeActivityStepDefinition = {
|
|
122
|
+
kind: "claude-activity-step",
|
|
123
|
+
target: "chat",
|
|
124
|
+
match(event) {
|
|
125
|
+
if (event.type === "step/start") return {
|
|
126
|
+
id: `${event.data.turn}:${event.data.step}`,
|
|
127
|
+
role: "start"
|
|
128
|
+
};
|
|
129
|
+
if (event.type !== "assistant/message" || !isClaudeProvider(event.data.message.source.provider)) return null;
|
|
130
|
+
return {
|
|
131
|
+
id: `${event.data.turn}:${event.data.step}`,
|
|
132
|
+
role: "update"
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
start(_context, match) {
|
|
136
|
+
if (match.event.type !== "step/start") throw new Error("Claude activity step requires step/start");
|
|
137
|
+
return {
|
|
138
|
+
turn: match.event.data.turn,
|
|
139
|
+
step: match.event.data.step
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
update(context, match) {
|
|
143
|
+
if (match.event.type !== "assistant/message") throw new Error("Claude activity step update requires assistant/message");
|
|
144
|
+
return {
|
|
145
|
+
...context.state,
|
|
146
|
+
assistantSeq: match.event.seq
|
|
147
|
+
};
|
|
148
|
+
},
|
|
149
|
+
buildViewNode(context) {
|
|
150
|
+
const state = context.state;
|
|
151
|
+
if (state?.assistantSeq === void 0) return null;
|
|
152
|
+
return {
|
|
153
|
+
key: context.key,
|
|
154
|
+
kind: "claude-activity-step",
|
|
155
|
+
id: context.id,
|
|
156
|
+
target: "chat",
|
|
157
|
+
anchorSeq: state.assistantSeq - .1,
|
|
158
|
+
location: context.start?.location ?? { kind: "unresolved" },
|
|
159
|
+
visibility: "visible",
|
|
160
|
+
data: {
|
|
161
|
+
turn: state.turn,
|
|
162
|
+
step: state.step
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
/** Publish a marker for turns containing standard assistant output from the Claude adapter. */
|
|
168
|
+
const claudeTurnDefinition = {
|
|
169
|
+
kind: "claudeCode",
|
|
170
|
+
match(event) {
|
|
171
|
+
if (event.type === "turn/start") return {
|
|
172
|
+
id: String(event.data.turn),
|
|
173
|
+
role: "start"
|
|
174
|
+
};
|
|
175
|
+
if (event.type !== "assistant/message" || !isClaudeProvider(event.data.message.source.provider)) return null;
|
|
176
|
+
return {
|
|
177
|
+
id: String(event.data.turn),
|
|
178
|
+
role: "update"
|
|
179
|
+
};
|
|
180
|
+
},
|
|
181
|
+
start(_context, match) {
|
|
182
|
+
if (match.event.type !== "turn/start") throw new Error("Claude turn marker requires turn/start");
|
|
183
|
+
return {
|
|
184
|
+
turn: match.event.data.turn,
|
|
185
|
+
claude: false
|
|
186
|
+
};
|
|
187
|
+
},
|
|
188
|
+
update(context, match) {
|
|
189
|
+
if (match.event.type !== "assistant/message") throw new Error("Claude turn marker update requires assistant/message");
|
|
190
|
+
return context.state.claude ? context.state : {
|
|
191
|
+
turn: context.state.turn,
|
|
192
|
+
claude: true
|
|
193
|
+
};
|
|
194
|
+
},
|
|
195
|
+
buildLocationData(context, scope) {
|
|
196
|
+
if (scope !== "turn" || context.state?.claude !== true) return null;
|
|
197
|
+
const value = { turn: context.state.turn };
|
|
198
|
+
return {
|
|
199
|
+
kind: "turn",
|
|
200
|
+
turn: context.state.turn,
|
|
201
|
+
key: "claudeCode",
|
|
202
|
+
value
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
/** Pure chain selector: only Claude-produced turns mount the sidecar-backed tail. */
|
|
207
|
+
function selectClaudeTurn(owner) {
|
|
208
|
+
return owner.turn.data.get("claudeCode") ?? null;
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/client/styles.ts
|
|
212
|
+
const iconChipRunning = { color: "var(--dsw-static-blue-450)" };
|
|
213
|
+
const iconChipError = { color: "var(--dsw-alias-state-error-primary)" };
|
|
214
|
+
const chevron = {
|
|
215
|
+
flex: "none",
|
|
216
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
217
|
+
fontSize: 11,
|
|
218
|
+
lineHeight: "20px",
|
|
219
|
+
transition: "transform 120ms ease",
|
|
220
|
+
userSelect: "none"
|
|
221
|
+
};
|
|
222
|
+
const chevronOpen = { transform: "rotate(90deg)" };
|
|
223
|
+
const detailCode = {
|
|
224
|
+
maxHeight: 220,
|
|
225
|
+
overflow: "auto",
|
|
226
|
+
margin: "5px 0 0",
|
|
227
|
+
padding: "8px 10px",
|
|
228
|
+
borderRadius: 6,
|
|
229
|
+
background: "var(--dsw-alias-bg-layer-2)",
|
|
230
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
231
|
+
fontSize: 11,
|
|
232
|
+
lineHeight: "17px",
|
|
233
|
+
whiteSpace: "pre-wrap",
|
|
234
|
+
overflowWrap: "anywhere"
|
|
235
|
+
};
|
|
236
|
+
const settingsPage = {
|
|
237
|
+
display: "flex",
|
|
238
|
+
flexDirection: "column",
|
|
239
|
+
gap: 18,
|
|
240
|
+
maxWidth: 760
|
|
241
|
+
};
|
|
242
|
+
const settingsHeading = {
|
|
243
|
+
margin: 0,
|
|
244
|
+
color: "var(--dsw-alias-label-primary)",
|
|
245
|
+
fontSize: 20,
|
|
246
|
+
lineHeight: "28px",
|
|
247
|
+
fontWeight: 650
|
|
248
|
+
};
|
|
249
|
+
const settingsBody = {
|
|
250
|
+
margin: 0,
|
|
251
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
252
|
+
fontSize: 14,
|
|
253
|
+
lineHeight: "22px"
|
|
254
|
+
};
|
|
255
|
+
const diagnosticGrid = {
|
|
256
|
+
display: "grid",
|
|
257
|
+
gridTemplateColumns: "minmax(130px, 0.4fr) minmax(0, 1fr)",
|
|
258
|
+
gap: "9px 18px",
|
|
259
|
+
padding: "16px 0",
|
|
260
|
+
borderTop: "1px solid var(--dsw-alias-border-l2)",
|
|
261
|
+
borderBottom: "1px solid var(--dsw-alias-border-l2)",
|
|
262
|
+
fontSize: 13
|
|
263
|
+
};
|
|
264
|
+
const diagnosticLabel = { color: "var(--dsw-alias-label-tertiary)" };
|
|
265
|
+
const diagnosticValue = {
|
|
266
|
+
color: "var(--dsw-alias-label-primary)",
|
|
267
|
+
overflowWrap: "anywhere"
|
|
268
|
+
};
|
|
269
|
+
const button = {
|
|
270
|
+
alignSelf: "flex-start",
|
|
271
|
+
minHeight: 34,
|
|
272
|
+
padding: "6px 14px",
|
|
273
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
274
|
+
borderRadius: 18,
|
|
275
|
+
background: "var(--dsw-alias-bg-layer-1)",
|
|
276
|
+
color: "var(--dsw-alias-label-primary)",
|
|
277
|
+
font: "inherit",
|
|
278
|
+
fontSize: 13,
|
|
279
|
+
cursor: "pointer"
|
|
280
|
+
};
|
|
281
|
+
const tasksPanel = {
|
|
282
|
+
display: "flex",
|
|
283
|
+
flexDirection: "column",
|
|
284
|
+
height: "100%",
|
|
285
|
+
minWidth: 0,
|
|
286
|
+
background: "var(--dsw-alias-bg-base)"
|
|
287
|
+
};
|
|
288
|
+
const tasksHeader = {
|
|
289
|
+
display: "flex",
|
|
290
|
+
alignItems: "center",
|
|
291
|
+
justifyContent: "space-between",
|
|
292
|
+
gap: 8,
|
|
293
|
+
padding: "12px 14px",
|
|
294
|
+
borderBottom: "1px solid var(--dsw-alias-border-l2)"
|
|
295
|
+
};
|
|
296
|
+
const tasksHeading = {
|
|
297
|
+
color: "var(--dsw-alias-label-primary)",
|
|
298
|
+
fontSize: 14,
|
|
299
|
+
lineHeight: "20px",
|
|
300
|
+
fontWeight: 600
|
|
301
|
+
};
|
|
302
|
+
const tasksClose = {
|
|
303
|
+
width: 26,
|
|
304
|
+
height: 26,
|
|
305
|
+
display: "grid",
|
|
306
|
+
placeItems: "center",
|
|
307
|
+
border: "none",
|
|
308
|
+
borderRadius: 7,
|
|
309
|
+
background: "transparent",
|
|
310
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
311
|
+
fontSize: 15,
|
|
312
|
+
lineHeight: "1",
|
|
313
|
+
cursor: "pointer"
|
|
314
|
+
};
|
|
315
|
+
const tasksBody = {
|
|
316
|
+
flex: 1,
|
|
317
|
+
minHeight: 0,
|
|
318
|
+
overflowY: "auto",
|
|
319
|
+
padding: "10px 12px 20px"
|
|
320
|
+
};
|
|
321
|
+
const tasksGroupHeading = {
|
|
322
|
+
minHeight: 30,
|
|
323
|
+
display: "flex",
|
|
324
|
+
alignItems: "center",
|
|
325
|
+
justifyContent: "space-between",
|
|
326
|
+
gap: 8
|
|
327
|
+
};
|
|
328
|
+
const tasksGroupTitle = {
|
|
329
|
+
display: "inline-flex",
|
|
330
|
+
alignItems: "center",
|
|
331
|
+
gap: 6,
|
|
332
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
333
|
+
fontSize: 12,
|
|
334
|
+
lineHeight: "20px",
|
|
335
|
+
fontWeight: 600
|
|
336
|
+
};
|
|
337
|
+
const tasksGroupToggle = {
|
|
338
|
+
display: "inline-flex",
|
|
339
|
+
alignItems: "center",
|
|
340
|
+
gap: 5,
|
|
341
|
+
padding: 0,
|
|
342
|
+
border: "none",
|
|
343
|
+
background: "transparent",
|
|
344
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
345
|
+
font: "inherit",
|
|
346
|
+
fontSize: 12,
|
|
347
|
+
lineHeight: "20px",
|
|
348
|
+
fontWeight: 600,
|
|
349
|
+
cursor: "pointer"
|
|
350
|
+
};
|
|
351
|
+
const tasksGroupCount = {
|
|
352
|
+
minWidth: 18,
|
|
353
|
+
padding: "0 5px",
|
|
354
|
+
borderRadius: 999,
|
|
355
|
+
background: "var(--dsw-alias-bg-layer-2)",
|
|
356
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
357
|
+
fontSize: 10,
|
|
358
|
+
lineHeight: "17px",
|
|
359
|
+
textAlign: "center",
|
|
360
|
+
fontVariantNumeric: "tabular-nums"
|
|
361
|
+
};
|
|
362
|
+
const tasksGroupEmpty = {
|
|
363
|
+
margin: "5px 4px 2px",
|
|
364
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
365
|
+
fontSize: 12,
|
|
366
|
+
lineHeight: "18px"
|
|
367
|
+
};
|
|
368
|
+
const tasksFinishedSection = {
|
|
369
|
+
marginTop: 12,
|
|
370
|
+
paddingTop: 8,
|
|
371
|
+
borderTop: "1px solid var(--dsw-alias-border-l2)"
|
|
372
|
+
};
|
|
373
|
+
const taskCardList = {
|
|
374
|
+
display: "flex",
|
|
375
|
+
flexDirection: "column",
|
|
376
|
+
gap: 8,
|
|
377
|
+
marginTop: 4
|
|
378
|
+
};
|
|
379
|
+
const taskCard = {
|
|
380
|
+
padding: "10px 11px",
|
|
381
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
382
|
+
borderRadius: 10,
|
|
383
|
+
background: "var(--dsw-alias-bg-layer-1)"
|
|
384
|
+
};
|
|
385
|
+
const taskCardRunning = { borderColor: "var(--dsw-alias-border-l3)" };
|
|
386
|
+
const taskCardTop = {
|
|
387
|
+
display: "flex",
|
|
388
|
+
alignItems: "flex-start",
|
|
389
|
+
gap: 9
|
|
390
|
+
};
|
|
391
|
+
const taskCardGlyph = {
|
|
392
|
+
width: 18,
|
|
393
|
+
height: 18,
|
|
394
|
+
flex: "none",
|
|
395
|
+
display: "grid",
|
|
396
|
+
placeItems: "center",
|
|
397
|
+
marginTop: 1,
|
|
398
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
399
|
+
fontSize: 11,
|
|
400
|
+
lineHeight: 1
|
|
401
|
+
};
|
|
402
|
+
const taskCardBody = {
|
|
403
|
+
flex: 1,
|
|
404
|
+
minWidth: 0
|
|
405
|
+
};
|
|
406
|
+
const taskTitle = {
|
|
407
|
+
margin: 0,
|
|
408
|
+
color: "var(--dsw-alias-label-primary)",
|
|
409
|
+
fontSize: 13,
|
|
410
|
+
lineHeight: "19px",
|
|
411
|
+
fontWeight: 550,
|
|
412
|
+
overflowWrap: "anywhere"
|
|
413
|
+
};
|
|
414
|
+
const taskStatusLine = {
|
|
415
|
+
margin: "1px 0 0",
|
|
416
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
417
|
+
fontSize: 11,
|
|
418
|
+
lineHeight: "17px"
|
|
419
|
+
};
|
|
420
|
+
const taskMeta$1 = {
|
|
421
|
+
margin: "7px 0 0 27px",
|
|
422
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
423
|
+
fontSize: 11,
|
|
424
|
+
lineHeight: "17px",
|
|
425
|
+
overflowWrap: "anywhere"
|
|
426
|
+
};
|
|
427
|
+
const taskSummary = {
|
|
428
|
+
margin: "6px 0 0 27px",
|
|
429
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
430
|
+
fontSize: 12,
|
|
431
|
+
lineHeight: "18px",
|
|
432
|
+
whiteSpace: "pre-wrap",
|
|
433
|
+
overflowWrap: "anywhere"
|
|
434
|
+
};
|
|
435
|
+
const taskTextButton = {
|
|
436
|
+
padding: 0,
|
|
437
|
+
border: "none",
|
|
438
|
+
background: "transparent",
|
|
439
|
+
color: "var(--dsw-static-blue-450)",
|
|
440
|
+
font: "inherit",
|
|
441
|
+
fontSize: 11,
|
|
442
|
+
lineHeight: "18px",
|
|
443
|
+
cursor: "pointer"
|
|
444
|
+
};
|
|
445
|
+
const taskActivitySection = { margin: "7px 0 0 27px" };
|
|
446
|
+
const taskActivityList = {
|
|
447
|
+
display: "flex",
|
|
448
|
+
flexDirection: "column",
|
|
449
|
+
gap: 7,
|
|
450
|
+
margin: "7px 0 0",
|
|
451
|
+
padding: "8px 9px",
|
|
452
|
+
borderRadius: 8,
|
|
453
|
+
background: "var(--dsw-alias-bg-layer-2)",
|
|
454
|
+
listStyle: "none"
|
|
455
|
+
};
|
|
456
|
+
const taskActivityItem = {
|
|
457
|
+
display: "flex",
|
|
458
|
+
alignItems: "flex-start",
|
|
459
|
+
gap: 6
|
|
460
|
+
};
|
|
461
|
+
const taskActivityGlyph = {
|
|
462
|
+
flex: "none",
|
|
463
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
464
|
+
fontSize: 11,
|
|
465
|
+
lineHeight: "17px"
|
|
466
|
+
};
|
|
467
|
+
const taskActivityBody = {
|
|
468
|
+
flex: 1,
|
|
469
|
+
minWidth: 0
|
|
470
|
+
};
|
|
471
|
+
const taskActivityTitle = {
|
|
472
|
+
margin: 0,
|
|
473
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
474
|
+
fontSize: 11,
|
|
475
|
+
lineHeight: "17px",
|
|
476
|
+
fontWeight: 500,
|
|
477
|
+
overflowWrap: "anywhere"
|
|
478
|
+
};
|
|
479
|
+
const taskActivitySummary = {
|
|
480
|
+
margin: "1px 0 0",
|
|
481
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
482
|
+
fontSize: 11,
|
|
483
|
+
lineHeight: "17px",
|
|
484
|
+
whiteSpace: "pre-wrap",
|
|
485
|
+
overflowWrap: "anywhere"
|
|
486
|
+
};
|
|
487
|
+
const taskActivityDetail = { marginTop: 3 };
|
|
488
|
+
const taskActivityDetailSummary = {
|
|
489
|
+
color: "var(--dsw-alias-label-tertiary)",
|
|
490
|
+
fontSize: 10,
|
|
491
|
+
lineHeight: "16px",
|
|
492
|
+
cursor: "pointer"
|
|
493
|
+
};
|
|
494
|
+
const tasksTurnLauncher = {
|
|
495
|
+
display: "inline-flex",
|
|
496
|
+
alignItems: "center",
|
|
497
|
+
gap: 7,
|
|
498
|
+
margin: "6px 0 2px",
|
|
499
|
+
padding: "5px 8px",
|
|
500
|
+
border: "none",
|
|
501
|
+
borderRadius: 8,
|
|
502
|
+
background: "transparent",
|
|
503
|
+
color: "var(--dsw-alias-label-secondary)",
|
|
504
|
+
font: "inherit",
|
|
505
|
+
fontSize: 12,
|
|
506
|
+
lineHeight: "18px",
|
|
507
|
+
cursor: "pointer"
|
|
508
|
+
};
|
|
509
|
+
const tasksTurnLauncherDot = {
|
|
510
|
+
color: "var(--dsw-static-blue-450)",
|
|
511
|
+
fontSize: 9
|
|
512
|
+
};
|
|
513
|
+
const tasksTriggerHoverCss = [
|
|
514
|
+
".dsh-claude-tasks-trigger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}",
|
|
515
|
+
".dsh-claude-tasks-trigger:focus:not(:focus-visible){outline:none;border-color:var(--dsw-alias-border-l2)}",
|
|
516
|
+
".dsh-claude-tasks-trigger[aria-pressed=\"true\"]:focus:not(:focus-visible){border-color:var(--dsw-alias-border-l3)}",
|
|
517
|
+
".dsh-claude-tasks-trigger>span,.dsh-claude-tasks-trigger>svg{flex:none}"
|
|
518
|
+
].join("");
|
|
519
|
+
const tasksHeaderButton = {
|
|
520
|
+
minWidth: 111,
|
|
521
|
+
height: 32,
|
|
522
|
+
display: "inline-flex",
|
|
523
|
+
alignItems: "center",
|
|
524
|
+
justifyContent: "center",
|
|
525
|
+
gap: 4,
|
|
526
|
+
padding: "6px 12px",
|
|
527
|
+
border: "1px solid var(--dsw-alias-border-l2)",
|
|
528
|
+
borderRadius: 18,
|
|
529
|
+
color: "var(--dsw-alias-label-primary)",
|
|
530
|
+
fontFamily: "var(--dsw-font-family)",
|
|
531
|
+
fontSize: 13,
|
|
532
|
+
fontWeight: 400,
|
|
533
|
+
lineHeight: "20px",
|
|
534
|
+
whiteSpace: "nowrap",
|
|
535
|
+
cursor: "pointer"
|
|
536
|
+
};
|
|
537
|
+
const tasksHeaderButtonActive = {
|
|
538
|
+
borderColor: "var(--dsw-alias-border-l3)",
|
|
539
|
+
background: "var(--dsw-alias-interactive-bg-hover)"
|
|
540
|
+
};
|
|
541
|
+
const tasksBadgeInline = {
|
|
542
|
+
minWidth: 14,
|
|
543
|
+
height: 14,
|
|
544
|
+
display: "grid",
|
|
545
|
+
placeItems: "center",
|
|
546
|
+
padding: "0 3px",
|
|
547
|
+
borderRadius: 999,
|
|
548
|
+
background: "var(--dsw-static-blue-450)",
|
|
549
|
+
color: "var(--dsw-alias-label-on-accent, #fff)",
|
|
550
|
+
fontSize: 9,
|
|
551
|
+
lineHeight: "1",
|
|
552
|
+
fontWeight: 600
|
|
553
|
+
};
|
|
554
|
+
//#endregion
|
|
555
|
+
//#region src/client/token-format.ts
|
|
556
|
+
function formatTokenCount(tokens) {
|
|
557
|
+
if (tokens >= 1e6) return `${Number((tokens / 1e6).toFixed(tokens >= 1e7 ? 0 : 1))}M`;
|
|
558
|
+
if (tokens >= 1e3) return `${Number((tokens / 1e3).toFixed(tokens >= 1e5 ? 0 : 1))}K`;
|
|
559
|
+
return String(tokens);
|
|
560
|
+
}
|
|
561
|
+
//#endregion
|
|
562
|
+
//#region src/client/ClaudeTasksPanel.tsx
|
|
563
|
+
const STATUS_LABEL = {
|
|
564
|
+
running: "tasksRunning",
|
|
565
|
+
completed: "tasksCompleted",
|
|
566
|
+
failed: "tasksFailed",
|
|
567
|
+
stopped: "tasksStopped",
|
|
568
|
+
killed: "tasksKilled"
|
|
569
|
+
};
|
|
570
|
+
function visibleTaskGroups(tasks, dismissedSettledIds) {
|
|
571
|
+
return {
|
|
572
|
+
running: tasks.filter((task) => task.status === "running"),
|
|
573
|
+
finished: tasks.filter((task) => task.status !== "running" && !dismissedSettledIds.has(task.taskId))
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
function activitiesForTask(activities, taskId) {
|
|
577
|
+
return activities.filter((activity) => activity.taskId === taskId);
|
|
578
|
+
}
|
|
579
|
+
function runningTasksForTurn(tasks, turn) {
|
|
580
|
+
return tasks.filter((task) => task.status === "running" && task.originTurn === turn);
|
|
581
|
+
}
|
|
582
|
+
function statusGlyph(status) {
|
|
583
|
+
if (status === "running") return "●";
|
|
584
|
+
if (status === "completed") return "✓";
|
|
585
|
+
if (status === "stopped") return "–";
|
|
586
|
+
return "×";
|
|
587
|
+
}
|
|
588
|
+
function formatDuration(ms) {
|
|
589
|
+
if (ms < 1e3) return String(Math.max(1, Math.round(ms))) + "ms";
|
|
590
|
+
const seconds = Math.round(ms / 1e3);
|
|
591
|
+
if (seconds < 60) return String(seconds) + "s";
|
|
592
|
+
const minutes = Math.floor(seconds / 60);
|
|
593
|
+
return String(minutes) + "m " + String(seconds % 60) + "s";
|
|
594
|
+
}
|
|
595
|
+
function taskMeta(task, t) {
|
|
596
|
+
const parts = [];
|
|
597
|
+
if (task.subagentType !== void 0) parts.push(task.subagentType);
|
|
598
|
+
else if (task.taskType !== void 0) parts.push(task.taskType);
|
|
599
|
+
if (task.usage?.durationMs !== void 0) parts.push(formatDuration(task.usage.durationMs));
|
|
600
|
+
if (task.usage?.totalTokens !== void 0) parts.push(t("tokens", { count: formatTokenCount(task.usage.totalTokens) }));
|
|
601
|
+
if (task.usage?.toolUses !== void 0) parts.push(t("tasksToolUses", { count: task.usage.toolUses }));
|
|
602
|
+
if (task.lastToolName !== void 0) parts.push(t("tasksLastTool", { tool: task.lastToolName }));
|
|
603
|
+
return parts;
|
|
604
|
+
}
|
|
605
|
+
function TaskActivity({ activity, t }) {
|
|
606
|
+
return /* @__PURE__ */ jsxs("li", {
|
|
607
|
+
style: taskActivityItem,
|
|
608
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
609
|
+
style: taskActivityGlyph,
|
|
610
|
+
"aria-hidden": "true",
|
|
611
|
+
children: activity.isError === true ? "×" : "›"
|
|
612
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
613
|
+
style: taskActivityBody,
|
|
614
|
+
children: [
|
|
615
|
+
/* @__PURE__ */ jsx("p", {
|
|
616
|
+
style: taskActivityTitle,
|
|
617
|
+
children: activity.title ?? activity.kind
|
|
618
|
+
}),
|
|
619
|
+
activity.summary === void 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
620
|
+
style: taskActivitySummary,
|
|
621
|
+
children: activity.summary
|
|
622
|
+
}),
|
|
623
|
+
activity.detail === void 0 ? null : /* @__PURE__ */ jsxs("details", {
|
|
624
|
+
style: taskActivityDetail,
|
|
625
|
+
children: [/* @__PURE__ */ jsx("summary", {
|
|
626
|
+
style: taskActivityDetailSummary,
|
|
627
|
+
children: t("detail")
|
|
628
|
+
}), /* @__PURE__ */ jsx("pre", {
|
|
629
|
+
style: detailCode,
|
|
630
|
+
children: activity.detail
|
|
631
|
+
})]
|
|
632
|
+
})
|
|
633
|
+
]
|
|
634
|
+
})]
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
function TaskCard(props) {
|
|
638
|
+
const { task, activities, t } = props;
|
|
639
|
+
const [activityOpen, setActivityOpen] = useState(false);
|
|
640
|
+
const running = task.status === "running";
|
|
641
|
+
const failed = task.status === "failed" || task.status === "killed";
|
|
642
|
+
const meta = taskMeta(task, t);
|
|
643
|
+
return /* @__PURE__ */ jsxs("article", {
|
|
644
|
+
style: {
|
|
645
|
+
...taskCard,
|
|
646
|
+
...running ? taskCardRunning : {}
|
|
647
|
+
},
|
|
648
|
+
children: [
|
|
649
|
+
/* @__PURE__ */ jsxs("div", {
|
|
650
|
+
style: taskCardTop,
|
|
651
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
652
|
+
className: running ? "dsh-claude-act-running" : void 0,
|
|
653
|
+
style: {
|
|
654
|
+
...taskCardGlyph,
|
|
655
|
+
...running ? iconChipRunning : {},
|
|
656
|
+
...failed ? iconChipError : {}
|
|
657
|
+
},
|
|
658
|
+
"aria-hidden": "true",
|
|
659
|
+
children: statusGlyph(task.status)
|
|
660
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
661
|
+
style: taskCardBody,
|
|
662
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
663
|
+
style: {
|
|
664
|
+
...taskTitle,
|
|
665
|
+
...failed ? { color: "var(--dsw-alias-state-error-primary)" } : {}
|
|
666
|
+
},
|
|
667
|
+
children: task.description
|
|
668
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
669
|
+
style: taskStatusLine,
|
|
670
|
+
children: [/* @__PURE__ */ jsx("span", { children: t(STATUS_LABEL[task.status] ?? "tasksRunning") }), task.backgrounded === true ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
671
|
+
"aria-hidden": "true",
|
|
672
|
+
children: " · "
|
|
673
|
+
}), /* @__PURE__ */ jsx("span", { children: t("tasksBackground") })] }) : null]
|
|
674
|
+
})]
|
|
675
|
+
})]
|
|
676
|
+
}),
|
|
677
|
+
meta.length === 0 ? null : /* @__PURE__ */ jsx("p", {
|
|
678
|
+
style: taskMeta$1,
|
|
679
|
+
children: meta.join(" · ")
|
|
680
|
+
}),
|
|
681
|
+
task.summary === void 0 || running ? null : /* @__PURE__ */ jsx("p", {
|
|
682
|
+
style: taskSummary,
|
|
683
|
+
children: task.summary
|
|
684
|
+
}),
|
|
685
|
+
activities.length === 0 ? null : /* @__PURE__ */ jsxs("div", {
|
|
686
|
+
style: taskActivitySection,
|
|
687
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
688
|
+
type: "button",
|
|
689
|
+
style: taskTextButton,
|
|
690
|
+
"aria-expanded": activityOpen,
|
|
691
|
+
onClick: () => setActivityOpen((value) => !value),
|
|
692
|
+
children: activityOpen ? t("tasksHideActivity") : t("tasksViewActivity")
|
|
693
|
+
}), activityOpen ? /* @__PURE__ */ jsx("ul", {
|
|
694
|
+
style: taskActivityList,
|
|
695
|
+
children: activities.map((activity) => /* @__PURE__ */ jsx(TaskActivity, {
|
|
696
|
+
activity,
|
|
697
|
+
t
|
|
698
|
+
}, `${activity.turn}:${activity.step}:${activity.ordinal}`))
|
|
699
|
+
}) : null]
|
|
700
|
+
})
|
|
701
|
+
]
|
|
702
|
+
});
|
|
703
|
+
}
|
|
704
|
+
function GroupHeading(props) {
|
|
705
|
+
const { label, count, collapsed, onToggle, action } = props;
|
|
706
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", {
|
|
707
|
+
style: tasksGroupCount,
|
|
708
|
+
children: count
|
|
709
|
+
})] });
|
|
710
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
711
|
+
style: tasksGroupHeading,
|
|
712
|
+
children: [onToggle === void 0 ? /* @__PURE__ */ jsx("div", {
|
|
713
|
+
style: tasksGroupTitle,
|
|
714
|
+
children: content
|
|
715
|
+
}) : /* @__PURE__ */ jsxs("button", {
|
|
716
|
+
type: "button",
|
|
717
|
+
style: tasksGroupToggle,
|
|
718
|
+
"aria-expanded": !collapsed,
|
|
719
|
+
onClick: onToggle,
|
|
720
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
721
|
+
style: {
|
|
722
|
+
...chevron,
|
|
723
|
+
...collapsed === true ? {} : chevronOpen
|
|
724
|
+
},
|
|
725
|
+
children: "›"
|
|
726
|
+
}), content]
|
|
727
|
+
}), action === void 0 ? null : /* @__PURE__ */ jsx("button", {
|
|
728
|
+
type: "button",
|
|
729
|
+
style: taskTextButton,
|
|
730
|
+
onClick: action.onClick,
|
|
731
|
+
children: action.label
|
|
732
|
+
})]
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
function ClaudeTasksPanel({ useClaudeProjection, t, closeDetails }) {
|
|
736
|
+
const projection = useClaudeProjection((value) => value);
|
|
737
|
+
useEffect(() => {
|
|
738
|
+
if (!projection.owned) closeDetails();
|
|
739
|
+
}, [closeDetails, projection.owned]);
|
|
740
|
+
const tasks = projection.tasks?.tasks ?? [];
|
|
741
|
+
const [finishedCollapsed, setFinishedCollapsed] = useState(false);
|
|
742
|
+
const [dismissedSettledIds, setDismissedSettledIds] = useState(() => /* @__PURE__ */ new Set());
|
|
743
|
+
const groups = useMemo(() => visibleTaskGroups(tasks, dismissedSettledIds), [tasks, dismissedSettledIds]);
|
|
744
|
+
const taskActivities = useMemo(() => new Map(tasks.map((task) => [task.taskId, activitiesForTask(projection.activities, task.taskId)])), [projection.activities, tasks]);
|
|
745
|
+
const clearFinished = () => setDismissedSettledIds((previous) => /* @__PURE__ */ new Set([...previous, ...tasks.filter((task) => task.status !== "running").map((task) => task.taskId)]));
|
|
746
|
+
if (!projection.owned) return null;
|
|
747
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
748
|
+
style: tasksPanel,
|
|
749
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
750
|
+
style: tasksHeader,
|
|
751
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
752
|
+
style: tasksHeading,
|
|
753
|
+
children: t("tasksPanel")
|
|
754
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
755
|
+
type: "button",
|
|
756
|
+
style: tasksClose,
|
|
757
|
+
"aria-label": t("tasksClose"),
|
|
758
|
+
onClick: closeDetails,
|
|
759
|
+
children: "×"
|
|
760
|
+
})]
|
|
761
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
762
|
+
style: tasksBody,
|
|
763
|
+
children: [/* @__PURE__ */ jsxs("section", {
|
|
764
|
+
"aria-label": t("tasksRunning"),
|
|
765
|
+
children: [/* @__PURE__ */ jsx(GroupHeading, {
|
|
766
|
+
label: t("tasksRunning"),
|
|
767
|
+
count: groups.running.length
|
|
768
|
+
}), groups.running.length === 0 ? /* @__PURE__ */ jsx("p", {
|
|
769
|
+
style: tasksGroupEmpty,
|
|
770
|
+
children: t("tasksNoneRunning")
|
|
771
|
+
}) : /* @__PURE__ */ jsx("div", {
|
|
772
|
+
style: taskCardList,
|
|
773
|
+
children: groups.running.map((task) => /* @__PURE__ */ jsx(TaskCard, {
|
|
774
|
+
task,
|
|
775
|
+
activities: taskActivities.get(task.taskId) ?? [],
|
|
776
|
+
t
|
|
777
|
+
}, task.taskId))
|
|
778
|
+
})]
|
|
779
|
+
}), /* @__PURE__ */ jsxs("section", {
|
|
780
|
+
"aria-label": t("tasksSettled"),
|
|
781
|
+
style: tasksFinishedSection,
|
|
782
|
+
children: [/* @__PURE__ */ jsx(GroupHeading, {
|
|
783
|
+
label: t("tasksSettled"),
|
|
784
|
+
count: groups.finished.length,
|
|
785
|
+
collapsed: finishedCollapsed,
|
|
786
|
+
onToggle: () => setFinishedCollapsed((value) => !value),
|
|
787
|
+
...groups.finished.length === 0 ? {} : { action: {
|
|
788
|
+
label: t("tasksClear"),
|
|
789
|
+
onClick: clearFinished
|
|
790
|
+
} }
|
|
791
|
+
}), finishedCollapsed || groups.finished.length === 0 ? null : /* @__PURE__ */ jsx("div", {
|
|
792
|
+
style: taskCardList,
|
|
793
|
+
children: groups.finished.map((task) => /* @__PURE__ */ jsx(TaskCard, {
|
|
794
|
+
task,
|
|
795
|
+
activities: taskActivities.get(task.taskId) ?? [],
|
|
796
|
+
t
|
|
797
|
+
}, task.taskId))
|
|
798
|
+
})]
|
|
799
|
+
})]
|
|
800
|
+
})]
|
|
801
|
+
});
|
|
802
|
+
}
|
|
803
|
+
function ClaudeTasksHeaderButton({ useClaudeProjection, t, isOpen, toggle, subscribe }) {
|
|
804
|
+
const open = useSyncExternalStore(subscribe, isOpen, isOpen);
|
|
805
|
+
const projection = useClaudeProjection((value) => value);
|
|
806
|
+
if (!projection.owned) return null;
|
|
807
|
+
const runningCount = projection.tasks?.tasks.filter((task) => task.status === "running").length ?? 0;
|
|
808
|
+
return /* @__PURE__ */ jsxs("button", {
|
|
809
|
+
type: "button",
|
|
810
|
+
className: "dsh-claude-tasks-trigger",
|
|
811
|
+
style: {
|
|
812
|
+
...tasksHeaderButton,
|
|
813
|
+
...open ? tasksHeaderButtonActive : {}
|
|
814
|
+
},
|
|
815
|
+
"aria-label": t("tasksOpen"),
|
|
816
|
+
"aria-pressed": open,
|
|
817
|
+
onClick: (event) => {
|
|
818
|
+
toggle();
|
|
819
|
+
event.currentTarget.blur();
|
|
820
|
+
},
|
|
821
|
+
children: [
|
|
822
|
+
/* @__PURE__ */ jsx("style", { children: tasksTriggerHoverCss }),
|
|
823
|
+
/* @__PURE__ */ jsxs("svg", {
|
|
824
|
+
width: "14",
|
|
825
|
+
height: "14",
|
|
826
|
+
viewBox: "0 0 24 24",
|
|
827
|
+
fill: "none",
|
|
828
|
+
stroke: "currentColor",
|
|
829
|
+
strokeWidth: "2",
|
|
830
|
+
strokeLinecap: "round",
|
|
831
|
+
strokeLinejoin: "round",
|
|
832
|
+
"aria-hidden": "true",
|
|
833
|
+
children: [
|
|
834
|
+
/* @__PURE__ */ jsx("path", { d: "m3 17 2 2 4-4" }),
|
|
835
|
+
/* @__PURE__ */ jsx("path", { d: "m3 7 2 2 4-4" }),
|
|
836
|
+
/* @__PURE__ */ jsx("path", { d: "M13 6h8" }),
|
|
837
|
+
/* @__PURE__ */ jsx("path", { d: "M13 12h8" }),
|
|
838
|
+
/* @__PURE__ */ jsx("path", { d: "M13 18h8" })
|
|
839
|
+
]
|
|
840
|
+
}),
|
|
841
|
+
/* @__PURE__ */ jsx("span", { children: t("tasks") }),
|
|
842
|
+
runningCount === 0 ? null : /* @__PURE__ */ jsx("span", {
|
|
843
|
+
className: "dsh-claude-act-running",
|
|
844
|
+
style: tasksBadgeInline,
|
|
845
|
+
"aria-hidden": "true",
|
|
846
|
+
children: runningCount
|
|
847
|
+
})
|
|
848
|
+
]
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
//#endregion
|
|
852
|
+
//#region src/client/ClaudeActivityTail.tsx
|
|
853
|
+
function ClaudeActivityTail({ matched, useClaudeProjection, t, openTasks }) {
|
|
854
|
+
const projection = useClaudeProjection((value) => value);
|
|
855
|
+
const runningTasks = useMemo(() => runningTasksForTurn(projection.tasks?.tasks ?? [], matched.turn), [projection.tasks, matched.turn]);
|
|
856
|
+
if (runningTasks.length === 0) return null;
|
|
857
|
+
return /* @__PURE__ */ jsx("div", {
|
|
858
|
+
"data-claude-activity-tail": matched.turn,
|
|
859
|
+
children: runningTasks.length === 0 ? null : /* @__PURE__ */ jsxs("button", {
|
|
860
|
+
type: "button",
|
|
861
|
+
style: tasksTurnLauncher,
|
|
862
|
+
onClick: openTasks,
|
|
863
|
+
children: [
|
|
864
|
+
/* @__PURE__ */ jsx("span", {
|
|
865
|
+
className: "dsh-claude-act-running",
|
|
866
|
+
style: tasksTurnLauncherDot,
|
|
867
|
+
"aria-hidden": "true",
|
|
868
|
+
children: "●"
|
|
869
|
+
}),
|
|
870
|
+
/* @__PURE__ */ jsx("span", { children: t("tasksRunningCount", { count: runningTasks.length }) }),
|
|
871
|
+
/* @__PURE__ */ jsx("span", {
|
|
872
|
+
"aria-hidden": "true",
|
|
873
|
+
children: "›"
|
|
874
|
+
})
|
|
875
|
+
]
|
|
876
|
+
})
|
|
877
|
+
});
|
|
878
|
+
}
|
|
879
|
+
//#endregion
|
|
880
|
+
//#region src/client/ClaudeActivityNode.tsx
|
|
881
|
+
const EMPTY_TASKS = [];
|
|
882
|
+
const ACTIVITY_CSS = [
|
|
883
|
+
".dsh-claude-flow{display:flex;flex-direction:column;gap:4px}",
|
|
884
|
+
".dsh-claude-flow-row{position:relative;overflow:hidden}",
|
|
885
|
+
".dsh-claude-flow-leading{flex-shrink:0}",
|
|
886
|
+
".dsh-claude-flow-title{font-weight:400}",
|
|
887
|
+
".dsh-claude-flow-chevron{color:var(--dsw-alias-label-secondary)}",
|
|
888
|
+
".dsh-claude-flow-separator{width:2px;height:2px;margin:0 8px;border-radius:1px;background:var(--dsw-alias-label-caption);flex:none}",
|
|
889
|
+
".dsh-claude-flow-summary{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:24px;flex:auto}",
|
|
890
|
+
".dsh-claude-flow-summary[data-error]{color:var(--dsw-alias-state-error-primary)}",
|
|
891
|
+
".dsh-claude-flow-body{margin:4px 0 4px 22px;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:24px;white-space:pre-wrap;overflow-wrap:anywhere}",
|
|
892
|
+
".dsh-claude-flow-detail{max-height:260px;overflow:auto;margin:4px 0 4px 4px;padding:12px 16px;border:1px solid var(--dsw-alias-border-l1);border-radius:12px;background:var(--dsw-alias-markdown-code-block);color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap}",
|
|
893
|
+
".dsh-claude-flow-subcalls{display:flex;flex-direction:column;gap:2px;margin:4px 0 4px 22px;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:22px}",
|
|
894
|
+
".dsh-claude-act-running{animation:dsh-claude-act-pulse 1.2s ease-in-out infinite}",
|
|
895
|
+
"@keyframes dsh-claude-act-pulse{0%,100%{opacity:1}50%{opacity:.3}}"
|
|
896
|
+
].join("");
|
|
897
|
+
let cssInjected = false;
|
|
898
|
+
function ensureCss() {
|
|
899
|
+
if (cssInjected || typeof document === "undefined") return;
|
|
900
|
+
cssInjected = true;
|
|
901
|
+
const element = document.createElement("style");
|
|
902
|
+
element.dataset.dshClaudeActivity = "";
|
|
903
|
+
element.textContent = ACTIVITY_CSS;
|
|
904
|
+
document.head.appendChild(element);
|
|
905
|
+
}
|
|
906
|
+
function subcallGlyph(subcall) {
|
|
907
|
+
if (subcall.isError === true || subcall.phase === "failed") return "×";
|
|
908
|
+
if (subcall.phase === "started" || subcall.phase === "updated") return "●";
|
|
909
|
+
return "✓";
|
|
910
|
+
}
|
|
911
|
+
function title(activity) {
|
|
912
|
+
return activity.toolName ?? activity.title ?? activity.kind.replaceAll("-", " ");
|
|
913
|
+
}
|
|
914
|
+
function activityState(activity, running) {
|
|
915
|
+
if (activity.isError === true || activity.kind === "error" || activity.phase === "denied" || activity.phase === "failed") return "error";
|
|
916
|
+
if (running) return "ongoing";
|
|
917
|
+
if (activity.kind === "warning") return "warning";
|
|
918
|
+
return "done";
|
|
919
|
+
}
|
|
920
|
+
function ActivityRow({ row, t }) {
|
|
921
|
+
const { activity, running, subcalls } = row;
|
|
922
|
+
const [open, setOpen] = useState(false);
|
|
923
|
+
const state = activityState(activity, running);
|
|
924
|
+
const detail = activity.detail;
|
|
925
|
+
const expandable = detail !== void 0 || subcalls.length > 0 || activity.kind === "thinking";
|
|
926
|
+
const summary = activity.summary ?? (running ? t("running") : state === "error" ? t("failed") : t("done"));
|
|
927
|
+
const body = activity.kind === "thinking" ? activity.summary : detail;
|
|
928
|
+
return /* @__PURE__ */ jsxs(DisclosureRow, {
|
|
929
|
+
rowClassName: "dsh-claude-flow-row",
|
|
930
|
+
leadingClassName: "dsh-claude-flow-leading",
|
|
931
|
+
titleClassName: "dsh-claude-flow-title",
|
|
932
|
+
chevronClassName: "dsh-claude-flow-chevron",
|
|
933
|
+
icon: activity.kind === "thinking" ? /* @__PURE__ */ jsx(IconThinkOutline14, { size: 14 }) : state === "done" ? /* @__PURE__ */ jsx(IconApiOutline14, { size: 14 }) : /* @__PURE__ */ jsx(StateDot, { state }),
|
|
934
|
+
title: activity.kind === "thinking" ? t("thinking") : title(activity),
|
|
935
|
+
open,
|
|
936
|
+
expandable,
|
|
937
|
+
expandOnRowClick: true,
|
|
938
|
+
keepContentWhenOpen: true,
|
|
939
|
+
onToggle: () => setOpen((value) => !value),
|
|
940
|
+
collapsedContent: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
941
|
+
className: "dsh-claude-flow-separator",
|
|
942
|
+
"aria-hidden": "true"
|
|
943
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
944
|
+
className: "dsh-claude-flow-summary",
|
|
945
|
+
"data-error": state === "error" || void 0,
|
|
946
|
+
children: summary
|
|
947
|
+
})] }),
|
|
948
|
+
children: [subcalls.length === 0 ? null : /* @__PURE__ */ jsx("div", {
|
|
949
|
+
className: "dsh-claude-flow-subcalls",
|
|
950
|
+
children: subcalls.map((subcall) => /* @__PURE__ */ jsxs("div", { children: [
|
|
951
|
+
subcallGlyph(subcall),
|
|
952
|
+
" ",
|
|
953
|
+
subcall.toolName ?? t("subagent"),
|
|
954
|
+
subcall.summary === void 0 ? "" : ` · ${subcall.summary}`
|
|
955
|
+
] }, subcall.toolUseId))
|
|
956
|
+
}), body === void 0 ? null : activity.kind === "thinking" ? /* @__PURE__ */ jsx("div", {
|
|
957
|
+
className: "dsh-claude-flow-body",
|
|
958
|
+
children: body
|
|
959
|
+
}) : /* @__PURE__ */ jsx("pre", {
|
|
960
|
+
className: "dsh-claude-flow-detail",
|
|
961
|
+
children: body
|
|
962
|
+
})]
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
function ClaudeActivityNode({ node, useClaudeProjection, t }) {
|
|
966
|
+
ensureCss();
|
|
967
|
+
const marker = node.data;
|
|
968
|
+
const activities = useClaudeProjection((value) => value.activities);
|
|
969
|
+
const tasks = useClaudeProjection((value) => value.tasks?.tasks ?? EMPTY_TASKS);
|
|
970
|
+
const rows = useMemo(() => activityRowsForStep(activities, marker.turn, marker.step, tasks), [
|
|
971
|
+
activities,
|
|
972
|
+
marker.step,
|
|
973
|
+
marker.turn,
|
|
974
|
+
tasks
|
|
975
|
+
]);
|
|
976
|
+
if (rows.length === 0) return null;
|
|
977
|
+
return /* @__PURE__ */ jsx("div", {
|
|
978
|
+
className: "dsh-claude-flow",
|
|
979
|
+
children: rows.map((row, index) => /* @__PURE__ */ jsx(ActivityRow, {
|
|
980
|
+
row,
|
|
981
|
+
t
|
|
982
|
+
}, `${row.activity.ordinal}:${index}`))
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
//#endregion
|
|
986
|
+
//#region src/client/ClaudeCodeSettings.tsx
|
|
987
|
+
function value(status, detail) {
|
|
988
|
+
return detail === void 0 ? status : `${status} · ${detail}`;
|
|
989
|
+
}
|
|
990
|
+
function ClaudeCodeSettings({ t }) {
|
|
991
|
+
const [report, setReport] = useState();
|
|
992
|
+
const [error, setError] = useState();
|
|
993
|
+
const [busy, setBusy] = useState(false);
|
|
994
|
+
const refresh = useCallback(async () => {
|
|
995
|
+
setBusy(true);
|
|
996
|
+
setError(void 0);
|
|
997
|
+
setReport(void 0);
|
|
998
|
+
try {
|
|
999
|
+
const response = await fetch(CLAUDE_DOCTOR_PATH, {
|
|
1000
|
+
credentials: "same-origin",
|
|
1001
|
+
headers: { accept: "application/json" }
|
|
1002
|
+
});
|
|
1003
|
+
const payload = await response.json();
|
|
1004
|
+
if (!response.ok) throw new Error("error" in payload ? payload.error : `HTTP ${response.status}`);
|
|
1005
|
+
setReport(payload);
|
|
1006
|
+
} catch (cause) {
|
|
1007
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
1008
|
+
} finally {
|
|
1009
|
+
setBusy(false);
|
|
1010
|
+
}
|
|
1011
|
+
}, []);
|
|
1012
|
+
useEffect(() => {
|
|
1013
|
+
refresh();
|
|
1014
|
+
}, [refresh]);
|
|
1015
|
+
const rows = report === void 0 ? [] : [
|
|
1016
|
+
[t("executable"), report.executable.status === "found" ? report.executable.path ?? t("unknown") : `${t("missing")} · ${report.executable.searched.join(", ")}`],
|
|
1017
|
+
[t("version"), value(report.version.status, report.version.value ?? report.version.message)],
|
|
1018
|
+
[t("authentication"), value(report.authentication.status, [report.authentication.method, report.authentication.subscription].filter(Boolean).join(" · ") || report.authentication.message)],
|
|
1019
|
+
[t("handshake"), report.handshake],
|
|
1020
|
+
[t("processes"), t("processSummary", {
|
|
1021
|
+
total: report.processes.count,
|
|
1022
|
+
active: report.processes.active
|
|
1023
|
+
})],
|
|
1024
|
+
[t("limits"), t("limitSummary", {
|
|
1025
|
+
max: report.limits.maxProcesses,
|
|
1026
|
+
minutes: Math.round(report.limits.idleTimeoutMs / 6e4)
|
|
1027
|
+
})]
|
|
1028
|
+
];
|
|
1029
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1030
|
+
style: settingsPage,
|
|
1031
|
+
children: [
|
|
1032
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h2", {
|
|
1033
|
+
style: settingsHeading,
|
|
1034
|
+
children: t("title")
|
|
1035
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
1036
|
+
style: settingsBody,
|
|
1037
|
+
children: t("description")
|
|
1038
|
+
})] }),
|
|
1039
|
+
rows.length === 0 ? null : /* @__PURE__ */ jsx("div", {
|
|
1040
|
+
style: diagnosticGrid,
|
|
1041
|
+
children: rows.flatMap(([label, rowValue]) => [/* @__PURE__ */ jsx("span", {
|
|
1042
|
+
style: diagnosticLabel,
|
|
1043
|
+
children: label
|
|
1044
|
+
}, `${label}-label`), /* @__PURE__ */ jsx("span", {
|
|
1045
|
+
style: diagnosticValue,
|
|
1046
|
+
children: rowValue
|
|
1047
|
+
}, `${label}-value`)])
|
|
1048
|
+
}),
|
|
1049
|
+
error === void 0 ? null : /* @__PURE__ */ jsxs("p", {
|
|
1050
|
+
style: {
|
|
1051
|
+
...settingsBody,
|
|
1052
|
+
color: "var(--dsw-alias-state-error-primary)"
|
|
1053
|
+
},
|
|
1054
|
+
children: [
|
|
1055
|
+
t("error"),
|
|
1056
|
+
": ",
|
|
1057
|
+
error
|
|
1058
|
+
]
|
|
1059
|
+
}),
|
|
1060
|
+
/* @__PURE__ */ jsx("button", {
|
|
1061
|
+
type: "button",
|
|
1062
|
+
style: button,
|
|
1063
|
+
onClick: () => {
|
|
1064
|
+
refresh();
|
|
1065
|
+
},
|
|
1066
|
+
disabled: busy,
|
|
1067
|
+
children: busy ? t("refreshing") : t("doctor")
|
|
1068
|
+
}),
|
|
1069
|
+
/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
|
|
1070
|
+
style: {
|
|
1071
|
+
...settingsHeading,
|
|
1072
|
+
fontSize: 15,
|
|
1073
|
+
lineHeight: "22px"
|
|
1074
|
+
},
|
|
1075
|
+
children: t("security")
|
|
1076
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
1077
|
+
style: settingsBody,
|
|
1078
|
+
children: t("securityBody")
|
|
1079
|
+
})] })
|
|
1080
|
+
]
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
//#endregion
|
|
1084
|
+
//#region src/client/projection.ts
|
|
1085
|
+
const EMPTY_CLAUDE_PROJECTION = {
|
|
1086
|
+
schemaVersion: 1,
|
|
1087
|
+
revision: 0,
|
|
1088
|
+
owned: false,
|
|
1089
|
+
activities: []
|
|
1090
|
+
};
|
|
1091
|
+
const POLL_INTERVAL_MS = 2e3;
|
|
1092
|
+
const MAX_ACTIVITIES = 1e4;
|
|
1093
|
+
function record(value) {
|
|
1094
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
1095
|
+
}
|
|
1096
|
+
function nonNegativeInteger(value) {
|
|
1097
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
1098
|
+
}
|
|
1099
|
+
/** Validate the public route envelope before publishing it to UI components. */
|
|
1100
|
+
function parseClaudeClientProjection(value) {
|
|
1101
|
+
const input = record(value);
|
|
1102
|
+
if (input === void 0 || input.schemaVersion !== 1 || !nonNegativeInteger(input.revision) || typeof input.owned !== "boolean" || !Array.isArray(input.activities) || input.activities.length > MAX_ACTIVITIES) throw new Error("invalid Claude sidecar projection");
|
|
1103
|
+
for (const item of input.activities) {
|
|
1104
|
+
const activity = record(item);
|
|
1105
|
+
if (activity === void 0 || !nonNegativeInteger(activity.turn) || !nonNegativeInteger(activity.step) || !nonNegativeInteger(activity.ordinal) || typeof activity.kind !== "string") throw new Error("invalid Claude sidecar activity");
|
|
1106
|
+
}
|
|
1107
|
+
if (input.contextUsage !== void 0 && record(input.contextUsage) === void 0) throw new Error("invalid Claude context projection");
|
|
1108
|
+
const tasks = input.tasks === void 0 ? void 0 : record(input.tasks);
|
|
1109
|
+
if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
|
|
1110
|
+
return input;
|
|
1111
|
+
}
|
|
1112
|
+
/** Create one lazy source: active subscribers trigger an immediate load and bounded polling. */
|
|
1113
|
+
function createClaudeProjectionSource(sessionId, fetchProjection = fetch, pollIntervalMs = POLL_INTERVAL_MS) {
|
|
1114
|
+
let snapshot = EMPTY_CLAUDE_PROJECTION;
|
|
1115
|
+
let timer;
|
|
1116
|
+
let controller;
|
|
1117
|
+
let disposed = false;
|
|
1118
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1119
|
+
const schedule = () => {
|
|
1120
|
+
if (disposed || listeners.size === 0) return;
|
|
1121
|
+
timer = setTimeout(() => {
|
|
1122
|
+
refresh();
|
|
1123
|
+
}, pollIntervalMs);
|
|
1124
|
+
};
|
|
1125
|
+
const refresh = async () => {
|
|
1126
|
+
if (disposed || listeners.size === 0) return;
|
|
1127
|
+
controller?.abort();
|
|
1128
|
+
controller = new AbortController();
|
|
1129
|
+
try {
|
|
1130
|
+
const response = await fetchProjection(`${CLAUDE_PROJECTION_PATH}/${encodeURIComponent(sessionId)}`, {
|
|
1131
|
+
headers: { accept: "application/json" },
|
|
1132
|
+
signal: controller.signal
|
|
1133
|
+
});
|
|
1134
|
+
if (!response.ok) throw new Error(`Claude projection request failed (${response.status})`);
|
|
1135
|
+
const next = parseClaudeClientProjection(await response.json());
|
|
1136
|
+
if (next.revision !== snapshot.revision || next.owned !== snapshot.owned) {
|
|
1137
|
+
snapshot = next;
|
|
1138
|
+
for (const listener of [...listeners]) listener();
|
|
1139
|
+
}
|
|
1140
|
+
} catch (error) {
|
|
1141
|
+
if (!(error instanceof DOMException && error.name === "AbortError") && snapshot !== EMPTY_CLAUDE_PROJECTION) {
|
|
1142
|
+
snapshot = EMPTY_CLAUDE_PROJECTION;
|
|
1143
|
+
for (const listener of [...listeners]) listener();
|
|
1144
|
+
}
|
|
1145
|
+
} finally {
|
|
1146
|
+
controller = void 0;
|
|
1147
|
+
schedule();
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
return {
|
|
1151
|
+
getSnapshot: () => snapshot,
|
|
1152
|
+
subscribe(listener) {
|
|
1153
|
+
if (disposed) return () => {};
|
|
1154
|
+
const wasIdle = listeners.size === 0;
|
|
1155
|
+
listeners.add(listener);
|
|
1156
|
+
if (wasIdle) refresh();
|
|
1157
|
+
return () => {
|
|
1158
|
+
listeners.delete(listener);
|
|
1159
|
+
if (listeners.size !== 0) return;
|
|
1160
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1161
|
+
timer = void 0;
|
|
1162
|
+
controller?.abort();
|
|
1163
|
+
controller = void 0;
|
|
1164
|
+
};
|
|
1165
|
+
},
|
|
1166
|
+
dispose() {
|
|
1167
|
+
disposed = true;
|
|
1168
|
+
listeners.clear();
|
|
1169
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1170
|
+
timer = void 0;
|
|
1171
|
+
controller?.abort();
|
|
1172
|
+
controller = void 0;
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1176
|
+
var ClaudeProjectionStore = class {
|
|
1177
|
+
#sources = /* @__PURE__ */ new Map();
|
|
1178
|
+
source(sessionId) {
|
|
1179
|
+
let source = this.#sources.get(sessionId);
|
|
1180
|
+
if (source === void 0) {
|
|
1181
|
+
source = createClaudeProjectionSource(sessionId);
|
|
1182
|
+
this.#sources.set(sessionId, source);
|
|
1183
|
+
}
|
|
1184
|
+
return source;
|
|
1185
|
+
}
|
|
1186
|
+
dispose() {
|
|
1187
|
+
for (const source of this.#sources.values()) source.dispose();
|
|
1188
|
+
this.#sources.clear();
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1191
|
+
//#endregion
|
|
1192
|
+
//#region src/client/locales.ts
|
|
1193
|
+
const zh = {
|
|
1194
|
+
nav: "Claude Code",
|
|
1195
|
+
title: "Claude Code",
|
|
1196
|
+
description: "DSH 使用本机 Claude Code,并保留其 Agent Loop、工具、CLAUDE.md、Skills、Hooks 与 MCP 配置。",
|
|
1197
|
+
activity: "Claude Code 活动",
|
|
1198
|
+
detail: "查看已脱敏详情",
|
|
1199
|
+
thinking: "思考",
|
|
1200
|
+
running: "运行中",
|
|
1201
|
+
failed: "失败",
|
|
1202
|
+
done: "完成",
|
|
1203
|
+
subagent: "子代理",
|
|
1204
|
+
tokens: "{count} 个 token",
|
|
1205
|
+
doctor: "运行诊断",
|
|
1206
|
+
refreshing: "诊断中…",
|
|
1207
|
+
executable: "可执行文件",
|
|
1208
|
+
version: "版本",
|
|
1209
|
+
authentication: "登录状态",
|
|
1210
|
+
handshake: "协议握手",
|
|
1211
|
+
processes: "活动进程",
|
|
1212
|
+
limits: "进程限制",
|
|
1213
|
+
processSummary: "共 {total} 个 · {active} 个活动中",
|
|
1214
|
+
limitSummary: "最多 {max} 个 · 空闲 {minutes} 分钟后回收",
|
|
1215
|
+
missing: "未找到",
|
|
1216
|
+
unknown: "未知",
|
|
1217
|
+
error: "诊断失败",
|
|
1218
|
+
security: "权限边界",
|
|
1219
|
+
securityBody: "Claude 工具权限通过 DSH 审批界面决定;当前版本不宣称对 ~/.claude 与工作区之外路径提供内核级写入隔离。",
|
|
1220
|
+
tasks: "任务",
|
|
1221
|
+
tasksPanel: "后台任务",
|
|
1222
|
+
tasksEmpty: "当前没有子代理或后台任务",
|
|
1223
|
+
tasksOpen: "查看后台任务",
|
|
1224
|
+
tasksClose: "关闭任务面板",
|
|
1225
|
+
tasksRunning: "运行中",
|
|
1226
|
+
tasksNoneRunning: "当前没有运行中的任务",
|
|
1227
|
+
tasksSettled: "已结束",
|
|
1228
|
+
tasksClear: "清除",
|
|
1229
|
+
tasksViewActivity: "查看活动",
|
|
1230
|
+
tasksHideActivity: "收起活动",
|
|
1231
|
+
tasksRunningCount: "{count} 个运行中任务",
|
|
1232
|
+
tasksToolUses: "{count} 次工具调用",
|
|
1233
|
+
tasksCompleted: "已完成",
|
|
1234
|
+
tasksFailed: "失败",
|
|
1235
|
+
tasksStopped: "已停止",
|
|
1236
|
+
tasksKilled: "已终止",
|
|
1237
|
+
tasksBackground: "后台",
|
|
1238
|
+
tasksLastTool: "最近工具 {tool}"
|
|
1239
|
+
};
|
|
1240
|
+
const en = {
|
|
1241
|
+
nav: "Claude Code",
|
|
1242
|
+
title: "Claude Code",
|
|
1243
|
+
description: "DSH uses the local Claude Code and preserves its agent loop, tools, CLAUDE.md, Skills, Hooks, and MCP configuration.",
|
|
1244
|
+
activity: "Claude Code activity",
|
|
1245
|
+
detail: "Show redacted detail",
|
|
1246
|
+
thinking: "Think",
|
|
1247
|
+
running: "Running",
|
|
1248
|
+
failed: "Failed",
|
|
1249
|
+
done: "Done",
|
|
1250
|
+
subagent: "Subagent",
|
|
1251
|
+
tokens: "{count} tokens",
|
|
1252
|
+
doctor: "Run Doctor",
|
|
1253
|
+
refreshing: "Running Doctor…",
|
|
1254
|
+
executable: "Executable",
|
|
1255
|
+
version: "Version",
|
|
1256
|
+
authentication: "Authentication",
|
|
1257
|
+
handshake: "Protocol handshake",
|
|
1258
|
+
processes: "Live processes",
|
|
1259
|
+
limits: "Process limits",
|
|
1260
|
+
processSummary: "{total} total · {active} active",
|
|
1261
|
+
limitSummary: "{max} max · {minutes} min idle",
|
|
1262
|
+
missing: "Not found",
|
|
1263
|
+
unknown: "Unknown",
|
|
1264
|
+
error: "Doctor failed",
|
|
1265
|
+
security: "Permission boundary",
|
|
1266
|
+
securityBody: "Claude tool permissions are decided through the DSH approval UI. This version does not claim kernel-level write isolation for ~/.claude or paths outside the workspace.",
|
|
1267
|
+
tasks: "Tasks",
|
|
1268
|
+
tasksPanel: "Background tasks",
|
|
1269
|
+
tasksEmpty: "No subagents or background tasks",
|
|
1270
|
+
tasksOpen: "Show background tasks",
|
|
1271
|
+
tasksClose: "Close tasks panel",
|
|
1272
|
+
tasksRunning: "Running",
|
|
1273
|
+
tasksNoneRunning: "No tasks are running",
|
|
1274
|
+
tasksSettled: "Finished",
|
|
1275
|
+
tasksClear: "Clear",
|
|
1276
|
+
tasksViewActivity: "View activity",
|
|
1277
|
+
tasksHideActivity: "Hide activity",
|
|
1278
|
+
tasksRunningCount: "{count} running task(s)",
|
|
1279
|
+
tasksToolUses: "{count} tool use(s)",
|
|
1280
|
+
tasksCompleted: "Completed",
|
|
1281
|
+
tasksFailed: "Failed",
|
|
1282
|
+
tasksStopped: "Stopped",
|
|
1283
|
+
tasksKilled: "Killed",
|
|
1284
|
+
tasksBackground: "Background",
|
|
1285
|
+
tasksLastTool: "Last tool {tool}"
|
|
1286
|
+
};
|
|
1287
|
+
//#endregion
|
|
1288
|
+
//#region src/client/index.tsx
|
|
1289
|
+
const name = "dsh-claude-client";
|
|
1290
|
+
const inject = [
|
|
1291
|
+
"slots",
|
|
1292
|
+
"locale",
|
|
1293
|
+
"conversationEvents",
|
|
1294
|
+
"sessions"
|
|
1295
|
+
];
|
|
1296
|
+
function apply(ctx) {
|
|
1297
|
+
const namespace = "settings.claude-code";
|
|
1298
|
+
ctx.effect(() => ctx.locale.register(namespace, {
|
|
1299
|
+
zh,
|
|
1300
|
+
en
|
|
1301
|
+
}), "dsh-claude: client copy");
|
|
1302
|
+
const t = ctx.locale.bind(namespace);
|
|
1303
|
+
const projections = new ClaudeProjectionStore();
|
|
1304
|
+
const sessions = ctx.get("sessions");
|
|
1305
|
+
if (sessions !== void 0) ctx.effect(() => sessions.provide({
|
|
1306
|
+
hooks: ["claudeProjection"],
|
|
1307
|
+
resolve: (binding) => ({ hooks: { claudeProjection: projections.source(binding.sessionId) } })
|
|
1308
|
+
}), "dsh-claude: sidecar projection provider");
|
|
1309
|
+
ctx.effect(() => () => projections.dispose(), "dsh-claude: sidecar projection lifecycle");
|
|
1310
|
+
ctx.effect(() => ctx.conversationEvents.register(claudeTurnDefinition), "dsh-claude: Claude turn marker");
|
|
1311
|
+
ctx.effect(() => ctx.conversationEvents.register(claudeActivityStepDefinition), "dsh-claude: Claude activity flow node");
|
|
1312
|
+
ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
|
|
1313
|
+
name: "conversation.chat.node",
|
|
1314
|
+
key: "claude-activity-step",
|
|
1315
|
+
locale: namespace
|
|
1316
|
+
}, ClaudeActivityNode));
|
|
1317
|
+
const layout = ctx.get("layout");
|
|
1318
|
+
const tasksPanelListeners = /* @__PURE__ */ new Set();
|
|
1319
|
+
let disposeTasksDetails;
|
|
1320
|
+
let tasksPanelSession;
|
|
1321
|
+
const notifyTasksPanel = () => {
|
|
1322
|
+
for (const fn of [...tasksPanelListeners]) fn();
|
|
1323
|
+
};
|
|
1324
|
+
const closeTasksPanel = () => {
|
|
1325
|
+
if (disposeTasksDetails === void 0) return;
|
|
1326
|
+
disposeTasksDetails();
|
|
1327
|
+
disposeTasksDetails = void 0;
|
|
1328
|
+
tasksPanelSession = void 0;
|
|
1329
|
+
layout?.closeDetails();
|
|
1330
|
+
notifyTasksPanel();
|
|
1331
|
+
};
|
|
1332
|
+
const openTasksPanel = (sessionId) => {
|
|
1333
|
+
closeTasksPanel();
|
|
1334
|
+
try {
|
|
1335
|
+
disposeTasksDetails = ctx.slots.register({
|
|
1336
|
+
name: "details",
|
|
1337
|
+
priority: -10,
|
|
1338
|
+
locale: namespace,
|
|
1339
|
+
inject: () => ({
|
|
1340
|
+
t,
|
|
1341
|
+
closeDetails: closeTasksPanel
|
|
1342
|
+
})
|
|
1343
|
+
}, ClaudeTasksPanel);
|
|
1344
|
+
} catch {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
tasksPanelSession = sessionId;
|
|
1348
|
+
layout?.openDetails();
|
|
1349
|
+
notifyTasksPanel();
|
|
1350
|
+
};
|
|
1351
|
+
const toggleTasksPanel = (sessionId) => {
|
|
1352
|
+
if (tasksPanelSession === sessionId) closeTasksPanel();
|
|
1353
|
+
else openTasksPanel(sessionId);
|
|
1354
|
+
};
|
|
1355
|
+
ctx.effect(() => {
|
|
1356
|
+
if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => closeTasksPanel();
|
|
1357
|
+
const observer = new MutationObserver(() => {
|
|
1358
|
+
if (tasksPanelSession !== void 0 && document.querySelector("[data-details-collapsed]") !== null) closeTasksPanel();
|
|
1359
|
+
});
|
|
1360
|
+
observer.observe(document.body, {
|
|
1361
|
+
attributes: true,
|
|
1362
|
+
attributeFilter: ["data-details-collapsed"],
|
|
1363
|
+
subtree: true
|
|
1364
|
+
});
|
|
1365
|
+
return () => {
|
|
1366
|
+
observer.disconnect();
|
|
1367
|
+
closeTasksPanel();
|
|
1368
|
+
};
|
|
1369
|
+
}, "dsh-claude: tasks panel lifecycle");
|
|
1370
|
+
const tasksLauncher = (sessionId) => ({
|
|
1371
|
+
isOpen: () => tasksPanelSession === sessionId,
|
|
1372
|
+
toggle: () => toggleTasksPanel(sessionId),
|
|
1373
|
+
subscribe: (fn) => {
|
|
1374
|
+
tasksPanelListeners.add(fn);
|
|
1375
|
+
return () => {
|
|
1376
|
+
tasksPanelListeners.delete(fn);
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
ctx.slots.inject("conversation.chat.turnTail", () => ctx.slots.register({
|
|
1381
|
+
name: "conversation.chat.turnTail",
|
|
1382
|
+
select: selectClaudeTurn,
|
|
1383
|
+
inject: (sessionId) => ({
|
|
1384
|
+
t,
|
|
1385
|
+
openTasks: () => openTasksPanel(sessionId)
|
|
1386
|
+
})
|
|
1387
|
+
}, ClaudeActivityTail));
|
|
1388
|
+
if (sessions !== void 0) ctx.effect(() => sessions.list.subscribe(() => {
|
|
1389
|
+
if (tasksPanelSession !== void 0 && sessions.list.getSnapshot().current !== tasksPanelSession) closeTasksPanel();
|
|
1390
|
+
}), "dsh-claude: tasks panel session tracking");
|
|
1391
|
+
ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
|
|
1392
|
+
name: "conversation.session.header.utilities",
|
|
1393
|
+
id: "claude-tasks",
|
|
1394
|
+
order: -10,
|
|
1395
|
+
label: () => t("tasksOpen"),
|
|
1396
|
+
inject: (sessionId) => ({
|
|
1397
|
+
t,
|
|
1398
|
+
...tasksLauncher(sessionId)
|
|
1399
|
+
})
|
|
1400
|
+
}, ClaudeTasksHeaderButton));
|
|
1401
|
+
ctx.slots.inject("settings.section", () => ctx.slots.register({
|
|
1402
|
+
name: "settings.section",
|
|
1403
|
+
id: "claude-code",
|
|
1404
|
+
order: 16,
|
|
1405
|
+
label: () => t("nav"),
|
|
1406
|
+
inject: () => ({ t })
|
|
1407
|
+
}, ClaudeCodeSettings));
|
|
1408
|
+
}
|
|
1409
|
+
//#endregion
|
|
1410
|
+
module.exports.apply = apply;
|
|
1411
|
+
module.exports.inject = inject;
|
|
1412
|
+
module.exports.name = name;
|
|
1413
|
+
return module.exports;
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
|
|
1417
|
+
//# sourceMappingURL=client.js.map
|