@norman-else/dsh-claude 0.1.18 → 0.1.19

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
@@ -5,7 +5,8 @@ window.__ModuleLoader__.load({
5
5
  module.exports;
6
6
  var { useCallback, useEffect, useId, useMemo, useRef, useState } = require("react");
7
7
  var { Fragment, jsx, jsxs } = require("react/jsx-runtime");
8
- var { DisclosureRow, IconApiOutline14, IconThinkOutline14, StateDot } = require("@deepseek-ai/dsh-client-ui-primitives");
8
+ var { DisclosureRow, IconApiOutline14, IconBranchOutline16, IconCheckOutline14, IconChevronDownOutline14, IconSearchOutline16, IconThinkOutline14, StateDot } = require("@deepseek-ai/dsh-client-ui-primitives");
9
+ var { createPortal } = require("react-dom");
9
10
  /** Claude's subagent dispatch tools; rendered as plugin-owned group cards
10
11
  * gathering subagent activity instead of native tool cards. */
11
12
  const TASK_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
@@ -14,6 +15,7 @@ window.__ModuleLoader__.load({
14
15
  const CLAUDE_UPDATE_PATH = "/plugins/dsh-claude/update";
15
16
  const CLAUDE_PROJECTION_PATH = "/plugins/dsh-claude/projection";
16
17
  const CLAUDE_GLOBAL_SETTINGS_PATH = "/plugins/dsh-claude/settings/global";
18
+ const CLAUDE_REPOSITORY_SETUP_PATH = "/plugins/dsh-claude/repository/setup";
17
19
  //#endregion
18
20
  //#region src/client/conversation-sidecar.ts
19
21
  function isTaskActivity(value) {
@@ -185,7 +187,8 @@ window.__ModuleLoader__.load({
185
187
  return {
186
188
  turn: match.event.data.turn,
187
189
  active: true,
188
- anchorSeq: match.event.seq + .1
190
+ anchored: false,
191
+ anchorSeq: Number.MAX_SAFE_INTEGER
189
192
  };
190
193
  },
191
194
  update(context, match) {
@@ -193,8 +196,10 @@ window.__ModuleLoader__.load({
193
196
  ...context.state,
194
197
  active: false
195
198
  };
199
+ if (match.event.type === "step/start" && !context.state.anchored) return context.state;
196
200
  return {
197
201
  ...context.state,
202
+ anchored: true,
198
203
  anchorSeq: match.event.seq + .1
199
204
  };
200
205
  },
@@ -362,6 +367,20 @@ window.__ModuleLoader__.load({
362
367
  position: "relative",
363
368
  minWidth: 0
364
369
  };
370
+ const settingTextInput = {
371
+ width: "100%",
372
+ minWidth: 0,
373
+ boxSizing: "border-box",
374
+ minHeight: 38,
375
+ padding: "7px 13px",
376
+ border: "1px solid var(--dsw-alias-border-l2)",
377
+ borderRadius: 10,
378
+ background: "var(--dsw-alias-bg-layer-2)",
379
+ color: "var(--dsw-alias-label-primary)",
380
+ font: "inherit",
381
+ fontSize: 13,
382
+ lineHeight: "20px"
383
+ };
365
384
  const settingSelectTrigger = {
366
385
  width: "100%",
367
386
  minHeight: 38,
@@ -481,22 +500,31 @@ window.__ModuleLoader__.load({
481
500
  const tasksPanel = {
482
501
  display: "flex",
483
502
  flexDirection: "column",
484
- height: "100%",
503
+ width: "calc(100% - 16px)",
504
+ height: "calc(100% - 16px)",
485
505
  minWidth: 0,
486
- background: "var(--dsw-alias-bg-base)"
506
+ margin: 8,
507
+ overflow: "hidden",
508
+ border: "1px solid var(--dsw-alias-border-l2)",
509
+ borderRadius: 12,
510
+ background: "var(--dsw-alias-bg-layer-1)",
511
+ boxShadow: "0 4px 16px color-mix(in srgb, #000 12%, transparent)"
487
512
  };
488
513
  const tasksHeader = {
514
+ boxSizing: "border-box",
515
+ height: 58,
516
+ flex: "none",
489
517
  display: "flex",
490
518
  alignItems: "center",
491
519
  justifyContent: "space-between",
492
- gap: 8,
493
- padding: "12px 14px",
520
+ gap: 10,
521
+ padding: "9px 12px",
494
522
  borderBottom: "1px solid var(--dsw-alias-border-l2)"
495
523
  };
496
524
  const tasksHeading = {
497
525
  display: "block",
498
526
  color: "var(--dsw-alias-label-primary)",
499
- fontSize: 14,
527
+ fontSize: 15,
500
528
  lineHeight: "20px",
501
529
  fontWeight: 600
502
530
  };
@@ -504,8 +532,8 @@ window.__ModuleLoader__.load({
504
532
  display: "block",
505
533
  marginTop: 1,
506
534
  color: "var(--dsw-alias-label-tertiary)",
507
- fontSize: 11,
508
- lineHeight: "16px"
535
+ fontSize: 12,
536
+ lineHeight: "17px"
509
537
  };
510
538
  const tasksClose = {
511
539
  width: 26,
@@ -524,7 +552,8 @@ window.__ModuleLoader__.load({
524
552
  flex: 1,
525
553
  minHeight: 0,
526
554
  overflowY: "auto",
527
- padding: "10px 12px 20px"
555
+ padding: "12px 14px 20px",
556
+ background: "var(--dsw-alias-bg-base)"
528
557
  };
529
558
  const tasksGroupHeading = {
530
559
  minHeight: 30,
@@ -538,7 +567,7 @@ window.__ModuleLoader__.load({
538
567
  alignItems: "center",
539
568
  gap: 6,
540
569
  color: "var(--dsw-alias-label-secondary)",
541
- fontSize: 12,
570
+ fontSize: 13,
542
571
  lineHeight: "20px",
543
572
  fontWeight: 600
544
573
  };
@@ -551,7 +580,7 @@ window.__ModuleLoader__.load({
551
580
  background: "transparent",
552
581
  color: "var(--dsw-alias-label-secondary)",
553
582
  font: "inherit",
554
- fontSize: 12,
583
+ fontSize: 13,
555
584
  lineHeight: "20px",
556
585
  fontWeight: 600,
557
586
  cursor: "pointer"
@@ -562,8 +591,8 @@ window.__ModuleLoader__.load({
562
591
  borderRadius: 999,
563
592
  background: "var(--dsw-alias-bg-layer-2)",
564
593
  color: "var(--dsw-alias-label-tertiary)",
565
- fontSize: 10,
566
- lineHeight: "17px",
594
+ fontSize: 11,
595
+ lineHeight: "18px",
567
596
  textAlign: "center",
568
597
  fontVariantNumeric: "tabular-nums"
569
598
  };
@@ -585,10 +614,11 @@ window.__ModuleLoader__.load({
585
614
  marginTop: 4
586
615
  };
587
616
  const taskCard = {
588
- padding: "10px 11px",
617
+ padding: "11px 12px",
589
618
  border: "1px solid var(--dsw-alias-border-l2)",
590
619
  borderRadius: 10,
591
- background: "var(--dsw-alias-bg-layer-1)"
620
+ background: "var(--dsw-alias-bg-layer-1)",
621
+ boxShadow: "0 1px 3px color-mix(in srgb, #000 7%, transparent)"
592
622
  };
593
623
  const taskCardRunning = { borderColor: "var(--dsw-alias-border-l3)" };
594
624
  const taskCardTop = {
@@ -614,8 +644,8 @@ window.__ModuleLoader__.load({
614
644
  const taskTitle = {
615
645
  margin: 0,
616
646
  color: "var(--dsw-alias-label-primary)",
617
- fontSize: 13,
618
- lineHeight: "19px",
647
+ fontSize: 14,
648
+ lineHeight: "20px",
619
649
  fontWeight: 550,
620
650
  overflowWrap: "anywhere"
621
651
  };
@@ -719,220 +749,880 @@ window.__ModuleLoader__.load({
719
749
  fontSize: 9
720
750
  };
721
751
  const tasksTurnLauncherDone = { color: "var(--dsw-alias-state-success-primary, var(--dsw-alias-label-tertiary))" };
722
- //#endregion
723
- //#region src/client/token-format.ts
724
- function formatTokenCount(tokens) {
725
- if (tokens >= 1e6) return `${Number((tokens / 1e6).toFixed(tokens >= 1e7 ? 0 : 1))}M`;
726
- if (tokens >= 1e3) return `${Number((tokens / 1e3).toFixed(tokens >= 1e5 ? 0 : 1))}K`;
727
- return String(tokens);
728
- }
729
- //#endregion
730
- //#region src/client/ClaudeTasksPanel.tsx
731
- const STATUS_LABEL = {
732
- running: "tasksRunning",
733
- completed: "tasksCompleted",
734
- failed: "tasksFailed",
735
- stopped: "tasksStopped",
736
- killed: "tasksKilled"
752
+ const heroRepositoryControls = {
753
+ position: "relative",
754
+ display: "inline-flex",
755
+ alignItems: "center",
756
+ gap: 8,
757
+ minWidth: 0
737
758
  };
738
- function visibleTaskGroups(tasks, dismissedSettledIds) {
739
- return {
740
- running: tasks.filter((task) => task.status === "running"),
741
- finished: tasks.filter((task) => task.status !== "running" && !dismissedSettledIds.has(task.taskId))
742
- };
743
- }
744
- function activitiesForTask(activities, taskId) {
745
- return activities.filter((activity) => activity.taskId === taskId);
746
- }
747
- function tasksForTurn(tasks, turn) {
748
- return tasks.filter((task) => task.originTurn === turn);
749
- }
750
- function summarizeTurnTasks(tasks) {
751
- if (tasks.length === 0) return void 0;
752
- const running = tasks.filter((task) => task.status === "running").length;
753
- const failed = tasks.filter((task) => task.status === "failed" || task.status === "stopped" || task.status === "killed").length;
754
- const completed = tasks.filter((task) => task.status === "completed").length;
755
- return {
756
- state: running > 0 ? "running" : failed > 0 ? "failed" : "completed",
757
- count: tasks.length,
758
- running,
759
- failed,
760
- completed
761
- };
762
- }
763
- function statusGlyph(status) {
764
- if (status === "running") return "●";
765
- if (status === "completed") return "✓";
766
- if (status === "stopped") return "–";
767
- return "×";
768
- }
769
- function formatDuration(ms) {
770
- if (ms < 1e3) return String(Math.max(1, Math.round(ms))) + "ms";
771
- const seconds = Math.round(ms / 1e3);
772
- if (seconds < 60) return String(seconds) + "s";
773
- const minutes = Math.floor(seconds / 60);
774
- return String(minutes) + "m " + String(seconds % 60) + "s";
775
- }
776
- function taskMeta(task, t) {
777
- const parts = [];
778
- if (task.subagentType !== void 0) parts.push(task.subagentType);
779
- else if (task.taskType !== void 0) parts.push(task.taskType);
780
- if (task.usage?.durationMs !== void 0) parts.push(formatDuration(task.usage.durationMs));
781
- if (task.usage?.totalTokens !== void 0) parts.push(t("tokens", { count: formatTokenCount(task.usage.totalTokens) }));
782
- if (task.usage?.toolUses !== void 0) parts.push(t("tasksToolUses", { count: task.usage.toolUses }));
783
- if (task.lastToolName !== void 0) parts.push(t("tasksLastTool", { tool: task.lastToolName }));
784
- return parts;
785
- }
786
- function TaskActivity({ activity, t }) {
787
- return /* @__PURE__ */ jsxs("li", {
788
- style: taskActivityItem,
789
- children: [/* @__PURE__ */ jsx("span", {
790
- style: taskActivityGlyph,
791
- "aria-hidden": "true",
792
- children: activity.isError === true ? "×" : "›"
793
- }), /* @__PURE__ */ jsxs("div", {
794
- style: taskActivityBody,
795
- children: [
796
- /* @__PURE__ */ jsx("p", {
797
- style: taskActivityTitle,
798
- children: activity.title ?? activity.kind
799
- }),
800
- activity.summary === void 0 ? null : /* @__PURE__ */ jsx("p", {
801
- style: taskActivitySummary,
802
- children: activity.summary
803
- }),
804
- activity.detail === void 0 ? null : /* @__PURE__ */ jsxs("details", {
805
- style: taskActivityDetail,
806
- children: [/* @__PURE__ */ jsx("summary", {
807
- style: taskActivityDetailSummary,
808
- children: t("detail")
809
- }), /* @__PURE__ */ jsx("pre", {
810
- style: detailCode,
811
- children: activity.detail
812
- })]
813
- })
814
- ]
815
- })]
816
- });
817
- }
818
- function TaskCard(props) {
819
- const { task, activities, t } = props;
820
- const [activityOpen, setActivityOpen] = useState(false);
821
- const running = task.status === "running";
822
- const failed = task.status === "failed" || task.status === "killed";
823
- const meta = taskMeta(task, t);
824
- return /* @__PURE__ */ jsxs("article", {
825
- style: {
826
- ...taskCard,
827
- ...running ? taskCardRunning : {}
828
- },
829
- children: [
830
- /* @__PURE__ */ jsxs("div", {
831
- style: taskCardTop,
832
- children: [/* @__PURE__ */ jsx("span", {
833
- className: running ? "dsh-claude-act-running" : void 0,
834
- style: {
835
- ...taskCardGlyph,
836
- ...running ? iconChipRunning : {},
837
- ...failed ? iconChipError : {}
838
- },
839
- "aria-hidden": "true",
840
- children: statusGlyph(task.status)
841
- }), /* @__PURE__ */ jsxs("div", {
842
- style: taskCardBody,
843
- children: [/* @__PURE__ */ jsx("p", {
844
- style: {
845
- ...taskTitle,
846
- ...failed ? { color: "var(--dsw-alias-state-error-primary)" } : {}
847
- },
848
- children: task.description
849
- }), /* @__PURE__ */ jsxs("p", {
850
- style: taskStatusLine,
851
- children: [/* @__PURE__ */ jsx("span", { children: t(STATUS_LABEL[task.status] ?? "tasksRunning") }), task.backgrounded === true ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
852
- "aria-hidden": "true",
853
- children: " · "
854
- }), /* @__PURE__ */ jsx("span", { children: t("tasksBackground") })] }) : null]
855
- })]
856
- })]
857
- }),
858
- meta.length === 0 ? null : /* @__PURE__ */ jsx("p", {
859
- style: taskMeta$1,
860
- children: meta.join(" · ")
861
- }),
862
- task.summary === void 0 || running ? null : /* @__PURE__ */ jsx("p", {
863
- style: taskSummary,
864
- children: task.summary
865
- }),
866
- activities.length === 0 ? null : /* @__PURE__ */ jsxs("div", {
867
- style: taskActivitySection,
868
- children: [/* @__PURE__ */ jsx("button", {
869
- type: "button",
870
- style: taskTextButton,
871
- "aria-expanded": activityOpen,
872
- onClick: () => setActivityOpen((value) => !value),
873
- children: activityOpen ? t("tasksHideActivity") : t("tasksViewActivity")
874
- }), activityOpen ? /* @__PURE__ */ jsx("ul", {
875
- style: taskActivityList,
876
- children: activities.map((activity) => /* @__PURE__ */ jsx(TaskActivity, {
877
- activity,
878
- t
879
- }, `${activity.turn}:${activity.step}:${activity.ordinal}`))
880
- }) : null]
881
- })
882
- ]
883
- });
884
- }
885
- function GroupHeading(props) {
886
- const { label, count, collapsed, onToggle, action } = props;
887
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", {
888
- style: tasksGroupCount,
889
- children: count
890
- })] });
891
- return /* @__PURE__ */ jsxs("div", {
892
- style: tasksGroupHeading,
893
- children: [onToggle === void 0 ? /* @__PURE__ */ jsx("div", {
894
- style: tasksGroupTitle,
895
- children: content
896
- }) : /* @__PURE__ */ jsxs("button", {
897
- type: "button",
898
- style: tasksGroupToggle,
899
- "aria-expanded": !collapsed,
900
- onClick: onToggle,
901
- children: [/* @__PURE__ */ jsx("span", {
902
- style: {
903
- ...chevron,
904
- ...collapsed === true ? {} : chevronOpen
905
- },
906
- children: "›"
907
- }), content]
908
- }), action === void 0 ? null : /* @__PURE__ */ jsx("button", {
909
- type: "button",
910
- style: taskTextButton,
911
- onClick: action.onClick,
912
- children: action.label
913
- })]
914
- });
915
- }
916
- function ClaudeTasksPanel({ useClaudeProjection, t, closeDetails, turn }) {
917
- const projection = useClaudeProjection((value) => value);
918
- const tasks = useMemo(() => tasksForTurn(projection.tasks?.tasks ?? [], turn), [projection.tasks, turn]);
919
- useEffect(() => {
920
- if (!projection.owned || tasks.length === 0) closeDetails();
921
- }, [
922
- closeDetails,
923
- projection.owned,
924
- tasks.length
925
- ]);
926
- const [finishedCollapsed, setFinishedCollapsed] = useState(false);
927
- const [dismissedSettledIds, setDismissedSettledIds] = useState(() => /* @__PURE__ */ new Set());
928
- const groups = useMemo(() => visibleTaskGroups(tasks, dismissedSettledIds), [tasks, dismissedSettledIds]);
929
- const taskActivities = useMemo(() => new Map(tasks.map((task) => [task.taskId, activitiesForTask(projection.activities, task.taskId)])), [projection.activities, tasks]);
930
- const clearFinished = () => setDismissedSettledIds((previous) => /* @__PURE__ */ new Set([...previous, ...tasks.filter((task) => task.status !== "running").map((task) => task.taskId)]));
931
- if (!projection.owned) return null;
932
- return /* @__PURE__ */ jsxs("div", {
933
- style: tasksPanel,
934
- children: [/* @__PURE__ */ jsxs("div", {
935
- style: tasksHeader,
759
+ const heroRepositoryCapsule = {
760
+ height: 30,
761
+ display: "inline-flex",
762
+ alignItems: "center",
763
+ minWidth: 0,
764
+ padding: 2,
765
+ border: "1px solid var(--dsw-alias-border-l1)",
766
+ borderRadius: 10,
767
+ background: "var(--dsw-alias-interactive-bg-base, var(--dsw-alias-bg-layer-1))",
768
+ color: "var(--dsw-alias-label-secondary)"
769
+ };
770
+ const heroBranchPicker = {
771
+ position: "relative",
772
+ display: "inline-flex",
773
+ minWidth: 0
774
+ };
775
+ const heroBranchTrigger = {
776
+ height: 26,
777
+ maxWidth: 230,
778
+ display: "inline-flex",
779
+ alignItems: "center",
780
+ gap: 6,
781
+ minWidth: 0,
782
+ padding: "0 7px",
783
+ border: "none",
784
+ borderRadius: 7,
785
+ background: "transparent",
786
+ color: "inherit",
787
+ font: "inherit",
788
+ fontSize: 12,
789
+ lineHeight: "18px",
790
+ cursor: "pointer"
791
+ };
792
+ const heroBranchName = {
793
+ minWidth: 0,
794
+ overflow: "hidden",
795
+ color: "var(--dsw-alias-label-primary)",
796
+ textOverflow: "ellipsis",
797
+ whiteSpace: "nowrap"
798
+ };
799
+ const heroBranchMenu = {
800
+ position: "absolute",
801
+ zIndex: 1100,
802
+ top: "calc(100% + 6px)",
803
+ left: 0,
804
+ width: 280,
805
+ boxSizing: "border-box",
806
+ display: "flex",
807
+ flexDirection: "column",
808
+ gap: 4,
809
+ padding: 4,
810
+ border: "1px solid var(--dsw-alias-border-inverted)",
811
+ borderRadius: 10,
812
+ background: "var(--dsw-specific-menu)",
813
+ boxShadow: "var(--dsw-shadow-lv3)"
814
+ };
815
+ const heroBranchSearch = {
816
+ height: 32,
817
+ boxSizing: "border-box",
818
+ display: "flex",
819
+ alignItems: "center",
820
+ gap: 6,
821
+ padding: "0 8px",
822
+ border: "1px solid var(--dsw-alias-border-l2)",
823
+ borderRadius: 7,
824
+ background: "var(--dsw-alias-bg-layer-1)",
825
+ color: "var(--dsw-alias-label-tertiary)"
826
+ };
827
+ const heroBranchSearchInput = {
828
+ minWidth: 0,
829
+ flex: 1,
830
+ border: "none",
831
+ outline: "none",
832
+ background: "transparent",
833
+ color: "var(--dsw-alias-label-primary)",
834
+ font: "inherit",
835
+ fontSize: 12,
836
+ lineHeight: "18px"
837
+ };
838
+ const heroBranchList = {
839
+ maxHeight: 170,
840
+ display: "flex",
841
+ flexDirection: "column",
842
+ overflowY: "auto",
843
+ overscrollBehavior: "contain"
844
+ };
845
+ const heroBranchItem = {
846
+ width: "100%",
847
+ height: 34,
848
+ minHeight: 34,
849
+ display: "flex",
850
+ alignItems: "center",
851
+ gap: 8,
852
+ padding: "0 9px",
853
+ border: "none",
854
+ borderRadius: 7,
855
+ background: "transparent",
856
+ color: "var(--dsw-alias-label-primary)",
857
+ font: "inherit",
858
+ fontSize: 12,
859
+ lineHeight: "18px",
860
+ textAlign: "left",
861
+ cursor: "pointer"
862
+ };
863
+ const heroBranchItemActive = { background: "var(--dsw-alias-interactive-bg-hover, var(--dsw-alias-bg-layer-2))" };
864
+ const heroBranchItemName = {
865
+ minWidth: 0,
866
+ flex: 1,
867
+ overflow: "hidden",
868
+ textOverflow: "ellipsis",
869
+ whiteSpace: "nowrap"
870
+ };
871
+ const heroBranchEmpty = {
872
+ height: 34,
873
+ display: "grid",
874
+ placeItems: "center",
875
+ color: "var(--dsw-alias-label-tertiary)",
876
+ fontSize: 12
877
+ };
878
+ const heroRepositoryDivider = {
879
+ width: 1,
880
+ height: 16,
881
+ flex: "none",
882
+ background: "var(--dsw-alias-border-l2)"
883
+ };
884
+ const heroWorktreeToggle = {
885
+ height: 26,
886
+ display: "inline-flex",
887
+ alignItems: "center",
888
+ gap: 6,
889
+ padding: "0 7px",
890
+ border: "none",
891
+ borderRadius: 7,
892
+ outline: "none",
893
+ background: "transparent",
894
+ color: "var(--dsw-alias-label-secondary)",
895
+ font: "inherit",
896
+ fontSize: 12,
897
+ lineHeight: "18px",
898
+ whiteSpace: "nowrap",
899
+ cursor: "pointer",
900
+ transition: "background 120ms ease, color 120ms ease, box-shadow 120ms ease"
901
+ };
902
+ const heroWorktreeToggleActive = {
903
+ background: "color-mix(in srgb, var(--dsw-static-blue-450) 10%, transparent)",
904
+ color: "var(--dsw-alias-label-primary)"
905
+ };
906
+ const heroWorktreeToggleFocused = { boxShadow: "0 0 0 2px color-mix(in srgb, var(--dsw-static-blue-450) 28%, transparent)" };
907
+ const heroWorktreeCheckbox = {
908
+ width: 15,
909
+ height: 15,
910
+ boxSizing: "border-box",
911
+ display: "grid",
912
+ placeItems: "center",
913
+ flex: "none",
914
+ border: "1px solid var(--dsw-alias-border-inverted)",
915
+ borderRadius: 4,
916
+ background: "var(--dsw-alias-bg-layer-2)",
917
+ boxShadow: "inset 0 1px 1px rgba(0, 0, 0, 0.08)",
918
+ color: "var(--dsw-alias-label-on-accent, #fff)",
919
+ transition: "border-color 120ms ease, background 120ms ease, box-shadow 120ms ease"
920
+ };
921
+ const heroWorktreeCheckboxChecked = {
922
+ borderColor: "var(--dsw-static-blue-450)",
923
+ background: "var(--dsw-static-blue-450)",
924
+ boxShadow: "0 1px 3px color-mix(in srgb, var(--dsw-static-blue-450) 35%, transparent)"
925
+ };
926
+ const heroWorktreeCheckboxIcon = {
927
+ width: 12,
928
+ height: 12,
929
+ display: "block"
930
+ };
931
+ const heroWorktreeProgressCard = {
932
+ position: "absolute",
933
+ zIndex: 1050,
934
+ top: "calc(100% + 10px)",
935
+ left: 0,
936
+ width: 320,
937
+ boxSizing: "border-box",
938
+ display: "flex",
939
+ flexDirection: "column",
940
+ gap: 12,
941
+ padding: 14,
942
+ border: "1px solid var(--dsw-alias-border-l2)",
943
+ borderRadius: 12,
944
+ background: "var(--dsw-alias-bg-layer-1)",
945
+ boxShadow: "var(--dsw-shadow-lv3)"
946
+ };
947
+ const heroWorktreeProgressHeader = {
948
+ display: "flex",
949
+ alignItems: "flex-start",
950
+ gap: 10
951
+ };
952
+ const heroWorktreeProgressSpinner = {
953
+ width: 18,
954
+ height: 18,
955
+ flex: "none",
956
+ color: "var(--dsw-static-blue-450)"
957
+ };
958
+ const heroWorktreeProgressError = {
959
+ width: 18,
960
+ height: 18,
961
+ display: "grid",
962
+ placeItems: "center",
963
+ flex: "none",
964
+ borderRadius: "50%",
965
+ background: "var(--dsw-alias-state-error-primary)",
966
+ color: "var(--dsw-alias-label-on-accent, #fff)",
967
+ fontSize: 13,
968
+ lineHeight: 1
969
+ };
970
+ const heroWorktreeProgressCopy = {
971
+ minWidth: 0,
972
+ display: "flex",
973
+ flex: 1,
974
+ flexDirection: "column",
975
+ gap: 2
976
+ };
977
+ const heroWorktreeProgressTitle = {
978
+ color: "var(--dsw-alias-label-primary)",
979
+ fontSize: 13,
980
+ lineHeight: "18px",
981
+ fontWeight: 600
982
+ };
983
+ const heroWorktreeProgressCurrent = {
984
+ color: "var(--dsw-alias-label-secondary)",
985
+ fontSize: 12,
986
+ lineHeight: "18px",
987
+ overflowWrap: "anywhere"
988
+ };
989
+ const heroWorktreeProgressDismiss = {
990
+ width: 24,
991
+ height: 24,
992
+ display: "grid",
993
+ placeItems: "center",
994
+ flex: "none",
995
+ padding: 0,
996
+ border: "none",
997
+ borderRadius: 6,
998
+ background: "transparent",
999
+ color: "var(--dsw-alias-label-tertiary)",
1000
+ font: "inherit",
1001
+ cursor: "pointer"
1002
+ };
1003
+ const heroWorktreeProgressSteps = {
1004
+ display: "flex",
1005
+ flexDirection: "column",
1006
+ gap: 7,
1007
+ paddingLeft: 2
1008
+ };
1009
+ const heroWorktreeProgressStep = {
1010
+ display: "flex",
1011
+ alignItems: "center",
1012
+ gap: 8,
1013
+ color: "var(--dsw-alias-label-secondary)",
1014
+ fontSize: 11,
1015
+ lineHeight: "16px"
1016
+ };
1017
+ const heroWorktreeProgressDot = {
1018
+ width: 14,
1019
+ height: 14,
1020
+ display: "grid",
1021
+ placeItems: "center",
1022
+ flex: "none",
1023
+ boxSizing: "border-box",
1024
+ borderRadius: "50%",
1025
+ fontSize: 9,
1026
+ lineHeight: 1
1027
+ };
1028
+ const heroWorktreeProgressDotDone = {
1029
+ background: "var(--dsw-static-blue-450)",
1030
+ color: "var(--dsw-alias-label-on-accent, #fff)"
1031
+ };
1032
+ const heroWorktreeProgressDotActive = { border: "2px solid var(--dsw-static-blue-450)" };
1033
+ const heroRepositoryStatus = {
1034
+ color: "var(--dsw-alias-label-tertiary)",
1035
+ fontSize: 11,
1036
+ whiteSpace: "nowrap"
1037
+ };
1038
+ const heroRepositoryError = {
1039
+ maxWidth: 240,
1040
+ overflow: "hidden",
1041
+ color: "var(--dsw-alias-state-error-primary)",
1042
+ fontSize: 11,
1043
+ textOverflow: "ellipsis",
1044
+ whiteSpace: "nowrap"
1045
+ };
1046
+ const repositoryBarFrame = {
1047
+ width: "calc(100% - 64px)",
1048
+ maxWidth: "var(--dsh-conversation-composer-max-width, 782px)",
1049
+ minWidth: 0,
1050
+ margin: "0 auto",
1051
+ boxSizing: "border-box"
1052
+ };
1053
+ const repositoryBar = {
1054
+ width: "100%",
1055
+ minWidth: 0,
1056
+ minHeight: 42,
1057
+ boxSizing: "border-box",
1058
+ display: "flex",
1059
+ alignItems: "center",
1060
+ gap: 9,
1061
+ padding: "7px 11px",
1062
+ border: "1px solid var(--dsw-alias-border-l2)",
1063
+ borderRadius: 11,
1064
+ background: "var(--dsw-alias-bg-layer-1)",
1065
+ color: "var(--dsw-alias-label-primary)",
1066
+ boxShadow: "0 1px 2px color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent)",
1067
+ font: "inherit",
1068
+ fontSize: 13,
1069
+ lineHeight: "20px",
1070
+ textAlign: "left"
1071
+ };
1072
+ const repositoryPrIcon = {
1073
+ width: 20,
1074
+ height: 20,
1075
+ display: "grid",
1076
+ placeItems: "center",
1077
+ flex: "none",
1078
+ borderRadius: 6,
1079
+ color: "var(--dsw-alias-state-success-primary, var(--dsw-static-blue-450))"
1080
+ };
1081
+ const repositoryPrimary = {
1082
+ minWidth: 0,
1083
+ flex: 1,
1084
+ overflow: "hidden",
1085
+ color: "var(--dsw-alias-label-primary)",
1086
+ fontSize: 13,
1087
+ fontWeight: 600,
1088
+ textOverflow: "ellipsis",
1089
+ whiteSpace: "nowrap"
1090
+ };
1091
+ const repositoryPrLinkFrame = {
1092
+ position: "relative",
1093
+ flex: "none"
1094
+ };
1095
+ const repositoryPrLink = {
1096
+ color: "var(--dsw-alias-state-success-primary)",
1097
+ fontSize: 13,
1098
+ fontWeight: 650,
1099
+ textDecoration: "none",
1100
+ cursor: "pointer"
1101
+ };
1102
+ const repositoryPrHoverCard = {
1103
+ position: "absolute",
1104
+ zIndex: 30,
1105
+ left: -34,
1106
+ bottom: "calc(100% + 14px)",
1107
+ width: 340,
1108
+ display: "flex",
1109
+ flexDirection: "column",
1110
+ gap: 10,
1111
+ padding: "13px 14px",
1112
+ border: "1px solid var(--dsw-alias-border-l2)",
1113
+ borderRadius: 12,
1114
+ background: "var(--dsw-alias-bg-layer-1)",
1115
+ boxShadow: "0 14px 38px color-mix(in srgb, #000 34%, transparent)",
1116
+ color: "var(--dsw-alias-label-primary)",
1117
+ pointerEvents: "auto"
1118
+ };
1119
+ const repositoryPrHoverTop = {
1120
+ display: "flex",
1121
+ alignItems: "center",
1122
+ gap: 7,
1123
+ minWidth: 0
1124
+ };
1125
+ const repositoryPrStateBadge = {
1126
+ flex: "none",
1127
+ display: "inline-flex",
1128
+ alignItems: "center",
1129
+ gap: 5,
1130
+ padding: "2px 8px",
1131
+ borderRadius: 999,
1132
+ background: "color-mix(in srgb, var(--dsw-alias-state-success-primary) 22%, transparent)",
1133
+ color: "var(--dsw-alias-state-success-primary)",
1134
+ fontSize: 11,
1135
+ fontWeight: 650
1136
+ };
1137
+ const repositoryPrHoverRepo = {
1138
+ minWidth: 0,
1139
+ flex: 1,
1140
+ overflow: "hidden",
1141
+ color: "var(--dsw-alias-label-tertiary)",
1142
+ fontSize: 11,
1143
+ textOverflow: "ellipsis",
1144
+ whiteSpace: "nowrap"
1145
+ };
1146
+ const repositoryPrHoverAge = {
1147
+ flex: "none",
1148
+ color: "var(--dsw-alias-label-tertiary)",
1149
+ fontSize: 11
1150
+ };
1151
+ const repositoryPrHoverTitle = {
1152
+ color: "var(--dsw-alias-label-primary)",
1153
+ fontSize: 14,
1154
+ lineHeight: "20px",
1155
+ fontWeight: 650,
1156
+ textDecoration: "underline",
1157
+ textUnderlineOffset: 2,
1158
+ cursor: "pointer"
1159
+ };
1160
+ const repositoryPrHoverBottom = {
1161
+ display: "flex",
1162
+ alignItems: "center",
1163
+ justifyContent: "space-between",
1164
+ gap: 12
1165
+ };
1166
+ const repositoryPrAuthor = {
1167
+ display: "inline-flex",
1168
+ alignItems: "center",
1169
+ gap: 6,
1170
+ color: "var(--dsw-alias-label-tertiary)",
1171
+ fontSize: 11
1172
+ };
1173
+ const repositoryPrAvatar = {
1174
+ width: 18,
1175
+ height: 18,
1176
+ display: "grid",
1177
+ placeItems: "center",
1178
+ borderRadius: 999,
1179
+ background: "var(--dsw-alias-bg-layer-2)",
1180
+ color: "var(--dsw-alias-label-secondary)",
1181
+ fontSize: 9,
1182
+ fontWeight: 700
1183
+ };
1184
+ const repositoryPrHoverStats = {
1185
+ display: "inline-flex",
1186
+ alignItems: "center",
1187
+ gap: 6,
1188
+ fontSize: 11,
1189
+ fontWeight: 650
1190
+ };
1191
+ const repositoryPrFiles = {
1192
+ padding: "2px 7px",
1193
+ borderRadius: 6,
1194
+ background: "var(--dsw-alias-bg-layer-2)",
1195
+ color: "var(--dsw-alias-label-tertiary)",
1196
+ fontWeight: 500
1197
+ };
1198
+ const repositoryRemote = {
1199
+ minWidth: 0,
1200
+ maxWidth: 116,
1201
+ overflow: "hidden",
1202
+ color: "var(--dsw-alias-label-tertiary)",
1203
+ fontSize: 12,
1204
+ textOverflow: "ellipsis",
1205
+ whiteSpace: "nowrap"
1206
+ };
1207
+ const repositoryBranch = {
1208
+ minWidth: 0,
1209
+ maxWidth: 125,
1210
+ overflow: "hidden",
1211
+ color: "var(--dsw-alias-label-secondary)",
1212
+ fontSize: 12,
1213
+ fontWeight: 550,
1214
+ textOverflow: "ellipsis",
1215
+ whiteSpace: "nowrap"
1216
+ };
1217
+ const repositoryWorktree = {
1218
+ flex: "none",
1219
+ color: "var(--dsw-alias-label-tertiary)",
1220
+ fontSize: 12
1221
+ };
1222
+ const repositoryStatusItems = {
1223
+ minWidth: 0,
1224
+ flex: 1,
1225
+ display: "flex",
1226
+ alignItems: "center",
1227
+ justifyContent: "flex-end",
1228
+ gap: 8,
1229
+ overflow: "hidden"
1230
+ };
1231
+ const repositoryItem = {
1232
+ display: "inline-flex",
1233
+ alignItems: "center",
1234
+ gap: 5,
1235
+ minWidth: 0,
1236
+ color: "var(--dsw-alias-label-tertiary)",
1237
+ fontSize: 12,
1238
+ fontWeight: 550,
1239
+ whiteSpace: "nowrap"
1240
+ };
1241
+ const repositoryItemDot = {
1242
+ width: 6,
1243
+ height: 6,
1244
+ flex: "none",
1245
+ borderRadius: 999,
1246
+ background: "currentColor"
1247
+ };
1248
+ const repositoryItemSuccess = { color: "var(--dsw-alias-state-success-primary)" };
1249
+ const repositoryItemWarning = { color: "var(--dsw-alias-state-warning-primary, #d69e2e)" };
1250
+ const repositoryItemError = { color: "var(--dsw-alias-state-error-primary)" };
1251
+ const diffTrigger = {
1252
+ flex: "none",
1253
+ display: "inline-flex",
1254
+ alignItems: "center",
1255
+ gap: 4,
1256
+ minHeight: 26,
1257
+ padding: "3px 8px",
1258
+ border: "1px solid var(--dsw-alias-border-l2)",
1259
+ borderRadius: 7,
1260
+ background: "var(--dsw-alias-bg-layer-2)",
1261
+ font: "inherit",
1262
+ fontSize: 12,
1263
+ lineHeight: "18px",
1264
+ fontWeight: 650,
1265
+ cursor: "pointer"
1266
+ };
1267
+ const diffAdd = { color: "var(--dsw-alias-state-success-primary)" };
1268
+ 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",
1277
+ border: "1px solid var(--dsw-alias-border-l2)",
1278
+ borderRadius: 12,
1279
+ background: "var(--dsw-alias-bg-layer-1)",
1280
+ boxShadow: "0 4px 16px color-mix(in srgb, #000 12%, transparent)"
1281
+ };
1282
+ const diffHeader = {
1283
+ boxSizing: "border-box",
1284
+ height: 49,
1285
+ flex: "none",
1286
+ display: "flex",
1287
+ alignItems: "center",
1288
+ justifyContent: "space-between",
1289
+ gap: 10,
1290
+ padding: "9px 12px",
1291
+ borderBottom: "1px solid var(--dsw-alias-border-l2)"
1292
+ };
1293
+ const diffHeaderTitle = {
1294
+ minWidth: 0,
1295
+ display: "flex",
1296
+ alignItems: "center",
1297
+ gap: 8,
1298
+ color: "var(--dsw-alias-label-primary)",
1299
+ fontSize: 15,
1300
+ fontWeight: 650
1301
+ };
1302
+ const diffHeaderBranch = {
1303
+ overflow: "hidden",
1304
+ color: "var(--dsw-alias-label-tertiary)",
1305
+ fontSize: 12,
1306
+ fontWeight: 500,
1307
+ textOverflow: "ellipsis",
1308
+ whiteSpace: "nowrap"
1309
+ };
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
1319
+ };
1320
+ const diffBody = {
1321
+ flex: 1,
1322
+ minHeight: 0,
1323
+ overflow: "auto",
1324
+ background: "var(--dsw-alias-bg-base)"
1325
+ };
1326
+ const diffFile = { borderBottom: "1px solid var(--dsw-alias-border-l2)" };
1327
+ const diffFileHeader = {
1328
+ width: "100%",
1329
+ minHeight: 38,
1330
+ display: "flex",
1331
+ alignItems: "center",
1332
+ gap: 7,
1333
+ padding: "7px 10px",
1334
+ border: "none",
1335
+ background: "var(--dsw-alias-bg-layer-1)",
1336
+ color: "var(--dsw-alias-label-primary)",
1337
+ font: "inherit",
1338
+ fontSize: 12,
1339
+ textAlign: "left",
1340
+ cursor: "pointer"
1341
+ };
1342
+ const diffFilePath = {
1343
+ minWidth: 0,
1344
+ flex: 1,
1345
+ overflow: "hidden",
1346
+ textOverflow: "ellipsis",
1347
+ whiteSpace: "nowrap"
1348
+ };
1349
+ const diffFileStats = {
1350
+ flex: "none",
1351
+ display: "inline-flex",
1352
+ gap: 4,
1353
+ fontSize: 12,
1354
+ fontWeight: 650
1355
+ };
1356
+ const diffCode = {
1357
+ minWidth: "max-content",
1358
+ padding: "4px 0 8px",
1359
+ background: "var(--dsw-alias-bg-base)",
1360
+ fontFamily: "var(--dsw-font-family-mono, ui-monospace, SFMono-Regular, Consolas, monospace)",
1361
+ fontSize: 13,
1362
+ lineHeight: "20px"
1363
+ };
1364
+ const diffLine = {
1365
+ minHeight: 17,
1366
+ display: "flex",
1367
+ whiteSpace: "pre"
1368
+ };
1369
+ const diffLineNumber = {
1370
+ width: 38,
1371
+ flex: "none",
1372
+ paddingRight: 8,
1373
+ color: "var(--dsw-alias-label-tertiary)",
1374
+ textAlign: "right",
1375
+ userSelect: "none"
1376
+ };
1377
+ const diffLineMarker = {
1378
+ width: 16,
1379
+ flex: "none",
1380
+ color: "inherit",
1381
+ textAlign: "center",
1382
+ userSelect: "none"
1383
+ };
1384
+ const diffLineAdd = {
1385
+ background: "color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent)",
1386
+ color: "var(--dsw-alias-state-success-primary)"
1387
+ };
1388
+ const diffLineDelete = {
1389
+ background: "color-mix(in srgb, var(--dsw-alias-state-error-primary) 13%, transparent)",
1390
+ color: "var(--dsw-alias-state-error-primary)"
1391
+ };
1392
+ const diffLineHunk = {
1393
+ background: "var(--dsw-alias-bg-layer-1)",
1394
+ color: "var(--dsw-alias-label-tertiary)",
1395
+ fontStyle: "italic"
1396
+ };
1397
+ const diffLineContext = { color: "var(--dsw-alias-label-secondary)" };
1398
+ const diffNotice = {
1399
+ margin: 10,
1400
+ padding: "9px 10px",
1401
+ borderRadius: 8,
1402
+ background: "var(--dsw-alias-bg-layer-2)",
1403
+ color: "var(--dsw-alias-label-secondary)",
1404
+ fontSize: 11,
1405
+ lineHeight: "17px"
1406
+ };
1407
+ const diffEmpty = {
1408
+ margin: 16,
1409
+ color: "var(--dsw-alias-label-tertiary)",
1410
+ fontSize: 11
1411
+ };
1412
+ //#endregion
1413
+ //#region src/client/token-format.ts
1414
+ function formatTokenCount(tokens) {
1415
+ if (tokens >= 1e6) return `${Number((tokens / 1e6).toFixed(tokens >= 1e7 ? 0 : 1))}M`;
1416
+ if (tokens >= 1e3) return `${Number((tokens / 1e3).toFixed(tokens >= 1e5 ? 0 : 1))}K`;
1417
+ return String(tokens);
1418
+ }
1419
+ //#endregion
1420
+ //#region src/client/ClaudeTasksPanel.tsx
1421
+ const STATUS_LABEL = {
1422
+ running: "tasksRunning",
1423
+ completed: "tasksCompleted",
1424
+ failed: "tasksFailed",
1425
+ stopped: "tasksStopped",
1426
+ killed: "tasksKilled"
1427
+ };
1428
+ function visibleTaskGroups(tasks, dismissedSettledIds) {
1429
+ return {
1430
+ running: tasks.filter((task) => task.status === "running"),
1431
+ finished: tasks.filter((task) => task.status !== "running" && !dismissedSettledIds.has(task.taskId))
1432
+ };
1433
+ }
1434
+ function activitiesForTask(activities, taskId) {
1435
+ return activities.filter((activity) => activity.taskId === taskId);
1436
+ }
1437
+ function tasksForTurn(tasks, turn) {
1438
+ return tasks.filter((task) => task.originTurn === turn);
1439
+ }
1440
+ function summarizeTurnTasks(tasks) {
1441
+ if (tasks.length === 0) return void 0;
1442
+ const running = tasks.filter((task) => task.status === "running").length;
1443
+ const failed = tasks.filter((task) => task.status === "failed" || task.status === "stopped" || task.status === "killed").length;
1444
+ const completed = tasks.filter((task) => task.status === "completed").length;
1445
+ return {
1446
+ state: running > 0 ? "running" : failed > 0 ? "failed" : "completed",
1447
+ count: tasks.length,
1448
+ running,
1449
+ failed,
1450
+ completed
1451
+ };
1452
+ }
1453
+ function statusGlyph(status) {
1454
+ if (status === "running") return "●";
1455
+ if (status === "completed") return "✓";
1456
+ if (status === "stopped") return "–";
1457
+ return "×";
1458
+ }
1459
+ function formatDuration(ms) {
1460
+ if (ms < 1e3) return String(Math.max(1, Math.round(ms))) + "ms";
1461
+ const seconds = Math.round(ms / 1e3);
1462
+ if (seconds < 60) return String(seconds) + "s";
1463
+ const minutes = Math.floor(seconds / 60);
1464
+ return String(minutes) + "m " + String(seconds % 60) + "s";
1465
+ }
1466
+ function taskMeta(task, t) {
1467
+ const parts = [];
1468
+ if (task.subagentType !== void 0) parts.push(task.subagentType);
1469
+ else if (task.taskType !== void 0) parts.push(task.taskType);
1470
+ if (task.usage?.durationMs !== void 0) parts.push(formatDuration(task.usage.durationMs));
1471
+ if (task.usage?.totalTokens !== void 0) parts.push(t("tokens", { count: formatTokenCount(task.usage.totalTokens) }));
1472
+ if (task.usage?.toolUses !== void 0) parts.push(t("tasksToolUses", { count: task.usage.toolUses }));
1473
+ if (task.lastToolName !== void 0) parts.push(t("tasksLastTool", { tool: task.lastToolName }));
1474
+ return parts;
1475
+ }
1476
+ function TaskActivity({ activity, t }) {
1477
+ return /* @__PURE__ */ jsxs("li", {
1478
+ style: taskActivityItem,
1479
+ children: [/* @__PURE__ */ jsx("span", {
1480
+ style: taskActivityGlyph,
1481
+ "aria-hidden": "true",
1482
+ children: activity.isError === true ? "×" : "›"
1483
+ }), /* @__PURE__ */ jsxs("div", {
1484
+ style: taskActivityBody,
1485
+ children: [
1486
+ /* @__PURE__ */ jsx("p", {
1487
+ style: taskActivityTitle,
1488
+ children: activity.title ?? activity.kind
1489
+ }),
1490
+ activity.summary === void 0 ? null : /* @__PURE__ */ jsx("p", {
1491
+ style: taskActivitySummary,
1492
+ children: activity.summary
1493
+ }),
1494
+ activity.detail === void 0 ? null : /* @__PURE__ */ jsxs("details", {
1495
+ style: taskActivityDetail,
1496
+ children: [/* @__PURE__ */ jsx("summary", {
1497
+ style: taskActivityDetailSummary,
1498
+ children: t("detail")
1499
+ }), /* @__PURE__ */ jsx("pre", {
1500
+ style: detailCode,
1501
+ children: activity.detail
1502
+ })]
1503
+ })
1504
+ ]
1505
+ })]
1506
+ });
1507
+ }
1508
+ function TaskCard(props) {
1509
+ const { task, activities, t } = props;
1510
+ const [activityOpen, setActivityOpen] = useState(false);
1511
+ const running = task.status === "running";
1512
+ const failed = task.status === "failed" || task.status === "killed";
1513
+ const meta = taskMeta(task, t);
1514
+ return /* @__PURE__ */ jsxs("article", {
1515
+ style: {
1516
+ ...taskCard,
1517
+ ...running ? taskCardRunning : {}
1518
+ },
1519
+ children: [
1520
+ /* @__PURE__ */ jsxs("div", {
1521
+ style: taskCardTop,
1522
+ children: [/* @__PURE__ */ jsx("span", {
1523
+ className: running ? "dsh-claude-act-running" : void 0,
1524
+ style: {
1525
+ ...taskCardGlyph,
1526
+ ...running ? iconChipRunning : {},
1527
+ ...failed ? iconChipError : {}
1528
+ },
1529
+ "aria-hidden": "true",
1530
+ children: statusGlyph(task.status)
1531
+ }), /* @__PURE__ */ jsxs("div", {
1532
+ style: taskCardBody,
1533
+ children: [/* @__PURE__ */ jsx("p", {
1534
+ style: {
1535
+ ...taskTitle,
1536
+ ...failed ? { color: "var(--dsw-alias-state-error-primary)" } : {}
1537
+ },
1538
+ children: task.description
1539
+ }), /* @__PURE__ */ jsxs("p", {
1540
+ style: taskStatusLine,
1541
+ children: [/* @__PURE__ */ jsx("span", { children: t(STATUS_LABEL[task.status] ?? "tasksRunning") }), task.backgrounded === true ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1542
+ "aria-hidden": "true",
1543
+ children: " · "
1544
+ }), /* @__PURE__ */ jsx("span", { children: t("tasksBackground") })] }) : null]
1545
+ })]
1546
+ })]
1547
+ }),
1548
+ meta.length === 0 ? null : /* @__PURE__ */ jsx("p", {
1549
+ style: taskMeta$1,
1550
+ children: meta.join(" · ")
1551
+ }),
1552
+ task.summary === void 0 || running ? null : /* @__PURE__ */ jsx("p", {
1553
+ style: taskSummary,
1554
+ children: task.summary
1555
+ }),
1556
+ activities.length === 0 ? null : /* @__PURE__ */ jsxs("div", {
1557
+ style: taskActivitySection,
1558
+ children: [/* @__PURE__ */ jsx("button", {
1559
+ type: "button",
1560
+ style: taskTextButton,
1561
+ "aria-expanded": activityOpen,
1562
+ onClick: () => setActivityOpen((value) => !value),
1563
+ children: activityOpen ? t("tasksHideActivity") : t("tasksViewActivity")
1564
+ }), activityOpen ? /* @__PURE__ */ jsx("ul", {
1565
+ style: taskActivityList,
1566
+ children: activities.map((activity) => /* @__PURE__ */ jsx(TaskActivity, {
1567
+ activity,
1568
+ t
1569
+ }, `${activity.turn}:${activity.step}:${activity.ordinal}`))
1570
+ }) : null]
1571
+ })
1572
+ ]
1573
+ });
1574
+ }
1575
+ function GroupHeading(props) {
1576
+ const { label, count, collapsed, onToggle, action } = props;
1577
+ const content = /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", { children: label }), /* @__PURE__ */ jsx("span", {
1578
+ style: tasksGroupCount,
1579
+ children: count
1580
+ })] });
1581
+ return /* @__PURE__ */ jsxs("div", {
1582
+ style: tasksGroupHeading,
1583
+ children: [onToggle === void 0 ? /* @__PURE__ */ jsx("div", {
1584
+ style: tasksGroupTitle,
1585
+ children: content
1586
+ }) : /* @__PURE__ */ jsxs("button", {
1587
+ type: "button",
1588
+ style: tasksGroupToggle,
1589
+ "aria-expanded": !collapsed,
1590
+ onClick: onToggle,
1591
+ children: [/* @__PURE__ */ jsx("span", {
1592
+ style: {
1593
+ ...chevron,
1594
+ ...collapsed === true ? {} : chevronOpen
1595
+ },
1596
+ children: "›"
1597
+ }), content]
1598
+ }), action === void 0 ? null : /* @__PURE__ */ jsx("button", {
1599
+ type: "button",
1600
+ style: taskTextButton,
1601
+ onClick: action.onClick,
1602
+ children: action.label
1603
+ })]
1604
+ });
1605
+ }
1606
+ function ClaudeTasksPanel({ useClaudeProjection, t, closeDetails, turn }) {
1607
+ const projection = useClaudeProjection((value) => value);
1608
+ const tasks = useMemo(() => tasksForTurn(projection.tasks?.tasks ?? [], turn), [projection.tasks, turn]);
1609
+ useEffect(() => {
1610
+ if (!projection.owned || tasks.length === 0) closeDetails();
1611
+ }, [
1612
+ closeDetails,
1613
+ projection.owned,
1614
+ tasks.length
1615
+ ]);
1616
+ const [finishedCollapsed, setFinishedCollapsed] = useState(false);
1617
+ const [dismissedSettledIds, setDismissedSettledIds] = useState(() => /* @__PURE__ */ new Set());
1618
+ const groups = useMemo(() => visibleTaskGroups(tasks, dismissedSettledIds), [tasks, dismissedSettledIds]);
1619
+ const taskActivities = useMemo(() => new Map(tasks.map((task) => [task.taskId, activitiesForTask(projection.activities, task.taskId)])), [projection.activities, tasks]);
1620
+ const clearFinished = () => setDismissedSettledIds((previous) => /* @__PURE__ */ new Set([...previous, ...tasks.filter((task) => task.status !== "running").map((task) => task.taskId)]));
1621
+ if (!projection.owned) return null;
1622
+ return /* @__PURE__ */ jsxs("div", {
1623
+ style: tasksPanel,
1624
+ children: [/* @__PURE__ */ jsxs("div", {
1625
+ style: tasksHeader,
936
1626
  children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("span", {
937
1627
  style: tasksHeading,
938
1628
  children: t("tasksPanelTurn")
@@ -1177,7 +1867,13 @@ window.__ModuleLoader__.load({
1177
1867
  return Array.isArray(settings) && settings.every((setting) => {
1178
1868
  if (typeof setting !== "object" || setting === null || Array.isArray(setting)) return false;
1179
1869
  const item = setting;
1180
- return typeof item.key === "string" && item.kind === "select" && typeof item.value === "string" && ["new-session", "restart"].includes(String(item.effect)) && Array.isArray(item.options) && item.options.every((option) => typeof option === "object" && option !== null && typeof option.value === "string" && typeof option.label === "string" && [
1870
+ if (typeof item.key !== "string" || typeof item.value !== "string" || ![
1871
+ "new-session",
1872
+ "next-worktree",
1873
+ "restart"
1874
+ ].includes(String(item.effect))) return false;
1875
+ if (item.kind === "text") return typeof item.maxLength === "number" && item.maxLength > 0;
1876
+ return item.kind === "select" && Array.isArray(item.options) && item.options.every((option) => typeof option === "object" && option !== null && typeof option.value === "string" && typeof option.label === "string" && [
1181
1877
  "built-in",
1182
1878
  "user",
1183
1879
  "configured"
@@ -1187,6 +1883,36 @@ window.__ModuleLoader__.load({
1187
1883
  function value(status, detail) {
1188
1884
  return detail === void 0 ? status : `${status} · ${detail}`;
1189
1885
  }
1886
+ function GlobalSettingText({ setting, disabled, onChange }) {
1887
+ const [draft, setDraft] = useState(setting.value);
1888
+ useEffect(() => {
1889
+ setDraft(setting.value);
1890
+ }, [setting.value]);
1891
+ const save = () => {
1892
+ if (draft !== setting.value) onChange(draft);
1893
+ };
1894
+ return /* @__PURE__ */ jsx("input", {
1895
+ type: "text",
1896
+ value: draft,
1897
+ maxLength: setting.maxLength,
1898
+ disabled,
1899
+ style: settingTextInput,
1900
+ onChange: (event) => {
1901
+ setDraft(event.currentTarget.value);
1902
+ },
1903
+ onBlur: save,
1904
+ onKeyDown: (event) => {
1905
+ if (event.key === "Enter") {
1906
+ event.preventDefault();
1907
+ save();
1908
+ event.currentTarget.blur();
1909
+ } else if (event.key === "Escape") {
1910
+ setDraft(setting.value);
1911
+ event.currentTarget.blur();
1912
+ }
1913
+ }
1914
+ });
1915
+ }
1190
1916
  function GlobalSettingSelect({ setting, disabled, onChange }) {
1191
1917
  const [open, setOpen] = useState(false);
1192
1918
  const [activeIndex, setActiveIndex] = useState(0);
@@ -1435,181 +2161,1246 @@ window.__ModuleLoader__.load({
1435
2161
  children: busy ? t("refreshing") : t("doctor")
1436
2162
  })]
1437
2163
  }),
1438
- rows.length === 0 ? /* @__PURE__ */ jsx("p", {
2164
+ rows.length === 0 ? /* @__PURE__ */ jsx("p", {
2165
+ style: notice,
2166
+ children: t("diagnosticsLoading")
2167
+ }) : /* @__PURE__ */ jsx("div", {
2168
+ style: diagnosticGrid,
2169
+ children: rows.flatMap(([label, rowValue]) => [/* @__PURE__ */ jsx("span", {
2170
+ style: diagnosticLabel,
2171
+ children: label
2172
+ }, `${label}-label`), /* @__PURE__ */ jsx("span", {
2173
+ style: diagnosticValue,
2174
+ children: rowValue
2175
+ }, `${label}-value`)])
2176
+ }),
2177
+ error === void 0 ? null : /* @__PURE__ */ jsxs("p", {
2178
+ role: "alert",
2179
+ style: {
2180
+ ...notice,
2181
+ color: "var(--dsw-alias-state-error-primary)"
2182
+ },
2183
+ children: [
2184
+ t("error"),
2185
+ ": ",
2186
+ error
2187
+ ]
2188
+ })
2189
+ ]
2190
+ }),
2191
+ /* @__PURE__ */ jsxs("section", {
2192
+ style: settingsCard,
2193
+ children: [
2194
+ /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
2195
+ style: settingsSectionHeading,
2196
+ children: t("globalSettings")
2197
+ }), /* @__PURE__ */ jsx("p", {
2198
+ style: settingsBody,
2199
+ children: t("globalSettingsBody")
2200
+ })] }),
2201
+ globalSettings === void 0 ? /* @__PURE__ */ jsx("p", {
2202
+ style: notice,
2203
+ children: t("globalSettingsLoading")
2204
+ }) : globalSettings.settings.map((setting) => /* @__PURE__ */ jsxs("div", {
2205
+ style: diagnosticGrid,
2206
+ children: [/* @__PURE__ */ jsx("span", {
2207
+ style: diagnosticLabel,
2208
+ children: setting.key === "outputStyle" ? t("outputStyle") : setting.key === "worktreeBranchPrefix" ? t("worktreeBranchPrefix") : setting.key
2209
+ }), setting.kind === "select" ? /* @__PURE__ */ jsx(GlobalSettingSelect, {
2210
+ setting,
2211
+ disabled: globalSettingsBusy,
2212
+ onChange: (nextValue) => {
2213
+ requestGlobalSettings({ [setting.key]: nextValue });
2214
+ }
2215
+ }) : /* @__PURE__ */ jsx(GlobalSettingText, {
2216
+ setting,
2217
+ disabled: globalSettingsBusy,
2218
+ onChange: (nextValue) => {
2219
+ requestGlobalSettings({ [setting.key]: nextValue });
2220
+ }
2221
+ })]
2222
+ }, setting.key)),
2223
+ globalSettings?.settings.some((setting) => setting.effect === "new-session") === true ? /* @__PURE__ */ jsx("p", {
2224
+ style: notice,
2225
+ children: t("globalSettingsNewSession")
2226
+ }) : null,
2227
+ globalSettings?.settings.some((setting) => setting.effect === "next-worktree") === true ? /* @__PURE__ */ jsx("p", {
2228
+ style: notice,
2229
+ children: t("worktreeBranchPrefixEffect")
2230
+ }) : null,
2231
+ globalSettingsError === void 0 ? null : /* @__PURE__ */ jsxs("p", {
2232
+ role: "alert",
2233
+ style: {
2234
+ ...notice,
2235
+ color: "var(--dsw-alias-state-error-primary)"
2236
+ },
2237
+ children: [
2238
+ t("globalSettingsError"),
2239
+ ": ",
2240
+ globalSettingsError
2241
+ ]
2242
+ })
2243
+ ]
2244
+ }),
2245
+ /* @__PURE__ */ jsxs("section", {
2246
+ style: settingsCard,
2247
+ children: [
2248
+ /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
2249
+ style: settingsSectionHeading,
2250
+ children: t("pluginUpdate")
2251
+ }), /* @__PURE__ */ jsx("p", {
2252
+ style: settingsBody,
2253
+ children: t("pluginUpdateBody")
2254
+ })] }),
2255
+ updateStatus === void 0 ? /* @__PURE__ */ jsx("p", {
2256
+ style: notice,
2257
+ children: t("updateNotChecked")
2258
+ }) : /* @__PURE__ */ jsxs("div", {
2259
+ style: diagnosticGrid,
2260
+ children: [
2261
+ /* @__PURE__ */ jsx("span", {
2262
+ style: diagnosticLabel,
2263
+ children: t("installedVersion")
2264
+ }),
2265
+ /* @__PURE__ */ jsx("span", {
2266
+ style: diagnosticValue,
2267
+ children: updateStatus.currentVersion
2268
+ }),
2269
+ /* @__PURE__ */ jsx("span", {
2270
+ style: diagnosticLabel,
2271
+ children: t("installSource")
2272
+ }),
2273
+ /* @__PURE__ */ jsx("span", {
2274
+ style: diagnosticValue,
2275
+ children: t(`updateSource_${updateStatus.source}`)
2276
+ }),
2277
+ /* @__PURE__ */ jsx("span", {
2278
+ style: diagnosticLabel,
2279
+ children: t("updateStatus")
2280
+ }),
2281
+ /* @__PURE__ */ jsx("span", {
2282
+ style: diagnosticValue,
2283
+ children: t(`updateState_${updateStatus.state}`)
2284
+ }),
2285
+ updateStatus.latestVersion === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
2286
+ style: diagnosticLabel,
2287
+ children: t("latestVersion")
2288
+ }), /* @__PURE__ */ jsx("span", {
2289
+ style: diagnosticValue,
2290
+ children: updateStatus.latestVersion
2291
+ })] })
2292
+ ]
2293
+ }),
2294
+ updateStatus?.message === void 0 ? null : /* @__PURE__ */ jsx("p", {
1439
2295
  style: notice,
1440
- children: t("diagnosticsLoading")
1441
- }) : /* @__PURE__ */ jsx("div", {
1442
- style: diagnosticGrid,
1443
- children: rows.flatMap(([label, rowValue]) => [/* @__PURE__ */ jsx("span", {
1444
- style: diagnosticLabel,
1445
- children: label
1446
- }, `${label}-label`), /* @__PURE__ */ jsx("span", {
1447
- style: diagnosticValue,
1448
- children: rowValue
1449
- }, `${label}-value`)])
2296
+ children: updateStatus.message
1450
2297
  }),
1451
- error === void 0 ? null : /* @__PURE__ */ jsxs("p", {
2298
+ updateStatus?.restartRequired !== true ? null : /* @__PURE__ */ jsx("p", {
2299
+ style: notice,
2300
+ children: t("restartRequired")
2301
+ }),
2302
+ updateError === void 0 ? null : /* @__PURE__ */ jsxs("p", {
1452
2303
  role: "alert",
1453
2304
  style: {
1454
2305
  ...notice,
1455
2306
  color: "var(--dsw-alias-state-error-primary)"
1456
2307
  },
1457
2308
  children: [
1458
- t("error"),
2309
+ t("updateError"),
1459
2310
  ": ",
1460
- error
2311
+ updateError
1461
2312
  ]
2313
+ }),
2314
+ /* @__PURE__ */ jsxs("div", {
2315
+ style: settingsActions,
2316
+ children: [/* @__PURE__ */ jsx("button", {
2317
+ type: "button",
2318
+ style: button,
2319
+ onClick: () => {
2320
+ requestUpdate("check");
2321
+ },
2322
+ disabled: updateBusy !== void 0,
2323
+ children: updateBusy === "check" ? t("checkingUpdates") : t("checkUpdates")
2324
+ }), /* @__PURE__ */ jsx("button", {
2325
+ type: "button",
2326
+ style: primaryButton,
2327
+ onClick: () => {
2328
+ requestUpdate("update");
2329
+ },
2330
+ disabled: updateBusy !== void 0 || updateStatus?.canUpdate !== true,
2331
+ children: updateBusy === "update" ? t("updatingPlugin") : t("updatePlugin")
2332
+ })]
1462
2333
  })
1463
2334
  ]
1464
2335
  }),
1465
2336
  /* @__PURE__ */ jsxs("section", {
1466
2337
  style: settingsCard,
2338
+ children: [/* @__PURE__ */ jsx("h3", {
2339
+ style: settingsSectionHeading,
2340
+ children: t("security")
2341
+ }), /* @__PURE__ */ jsx("p", {
2342
+ style: settingsBody,
2343
+ children: t("securityBody")
2344
+ })]
2345
+ })
2346
+ ]
2347
+ });
2348
+ }
2349
+ //#endregion
2350
+ //#region src/client/ClaudeRepositoryStatus.tsx
2351
+ function StatusItem({ label, tone = "neutral" }) {
2352
+ const toneStyle = tone === "success" ? repositoryItemSuccess : tone === "warning" ? repositoryItemWarning : tone === "error" ? repositoryItemError : {};
2353
+ return /* @__PURE__ */ jsxs("span", {
2354
+ style: {
2355
+ ...repositoryItem,
2356
+ ...toneStyle
2357
+ },
2358
+ children: [/* @__PURE__ */ jsx("span", {
2359
+ style: repositoryItemDot,
2360
+ "aria-hidden": "true"
2361
+ }), label]
2362
+ });
2363
+ }
2364
+ function PullRequestIcon({ size = 16 }) {
2365
+ return /* @__PURE__ */ jsxs("svg", {
2366
+ width: size,
2367
+ height: size,
2368
+ viewBox: "0 0 16 16",
2369
+ fill: "none",
2370
+ stroke: "currentColor",
2371
+ strokeWidth: "1.8",
2372
+ strokeLinecap: "round",
2373
+ strokeLinejoin: "round",
2374
+ "aria-hidden": "true",
2375
+ children: [
2376
+ /* @__PURE__ */ jsx("circle", {
2377
+ cx: "4",
2378
+ cy: "3",
2379
+ r: "1.6"
2380
+ }),
2381
+ /* @__PURE__ */ jsx("circle", {
2382
+ cx: "4",
2383
+ cy: "13",
2384
+ r: "1.6"
2385
+ }),
2386
+ /* @__PURE__ */ jsx("circle", {
2387
+ cx: "12",
2388
+ cy: "13",
2389
+ r: "1.6"
2390
+ }),
2391
+ /* @__PURE__ */ jsx("path", { d: "M4 4.6v6.8" }),
2392
+ /* @__PURE__ */ jsx("path", { d: "M7.5 3H9a3 3 0 0 1 3 3v5.4" })
2393
+ ]
2394
+ });
2395
+ }
2396
+ function repositoryName(remote) {
2397
+ return remote?.split("/").at(-1);
2398
+ }
2399
+ function relativeAge(value) {
2400
+ if (value === void 0) return void 0;
2401
+ const elapsedHours = Math.max(0, Math.floor((Date.now() - Date.parse(value)) / 36e5));
2402
+ if (!Number.isFinite(elapsedHours)) return void 0;
2403
+ if (elapsedHours < 1) return "<1h";
2404
+ if (elapsedHours < 24) return `${elapsedHours}h`;
2405
+ const days = Math.floor(elapsedHours / 24);
2406
+ return days < 30 ? `${days}d` : `${Math.floor(days / 30)}mo`;
2407
+ }
2408
+ function PullRequestHoverCard({ repository, t }) {
2409
+ const pullRequest = repository.pullRequest;
2410
+ if (pullRequest === void 0) return null;
2411
+ const age = relativeAge(pullRequest.createdAt);
2412
+ return /* @__PURE__ */ jsxs("span", {
2413
+ role: "tooltip",
2414
+ style: repositoryPrHoverCard,
2415
+ children: [
2416
+ /* @__PURE__ */ jsxs("span", {
2417
+ style: repositoryPrHoverTop,
1467
2418
  children: [
1468
- /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
1469
- style: settingsSectionHeading,
1470
- children: t("globalSettings")
1471
- }), /* @__PURE__ */ jsx("p", {
1472
- style: settingsBody,
1473
- children: t("globalSettingsBody")
1474
- })] }),
1475
- globalSettings === void 0 ? /* @__PURE__ */ jsx("p", {
1476
- style: notice,
1477
- children: t("globalSettingsLoading")
1478
- }) : globalSettings.settings.map((setting) => /* @__PURE__ */ jsxs("div", {
1479
- style: diagnosticGrid,
1480
- children: [/* @__PURE__ */ jsx("span", {
1481
- style: diagnosticLabel,
1482
- children: setting.key === "outputStyle" ? t("outputStyle") : setting.key
1483
- }), /* @__PURE__ */ jsx(GlobalSettingSelect, {
1484
- setting,
1485
- disabled: globalSettingsBusy,
1486
- onChange: (nextValue) => {
1487
- requestGlobalSettings({ [setting.key]: nextValue });
2419
+ /* @__PURE__ */ jsxs("span", {
2420
+ style: repositoryPrStateBadge,
2421
+ children: [/* @__PURE__ */ jsx(PullRequestIcon, { size: 13 }), t(`repositoryState_${pullRequest.state}`)]
2422
+ }),
2423
+ /* @__PURE__ */ jsxs("span", {
2424
+ style: repositoryPrHoverRepo,
2425
+ children: [
2426
+ repositoryName(repository.remote),
2427
+ " #",
2428
+ pullRequest.number
2429
+ ]
2430
+ }),
2431
+ age === void 0 ? null : /* @__PURE__ */ jsx("span", {
2432
+ style: repositoryPrHoverAge,
2433
+ children: age
2434
+ })
2435
+ ]
2436
+ }),
2437
+ /* @__PURE__ */ jsx("a", {
2438
+ href: pullRequest.url,
2439
+ target: "_blank",
2440
+ rel: "noopener noreferrer",
2441
+ style: repositoryPrHoverTitle,
2442
+ children: pullRequest.title
2443
+ }),
2444
+ /* @__PURE__ */ jsxs("span", {
2445
+ style: repositoryPrHoverBottom,
2446
+ children: [pullRequest.author === void 0 ? /* @__PURE__ */ jsx("span", {}) : /* @__PURE__ */ jsxs("span", {
2447
+ style: repositoryPrAuthor,
2448
+ children: [/* @__PURE__ */ jsx("span", {
2449
+ style: repositoryPrAvatar,
2450
+ children: pullRequest.author.slice(0, 1).toUpperCase()
2451
+ }), pullRequest.author]
2452
+ }), /* @__PURE__ */ jsxs("span", {
2453
+ style: repositoryPrHoverStats,
2454
+ children: [/* @__PURE__ */ jsxs("span", { children: [
2455
+ /* @__PURE__ */ jsxs("span", {
2456
+ style: diffAdd,
2457
+ children: ["+", repository.diff?.additions ?? 0]
2458
+ }),
2459
+ " ",
2460
+ /* @__PURE__ */ jsxs("span", {
2461
+ style: diffDelete,
2462
+ children: ["−", repository.diff?.deletions ?? 0]
2463
+ })
2464
+ ] }), /* @__PURE__ */ jsx("span", {
2465
+ style: repositoryPrFiles,
2466
+ children: t("diffFilesShort", { count: repository.diff?.files ?? 0 })
2467
+ })]
2468
+ })]
2469
+ })
2470
+ ]
2471
+ });
2472
+ }
2473
+ function PullRequestLink({ repository, t }) {
2474
+ const [hovered, setHovered] = useState(false);
2475
+ const closeTimer = useRef();
2476
+ const pullRequest = repository.pullRequest;
2477
+ const open = () => {
2478
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2479
+ closeTimer.current = void 0;
2480
+ setHovered(true);
2481
+ };
2482
+ const scheduleClose = () => {
2483
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2484
+ closeTimer.current = setTimeout(() => {
2485
+ closeTimer.current = void 0;
2486
+ setHovered(false);
2487
+ }, 350);
2488
+ };
2489
+ useEffect(() => () => {
2490
+ if (closeTimer.current !== void 0) clearTimeout(closeTimer.current);
2491
+ }, []);
2492
+ if (pullRequest === void 0) return null;
2493
+ return /* @__PURE__ */ jsxs("span", {
2494
+ style: repositoryPrLinkFrame,
2495
+ onMouseEnter: open,
2496
+ onMouseLeave: scheduleClose,
2497
+ onFocus: open,
2498
+ onBlur: (event) => {
2499
+ if (!event.currentTarget.contains(event.relatedTarget)) scheduleClose();
2500
+ },
2501
+ children: [hovered ? /* @__PURE__ */ jsx("span", {
2502
+ onMouseEnter: open,
2503
+ onMouseLeave: scheduleClose,
2504
+ children: /* @__PURE__ */ jsx(PullRequestHoverCard, {
2505
+ repository,
2506
+ t
2507
+ })
2508
+ }) : null, /* @__PURE__ */ jsxs("a", {
2509
+ href: pullRequest.url,
2510
+ target: "_blank",
2511
+ rel: "noopener noreferrer",
2512
+ style: repositoryPrLink,
2513
+ "aria-label": t("repositoryOpenPr", { number: pullRequest.number }),
2514
+ children: ["#", pullRequest.number]
2515
+ })]
2516
+ });
2517
+ }
2518
+ function ClaudeRepositoryStatus({ sessionId, useSessions, useClaudeProjection, t, openDiff }) {
2519
+ const blank = useSessions((value) => value.byId[sessionId]?.blank === true);
2520
+ const projection = useClaudeProjection((value) => value);
2521
+ const repository = projection.repository;
2522
+ if (blank || !projection.owned || repository === void 0) return null;
2523
+ const branch = repository.detached === true ? t("repositoryDetached") : repository.branch ?? t("repositoryUnknownBranch");
2524
+ const pullRequest = repository.pullRequest;
2525
+ if (repository.status !== "ready") return /* @__PURE__ */ jsx("div", {
2526
+ style: repositoryBarFrame,
2527
+ children: /* @__PURE__ */ jsxs("div", {
2528
+ 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
+ })]
2536
+ })
2537
+ });
2538
+ return /* @__PURE__ */ jsx("div", {
2539
+ style: repositoryBarFrame,
2540
+ children: /* @__PURE__ */ jsxs("div", {
2541
+ style: repositoryBar,
2542
+ children: [
2543
+ /* @__PURE__ */ jsx("span", {
2544
+ style: repositoryPrIcon,
2545
+ children: /* @__PURE__ */ jsx(PullRequestIcon, {})
2546
+ }),
2547
+ /* @__PURE__ */ jsx(PullRequestLink, {
2548
+ repository,
2549
+ t
2550
+ }),
2551
+ repository.remote === void 0 ? null : /* @__PURE__ */ jsx("span", {
2552
+ style: repositoryRemote,
2553
+ children: repositoryName(repository.remote)
2554
+ }),
2555
+ /* @__PURE__ */ jsx("span", {
2556
+ style: repositoryBranch,
2557
+ children: branch
2558
+ }),
2559
+ repository.worktree === true ? /* @__PURE__ */ jsx("span", {
2560
+ style: repositoryWorktree,
2561
+ children: t("repositoryWorktree")
2562
+ }) : null,
2563
+ /* @__PURE__ */ jsxs("span", {
2564
+ style: repositoryStatusItems,
2565
+ children: [repository.diff !== void 0 && (repository.diff.additions > 0 || repository.diff.deletions > 0) ? /* @__PURE__ */ jsxs("button", {
2566
+ 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
+ })] })]
2584
+ })
2585
+ ]
2586
+ })
2587
+ });
2588
+ }
2589
+ //#endregion
2590
+ //#region src/client/ClaudeDiffPanel.tsx
2591
+ function pathFromHeader(line) {
2592
+ return /^diff --git a\/(.+) b\/(.+)$/u.exec(line)?.[2];
2593
+ }
2594
+ function parseUnifiedDiff(patch) {
2595
+ const files = [];
2596
+ let path;
2597
+ let lines = [];
2598
+ const flush = () => {
2599
+ if (path === void 0) return;
2600
+ const content = lines.filter((line) => !line.startsWith("diff --git ") && !line.startsWith("index ") && !line.startsWith("--- ") && !line.startsWith("+++ "));
2601
+ files.push({
2602
+ path,
2603
+ additions: content.filter((line) => line.startsWith("+")).length,
2604
+ deletions: content.filter((line) => line.startsWith("-")).length,
2605
+ lines: content
2606
+ });
2607
+ };
2608
+ for (const line of patch.split(/\r?\n/u)) {
2609
+ const nextPath = pathFromHeader(line);
2610
+ if (nextPath !== void 0) {
2611
+ flush();
2612
+ path = nextPath;
2613
+ lines = [line];
2614
+ } else if (path !== void 0) lines.push(line);
2615
+ }
2616
+ flush();
2617
+ return files;
2618
+ }
2619
+ function numberDiffLines(lines) {
2620
+ const numbered = [];
2621
+ let oldLine = 0;
2622
+ let newLine = 0;
2623
+ let previousOldEnd;
2624
+ for (const line of lines) {
2625
+ const hunk = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/u.exec(line);
2626
+ if (hunk !== null) {
2627
+ const nextOld = Number(hunk[1]);
2628
+ if (previousOldEnd !== void 0 && nextOld > previousOldEnd) numbered.push({
2629
+ line: `${nextOld - previousOldEnd} unmodified lines`,
2630
+ kind: "collapsed"
2631
+ });
2632
+ oldLine = nextOld;
2633
+ newLine = Number(hunk[3]);
2634
+ previousOldEnd = nextOld + Number(hunk[2] ?? 1);
2635
+ numbered.push({
2636
+ line,
2637
+ kind: "hunk"
2638
+ });
2639
+ continue;
2640
+ }
2641
+ if (line.startsWith("+")) {
2642
+ numbered.push({
2643
+ line,
2644
+ kind: "add",
2645
+ newLine
2646
+ });
2647
+ newLine += 1;
2648
+ } else if (line.startsWith("-")) {
2649
+ numbered.push({
2650
+ line,
2651
+ kind: "delete",
2652
+ oldLine
2653
+ });
2654
+ oldLine += 1;
2655
+ } else {
2656
+ numbered.push({
2657
+ line,
2658
+ kind: "context",
2659
+ oldLine,
2660
+ newLine
2661
+ });
2662
+ oldLine += 1;
2663
+ newLine += 1;
2664
+ }
2665
+ }
2666
+ return numbered;
2667
+ }
2668
+ function DiffLine({ entry }) {
2669
+ const style = entry.kind === "add" ? diffLineAdd : entry.kind === "delete" ? diffLineDelete : entry.kind === "hunk" || entry.kind === "collapsed" ? diffLineHunk : diffLineContext;
2670
+ 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
+ return /* @__PURE__ */ jsxs("div", {
2672
+ style: {
2673
+ ...diffLine,
2674
+ ...style
2675
+ },
2676
+ children: [
2677
+ /* @__PURE__ */ jsx("span", {
2678
+ style: diffLineNumber,
2679
+ children: lineNumber
2680
+ }),
2681
+ /* @__PURE__ */ jsx("span", {
2682
+ style: diffLineMarker,
2683
+ children: entry.kind === "add" ? "+" : entry.kind === "delete" ? "−" : entry.kind === "collapsed" ? "⌄" : " "
2684
+ }),
2685
+ /* @__PURE__ */ jsx("span", { children: entry.kind === "collapsed" ? entry.line : entry.line.slice(entry.kind === "hunk" ? 0 : 1) })
2686
+ ]
2687
+ });
2688
+ }
2689
+ function DiffFileSection({ file, initiallyOpen }) {
2690
+ const [open, setOpen] = useState(initiallyOpen);
2691
+ return /* @__PURE__ */ jsxs("section", {
2692
+ style: diffFile,
2693
+ children: [/* @__PURE__ */ jsxs("button", {
2694
+ type: "button",
2695
+ style: diffFileHeader,
2696
+ "aria-expanded": open,
2697
+ onClick: () => setOpen((value) => !value),
2698
+ children: [
2699
+ /* @__PURE__ */ jsx("span", {
2700
+ style: {
2701
+ ...chevron,
2702
+ ...open ? chevronOpen : {}
2703
+ },
2704
+ children: "›"
2705
+ }),
2706
+ /* @__PURE__ */ jsx("span", {
2707
+ style: diffFilePath,
2708
+ children: file.path
2709
+ }),
2710
+ /* @__PURE__ */ jsxs("span", {
2711
+ style: diffFileStats,
2712
+ children: [/* @__PURE__ */ jsxs("span", {
2713
+ style: diffAdd,
2714
+ children: ["+", file.additions]
2715
+ }), /* @__PURE__ */ jsxs("span", {
2716
+ style: diffDelete,
2717
+ children: ["−", file.deletions]
2718
+ })]
2719
+ })
2720
+ ]
2721
+ }), open ? /* @__PURE__ */ jsx("div", {
2722
+ style: diffCode,
2723
+ children: numberDiffLines(file.lines).map((entry, index) => /* @__PURE__ */ jsx(DiffLine, { entry }, `${index}:${entry.line}`))
2724
+ }) : null]
2725
+ });
2726
+ }
2727
+ function ClaudeDiffPanel({ useClaudeProjection, t, closeDetails }) {
2728
+ const projection = useClaudeProjection((value) => value);
2729
+ const repository = projection.repository;
2730
+ const diff = repository?.diff;
2731
+ const files = useMemo(() => parseUnifiedDiff(diff?.patch ?? ""), [diff?.patch]);
2732
+ useEffect(() => {
2733
+ if (!projection.owned || repository?.status !== "ready" || diff === void 0) closeDetails();
2734
+ }, [
2735
+ closeDetails,
2736
+ diff,
2737
+ projection.owned,
2738
+ repository?.status
2739
+ ]);
2740
+ if (!projection.owned || repository?.status !== "ready" || diff === void 0) return null;
2741
+ const branch = repository.detached === true ? t("repositoryDetached") : repository.branch ?? t("repositoryUnknownBranch");
2742
+ return /* @__PURE__ */ jsxs("div", {
2743
+ style: diffPanel,
2744
+ 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
+ ]
2760
+ }), /* @__PURE__ */ jsx("button", {
2761
+ type: "button",
2762
+ style: tasksClose,
2763
+ "aria-label": t("diffClose"),
2764
+ onClick: closeDetails,
2765
+ children: "×"
2766
+ })]
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
+ })
2795
+ ]
2796
+ });
2797
+ }
2798
+ //#endregion
2799
+ //#region src/client/hero-dom-bridge.ts
2800
+ const PORTAL_ATTRIBUTE = "data-dsh-claude-hero-controls";
2801
+ function normalizedText(element) {
2802
+ return (element.textContent ?? "").replace(/\s+/gu, " ").trim();
2803
+ }
2804
+ function isClaudePresetText(value) {
2805
+ return /^claude(?: code)?$/iu.test(value.replace(/\s+/gu, " ").trim());
2806
+ }
2807
+ function directChildContaining(parent, descendant) {
2808
+ return Array.from(parent.children).find((child) => child === descendant || child.contains(descendant));
2809
+ }
2810
+ /** Locate rc.8's hero preset seat without relying on hashed CSS module names. */
2811
+ function locateClaudePresetSeat(root = document) {
2812
+ const heroes = Array.from(root.querySelectorAll("[data-phase=\"hero\"]"));
2813
+ if (heroes.length !== 1) return void 0;
2814
+ const hero = heroes[0];
2815
+ if (hero === void 0) return void 0;
2816
+ const presetButtons = Array.from(hero.querySelectorAll("button[aria-haspopup=\"menu\"]")).filter((button) => button.getAttribute("aria-label") === null && isClaudePresetText(normalizedText(button)));
2817
+ if (presetButtons.length !== 1) return void 0;
2818
+ const preset = presetButtons[0];
2819
+ if (preset === void 0) return void 0;
2820
+ let row = preset.parentElement;
2821
+ while (row !== null && row !== hero) {
2822
+ if (Array.from(row.querySelectorAll("button[aria-haspopup=\"menu\"][aria-label]")).length === 1) {
2823
+ const seat = directChildContaining(row, preset);
2824
+ if (seat !== void 0) return {
2825
+ hero,
2826
+ seat
2827
+ };
2828
+ }
2829
+ row = row.parentElement;
2830
+ }
2831
+ }
2832
+ function ensureClaudeHeroPortal(seat) {
2833
+ const sibling = seat.nextElementSibling;
2834
+ if (sibling instanceof HTMLElement && sibling.hasAttribute(PORTAL_ATTRIBUTE)) return sibling;
2835
+ const portal = document.createElement("span");
2836
+ portal.setAttribute(PORTAL_ATTRIBUTE, "");
2837
+ seat.insertAdjacentElement("afterend", portal);
2838
+ return portal;
2839
+ }
2840
+ function removeClaudeHeroPortals(root = document) {
2841
+ for (const portal of root.querySelectorAll(`[${PORTAL_ATTRIBUTE}]`)) portal.remove();
2842
+ }
2843
+ //#endregion
2844
+ //#region src/client/repository-setup-api.ts
2845
+ const HOST_STAGES = /* @__PURE__ */ new Set([
2846
+ "inspecting",
2847
+ "fetching",
2848
+ "creating-worktree",
2849
+ "saving-worktree",
2850
+ "switching-branch"
2851
+ ]);
2852
+ function record$1(value) {
2853
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : void 0;
2854
+ }
2855
+ function setupResult(value) {
2856
+ const item = record$1(value);
2857
+ if (item === void 0 || item.mode !== "checkout" && item.mode !== "worktree" || typeof item.root !== "string" || typeof item.path !== "string" || typeof item.branch !== "string" || item.leaseId !== void 0 && typeof item.leaseId !== "string") return void 0;
2858
+ return item;
2859
+ }
2860
+ function parseRepositorySetupEvent(line, onProgress) {
2861
+ const event = record$1(JSON.parse(line));
2862
+ if (event?.type === "progress" && typeof event.stage === "string" && HOST_STAGES.has(event.stage)) {
2863
+ onProgress(event.stage);
2864
+ return;
2865
+ }
2866
+ if (event?.type === "complete") {
2867
+ const result = setupResult(event.result);
2868
+ if (result !== void 0) return result;
2869
+ }
2870
+ if (event?.type === "error" && typeof event.message === "string") throw new Error(event.message);
2871
+ throw new Error("Invalid repository setup progress response.");
2872
+ }
2873
+ async function response(pending) {
2874
+ const result = await pending;
2875
+ const body = await result.json();
2876
+ if (!result.ok) {
2877
+ const error = body;
2878
+ throw new Error(error.message ?? error.error ?? "Repository setup failed.");
2879
+ }
2880
+ return body;
2881
+ }
2882
+ function loadRepositoryBranches(cwd, signal) {
2883
+ return response(fetch(`${CLAUDE_REPOSITORY_SETUP_PATH}/branches?cwd=${encodeURIComponent(cwd)}`, {
2884
+ method: "GET",
2885
+ credentials: "same-origin",
2886
+ headers: { accept: "application/json" },
2887
+ ...signal === void 0 ? {} : { signal }
2888
+ }));
2889
+ }
2890
+ async function prepareRepository(cwd, branch, worktree, branchName, onProgress = () => {}) {
2891
+ const result = await fetch(CLAUDE_REPOSITORY_SETUP_PATH, {
2892
+ method: "POST",
2893
+ credentials: "same-origin",
2894
+ headers: {
2895
+ accept: "application/x-ndjson",
2896
+ "content-type": "application/json"
2897
+ },
2898
+ body: JSON.stringify({
2899
+ cwd,
2900
+ branch,
2901
+ worktree,
2902
+ ...branchName === void 0 ? {} : { branchName }
2903
+ })
2904
+ });
2905
+ if (!result.ok) {
2906
+ const body = await result.json();
2907
+ throw new Error(body.message ?? body.error ?? "Repository setup failed.");
2908
+ }
2909
+ if (result.body === null) throw new Error("Repository setup progress stream is unavailable.");
2910
+ const reader = result.body.getReader();
2911
+ const decoder = new TextDecoder();
2912
+ let buffer = "";
2913
+ let completed;
2914
+ while (true) {
2915
+ const chunk = await reader.read();
2916
+ buffer += decoder.decode(chunk.value, { stream: !chunk.done });
2917
+ const lines = buffer.split("\n");
2918
+ buffer = lines.pop() ?? "";
2919
+ for (const line of lines) {
2920
+ if (line.trim().length === 0) continue;
2921
+ const value = parseRepositorySetupEvent(line, onProgress);
2922
+ if (value !== void 0) completed = value;
2923
+ }
2924
+ if (chunk.done) break;
2925
+ }
2926
+ if (buffer.trim().length > 0) {
2927
+ const value = parseRepositorySetupEvent(buffer, onProgress);
2928
+ if (value !== void 0) completed = value;
2929
+ }
2930
+ if (completed === void 0) throw new Error("Repository setup progress ended before completion.");
2931
+ return completed;
2932
+ }
2933
+ async function bindRepositoryLease(leaseId, sessionId) {
2934
+ await response(fetch(`${CLAUDE_REPOSITORY_SETUP_PATH}/bind`, {
2935
+ method: "POST",
2936
+ credentials: "same-origin",
2937
+ headers: {
2938
+ accept: "application/json",
2939
+ "content-type": "application/json"
2940
+ },
2941
+ body: JSON.stringify({
2942
+ leaseId,
2943
+ sessionId
2944
+ })
2945
+ }));
2946
+ }
2947
+ //#endregion
2948
+ //#region src/client/ClaudeHeroRepositoryControls.tsx
2949
+ function shouldInterceptKey(event) {
2950
+ if (event.key !== "Enter" || event.shiftKey || event.repeat || event.isComposing) return false;
2951
+ const target = event.target;
2952
+ return target instanceof HTMLTextAreaElement && target.closest("[data-phase=\"hero\"]") !== null;
2953
+ }
2954
+ function shouldInterceptClick(event) {
2955
+ const target = event.target;
2956
+ if (!(target instanceof Element)) return false;
2957
+ const button = target.closest("[data-phase=\"hero\"] [data-composer-card] button");
2958
+ if (button === null || button.disabled) return false;
2959
+ const card = button.closest("[data-composer-card]");
2960
+ return (card === null ? [] : Array.from(card.querySelectorAll("button:not(:disabled)"))).at(-1) === button;
2961
+ }
2962
+ function repositoryBranchOptions(branches) {
2963
+ const local = new Set(branches.branches);
2964
+ return [...branches.branches, ...branches.remoteBranches.filter((branch) => !local.has(branch))];
2965
+ }
2966
+ function selectedBranchFirst(branches, selected) {
2967
+ return branches.includes(selected) ? [selected, ...branches.filter((branch) => branch !== selected)] : branches;
2968
+ }
2969
+ function filterRepositoryBranches(branches, query) {
2970
+ const normalized = query.trim().toLocaleLowerCase();
2971
+ return normalized.length === 0 ? branches : branches.filter((branch) => branch.toLocaleLowerCase().includes(normalized));
2972
+ }
2973
+ function branchMenuNavigationIndex(current, count, key) {
2974
+ if (count <= 0) return 0;
2975
+ if (key === "Home") return 0;
2976
+ if (key === "End") return count - 1;
2977
+ return (current + (key === "ArrowDown" ? 1 : -1) + count) % count;
2978
+ }
2979
+ const WORKTREE_PROGRESS_STAGES = [
2980
+ "inspecting",
2981
+ "fetching",
2982
+ "creating-worktree",
2983
+ "saving-worktree",
2984
+ "creating-workspace",
2985
+ "starting-session",
2986
+ "transferring-draft",
2987
+ "submitting"
2988
+ ];
2989
+ const PROGRESS_LABEL_KEYS = {
2990
+ inspecting: "repositoryProgress_inspecting",
2991
+ fetching: "repositoryProgress_fetching",
2992
+ "creating-worktree": "repositoryProgress_creating-worktree",
2993
+ "saving-worktree": "repositoryProgress_saving-worktree",
2994
+ "switching-branch": "repositoryProgress_switching-branch",
2995
+ "creating-workspace": "repositoryProgress_creating-workspace",
2996
+ "starting-session": "repositoryProgress_starting-session",
2997
+ "transferring-draft": "repositoryProgress_transferring-draft",
2998
+ submitting: "repositoryProgress_submitting"
2999
+ };
3000
+ function progressLabelKey(stage) {
3001
+ return PROGRESS_LABEL_KEYS[stage];
3002
+ }
3003
+ function WorktreeProgressCard({ stage, error, t, onDismiss }) {
3004
+ const current = WORKTREE_PROGRESS_STAGES.indexOf(stage);
3005
+ const visible = WORKTREE_PROGRESS_STAGES.slice(0, Math.max(0, current) + 1);
3006
+ return /* @__PURE__ */ jsxs("div", {
3007
+ role: error === void 0 ? "status" : "alert",
3008
+ "aria-live": "polite",
3009
+ style: heroWorktreeProgressCard,
3010
+ children: [/* @__PURE__ */ jsxs("div", {
3011
+ style: heroWorktreeProgressHeader,
3012
+ children: [
3013
+ error === void 0 ? /* @__PURE__ */ jsxs("svg", {
3014
+ "aria-hidden": "true",
3015
+ viewBox: "0 0 20 20",
3016
+ style: heroWorktreeProgressSpinner,
3017
+ children: [/* @__PURE__ */ jsx("circle", {
3018
+ cx: "10",
3019
+ cy: "10",
3020
+ r: "8",
3021
+ fill: "none",
3022
+ stroke: "currentColor",
3023
+ strokeOpacity: "0.2",
3024
+ strokeWidth: "2"
3025
+ }), /* @__PURE__ */ jsx("path", {
3026
+ d: "M10 2a8 8 0 0 1 8 8",
3027
+ fill: "none",
3028
+ stroke: "currentColor",
3029
+ strokeLinecap: "round",
3030
+ strokeWidth: "2",
3031
+ children: /* @__PURE__ */ jsx("animateTransform", {
3032
+ attributeName: "transform",
3033
+ type: "rotate",
3034
+ from: "0 10 10",
3035
+ to: "360 10 10",
3036
+ dur: "0.8s",
3037
+ repeatCount: "indefinite"
3038
+ })
3039
+ })]
3040
+ }) : /* @__PURE__ */ jsx("span", {
3041
+ "aria-hidden": "true",
3042
+ style: heroWorktreeProgressError,
3043
+ children: "×"
3044
+ }),
3045
+ /* @__PURE__ */ jsxs("div", {
3046
+ style: heroWorktreeProgressCopy,
3047
+ children: [/* @__PURE__ */ jsx("strong", {
3048
+ style: heroWorktreeProgressTitle,
3049
+ children: error === void 0 ? t("repositoryProgressTitle") : t("repositoryProgressFailed")
3050
+ }), /* @__PURE__ */ jsx("span", {
3051
+ style: heroWorktreeProgressCurrent,
3052
+ children: error ?? t(progressLabelKey(stage))
3053
+ })]
3054
+ }),
3055
+ error === void 0 ? null : /* @__PURE__ */ jsx("button", {
3056
+ type: "button",
3057
+ style: heroWorktreeProgressDismiss,
3058
+ onClick: onDismiss,
3059
+ "aria-label": t("repositoryProgressDismiss"),
3060
+ children: "×"
3061
+ })
3062
+ ]
3063
+ }), /* @__PURE__ */ jsx("div", {
3064
+ style: heroWorktreeProgressSteps,
3065
+ children: visible.map((item, index) => /* @__PURE__ */ jsxs("span", {
3066
+ style: heroWorktreeProgressStep,
3067
+ children: [/* @__PURE__ */ jsx("span", {
3068
+ "aria-hidden": "true",
3069
+ style: {
3070
+ ...heroWorktreeProgressDot,
3071
+ ...index < visible.length - 1 ? heroWorktreeProgressDotDone : heroWorktreeProgressDotActive
3072
+ },
3073
+ children: index < visible.length - 1 ? "✓" : ""
3074
+ }), t(progressLabelKey(item))]
3075
+ }, item))
3076
+ })]
3077
+ });
3078
+ }
3079
+ function ClaudeHeroRepositoryCapsule({ branches, selected, worktree, busy, menuOpen, worktreeLabel, searchPlaceholder, emptySearchLabel, onMenuOpenChange, onSelect, onWorktreeChange }) {
3080
+ const pickerRef = useRef(null);
3081
+ const searchRef = useRef(null);
3082
+ const optionRefs = useRef([]);
3083
+ const [query, setQuery] = useState("");
3084
+ const [activeIndex, setActiveIndex] = useState(0);
3085
+ const [worktreeHovered, setWorktreeHovered] = useState(false);
3086
+ const [worktreeFocused, setWorktreeFocused] = useState(false);
3087
+ const ordered = useMemo(() => selectedBranchFirst(branches, selected), [branches, selected]);
3088
+ const filtered = useMemo(() => filterRepositoryBranches(ordered, query), [ordered, query]);
3089
+ useEffect(() => {
3090
+ if (!menuOpen) {
3091
+ setQuery("");
3092
+ setActiveIndex(0);
3093
+ return;
3094
+ }
3095
+ setActiveIndex(0);
3096
+ searchRef.current?.focus();
3097
+ const closeOnOutsidePointer = (event) => {
3098
+ if (event.target instanceof Node && pickerRef.current?.contains(event.target) !== true) onMenuOpenChange(false);
3099
+ };
3100
+ document.addEventListener("pointerdown", closeOnOutsidePointer);
3101
+ return () => {
3102
+ document.removeEventListener("pointerdown", closeOnOutsidePointer);
3103
+ };
3104
+ }, [menuOpen, onMenuOpenChange]);
3105
+ useEffect(() => {
3106
+ setActiveIndex(0);
3107
+ }, [query]);
3108
+ useEffect(() => {
3109
+ if (menuOpen) optionRefs.current[activeIndex]?.scrollIntoView({ block: "nearest" });
3110
+ }, [activeIndex, menuOpen]);
3111
+ const chooseActive = () => {
3112
+ const branch = filtered[activeIndex];
3113
+ if (branch !== void 0) onSelect(branch);
3114
+ };
3115
+ const handleMenuKeyDown = (event) => {
3116
+ if (event.key === "ArrowDown" || event.key === "ArrowUp" || event.key === "Home" || event.key === "End") {
3117
+ event.preventDefault();
3118
+ const key = event.key;
3119
+ setActiveIndex((current) => branchMenuNavigationIndex(current, filtered.length, key));
3120
+ } else if (event.key === "Enter") {
3121
+ event.preventDefault();
3122
+ chooseActive();
3123
+ } else if (event.key === "Escape") {
3124
+ event.preventDefault();
3125
+ onMenuOpenChange(false);
3126
+ }
3127
+ };
3128
+ return /* @__PURE__ */ jsxs("span", {
3129
+ style: heroRepositoryCapsule,
3130
+ children: [
3131
+ /* @__PURE__ */ jsxs("span", {
3132
+ ref: pickerRef,
3133
+ style: heroBranchPicker,
3134
+ children: [/* @__PURE__ */ jsxs("button", {
3135
+ type: "button",
3136
+ style: heroBranchTrigger,
3137
+ "aria-haspopup": "menu",
3138
+ "aria-expanded": menuOpen,
3139
+ disabled: busy,
3140
+ onClick: () => {
3141
+ onMenuOpenChange(!menuOpen);
3142
+ },
3143
+ children: [
3144
+ /* @__PURE__ */ jsx(IconBranchOutline16, {}),
3145
+ /* @__PURE__ */ jsx("span", {
3146
+ style: heroBranchName,
3147
+ children: selected
3148
+ }),
3149
+ /* @__PURE__ */ jsx(IconChevronDownOutline14, {})
3150
+ ]
3151
+ }), menuOpen ? /* @__PURE__ */ jsxs("span", {
3152
+ role: "menu",
3153
+ "aria-activedescendant": filtered[activeIndex] === void 0 ? void 0 : `claude-branch-option-${activeIndex}`,
3154
+ style: heroBranchMenu,
3155
+ onKeyDown: handleMenuKeyDown,
3156
+ children: [/* @__PURE__ */ jsxs("label", {
3157
+ style: heroBranchSearch,
3158
+ children: [/* @__PURE__ */ jsx(IconSearchOutline16, {}), /* @__PURE__ */ jsx("input", {
3159
+ ref: searchRef,
3160
+ type: "search",
3161
+ value: query,
3162
+ placeholder: searchPlaceholder,
3163
+ "aria-label": searchPlaceholder,
3164
+ style: heroBranchSearchInput,
3165
+ onChange: (event) => {
3166
+ setQuery(event.currentTarget.value);
1488
3167
  }
1489
3168
  })]
1490
- }, setting.key)),
1491
- globalSettings?.settings.some((setting) => setting.effect === "new-session") === true ? /* @__PURE__ */ jsx("p", {
1492
- style: notice,
1493
- children: t("globalSettingsNewSession")
1494
- }) : null,
1495
- globalSettingsError === void 0 ? null : /* @__PURE__ */ jsxs("p", {
1496
- role: "alert",
1497
- style: {
1498
- ...notice,
1499
- color: "var(--dsw-alias-state-error-primary)"
1500
- },
1501
- children: [
1502
- t("globalSettingsError"),
1503
- ": ",
1504
- globalSettingsError
1505
- ]
1506
- })
1507
- ]
1508
- }),
1509
- /* @__PURE__ */ jsxs("section", {
1510
- style: settingsCard,
1511
- children: [
1512
- /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
1513
- style: settingsSectionHeading,
1514
- children: t("pluginUpdate")
1515
- }), /* @__PURE__ */ jsx("p", {
1516
- style: settingsBody,
1517
- children: t("pluginUpdateBody")
1518
- })] }),
1519
- updateStatus === void 0 ? /* @__PURE__ */ jsx("p", {
1520
- style: notice,
1521
- children: t("updateNotChecked")
1522
- }) : /* @__PURE__ */ jsxs("div", {
1523
- style: diagnosticGrid,
1524
- children: [
1525
- /* @__PURE__ */ jsx("span", {
1526
- style: diagnosticLabel,
1527
- children: t("installedVersion")
1528
- }),
1529
- /* @__PURE__ */ jsx("span", {
1530
- style: diagnosticValue,
1531
- children: updateStatus.currentVersion
1532
- }),
1533
- /* @__PURE__ */ jsx("span", {
1534
- style: diagnosticLabel,
1535
- children: t("installSource")
1536
- }),
1537
- /* @__PURE__ */ jsx("span", {
1538
- style: diagnosticValue,
1539
- children: t(`updateSource_${updateStatus.source}`)
1540
- }),
1541
- /* @__PURE__ */ jsx("span", {
1542
- style: diagnosticLabel,
1543
- children: t("updateStatus")
1544
- }),
1545
- /* @__PURE__ */ jsx("span", {
1546
- style: diagnosticValue,
1547
- children: t(`updateState_${updateStatus.state}`)
1548
- }),
1549
- updateStatus.latestVersion === void 0 ? null : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
1550
- style: diagnosticLabel,
1551
- children: t("latestVersion")
1552
- }), /* @__PURE__ */ jsx("span", {
1553
- style: diagnosticValue,
1554
- children: updateStatus.latestVersion
1555
- })] })
1556
- ]
1557
- }),
1558
- updateStatus?.message === void 0 ? null : /* @__PURE__ */ jsx("p", {
1559
- style: notice,
1560
- children: updateStatus.message
1561
- }),
1562
- updateStatus?.restartRequired !== true ? null : /* @__PURE__ */ jsx("p", {
1563
- style: notice,
1564
- children: t("restartRequired")
1565
- }),
1566
- updateError === void 0 ? null : /* @__PURE__ */ jsxs("p", {
1567
- role: "alert",
1568
- style: {
1569
- ...notice,
1570
- color: "var(--dsw-alias-state-error-primary)"
1571
- },
1572
- children: [
1573
- t("updateError"),
1574
- ": ",
1575
- updateError
1576
- ]
1577
- }),
1578
- /* @__PURE__ */ jsxs("div", {
1579
- style: settingsActions,
1580
- children: [/* @__PURE__ */ jsx("button", {
1581
- type: "button",
1582
- style: button,
1583
- onClick: () => {
1584
- requestUpdate("check");
3169
+ }), /* @__PURE__ */ jsx("span", {
3170
+ style: heroBranchList,
3171
+ children: filtered.length === 0 ? /* @__PURE__ */ jsx("span", {
3172
+ style: heroBranchEmpty,
3173
+ children: emptySearchLabel
3174
+ }) : filtered.map((branch, index) => /* @__PURE__ */ jsxs("button", {
3175
+ ref: (element) => {
3176
+ optionRefs.current[index] = element;
1585
3177
  },
1586
- disabled: updateBusy !== void 0,
1587
- children: updateBusy === "check" ? t("checkingUpdates") : t("checkUpdates")
1588
- }), /* @__PURE__ */ jsx("button", {
3178
+ id: `claude-branch-option-${index}`,
1589
3179
  type: "button",
1590
- style: primaryButton,
3180
+ role: "menuitem",
3181
+ "aria-current": branch === selected ? "true" : void 0,
3182
+ "data-active": index === activeIndex ? "true" : void 0,
3183
+ style: {
3184
+ ...heroBranchItem,
3185
+ ...index === activeIndex ? heroBranchItemActive : {}
3186
+ },
3187
+ onMouseEnter: () => {
3188
+ setActiveIndex(index);
3189
+ },
1591
3190
  onClick: () => {
1592
- requestUpdate("update");
3191
+ onSelect(branch);
1593
3192
  },
1594
- disabled: updateBusy !== void 0 || updateStatus?.canUpdate !== true,
1595
- children: updateBusy === "update" ? t("updatingPlugin") : t("updatePlugin")
1596
- })]
1597
- })
1598
- ]
3193
+ children: [/* @__PURE__ */ jsx("span", {
3194
+ style: heroBranchItemName,
3195
+ children: branch
3196
+ }), branch === selected ? /* @__PURE__ */ jsx(IconCheckOutline14, {}) : null]
3197
+ }, branch))
3198
+ })]
3199
+ }) : null]
1599
3200
  }),
1600
- /* @__PURE__ */ jsxs("section", {
1601
- style: settingsCard,
1602
- children: [/* @__PURE__ */ jsx("h3", {
1603
- style: settingsSectionHeading,
1604
- children: t("security")
1605
- }), /* @__PURE__ */ jsx("p", {
1606
- style: settingsBody,
1607
- children: t("securityBody")
1608
- })]
3201
+ /* @__PURE__ */ jsx("span", {
3202
+ "aria-hidden": "true",
3203
+ style: heroRepositoryDivider
3204
+ }),
3205
+ /* @__PURE__ */ jsxs("button", {
3206
+ type: "button",
3207
+ role: "checkbox",
3208
+ "aria-checked": worktree,
3209
+ disabled: busy,
3210
+ style: {
3211
+ ...heroWorktreeToggle,
3212
+ ...worktree || worktreeHovered ? heroWorktreeToggleActive : {},
3213
+ ...worktreeFocused ? heroWorktreeToggleFocused : {}
3214
+ },
3215
+ onMouseEnter: () => {
3216
+ setWorktreeHovered(true);
3217
+ },
3218
+ onMouseLeave: () => {
3219
+ setWorktreeHovered(false);
3220
+ },
3221
+ onFocus: () => {
3222
+ setWorktreeFocused(true);
3223
+ },
3224
+ onBlur: () => {
3225
+ setWorktreeFocused(false);
3226
+ },
3227
+ onClick: () => {
3228
+ onWorktreeChange(!worktree);
3229
+ },
3230
+ children: [/* @__PURE__ */ jsx("span", {
3231
+ "aria-hidden": "true",
3232
+ style: {
3233
+ ...heroWorktreeCheckbox,
3234
+ ...worktree ? heroWorktreeCheckboxChecked : {}
3235
+ },
3236
+ children: worktree ? /* @__PURE__ */ jsx("svg", {
3237
+ viewBox: "0 0 12 12",
3238
+ style: heroWorktreeCheckboxIcon,
3239
+ children: /* @__PURE__ */ jsx("path", {
3240
+ d: "m2.5 6.2 2.1 2.1 4.9-5",
3241
+ fill: "none",
3242
+ stroke: "currentColor",
3243
+ strokeLinecap: "round",
3244
+ strokeLinejoin: "round",
3245
+ strokeWidth: "1.8"
3246
+ })
3247
+ }) : null
3248
+ }), worktreeLabel]
1609
3249
  })
1610
3250
  ]
1611
3251
  });
1612
3252
  }
3253
+ function ClaudeHeroRepositoryControls({ sessionId, useSessions, useWorkspaces, input, t, prepare }) {
3254
+ const cwd = useSessions((state) => state.byId[sessionId]?.cwd);
3255
+ const workspacePath = useWorkspaces((state) => state.items.find((item) => item.sessionIds.includes(sessionId))?.path);
3256
+ const [portal, setPortal] = useState();
3257
+ const [branches, setBranches] = useState();
3258
+ const [selected, setSelected] = useState("");
3259
+ const [worktree, setWorktree] = useState(false);
3260
+ const [menuOpen, setMenuOpen] = useState(false);
3261
+ const [busy, setBusy] = useState(false);
3262
+ const [progressStage, setProgressStage] = useState();
3263
+ const [progressError, setProgressError] = useState();
3264
+ const [error, setError] = useState();
3265
+ const pendingRef = useRef(false);
3266
+ const path = workspacePath ?? cwd;
3267
+ useEffect(() => {
3268
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
3269
+ let scheduled = false;
3270
+ const reconcile = () => {
3271
+ scheduled = false;
3272
+ const target = locateClaudePresetSeat();
3273
+ if (target === void 0) {
3274
+ removeClaudeHeroPortals();
3275
+ setPortal(void 0);
3276
+ return;
3277
+ }
3278
+ setPortal(ensureClaudeHeroPortal(target.seat));
3279
+ };
3280
+ const schedule = () => {
3281
+ if (scheduled) return;
3282
+ scheduled = true;
3283
+ queueMicrotask(reconcile);
3284
+ };
3285
+ reconcile();
3286
+ const observer = new MutationObserver(schedule);
3287
+ observer.observe(document.body, {
3288
+ childList: true,
3289
+ subtree: true,
3290
+ characterData: true,
3291
+ attributes: true,
3292
+ attributeFilter: ["data-phase"]
3293
+ });
3294
+ return () => {
3295
+ observer.disconnect();
3296
+ removeClaudeHeroPortals();
3297
+ };
3298
+ }, [sessionId]);
3299
+ useEffect(() => {
3300
+ setBranches(void 0);
3301
+ setSelected("");
3302
+ setWorktree(false);
3303
+ setMenuOpen(false);
3304
+ setProgressStage(void 0);
3305
+ setProgressError(void 0);
3306
+ setError(void 0);
3307
+ if (portal === void 0 || path === void 0) return;
3308
+ const controller = new AbortController();
3309
+ loadRepositoryBranches(path, controller.signal).then((value) => {
3310
+ setBranches(value);
3311
+ setSelected(value.current ?? value.branches[0] ?? "");
3312
+ }, (reason) => {
3313
+ if (!controller.signal.aborted) setError(reason instanceof Error ? reason.message : String(reason));
3314
+ });
3315
+ return () => {
3316
+ controller.abort();
3317
+ };
3318
+ }, [
3319
+ portal,
3320
+ path,
3321
+ sessionId
3322
+ ]);
3323
+ const availableBranches = branches === void 0 ? [] : repositoryBranchOptions(branches);
3324
+ const changed = branches !== void 0 && selected.length > 0 && (worktree || selected !== branches.current);
3325
+ useEffect(() => {
3326
+ if (!changed || portal === void 0 || busy) return;
3327
+ const submit = (event) => {
3328
+ if (pendingRef.current || input.draft.trim().length === 0) return;
3329
+ if (!(event instanceof KeyboardEvent ? shouldInterceptKey(event) : shouldInterceptClick(event))) return;
3330
+ event.preventDefault();
3331
+ event.stopPropagation();
3332
+ pendingRef.current = true;
3333
+ setBusy(true);
3334
+ setProgressError(void 0);
3335
+ setProgressStage(worktree ? "inspecting" : void 0);
3336
+ setError(void 0);
3337
+ prepare(branches.root, selected, worktree, (stage) => {
3338
+ if (worktree) setProgressStage(stage);
3339
+ }).catch((reason) => {
3340
+ const message = reason instanceof Error ? reason.message : String(reason);
3341
+ if (worktree) setProgressError(message);
3342
+ else setError(message);
3343
+ }).finally(() => {
3344
+ pendingRef.current = false;
3345
+ setBusy(false);
3346
+ });
3347
+ };
3348
+ document.addEventListener("keydown", submit, true);
3349
+ document.addEventListener("click", submit, true);
3350
+ return () => {
3351
+ document.removeEventListener("keydown", submit, true);
3352
+ document.removeEventListener("click", submit, true);
3353
+ };
3354
+ }, [
3355
+ branches,
3356
+ busy,
3357
+ changed,
3358
+ input.draft,
3359
+ portal,
3360
+ prepare,
3361
+ selected,
3362
+ worktree
3363
+ ]);
3364
+ if (portal === void 0 || path === void 0) return null;
3365
+ return createPortal(/* @__PURE__ */ jsxs("span", {
3366
+ style: heroRepositoryControls,
3367
+ children: [branches === void 0 ? /* @__PURE__ */ jsx("span", {
3368
+ style: heroRepositoryStatus,
3369
+ children: error ?? t("repositoryBranchesLoading")
3370
+ }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ClaudeHeroRepositoryCapsule, {
3371
+ branches: availableBranches,
3372
+ selected,
3373
+ worktree,
3374
+ busy,
3375
+ menuOpen,
3376
+ worktreeLabel: t("repositoryWorktree"),
3377
+ searchPlaceholder: t("repositoryBranchSearch"),
3378
+ emptySearchLabel: t("repositoryBranchSearchEmpty"),
3379
+ onMenuOpenChange: setMenuOpen,
3380
+ onSelect: (branch) => {
3381
+ setSelected(branch);
3382
+ setMenuOpen(false);
3383
+ setError(void 0);
3384
+ },
3385
+ onWorktreeChange: (checked) => {
3386
+ setWorktree(checked);
3387
+ setError(void 0);
3388
+ }
3389
+ }), error === void 0 ? null : /* @__PURE__ */ jsx("span", {
3390
+ role: "alert",
3391
+ style: heroRepositoryError,
3392
+ children: error
3393
+ })] }), progressStage === void 0 || !busy && progressError === void 0 ? null : /* @__PURE__ */ jsx(WorktreeProgressCard, {
3394
+ stage: progressStage,
3395
+ ...progressError === void 0 ? {} : { error: progressError },
3396
+ t,
3397
+ onDismiss: () => {
3398
+ setProgressStage(void 0);
3399
+ setProgressError(void 0);
3400
+ }
3401
+ })]
3402
+ }), portal);
3403
+ }
1613
3404
  //#endregion
1614
3405
  //#region src/client/projection.ts
1615
3406
  const EMPTY_CLAUDE_PROJECTION = {
@@ -1622,12 +3413,52 @@ window.__ModuleLoader__.load({
1622
3413
  const POLL_INTERVAL_MS = 2e3;
1623
3414
  const MAX_ACTIVITIES = 1e4;
1624
3415
  const MAX_COMMANDS = 2e3;
3416
+ const MAX_REPOSITORY_TEXT_CHARS = 1024;
3417
+ const MAX_DIFF_CHARS = 262144;
1625
3418
  function record(value) {
1626
3419
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
1627
3420
  }
1628
3421
  function nonNegativeInteger(value) {
1629
3422
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
1630
3423
  }
3424
+ function optionalBoundedString(value) {
3425
+ return value === void 0 || typeof value === "string" && value.length <= MAX_REPOSITORY_TEXT_CHARS;
3426
+ }
3427
+ function validateRepository(value) {
3428
+ const repository = record(value);
3429
+ if (repository === void 0 || ![
3430
+ "ready",
3431
+ "not-repository",
3432
+ "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;
3434
+ if (repository.diff !== void 0) {
3435
+ const diff = record(repository.diff);
3436
+ 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;
3437
+ }
3438
+ if (repository.pullRequest === void 0) return true;
3439
+ const pullRequest = record(repository.pullRequest);
3440
+ if (pullRequest === void 0 || !Number.isSafeInteger(pullRequest.number) || Number(pullRequest.number) <= 0 || typeof pullRequest.title !== "string" || pullRequest.title.length > MAX_REPOSITORY_TEXT_CHARS || typeof pullRequest.url !== "string" || pullRequest.url.length > MAX_REPOSITORY_TEXT_CHARS || ![
3441
+ "open",
3442
+ "closed",
3443
+ "merged"
3444
+ ].includes(String(pullRequest.state)) || typeof pullRequest.draft !== "boolean" || ![
3445
+ "approved",
3446
+ "changes-requested",
3447
+ "review-required",
3448
+ "none"
3449
+ ].includes(String(pullRequest.review)) || ![
3450
+ "passing",
3451
+ "pending",
3452
+ "failing",
3453
+ "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;
3455
+ try {
3456
+ const url = new URL(pullRequest.url);
3457
+ return url.protocol === "https:" && url.hostname === "github.com";
3458
+ } catch {
3459
+ return false;
3460
+ }
3461
+ }
1631
3462
  /** Validate the public route envelope before publishing it to UI components. */
1632
3463
  function parseClaudeClientProjection(value) {
1633
3464
  const input = record(value);
@@ -1643,6 +3474,7 @@ window.__ModuleLoader__.load({
1643
3474
  if (input.contextUsage !== void 0 && record(input.contextUsage) === void 0) throw new Error("invalid Claude context projection");
1644
3475
  const tasks = input.tasks === void 0 ? void 0 : record(input.tasks);
1645
3476
  if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
3477
+ if (input.repository !== void 0 && !validateRepository(input.repository)) throw new Error("invalid Claude repository projection");
1646
3478
  return input;
1647
3479
  }
1648
3480
  /** Create one lazy source: active subscribers trigger an immediate load and bounded polling. */
@@ -1670,15 +3502,13 @@ window.__ModuleLoader__.load({
1670
3502
  if (!response.ok) throw new Error(`Claude projection request failed (${response.status})`);
1671
3503
  const next = parseClaudeClientProjection(await response.json());
1672
3504
  const commandCatalogChanged = JSON.stringify(next.commands) !== JSON.stringify(snapshot.commands);
1673
- if (next.revision !== snapshot.revision || next.owned !== snapshot.owned || commandCatalogChanged) {
3505
+ const repositoryChanged = JSON.stringify(next.repository) !== JSON.stringify(snapshot.repository);
3506
+ if (next.revision !== snapshot.revision || next.owned !== snapshot.owned || commandCatalogChanged || repositoryChanged) {
1674
3507
  snapshot = next;
1675
3508
  for (const listener of [...listeners]) listener();
1676
3509
  }
1677
3510
  } catch (error) {
1678
- if (!(error instanceof DOMException && error.name === "AbortError") && snapshot !== EMPTY_CLAUDE_PROJECTION) {
1679
- snapshot = EMPTY_CLAUDE_PROJECTION;
1680
- for (const listener of [...listeners]) listener();
1681
- }
3511
+ if (error instanceof DOMException && error.name === "AbortError") return;
1682
3512
  } finally {
1683
3513
  controller = void 0;
1684
3514
  schedule();
@@ -1808,6 +3638,170 @@ window.__ModuleLoader__.load({
1808
3638
  }
1809
3639
  }
1810
3640
  //#endregion
3641
+ //#region src/client/details-resize.ts
3642
+ const DETAILS_MIN_WIDTH = 300;
3643
+ const DETAILS_DEFAULT_WIDTH = 480;
3644
+ const DETAILS_MAX_RATIO = .5;
3645
+ const DRAG_THRESHOLD = 4;
3646
+ function clampDetailsWidth(width, frameWidth) {
3647
+ const maximum = Math.max(DETAILS_MIN_WIDTH, Math.floor(frameWidth * DETAILS_MAX_RATIO));
3648
+ return Math.min(maximum, Math.max(DETAILS_MIN_WIDTH, Math.round(width)));
3649
+ }
3650
+ function defaultDetailsWidth(frameWidth) {
3651
+ return clampDetailsWidth(DETAILS_DEFAULT_WIDTH, frameWidth);
3652
+ }
3653
+ function pixelValue(value) {
3654
+ const parsed = Number.parseFloat(value);
3655
+ return Number.isFinite(parsed) ? parsed : void 0;
3656
+ }
3657
+ /**
3658
+ * Extends the native Details drag handle for the plugin Diff panel without
3659
+ * depending on DSH's private layout store. The returned cleanup restores every
3660
+ * inline value owned by the native frame.
3661
+ */
3662
+ function enableExpandedDetailsResize() {
3663
+ if (typeof document === "undefined" || typeof window === "undefined") return () => void 0;
3664
+ let frame;
3665
+ let handle;
3666
+ let width;
3667
+ let dragStartX = 0;
3668
+ let dragStartWidth = 0;
3669
+ let pointerId;
3670
+ let dragged = false;
3671
+ let originalGrid = "";
3672
+ let originalHandleLeft = "";
3673
+ let frameWasDragging = false;
3674
+ let handleWasDragging = false;
3675
+ let resizeObserver;
3676
+ let mutationObserver;
3677
+ let animationFrame;
3678
+ const applyWidth = () => {
3679
+ if (frame === void 0 || handle === void 0 || width === void 0) return;
3680
+ const frameWidth = frame.getBoundingClientRect().width;
3681
+ if (frameWidth <= 0) return;
3682
+ width = clampDetailsWidth(width, frameWidth);
3683
+ const grid = `${pixelValue(getComputedStyle(frame).gridTemplateColumns.split(/\s+/u)[0] ?? "") ?? 0}px minmax(0, 1fr) ${width}px`;
3684
+ const left = `${frameWidth - width}px`;
3685
+ if (frame.style.gridTemplateColumns !== grid) frame.style.gridTemplateColumns = grid;
3686
+ if (handle.style.left !== left) handle.style.left = left;
3687
+ };
3688
+ const scheduleApply = () => {
3689
+ if (animationFrame !== void 0) return;
3690
+ animationFrame = window.requestAnimationFrame(() => {
3691
+ animationFrame = void 0;
3692
+ applyWidth();
3693
+ });
3694
+ };
3695
+ const finishDrag = () => {
3696
+ if (pointerId === void 0) return;
3697
+ pointerId = void 0;
3698
+ if (frame !== void 0 && !frameWasDragging) frame.removeAttribute("data-dragging");
3699
+ if (handle !== void 0 && !handleWasDragging) handle.removeAttribute("data-dragging");
3700
+ };
3701
+ const onPointerMove = (event) => {
3702
+ if (event.pointerId !== pointerId || frame === void 0) return;
3703
+ const delta = event.clientX - dragStartX;
3704
+ if (!dragged && Math.abs(delta) < DRAG_THRESHOLD) return;
3705
+ dragged = true;
3706
+ width = clampDetailsWidth(dragStartWidth - delta, frame.getBoundingClientRect().width);
3707
+ applyWidth();
3708
+ event.preventDefault();
3709
+ };
3710
+ const onPointerEnd = (event) => {
3711
+ if (event.pointerId !== pointerId) return;
3712
+ finishDrag();
3713
+ };
3714
+ const onPointerDown = (event) => {
3715
+ const target = event.target;
3716
+ if (!(target instanceof Element)) return;
3717
+ const candidate = target.closest("[data-side=\"details\"]");
3718
+ const candidateFrame = candidate?.parentElement;
3719
+ if (candidate === null || candidate === void 0 || candidateFrame === null || candidateFrame === void 0) return;
3720
+ const currentFrame = candidateFrame;
3721
+ const currentHandle = candidate;
3722
+ const detailsColumn = currentFrame.children.item(2);
3723
+ const measuredWidth = detailsColumn instanceof HTMLElement ? detailsColumn.getBoundingClientRect().width : 0;
3724
+ const frameWidth = currentFrame.getBoundingClientRect().width;
3725
+ if (measuredWidth <= 0 || frameWidth <= 0) return;
3726
+ const firstDrag = frame === void 0;
3727
+ frame = currentFrame;
3728
+ handle = currentHandle;
3729
+ width = clampDetailsWidth(width ?? measuredWidth, frameWidth);
3730
+ dragStartWidth = width;
3731
+ dragStartX = event.clientX;
3732
+ pointerId = event.pointerId;
3733
+ dragged = false;
3734
+ if (firstDrag) {
3735
+ originalGrid = currentFrame.style.gridTemplateColumns;
3736
+ originalHandleLeft = currentHandle.style.left;
3737
+ frameWasDragging = currentFrame.hasAttribute("data-dragging");
3738
+ handleWasDragging = currentHandle.hasAttribute("data-dragging");
3739
+ }
3740
+ currentFrame.setAttribute("data-dragging", "");
3741
+ currentHandle.setAttribute("data-dragging", "true");
3742
+ if (firstDrag) {
3743
+ resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(scheduleApply);
3744
+ resizeObserver?.observe(currentFrame);
3745
+ mutationObserver = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver(scheduleApply);
3746
+ mutationObserver?.observe(currentFrame, {
3747
+ attributes: true,
3748
+ attributeFilter: ["style"]
3749
+ });
3750
+ mutationObserver?.observe(currentHandle, {
3751
+ attributes: true,
3752
+ attributeFilter: ["style"]
3753
+ });
3754
+ }
3755
+ event.preventDefault();
3756
+ event.stopPropagation();
3757
+ event.stopImmediatePropagation();
3758
+ };
3759
+ const applyDefaultWidth = () => {
3760
+ const initialHandle = document.querySelector("[data-side=\"details\"]");
3761
+ const initialFrame = initialHandle?.parentElement;
3762
+ if (initialHandle === null || initialHandle === void 0 || initialFrame === null || initialFrame === void 0) return;
3763
+ frame = initialFrame;
3764
+ handle = initialHandle;
3765
+ originalGrid = frame.style.gridTemplateColumns;
3766
+ originalHandleLeft = handle.style.left;
3767
+ frameWasDragging = frame.hasAttribute("data-dragging");
3768
+ handleWasDragging = handle.hasAttribute("data-dragging");
3769
+ width = defaultDetailsWidth(frame.getBoundingClientRect().width);
3770
+ resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(scheduleApply);
3771
+ resizeObserver?.observe(frame);
3772
+ mutationObserver = typeof MutationObserver === "undefined" ? void 0 : new MutationObserver(scheduleApply);
3773
+ mutationObserver?.observe(frame, {
3774
+ attributes: true,
3775
+ attributeFilter: ["style"]
3776
+ });
3777
+ mutationObserver?.observe(handle, {
3778
+ attributes: true,
3779
+ attributeFilter: ["style"]
3780
+ });
3781
+ applyWidth();
3782
+ };
3783
+ animationFrame = window.requestAnimationFrame(() => {
3784
+ animationFrame = void 0;
3785
+ applyDefaultWidth();
3786
+ });
3787
+ document.addEventListener("pointerdown", onPointerDown, true);
3788
+ window.addEventListener("pointermove", onPointerMove, true);
3789
+ window.addEventListener("pointerup", onPointerEnd, true);
3790
+ window.addEventListener("pointercancel", onPointerEnd, true);
3791
+ return () => {
3792
+ document.removeEventListener("pointerdown", onPointerDown, true);
3793
+ window.removeEventListener("pointermove", onPointerMove, true);
3794
+ window.removeEventListener("pointerup", onPointerEnd, true);
3795
+ window.removeEventListener("pointercancel", onPointerEnd, true);
3796
+ resizeObserver?.disconnect();
3797
+ mutationObserver?.disconnect();
3798
+ if (animationFrame !== void 0) window.cancelAnimationFrame(animationFrame);
3799
+ finishDrag();
3800
+ if (frame !== void 0) frame.style.gridTemplateColumns = originalGrid;
3801
+ if (handle !== void 0) handle.style.left = originalHandleLeft;
3802
+ };
3803
+ }
3804
+ //#endregion
1811
3805
  //#region src/client/locales.ts
1812
3806
  const zh = {
1813
3807
  nav: "Claude Code",
@@ -1839,12 +3833,14 @@ window.__ModuleLoader__.load({
1839
3833
  error: "诊断失败",
1840
3834
  security: "权限边界",
1841
3835
  securityBody: "Claude 工具权限通过 DSH 审批界面决定;当前版本不宣称对 ~/.claude 与工作区之外路径提供内核级写入隔离。",
1842
- globalSettings: "Claude Code 全局设置",
1843
- globalSettingsBody: "修改受支持的 ~/.claude/settings.json 设置;其他字段会被保留。",
3836
+ globalSettings: "Claude Code 设置",
3837
+ globalSettingsBody: "修改受支持的 Claude Code 与插件设置;其他字段会被保留。",
1844
3838
  globalSettingsLoading: "正在加载全局设置…",
1845
3839
  globalSettingsNewSession: "Output Style 修改仅对新建 Claude 会话生效。",
1846
3840
  globalSettingsError: "全局设置保存失败",
1847
3841
  outputStyle: "Output Style",
3842
+ worktreeBranchPrefix: "Worktree 分支前缀",
3843
+ worktreeBranchPrefixEffect: "分支前缀修改会应用于之后自动创建的 Worktree 分支;显式指定的完整分支名不会被修改。",
1848
3844
  pluginUpdate: "插件更新",
1849
3845
  pluginUpdateBody: "检查 npm 上的新版本。只有可唯一识别的 npm 安装才能直接更新;本地开发链接不会被替换。",
1850
3846
  updateNotChecked: "尚未检查更新。",
@@ -1891,7 +3887,73 @@ window.__ModuleLoader__.load({
1891
3887
  tasksStopped: "已停止",
1892
3888
  tasksKilled: "已终止",
1893
3889
  tasksBackground: "后台",
1894
- tasksLastTool: "最近工具 {tool}"
3890
+ tasksLastTool: "最近工具 {tool}",
3891
+ repositoryOpen: "查看仓库与 PR 详情",
3892
+ repositoryPanel: "仓库状态",
3893
+ repositoryClose: "关闭仓库面板",
3894
+ repositorySection: "仓库",
3895
+ repositoryStatus: "状态",
3896
+ repositoryAvailable: "可用",
3897
+ repositoryUnavailable: "仓库状态不可用",
3898
+ repositoryNotGit: "非 Git 仓库",
3899
+ repositoryCwd: "会话目录",
3900
+ repositoryRoot: "仓库根目录",
3901
+ repositoryBranch: "分支",
3902
+ repositoryBranchSearch: "检索分支",
3903
+ repositoryBranchSearchEmpty: "没有匹配的分支",
3904
+ repositoryBranchesLoading: "正在加载分支…",
3905
+ repositoryProgressTitle: "正在创建 Worktree",
3906
+ repositoryProgressFailed: "Worktree 创建失败",
3907
+ repositoryProgressDismiss: "关闭 Worktree 进度",
3908
+ repositoryProgress_inspecting: "检查仓库和分支",
3909
+ repositoryProgress_fetching: "刷新远程引用",
3910
+ "repositoryProgress_creating-worktree": "创建分支和 Worktree",
3911
+ "repositoryProgress_saving-worktree": "保存 Worktree 状态",
3912
+ "repositoryProgress_switching-branch": "切换本地分支",
3913
+ "repositoryProgress_creating-workspace": "创建 DSH Workspace",
3914
+ "repositoryProgress_starting-session": "启动 Claude 会话",
3915
+ "repositoryProgress_transferring-draft": "转移消息和附件",
3916
+ repositoryProgress_submitting: "提交消息",
3917
+ repositorySessionUnavailable: "无法准备目标会话。",
3918
+ repositoryDraftTransferFailed: "无法将草稿附件转移到 worktree 会话。",
3919
+ repositoryDetached: "Detached HEAD",
3920
+ repositoryUnknownBranch: "未知分支",
3921
+ repositoryWorktree: "Worktree",
3922
+ repositoryWorktreeLabel: "Git worktree",
3923
+ repositoryChanges: "改动",
3924
+ repositoryModified: "有修改",
3925
+ repositoryClean: "干净",
3926
+ repositoryLocal: "本地仓库",
3927
+ repositoryPullRequest: "Pull Request",
3928
+ repositoryNoPr: "当前分支没有关联 PR",
3929
+ repositoryPr: "PR #{number}",
3930
+ repositoryPrDraft: "草稿 PR #{number}",
3931
+ repositoryPrState: "PR 状态",
3932
+ repositoryDraft: "草稿",
3933
+ repositoryState_open: "开放",
3934
+ repositoryState_closed: "已关闭",
3935
+ repositoryState_merged: "已合并",
3936
+ repositoryChecks: "检查",
3937
+ repositoryChecks_passing: "检查通过",
3938
+ repositoryChecks_pending: "检查进行中",
3939
+ repositoryChecks_failing: "检查失败",
3940
+ repositoryChecks_none: "无检查",
3941
+ repositoryReview: "评审",
3942
+ repositoryReview_approved: "已批准",
3943
+ "repositoryReview_changes-requested": "要求修改",
3944
+ "repositoryReview_review-required": "等待评审",
3945
+ repositoryReview_none: "无评审状态",
3946
+ repositoryMergeState: "合并状态",
3947
+ repositoryOpenPr: "在浏览器中打开 PR #{number}",
3948
+ yes: "是",
3949
+ no: "否",
3950
+ diffOpen: "查看分支改动",
3951
+ diffClose: "关闭 Diff 面板",
3952
+ diffWorkingTree: "分支改动",
3953
+ diffFiles: "{count} 个已修改文件",
3954
+ diffFilesShort: "{count} 个文件",
3955
+ diffTruncated: "Diff 超出安全显示上限。请在终端中查看完整内容。",
3956
+ diffEmpty: "没有可显示的 tracked 文件改动"
1895
3957
  };
1896
3958
  const en = {
1897
3959
  nav: "Claude Code",
@@ -1923,12 +3985,14 @@ window.__ModuleLoader__.load({
1923
3985
  error: "Doctor failed",
1924
3986
  security: "Permission boundary",
1925
3987
  securityBody: "Claude tool permissions are decided through the DSH approval UI. This version does not claim kernel-level write isolation for ~/.claude or paths outside the workspace.",
1926
- globalSettings: "Claude Code global settings",
1927
- globalSettingsBody: "Modify supported ~/.claude/settings.json values while preserving every other field.",
3988
+ globalSettings: "Claude Code settings",
3989
+ globalSettingsBody: "Modify supported Claude Code and plugin settings while preserving every other field.",
1928
3990
  globalSettingsLoading: "Loading global settings…",
1929
3991
  globalSettingsNewSession: "Output Style changes apply only to new Claude sessions.",
1930
3992
  globalSettingsError: "Global settings save failed",
1931
3993
  outputStyle: "Output Style",
3994
+ worktreeBranchPrefix: "Worktree branch prefix",
3995
+ worktreeBranchPrefixEffect: "Prefix changes apply to subsequently generated Worktree branches. Explicit full branch names remain unchanged.",
1932
3996
  pluginUpdate: "Plugin updates",
1933
3997
  pluginUpdateBody: "Check npm for new releases. Only a uniquely identified npm installation can update in place; local development links are never replaced.",
1934
3998
  updateNotChecked: "Updates have not been checked yet.",
@@ -1975,7 +4039,73 @@ window.__ModuleLoader__.load({
1975
4039
  tasksStopped: "Stopped",
1976
4040
  tasksKilled: "Killed",
1977
4041
  tasksBackground: "Background",
1978
- tasksLastTool: "Last tool {tool}"
4042
+ tasksLastTool: "Last tool {tool}",
4043
+ repositoryOpen: "Show repository and pull request details",
4044
+ repositoryPanel: "Repository status",
4045
+ repositoryClose: "Close repository panel",
4046
+ repositorySection: "Repository",
4047
+ repositoryStatus: "Status",
4048
+ repositoryAvailable: "Available",
4049
+ repositoryUnavailable: "Repository status unavailable",
4050
+ repositoryNotGit: "Not a Git repository",
4051
+ repositoryCwd: "Session directory",
4052
+ repositoryRoot: "Repository root",
4053
+ repositoryBranch: "Branch",
4054
+ repositoryBranchSearch: "Search branches",
4055
+ repositoryBranchSearchEmpty: "No matching branches",
4056
+ repositoryBranchesLoading: "Loading branches…",
4057
+ repositoryProgressTitle: "Creating Worktree",
4058
+ repositoryProgressFailed: "Worktree creation failed",
4059
+ repositoryProgressDismiss: "Dismiss Worktree progress",
4060
+ repositoryProgress_inspecting: "Checking repository and branch",
4061
+ repositoryProgress_fetching: "Refreshing remote references",
4062
+ "repositoryProgress_creating-worktree": "Creating branch and Worktree",
4063
+ "repositoryProgress_saving-worktree": "Saving Worktree state",
4064
+ "repositoryProgress_switching-branch": "Switching local branch",
4065
+ "repositoryProgress_creating-workspace": "Creating DSH Workspace",
4066
+ "repositoryProgress_starting-session": "Starting Claude session",
4067
+ "repositoryProgress_transferring-draft": "Transferring message and attachments",
4068
+ repositoryProgress_submitting: "Submitting message",
4069
+ repositorySessionUnavailable: "The target session could not be prepared.",
4070
+ repositoryDraftTransferFailed: "Draft attachments could not be moved to the worktree session.",
4071
+ repositoryDetached: "Detached HEAD",
4072
+ repositoryUnknownBranch: "Unknown branch",
4073
+ repositoryWorktree: "Worktree",
4074
+ repositoryWorktreeLabel: "Git worktree",
4075
+ repositoryChanges: "Changes",
4076
+ repositoryModified: "Modified",
4077
+ repositoryClean: "Clean",
4078
+ repositoryLocal: "Local repository",
4079
+ repositoryPullRequest: "Pull request",
4080
+ repositoryNoPr: "No pull request for this branch",
4081
+ repositoryPr: "PR #{number}",
4082
+ repositoryPrDraft: "Draft PR #{number}",
4083
+ repositoryPrState: "PR state",
4084
+ repositoryDraft: "Draft",
4085
+ repositoryState_open: "Open",
4086
+ repositoryState_closed: "Closed",
4087
+ repositoryState_merged: "Merged",
4088
+ repositoryChecks: "Checks",
4089
+ repositoryChecks_passing: "Checks passing",
4090
+ repositoryChecks_pending: "Checks pending",
4091
+ repositoryChecks_failing: "Checks failing",
4092
+ repositoryChecks_none: "No checks",
4093
+ repositoryReview: "Review",
4094
+ repositoryReview_approved: "Approved",
4095
+ "repositoryReview_changes-requested": "Changes requested",
4096
+ "repositoryReview_review-required": "Review required",
4097
+ repositoryReview_none: "No review status",
4098
+ repositoryMergeState: "Merge state",
4099
+ repositoryOpenPr: "Open PR #{number} in browser",
4100
+ yes: "Yes",
4101
+ no: "No",
4102
+ diffOpen: "View branch changes",
4103
+ diffClose: "Close diff panel",
4104
+ diffWorkingTree: "Branch changes",
4105
+ diffFiles: "{count} modified file(s)",
4106
+ diffFilesShort: "{count} files",
4107
+ diffTruncated: "The diff exceeds the safe display limit. Use the terminal to inspect the complete content.",
4108
+ diffEmpty: "No tracked file changes to display"
1979
4109
  };
1980
4110
  //#endregion
1981
4111
  //#region src/client/index.tsx
@@ -1985,8 +4115,10 @@ window.__ModuleLoader__.load({
1985
4115
  "locale",
1986
4116
  "conversationEvents",
1987
4117
  "sessions",
4118
+ "workspaces",
1988
4119
  "inputTriggers",
1989
- "conversation"
4120
+ "conversation",
4121
+ "connection"
1990
4122
  ];
1991
4123
  function apply(ctx) {
1992
4124
  const namespace = "settings.claude-code";
@@ -1998,6 +4130,9 @@ window.__ModuleLoader__.load({
1998
4130
  const projections = new ClaudeProjectionStore();
1999
4131
  ctx.effect(() => ctx.inputTriggers.registerSource(createClaudeCommandSource(ctx, projections)), "dsh-claude: Claude slash source");
2000
4132
  const sessions = ctx.get("sessions");
4133
+ const workspaces = ctx.get("workspaces");
4134
+ const conversation = ctx.get("conversation");
4135
+ const connection = ctx.get("connection");
2001
4136
  if (sessions !== void 0) ctx.effect(() => sessions.provide({
2002
4137
  hooks: ["claudeProjection"],
2003
4138
  resolve: (binding) => ({ hooks: { claudeProjection: projections.source(binding.sessionId) } })
@@ -2012,41 +4147,61 @@ window.__ModuleLoader__.load({
2012
4147
  locale: namespace
2013
4148
  }, ClaudeActivityNode));
2014
4149
  const layout = ctx.get("layout");
2015
- let disposeTasksDetails;
2016
- let tasksPanelTarget;
2017
- const closeTasksPanel = () => {
2018
- if (disposeTasksDetails === void 0) return;
2019
- disposeTasksDetails();
2020
- disposeTasksDetails = void 0;
2021
- tasksPanelTarget = void 0;
4150
+ let disposePluginDetails;
4151
+ let disposeExpandedDetailsResize;
4152
+ let detailsSessionId;
4153
+ const closePluginDetails = () => {
4154
+ if (disposePluginDetails === void 0) return;
4155
+ disposeExpandedDetailsResize?.();
4156
+ disposeExpandedDetailsResize = void 0;
4157
+ disposePluginDetails();
4158
+ disposePluginDetails = void 0;
4159
+ detailsSessionId = void 0;
2022
4160
  layout?.closeDetails();
2023
4161
  };
2024
4162
  const openTasksPanel = (sessionId, turn) => {
2025
- closeTasksPanel();
4163
+ closePluginDetails();
2026
4164
  try {
2027
- disposeTasksDetails = ctx.slots.register({
4165
+ disposePluginDetails = ctx.slots.register({
2028
4166
  name: "details",
2029
4167
  priority: -10,
2030
4168
  locale: namespace,
2031
4169
  inject: () => ({
2032
4170
  t,
2033
4171
  turn,
2034
- closeDetails: closeTasksPanel
4172
+ closeDetails: closePluginDetails
2035
4173
  })
2036
4174
  }, ClaudeTasksPanel);
2037
4175
  } catch {
2038
4176
  return;
2039
4177
  }
2040
- tasksPanelTarget = {
2041
- sessionId,
2042
- turn
2043
- };
4178
+ detailsSessionId = sessionId;
4179
+ layout?.openDetails();
4180
+ disposeExpandedDetailsResize = enableExpandedDetailsResize();
4181
+ };
4182
+ const openDiffPanel = (sessionId) => {
4183
+ closePluginDetails();
4184
+ try {
4185
+ disposePluginDetails = ctx.slots.register({
4186
+ name: "details",
4187
+ priority: -10,
4188
+ locale: namespace,
4189
+ inject: () => ({
4190
+ t,
4191
+ closeDetails: closePluginDetails
4192
+ })
4193
+ }, ClaudeDiffPanel);
4194
+ } catch {
4195
+ return;
4196
+ }
4197
+ detailsSessionId = sessionId;
2044
4198
  layout?.openDetails();
4199
+ disposeExpandedDetailsResize = enableExpandedDetailsResize();
2045
4200
  };
2046
4201
  ctx.effect(() => {
2047
- if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => closeTasksPanel();
4202
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return () => closePluginDetails();
2048
4203
  const observer = new MutationObserver(() => {
2049
- if (tasksPanelTarget !== void 0 && document.querySelector("[data-details-collapsed]") !== null) closeTasksPanel();
4204
+ if (detailsSessionId !== void 0 && document.querySelector("[data-details-collapsed]") !== null) closePluginDetails();
2050
4205
  });
2051
4206
  observer.observe(document.body, {
2052
4207
  attributes: true,
@@ -2055,9 +4210,9 @@ window.__ModuleLoader__.load({
2055
4210
  });
2056
4211
  return () => {
2057
4212
  observer.disconnect();
2058
- closeTasksPanel();
4213
+ closePluginDetails();
2059
4214
  };
2060
- }, "dsh-claude: tasks panel lifecycle");
4215
+ }, "dsh-claude: details panel lifecycle");
2061
4216
  ctx.slots.inject("conversation.chat.node", () => ctx.slots.register({
2062
4217
  name: "conversation.chat.node",
2063
4218
  key: "claude-active-tasks",
@@ -2072,9 +4227,62 @@ window.__ModuleLoader__.load({
2072
4227
  openTasks: (turn) => openTasksPanel(sessionId, turn)
2073
4228
  })
2074
4229
  }, ClaudeActivityTail));
4230
+ ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
4231
+ name: "conversation.input.dock",
4232
+ id: "claude-repository-status",
4233
+ order: 20,
4234
+ locale: namespace,
4235
+ inject: (sessionId) => ({
4236
+ t,
4237
+ openDiff: () => openDiffPanel(sessionId)
4238
+ })
4239
+ }, ClaudeRepositoryStatus));
4240
+ if (sessions !== void 0 && workspaces !== void 0 && conversation !== void 0 && connection !== void 0) ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
4241
+ name: "conversation.input.dock",
4242
+ id: "claude-hero-repository-controls",
4243
+ order: 21,
4244
+ locale: namespace,
4245
+ inject: (sourceSessionId) => ({
4246
+ t,
4247
+ prepare: async (cwd, branch, useWorktree, onProgress) => {
4248
+ const sourceScope = sessions.scope(sourceSessionId);
4249
+ if (sourceScope === void 0) throw new Error(t("repositorySessionUnavailable"));
4250
+ const sourceInput = conversation.input.for(sourceScope);
4251
+ const draft = sourceInput.state.getSnapshot().draft;
4252
+ const imageIds = sourceInput.state.getSnapshot().imageIds;
4253
+ const prepared = await prepareRepository(cwd, branch, useWorktree, void 0, onProgress);
4254
+ if (prepared.mode === "checkout") {
4255
+ sourceInput.submit();
4256
+ return;
4257
+ }
4258
+ onProgress("creating-workspace");
4259
+ const workspace = await workspaces.create({ path: prepared.path });
4260
+ onProgress("starting-session");
4261
+ const targetSessionId = await workspaces.connectWorkspace(workspace.workspaceId);
4262
+ const targetScope = sessions.scope(targetSessionId);
4263
+ if (targetScope === void 0) throw new Error(t("repositorySessionUnavailable"));
4264
+ const presetResponse = await connection.api.agentPresets.select({
4265
+ sessionId: targetSessionId,
4266
+ agentPreset: "claude"
4267
+ });
4268
+ if (!presetResponse.result.ok) throw new Error(presetResponse.result.error.message);
4269
+ sessions.noteAgentPreset(targetSessionId, presetResponse.result.value.agentPreset);
4270
+ const targetInput = conversation.input.for(targetScope);
4271
+ onProgress("transferring-draft");
4272
+ if (imageIds.length > 0 && !targetInput.addImages(imageIds)) throw new Error(t("repositoryDraftTransferFailed"));
4273
+ if (draft !== "") targetInput.setDraft(draft);
4274
+ if (prepared.leaseId !== void 0) await bindRepositoryLease(prepared.leaseId, targetSessionId);
4275
+ sessions.open(targetSessionId);
4276
+ onProgress("submitting");
4277
+ targetInput.submit();
4278
+ sourceInput.setDraft("");
4279
+ for (const imageId of imageIds) sourceInput.removeImage(imageId);
4280
+ }
4281
+ })
4282
+ }, ClaudeHeroRepositoryControls));
2075
4283
  if (sessions !== void 0) ctx.effect(() => sessions.list.subscribe(() => {
2076
- if (tasksPanelTarget !== void 0 && sessions.list.getSnapshot().current !== tasksPanelTarget.sessionId) closeTasksPanel();
2077
- }), "dsh-claude: tasks panel session tracking");
4284
+ if (detailsSessionId !== void 0 && sessions.list.getSnapshot().current !== detailsSessionId) closePluginDetails();
4285
+ }), "dsh-claude: details panel session tracking");
2078
4286
  ctx.slots.inject("settings.section", () => ctx.slots.register({
2079
4287
  name: "settings.section",
2080
4288
  id: "claude-code",