@norman-else/dsh-claude 0.1.19 → 0.1.20

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/lib/client.js CHANGED
@@ -3,9 +3,9 @@ window.__ModuleLoader__.load({
3
3
  factory: (require) => {
4
4
  var module = { exports: {} };
5
5
  module.exports;
6
- var { useCallback, useEffect, useId, useMemo, useRef, useState } = require("react");
7
- var { Fragment, jsx, jsxs } = require("react/jsx-runtime");
8
- var { DisclosureRow, IconApiOutline14, IconBranchOutline16, IconCheckOutline14, IconChevronDownOutline14, IconSearchOutline16, IconThinkOutline14, StateDot } = require("@deepseek-ai/dsh-client-ui-primitives");
6
+ var { Fragment, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } = require("react");
7
+ var { DiffBlock, DisclosureRow, HoverCard, IconApiOutline14, IconBranchOutline16, IconCheckOutline14, IconChevronDownOutline14, IconCloseOutline16, IconFullscreenOutline16, IconSearchOutline16, IconThinkOutline14, MarkdownText, Menu, Modal, StateDot } = require("@deepseek-ai/dsh-client-ui-primitives");
8
+ var { Fragment: Fragment$1, jsx, jsxs } = require("react/jsx-runtime");
9
9
  var { createPortal } = require("react-dom");
10
10
  /** Claude's subagent dispatch tools; rendered as plugin-owned group cards
11
11
  * gathering subagent activity instead of native tool cards. */
@@ -16,6 +16,21 @@ window.__ModuleLoader__.load({
16
16
  const CLAUDE_PROJECTION_PATH = "/plugins/dsh-claude/projection";
17
17
  const CLAUDE_GLOBAL_SETTINGS_PATH = "/plugins/dsh-claude/settings/global";
18
18
  const CLAUDE_REPOSITORY_SETUP_PATH = "/plugins/dsh-claude/repository/setup";
19
+ const CLAUDE_REPOSITORY_ACTION_PATH = "/plugins/dsh-claude/repository/action";
20
+ const CLAUDE_REVIEW_COMMENT_PATH = "/plugins/dsh-claude/review-comments";
21
+ //#endregion
22
+ //#region src/client/task-projection.ts
23
+ /** Tasks UI is reserved for detached work and genuine Claude subagents. */
24
+ function isProjectedTask(task) {
25
+ if (task.backgrounded === true) return true;
26
+ return task.subagentType !== void 0 && task.subagentType.trim().length > 0;
27
+ }
28
+ function isProjectedTaskActivity(activity, tasks) {
29
+ if (activity.kind !== "subagent" || activity.parentToolUseId !== void 0) return true;
30
+ if (activity.taskId === void 0) return false;
31
+ const task = tasks.find((candidate) => candidate.taskId === activity.taskId);
32
+ return task !== void 0 && isProjectedTask(task);
33
+ }
19
34
  //#endregion
20
35
  //#region src/client/conversation-sidecar.ts
21
36
  function isTaskActivity(value) {
@@ -53,7 +68,7 @@ window.__ModuleLoader__.load({
53
68
  const rows = [];
54
69
  const byId = /* @__PURE__ */ new Map();
55
70
  for (const value of activities) {
56
- if (!accepts(value)) continue;
71
+ if (!accepts(value) || !isProjectedTaskActivity(value, tasks)) continue;
57
72
  const existingTaskId = value.toolUseId === void 0 ? void 0 : `task-${value.toolUseId}`;
58
73
  const updatesExistingTask = value.kind === "tool-result" && existingTaskId !== void 0 && byId.has(existingTaskId);
59
74
  if (!presentable(value) && !updatesExistingTask) continue;
@@ -117,10 +132,232 @@ window.__ModuleLoader__.load({
117
132
  };
118
133
  });
119
134
  }
120
- function activityRowsForStep(activities, turn, step, tasks = []) {
121
- return activityRows(activities, (activity) => activity.turn === turn && activity.step === step, tasks);
135
+ function inputRecord(detail) {
136
+ if (detail === void 0) return void 0;
137
+ try {
138
+ const value = JSON.parse(detail);
139
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
140
+ } catch {
141
+ return;
142
+ }
143
+ }
144
+ function inputString(input, key) {
145
+ const value = input?.[key];
146
+ return typeof value === "string" && value.length > 0 ? value : void 0;
147
+ }
148
+ function lineCount(text) {
149
+ return text.length === 0 ? 0 : text.split(/\r?\n/u).length;
150
+ }
151
+ function editDiffs(toolName, input) {
152
+ const path = inputString(input, "file_path");
153
+ if (path === void 0) return void 0;
154
+ if (toolName === "MultiEdit" && Array.isArray(input?.edits)) {
155
+ const diffs = input.edits.flatMap((edit) => {
156
+ if (edit === null || typeof edit !== "object" || Array.isArray(edit)) return [];
157
+ const item = edit;
158
+ const newText = inputString(item, "new_string");
159
+ if (newText === void 0) return [];
160
+ return [{
161
+ path,
162
+ oldText: inputString(item, "old_string") ?? null,
163
+ newText
164
+ }];
165
+ });
166
+ return diffs.length === 0 ? void 0 : diffs;
167
+ }
168
+ if (toolName === "Edit") {
169
+ const newText = inputString(input, "new_string");
170
+ return newText === void 0 ? void 0 : [{
171
+ path,
172
+ oldText: inputString(input, "old_string") ?? null,
173
+ newText
174
+ }];
175
+ }
176
+ if (toolName === "Write") {
177
+ const content = inputString(input, "content");
178
+ return content === void 0 ? void 0 : [{
179
+ path,
180
+ oldText: null,
181
+ newText: content
182
+ }];
183
+ }
184
+ }
185
+ function toolDescription(toolName, input, failed = false) {
186
+ const path = inputString(input, "file_path") ?? inputString(input, "path");
187
+ const pattern = inputString(input, "pattern") ?? inputString(input, "query");
188
+ const description = inputString(input, "description");
189
+ const target = path ?? pattern;
190
+ let completed;
191
+ let failedAction;
192
+ switch (toolName) {
193
+ case "Grep":
194
+ completed = path === void 0 ? `Searched for ${pattern ?? "matches"}` : `Searched ${path} for ${pattern ?? "matches"}`;
195
+ failedAction = path === void 0 ? `search for ${pattern ?? "matches"}` : `search ${path} for ${pattern ?? "matches"}`;
196
+ break;
197
+ case "Glob":
198
+ completed = `Searched for ${pattern ?? "files"}`;
199
+ failedAction = `search for ${pattern ?? "files"}`;
200
+ break;
201
+ case "Read":
202
+ completed = `Read ${path ?? "a file"}`;
203
+ failedAction = `read ${path ?? "a file"}`;
204
+ break;
205
+ case "WebFetch": {
206
+ const url = inputString(input, "url") ?? "a web page";
207
+ completed = `Fetched ${url}`;
208
+ failedAction = `fetch ${url}`;
209
+ break;
210
+ }
211
+ case "WebSearch":
212
+ completed = `Searched the web for ${pattern ?? "results"}`;
213
+ failedAction = `search the web for ${pattern ?? "results"}`;
214
+ break;
215
+ case "Edit":
216
+ case "MultiEdit":
217
+ completed = `Edited ${path ?? "a file"}`;
218
+ failedAction = `edit ${path ?? "a file"}`;
219
+ break;
220
+ case "Write":
221
+ completed = `Wrote ${path ?? "a file"}`;
222
+ failedAction = `write ${path ?? "a file"}`;
223
+ break;
224
+ case "Bash": {
225
+ const command = inputString(input, "command") ?? "a command";
226
+ completed = description ?? `Ran ${command}`;
227
+ failedAction = description === void 0 ? `run ${command}` : description;
228
+ break;
229
+ }
230
+ default:
231
+ completed = description ?? `${toolName}${target === void 0 ? "" : ` ${target}`}`;
232
+ failedAction = completed.charAt(0).toLowerCase() + completed.slice(1);
233
+ }
234
+ return failed ? `Failed to ${failedAction}` : completed;
235
+ }
236
+ /** Fold one step's shared ordinal stream into Claude Code-style prose and tool groups. */
237
+ function transcriptItemsForStep(activities, turn, step, tasks = []) {
238
+ const ordered = activities.filter((activity) => activity.turn === turn && activity.step === step).slice().sort((left, right) => left.ordinal - right.ordinal);
239
+ const items = [];
240
+ let group;
241
+ const flushGroup = () => {
242
+ if (group === void 0 || group.tools.length === 0) return;
243
+ const current = group;
244
+ const diffs = current.tools.flatMap((tool) => tool.diffs ?? []);
245
+ const additions = diffs.reduce((total, diff) => total + lineCount(diff.newText), 0);
246
+ const deletions = diffs.reduce((total, diff) => total + (diff.oldText === null ? 0 : lineCount(diff.oldText)), 0);
247
+ const files = new Set(diffs.map((diff) => diff.path)).size;
248
+ items.push({
249
+ kind: "tools",
250
+ ordinal: current.ordinal,
251
+ tools: current.tools,
252
+ ...diffs.length === 0 ? {} : {
253
+ additions,
254
+ deletions,
255
+ files
256
+ }
257
+ });
258
+ group = void 0;
259
+ for (const activity of current.trailingActivities) {
260
+ const row = activityRows([activity], () => true, tasks)[0];
261
+ if (row !== void 0) items.push({
262
+ kind: "activity",
263
+ ordinal: activity.ordinal,
264
+ row
265
+ });
266
+ }
267
+ };
268
+ for (const activity of ordered) {
269
+ if (!isProjectedTaskActivity(activity, tasks)) continue;
270
+ if (activity.kind === "text") {
271
+ flushGroup();
272
+ if (activity.text !== void 0 && activity.text.length > 0) items.push({
273
+ kind: "text",
274
+ ordinal: activity.ordinal,
275
+ text: activity.text
276
+ });
277
+ continue;
278
+ }
279
+ if (activity.kind === "tool-call" && activity.toolUseId !== void 0 && activity.toolName !== void 0) {
280
+ group ??= {
281
+ ordinal: activity.ordinal,
282
+ tools: [],
283
+ byId: /* @__PURE__ */ new Map(),
284
+ trailingActivities: []
285
+ };
286
+ group.byId.set(activity.toolUseId, group.tools.length);
287
+ const input = inputRecord(activity.detail);
288
+ group.tools.push({
289
+ toolUseId: activity.toolUseId,
290
+ toolName: activity.toolName,
291
+ description: toolDescription(activity.toolName, input),
292
+ ...activity.summary === void 0 ? {} : { summary: activity.summary },
293
+ ...activity.detail === void 0 ? {} : { input: activity.detail },
294
+ ...activity.phase === void 0 ? {} : { phase: activity.phase },
295
+ ...activity.isError === void 0 ? {} : { isError: activity.isError },
296
+ subcalls: []
297
+ });
298
+ continue;
299
+ }
300
+ if ((activity.kind === "tool-result" || activity.kind === "permission") && activity.toolUseId !== void 0 && group !== void 0) {
301
+ const index = group.byId.get(activity.toolUseId);
302
+ const previous = index === void 0 ? void 0 : group.tools[index];
303
+ if (index !== void 0 && previous !== void 0) {
304
+ const failed = activity.isError === true || activity.phase === "failed" || activity.kind === "permission";
305
+ const diffs = failed ? void 0 : editDiffs(previous.toolName, inputRecord(previous.input));
306
+ const additions = diffs?.reduce((total, diff) => total + lineCount(diff.newText), 0);
307
+ const deletions = diffs?.reduce((total, diff) => total + (diff.oldText === null ? 0 : lineCount(diff.oldText)), 0);
308
+ group.tools[index] = {
309
+ ...previous,
310
+ description: toolDescription(previous.toolName, inputRecord(previous.input), failed),
311
+ ...activity.detail === void 0 ? {} : { output: activity.detail },
312
+ ...activity.phase === void 0 ? {} : { phase: activity.phase },
313
+ ...activity.isError === void 0 ? {} : { isError: activity.isError },
314
+ ...diffs === void 0 ? {} : {
315
+ diffs,
316
+ additions: additions ?? 0,
317
+ deletions: deletions ?? 0
318
+ },
319
+ ...activity.kind === "permission" ? {
320
+ output: activity.summary,
321
+ isError: true
322
+ } : {}
323
+ };
324
+ }
325
+ continue;
326
+ }
327
+ if (activity.kind === "subagent" && activity.parentToolUseId !== void 0 && group !== void 0) {
328
+ const index = group.byId.get(activity.parentToolUseId);
329
+ const previous = index === void 0 ? void 0 : group.tools[index];
330
+ const nested = subcallOf(activity);
331
+ if (index !== void 0 && previous !== void 0 && nested !== void 0) {
332
+ const nestedIndex = previous.subcalls.findIndex((item) => item.toolUseId === nested.toolUseId);
333
+ const subcalls = nestedIndex === -1 ? [...previous.subcalls, nested] : previous.subcalls.map((item, position) => position === nestedIndex ? {
334
+ ...item,
335
+ ...nested
336
+ } : item);
337
+ group.tools[index] = {
338
+ ...previous,
339
+ subcalls
340
+ };
341
+ }
342
+ continue;
343
+ }
344
+ if (!presentable(activity)) continue;
345
+ if (group !== void 0) {
346
+ group.trailingActivities.push(activity);
347
+ continue;
348
+ }
349
+ const row = activityRows([activity], () => true, tasks)[0];
350
+ if (row !== void 0) items.push({
351
+ kind: "activity",
352
+ ordinal: activity.ordinal,
353
+ row
354
+ });
355
+ }
356
+ flushGroup();
357
+ return items;
122
358
  }
123
- /** Anchor one sidecar-backed activity group immediately before its Claude assistant step. */
359
+ /** Keep one sidecar-backed activity group at the live chat tail, then anchor it
360
+ * before the native assistant message or at step settlement when none appears. */
124
361
  const claudeActivityStepDefinition = {
125
362
  kind: "claude-activity-step",
126
363
  target: "chat",
@@ -129,6 +366,10 @@ window.__ModuleLoader__.load({
129
366
  id: `${event.data.turn}:${event.data.step}`,
130
367
  role: "start"
131
368
  };
369
+ if (event.type === "step/end") return {
370
+ id: `${event.data.turn}:${event.data.step}`,
371
+ role: "update"
372
+ };
132
373
  if (event.type !== "assistant/message" || event.data.message.source.provider !== "claude") return null;
133
374
  return {
134
375
  id: `${event.data.turn}:${event.data.step}`,
@@ -139,25 +380,31 @@ window.__ModuleLoader__.load({
139
380
  if (match.event.type !== "step/start") throw new Error("Claude activity step requires step/start");
140
381
  return {
141
382
  turn: match.event.data.turn,
142
- step: match.event.data.step
383
+ step: match.event.data.step,
384
+ anchorSeq: Number.MAX_SAFE_INTEGER - 1
143
385
  };
144
386
  },
145
387
  update(context, match) {
146
- if (match.event.type !== "assistant/message") throw new Error("Claude activity step update requires assistant/message");
147
- return {
388
+ if (match.event.type === "assistant/message") return {
148
389
  ...context.state,
149
- assistantSeq: match.event.seq
390
+ assistantSeq: match.event.seq,
391
+ anchorSeq: match.event.seq - .1
150
392
  };
393
+ if (match.event.type === "step/end") return context.state.assistantSeq === void 0 ? {
394
+ ...context.state,
395
+ anchorSeq: match.event.seq - .1
396
+ } : context.state;
397
+ throw new Error("Claude activity step update requires assistant/message or step/end");
151
398
  },
152
399
  buildViewNode(context) {
153
400
  const state = context.state;
154
- if (state?.assistantSeq === void 0) return null;
401
+ if (state === void 0) return null;
155
402
  return {
156
403
  key: context.key,
157
404
  kind: "claude-activity-step",
158
405
  id: context.id,
159
406
  target: "chat",
160
- anchorSeq: state.assistantSeq - .1,
407
+ anchorSeq: state.anchorSeq,
161
408
  location: context.start?.location ?? { kind: "unresolved" },
162
409
  visibility: "visible",
163
410
  data: {
@@ -535,19 +782,35 @@ window.__ModuleLoader__.load({
535
782
  fontSize: 12,
536
783
  lineHeight: "17px"
537
784
  };
538
- const tasksClose = {
539
- width: 26,
540
- height: 26,
541
- display: "grid",
542
- placeItems: "center",
543
- border: "none",
544
- borderRadius: 7,
545
- background: "transparent",
546
- color: "var(--dsw-alias-label-tertiary)",
547
- fontSize: 15,
548
- lineHeight: "1",
549
- cursor: "pointer"
550
- };
785
+ const panelIconButtonClass = "dshClaudePanelIconButton";
786
+ const panelIconButtonCss = `
787
+ .${panelIconButtonClass} {
788
+ width: 26px;
789
+ height: 26px;
790
+ display: grid;
791
+ place-items: center;
792
+ padding: 0;
793
+ border: none;
794
+ border-radius: 7px;
795
+ background: transparent;
796
+ color: var(--dsw-alias-label-tertiary);
797
+ font: inherit;
798
+ line-height: 1;
799
+ cursor: pointer;
800
+ transition: background-color 120ms ease, color 120ms ease;
801
+ }
802
+ .${panelIconButtonClass}:hover {
803
+ background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);
804
+ color: var(--dsw-alias-label-primary);
805
+ }
806
+ .${panelIconButtonClass}:active {
807
+ background: color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent);
808
+ }
809
+ .${panelIconButtonClass}:focus-visible {
810
+ outline: 2px solid var(--dsw-static-blue-450);
811
+ outline-offset: 1px;
812
+ }
813
+ `;
551
814
  const tasksBody = {
552
815
  flex: 1,
553
816
  minHeight: 0,
@@ -729,26 +992,105 @@ window.__ModuleLoader__.load({
729
992
  lineHeight: "16px",
730
993
  cursor: "pointer"
731
994
  };
732
- const tasksTurnLauncher = {
995
+ const tasksBadgeWrap = {
996
+ display: "flex",
997
+ justifyContent: "flex-end",
998
+ margin: "8px 0 4px"
999
+ };
1000
+ const tasksBadgeSeat = {
1001
+ position: "relative",
1002
+ display: "inline-flex"
1003
+ };
1004
+ const tasksTurnBadge = {
733
1005
  display: "inline-flex",
734
1006
  alignItems: "center",
735
- gap: 7,
736
- margin: "6px 0 2px",
737
- padding: "5px 8px",
1007
+ gap: 5,
1008
+ padding: "2px 4px",
738
1009
  border: "none",
739
- borderRadius: 8,
1010
+ borderRadius: 6,
740
1011
  background: "transparent",
741
- color: "var(--dsw-alias-label-secondary)",
1012
+ color: "var(--dsw-alias-label-tertiary)",
742
1013
  font: "inherit",
1014
+ fontSize: 11,
1015
+ lineHeight: "16px",
1016
+ fontVariantNumeric: "tabular-nums",
1017
+ cursor: "pointer",
1018
+ transition: "color 120ms ease, opacity 120ms ease"
1019
+ };
1020
+ const tasksBadgeHovered = { color: "var(--dsw-alias-label-secondary)" };
1021
+ const tasksBadgeDone = { opacity: .7 };
1022
+ const tasksBadgeDot = {
1023
+ width: 8,
1024
+ height: 8,
1025
+ flex: "none",
1026
+ borderRadius: 999,
1027
+ background: "var(--dsw-static-blue-450)"
1028
+ };
1029
+ const tasksBadgeDotError = { background: "var(--dsw-alias-state-error-primary)" };
1030
+ const tasksBadgeDotDone = { background: "var(--dsw-alias-state-success-primary, var(--dsw-static-green-500))" };
1031
+ const tasksBadgeCount = { fontWeight: 600 };
1032
+ const tasksHoverCard = {
1033
+ position: "absolute",
1034
+ right: 0,
1035
+ bottom: "calc(100% + 8px)",
1036
+ zIndex: 40,
1037
+ minWidth: 240,
1038
+ maxWidth: 340,
1039
+ boxSizing: "border-box",
1040
+ display: "flex",
1041
+ flexDirection: "column",
1042
+ gap: 6,
1043
+ padding: "10px 12px",
1044
+ border: "1px solid var(--dsw-alias-border-l2)",
1045
+ borderRadius: 12,
1046
+ background: "var(--dsw-alias-bg-layer-2)",
1047
+ boxShadow: "0 8px 24px color-mix(in srgb, #000 24%, transparent)",
743
1048
  fontSize: 12,
744
1049
  lineHeight: "18px",
745
- cursor: "pointer"
1050
+ pointerEvents: "auto"
746
1051
  };
747
- const tasksTurnLauncherDot = {
748
- color: "var(--dsw-static-blue-450)",
749
- fontSize: 9
1052
+ const tasksHoverHeader = {
1053
+ color: "var(--dsw-alias-label-primary)",
1054
+ fontWeight: 600
1055
+ };
1056
+ const tasksHoverRow = {
1057
+ minWidth: 0,
1058
+ display: "flex",
1059
+ alignItems: "center",
1060
+ gap: 7
1061
+ };
1062
+ const tasksHoverGlyph = {
1063
+ width: 12,
1064
+ flex: "none",
1065
+ textAlign: "center",
1066
+ fontSize: 10,
1067
+ lineHeight: 1,
1068
+ fontWeight: 700
1069
+ };
1070
+ const tasksHoverGlyphRunning = { color: "var(--dsw-static-blue-450)" };
1071
+ const tasksHoverGlyphError = { color: "var(--dsw-alias-state-error-primary)" };
1072
+ const tasksHoverGlyphDone = { color: "var(--dsw-alias-state-success-primary, var(--dsw-static-green-500))" };
1073
+ const tasksHoverDesc = {
1074
+ minWidth: 0,
1075
+ flex: 1,
1076
+ overflow: "hidden",
1077
+ textOverflow: "ellipsis",
1078
+ whiteSpace: "nowrap",
1079
+ color: "var(--dsw-alias-label-secondary)"
1080
+ };
1081
+ const tasksHoverType = {
1082
+ flex: "none",
1083
+ color: "var(--dsw-alias-label-tertiary)",
1084
+ fontSize: 10
1085
+ };
1086
+ const tasksHoverMore = { color: "var(--dsw-alias-label-tertiary)" };
1087
+ const tasksHoverHint = {
1088
+ marginTop: 2,
1089
+ paddingTop: 6,
1090
+ borderTop: "1px solid var(--dsw-alias-border-l1)",
1091
+ color: "var(--dsw-alias-label-tertiary)",
1092
+ fontSize: 11
750
1093
  };
751
- const tasksTurnLauncherDone = { color: "var(--dsw-alias-state-success-primary, var(--dsw-alias-label-tertiary))" };
752
1094
  const heroRepositoryControls = {
753
1095
  position: "relative",
754
1096
  display: "inline-flex",
@@ -1069,6 +1411,10 @@ window.__ModuleLoader__.load({
1069
1411
  lineHeight: "20px",
1070
1412
  textAlign: "left"
1071
1413
  };
1414
+ const repositoryBarMerged = {
1415
+ borderColor: "color-mix(in srgb, #a78bfa 30%, var(--dsw-alias-border-l2))",
1416
+ background: "color-mix(in srgb, #a78bfa 5%, var(--dsw-alias-bg-layer-1))"
1417
+ };
1072
1418
  const repositoryPrIcon = {
1073
1419
  width: 20,
1074
1420
  height: 20,
@@ -1078,6 +1424,7 @@ window.__ModuleLoader__.load({
1078
1424
  borderRadius: 6,
1079
1425
  color: "var(--dsw-alias-state-success-primary, var(--dsw-static-blue-450))"
1080
1426
  };
1427
+ const repositoryPrIconMerged = { color: "#a78bfa" };
1081
1428
  const repositoryPrimary = {
1082
1429
  minWidth: 0,
1083
1430
  flex: 1,
@@ -1099,6 +1446,7 @@ window.__ModuleLoader__.load({
1099
1446
  textDecoration: "none",
1100
1447
  cursor: "pointer"
1101
1448
  };
1449
+ const repositoryPrLinkMerged = { color: "#a78bfa" };
1102
1450
  const repositoryPrHoverCard = {
1103
1451
  position: "absolute",
1104
1452
  zIndex: 30,
@@ -1134,6 +1482,10 @@ window.__ModuleLoader__.load({
1134
1482
  fontSize: 11,
1135
1483
  fontWeight: 650
1136
1484
  };
1485
+ const repositoryPrStateBadgeMerged = {
1486
+ background: "color-mix(in srgb, #a78bfa 18%, transparent)",
1487
+ color: "#a78bfa"
1488
+ };
1137
1489
  const repositoryPrHoverRepo = {
1138
1490
  minWidth: 0,
1139
1491
  flex: 1,
@@ -1248,6 +1600,31 @@ window.__ModuleLoader__.load({
1248
1600
  const repositoryItemSuccess = { color: "var(--dsw-alias-state-success-primary)" };
1249
1601
  const repositoryItemWarning = { color: "var(--dsw-alias-state-warning-primary, #d69e2e)" };
1250
1602
  const repositoryItemError = { color: "var(--dsw-alias-state-error-primary)" };
1603
+ const repositoryMergedStatus = {
1604
+ minWidth: 0,
1605
+ display: "inline-flex",
1606
+ alignItems: "center",
1607
+ gap: 6,
1608
+ overflow: "hidden",
1609
+ color: "#a78bfa",
1610
+ fontSize: 12,
1611
+ fontWeight: 600,
1612
+ whiteSpace: "nowrap",
1613
+ textOverflow: "ellipsis"
1614
+ };
1615
+ const repositoryMergedDot = {
1616
+ width: 6,
1617
+ height: 6,
1618
+ flex: "none",
1619
+ borderRadius: 999,
1620
+ background: "currentColor"
1621
+ };
1622
+ const repositoryMergedAge = {
1623
+ overflow: "hidden",
1624
+ color: "var(--dsw-alias-label-tertiary)",
1625
+ fontWeight: 500,
1626
+ textOverflow: "ellipsis"
1627
+ };
1251
1628
  const diffTrigger = {
1252
1629
  flex: "none",
1253
1630
  display: "inline-flex",
@@ -1264,85 +1641,334 @@ window.__ModuleLoader__.load({
1264
1641
  fontWeight: 650,
1265
1642
  cursor: "pointer"
1266
1643
  };
1644
+ const diffTriggerMuted = {
1645
+ background: "transparent",
1646
+ color: "var(--dsw-alias-label-tertiary)"
1647
+ };
1267
1648
  const diffAdd = { color: "var(--dsw-alias-state-success-primary)" };
1268
1649
  const diffDelete = { color: "var(--dsw-alias-state-error-primary)" };
1269
- const diffPanel = {
1270
- display: "flex",
1271
- flexDirection: "column",
1272
- width: "calc(100% - 16px)",
1273
- height: "calc(100% - 16px)",
1274
- minWidth: 0,
1275
- margin: 8,
1276
- overflow: "hidden",
1650
+ const diffCommentButtonClass = "dshClaudeDiffCommentButton";
1651
+ const diffLineRowClass = "dshClaudeDiffLineRow";
1652
+ const diffCommentTextareaClass = "dshClaudeDiffCommentTextarea";
1653
+ const diffCommentCss = `
1654
+ .${diffCommentButtonClass} {
1655
+ width: 18px;
1656
+ height: 18px;
1657
+ flex: none;
1658
+ display: grid;
1659
+ place-items: center;
1660
+ align-self: center;
1661
+ margin: 0 2px;
1662
+ padding: 0;
1663
+ border: none;
1664
+ border-radius: 4px;
1665
+ background: var(--dsw-static-blue-450);
1666
+ color: var(--dsw-alias-label-on-accent, #fff);
1667
+ font: inherit;
1668
+ font-size: 13px;
1669
+ line-height: 1;
1670
+ cursor: pointer;
1671
+ opacity: 0;
1672
+ transition: opacity 100ms ease;
1673
+ }
1674
+ .${diffLineRowClass}:hover .${diffCommentButtonClass},
1675
+ .${diffCommentButtonClass}:focus-visible {
1676
+ opacity: 1;
1677
+ }
1678
+ .${diffCommentButtonClass}[disabled] {
1679
+ visibility: hidden;
1680
+ }
1681
+ .${diffCommentTextareaClass}:focus {
1682
+ outline: none;
1683
+ box-shadow: inset 0 0 0 1px var(--dsw-static-blue-450);
1684
+ }
1685
+ `;
1686
+ const diffCommentBlock = {
1687
+ boxSizing: "border-box",
1688
+ width: "min(640px, calc(var(--dsh-claude-diff-viewport, 520px) - 72px))",
1689
+ position: "sticky",
1690
+ left: 62,
1691
+ margin: "4px 8px 8px 62px",
1692
+ padding: "8px 10px",
1277
1693
  border: "1px solid var(--dsw-alias-border-l2)",
1278
- borderRadius: 12,
1694
+ borderRadius: 8,
1279
1695
  background: "var(--dsw-alias-bg-layer-1)",
1280
- boxShadow: "0 4px 16px color-mix(in srgb, #000 12%, transparent)"
1696
+ fontFamily: "var(--dsw-font-family, system-ui)",
1697
+ fontSize: 12,
1698
+ lineHeight: "18px",
1699
+ whiteSpace: "normal"
1281
1700
  };
1282
- const diffHeader = {
1283
- boxSizing: "border-box",
1284
- height: 49,
1285
- flex: "none",
1701
+ const diffCommentCardText = {
1702
+ margin: 0,
1703
+ color: "var(--dsw-alias-label-primary)",
1704
+ overflowWrap: "anywhere"
1705
+ };
1706
+ const diffCommentCardMeta = {
1286
1707
  display: "flex",
1287
1708
  alignItems: "center",
1288
1709
  justifyContent: "space-between",
1289
- gap: 10,
1290
- padding: "9px 12px",
1291
- borderBottom: "1px solid var(--dsw-alias-border-l2)"
1710
+ gap: 8,
1711
+ marginBottom: 4,
1712
+ color: "var(--dsw-alias-label-tertiary)",
1713
+ fontSize: 11
1292
1714
  };
1293
- const diffHeaderTitle = {
1294
- minWidth: 0,
1715
+ const diffCommentTextarea = {
1716
+ width: "100%",
1717
+ minHeight: 56,
1718
+ boxSizing: "border-box",
1719
+ padding: "6px 8px",
1720
+ border: "1px solid var(--dsw-alias-border-l2)",
1721
+ borderRadius: 6,
1722
+ background: "var(--dsw-alias-bg-base)",
1723
+ color: "var(--dsw-alias-label-primary)",
1724
+ font: "inherit",
1725
+ resize: "vertical"
1726
+ };
1727
+ const diffCommentActions = {
1295
1728
  display: "flex",
1296
- alignItems: "center",
1729
+ justifyContent: "flex-end",
1297
1730
  gap: 8,
1298
- color: "var(--dsw-alias-label-primary)",
1299
- fontSize: 15,
1300
- fontWeight: 650
1731
+ marginTop: 6
1301
1732
  };
1302
- const diffHeaderBranch = {
1303
- overflow: "hidden",
1304
- color: "var(--dsw-alias-label-tertiary)",
1733
+ const diffCommentActionButton = {
1734
+ minHeight: 24,
1735
+ padding: "2px 10px",
1736
+ border: "1px solid var(--dsw-alias-border-l2)",
1737
+ borderRadius: 6,
1738
+ background: "transparent",
1739
+ color: "var(--dsw-alias-label-secondary)",
1740
+ font: "inherit",
1305
1741
  fontSize: 12,
1306
- fontWeight: 500,
1307
- textOverflow: "ellipsis",
1308
- whiteSpace: "nowrap"
1742
+ cursor: "pointer"
1309
1743
  };
1310
- const diffSummary = {
1311
- minHeight: 34,
1312
- display: "flex",
1313
- alignItems: "center",
1314
- gap: 7,
1315
- padding: "6px 12px",
1316
- borderBottom: "1px solid var(--dsw-alias-border-l2)",
1317
- color: "var(--dsw-alias-label-tertiary)",
1318
- fontSize: 12
1744
+ const diffCommentSubmitButton = {
1745
+ border: "none",
1746
+ background: "var(--dsw-static-blue-450)",
1747
+ color: "var(--dsw-alias-label-on-accent, #fff)",
1748
+ fontWeight: 600
1319
1749
  };
1320
- const diffBody = {
1321
- flex: 1,
1322
- minHeight: 0,
1323
- overflow: "auto",
1324
- background: "var(--dsw-alias-bg-base)"
1750
+ const diffCommentError = {
1751
+ margin: "4px 0 0",
1752
+ color: "var(--dsw-alias-state-error-primary)",
1753
+ fontSize: 11
1325
1754
  };
1326
- const diffFile = { borderBottom: "1px solid var(--dsw-alias-border-l2)" };
1327
- const diffFileHeader = {
1755
+ const reviewCommentBarFrame = {
1756
+ width: "calc(100% - 64px)",
1757
+ maxWidth: "var(--dsh-conversation-composer-max-width, 782px)",
1758
+ margin: "0 auto",
1759
+ boxSizing: "border-box"
1760
+ };
1761
+ const reviewCommentBar = {
1328
1762
  width: "100%",
1329
- minHeight: 38,
1763
+ minWidth: 0,
1764
+ minHeight: 42,
1765
+ boxSizing: "border-box",
1330
1766
  display: "flex",
1767
+ flexWrap: "wrap",
1331
1768
  alignItems: "center",
1332
- gap: 7,
1333
- padding: "7px 10px",
1334
- border: "none",
1769
+ gap: 8,
1770
+ padding: "7px 11px",
1771
+ border: "1px solid var(--dsw-alias-border-l2)",
1772
+ borderRadius: 11,
1335
1773
  background: "var(--dsw-alias-bg-layer-1)",
1774
+ boxShadow: "0 1px 2px color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent)",
1336
1775
  color: "var(--dsw-alias-label-primary)",
1337
- font: "inherit",
1338
1776
  fontSize: 12,
1339
- textAlign: "left",
1340
- cursor: "pointer"
1777
+ lineHeight: "20px"
1341
1778
  };
1342
- const diffFilePath = {
1343
- minWidth: 0,
1344
- flex: 1,
1345
- overflow: "hidden",
1779
+ const reviewCommentIcon = {
1780
+ width: 20,
1781
+ height: 20,
1782
+ display: "grid",
1783
+ placeItems: "center",
1784
+ flex: "none",
1785
+ color: "var(--dsw-static-blue-450)"
1786
+ };
1787
+ const reviewCommentClearSeat = {
1788
+ marginLeft: "auto",
1789
+ alignSelf: "flex-start",
1790
+ flex: "none",
1791
+ display: "inline-flex"
1792
+ };
1793
+ const reviewCommentChip = {
1794
+ display: "inline-flex",
1795
+ alignItems: "center",
1796
+ gap: 3,
1797
+ maxWidth: 240,
1798
+ padding: "1px 4px 1px 9px",
1799
+ border: "1px solid color-mix(in srgb, var(--dsw-static-blue-450) 32%, transparent)",
1800
+ borderRadius: 999,
1801
+ background: "color-mix(in srgb, var(--dsw-static-blue-450) 10%, transparent)",
1802
+ color: "var(--dsw-alias-label-primary)",
1803
+ fontSize: 12,
1804
+ lineHeight: "20px"
1805
+ };
1806
+ const reviewCommentChipLabel$1 = {
1807
+ overflow: "hidden",
1808
+ textOverflow: "ellipsis",
1809
+ whiteSpace: "nowrap"
1810
+ };
1811
+ const reviewCommentChipRemove = {
1812
+ width: 16,
1813
+ height: 16,
1814
+ flex: "none",
1815
+ display: "grid",
1816
+ placeItems: "center",
1817
+ padding: 0,
1818
+ border: "none",
1819
+ borderRadius: 999,
1820
+ background: "transparent",
1821
+ color: "var(--dsw-alias-label-tertiary)",
1822
+ font: "inherit",
1823
+ fontSize: 12,
1824
+ lineHeight: 1,
1825
+ cursor: "pointer"
1826
+ };
1827
+ const reviewCommentHoverCard = {
1828
+ display: "block",
1829
+ maxWidth: 360,
1830
+ padding: "8px 10px",
1831
+ fontSize: 12,
1832
+ lineHeight: "18px"
1833
+ };
1834
+ const reviewCommentHoverPath = {
1835
+ display: "block",
1836
+ marginBottom: 4,
1837
+ color: "var(--dsw-alias-label-tertiary)",
1838
+ fontSize: 11,
1839
+ overflowWrap: "anywhere"
1840
+ };
1841
+ const reviewCommentHoverText = {
1842
+ margin: 0,
1843
+ color: "var(--dsw-alias-label-primary)",
1844
+ whiteSpace: "pre-wrap",
1845
+ overflowWrap: "anywhere"
1846
+ };
1847
+ const diffAhead = { color: "var(--dsw-static-blue-450)" };
1848
+ const diffAheadMuted = { color: "color-mix(in srgb, var(--dsw-static-blue-450) 62%, var(--dsw-alias-label-tertiary))" };
1849
+ const diffAddMuted = { color: "color-mix(in srgb, var(--dsw-alias-state-success-primary) 62%, var(--dsw-alias-label-tertiary))" };
1850
+ const diffDeleteMuted = { color: "color-mix(in srgb, var(--dsw-alias-state-error-primary) 62%, var(--dsw-alias-label-tertiary))" };
1851
+ const diffPanel = {
1852
+ display: "flex",
1853
+ flexDirection: "column",
1854
+ width: "calc(100% - 16px)",
1855
+ height: "calc(100% - 16px)",
1856
+ minWidth: 0,
1857
+ margin: 8,
1858
+ overflow: "hidden",
1859
+ border: "1px solid var(--dsw-alias-border-l2)",
1860
+ borderRadius: 12,
1861
+ background: "var(--dsw-alias-bg-layer-1)",
1862
+ boxShadow: "0 4px 16px color-mix(in srgb, #000 12%, transparent)"
1863
+ };
1864
+ const diffPanelMaximized = {
1865
+ width: "100%",
1866
+ height: "100%",
1867
+ margin: 0
1868
+ };
1869
+ const diffHeader = {
1870
+ boxSizing: "border-box",
1871
+ height: 49,
1872
+ flex: "none",
1873
+ display: "flex",
1874
+ alignItems: "center",
1875
+ justifyContent: "space-between",
1876
+ gap: 10,
1877
+ padding: "9px 12px",
1878
+ borderBottom: "1px solid var(--dsw-alias-border-l2)"
1879
+ };
1880
+ const diffHeaderTitle = {
1881
+ minWidth: 0,
1882
+ display: "flex",
1883
+ alignItems: "center",
1884
+ gap: 8,
1885
+ color: "var(--dsw-alias-label-primary)",
1886
+ fontSize: 15,
1887
+ fontWeight: 650
1888
+ };
1889
+ const diffHeaderActions = {
1890
+ display: "flex",
1891
+ alignItems: "center",
1892
+ gap: 5
1893
+ };
1894
+ const diffSplitButton = {
1895
+ display: "inline-flex",
1896
+ alignItems: "stretch"
1897
+ };
1898
+ const diffCommitButton = {
1899
+ minHeight: 28,
1900
+ padding: "4px 10px",
1901
+ border: "none",
1902
+ borderRadius: "7px 0 0 7px",
1903
+ background: "var(--dsw-static-blue-450)",
1904
+ color: "var(--dsw-alias-label-on-accent, #fff)",
1905
+ font: "inherit",
1906
+ fontSize: 12,
1907
+ fontWeight: 650,
1908
+ cursor: "pointer"
1909
+ };
1910
+ const diffActionDisabled = {
1911
+ opacity: .45,
1912
+ cursor: "default"
1913
+ };
1914
+ const diffCommitMenuButton = {
1915
+ width: 28,
1916
+ minHeight: 28,
1917
+ display: "grid",
1918
+ placeItems: "center",
1919
+ padding: 0,
1920
+ border: "none",
1921
+ borderLeft: "1px solid color-mix(in srgb, #fff 32%, transparent)",
1922
+ borderRadius: "0 7px 7px 0",
1923
+ background: "var(--dsw-static-blue-450)",
1924
+ color: "var(--dsw-alias-label-on-accent, #fff)",
1925
+ font: "inherit",
1926
+ cursor: "pointer"
1927
+ };
1928
+ const diffHeaderBranch = {
1929
+ overflow: "hidden",
1930
+ color: "var(--dsw-alias-label-tertiary)",
1931
+ fontSize: 12,
1932
+ fontWeight: 500,
1933
+ textOverflow: "ellipsis",
1934
+ whiteSpace: "nowrap"
1935
+ };
1936
+ const diffSummary = {
1937
+ minHeight: 34,
1938
+ display: "flex",
1939
+ alignItems: "center",
1940
+ gap: 7,
1941
+ padding: "6px 12px",
1942
+ borderBottom: "1px solid var(--dsw-alias-border-l2)",
1943
+ color: "var(--dsw-alias-label-tertiary)",
1944
+ fontSize: 12
1945
+ };
1946
+ const diffBody = {
1947
+ flex: 1,
1948
+ minHeight: 0,
1949
+ overflow: "auto",
1950
+ background: "var(--dsw-alias-bg-base)"
1951
+ };
1952
+ const diffFile = { borderBottom: "1px solid var(--dsw-alias-border-l2)" };
1953
+ const diffFileHeader = {
1954
+ width: "100%",
1955
+ minHeight: 38,
1956
+ display: "flex",
1957
+ alignItems: "center",
1958
+ gap: 7,
1959
+ padding: "7px 10px",
1960
+ border: "none",
1961
+ background: "var(--dsw-alias-bg-layer-1)",
1962
+ color: "var(--dsw-alias-label-primary)",
1963
+ font: "inherit",
1964
+ fontSize: 12,
1965
+ textAlign: "left",
1966
+ cursor: "pointer"
1967
+ };
1968
+ const diffFilePath = {
1969
+ minWidth: 0,
1970
+ flex: 1,
1971
+ overflow: "hidden",
1346
1972
  textOverflow: "ellipsis",
1347
1973
  whiteSpace: "nowrap"
1348
1974
  };
@@ -1409,6 +2035,152 @@ window.__ModuleLoader__.load({
1409
2035
  color: "var(--dsw-alias-label-tertiary)",
1410
2036
  fontSize: 11
1411
2037
  };
2038
+ const diffModalCss = `
2039
+ .dshClaudeRepositoryActionModal {
2040
+ box-sizing: border-box;
2041
+ width: min(760px, calc(100vw - 48px));
2042
+ max-width: calc(100vw - 48px);
2043
+ max-height: min(680px, calc(100vh - 48px));
2044
+ }
2045
+ .dshClaudeRepositoryActionModalContent {
2046
+ flex: 1;
2047
+ min-height: 0;
2048
+ overflow-y: auto;
2049
+ }
2050
+ .dshClaudeRepositoryActionModalContent > div:first-child {
2051
+ position: sticky;
2052
+ top: 0;
2053
+ z-index: 2;
2054
+ background: var(--dsw-alias-bg-layer-2);
2055
+ }
2056
+ .dshClaudeRepositoryActionModalContent h2 {
2057
+ font-size: 24px;
2058
+ line-height: 32px;
2059
+ }
2060
+ .dshClaudeRepositoryActionModalContent > p {
2061
+ font-size: 18px;
2062
+ line-height: 28px;
2063
+ }
2064
+ .dshClaudeRepositoryActionModal input[type='checkbox'] {
2065
+ width: 18px;
2066
+ height: 18px;
2067
+ }
2068
+ .dshClaudeRepositoryActionModal textarea:focus,
2069
+ .dshClaudeRepositoryActionModal input:not([type='checkbox']):focus {
2070
+ outline: none;
2071
+ box-shadow: inset 0 0 0 1px var(--dsw-static-blue-450);
2072
+ }
2073
+ `;
2074
+ const diffModalBody = {
2075
+ display: "flex",
2076
+ flexDirection: "column",
2077
+ gap: 16,
2078
+ width: "100%",
2079
+ minWidth: 0,
2080
+ boxSizing: "border-box"
2081
+ };
2082
+ const diffModalMeta = {
2083
+ display: "flex",
2084
+ justifyContent: "space-between",
2085
+ gap: 16,
2086
+ minWidth: 0,
2087
+ color: "var(--dsw-alias-label-secondary)",
2088
+ fontSize: 16,
2089
+ lineHeight: "24px"
2090
+ };
2091
+ const diffModalMetaText = {
2092
+ minWidth: 0,
2093
+ overflow: "hidden",
2094
+ textOverflow: "ellipsis",
2095
+ whiteSpace: "nowrap"
2096
+ };
2097
+ const diffModalFiles = {
2098
+ minWidth: 0,
2099
+ maxHeight: 300,
2100
+ overflowX: "hidden",
2101
+ overflowY: "auto",
2102
+ border: "1px solid var(--dsw-alias-border-l2)",
2103
+ borderRadius: 8
2104
+ };
2105
+ const diffModalFile = {
2106
+ display: "flex",
2107
+ justifyContent: "space-between",
2108
+ gap: 12,
2109
+ minWidth: 0,
2110
+ padding: "10px 14px",
2111
+ borderBottom: "1px solid var(--dsw-alias-border-l2)",
2112
+ color: "var(--dsw-alias-label-secondary)",
2113
+ fontSize: 15,
2114
+ lineHeight: "22px"
2115
+ };
2116
+ const diffModalFilePath = {
2117
+ minWidth: 0,
2118
+ overflow: "hidden",
2119
+ textOverflow: "ellipsis",
2120
+ whiteSpace: "nowrap"
2121
+ };
2122
+ const diffModalFileState = { flex: "none" };
2123
+ const diffModalField = {
2124
+ display: "flex",
2125
+ flexDirection: "column",
2126
+ gap: 8,
2127
+ color: "var(--dsw-alias-label-secondary)",
2128
+ fontSize: 16,
2129
+ lineHeight: "24px",
2130
+ fontWeight: 550
2131
+ };
2132
+ const diffModalTextarea = {
2133
+ ...settingTextInput,
2134
+ minHeight: 140,
2135
+ padding: "10px 14px",
2136
+ fontSize: 16,
2137
+ lineHeight: "24px",
2138
+ resize: "vertical"
2139
+ };
2140
+ const diffModalTextInput = {
2141
+ ...settingTextInput,
2142
+ minHeight: 44,
2143
+ padding: "9px 14px",
2144
+ fontSize: 16,
2145
+ lineHeight: "24px"
2146
+ };
2147
+ const diffModalCheckbox = {
2148
+ display: "flex",
2149
+ alignItems: "center",
2150
+ gap: 10,
2151
+ color: "var(--dsw-alias-label-secondary)",
2152
+ fontSize: 16,
2153
+ lineHeight: "24px"
2154
+ };
2155
+ const diffModalFooter = {
2156
+ display: "flex",
2157
+ justifyContent: "flex-end",
2158
+ gap: 12
2159
+ };
2160
+ const diffModalButton = {
2161
+ minHeight: 42,
2162
+ padding: "8px 18px",
2163
+ fontSize: 16,
2164
+ lineHeight: "24px"
2165
+ };
2166
+ const diffModalStatus = {
2167
+ margin: 0,
2168
+ color: "var(--dsw-alias-label-secondary)",
2169
+ fontSize: 16,
2170
+ lineHeight: "24px"
2171
+ };
2172
+ const diffModalError = {
2173
+ margin: "10px 0 0",
2174
+ color: "var(--dsw-alias-state-error-primary)",
2175
+ fontSize: 16,
2176
+ lineHeight: "24px"
2177
+ };
2178
+ const diffModalSuccess = {
2179
+ margin: 0,
2180
+ color: "var(--dsw-alias-state-success-primary)",
2181
+ fontSize: 16,
2182
+ lineHeight: "24px"
2183
+ };
1412
2184
  //#endregion
1413
2185
  //#region src/client/token-format.ts
1414
2186
  function formatTokenCount(tokens) {
@@ -1426,16 +2198,17 @@ window.__ModuleLoader__.load({
1426
2198
  killed: "tasksKilled"
1427
2199
  };
1428
2200
  function visibleTaskGroups(tasks, dismissedSettledIds) {
2201
+ const projected = tasks.filter(isProjectedTask);
1429
2202
  return {
1430
- running: tasks.filter((task) => task.status === "running"),
1431
- finished: tasks.filter((task) => task.status !== "running" && !dismissedSettledIds.has(task.taskId))
2203
+ running: projected.filter((task) => task.status === "running"),
2204
+ finished: projected.filter((task) => task.status !== "running" && !dismissedSettledIds.has(task.taskId))
1432
2205
  };
1433
2206
  }
1434
2207
  function activitiesForTask(activities, taskId) {
1435
2208
  return activities.filter((activity) => activity.taskId === taskId);
1436
2209
  }
1437
2210
  function tasksForTurn(tasks, turn) {
1438
- return tasks.filter((task) => task.originTurn === turn);
2211
+ return tasks.filter((task) => task.originTurn === turn && isProjectedTask(task));
1439
2212
  }
1440
2213
  function summarizeTurnTasks(tasks) {
1441
2214
  if (tasks.length === 0) return void 0;
@@ -1538,7 +2311,7 @@ window.__ModuleLoader__.load({
1538
2311
  children: task.description
1539
2312
  }), /* @__PURE__ */ jsxs("p", {
1540
2313
  style: taskStatusLine,
1541
- children: [/* @__PURE__ */ jsx("span", { children: t(STATUS_LABEL[task.status] ?? "tasksRunning") }), task.backgrounded === true ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
2314
+ children: [/* @__PURE__ */ jsx("span", { children: t(STATUS_LABEL[task.status] ?? "tasksRunning") }), task.backgrounded === true ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
1542
2315
  "aria-hidden": "true",
1543
2316
  children: " · "
1544
2317
  }), /* @__PURE__ */ jsx("span", { children: t("tasksBackground") })] }) : null]
@@ -1574,7 +2347,7 @@ window.__ModuleLoader__.load({
1574
2347
  }
1575
2348
  function GroupHeading(props) {
1576
2349
  const { label, count, collapsed, onToggle, action } = props;
1577
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", {
2350
+ const content = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", {
1578
2351
  style: tasksGroupCount,
1579
2352
  children: count
1580
2353
  })] });
@@ -1621,96 +2394,192 @@ window.__ModuleLoader__.load({
1621
2394
  if (!projection.owned) return null;
1622
2395
  return /* @__PURE__ */ jsxs("div", {
1623
2396
  style: tasksPanel,
1624
- children: [/* @__PURE__ */ jsxs("div", {
1625
- style: tasksHeader,
1626
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
1627
- style: tasksHeading,
1628
- children: t("tasksPanelTurn")
1629
- }), /* @__PURE__ */ jsx("span", {
1630
- style: tasksTurnMeta,
1631
- children: t("tasksTurnNumber", { turn })
1632
- })] }), /* @__PURE__ */ jsx("button", {
1633
- type: "button",
1634
- style: tasksClose,
1635
- "aria-label": t("tasksClose"),
1636
- onClick: closeDetails,
1637
- children: "×"
1638
- })]
1639
- }), /* @__PURE__ */ jsxs("div", {
1640
- style: tasksBody,
1641
- children: [/* @__PURE__ */ jsxs("section", {
1642
- "aria-label": t("tasksRunning"),
1643
- children: [/* @__PURE__ */ jsx(GroupHeading, {
1644
- label: t("tasksRunning"),
1645
- count: groups.running.length
1646
- }), groups.running.length === 0 ? /* @__PURE__ */ jsx("p", {
1647
- style: tasksGroupEmpty,
1648
- children: t("tasksNoneRunning")
1649
- }) : /* @__PURE__ */ jsx("div", {
1650
- style: taskCardList,
1651
- children: groups.running.map((task) => /* @__PURE__ */ jsx(TaskCard, {
1652
- task,
1653
- activities: taskActivities.get(task.taskId) ?? [],
1654
- t
1655
- }, task.taskId))
2397
+ children: [
2398
+ /* @__PURE__ */ jsx("style", {
2399
+ "data-dsh-claude-panel-icon-styles": true,
2400
+ children: panelIconButtonCss
2401
+ }),
2402
+ /* @__PURE__ */ jsxs("div", {
2403
+ style: tasksHeader,
2404
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
2405
+ style: tasksHeading,
2406
+ children: t("tasksPanelTurn")
2407
+ }), /* @__PURE__ */ jsx("span", {
2408
+ style: tasksTurnMeta,
2409
+ children: t("tasksTurnNumber", { turn })
2410
+ })] }), /* @__PURE__ */ jsx("button", {
2411
+ type: "button",
2412
+ className: panelIconButtonClass,
2413
+ "aria-label": t("tasksClose"),
2414
+ onClick: closeDetails,
2415
+ children: /* @__PURE__ */ jsx(IconCloseOutline16, {})
1656
2416
  })]
1657
- }), /* @__PURE__ */ jsxs("section", {
1658
- "aria-label": t("tasksSettled"),
1659
- style: tasksFinishedSection,
1660
- children: [/* @__PURE__ */ jsx(GroupHeading, {
1661
- label: t("tasksSettled"),
1662
- count: groups.finished.length,
1663
- collapsed: finishedCollapsed,
1664
- onToggle: () => setFinishedCollapsed((value) => !value),
1665
- ...groups.finished.length === 0 ? {} : { action: {
1666
- label: t("tasksClear"),
1667
- onClick: clearFinished
1668
- } }
1669
- }), finishedCollapsed || groups.finished.length === 0 ? null : /* @__PURE__ */ jsx("div", {
1670
- style: taskCardList,
1671
- children: groups.finished.map((task) => /* @__PURE__ */ jsx(TaskCard, {
1672
- task,
1673
- activities: taskActivities.get(task.taskId) ?? [],
1674
- t
1675
- }, task.taskId))
2417
+ }),
2418
+ /* @__PURE__ */ jsxs("div", {
2419
+ style: tasksBody,
2420
+ children: [/* @__PURE__ */ jsxs("section", {
2421
+ "aria-label": t("tasksRunning"),
2422
+ children: [/* @__PURE__ */ jsx(GroupHeading, {
2423
+ label: t("tasksRunning"),
2424
+ count: groups.running.length
2425
+ }), groups.running.length === 0 ? /* @__PURE__ */ jsx("p", {
2426
+ style: tasksGroupEmpty,
2427
+ children: t("tasksNoneRunning")
2428
+ }) : /* @__PURE__ */ jsx("div", {
2429
+ style: taskCardList,
2430
+ children: groups.running.map((task) => /* @__PURE__ */ jsx(TaskCard, {
2431
+ task,
2432
+ activities: taskActivities.get(task.taskId) ?? [],
2433
+ t
2434
+ }, task.taskId))
2435
+ })]
2436
+ }), /* @__PURE__ */ jsxs("section", {
2437
+ "aria-label": t("tasksSettled"),
2438
+ style: tasksFinishedSection,
2439
+ children: [/* @__PURE__ */ jsx(GroupHeading, {
2440
+ label: t("tasksSettled"),
2441
+ count: groups.finished.length,
2442
+ collapsed: finishedCollapsed,
2443
+ onToggle: () => setFinishedCollapsed((value) => !value),
2444
+ ...groups.finished.length === 0 ? {} : { action: {
2445
+ label: t("tasksClear"),
2446
+ onClick: clearFinished
2447
+ } }
2448
+ }), finishedCollapsed || groups.finished.length === 0 ? null : /* @__PURE__ */ jsx("div", {
2449
+ style: taskCardList,
2450
+ children: groups.finished.map((task) => /* @__PURE__ */ jsx(TaskCard, {
2451
+ task,
2452
+ activities: taskActivities.get(task.taskId) ?? [],
2453
+ t
2454
+ }, task.taskId))
2455
+ })]
1676
2456
  })]
1677
- })]
1678
- })]
2457
+ })
2458
+ ]
1679
2459
  });
1680
2460
  }
1681
2461
  //#endregion
1682
2462
  //#region src/client/ClaudeActivityTail.tsx
2463
+ const MAX_HOVER_TASKS = 6;
2464
+ function taskGlyph(status) {
2465
+ if (status === "failed") return {
2466
+ glyph: "×",
2467
+ style: tasksHoverGlyphError
2468
+ };
2469
+ if (status === "completed") return {
2470
+ glyph: "✓",
2471
+ style: tasksHoverGlyphDone
2472
+ };
2473
+ return {
2474
+ glyph: "●",
2475
+ style: tasksHoverGlyphRunning
2476
+ };
2477
+ }
1683
2478
  function ClaudeTaskLauncher({ turn, tasks, t, openTasks }) {
1684
- const summary = useMemo(() => summarizeTurnTasks(tasksForTurn(tasks, turn)), [tasks, turn]);
2479
+ const [hovered, setHovered] = useState(false);
2480
+ const closeTimer = useRef();
2481
+ const turnTasks = useMemo(() => tasksForTurn(tasks, turn), [tasks, turn]);
2482
+ const summary = useMemo(() => summarizeTurnTasks(turnTasks), [turnTasks]);
2483
+ const open = () => {
2484
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2485
+ closeTimer.current = void 0;
2486
+ setHovered(true);
2487
+ };
2488
+ const scheduleClose = () => {
2489
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2490
+ closeTimer.current = setTimeout(() => {
2491
+ closeTimer.current = void 0;
2492
+ setHovered(false);
2493
+ }, 350);
2494
+ };
2495
+ useEffect(() => () => {
2496
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2497
+ }, []);
1685
2498
  if (summary === void 0) return null;
1686
2499
  const label = summary.state === "running" ? t("tasksTurnRunning", { count: summary.running }) : summary.state === "failed" ? t("tasksTurnFailed", {
1687
2500
  failed: summary.failed,
1688
2501
  completed: summary.completed
1689
2502
  }) : t("tasksTurnCompleted", { count: summary.completed });
1690
- const glyph = summary.state === "running" ? "●" : summary.state === "failed" ? "×" : "✓";
2503
+ const stateStyle = summary.state === "completed" ? tasksBadgeDone : {};
2504
+ const dotStyle = summary.state === "failed" ? tasksBadgeDotError : summary.state === "completed" ? tasksBadgeDotDone : {};
1691
2505
  return /* @__PURE__ */ jsx("div", {
1692
2506
  "data-claude-task-launcher": turn,
1693
- children: /* @__PURE__ */ jsxs("button", {
1694
- type: "button",
1695
- style: tasksTurnLauncher,
1696
- onClick: () => openTasks(turn),
1697
- children: [
1698
- /* @__PURE__ */ jsx("span", {
2507
+ style: tasksBadgeWrap,
2508
+ children: /* @__PURE__ */ jsxs("span", {
2509
+ style: tasksBadgeSeat,
2510
+ onMouseEnter: open,
2511
+ onMouseLeave: scheduleClose,
2512
+ onFocus: open,
2513
+ onBlur: (event) => {
2514
+ if (!event.currentTarget.contains(event.relatedTarget)) scheduleClose();
2515
+ },
2516
+ children: [hovered ? /* @__PURE__ */ jsxs("span", {
2517
+ role: "tooltip",
2518
+ style: tasksHoverCard,
2519
+ onMouseEnter: open,
2520
+ onMouseLeave: scheduleClose,
2521
+ children: [
2522
+ /* @__PURE__ */ jsx("span", {
2523
+ style: tasksHoverHeader,
2524
+ children: label
2525
+ }),
2526
+ turnTasks.slice(0, MAX_HOVER_TASKS).map((task) => {
2527
+ const { glyph, style } = taskGlyph(task.status);
2528
+ return /* @__PURE__ */ jsxs("span", {
2529
+ style: tasksHoverRow,
2530
+ children: [
2531
+ /* @__PURE__ */ jsx("span", {
2532
+ className: task.status === "running" ? "dsh-claude-act-running" : void 0,
2533
+ style: {
2534
+ ...tasksHoverGlyph,
2535
+ ...style
2536
+ },
2537
+ "aria-hidden": "true",
2538
+ children: glyph
2539
+ }),
2540
+ /* @__PURE__ */ jsx("span", {
2541
+ style: tasksHoverDesc,
2542
+ title: task.description,
2543
+ children: task.description
2544
+ }),
2545
+ task.subagentType === void 0 ? null : /* @__PURE__ */ jsx("span", {
2546
+ style: tasksHoverType,
2547
+ children: task.subagentType
2548
+ })
2549
+ ]
2550
+ }, task.taskId);
2551
+ }),
2552
+ turnTasks.length > MAX_HOVER_TASKS ? /* @__PURE__ */ jsxs("span", {
2553
+ style: tasksHoverMore,
2554
+ children: ["+", turnTasks.length - MAX_HOVER_TASKS]
2555
+ }) : null,
2556
+ /* @__PURE__ */ jsx("span", {
2557
+ style: tasksHoverHint,
2558
+ children: t("tasksOpen")
2559
+ })
2560
+ ]
2561
+ }) : null, /* @__PURE__ */ jsxs("button", {
2562
+ type: "button",
2563
+ className: "dsh-claude-task-launcher",
2564
+ style: {
2565
+ ...tasksTurnBadge,
2566
+ ...stateStyle,
2567
+ ...hovered ? tasksBadgeHovered : {}
2568
+ },
2569
+ "aria-label": `${label} — ${t("tasksOpen")}`,
2570
+ onClick: () => openTasks(turn),
2571
+ children: [/* @__PURE__ */ jsx("span", {
1699
2572
  className: summary.state === "running" ? "dsh-claude-act-running" : void 0,
1700
2573
  style: {
1701
- ...tasksTurnLauncherDot,
1702
- ...summary.state === "failed" ? iconChipError : {},
1703
- ...summary.state === "completed" ? tasksTurnLauncherDone : {}
2574
+ ...tasksBadgeDot,
2575
+ ...dotStyle
1704
2576
  },
1705
- "aria-hidden": "true",
1706
- children: glyph
1707
- }),
1708
- /* @__PURE__ */ jsx("span", { children: label }),
1709
- /* @__PURE__ */ jsx("span", {
1710
- "aria-hidden": "true",
1711
- children: "›"
1712
- })
1713
- ]
2577
+ "aria-hidden": "true"
2578
+ }), /* @__PURE__ */ jsx("span", {
2579
+ style: tasksBadgeCount,
2580
+ children: turnTasks.length
2581
+ })]
2582
+ })]
1714
2583
  })
1715
2584
  });
1716
2585
  }
@@ -1740,7 +2609,38 @@ window.__ModuleLoader__.load({
1740
2609
  //#region src/client/ClaudeActivityNode.tsx
1741
2610
  const EMPTY_TASKS = [];
1742
2611
  const ACTIVITY_CSS = [
1743
- ".dsh-claude-flow{display:flex;flex-direction:column;gap:4px}",
2612
+ ".dsh-claude-flow{display:flex;flex-direction:column;gap:10px}",
2613
+ ".dsh-claude-transcript-text{color:var(--dsw-alias-label-primary);font-size:15px;line-height:24px;overflow-wrap:anywhere}",
2614
+ ".dsh-claude-tool-group-native{overflow:visible}",
2615
+ ".dsh-claude-tool-group-native>.dsh-claude-flow-row{padding:0}",
2616
+ ".dsh-claude-tool-list{max-height:min(420px,calc(100vh - 320px));overflow-x:hidden;overflow-y:auto;overscroll-behavior:contain;margin-top:4px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;scrollbar-gutter:stable}",
2617
+ ".dsh-claude-tool-item{border-top:1px solid var(--dsw-alias-border-l1)}",
2618
+ ".dsh-claude-tool-item:first-child{border-top:0}",
2619
+ ".dsh-claude-tool-summary-row{display:flex;align-items:center;min-height:34px;gap:8px;padding:0 10px;cursor:pointer;list-style:none}",
2620
+ ".dsh-claude-tool-summary-row::-webkit-details-marker{display:none}",
2621
+ ".dsh-claude-tool-summary-row::after{content:\"›\";margin-left:2px;flex:none;align-self:center;color:var(--dsw-alias-label-secondary);font-size:22px;line-height:1;transform-origin:center;transition:transform .15s ease}",
2622
+ ".dsh-claude-tool-item[open]>.dsh-claude-tool-summary-row::after{transform:rotate(90deg)}",
2623
+ ".dsh-claude-tool-content{min-width:0;padding:0 10px 8px}",
2624
+ ".dsh-claude-tool-content>*{max-width:100%;box-sizing:border-box}",
2625
+ ".dsh-claude-tool-section{margin-top:8px}",
2626
+ ".dsh-claude-tool-section-title{margin-bottom:4px;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;text-transform:uppercase;letter-spacing:.04em}",
2627
+ ".dsh-claude-tool-fields{display:grid;grid-template-columns:max-content minmax(0,1fr);gap:3px 12px;font-size:13px;line-height:20px}",
2628
+ ".dsh-claude-tool-field-key{color:var(--dsw-alias-label-tertiary)}",
2629
+ ".dsh-claude-tool-field-value{min-width:0;color:var(--dsw-alias-label-primary);white-space:pre-wrap;overflow-wrap:anywhere}",
2630
+ ".dsh-claude-tool-paths{display:flex;flex-direction:column;gap:2px;margin:0;padding:0;list-style:none;font:var(--dsw-font-markdown-code-block-small)}",
2631
+ ".dsh-claude-tool-path{overflow-wrap:anywhere;color:var(--dsw-alias-label-primary)}",
2632
+ ".dsh-claude-tool-code{max-height:260px;overflow:auto;margin:0;padding:8px 0;border-radius:8px;background:var(--dsw-alias-markdown-code-block);font:var(--dsw-font-markdown-code-block-small)}",
2633
+ ".dsh-claude-tool-code-line{display:grid;grid-template-columns:44px minmax(max-content,1fr);min-height:18px}",
2634
+ ".dsh-claude-tool-line-number{padding-right:10px;text-align:right;user-select:none;color:var(--dsw-alias-label-caption);border-right:1px solid var(--dsw-alias-border-l1)}",
2635
+ ".dsh-claude-tool-line-text{padding:0 10px;white-space:pre}",
2636
+ ".dsh-claude-tool-label{width:72px;flex:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;line-height:20px;color:var(--dsw-alias-label-tertiary)}",
2637
+ ".dsh-claude-tool-description{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px;color:var(--dsw-alias-label-primary)}",
2638
+ ".dsh-claude-tool-stats{display:inline-flex;gap:4px;flex:none;font-size:13px;line-height:20px}",
2639
+ ".dsh-claude-diff-add{color:var(--dsw-alias-state-success-primary,#21c55d)}",
2640
+ ".dsh-claude-diff-delete{color:var(--dsw-alias-state-error-primary)}",
2641
+ ".dsh-claude-tool-name{font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary)}",
2642
+ ".dsh-claude-tool-summary{margin-left:8px;color:var(--dsw-alias-label-tertiary)}",
2643
+ ".dsh-claude-tool-detail{margin:6px 0 0;padding:8px 10px;max-height:220px;overflow:auto;border-radius:8px;background:var(--dsw-alias-markdown-code-block);font:var(--dsw-font-markdown-code-block-small);white-space:pre-wrap;overflow-wrap:anywhere}",
1744
2644
  ".dsh-claude-flow-row{position:relative;overflow:hidden}",
1745
2645
  ".dsh-claude-flow-leading{flex-shrink:0}",
1746
2646
  ".dsh-claude-flow-title{font-weight:400}",
@@ -1797,7 +2697,7 @@ window.__ModuleLoader__.load({
1797
2697
  expandOnRowClick: true,
1798
2698
  keepContentWhenOpen: true,
1799
2699
  onToggle: () => setOpen((value) => !value),
1800
- collapsedContent: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
2700
+ collapsedContent: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
1801
2701
  className: "dsh-claude-flow-separator",
1802
2702
  "aria-hidden": "true"
1803
2703
  }), /* @__PURE__ */ jsx("span", {
@@ -1822,24 +2722,292 @@ window.__ModuleLoader__.load({
1822
2722
  })]
1823
2723
  });
1824
2724
  }
2725
+ function parsedValue(value) {
2726
+ if (value === void 0 || value.length === 0) return void 0;
2727
+ try {
2728
+ return JSON.parse(value);
2729
+ } catch {
2730
+ return value;
2731
+ }
2732
+ }
2733
+ function record$4(value) {
2734
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2735
+ }
2736
+ function text(value) {
2737
+ return typeof value === "string" && value.length > 0 ? value : void 0;
2738
+ }
2739
+ function numberValue(value) {
2740
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
2741
+ }
2742
+ function displayValue(value) {
2743
+ if (value === null) return "null";
2744
+ if (typeof value === "string") return value;
2745
+ if (typeof value === "number" || typeof value === "boolean") return String(value);
2746
+ if (Array.isArray(value)) return value.map(displayValue).join(", ");
2747
+ return record$4(value) === void 0 ? String(value) : Object.entries(value).map(([key, item]) => `${key}: ${displayValue(item)}`).join("\n");
2748
+ }
2749
+ function Section({ title, children }) {
2750
+ return /* @__PURE__ */ jsxs("section", {
2751
+ className: "dsh-claude-tool-section",
2752
+ children: [/* @__PURE__ */ jsx("div", {
2753
+ className: "dsh-claude-tool-section-title",
2754
+ children: title
2755
+ }), children]
2756
+ });
2757
+ }
2758
+ function Fields({ value, omit = [] }) {
2759
+ const entries = Object.entries(value).filter(([key, item]) => !omit.includes(key) && item !== void 0 && item !== "");
2760
+ if (entries.length === 0) return null;
2761
+ return /* @__PURE__ */ jsx("div", {
2762
+ className: "dsh-claude-tool-fields",
2763
+ children: entries.map(([key, item]) => /* @__PURE__ */ jsxs("div", {
2764
+ style: { display: "contents" },
2765
+ children: [/* @__PURE__ */ jsx("span", {
2766
+ className: "dsh-claude-tool-field-key",
2767
+ children: key.replaceAll("_", " ")
2768
+ }), /* @__PURE__ */ jsx("span", {
2769
+ className: "dsh-claude-tool-field-value",
2770
+ children: displayValue(item)
2771
+ })]
2772
+ }, key))
2773
+ });
2774
+ }
2775
+ function Paths({ paths }) {
2776
+ if (paths.length === 0) return null;
2777
+ return /* @__PURE__ */ jsx("ul", {
2778
+ className: "dsh-claude-tool-paths",
2779
+ children: paths.map((path, index) => /* @__PURE__ */ jsx("li", {
2780
+ className: "dsh-claude-tool-path",
2781
+ children: path
2782
+ }, `${path}:${index}`))
2783
+ });
2784
+ }
2785
+ function Source({ content, start = 1 }) {
2786
+ return /* @__PURE__ */ jsx("div", {
2787
+ className: "dsh-claude-tool-code",
2788
+ children: content.split(/\r?\n/u).map((line, index) => /* @__PURE__ */ jsxs("div", {
2789
+ className: "dsh-claude-tool-code-line",
2790
+ children: [/* @__PURE__ */ jsx("span", {
2791
+ className: "dsh-claude-tool-line-number",
2792
+ children: start + index
2793
+ }), /* @__PURE__ */ jsx("span", {
2794
+ className: "dsh-claude-tool-line-text",
2795
+ children: line || " "
2796
+ })]
2797
+ }, index))
2798
+ });
2799
+ }
2800
+ function TextDetail({ title, value }) {
2801
+ if (value === void 0 || value.length === 0) return null;
2802
+ return /* @__PURE__ */ jsx(Section, {
2803
+ title,
2804
+ children: /* @__PURE__ */ jsx("pre", {
2805
+ className: "dsh-claude-tool-detail",
2806
+ children: value
2807
+ })
2808
+ });
2809
+ }
2810
+ function filenameList(value) {
2811
+ if (!Array.isArray(value)) return [];
2812
+ return value.filter((item) => typeof item === "string");
2813
+ }
2814
+ function ToolPresentation({ tool, t }) {
2815
+ const inputValue = parsedValue(tool.input);
2816
+ const outputValue = parsedValue(tool.output);
2817
+ const input = record$4(inputValue);
2818
+ const output = record$4(outputValue);
2819
+ const outputTitle = tool.isError === true ? t("toolError") : t("toolOutput");
2820
+ if (tool.diffs !== void 0) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(DiffBlock, { diffs: [...tool.diffs] }), /* @__PURE__ */ jsx(TextDetail, {
2821
+ title: outputTitle,
2822
+ value: typeof outputValue === "string" ? outputValue : void 0
2823
+ })] });
2824
+ if (tool.toolName === "Read") {
2825
+ const file = record$4(output?.file);
2826
+ const path = text(file?.filePath) ?? text(input?.file_path);
2827
+ const content = text(file?.content) ?? (typeof outputValue === "string" ? outputValue : void 0);
2828
+ const offset = numberValue(input?.offset) ?? 1;
2829
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
2830
+ path === void 0 ? null : /* @__PURE__ */ jsx(Section, {
2831
+ title: "File",
2832
+ children: /* @__PURE__ */ jsx("div", {
2833
+ className: "dsh-claude-tool-path",
2834
+ children: path
2835
+ })
2836
+ }),
2837
+ input === void 0 ? null : /* @__PURE__ */ jsx(Section, {
2838
+ title: t("toolInput"),
2839
+ children: /* @__PURE__ */ jsx(Fields, {
2840
+ value: input,
2841
+ omit: ["file_path"]
2842
+ })
2843
+ }),
2844
+ content === void 0 ? null : /* @__PURE__ */ jsx(Section, {
2845
+ title: outputTitle,
2846
+ children: /* @__PURE__ */ jsx(Source, {
2847
+ content,
2848
+ start: offset
2849
+ })
2850
+ })
2851
+ ] });
2852
+ }
2853
+ if (tool.toolName === "Grep" || tool.toolName === "Glob") {
2854
+ const filenames = filenameList(output?.filenames);
2855
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [input === void 0 ? /* @__PURE__ */ jsx(TextDetail, {
2856
+ title: t("toolInput"),
2857
+ value: typeof inputValue === "string" ? inputValue : void 0
2858
+ }) : /* @__PURE__ */ jsx(Section, {
2859
+ title: t("toolInput"),
2860
+ children: /* @__PURE__ */ jsx(Fields, { value: input })
2861
+ }), filenames.length === 0 ? /* @__PURE__ */ jsx(TextDetail, {
2862
+ title: outputTitle,
2863
+ value: typeof outputValue === "string" ? outputValue : output === void 0 ? void 0 : displayValue(output)
2864
+ }) : /* @__PURE__ */ jsx(Section, {
2865
+ title: outputTitle,
2866
+ children: /* @__PURE__ */ jsx(Paths, { paths: filenames })
2867
+ })] });
2868
+ }
2869
+ if (tool.toolName === "Bash" || tool.toolName === "PowerShell") {
2870
+ const command = text(input?.command);
2871
+ const terminal = [text(output?.stdout), text(output?.stderr)].filter((value) => value !== void 0).join("\n");
2872
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
2873
+ /* @__PURE__ */ jsx(TextDetail, {
2874
+ title: "Command",
2875
+ value: command ?? (typeof inputValue === "string" ? inputValue : void 0)
2876
+ }),
2877
+ input === void 0 ? null : /* @__PURE__ */ jsx(Section, {
2878
+ title: t("toolInput"),
2879
+ children: /* @__PURE__ */ jsx(Fields, {
2880
+ value: input,
2881
+ omit: ["command"]
2882
+ })
2883
+ }),
2884
+ /* @__PURE__ */ jsx(TextDetail, {
2885
+ title: outputTitle,
2886
+ value: terminal || (typeof outputValue === "string" ? outputValue : void 0)
2887
+ })
2888
+ ] });
2889
+ }
2890
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [input === void 0 ? /* @__PURE__ */ jsx(TextDetail, {
2891
+ title: t("toolInput"),
2892
+ value: typeof inputValue === "string" ? inputValue : void 0
2893
+ }) : /* @__PURE__ */ jsx(Section, {
2894
+ title: t("toolInput"),
2895
+ children: /* @__PURE__ */ jsx(Fields, { value: input })
2896
+ }), output === void 0 ? /* @__PURE__ */ jsx(TextDetail, {
2897
+ title: outputTitle,
2898
+ value: typeof outputValue === "string" ? outputValue : void 0
2899
+ }) : /* @__PURE__ */ jsx(Section, {
2900
+ title: outputTitle,
2901
+ children: /* @__PURE__ */ jsx(Fields, { value: output })
2902
+ })] });
2903
+ }
2904
+ function ClaudeTranscriptToolItem({ tool, t }) {
2905
+ return /* @__PURE__ */ jsxs("details", {
2906
+ className: "dsh-claude-tool-item",
2907
+ children: [/* @__PURE__ */ jsxs("summary", {
2908
+ className: "dsh-claude-tool-summary-row",
2909
+ children: [
2910
+ /* @__PURE__ */ jsx("span", {
2911
+ className: "dsh-claude-tool-label",
2912
+ children: tool.toolName
2913
+ }),
2914
+ /* @__PURE__ */ jsx("span", {
2915
+ className: "dsh-claude-tool-description",
2916
+ children: tool.description
2917
+ }),
2918
+ tool.additions === void 0 && tool.deletions === void 0 ? null : /* @__PURE__ */ jsxs("span", {
2919
+ className: "dsh-claude-tool-stats",
2920
+ children: [/* @__PURE__ */ jsxs("span", {
2921
+ className: "dsh-claude-diff-add",
2922
+ children: ["+", tool.additions ?? 0]
2923
+ }), /* @__PURE__ */ jsxs("span", {
2924
+ className: "dsh-claude-diff-delete",
2925
+ children: ["−", tool.deletions ?? 0]
2926
+ })]
2927
+ })
2928
+ ]
2929
+ }), /* @__PURE__ */ jsxs("div", {
2930
+ className: "dsh-claude-tool-content",
2931
+ children: [tool.subcalls.length === 0 ? null : /* @__PURE__ */ jsx("div", {
2932
+ className: "dsh-claude-flow-subcalls",
2933
+ children: tool.subcalls.map((subcall) => /* @__PURE__ */ jsxs("div", { children: [
2934
+ subcallGlyph(subcall),
2935
+ " ",
2936
+ subcall.toolName ?? t("subagent"),
2937
+ subcall.summary === void 0 ? "" : ` · ${subcall.summary}`
2938
+ ] }, subcall.toolUseId))
2939
+ }), /* @__PURE__ */ jsx(ToolPresentation, {
2940
+ tool,
2941
+ t
2942
+ })]
2943
+ })]
2944
+ });
2945
+ }
2946
+ function ClaudeTranscriptToolGroup({ tools, additions, deletions, files: _files, t }) {
2947
+ const [open, setOpen] = useState(false);
2948
+ const failed = tools.some((tool) => tool.isError === true || tool.phase === "failed");
2949
+ const running = tools.some((tool) => tool.phase === "started" || tool.phase === "updated");
2950
+ const summary = tools.length === 1 ? t("usedTool") : t("usedTools", { count: tools.length });
2951
+ return /* @__PURE__ */ jsxs("div", {
2952
+ className: "dsh-claude-tool-group-native",
2953
+ children: [/* @__PURE__ */ jsx(DisclosureRow, {
2954
+ rowClassName: "dsh-claude-flow-row",
2955
+ leadingClassName: "dsh-claude-flow-leading",
2956
+ titleClassName: "dsh-claude-flow-title",
2957
+ chevronClassName: "dsh-claude-flow-chevron",
2958
+ icon: failed ? /* @__PURE__ */ jsx(StateDot, { state: "error" }) : running ? /* @__PURE__ */ jsx(StateDot, { state: "ongoing" }) : /* @__PURE__ */ jsx(IconApiOutline14, { size: 14 }),
2959
+ title: summary,
2960
+ open,
2961
+ expandable: true,
2962
+ expandOnRowClick: true,
2963
+ keepContentWhenOpen: true,
2964
+ onToggle: () => setOpen((value) => !value),
2965
+ collapsedContent: additions !== void 0 || deletions !== void 0 ? /* @__PURE__ */ jsxs("span", {
2966
+ className: "dsh-claude-tool-stats",
2967
+ children: [/* @__PURE__ */ jsxs("span", {
2968
+ className: "dsh-claude-diff-add",
2969
+ children: ["+", additions ?? 0]
2970
+ }), /* @__PURE__ */ jsxs("span", {
2971
+ className: "dsh-claude-diff-delete",
2972
+ children: ["−", deletions ?? 0]
2973
+ })]
2974
+ }) : void 0
2975
+ }), open ? /* @__PURE__ */ jsx("div", {
2976
+ className: "dsh-claude-tool-list",
2977
+ children: tools.map((tool) => /* @__PURE__ */ jsx(ClaudeTranscriptToolItem, {
2978
+ tool,
2979
+ t
2980
+ }, tool.toolUseId))
2981
+ }) : null]
2982
+ });
2983
+ }
1825
2984
  function ClaudeActivityNode({ node, useClaudeProjection, t }) {
1826
2985
  ensureCss();
1827
2986
  const marker = node.data;
1828
2987
  const activities = useClaudeProjection((value) => value.activities);
1829
2988
  const tasks = useClaudeProjection((value) => value.tasks?.tasks ?? EMPTY_TASKS);
1830
- const rows = useMemo(() => activityRowsForStep(activities, marker.turn, marker.step, tasks), [
2989
+ const items = useMemo(() => transcriptItemsForStep(activities, marker.turn, marker.step, tasks), [
1831
2990
  activities,
1832
2991
  marker.step,
1833
2992
  marker.turn,
1834
2993
  tasks
1835
2994
  ]);
1836
- if (rows.length === 0) return null;
2995
+ if (items.length === 0) return null;
1837
2996
  return /* @__PURE__ */ jsx("div", {
1838
2997
  className: "dsh-claude-flow",
1839
- children: rows.map((row, index) => /* @__PURE__ */ jsx(ActivityRow, {
1840
- row,
2998
+ children: items.map((item) => item.kind === "text" ? /* @__PURE__ */ jsx("div", {
2999
+ className: "dsh-claude-transcript-text",
3000
+ children: /* @__PURE__ */ jsx(MarkdownText, { text: item.text })
3001
+ }, `text:${item.ordinal}`) : item.kind === "tools" ? /* @__PURE__ */ jsx(ClaudeTranscriptToolGroup, {
3002
+ tools: item.tools,
3003
+ ...item.additions === void 0 ? {} : { additions: item.additions },
3004
+ ...item.deletions === void 0 ? {} : { deletions: item.deletions },
3005
+ ...item.files === void 0 ? {} : { files: item.files },
1841
3006
  t
1842
- }, `${row.activity.ordinal}:${index}`))
3007
+ }, `tools:${item.ordinal}`) : /* @__PURE__ */ jsx(ActivityRow, {
3008
+ row: item.row,
3009
+ t
3010
+ }, `activity:${item.ordinal}`))
1843
3011
  });
1844
3012
  }
1845
3013
  //#endregion
@@ -2282,7 +3450,7 @@ window.__ModuleLoader__.load({
2282
3450
  style: diagnosticValue,
2283
3451
  children: t(`updateState_${updateStatus.state}`)
2284
3452
  }),
2285
- updateStatus.latestVersion === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
3453
+ updateStatus.latestVersion === void 0 ? null : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
2286
3454
  style: diagnosticLabel,
2287
3455
  children: t("latestVersion")
2288
3456
  }), /* @__PURE__ */ jsx("span", {
@@ -2348,6 +3516,16 @@ window.__ModuleLoader__.load({
2348
3516
  }
2349
3517
  //#endregion
2350
3518
  //#region src/client/ClaudeRepositoryStatus.tsx
3519
+ const RATE_LIMIT_TITLE_PREFIX = "Claude rate limit";
3520
+ const RATE_LIMIT_BLOCKING_TITLE = "Claude rate limit is blocking requests";
3521
+ /** Whether the newest quota update in the activity feed reports a blocked state. */
3522
+ function rateLimitBlocked(activities) {
3523
+ for (let index = activities.length - 1; index >= 0; index -= 1) {
3524
+ const title = activities[index]?.title;
3525
+ if (title?.startsWith(RATE_LIMIT_TITLE_PREFIX) === true) return title === RATE_LIMIT_BLOCKING_TITLE;
3526
+ }
3527
+ return false;
3528
+ }
2351
3529
  function StatusItem({ label, tone = "neutral" }) {
2352
3530
  const toneStyle = tone === "success" ? repositoryItemSuccess : tone === "warning" ? repositoryItemWarning : tone === "error" ? repositoryItemError : {};
2353
3531
  return /* @__PURE__ */ jsxs("span", {
@@ -2361,7 +3539,37 @@ window.__ModuleLoader__.load({
2361
3539
  }), label]
2362
3540
  });
2363
3541
  }
2364
- function PullRequestIcon({ size = 16 }) {
3542
+ function PullRequestIcon({ size = 16, merged = false }) {
3543
+ if (merged) return /* @__PURE__ */ jsxs("svg", {
3544
+ width: size,
3545
+ height: size,
3546
+ viewBox: "0 0 16 16",
3547
+ fill: "none",
3548
+ stroke: "currentColor",
3549
+ strokeWidth: "1.8",
3550
+ strokeLinecap: "round",
3551
+ strokeLinejoin: "round",
3552
+ "aria-hidden": "true",
3553
+ children: [
3554
+ /* @__PURE__ */ jsx("circle", {
3555
+ cx: "4",
3556
+ cy: "3",
3557
+ r: "1.6"
3558
+ }),
3559
+ /* @__PURE__ */ jsx("circle", {
3560
+ cx: "4",
3561
+ cy: "13",
3562
+ r: "1.6"
3563
+ }),
3564
+ /* @__PURE__ */ jsx("circle", {
3565
+ cx: "12",
3566
+ cy: "8",
3567
+ r: "1.6"
3568
+ }),
3569
+ /* @__PURE__ */ jsx("path", { d: "M4 4.6v6.8" }),
3570
+ /* @__PURE__ */ jsx("path", { d: "M5.6 3H7a5 5 0 0 1 5 3.4" })
3571
+ ]
3572
+ });
2365
3573
  return /* @__PURE__ */ jsxs("svg", {
2366
3574
  width: size,
2367
3575
  height: size,
@@ -2408,7 +3616,8 @@ window.__ModuleLoader__.load({
2408
3616
  function PullRequestHoverCard({ repository, t }) {
2409
3617
  const pullRequest = repository.pullRequest;
2410
3618
  if (pullRequest === void 0) return null;
2411
- const age = relativeAge(pullRequest.createdAt);
3619
+ const merged = pullRequest.state === "merged";
3620
+ const age = relativeAge(merged ? pullRequest.mergedAt : pullRequest.createdAt);
2412
3621
  return /* @__PURE__ */ jsxs("span", {
2413
3622
  role: "tooltip",
2414
3623
  style: repositoryPrHoverCard,
@@ -2417,8 +3626,14 @@ window.__ModuleLoader__.load({
2417
3626
  style: repositoryPrHoverTop,
2418
3627
  children: [
2419
3628
  /* @__PURE__ */ jsxs("span", {
2420
- style: repositoryPrStateBadge,
2421
- children: [/* @__PURE__ */ jsx(PullRequestIcon, { size: 13 }), t(`repositoryState_${pullRequest.state}`)]
3629
+ style: {
3630
+ ...repositoryPrStateBadge,
3631
+ ...merged ? repositoryPrStateBadgeMerged : {}
3632
+ },
3633
+ children: [/* @__PURE__ */ jsx(PullRequestIcon, {
3634
+ size: 13,
3635
+ merged
3636
+ }), t(`repositoryState_${pullRequest.state}`)]
2422
3637
  }),
2423
3638
  /* @__PURE__ */ jsxs("span", {
2424
3639
  style: repositoryPrHoverRepo,
@@ -2509,7 +3724,10 @@ window.__ModuleLoader__.load({
2509
3724
  href: pullRequest.url,
2510
3725
  target: "_blank",
2511
3726
  rel: "noopener noreferrer",
2512
- style: repositoryPrLink,
3727
+ style: {
3728
+ ...repositoryPrLink,
3729
+ ...pullRequest.state === "merged" ? repositoryPrLinkMerged : {}
3730
+ },
2513
3731
  "aria-label": t("repositoryOpenPr", { number: pullRequest.number }),
2514
3732
  children: ["#", pullRequest.number]
2515
3733
  })]
@@ -2522,27 +3740,46 @@ window.__ModuleLoader__.load({
2522
3740
  if (blank || !projection.owned || repository === void 0) return null;
2523
3741
  const branch = repository.detached === true ? t("repositoryDetached") : repository.branch ?? t("repositoryUnknownBranch");
2524
3742
  const pullRequest = repository.pullRequest;
3743
+ const merged = pullRequest?.state === "merged";
3744
+ const mergedAge = merged ? relativeAge(pullRequest.mergedAt) : void 0;
3745
+ const aheadCount = repository.ahead ?? 0;
3746
+ const pushable = repository.remote !== void 0 && repository.detached !== true && (aheadCount > 0 || repository.upstream === false);
3747
+ const hasDiff = repository.diff !== void 0 && (repository.diff.additions > 0 || repository.diff.deletions > 0);
3748
+ const rateLimited = rateLimitBlocked(projection.activities);
2525
3749
  if (repository.status !== "ready") return /* @__PURE__ */ jsx("div", {
2526
3750
  style: repositoryBarFrame,
2527
3751
  children: /* @__PURE__ */ jsxs("div", {
2528
3752
  style: repositoryBar,
2529
- children: [/* @__PURE__ */ jsx("span", {
2530
- style: repositoryPrIcon,
2531
- children: /* @__PURE__ */ jsx(PullRequestIcon, {})
2532
- }), /* @__PURE__ */ jsx("span", {
2533
- style: repositoryPrimary,
2534
- children: repository.status === "not-repository" ? t("repositoryNotGit") : t("repositoryUnavailable")
2535
- })]
3753
+ children: [
3754
+ /* @__PURE__ */ jsx("span", {
3755
+ style: repositoryPrIcon,
3756
+ children: /* @__PURE__ */ jsx(PullRequestIcon, {})
3757
+ }),
3758
+ /* @__PURE__ */ jsx("span", {
3759
+ style: repositoryPrimary,
3760
+ children: repository.status === "not-repository" ? t("repositoryNotGit") : t("repositoryUnavailable")
3761
+ }),
3762
+ rateLimited ? /* @__PURE__ */ jsx(StatusItem, {
3763
+ label: t("repositoryRateLimited"),
3764
+ tone: "warning"
3765
+ }) : null
3766
+ ]
2536
3767
  })
2537
3768
  });
2538
3769
  return /* @__PURE__ */ jsx("div", {
2539
3770
  style: repositoryBarFrame,
2540
3771
  children: /* @__PURE__ */ jsxs("div", {
2541
- style: repositoryBar,
3772
+ style: {
3773
+ ...repositoryBar,
3774
+ ...merged ? repositoryBarMerged : {}
3775
+ },
2542
3776
  children: [
2543
3777
  /* @__PURE__ */ jsx("span", {
2544
- style: repositoryPrIcon,
2545
- children: /* @__PURE__ */ jsx(PullRequestIcon, {})
3778
+ style: {
3779
+ ...repositoryPrIcon,
3780
+ ...merged ? repositoryPrIconMerged : {}
3781
+ },
3782
+ children: /* @__PURE__ */ jsx(PullRequestIcon, { merged })
2546
3783
  }),
2547
3784
  /* @__PURE__ */ jsx(PullRequestLink, {
2548
3785
  repository,
@@ -2553,40 +3790,320 @@ window.__ModuleLoader__.load({
2553
3790
  children: repositoryName(repository.remote)
2554
3791
  }),
2555
3792
  /* @__PURE__ */ jsx("span", {
2556
- style: repositoryBranch,
2557
- children: branch
3793
+ style: repositoryBranch,
3794
+ children: branch
3795
+ }),
3796
+ repository.worktree === true ? /* @__PURE__ */ jsx("span", {
3797
+ style: repositoryWorktree,
3798
+ children: t("repositoryWorktree")
3799
+ }) : null,
3800
+ /* @__PURE__ */ jsxs("span", {
3801
+ style: repositoryStatusItems,
3802
+ children: [
3803
+ rateLimited ? /* @__PURE__ */ jsx(StatusItem, {
3804
+ label: t("repositoryRateLimited"),
3805
+ tone: "warning"
3806
+ }) : null,
3807
+ hasDiff || pushable ? /* @__PURE__ */ jsxs("button", {
3808
+ type: "button",
3809
+ style: {
3810
+ ...diffTrigger,
3811
+ ...merged ? diffTriggerMuted : {}
3812
+ },
3813
+ onClick: openDiff,
3814
+ "aria-label": t("diffOpen"),
3815
+ children: [hasDiff && repository.diff !== void 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
3816
+ style: merged ? diffAddMuted : diffAdd,
3817
+ children: ["+", repository.diff.additions]
3818
+ }), /* @__PURE__ */ jsxs("span", {
3819
+ style: merged ? diffDeleteMuted : diffDelete,
3820
+ children: ["−", repository.diff.deletions]
3821
+ })] }) : null, pushable ? /* @__PURE__ */ jsxs("span", {
3822
+ style: merged ? diffAheadMuted : diffAhead,
3823
+ children: ["↑", aheadCount > 0 ? aheadCount : ""]
3824
+ }) : null]
3825
+ }) : null,
3826
+ pullRequest === void 0 ? null : merged ? /* @__PURE__ */ jsxs("span", {
3827
+ style: repositoryMergedStatus,
3828
+ children: [
3829
+ /* @__PURE__ */ jsx("span", {
3830
+ style: repositoryMergedDot,
3831
+ "aria-hidden": "true"
3832
+ }),
3833
+ t("repositoryMergedInto", { branch: pullRequest.baseBranch ?? t("repositoryUnknownBranch") }),
3834
+ mergedAge === void 0 ? null : /* @__PURE__ */ jsxs("span", {
3835
+ style: repositoryMergedAge,
3836
+ children: ["· ", t("repositoryMergedAgo", { age: mergedAge })]
3837
+ })
3838
+ ]
3839
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(StatusItem, {
3840
+ label: t(`repositoryChecks_${pullRequest.checks}`),
3841
+ tone: pullRequest.checks === "passing" ? "success" : pullRequest.checks === "failing" ? "error" : pullRequest.checks === "pending" ? "warning" : "neutral"
3842
+ }), /* @__PURE__ */ jsx(StatusItem, {
3843
+ label: t(`repositoryReview_${pullRequest.review}`),
3844
+ tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral"
3845
+ })] })
3846
+ ]
3847
+ })
3848
+ ]
3849
+ })
3850
+ });
3851
+ }
3852
+ //#endregion
3853
+ //#region src/client/review-comment-api.ts
3854
+ function record$3(value) {
3855
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3856
+ }
3857
+ async function post(path, sessionId, body) {
3858
+ const response = await fetch(`${CLAUDE_REVIEW_COMMENT_PATH}${path}?sessionId=${encodeURIComponent(sessionId)}`, {
3859
+ method: "POST",
3860
+ credentials: "same-origin",
3861
+ headers: {
3862
+ accept: "application/json",
3863
+ "content-type": "application/json"
3864
+ },
3865
+ body: JSON.stringify(body)
3866
+ });
3867
+ const value = await response.json();
3868
+ if (!response.ok) {
3869
+ const error = record$3(value);
3870
+ throw new Error(typeof error?.message === "string" ? error.message : "Review comment request failed.");
3871
+ }
3872
+ return value;
3873
+ }
3874
+ async function addReviewComment(sessionId, comment) {
3875
+ const created = record$3(record$3(await post("", sessionId, comment))?.comment);
3876
+ if (created === void 0 || typeof created.id !== "string") throw new Error("Invalid review comment response.");
3877
+ return created;
3878
+ }
3879
+ async function removeReviewComment(sessionId, id) {
3880
+ await post("/remove", sessionId, { id });
3881
+ }
3882
+ async function clearReviewComments(sessionId) {
3883
+ await post("/clear", sessionId, {});
3884
+ }
3885
+ //#endregion
3886
+ //#region src/client/ClaudeReviewComments.tsx
3887
+ function reviewCommentChipLabel(comment) {
3888
+ return `${comment.path.split("/").at(-1) ?? comment.path}:${comment.line}`;
3889
+ }
3890
+ function CommentIcon() {
3891
+ return /* @__PURE__ */ jsx("svg", {
3892
+ width: "16",
3893
+ height: "16",
3894
+ viewBox: "0 0 16 16",
3895
+ fill: "none",
3896
+ stroke: "currentColor",
3897
+ strokeWidth: "1.5",
3898
+ strokeLinecap: "round",
3899
+ strokeLinejoin: "round",
3900
+ "aria-hidden": "true",
3901
+ children: /* @__PURE__ */ jsx("path", { d: "M2.75 2.75h10.5a1 1 0 0 1 1 1v6.5a1 1 0 0 1-1 1H8.2l-3.2 2.9v-2.9H2.75a1 1 0 0 1-1-1v-6.5a1 1 0 0 1 1-1Z" })
3902
+ });
3903
+ }
3904
+ function SendIcon() {
3905
+ return /* @__PURE__ */ jsx("svg", {
3906
+ width: "14",
3907
+ height: "14",
3908
+ viewBox: "0 0 16 16",
3909
+ fill: "none",
3910
+ stroke: "currentColor",
3911
+ strokeWidth: "1.5",
3912
+ strokeLinecap: "round",
3913
+ strokeLinejoin: "round",
3914
+ "aria-hidden": "true",
3915
+ children: /* @__PURE__ */ jsx("path", { d: "M14 2 7.3 8.7M14 2 9.7 14l-2.4-5.3L2 6.3 14 2Z" })
3916
+ });
3917
+ }
3918
+ function TrashIcon() {
3919
+ return /* @__PURE__ */ jsx("svg", {
3920
+ width: "14",
3921
+ height: "14",
3922
+ viewBox: "0 0 16 16",
3923
+ fill: "none",
3924
+ stroke: "currentColor",
3925
+ strokeWidth: "1.5",
3926
+ strokeLinecap: "round",
3927
+ strokeLinejoin: "round",
3928
+ "aria-hidden": "true",
3929
+ children: /* @__PURE__ */ jsx("path", { d: "M2.5 4h11M6.3 2.5h3.4M4.2 4l.65 9.3a1 1 0 0 0 1 .93h4.3a1 1 0 0 0 1-.93L11.8 4M6.7 6.8v4.6M9.3 6.8v4.6" })
3930
+ });
3931
+ }
3932
+ function CommentChip({ comment, t, onRemove }) {
3933
+ return /* @__PURE__ */ jsx(HoverCard, {
3934
+ anchor: /* @__PURE__ */ jsxs("span", {
3935
+ style: reviewCommentChip,
3936
+ children: [/* @__PURE__ */ jsx("span", {
3937
+ style: reviewCommentChipLabel$1,
3938
+ children: reviewCommentChipLabel(comment)
3939
+ }), /* @__PURE__ */ jsx("button", {
3940
+ type: "button",
3941
+ style: reviewCommentChipRemove,
3942
+ "aria-label": t("reviewCommentRemove"),
3943
+ onClick: () => onRemove(comment.id),
3944
+ children: "×"
3945
+ })]
3946
+ }),
3947
+ content: /* @__PURE__ */ jsxs("span", {
3948
+ style: reviewCommentHoverCard,
3949
+ children: [/* @__PURE__ */ jsxs("span", {
3950
+ style: reviewCommentHoverPath,
3951
+ children: [
3952
+ comment.path,
3953
+ " · ",
3954
+ comment.side === "old" ? t("reviewCommentOldSide", { line: comment.line }) : t("reviewCommentNewSide", { line: comment.line })
3955
+ ]
3956
+ }), /* @__PURE__ */ jsx("p", {
3957
+ style: reviewCommentHoverText,
3958
+ children: comment.text
3959
+ })]
3960
+ }),
3961
+ openDelayMs: 250
3962
+ });
3963
+ }
3964
+ /** Pending review comments docked above the composer; drained by the next user turn. */
3965
+ function ClaudeReviewComments({ useClaudeProjection, t, sessionId, submitWith }) {
3966
+ const projection = useClaudeProjection((value) => value);
3967
+ const [removedIds, setRemovedIds] = useState(() => /* @__PURE__ */ new Set());
3968
+ const comments = (projection.reviewComments ?? []).filter((comment) => !removedIds.has(comment.id));
3969
+ if (!projection.owned || comments.length === 0) return null;
3970
+ const remove = (id) => {
3971
+ setRemovedIds((previous) => /* @__PURE__ */ new Set([...previous, id]));
3972
+ removeReviewComment(sessionId, id).catch(() => {
3973
+ setRemovedIds((previous) => {
3974
+ const next = new Set(previous);
3975
+ next.delete(id);
3976
+ return next;
3977
+ });
3978
+ });
3979
+ };
3980
+ const clearAll = () => {
3981
+ const ids = comments.map((comment) => comment.id);
3982
+ setRemovedIds((previous) => /* @__PURE__ */ new Set([...previous, ...ids]));
3983
+ clearReviewComments(sessionId).catch(() => {
3984
+ setRemovedIds((previous) => {
3985
+ const next = new Set(previous);
3986
+ for (const id of ids) next.delete(id);
3987
+ return next;
3988
+ });
3989
+ });
3990
+ };
3991
+ return /* @__PURE__ */ jsxs("div", {
3992
+ style: reviewCommentBarFrame,
3993
+ children: [/* @__PURE__ */ jsx("style", {
3994
+ "data-dsh-claude-review-comment-styles": true,
3995
+ children: panelIconButtonCss
3996
+ }), /* @__PURE__ */ jsxs("div", {
3997
+ style: reviewCommentBar,
3998
+ children: [
3999
+ /* @__PURE__ */ jsx("span", {
4000
+ style: reviewCommentIcon,
4001
+ children: /* @__PURE__ */ jsx(CommentIcon, {})
2558
4002
  }),
2559
- repository.worktree === true ? /* @__PURE__ */ jsx("span", {
2560
- style: repositoryWorktree,
2561
- children: t("repositoryWorktree")
2562
- }) : null,
4003
+ comments.map((comment) => /* @__PURE__ */ jsx(CommentChip, {
4004
+ comment,
4005
+ t,
4006
+ onRemove: remove
4007
+ }, comment.id)),
2563
4008
  /* @__PURE__ */ jsxs("span", {
2564
- style: repositoryStatusItems,
2565
- children: [repository.diff !== void 0 && (repository.diff.additions > 0 || repository.diff.deletions > 0) ? /* @__PURE__ */ jsxs("button", {
4009
+ style: reviewCommentClearSeat,
4010
+ children: [submitWith === void 0 ? null : /* @__PURE__ */ jsx("button", {
2566
4011
  type: "button",
2567
- style: diffTrigger,
2568
- onClick: openDiff,
2569
- "aria-label": t("diffOpen"),
2570
- children: [/* @__PURE__ */ jsxs("span", {
2571
- style: diffAdd,
2572
- children: ["+", repository.diff.additions]
2573
- }), /* @__PURE__ */ jsxs("span", {
2574
- style: diffDelete,
2575
- children: ["−", repository.diff.deletions]
2576
- })]
2577
- }) : null, pullRequest === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(StatusItem, {
2578
- label: t(`repositoryChecks_${pullRequest.checks}`),
2579
- tone: pullRequest.checks === "passing" ? "success" : pullRequest.checks === "failing" ? "error" : pullRequest.checks === "pending" ? "warning" : "neutral"
2580
- }), /* @__PURE__ */ jsx(StatusItem, {
2581
- label: t(`repositoryReview_${pullRequest.review}`),
2582
- tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral"
2583
- })] })]
4012
+ className: panelIconButtonClass,
4013
+ "aria-label": t("reviewCommentsSend"),
4014
+ onClick: () => submitWith(t("reviewCommentsSendDraft")),
4015
+ children: /* @__PURE__ */ jsx(SendIcon, {})
4016
+ }), /* @__PURE__ */ jsx("button", {
4017
+ type: "button",
4018
+ className: panelIconButtonClass,
4019
+ "aria-label": t("reviewCommentsClear"),
4020
+ onClick: clearAll,
4021
+ children: /* @__PURE__ */ jsx(TrashIcon, {})
4022
+ })]
2584
4023
  })
2585
4024
  ]
2586
- })
4025
+ })]
2587
4026
  });
2588
4027
  }
2589
4028
  //#endregion
4029
+ //#region src/client/repository-action-api.ts
4030
+ var RepositoryActionClientError = class extends Error {
4031
+ code;
4032
+ commit;
4033
+ constructor(message, code, commit) {
4034
+ super(message);
4035
+ this.name = "RepositoryActionClientError";
4036
+ if (code !== void 0) this.code = code;
4037
+ if (commit !== void 0) this.commit = commit;
4038
+ }
4039
+ };
4040
+ function record$2(value) {
4041
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
4042
+ }
4043
+ async function response$1(pending) {
4044
+ const result = await pending;
4045
+ const body = await result.json();
4046
+ if (!result.ok) {
4047
+ const error = record$2(body);
4048
+ throw new RepositoryActionClientError(typeof error?.message === "string" ? error.message : "Repository action failed.", typeof error?.error === "string" ? error.error : void 0, typeof error?.commit === "string" ? error.commit : void 0);
4049
+ }
4050
+ return body;
4051
+ }
4052
+ function preview(value) {
4053
+ const input = record$2(value);
4054
+ if (input === void 0 || typeof input.root !== "string" || typeof input.branch !== "string" || typeof input.head !== "string" || typeof input.fingerprint !== "string" || !Array.isArray(input.files) || typeof input.patch !== "string" || typeof input.truncated !== "boolean" || typeof input.hasStaged !== "boolean" || typeof input.hasUnstaged !== "boolean" || typeof input.hasUntracked !== "boolean" || input.upstream !== void 0 && typeof input.upstream !== "string" || !Array.isArray(input.unpushedCommits) || typeof input.unpushedTruncated !== "boolean") throw new Error("Invalid repository action preview.");
4055
+ for (const file of input.files) {
4056
+ const item = record$2(file);
4057
+ if (item === void 0 || typeof item.path !== "string" || typeof item.staged !== "boolean" || typeof item.unstaged !== "boolean" || typeof item.untracked !== "boolean") throw new Error("Invalid repository action file.");
4058
+ }
4059
+ for (const commit of input.unpushedCommits) {
4060
+ const item = record$2(commit);
4061
+ if (item === void 0 || typeof item.hash !== "string" || typeof item.subject !== "string") throw new Error("Invalid repository action commit.");
4062
+ }
4063
+ return input;
4064
+ }
4065
+ function result(value) {
4066
+ const input = record$2(value);
4067
+ if (input === void 0 || typeof input.commit !== "string" || typeof input.pushed !== "boolean" || input.pullRequestUrl !== void 0 && typeof input.pullRequestUrl !== "string") throw new Error("Invalid repository action result.");
4068
+ return input;
4069
+ }
4070
+ function endpoint(path, sessionId) {
4071
+ return `${CLAUDE_REPOSITORY_ACTION_PATH}${path}?sessionId=${encodeURIComponent(sessionId)}`;
4072
+ }
4073
+ async function loadRepositoryActionPreview(sessionId, signal) {
4074
+ return preview(await response$1(fetch(endpoint("/preview", sessionId), {
4075
+ method: "GET",
4076
+ credentials: "same-origin",
4077
+ headers: { accept: "application/json" },
4078
+ ...signal === void 0 ? {} : { signal }
4079
+ })));
4080
+ }
4081
+ async function generateCommitMessage(sessionId, fingerprint, signal) {
4082
+ const value = record$2(await response$1(fetch(endpoint("/message", sessionId), {
4083
+ method: "POST",
4084
+ credentials: "same-origin",
4085
+ headers: {
4086
+ accept: "application/json",
4087
+ "content-type": "application/json"
4088
+ },
4089
+ body: JSON.stringify({ fingerprint }),
4090
+ ...signal === void 0 ? {} : { signal }
4091
+ })));
4092
+ if (typeof value?.message !== "string") throw new Error("Invalid generated commit message.");
4093
+ return value.message;
4094
+ }
4095
+ function executeRepositoryAction(sessionId, request) {
4096
+ return response$1(fetch(endpoint("", sessionId), {
4097
+ method: "POST",
4098
+ credentials: "same-origin",
4099
+ headers: {
4100
+ accept: "application/json",
4101
+ "content-type": "application/json"
4102
+ },
4103
+ body: JSON.stringify(request)
4104
+ })).then(result);
4105
+ }
4106
+ //#endregion
2590
4107
  //#region src/client/ClaudeDiffPanel.tsx
2591
4108
  function pathFromHeader(line) {
2592
4109
  return /^diff --git a\/(.+) b\/(.+)$/u.exec(line)?.[2];
@@ -2665,15 +4182,35 @@ window.__ModuleLoader__.load({
2665
4182
  }
2666
4183
  return numbered;
2667
4184
  }
2668
- function DiffLine({ entry }) {
4185
+ /** Which working-tree line a comment on this rendered diff row refers to. */
4186
+ function commentAnchorForLine(entry) {
4187
+ if (entry.kind === "add" || entry.kind === "context") return entry.newLine === void 0 ? void 0 : {
4188
+ line: entry.newLine,
4189
+ side: "new"
4190
+ };
4191
+ if (entry.kind === "delete") return entry.oldLine === void 0 ? void 0 : {
4192
+ line: entry.oldLine,
4193
+ side: "old"
4194
+ };
4195
+ }
4196
+ function DiffLine({ entry, addLabel, onComment }) {
2669
4197
  const style = entry.kind === "add" ? diffLineAdd : entry.kind === "delete" ? diffLineDelete : entry.kind === "hunk" || entry.kind === "collapsed" ? diffLineHunk : diffLineContext;
2670
4198
  const lineNumber = entry.oldLine === void 0 && entry.newLine === void 0 ? "" : entry.oldLine === void 0 ? String(entry.newLine) : entry.newLine === void 0 ? String(entry.oldLine) : String(entry.newLine);
2671
4199
  return /* @__PURE__ */ jsxs("div", {
4200
+ className: diffLineRowClass,
2672
4201
  style: {
2673
4202
  ...diffLine,
2674
4203
  ...style
2675
4204
  },
2676
4205
  children: [
4206
+ /* @__PURE__ */ jsx("button", {
4207
+ type: "button",
4208
+ className: diffCommentButtonClass,
4209
+ disabled: onComment === void 0,
4210
+ "aria-label": addLabel,
4211
+ onClick: onComment,
4212
+ children: "+"
4213
+ }),
2677
4214
  /* @__PURE__ */ jsx("span", {
2678
4215
  style: diffLineNumber,
2679
4216
  children: lineNumber
@@ -2686,7 +4223,7 @@ window.__ModuleLoader__.load({
2686
4223
  ]
2687
4224
  });
2688
4225
  }
2689
- function DiffFileSection({ file, initiallyOpen }) {
4226
+ function DiffFileSection({ file, initiallyOpen, t, comments, editorAnchor, editorNode, onOpenEditor, onRemoveComment }) {
2690
4227
  const [open, setOpen] = useState(initiallyOpen);
2691
4228
  return /* @__PURE__ */ jsxs("section", {
2692
4229
  style: diffFile,
@@ -2720,15 +4257,278 @@ window.__ModuleLoader__.load({
2720
4257
  ]
2721
4258
  }), open ? /* @__PURE__ */ jsx("div", {
2722
4259
  style: diffCode,
2723
- children: numberDiffLines(file.lines).map((entry, index) => /* @__PURE__ */ jsx(DiffLine, { entry }, `${index}:${entry.line}`))
4260
+ children: numberDiffLines(file.lines).map((entry, index) => {
4261
+ const anchor = commentAnchorForLine(entry);
4262
+ const lineComments = anchor === void 0 ? [] : comments.filter((comment) => comment.line === anchor.line && comment.side === anchor.side);
4263
+ const editorOpen = anchor !== void 0 && editorAnchor !== void 0 && editorAnchor.line === anchor.line && editorAnchor.side === anchor.side;
4264
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
4265
+ /* @__PURE__ */ jsx(DiffLine, {
4266
+ entry,
4267
+ addLabel: t("reviewCommentAdd"),
4268
+ onComment: anchor === void 0 ? void 0 : () => onOpenEditor(anchor)
4269
+ }),
4270
+ lineComments.map((comment) => /* @__PURE__ */ jsxs("div", {
4271
+ style: diffCommentBlock,
4272
+ children: [/* @__PURE__ */ jsxs("div", {
4273
+ style: diffCommentCardMeta,
4274
+ children: [/* @__PURE__ */ jsx("span", { children: comment.side === "old" ? t("reviewCommentOldSide", { line: comment.line }) : t("reviewCommentNewSide", { line: comment.line }) }), /* @__PURE__ */ jsx("button", {
4275
+ type: "button",
4276
+ style: reviewCommentChipRemove,
4277
+ "aria-label": t("reviewCommentRemove"),
4278
+ onClick: () => onRemoveComment(comment.id),
4279
+ children: "×"
4280
+ })]
4281
+ }), /* @__PURE__ */ jsx("p", {
4282
+ style: diffCommentCardText,
4283
+ children: comment.text
4284
+ })]
4285
+ }, comment.id)),
4286
+ editorOpen ? editorNode : null
4287
+ ] }, `${index}:${entry.line}`);
4288
+ })
2724
4289
  }) : null]
2725
4290
  });
2726
4291
  }
2727
- function ClaudeDiffPanel({ useClaudeProjection, t, closeDetails }) {
4292
+ function actionLabel(action, t) {
4293
+ return (action === "commit" ? t("diffCommit") : action === "commit-push" ? t("diffCommitPush") : action === "push" ? t("diffPush") : t("diffCreatePr")).replace(/[….]+$/u, "");
4294
+ }
4295
+ function repositoryActionAvailability(repository) {
4296
+ const ready = repository?.status === "ready" && repository.detached !== true;
4297
+ const committable = ready && repository.dirty === true;
4298
+ const hasRemote = repository?.remote !== void 0;
4299
+ const hasOpenPullRequest = repository?.pullRequest?.state === "open";
4300
+ const pushable = ready && hasRemote && (repository.upstream === false || (repository.ahead ?? 0) > 0);
4301
+ return {
4302
+ "commit": committable,
4303
+ "commit-push": committable && hasRemote,
4304
+ "push": pushable,
4305
+ "create-pr": (committable || pushable) && hasRemote && !hasOpenPullRequest
4306
+ };
4307
+ }
4308
+ function RestorePanelIcon() {
4309
+ return /* @__PURE__ */ jsx("svg", {
4310
+ width: "16",
4311
+ height: "16",
4312
+ viewBox: "0 0 16 16",
4313
+ fill: "currentColor",
4314
+ "aria-hidden": "true",
4315
+ children: /* @__PURE__ */ jsx("path", { d: "M1.5 5h3V2h1.4v4.4H1.5V5Zm9.9-3h1.4v3h3v1.4h-4.4V2ZM1.5 9.6h4.4V14H4.5v-3h-3V9.6Zm9.9 0h4.4V11h-3v3h-1.4V9.6Z" })
4316
+ });
4317
+ }
4318
+ function ClaudeDiffPanel({ useClaudeProjection, t, sessionId, maximized, closeDetails, toggleMaximized }) {
2728
4319
  const projection = useClaudeProjection((value) => value);
2729
4320
  const repository = projection.repository;
2730
4321
  const diff = repository?.diff;
2731
4322
  const files = useMemo(() => parseUnifiedDiff(diff?.patch ?? ""), [diff?.patch]);
4323
+ const [menuOpen, setMenuOpen] = useState(false);
4324
+ const [dialog, setDialog] = useState();
4325
+ const [message, setMessage] = useState("");
4326
+ const [includeUnstaged, setIncludeUnstaged] = useState(true);
4327
+ const [prTitle, setPrTitle] = useState("");
4328
+ const [prBody, setPrBody] = useState("");
4329
+ const [baseBranch, setBaseBranch] = useState("");
4330
+ const [draft, setDraft] = useState(true);
4331
+ const [commentEditor, setCommentEditor] = useState();
4332
+ const [commentDraft, setCommentDraft] = useState("");
4333
+ const [commentBusy, setCommentBusy] = useState(false);
4334
+ const [commentError, setCommentError] = useState();
4335
+ const [localComments, setLocalComments] = useState([]);
4336
+ const [removedCommentIds, setRemovedCommentIds] = useState(() => /* @__PURE__ */ new Set());
4337
+ const actionController = useRef();
4338
+ const diffViewportObserver = useRef();
4339
+ const diffBodyRef = useCallback((element) => {
4340
+ diffViewportObserver.current?.disconnect();
4341
+ diffViewportObserver.current = void 0;
4342
+ if (element === null || typeof ResizeObserver === "undefined") return;
4343
+ const update = () => element.style.setProperty("--dsh-claude-diff-viewport", `${element.clientWidth}px`);
4344
+ update();
4345
+ const observer = new ResizeObserver(update);
4346
+ observer.observe(element);
4347
+ diffViewportObserver.current = observer;
4348
+ }, []);
4349
+ useEffect(() => () => diffViewportObserver.current?.disconnect(), []);
4350
+ const closeDialog = useCallback(() => {
4351
+ if (dialog?.submitting === true) return;
4352
+ actionController.current?.abort();
4353
+ actionController.current = void 0;
4354
+ setDialog(void 0);
4355
+ }, [dialog?.submitting]);
4356
+ useEffect(() => {
4357
+ if (dialog?.commit === void 0 || dialog.error !== void 0 || dialog.pullRequestUrl !== void 0) return;
4358
+ const timer = setTimeout(closeDialog, 1200);
4359
+ return () => clearTimeout(timer);
4360
+ }, [
4361
+ closeDialog,
4362
+ dialog?.commit,
4363
+ dialog?.error,
4364
+ dialog?.pullRequestUrl
4365
+ ]);
4366
+ const openAction = useCallback((action) => {
4367
+ actionController.current?.abort();
4368
+ setMenuOpen(false);
4369
+ setDialog({
4370
+ action,
4371
+ loading: true,
4372
+ submitting: false
4373
+ });
4374
+ setMessage("");
4375
+ setPrTitle("");
4376
+ setPrBody("");
4377
+ setBaseBranch("");
4378
+ setDraft(true);
4379
+ const controller = new AbortController();
4380
+ actionController.current = controller;
4381
+ loadRepositoryActionPreview(sessionId, controller.signal).then(async (preview) => {
4382
+ setIncludeUnstaged(preview.hasUnstaged || preview.hasUntracked);
4383
+ if (action === "push") {
4384
+ setDialog({
4385
+ action,
4386
+ preview,
4387
+ loading: false,
4388
+ submitting: false
4389
+ });
4390
+ return;
4391
+ }
4392
+ setDialog({
4393
+ action,
4394
+ preview,
4395
+ loading: true,
4396
+ submitting: false
4397
+ });
4398
+ const generated = await generateCommitMessage(sessionId, preview.fingerprint, controller.signal);
4399
+ setMessage(generated);
4400
+ setPrTitle(generated);
4401
+ setPrBody(`Summary: ${generated}\n\nChanges:\n- ${generated}`);
4402
+ setDialog({
4403
+ action,
4404
+ preview,
4405
+ loading: false,
4406
+ submitting: false
4407
+ });
4408
+ }).catch((error) => {
4409
+ if (!controller.signal.aborted) setDialog({
4410
+ action,
4411
+ loading: false,
4412
+ submitting: false,
4413
+ error: error instanceof Error ? error.message : t("diffActionFailed")
4414
+ });
4415
+ });
4416
+ }, [sessionId, t]);
4417
+ const confirm = useCallback(async () => {
4418
+ if (dialog?.preview === void 0 || dialog.action !== "push" && message.trim().length === 0) return;
4419
+ const { error: _error, ...pending } = dialog;
4420
+ setDialog({
4421
+ ...pending,
4422
+ submitting: true
4423
+ });
4424
+ try {
4425
+ const result = await executeRepositoryAction(sessionId, {
4426
+ action: dialog.action,
4427
+ fingerprint: dialog.preview.fingerprint,
4428
+ message,
4429
+ includeUnstaged,
4430
+ ...dialog.action === "create-pr" ? {
4431
+ prTitle,
4432
+ prBody,
4433
+ ...baseBranch.trim() === "" ? {} : { baseBranch },
4434
+ draft
4435
+ } : {}
4436
+ });
4437
+ setDialog({
4438
+ ...dialog,
4439
+ submitting: false,
4440
+ commit: result.commit,
4441
+ ...result.pullRequestUrl === void 0 ? {} : { pullRequestUrl: result.pullRequestUrl }
4442
+ });
4443
+ } catch (error) {
4444
+ const completedCommit = typeof error === "object" && error !== null && "commit" in error && typeof error.commit === "string" ? error.commit : void 0;
4445
+ setDialog({
4446
+ ...dialog,
4447
+ submitting: false,
4448
+ error: error instanceof Error ? error.message : t("diffActionFailed"),
4449
+ ...completedCommit === void 0 ? {} : { commit: completedCommit }
4450
+ });
4451
+ }
4452
+ }, [
4453
+ baseBranch,
4454
+ dialog,
4455
+ draft,
4456
+ includeUnstaged,
4457
+ message,
4458
+ prBody,
4459
+ prTitle,
4460
+ sessionId,
4461
+ t
4462
+ ]);
4463
+ const openCommentEditor = useCallback((path, anchor) => {
4464
+ setCommentEditor({
4465
+ path,
4466
+ ...anchor
4467
+ });
4468
+ setCommentDraft("");
4469
+ setCommentError(void 0);
4470
+ }, []);
4471
+ const closeCommentEditor = useCallback(() => {
4472
+ setCommentEditor(void 0);
4473
+ setCommentDraft("");
4474
+ setCommentError(void 0);
4475
+ }, []);
4476
+ const submitComment = useCallback(async () => {
4477
+ if (commentEditor === void 0 || commentDraft.trim().length === 0 || commentBusy) return;
4478
+ setCommentBusy(true);
4479
+ setCommentError(void 0);
4480
+ try {
4481
+ const created = await addReviewComment(sessionId, {
4482
+ path: commentEditor.path,
4483
+ line: commentEditor.line,
4484
+ side: commentEditor.side,
4485
+ text: commentDraft.trim()
4486
+ });
4487
+ setLocalComments((list) => [...list, created]);
4488
+ closeCommentEditor();
4489
+ } catch (error) {
4490
+ setCommentError(error instanceof Error ? error.message : t("reviewCommentFailed"));
4491
+ } finally {
4492
+ setCommentBusy(false);
4493
+ }
4494
+ }, [
4495
+ closeCommentEditor,
4496
+ commentBusy,
4497
+ commentDraft,
4498
+ commentEditor,
4499
+ sessionId,
4500
+ t
4501
+ ]);
4502
+ const removeComment = useCallback((id) => {
4503
+ setRemovedCommentIds((previous) => /* @__PURE__ */ new Set([...previous, id]));
4504
+ removeReviewComment(sessionId, id).catch(() => {
4505
+ setRemovedCommentIds((previous) => {
4506
+ const next = new Set(previous);
4507
+ next.delete(id);
4508
+ return next;
4509
+ });
4510
+ });
4511
+ }, [sessionId]);
4512
+ useEffect(() => {
4513
+ const projected = new Set((projection.reviewComments ?? []).map((comment) => comment.id));
4514
+ setLocalComments((list) => list.some((comment) => projected.has(comment.id)) ? list.filter((comment) => !projected.has(comment.id)) : list);
4515
+ setRemovedCommentIds((previous) => {
4516
+ const kept = [...previous].filter((id) => projected.has(id));
4517
+ return kept.length === previous.size ? previous : new Set(kept);
4518
+ });
4519
+ }, [projection.reviewComments]);
4520
+ const reviewComments = useMemo(() => {
4521
+ const merged = /* @__PURE__ */ new Map();
4522
+ for (const comment of projection.reviewComments ?? []) merged.set(comment.id, comment);
4523
+ for (const comment of localComments) merged.set(comment.id, comment);
4524
+ for (const id of removedCommentIds) merged.delete(id);
4525
+ return [...merged.values()];
4526
+ }, [
4527
+ localComments,
4528
+ projection.reviewComments,
4529
+ removedCommentIds
4530
+ ]);
4531
+ useEffect(() => () => actionController.current?.abort(), []);
2732
4532
  useEffect(() => {
2733
4533
  if (!projection.owned || repository?.status !== "ready" || diff === void 0) closeDetails();
2734
4534
  }, [
@@ -2739,61 +4539,431 @@ window.__ModuleLoader__.load({
2739
4539
  ]);
2740
4540
  if (!projection.owned || repository?.status !== "ready" || diff === void 0) return null;
2741
4541
  const branch = repository.detached === true ? t("repositoryDetached") : repository.branch ?? t("repositoryUnknownBranch");
2742
- return /* @__PURE__ */ jsxs("div", {
2743
- style: diffPanel,
4542
+ const availability = repositoryActionAvailability(repository);
4543
+ const anyActionAvailable = availability["commit"] || availability["commit-push"] || availability["push"] || availability["create-pr"];
4544
+ const menuItems = [
4545
+ {
4546
+ id: "commit",
4547
+ label: t("diffCommit"),
4548
+ disabled: !availability["commit"]
4549
+ },
4550
+ {
4551
+ id: "commit-push",
4552
+ label: t("diffCommitPush"),
4553
+ disabled: !availability["commit-push"]
4554
+ },
4555
+ {
4556
+ id: "push",
4557
+ label: t("diffPush"),
4558
+ disabled: !availability["push"]
4559
+ },
4560
+ {
4561
+ id: "create-pr",
4562
+ label: t("diffCreatePr"),
4563
+ disabled: !availability["create-pr"]
4564
+ }
4565
+ ];
4566
+ const completed = dialog?.commit !== void 0 && dialog.error === void 0;
4567
+ const commentEditorNode = commentEditor === void 0 ? null : /* @__PURE__ */ jsxs("div", {
4568
+ style: diffCommentBlock,
2744
4569
  children: [
2745
- /* @__PURE__ */ jsxs("header", {
2746
- style: diffHeader,
2747
- children: [/* @__PURE__ */ jsxs("div", {
2748
- style: diffHeaderTitle,
2749
- children: [
2750
- /* @__PURE__ */ jsx("span", {
2751
- style: diffHeaderBranch,
2752
- children: branch
2753
- }),
2754
- /* @__PURE__ */ jsx("span", {
2755
- "aria-hidden": "true",
2756
- children: "›"
2757
- }),
2758
- /* @__PURE__ */ jsx("span", { children: t("diffWorkingTree") })
2759
- ]
4570
+ /* @__PURE__ */ jsx("textarea", {
4571
+ className: diffCommentTextareaClass,
4572
+ style: diffCommentTextarea,
4573
+ value: commentDraft,
4574
+ maxLength: 2e3,
4575
+ placeholder: t("reviewCommentPlaceholder"),
4576
+ autoFocus: true,
4577
+ onChange: (event) => setCommentDraft(event.currentTarget.value)
4578
+ }),
4579
+ commentError !== void 0 ? /* @__PURE__ */ jsx("p", {
4580
+ style: diffCommentError,
4581
+ children: commentError
4582
+ }) : null,
4583
+ /* @__PURE__ */ jsxs("div", {
4584
+ style: diffCommentActions,
4585
+ children: [/* @__PURE__ */ jsx("button", {
4586
+ type: "button",
4587
+ style: diffCommentActionButton,
4588
+ onClick: closeCommentEditor,
4589
+ children: t("reviewCommentCancel")
2760
4590
  }), /* @__PURE__ */ jsx("button", {
2761
4591
  type: "button",
2762
- style: tasksClose,
2763
- "aria-label": t("diffClose"),
2764
- onClick: closeDetails,
2765
- children: "×"
4592
+ style: {
4593
+ ...diffCommentActionButton,
4594
+ ...diffCommentSubmitButton
4595
+ },
4596
+ disabled: commentBusy || commentDraft.trim().length === 0,
4597
+ onClick: () => void submitComment(),
4598
+ children: t("reviewCommentSubmit")
2766
4599
  })]
2767
- }),
2768
- /* @__PURE__ */ jsxs("div", {
2769
- style: diffSummary,
2770
- children: [
2771
- /* @__PURE__ */ jsx("span", { children: t("diffFiles", { count: diff.files }) }),
2772
- /* @__PURE__ */ jsxs("span", {
2773
- style: diffAdd,
2774
- children: ["+", diff.additions]
2775
- }),
2776
- /* @__PURE__ */ jsxs("span", {
2777
- style: diffDelete,
2778
- children: ["−", diff.deletions]
2779
- })
2780
- ]
2781
- }),
2782
- /* @__PURE__ */ jsxs("div", {
2783
- style: diffBody,
2784
- children: [diff.truncated ? /* @__PURE__ */ jsx("p", {
2785
- style: diffNotice,
2786
- children: t("diffTruncated")
2787
- }) : null, files.length === 0 ? /* @__PURE__ */ jsx("p", {
2788
- style: diffEmpty,
2789
- children: t("diffEmpty")
2790
- }) : files.map((file, index) => /* @__PURE__ */ jsx(DiffFileSection, {
2791
- file,
2792
- initiallyOpen: index === 0
2793
- }, file.path))]
2794
4600
  })
2795
4601
  ]
2796
4602
  });
4603
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
4604
+ /* @__PURE__ */ jsxs("style", {
4605
+ "data-dsh-claude-repository-modal-styles": true,
4606
+ children: [
4607
+ diffModalCss,
4608
+ panelIconButtonCss,
4609
+ diffCommentCss
4610
+ ]
4611
+ }),
4612
+ /* @__PURE__ */ jsxs("div", {
4613
+ style: {
4614
+ ...diffPanel,
4615
+ ...maximized ? diffPanelMaximized : {}
4616
+ },
4617
+ children: [
4618
+ /* @__PURE__ */ jsxs("header", {
4619
+ style: diffHeader,
4620
+ children: [/* @__PURE__ */ jsxs("div", {
4621
+ style: diffHeaderTitle,
4622
+ children: [
4623
+ /* @__PURE__ */ jsx("span", {
4624
+ style: diffHeaderBranch,
4625
+ children: branch
4626
+ }),
4627
+ /* @__PURE__ */ jsx("span", {
4628
+ "aria-hidden": "true",
4629
+ children: "›"
4630
+ }),
4631
+ /* @__PURE__ */ jsx("span", { children: t("diffWorkingTree") })
4632
+ ]
4633
+ }), /* @__PURE__ */ jsxs("div", {
4634
+ style: diffHeaderActions,
4635
+ children: [
4636
+ /* @__PURE__ */ jsxs("div", {
4637
+ style: diffSplitButton,
4638
+ children: [/* @__PURE__ */ jsx("button", {
4639
+ type: "button",
4640
+ style: {
4641
+ ...diffCommitButton,
4642
+ ...availability["commit"] ? {} : diffActionDisabled
4643
+ },
4644
+ disabled: !availability["commit"],
4645
+ onClick: () => openAction("commit"),
4646
+ children: t("diffCommit")
4647
+ }), /* @__PURE__ */ jsx(Menu, {
4648
+ open: menuOpen,
4649
+ items: menuItems,
4650
+ onSelect: (id) => {
4651
+ if (availability[id]) openAction(id);
4652
+ },
4653
+ onClose: () => setMenuOpen(false),
4654
+ align: "end",
4655
+ portal: true,
4656
+ anchor: /* @__PURE__ */ jsx("button", {
4657
+ type: "button",
4658
+ style: {
4659
+ ...diffCommitMenuButton,
4660
+ ...anyActionAvailable ? {} : diffActionDisabled
4661
+ },
4662
+ disabled: !anyActionAvailable,
4663
+ "aria-label": t("diffCommitMenu"),
4664
+ "aria-expanded": menuOpen,
4665
+ onClick: () => setMenuOpen((value) => !value),
4666
+ children: /* @__PURE__ */ jsx(IconChevronDownOutline14, {})
4667
+ })
4668
+ })]
4669
+ }),
4670
+ /* @__PURE__ */ jsx("button", {
4671
+ type: "button",
4672
+ className: panelIconButtonClass,
4673
+ "aria-label": maximized ? t("diffRestore") : t("diffMaximize"),
4674
+ onClick: toggleMaximized,
4675
+ children: maximized ? /* @__PURE__ */ jsx(RestorePanelIcon, {}) : /* @__PURE__ */ jsx(IconFullscreenOutline16, {})
4676
+ }),
4677
+ /* @__PURE__ */ jsx("button", {
4678
+ type: "button",
4679
+ className: panelIconButtonClass,
4680
+ "aria-label": t("diffClose"),
4681
+ onClick: closeDetails,
4682
+ children: /* @__PURE__ */ jsx(IconCloseOutline16, {})
4683
+ })
4684
+ ]
4685
+ })]
4686
+ }),
4687
+ /* @__PURE__ */ jsxs("div", {
4688
+ style: diffSummary,
4689
+ children: [
4690
+ /* @__PURE__ */ jsx("span", { children: t("diffFiles", { count: diff.files }) }),
4691
+ /* @__PURE__ */ jsxs("span", {
4692
+ style: diffAdd,
4693
+ children: ["+", diff.additions]
4694
+ }),
4695
+ /* @__PURE__ */ jsxs("span", {
4696
+ style: diffDelete,
4697
+ children: ["−", diff.deletions]
4698
+ })
4699
+ ]
4700
+ }),
4701
+ /* @__PURE__ */ jsxs("div", {
4702
+ ref: diffBodyRef,
4703
+ style: diffBody,
4704
+ children: [diff.truncated ? /* @__PURE__ */ jsx("p", {
4705
+ style: diffNotice,
4706
+ children: t("diffTruncated")
4707
+ }) : null, files.length === 0 ? /* @__PURE__ */ jsx("p", {
4708
+ style: diffEmpty,
4709
+ children: t("diffEmpty")
4710
+ }) : files.map((file, index) => /* @__PURE__ */ jsx(DiffFileSection, {
4711
+ file,
4712
+ initiallyOpen: index === 0,
4713
+ t,
4714
+ comments: reviewComments.filter((comment) => comment.path === file.path),
4715
+ editorAnchor: commentEditor !== void 0 && commentEditor.path === file.path ? commentEditor : void 0,
4716
+ editorNode: commentEditorNode,
4717
+ onOpenEditor: (anchor) => openCommentEditor(file.path, anchor),
4718
+ onRemoveComment: removeComment
4719
+ }, file.path))]
4720
+ })
4721
+ ]
4722
+ }),
4723
+ /* @__PURE__ */ jsxs(Modal, {
4724
+ className: "dshClaudeRepositoryActionModal",
4725
+ contentClassName: "dshClaudeRepositoryActionModalContent",
4726
+ open: dialog !== void 0,
4727
+ onClose: closeDialog,
4728
+ title: dialog === void 0 ? t("diffCommit") : actionLabel(dialog.action, t),
4729
+ closeLabel: t("diffCancel"),
4730
+ description: t("diffConfirmDescription"),
4731
+ footer: /* @__PURE__ */ jsxs("div", {
4732
+ style: diffModalFooter,
4733
+ children: [/* @__PURE__ */ jsx("button", {
4734
+ type: "button",
4735
+ style: {
4736
+ ...button,
4737
+ ...diffModalButton
4738
+ },
4739
+ disabled: dialog?.submitting === true,
4740
+ onClick: closeDialog,
4741
+ children: completed ? t("diffDone") : t("diffCancel")
4742
+ }), !completed ? /* @__PURE__ */ jsx("button", {
4743
+ type: "button",
4744
+ style: {
4745
+ ...primaryButton,
4746
+ ...diffModalButton
4747
+ },
4748
+ disabled: dialog?.loading === true || dialog?.submitting === true || dialog?.preview === void 0 || dialog.action !== "push" && message.trim() === "",
4749
+ onClick: () => void confirm(),
4750
+ children: dialog?.submitting === true ? t("diffSubmitting") : t("diffConfirm")
4751
+ }) : null]
4752
+ }),
4753
+ children: [
4754
+ dialog?.loading === true ? /* @__PURE__ */ jsx("p", {
4755
+ style: diffModalStatus,
4756
+ children: t("diffGeneratingMessage")
4757
+ }) : null,
4758
+ dialog?.preview !== void 0 ? /* @__PURE__ */ jsxs("div", {
4759
+ style: diffModalBody,
4760
+ children: [
4761
+ /* @__PURE__ */ jsxs("div", {
4762
+ style: diffModalMeta,
4763
+ children: [/* @__PURE__ */ jsx("strong", {
4764
+ style: diffModalMetaText,
4765
+ title: dialog.preview.branch,
4766
+ children: dialog.action === "push" ? `${dialog.preview.branch} → ${dialog.preview.upstream ?? `origin/${dialog.preview.branch}`}` : dialog.preview.branch
4767
+ }), /* @__PURE__ */ jsx("span", {
4768
+ style: diffModalFileState,
4769
+ children: dialog.action === "push" ? t("diffPushAhead", { count: dialog.preview.unpushedTruncated ? `${dialog.preview.unpushedCommits.length}+` : dialog.preview.unpushedCommits.length }) : t("diffFiles", { count: dialog.preview.files.length })
4770
+ })]
4771
+ }),
4772
+ dialog.action === "push" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
4773
+ style: diffModalFiles,
4774
+ children: dialog.preview.unpushedCommits.map((commit) => /* @__PURE__ */ jsxs("div", {
4775
+ style: diffModalFile,
4776
+ children: [/* @__PURE__ */ jsx("span", {
4777
+ style: diffModalFilePath,
4778
+ title: commit.subject,
4779
+ children: commit.subject
4780
+ }), /* @__PURE__ */ jsx("span", {
4781
+ style: diffModalFileState,
4782
+ children: commit.hash.slice(0, 8)
4783
+ })]
4784
+ }, commit.hash))
4785
+ }), /* @__PURE__ */ jsx("p", {
4786
+ style: diffModalStatus,
4787
+ children: t("diffPushDescription")
4788
+ })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
4789
+ /* @__PURE__ */ jsx("div", {
4790
+ style: diffModalFiles,
4791
+ children: dialog.preview.files.map((file) => /* @__PURE__ */ jsxs("div", {
4792
+ style: diffModalFile,
4793
+ children: [/* @__PURE__ */ jsx("span", {
4794
+ style: diffModalFilePath,
4795
+ title: file.path,
4796
+ children: file.path
4797
+ }), /* @__PURE__ */ jsx("span", {
4798
+ style: diffModalFileState,
4799
+ children: file.untracked ? t("diffUntracked") : file.staged && file.unstaged ? t("diffStagedUnstaged") : file.staged ? t("diffStaged") : t("diffUnstaged")
4800
+ })]
4801
+ }, file.path))
4802
+ }),
4803
+ /* @__PURE__ */ jsxs("label", {
4804
+ style: diffModalCheckbox,
4805
+ children: [/* @__PURE__ */ jsx("input", {
4806
+ type: "checkbox",
4807
+ checked: includeUnstaged,
4808
+ disabled: !dialog.preview.hasUnstaged && !dialog.preview.hasUntracked,
4809
+ onChange: (event) => setIncludeUnstaged(event.currentTarget.checked)
4810
+ }), t("diffIncludeUnstaged")]
4811
+ }),
4812
+ /* @__PURE__ */ jsxs("label", {
4813
+ style: diffModalField,
4814
+ children: [t("diffCommitMessage"), /* @__PURE__ */ jsx("textarea", {
4815
+ style: diffModalTextarea,
4816
+ value: message,
4817
+ maxLength: 512,
4818
+ onChange: (event) => setMessage(event.currentTarget.value)
4819
+ })]
4820
+ })
4821
+ ] }),
4822
+ dialog.action === "create-pr" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
4823
+ /* @__PURE__ */ jsxs("label", {
4824
+ style: diffModalField,
4825
+ children: [t("diffPrTitle"), /* @__PURE__ */ jsx("input", {
4826
+ style: diffModalTextInput,
4827
+ value: prTitle,
4828
+ maxLength: 256,
4829
+ onChange: (event) => setPrTitle(event.currentTarget.value)
4830
+ })]
4831
+ }),
4832
+ /* @__PURE__ */ jsxs("label", {
4833
+ style: diffModalField,
4834
+ children: [t("diffPrBase"), /* @__PURE__ */ jsx("input", {
4835
+ style: diffModalTextInput,
4836
+ value: baseBranch,
4837
+ maxLength: 512,
4838
+ placeholder: t("diffPrBaseDefault"),
4839
+ onChange: (event) => setBaseBranch(event.currentTarget.value)
4840
+ })]
4841
+ }),
4842
+ /* @__PURE__ */ jsxs("label", {
4843
+ style: diffModalField,
4844
+ children: [t("diffPrDescription"), /* @__PURE__ */ jsx("textarea", {
4845
+ style: {
4846
+ ...diffModalTextarea,
4847
+ minHeight: 240
4848
+ },
4849
+ value: prBody,
4850
+ maxLength: 8192,
4851
+ onChange: (event) => setPrBody(event.currentTarget.value)
4852
+ })]
4853
+ }),
4854
+ /* @__PURE__ */ jsxs("label", {
4855
+ style: diffModalCheckbox,
4856
+ children: [/* @__PURE__ */ jsx("input", {
4857
+ type: "checkbox",
4858
+ checked: draft,
4859
+ onChange: (event) => setDraft(event.currentTarget.checked)
4860
+ }), t("diffPrDraft")]
4861
+ })
4862
+ ] }) : null,
4863
+ dialog.commit !== void 0 ? /* @__PURE__ */ jsx("p", {
4864
+ style: diffModalSuccess,
4865
+ children: dialog.action === "push" ? t("diffPushCompleted", { commit: dialog.commit.slice(0, 8) }) : t("diffCommitCompleted", { commit: dialog.commit.slice(0, 8) })
4866
+ }) : null,
4867
+ dialog.pullRequestUrl !== void 0 ? /* @__PURE__ */ jsx("a", {
4868
+ href: dialog.pullRequestUrl,
4869
+ target: "_blank",
4870
+ rel: "noopener noreferrer",
4871
+ children: t("diffOpenPr")
4872
+ }) : null
4873
+ ]
4874
+ }) : null,
4875
+ dialog?.error !== void 0 ? /* @__PURE__ */ jsxs("p", {
4876
+ role: "alert",
4877
+ style: diffModalError,
4878
+ children: [dialog.error, dialog.commit === void 0 ? "" : ` ${t("diffCommitPreserved", { commit: dialog.commit.slice(0, 8) })}`]
4879
+ }) : null
4880
+ ]
4881
+ })
4882
+ ] });
4883
+ }
4884
+ //#endregion
4885
+ //#region src/client/ClaudeDiffOverlay.tsx
4886
+ const useClientLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
4887
+ function shouldRestoreFromEscape(event, root = document) {
4888
+ return event.key === "Escape" && root.querySelector("[role=\"dialog\"][aria-modal=\"true\"]") === null;
4889
+ }
4890
+ function workspaceBounds(overlay) {
4891
+ const frame = overlay.parentElement;
4892
+ if (frame === null) return void 0;
4893
+ const overlayRect = overlay.getBoundingClientRect();
4894
+ const candidates = Array.from(frame.children).filter((element) => element !== overlay).map((element) => element.getBoundingClientRect()).filter((rect) => rect.width > 0 && rect.height > 0);
4895
+ const insetCandidates = candidates.filter((rect) => rect.left > overlayRect.left);
4896
+ const workspace = (insetCandidates.length > 0 ? insetCandidates : candidates).reduce((largest, rect) => {
4897
+ if (largest === void 0 || rect.width * rect.height > largest.width * largest.height) return rect;
4898
+ return largest;
4899
+ }, void 0);
4900
+ if (workspace === void 0) return void 0;
4901
+ const left = Math.max(0, workspace.left - overlayRect.left);
4902
+ const top = Math.max(0, workspace.top - overlayRect.top);
4903
+ return {
4904
+ left,
4905
+ top,
4906
+ width: Math.max(0, Math.min(workspace.width, overlayRect.width - left)),
4907
+ height: Math.max(0, Math.min(workspace.height, overlayRect.height - top))
4908
+ };
4909
+ }
4910
+ function observeWorkspaceBounds(overlay, listener) {
4911
+ const frame = overlay.parentElement;
4912
+ if (frame === null) return () => {};
4913
+ const update = () => {
4914
+ const next = workspaceBounds(overlay);
4915
+ if (next !== void 0) listener(next);
4916
+ };
4917
+ update();
4918
+ const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(update);
4919
+ observer?.observe(frame);
4920
+ for (const element of Array.from(frame.children)) observer?.observe(element);
4921
+ const mutation = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver(update);
4922
+ mutation?.observe(frame, {
4923
+ attributes: true,
4924
+ childList: true
4925
+ });
4926
+ window.addEventListener("resize", update);
4927
+ return () => {
4928
+ observer?.disconnect();
4929
+ mutation?.disconnect();
4930
+ window.removeEventListener("resize", update);
4931
+ };
4932
+ }
4933
+ function ClaudeDiffOverlay({ children, onRestore }) {
4934
+ const ref = useRef(null);
4935
+ const [bounds, setBounds] = useState();
4936
+ useClientLayoutEffect(() => {
4937
+ const overlay = ref.current?.closest("[data-shell-overlay]");
4938
+ if (overlay === void 0 || overlay === null) return;
4939
+ return observeWorkspaceBounds(overlay, (next) => {
4940
+ setBounds((current) => current?.left === next.left && current.top === next.top && current.width === next.width && current.height === next.height ? current : next);
4941
+ });
4942
+ }, []);
4943
+ useEffect(() => {
4944
+ const escape = (event) => {
4945
+ if (shouldRestoreFromEscape(event)) onRestore();
4946
+ };
4947
+ window.addEventListener("keydown", escape);
4948
+ return () => window.removeEventListener("keydown", escape);
4949
+ }, [onRestore]);
4950
+ return /* @__PURE__ */ jsx("div", {
4951
+ ref,
4952
+ "data-dsh-claude-diff-overlay": true,
4953
+ style: {
4954
+ position: "absolute",
4955
+ left: bounds?.left ?? 0,
4956
+ top: bounds?.top ?? 0,
4957
+ width: bounds?.width ?? 0,
4958
+ height: bounds?.height ?? 0,
4959
+ visibility: bounds === void 0 ? "hidden" : "visible",
4960
+ padding: 8,
4961
+ boxSizing: "border-box",
4962
+ background: "var(--dsw-alias-bg-base)",
4963
+ pointerEvents: bounds === void 0 ? "none" : "auto"
4964
+ },
4965
+ children
4966
+ });
2797
4967
  }
2798
4968
  //#endregion
2799
4969
  //#region src/client/hero-dom-bridge.ts
@@ -3367,7 +5537,7 @@ window.__ModuleLoader__.load({
3367
5537
  children: [branches === void 0 ? /* @__PURE__ */ jsx("span", {
3368
5538
  style: heroRepositoryStatus,
3369
5539
  children: error ?? t("repositoryBranchesLoading")
3370
- }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ClaudeHeroRepositoryCapsule, {
5540
+ }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ClaudeHeroRepositoryCapsule, {
3371
5541
  branches: availableBranches,
3372
5542
  selected,
3373
5543
  worktree,
@@ -3415,6 +5585,8 @@ window.__ModuleLoader__.load({
3415
5585
  const MAX_COMMANDS = 2e3;
3416
5586
  const MAX_REPOSITORY_TEXT_CHARS = 1024;
3417
5587
  const MAX_DIFF_CHARS = 262144;
5588
+ const MAX_REVIEW_COMMENTS = 50;
5589
+ const MAX_REVIEW_COMMENT_CHARS = 2e3;
3418
5590
  function record(value) {
3419
5591
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3420
5592
  }
@@ -3430,7 +5602,7 @@ window.__ModuleLoader__.load({
3430
5602
  "ready",
3431
5603
  "not-repository",
3432
5604
  "unavailable"
3433
- ].includes(String(repository.status)) || typeof repository.cwd !== "string" || repository.cwd.length > MAX_REPOSITORY_TEXT_CHARS || !optionalBoundedString(repository.root) || !optionalBoundedString(repository.branch) || !optionalBoundedString(repository.remote) || repository.detached !== void 0 && typeof repository.detached !== "boolean" || repository.worktree !== void 0 && typeof repository.worktree !== "boolean" || repository.dirty !== void 0 && typeof repository.dirty !== "boolean") return false;
5605
+ ].includes(String(repository.status)) || typeof repository.cwd !== "string" || repository.cwd.length > MAX_REPOSITORY_TEXT_CHARS || !optionalBoundedString(repository.root) || !optionalBoundedString(repository.branch) || !optionalBoundedString(repository.remote) || repository.detached !== void 0 && typeof repository.detached !== "boolean" || repository.worktree !== void 0 && typeof repository.worktree !== "boolean" || repository.dirty !== void 0 && typeof repository.dirty !== "boolean" || repository.upstream !== void 0 && typeof repository.upstream !== "boolean" || repository.ahead !== void 0 && !nonNegativeInteger(repository.ahead) || repository.behind !== void 0 && !nonNegativeInteger(repository.behind)) return false;
3434
5606
  if (repository.diff !== void 0) {
3435
5607
  const diff = record(repository.diff);
3436
5608
  if (diff === void 0 || !nonNegativeInteger(diff.additions) || !nonNegativeInteger(diff.deletions) || !nonNegativeInteger(diff.files) || typeof diff.truncated !== "boolean" || diff.patch !== void 0 && (typeof diff.patch !== "string" || diff.patch.length > MAX_DIFF_CHARS)) return false;
@@ -3451,7 +5623,7 @@ window.__ModuleLoader__.load({
3451
5623
  "pending",
3452
5624
  "failing",
3453
5625
  "none"
3454
- ].includes(String(pullRequest.checks)) || !optionalBoundedString(pullRequest.mergeState) || !optionalBoundedString(pullRequest.author) || !optionalBoundedString(pullRequest.baseBranch) || pullRequest.createdAt !== void 0 && (typeof pullRequest.createdAt !== "string" || !Number.isFinite(Date.parse(pullRequest.createdAt)))) return false;
5626
+ ].includes(String(pullRequest.checks)) || !optionalBoundedString(pullRequest.mergeState) || !optionalBoundedString(pullRequest.author) || !optionalBoundedString(pullRequest.baseBranch) || pullRequest.createdAt !== void 0 && (typeof pullRequest.createdAt !== "string" || !Number.isFinite(Date.parse(pullRequest.createdAt))) || pullRequest.mergedAt !== void 0 && (typeof pullRequest.mergedAt !== "string" || !Number.isFinite(Date.parse(pullRequest.mergedAt)))) return false;
3455
5627
  try {
3456
5628
  const url = new URL(pullRequest.url);
3457
5629
  return url.protocol === "https:" && url.hostname === "github.com";
@@ -3475,6 +5647,13 @@ window.__ModuleLoader__.load({
3475
5647
  const tasks = input.tasks === void 0 ? void 0 : record(input.tasks);
3476
5648
  if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
3477
5649
  if (input.repository !== void 0 && !validateRepository(input.repository)) throw new Error("invalid Claude repository projection");
5650
+ if (input.reviewComments !== void 0) {
5651
+ if (!Array.isArray(input.reviewComments) || input.reviewComments.length > MAX_REVIEW_COMMENTS) throw new Error("invalid Claude review comment projection");
5652
+ for (const item of input.reviewComments) {
5653
+ const comment = record(item);
5654
+ if (comment === void 0 || typeof comment.id !== "string" || comment.id.length === 0 || comment.id.length > 128 || typeof comment.path !== "string" || comment.path.length === 0 || comment.path.length > MAX_REPOSITORY_TEXT_CHARS || !nonNegativeInteger(comment.line) || comment.side !== "old" && comment.side !== "new" || typeof comment.text !== "string" || comment.text.length > MAX_REVIEW_COMMENT_CHARS) throw new Error("invalid Claude review comment projection");
5655
+ }
5656
+ }
3478
5657
  return input;
3479
5658
  }
3480
5659
  /** Create one lazy source: active subscribers trigger an immediate load and bounded polling. */
@@ -3503,7 +5682,8 @@ window.__ModuleLoader__.load({
3503
5682
  const next = parseClaudeClientProjection(await response.json());
3504
5683
  const commandCatalogChanged = JSON.stringify(next.commands) !== JSON.stringify(snapshot.commands);
3505
5684
  const repositoryChanged = JSON.stringify(next.repository) !== JSON.stringify(snapshot.repository);
3506
- if (next.revision !== snapshot.revision || next.owned !== snapshot.owned || commandCatalogChanged || repositoryChanged) {
5685
+ const reviewCommentsChanged = JSON.stringify(next.reviewComments) !== JSON.stringify(snapshot.reviewComments);
5686
+ if (next.revision !== snapshot.revision || next.owned !== snapshot.owned || commandCatalogChanged || repositoryChanged || reviewCommentsChanged) {
3507
5687
  snapshot = next;
3508
5688
  for (const listener of [...listeners]) listener();
3509
5689
  }
@@ -3814,6 +5994,11 @@ window.__ModuleLoader__.load({
3814
5994
  failed: "失败",
3815
5995
  done: "完成",
3816
5996
  subagent: "子代理",
5997
+ usedTool: "使用了 1 个工具",
5998
+ usedTools: "使用了 {count} 个工具",
5999
+ toolInput: "输入",
6000
+ toolOutput: "输出",
6001
+ toolError: "错误",
3817
6002
  tokens: "{count} 个 token",
3818
6003
  doctor: "运行诊断",
3819
6004
  refreshing: "诊断中…",
@@ -3878,6 +6063,7 @@ window.__ModuleLoader__.load({
3878
6063
  tasksViewActivity: "查看活动",
3879
6064
  tasksHideActivity: "收起活动",
3880
6065
  tasksRunningCount: "{count} 个运行中任务",
6066
+ repositoryRateLimited: "Claude 额度限流中",
3881
6067
  tasksTurnRunning: "{count} 个任务执行中",
3882
6068
  tasksTurnCompleted: "{count} 个任务已完成",
3883
6069
  tasksTurnFailed: "{failed} 个任务失败,{completed} 个已完成",
@@ -3933,6 +6119,8 @@ window.__ModuleLoader__.load({
3933
6119
  repositoryState_open: "开放",
3934
6120
  repositoryState_closed: "已关闭",
3935
6121
  repositoryState_merged: "已合并",
6122
+ repositoryMergedInto: "已合并到 {branch}",
6123
+ repositoryMergedAgo: "{age}前",
3936
6124
  repositoryChecks: "检查",
3937
6125
  repositoryChecks_passing: "检查通过",
3938
6126
  repositoryChecks_pending: "检查进行中",
@@ -3953,7 +6141,49 @@ window.__ModuleLoader__.load({
3953
6141
  diffFiles: "{count} 个已修改文件",
3954
6142
  diffFilesShort: "{count} 个文件",
3955
6143
  diffTruncated: "Diff 超出安全显示上限。请在终端中查看完整内容。",
3956
- diffEmpty: "没有可显示的 tracked 文件改动"
6144
+ diffEmpty: "没有可显示的 tracked 文件改动",
6145
+ diffMaximize: "最大化 Diff 面板",
6146
+ diffRestore: "还原 Diff 面板",
6147
+ diffCommit: "Commit",
6148
+ diffCommitMenu: "打开提交操作菜单",
6149
+ diffCommitPush: "Commit & Push…",
6150
+ diffPush: "Push",
6151
+ diffCreatePr: "Create PR…",
6152
+ diffConfirmDescription: "确认仓库快照和将要执行的 Git 操作。",
6153
+ diffPushDescription: "将本地未推送的 commit 推送到远端分支。",
6154
+ diffPushAhead: "{count} 个未推送的 commit",
6155
+ diffPushCompleted: "已推送 commit {commit}",
6156
+ diffGeneratingMessage: "正在读取仓库并生成 commit message…",
6157
+ diffActionFailed: "仓库操作失败。",
6158
+ diffIncludeUnstaged: "包含 unstaged 和 untracked 改动",
6159
+ diffCommitMessage: "Commit message",
6160
+ diffStaged: "Staged",
6161
+ diffUnstaged: "Unstaged",
6162
+ diffStagedUnstaged: "Staged + unstaged",
6163
+ diffUntracked: "Untracked",
6164
+ diffPrTitle: "PR title",
6165
+ diffPrBase: "Base branch",
6166
+ diffPrBaseDefault: "使用远端默认分支",
6167
+ diffPrDescription: "PR description(仅 Summary 与 Changes)",
6168
+ diffPrDraft: "创建为 Draft PR",
6169
+ diffCancel: "取消",
6170
+ diffConfirm: "确认",
6171
+ diffSubmitting: "执行中…",
6172
+ diffDone: "完成",
6173
+ diffCommitCompleted: "已创建 commit {commit}",
6174
+ diffCommitPreserved: "本地 commit {commit} 已保留。",
6175
+ diffOpenPr: "打开 Pull Request",
6176
+ reviewCommentAdd: "添加行评论",
6177
+ reviewCommentPlaceholder: "请求更改",
6178
+ reviewCommentSubmit: "注释",
6179
+ reviewCommentCancel: "取消",
6180
+ reviewCommentRemove: "删除评论",
6181
+ reviewCommentFailed: "评论操作失败。",
6182
+ reviewCommentsClear: "清除全部评论",
6183
+ reviewCommentsSend: "发送评论",
6184
+ reviewCommentsSendDraft: "请处理以上代码评论。",
6185
+ reviewCommentOldSide: "旧代码第 {line} 行",
6186
+ reviewCommentNewSide: "第 {line} 行"
3957
6187
  };
3958
6188
  const en = {
3959
6189
  nav: "Claude Code",
@@ -3966,6 +6196,11 @@ window.__ModuleLoader__.load({
3966
6196
  failed: "Failed",
3967
6197
  done: "Done",
3968
6198
  subagent: "Subagent",
6199
+ usedTool: "Used 1 tool",
6200
+ usedTools: "Used {count} tools",
6201
+ toolInput: "Input",
6202
+ toolOutput: "Output",
6203
+ toolError: "Error",
3969
6204
  tokens: "{count} tokens",
3970
6205
  doctor: "Run Doctor",
3971
6206
  refreshing: "Running Doctor…",
@@ -4030,6 +6265,7 @@ window.__ModuleLoader__.load({
4030
6265
  tasksViewActivity: "View activity",
4031
6266
  tasksHideActivity: "Hide activity",
4032
6267
  tasksRunningCount: "{count} running task(s)",
6268
+ repositoryRateLimited: "Rate limited",
4033
6269
  tasksTurnRunning: "{count} task(s) running",
4034
6270
  tasksTurnCompleted: "{count} task(s) completed",
4035
6271
  tasksTurnFailed: "{failed} failed, {completed} completed",
@@ -4085,6 +6321,8 @@ window.__ModuleLoader__.load({
4085
6321
  repositoryState_open: "Open",
4086
6322
  repositoryState_closed: "Closed",
4087
6323
  repositoryState_merged: "Merged",
6324
+ repositoryMergedInto: "Merged into {branch}",
6325
+ repositoryMergedAgo: "{age} ago",
4088
6326
  repositoryChecks: "Checks",
4089
6327
  repositoryChecks_passing: "Checks passing",
4090
6328
  repositoryChecks_pending: "Checks pending",
@@ -4105,10 +6343,67 @@ window.__ModuleLoader__.load({
4105
6343
  diffFiles: "{count} modified file(s)",
4106
6344
  diffFilesShort: "{count} files",
4107
6345
  diffTruncated: "The diff exceeds the safe display limit. Use the terminal to inspect the complete content.",
4108
- diffEmpty: "No tracked file changes to display"
6346
+ diffEmpty: "No tracked file changes to display",
6347
+ diffMaximize: "Maximize diff panel",
6348
+ diffRestore: "Restore diff panel",
6349
+ diffCommit: "Commit",
6350
+ diffCommitMenu: "Open commit actions",
6351
+ diffCommitPush: "Commit & Push…",
6352
+ diffPush: "Push",
6353
+ diffCreatePr: "Create PR…",
6354
+ diffConfirmDescription: "Confirm the repository snapshot and Git operation.",
6355
+ diffPushDescription: "Push local commits to the remote branch.",
6356
+ diffPushAhead: "{count} unpushed commit(s)",
6357
+ diffPushCompleted: "Pushed commit {commit}",
6358
+ diffGeneratingMessage: "Reading the repository and generating a commit message…",
6359
+ diffActionFailed: "Repository action failed.",
6360
+ diffIncludeUnstaged: "Include unstaged and untracked changes",
6361
+ diffCommitMessage: "Commit message",
6362
+ diffStaged: "Staged",
6363
+ diffUnstaged: "Unstaged",
6364
+ diffStagedUnstaged: "Staged + unstaged",
6365
+ diffUntracked: "Untracked",
6366
+ diffPrTitle: "PR title",
6367
+ diffPrBase: "Base branch",
6368
+ diffPrBaseDefault: "Use the remote default branch",
6369
+ diffPrDescription: "PR description (Summary and Changes only)",
6370
+ diffPrDraft: "Create as a Draft PR",
6371
+ diffCancel: "Cancel",
6372
+ diffConfirm: "Confirm",
6373
+ diffSubmitting: "Working…",
6374
+ diffDone: "Done",
6375
+ diffCommitCompleted: "Created commit {commit}",
6376
+ diffCommitPreserved: "Local commit {commit} was preserved.",
6377
+ diffOpenPr: "Open pull request",
6378
+ reviewCommentAdd: "Add line comment",
6379
+ reviewCommentPlaceholder: "Request changes",
6380
+ reviewCommentSubmit: "Comment",
6381
+ reviewCommentCancel: "Cancel",
6382
+ reviewCommentRemove: "Remove comment",
6383
+ reviewCommentFailed: "The comment could not be saved.",
6384
+ reviewCommentsClear: "Clear all comments",
6385
+ reviewCommentsSend: "Send comments",
6386
+ reviewCommentsSendDraft: "Please address the attached review comments.",
6387
+ reviewCommentOldSide: "Old line {line}",
6388
+ reviewCommentNewSide: "Line {line}"
4109
6389
  };
4110
6390
  //#endregion
4111
6391
  //#region src/client/index.tsx
6392
+ function MaximizedDiff({ source, t, sessionId, closeDetails, restore }) {
6393
+ const snapshot = useSyncExternalStore(source.subscribe, source.getSnapshot, source.getSnapshot);
6394
+ const useClaudeProjection = (selector) => selector(snapshot);
6395
+ return /* @__PURE__ */ jsx(ClaudeDiffOverlay, {
6396
+ onRestore: restore,
6397
+ children: /* @__PURE__ */ jsx(ClaudeDiffPanel, {
6398
+ useClaudeProjection,
6399
+ t,
6400
+ sessionId,
6401
+ maximized: true,
6402
+ closeDetails,
6403
+ toggleMaximized: restore
6404
+ })
6405
+ });
6406
+ }
4112
6407
  const name = "dsh-claude-client";
4113
6408
  const inject = [
4114
6409
  "slots",
@@ -4148,17 +6443,30 @@ window.__ModuleLoader__.load({
4148
6443
  }, ClaudeActivityNode));
4149
6444
  const layout = ctx.get("layout");
4150
6445
  let disposePluginDetails;
6446
+ let disposeDiffOverlay;
4151
6447
  let disposeExpandedDetailsResize;
4152
6448
  let detailsSessionId;
6449
+ const restoreDiff = () => {
6450
+ if (disposeDiffOverlay === void 0) return;
6451
+ disposeDiffOverlay();
6452
+ disposeDiffOverlay = void 0;
6453
+ layout?.openDetails();
6454
+ disposeExpandedDetailsResize = enableExpandedDetailsResize();
6455
+ };
4153
6456
  const closePluginDetails = () => {
4154
- if (disposePluginDetails === void 0) return;
6457
+ if (disposePluginDetails === void 0 && disposeDiffOverlay === void 0 && disposeExpandedDetailsResize === void 0 && detailsSessionId === void 0) return;
6458
+ disposeDiffOverlay?.();
6459
+ disposeDiffOverlay = void 0;
4155
6460
  disposeExpandedDetailsResize?.();
4156
6461
  disposeExpandedDetailsResize = void 0;
4157
- disposePluginDetails();
6462
+ disposePluginDetails?.();
4158
6463
  disposePluginDetails = void 0;
4159
6464
  detailsSessionId = void 0;
4160
6465
  layout?.closeDetails();
4161
6466
  };
6467
+ ctx.effect(() => ctx.slots.onEntryError((key, entry) => {
6468
+ if (key === "shell.overlay" && entry.options.id === "claude-diff-overlay") restoreDiff();
6469
+ }), "dsh-claude: diff overlay recovery");
4162
6470
  const openTasksPanel = (sessionId, turn) => {
4163
6471
  closePluginDetails();
4164
6472
  try {
@@ -4181,27 +6489,64 @@ window.__ModuleLoader__.load({
4181
6489
  };
4182
6490
  const openDiffPanel = (sessionId) => {
4183
6491
  closePluginDetails();
4184
- try {
4185
- disposePluginDetails = ctx.slots.register({
4186
- name: "details",
4187
- priority: -10,
4188
- locale: namespace,
4189
- inject: () => ({
6492
+ detailsSessionId = sessionId;
6493
+ const registerDetails = () => {
6494
+ try {
6495
+ disposePluginDetails = ctx.slots.register({
6496
+ name: "details",
6497
+ priority: -10,
6498
+ locale: namespace,
6499
+ inject: () => ({
6500
+ t,
6501
+ sessionId,
6502
+ maximized: false,
6503
+ closeDetails: closePluginDetails,
6504
+ toggleMaximized: maximizeDiff
6505
+ })
6506
+ }, ClaudeDiffPanel);
6507
+ } catch {
6508
+ disposePluginDetails = void 0;
6509
+ return false;
6510
+ }
6511
+ layout?.openDetails();
6512
+ return true;
6513
+ };
6514
+ const maximizeDiff = () => {
6515
+ if (disposeDiffOverlay !== void 0) {
6516
+ restoreDiff();
6517
+ return;
6518
+ }
6519
+ disposeExpandedDetailsResize?.();
6520
+ disposeExpandedDetailsResize = void 0;
6521
+ layout?.closeDetails();
6522
+ try {
6523
+ disposeDiffOverlay = ctx.slots.register({
6524
+ name: "shell.overlay",
6525
+ id: "claude-diff-overlay",
6526
+ locale: namespace
6527
+ }, () => /* @__PURE__ */ jsx(MaximizedDiff, {
6528
+ source: projections.source(sessionId),
4190
6529
  t,
4191
- closeDetails: closePluginDetails
4192
- })
4193
- }, ClaudeDiffPanel);
4194
- } catch {
6530
+ sessionId,
6531
+ closeDetails: closePluginDetails,
6532
+ restore: restoreDiff
6533
+ }));
6534
+ } catch {
6535
+ disposeDiffOverlay = void 0;
6536
+ layout?.openDetails();
6537
+ disposeExpandedDetailsResize = enableExpandedDetailsResize();
6538
+ }
6539
+ };
6540
+ if (!registerDetails()) {
6541
+ detailsSessionId = void 0;
4195
6542
  return;
4196
6543
  }
4197
- detailsSessionId = sessionId;
4198
- layout?.openDetails();
4199
6544
  disposeExpandedDetailsResize = enableExpandedDetailsResize();
4200
6545
  };
4201
6546
  ctx.effect(() => {
4202
6547
  if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => closePluginDetails();
4203
6548
  const observer = new MutationObserver(() => {
4204
- if (detailsSessionId !== void 0 && document.querySelector("[data-details-collapsed]") !== null) closePluginDetails();
6549
+ if (detailsSessionId !== void 0 && disposeDiffOverlay === void 0 && document.querySelector("[data-details-collapsed]") !== null) closePluginDetails();
4205
6550
  });
4206
6551
  observer.observe(document.body, {
4207
6552
  attributes: true,
@@ -4227,10 +6572,27 @@ window.__ModuleLoader__.load({
4227
6572
  openTasks: (turn) => openTasksPanel(sessionId, turn)
4228
6573
  })
4229
6574
  }, ClaudeActivityTail));
6575
+ ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
6576
+ name: "conversation.input.dock",
6577
+ id: "claude-review-comments",
6578
+ order: 18,
6579
+ locale: namespace,
6580
+ inject: (sessionId) => ({
6581
+ t,
6582
+ sessionId,
6583
+ ...sessions === void 0 || conversation === void 0 ? {} : { submitWith: (fallbackDraft) => {
6584
+ const scope = sessions.scope(sessionId);
6585
+ if (scope === void 0) return;
6586
+ const input = conversation.input.for(scope);
6587
+ if (input.state.getSnapshot().draft.trim() === "") input.setDraft(fallbackDraft);
6588
+ input.submit();
6589
+ } }
6590
+ })
6591
+ }, ClaudeReviewComments));
4230
6592
  ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
4231
6593
  name: "conversation.input.dock",
4232
6594
  id: "claude-repository-status",
4233
- order: 20,
6595
+ order: 20.5,
4234
6596
  locale: namespace,
4235
6597
  inject: (sessionId) => ({
4236
6598
  t,