@norman-else/dsh-claude 0.1.22 → 0.1.24

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
@@ -4,7 +4,7 @@ window.__ModuleLoader__.load({
4
4
  var module = { exports: {} };
5
5
  module.exports;
6
6
  var { Fragment, useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } = require("react");
7
- var { DiffBlock, DisclosureRow, HoverCard, IconApiOutline14, IconBranchOutline16, IconCheckOutline14, IconChevronDownOutline14, IconCloseOutline16, IconFullscreenOutline16, IconSearchOutline16, IconThinkOutline14, MarkdownText, Menu, Modal, StateDot } = require("@deepseek-ai/dsh-client-ui-primitives");
7
+ var { DiffBlock, DisclosureRow, HoverCard, IconApiOutline14, IconBranchOutline16, IconCheckOutline14, IconCheckOutline16, IconChevronDownOutline14, IconChevronUpOutline14, IconCloseOutline16, IconEditOutline16, IconFullscreenOutline16, IconQueueOutline14, IconSearchOutline16, IconSendOutline14, IconThinkOutline14, IconTrashOutline16, MarkdownText, Menu, Modal, StateDot, Tooltip } = require("@deepseek-ai/dsh-client-ui-primitives");
8
8
  var { Fragment: Fragment$1, jsx, jsxs } = require("react/jsx-runtime");
9
9
  var { createPortal } = require("react-dom");
10
10
  /** Claude's subagent dispatch tools; rendered as plugin-owned group cards
@@ -18,6 +18,7 @@ window.__ModuleLoader__.load({
18
18
  const CLAUDE_REPOSITORY_SETUP_PATH = "/plugins/dsh-claude/repository/setup";
19
19
  const CLAUDE_REPOSITORY_ACTION_PATH = "/plugins/dsh-claude/repository/action";
20
20
  const CLAUDE_REVIEW_COMMENT_PATH = "/plugins/dsh-claude/review-comments";
21
+ const CLAUDE_REPOSITORY_FEEDBACK_PATH = "/plugins/dsh-claude/repository/feedback";
21
22
  //#endregion
22
23
  //#region src/client/task-projection.ts
23
24
  /** Tasks UI is reserved for detached work and genuine Claude subagents. */
@@ -657,8 +658,7 @@ window.__ModuleLoader__.load({
657
658
  flex: 1,
658
659
  overflow: "hidden",
659
660
  textOverflow: "ellipsis",
660
- whiteSpace: "nowrap",
661
- fontWeight: 550
661
+ whiteSpace: "nowrap"
662
662
  };
663
663
  const settingSelectChevron = {
664
664
  flex: "none",
@@ -1411,6 +1411,91 @@ window.__ModuleLoader__.load({
1411
1411
  lineHeight: "22px",
1412
1412
  textAlign: "left"
1413
1413
  };
1414
+ const queueBar = {
1415
+ width: "100%",
1416
+ minWidth: 0,
1417
+ boxSizing: "border-box",
1418
+ display: "flex",
1419
+ flexDirection: "column",
1420
+ padding: "3px 6px 3px 11px",
1421
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1422
+ borderRadius: 11,
1423
+ background: "var(--dsw-alias-bg-layer-1)",
1424
+ color: "var(--dsw-alias-label-primary)",
1425
+ boxShadow: "0 1px 2px color-mix(in srgb, var(--dsw-alias-label-primary) 4%, transparent)",
1426
+ font: "inherit",
1427
+ fontSize: 13,
1428
+ lineHeight: "20px"
1429
+ };
1430
+ const queueHeader = {
1431
+ width: "100%",
1432
+ minHeight: 30,
1433
+ display: "flex",
1434
+ alignItems: "center",
1435
+ gap: 8,
1436
+ padding: "2px 0",
1437
+ border: "none",
1438
+ outline: "none",
1439
+ background: "transparent",
1440
+ color: "inherit",
1441
+ font: "inherit",
1442
+ fontSize: 13,
1443
+ textAlign: "left",
1444
+ cursor: "pointer"
1445
+ };
1446
+ const queueLead = {
1447
+ flex: "none",
1448
+ display: "grid",
1449
+ placeItems: "center",
1450
+ color: "var(--dsw-alias-label-tertiary)"
1451
+ };
1452
+ const queueCount = {
1453
+ minWidth: 0,
1454
+ flex: 1,
1455
+ fontWeight: 550
1456
+ };
1457
+ const queueList = {
1458
+ maxHeight: 180,
1459
+ margin: 0,
1460
+ padding: 0,
1461
+ listStyle: "none",
1462
+ overflowY: "auto"
1463
+ };
1464
+ const queueRow = {
1465
+ minHeight: 30,
1466
+ display: "flex",
1467
+ alignItems: "center",
1468
+ gap: 8
1469
+ };
1470
+ const queueRowDivider = { borderTop: "1px solid var(--dsw-alias-border-l1, color-mix(in srgb, currentColor 12%, transparent))" };
1471
+ const queuePreview = {
1472
+ minWidth: 0,
1473
+ flex: 1,
1474
+ overflow: "hidden",
1475
+ color: "var(--dsw-alias-label-secondary)",
1476
+ textOverflow: "ellipsis",
1477
+ whiteSpace: "nowrap"
1478
+ };
1479
+ const queueEditor = {
1480
+ minWidth: 0,
1481
+ flex: 1,
1482
+ height: 26,
1483
+ boxSizing: "border-box",
1484
+ padding: "0 8px",
1485
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1486
+ borderRadius: 6,
1487
+ outline: "none",
1488
+ background: "var(--dsw-alias-bg-layer-2)",
1489
+ color: "var(--dsw-alias-label-primary)",
1490
+ font: "inherit",
1491
+ fontSize: 13
1492
+ };
1493
+ const queueActions = {
1494
+ flex: "none",
1495
+ display: "inline-flex",
1496
+ alignItems: "center",
1497
+ gap: 2
1498
+ };
1414
1499
  const repositoryBarMerged = {
1415
1500
  borderColor: "color-mix(in srgb, #a78bfa 30%, var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent)))",
1416
1501
  background: "color-mix(in srgb, #a78bfa 5%, var(--dsw-alias-bg-layer-1))"
@@ -1590,6 +1675,11 @@ window.__ModuleLoader__.load({
1590
1675
  fontWeight: 550,
1591
1676
  whiteSpace: "nowrap"
1592
1677
  };
1678
+ const repositoryItemLabel = {
1679
+ minWidth: 0,
1680
+ overflow: "hidden",
1681
+ textOverflow: "ellipsis"
1682
+ };
1593
1683
  const repositoryItemDot = {
1594
1684
  width: 6,
1595
1685
  height: 6,
@@ -1645,6 +1735,176 @@ window.__ModuleLoader__.load({
1645
1735
  background: "transparent",
1646
1736
  color: "var(--dsw-alias-label-tertiary)"
1647
1737
  };
1738
+ const repositoryAutoFix = {
1739
+ width: 26,
1740
+ minHeight: 26,
1741
+ flex: "none",
1742
+ display: "inline-flex",
1743
+ alignItems: "center",
1744
+ justifyContent: "center",
1745
+ padding: 0,
1746
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1747
+ borderRadius: 7,
1748
+ outline: "none",
1749
+ background: "var(--dsw-alias-bg-layer-2)",
1750
+ color: "var(--dsw-alias-label-tertiary)",
1751
+ font: "inherit",
1752
+ lineHeight: "18px",
1753
+ cursor: "pointer"
1754
+ };
1755
+ const repositoryAutoFixActive = {
1756
+ borderColor: "color-mix(in srgb, var(--dsw-static-blue-450) 45%, transparent)",
1757
+ background: "color-mix(in srgb, var(--dsw-static-blue-450) 12%, transparent)",
1758
+ color: "var(--dsw-static-blue-450)"
1759
+ };
1760
+ const repositoryUpdateTrigger = {
1761
+ flex: "none",
1762
+ display: "inline-flex",
1763
+ alignItems: "center",
1764
+ gap: 4,
1765
+ minHeight: 26,
1766
+ padding: "3px 8px",
1767
+ border: "1px solid color-mix(in srgb, var(--dsw-static-blue-450) 45%, transparent)",
1768
+ borderRadius: 7,
1769
+ background: "color-mix(in srgb, var(--dsw-static-blue-450) 12%, transparent)",
1770
+ color: "var(--dsw-static-blue-450)",
1771
+ font: "inherit",
1772
+ fontSize: 12,
1773
+ lineHeight: "18px",
1774
+ fontWeight: 650,
1775
+ whiteSpace: "nowrap",
1776
+ cursor: "pointer"
1777
+ };
1778
+ const repositoryChecksFrame = {
1779
+ position: "relative",
1780
+ display: "inline-flex",
1781
+ minWidth: 0
1782
+ };
1783
+ const repositoryChecksTrigger = {
1784
+ display: "inline-flex",
1785
+ alignItems: "center",
1786
+ minWidth: 0,
1787
+ padding: 0,
1788
+ border: "none",
1789
+ background: "transparent",
1790
+ font: "inherit",
1791
+ color: "inherit",
1792
+ cursor: "pointer"
1793
+ };
1794
+ const repositoryChecksCard = {
1795
+ position: "absolute",
1796
+ zIndex: 1100,
1797
+ bottom: "calc(100% + 8px)",
1798
+ right: 0,
1799
+ width: 320,
1800
+ boxSizing: "border-box",
1801
+ display: "flex",
1802
+ flexDirection: "column",
1803
+ alignItems: "stretch",
1804
+ gap: 8,
1805
+ padding: 12,
1806
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1807
+ borderRadius: 10,
1808
+ background: "var(--dsw-specific-menu, var(--dsw-alias-bg-layer-1))",
1809
+ boxShadow: "var(--dsw-shadow-lv3)",
1810
+ textAlign: "left",
1811
+ cursor: "default"
1812
+ };
1813
+ const repositoryChecksTitle = {
1814
+ color: "var(--dsw-alias-label-primary)",
1815
+ fontSize: 12,
1816
+ fontWeight: 650
1817
+ };
1818
+ const repositoryChecksHint = {
1819
+ color: "var(--dsw-alias-label-tertiary)",
1820
+ fontSize: 12
1821
+ };
1822
+ const repositoryChecksError = {
1823
+ color: "var(--dsw-alias-state-error-primary)",
1824
+ fontSize: 12
1825
+ };
1826
+ const repositoryChecksItem = {
1827
+ display: "flex",
1828
+ flexDirection: "column",
1829
+ gap: 2,
1830
+ minWidth: 0
1831
+ };
1832
+ const repositoryChecksName = {
1833
+ color: "var(--dsw-alias-label-primary)",
1834
+ fontSize: 12,
1835
+ fontWeight: 600,
1836
+ overflow: "hidden",
1837
+ textOverflow: "ellipsis",
1838
+ whiteSpace: "nowrap"
1839
+ };
1840
+ const repositoryChecksDesc = {
1841
+ color: "var(--dsw-alias-label-tertiary)",
1842
+ fontSize: 11,
1843
+ overflow: "hidden",
1844
+ textOverflow: "ellipsis",
1845
+ whiteSpace: "nowrap"
1846
+ };
1847
+ const repositoryChecksFix = {
1848
+ alignSelf: "flex-end",
1849
+ minHeight: 26,
1850
+ padding: "3px 10px",
1851
+ border: "none",
1852
+ borderRadius: 7,
1853
+ background: "var(--dsw-static-blue-450)",
1854
+ color: "var(--dsw-alias-label-on-accent, #fff)",
1855
+ font: "inherit",
1856
+ fontSize: 12,
1857
+ fontWeight: 650,
1858
+ cursor: "pointer"
1859
+ };
1860
+ const diffPrCommentsButton = {
1861
+ minHeight: 28,
1862
+ display: "inline-flex",
1863
+ alignItems: "center",
1864
+ gap: 4,
1865
+ padding: "4px 8px",
1866
+ border: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
1867
+ borderRadius: 7,
1868
+ background: "var(--dsw-alias-bg-layer-2)",
1869
+ font: "inherit",
1870
+ fontSize: 12,
1871
+ fontWeight: 650,
1872
+ whiteSpace: "nowrap",
1873
+ cursor: "pointer"
1874
+ };
1875
+ const diffGhCommentAuthor = {
1876
+ color: "var(--dsw-alias-label-tertiary)",
1877
+ fontWeight: 600
1878
+ };
1879
+ const diffGhCommentLink = {
1880
+ color: "var(--dsw-static-blue-450)",
1881
+ textDecoration: "none",
1882
+ fontWeight: 650
1883
+ };
1884
+ const diffModalConflicts = {
1885
+ display: "flex",
1886
+ flexDirection: "column",
1887
+ gap: 4,
1888
+ margin: 0,
1889
+ padding: "8px 10px",
1890
+ borderRadius: 8,
1891
+ background: "var(--dsw-alias-bg-layer-2)",
1892
+ fontSize: 12,
1893
+ listStyle: "none"
1894
+ };
1895
+ const diffModalConflictResolve = {
1896
+ alignSelf: "flex-start",
1897
+ minHeight: 28,
1898
+ padding: "4px 12px",
1899
+ border: "none",
1900
+ borderRadius: 7,
1901
+ background: "var(--dsw-static-blue-450)",
1902
+ color: "var(--dsw-alias-label-on-accent, #fff)",
1903
+ font: "inherit",
1904
+ fontSize: 12,
1905
+ fontWeight: 650,
1906
+ cursor: "pointer"
1907
+ };
1648
1908
  const repositoryMergeTrigger = {
1649
1909
  flex: "none",
1650
1910
  display: "inline-flex",
@@ -1899,11 +2159,19 @@ window.__ModuleLoader__.load({
1899
2159
  display: "flex",
1900
2160
  alignItems: "center",
1901
2161
  gap: 8,
2162
+ overflow: "hidden",
1902
2163
  color: "var(--dsw-alias-label-primary)",
1903
2164
  fontSize: 15,
1904
- fontWeight: 650
2165
+ fontWeight: 650,
2166
+ whiteSpace: "nowrap"
2167
+ };
2168
+ const diffHeaderLabel = {
2169
+ minWidth: 0,
2170
+ overflow: "hidden",
2171
+ textOverflow: "ellipsis"
1905
2172
  };
1906
2173
  const diffHeaderActions = {
2174
+ flex: "none",
1907
2175
  display: "flex",
1908
2176
  alignItems: "center",
1909
2177
  gap: 5
@@ -2647,7 +2915,7 @@ window.__ModuleLoader__.load({
2647
2915
  const MAX_REVIEW_COMMENTS = 50;
2648
2916
  const MAX_REVIEW_COMMENT_CHARS = 2e3;
2649
2917
  const MAX_TRANSCRIPT_CHARS = 64e3;
2650
- function record$4(value) {
2918
+ function record$5(value) {
2651
2919
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
2652
2920
  }
2653
2921
  function nonNegativeInteger(value) {
@@ -2657,18 +2925,18 @@ window.__ModuleLoader__.load({
2657
2925
  return value === void 0 || typeof value === "string" && value.length <= MAX_REPOSITORY_TEXT_CHARS;
2658
2926
  }
2659
2927
  function validateRepository(value) {
2660
- const repository = record$4(value);
2928
+ const repository = record$5(value);
2661
2929
  if (repository === void 0 || ![
2662
2930
  "ready",
2663
2931
  "not-repository",
2664
2932
  "unavailable"
2665
2933
  ].includes(String(repository.status)) || typeof repository.cwd !== "string" || repository.cwd.length > MAX_REPOSITORY_TEXT_CHARS || !optionalBoundedString(repository.root) || !optionalBoundedString(repository.branch) || !optionalBoundedString(repository.remote) || repository.detached !== void 0 && typeof repository.detached !== "boolean" || repository.worktree !== void 0 && typeof repository.worktree !== "boolean" || repository.dirty !== void 0 && typeof repository.dirty !== "boolean" || repository.upstream !== void 0 && typeof repository.upstream !== "boolean" || repository.ahead !== void 0 && !nonNegativeInteger(repository.ahead) || repository.behind !== void 0 && !nonNegativeInteger(repository.behind)) return false;
2666
2934
  if (repository.diff !== void 0) {
2667
- const diff = record$4(repository.diff);
2935
+ const diff = record$5(repository.diff);
2668
2936
  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;
2669
2937
  }
2670
2938
  if (repository.pullRequest === void 0) return true;
2671
- const pullRequest = record$4(repository.pullRequest);
2939
+ const pullRequest = record$5(repository.pullRequest);
2672
2940
  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 || ![
2673
2941
  "open",
2674
2942
  "closed",
@@ -2693,24 +2961,24 @@ window.__ModuleLoader__.load({
2693
2961
  }
2694
2962
  /** Validate the public route envelope before publishing it to UI components. */
2695
2963
  function parseClaudeClientProjection(value) {
2696
- const input = record$4(value);
2964
+ const input = record$5(value);
2697
2965
  if (input === void 0 || input.schemaVersion !== 1 || !nonNegativeInteger(input.revision) || typeof input.owned !== "boolean" || !Array.isArray(input.commands) || input.commands.length > MAX_COMMANDS || !Array.isArray(input.activities) || input.activities.length > MAX_ACTIVITIES) throw new Error("invalid Claude sidecar projection");
2698
2966
  for (const item of input.commands) {
2699
- const command = record$4(item);
2967
+ const command = record$5(item);
2700
2968
  if (command === void 0 || typeof command.publicName !== "string" || typeof command.claudeName !== "string" || typeof command.description !== "string" || command.hint !== void 0 && typeof command.hint !== "string" || typeof command.prefixed !== "boolean") throw new Error("invalid Claude command projection");
2701
2969
  }
2702
2970
  for (const item of input.activities) {
2703
- const activity = record$4(item);
2971
+ const activity = record$5(item);
2704
2972
  if (activity === void 0 || !nonNegativeInteger(activity.turn) || !nonNegativeInteger(activity.step) || !nonNegativeInteger(activity.ordinal) || typeof activity.kind !== "string") throw new Error("invalid Claude sidecar activity");
2705
2973
  }
2706
- if (input.contextUsage !== void 0 && record$4(input.contextUsage) === void 0) throw new Error("invalid Claude context projection");
2707
- const tasks = input.tasks === void 0 ? void 0 : record$4(input.tasks);
2974
+ if (input.contextUsage !== void 0 && record$5(input.contextUsage) === void 0) throw new Error("invalid Claude context projection");
2975
+ const tasks = input.tasks === void 0 ? void 0 : record$5(input.tasks);
2708
2976
  if (tasks !== void 0 && !Array.isArray(tasks.tasks)) throw new Error("invalid Claude tasks projection");
2709
2977
  if (input.repository !== void 0 && !validateRepository(input.repository)) throw new Error("invalid Claude repository projection");
2710
2978
  if (input.reviewComments !== void 0) {
2711
2979
  if (!Array.isArray(input.reviewComments) || input.reviewComments.length > MAX_REVIEW_COMMENTS) throw new Error("invalid Claude review comment projection");
2712
2980
  for (const item of input.reviewComments) {
2713
- const comment = record$4(item);
2981
+ const comment = record$5(item);
2714
2982
  if (comment === void 0 || typeof comment.id !== "string" || comment.id.length === 0 || comment.id.length > 128 || typeof comment.path !== "string" || comment.path.length === 0 || comment.path.length > MAX_REPOSITORY_TEXT_CHARS || !nonNegativeInteger(comment.line) || comment.side !== "old" && comment.side !== "new" || typeof comment.text !== "string" || comment.text.length > MAX_REVIEW_COMMENT_CHARS) throw new Error("invalid Claude review comment projection");
2715
2983
  }
2716
2984
  }
@@ -2908,7 +3176,7 @@ window.__ModuleLoader__.load({
2908
3176
  } catch {
2909
3177
  return;
2910
3178
  }
2911
- const event = record$4(value);
3179
+ const event = record$5(value);
2912
3180
  if (event === void 0 || typeof event.type !== "string") return;
2913
3181
  try {
2914
3182
  switch (event.type) {
@@ -3167,7 +3435,7 @@ window.__ModuleLoader__.load({
3167
3435
  return value;
3168
3436
  }
3169
3437
  }
3170
- function record$3(value) {
3438
+ function record$4(value) {
3171
3439
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3172
3440
  }
3173
3441
  function text(value) {
@@ -3181,7 +3449,7 @@ window.__ModuleLoader__.load({
3181
3449
  if (typeof value === "string") return value;
3182
3450
  if (typeof value === "number" || typeof value === "boolean") return String(value);
3183
3451
  if (Array.isArray(value)) return value.map(displayValue).join(", ");
3184
- return record$3(value) === void 0 ? String(value) : Object.entries(value).map(([key, item]) => `${key}: ${displayValue(item)}`).join("\n");
3452
+ return record$4(value) === void 0 ? String(value) : Object.entries(value).map(([key, item]) => `${key}: ${displayValue(item)}`).join("\n");
3185
3453
  }
3186
3454
  function Section({ title, children }) {
3187
3455
  return /* @__PURE__ */ jsxs("section", {
@@ -3251,15 +3519,15 @@ window.__ModuleLoader__.load({
3251
3519
  function ToolPresentation({ tool, t }) {
3252
3520
  const inputValue = parsedValue(tool.input);
3253
3521
  const outputValue = parsedValue(tool.output);
3254
- const input = record$3(inputValue);
3255
- const output = record$3(outputValue);
3522
+ const input = record$4(inputValue);
3523
+ const output = record$4(outputValue);
3256
3524
  const outputTitle = tool.isError === true ? t("toolError") : t("toolOutput");
3257
3525
  if (tool.diffs !== void 0) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(DiffBlock, { diffs: [...tool.diffs] }), /* @__PURE__ */ jsx(TextDetail, {
3258
3526
  title: outputTitle,
3259
3527
  value: typeof outputValue === "string" ? outputValue : void 0
3260
3528
  })] });
3261
3529
  if (tool.toolName === "Read") {
3262
- const file = record$3(output?.file);
3530
+ const file = record$4(output?.file);
3263
3531
  const path = text(file?.filePath) ?? text(input?.file_path);
3264
3532
  const content = text(file?.content) ?? (typeof outputValue === "string" ? outputValue : void 0);
3265
3533
  const offset = numberValue(input?.offset) ?? 1;
@@ -3810,7 +4078,7 @@ window.__ModuleLoader__.load({
3810
4078
  style: diagnosticGrid,
3811
4079
  children: [/* @__PURE__ */ jsx("span", {
3812
4080
  style: diagnosticLabel,
3813
- children: setting.key === "outputStyle" ? t("outputStyle") : setting.key === "worktreeBranchPrefix" ? t("worktreeBranchPrefix") : setting.key
4081
+ children: setting.key === "outputStyle" ? t("outputStyle") : setting.key === "worktreeBranchPrefix" ? t("worktreeBranchPrefix") : setting.key === "maxProcesses" ? t("maxProcessesSetting") : setting.key === "idleTimeoutMinutes" ? t("idleTimeoutSetting") : setting.key
3814
4082
  }), setting.kind === "select" ? /* @__PURE__ */ jsx(GlobalSettingSelect, {
3815
4083
  setting,
3816
4084
  disabled: globalSettingsBusy,
@@ -3833,6 +4101,10 @@ window.__ModuleLoader__.load({
3833
4101
  style: notice,
3834
4102
  children: t("worktreeBranchPrefixEffect")
3835
4103
  }) : null,
4104
+ globalSettings?.settings.some((setting) => setting.key === "maxProcesses") === true ? /* @__PURE__ */ jsx("p", {
4105
+ style: notice,
4106
+ children: t("limitsSettingEffect")
4107
+ }) : null,
3836
4108
  globalSettingsError === void 0 ? null : /* @__PURE__ */ jsxs("p", {
3837
4109
  role: "alert",
3838
4110
  style: {
@@ -3963,34 +4235,34 @@ window.__ModuleLoader__.load({
3963
4235
  if (commit !== void 0) this.commit = commit;
3964
4236
  }
3965
4237
  };
3966
- function record$2(value) {
4238
+ function record$3(value) {
3967
4239
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
3968
4240
  }
3969
4241
  async function response$1(pending) {
3970
4242
  const result = await pending;
3971
4243
  const body = await result.json();
3972
4244
  if (!result.ok) {
3973
- const error = record$2(body);
4245
+ const error = record$3(body);
3974
4246
  throw new RepositoryActionClientError(typeof error?.message === "string" ? error.message : "Repository action failed.", typeof error?.error === "string" ? error.error : void 0, typeof error?.commit === "string" ? error.commit : void 0);
3975
4247
  }
3976
4248
  return body;
3977
4249
  }
3978
4250
  function preview(value) {
3979
- const input = record$2(value);
4251
+ const input = record$3(value);
3980
4252
  if (input === void 0 || typeof input.root !== "string" || typeof input.branch !== "string" || typeof input.head !== "string" || typeof input.fingerprint !== "string" || !Array.isArray(input.files) || typeof input.patch !== "string" || typeof input.truncated !== "boolean" || typeof input.hasStaged !== "boolean" || typeof input.hasUnstaged !== "boolean" || typeof input.hasUntracked !== "boolean" || input.upstream !== void 0 && typeof input.upstream !== "string" || !Array.isArray(input.unpushedCommits) || typeof input.unpushedTruncated !== "boolean") throw new Error("Invalid repository action preview.");
3981
4253
  for (const file of input.files) {
3982
- const item = record$2(file);
4254
+ const item = record$3(file);
3983
4255
  if (item === void 0 || typeof item.path !== "string" || typeof item.staged !== "boolean" || typeof item.unstaged !== "boolean" || typeof item.untracked !== "boolean") throw new Error("Invalid repository action file.");
3984
4256
  }
3985
4257
  for (const commit of input.unpushedCommits) {
3986
- const item = record$2(commit);
4258
+ const item = record$3(commit);
3987
4259
  if (item === void 0 || typeof item.hash !== "string" || typeof item.subject !== "string") throw new Error("Invalid repository action commit.");
3988
4260
  }
3989
4261
  return input;
3990
4262
  }
3991
4263
  function result(value) {
3992
- const input = record$2(value);
3993
- if (input === void 0 || typeof input.commit !== "string" || typeof input.pushed !== "boolean" || input.pullRequestUrl !== void 0 && typeof input.pullRequestUrl !== "string") throw new Error("Invalid repository action result.");
4264
+ const input = record$3(value);
4265
+ if (input === void 0 || typeof input.commit !== "string" || typeof input.pushed !== "boolean" || input.pullRequestUrl !== void 0 && typeof input.pullRequestUrl !== "string" || input.conflicts !== void 0 && (!Array.isArray(input.conflicts) || input.conflicts.some((item) => typeof item !== "string"))) throw new Error("Invalid repository action result.");
3994
4266
  return input;
3995
4267
  }
3996
4268
  function endpoint(path, sessionId) {
@@ -4005,7 +4277,7 @@ window.__ModuleLoader__.load({
4005
4277
  })));
4006
4278
  }
4007
4279
  async function generateCommitMessage(sessionId, fingerprint, signal) {
4008
- const value = record$2(await response$1(fetch(endpoint("/message", sessionId), {
4280
+ const value = record$3(await response$1(fetch(endpoint("/message", sessionId), {
4009
4281
  method: "POST",
4010
4282
  credentials: "same-origin",
4011
4283
  headers: {
@@ -4030,6 +4302,110 @@ window.__ModuleLoader__.load({
4030
4302
  })).then(result);
4031
4303
  }
4032
4304
  //#endregion
4305
+ //#region src/client/pr-feedback-api.ts
4306
+ function record$2(value) {
4307
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
4308
+ }
4309
+ async function loadJson(path, sessionId, pullNumber, signal) {
4310
+ const response = await fetch(`${CLAUDE_REPOSITORY_FEEDBACK_PATH}${path}?sessionId=${encodeURIComponent(sessionId)}&number=${pullNumber}`, {
4311
+ method: "GET",
4312
+ credentials: "same-origin",
4313
+ headers: { accept: "application/json" },
4314
+ ...signal === void 0 ? {} : { signal }
4315
+ });
4316
+ const body = record$2(await response.json());
4317
+ if (!response.ok) throw new Error(typeof body?.message === "string" ? body.message : "Pull request feedback is unavailable.");
4318
+ if (body === void 0) throw new Error("Invalid pull request feedback response.");
4319
+ return body;
4320
+ }
4321
+ async function loadPullRequestComments(sessionId, pullNumber, signal) {
4322
+ const body = await loadJson("/comments", sessionId, pullNumber, signal);
4323
+ if (!Array.isArray(body.comments)) throw new Error("Invalid pull request comments response.");
4324
+ const comments = [];
4325
+ for (const item of body.comments) {
4326
+ const input = record$2(item);
4327
+ if (input === void 0 || typeof input.id !== "number" || typeof input.path !== "string" || typeof input.author !== "string" || typeof input.body !== "string" || typeof input.url !== "string" || input.side !== "new" && input.side !== "old" || input.line !== void 0 && typeof input.line !== "number") continue;
4328
+ comments.push(input);
4329
+ }
4330
+ return comments;
4331
+ }
4332
+ async function loadFailingChecks(sessionId, pullNumber, signal) {
4333
+ const body = await loadJson("/checks", sessionId, pullNumber, signal);
4334
+ if (!Array.isArray(body.checks)) throw new Error("Invalid pull request checks response.");
4335
+ const checks = [];
4336
+ for (const item of body.checks) {
4337
+ const input = record$2(item);
4338
+ if (input === void 0 || typeof input.name !== "string" || input.link !== void 0 && typeof input.link !== "string" || input.description !== void 0 && typeof input.description !== "string" || input.log !== void 0 && typeof input.log !== "string") continue;
4339
+ checks.push(input);
4340
+ }
4341
+ return checks;
4342
+ }
4343
+ /** Draft handed to Claude when the user forwards GitHub review comments. */
4344
+ function composeCommentsPrompt(comments) {
4345
+ return `Please address the following GitHub pull request review comments. Make the requested changes, or explain briefly when a comment should not be applied.\n\n${comments.map((comment) => `- ${comment.path}${comment.line === void 0 ? "" : `:${comment.line}`} (@${comment.author}): ${comment.body.replaceAll("\n", "\n ")}`).join("\n")}`;
4346
+ }
4347
+ /** Draft handed to Claude when the user forwards failing CI checks. */
4348
+ function composeChecksPrompt(checks) {
4349
+ return `The following CI checks are failing on the current pull request. Investigate the failure logs, fix the underlying problems, and re-run the relevant commands locally when possible.\n\n${checks.map((check) => {
4350
+ return `${`## ${check.name}${check.link === void 0 ? "" : ` (${check.link})`}`}${check.description === void 0 ? "" : `\n${check.description}`}${check.log === void 0 ? "" : `\n\n\`\`\`\n${check.log}\n\`\`\``}`;
4351
+ }).join("\n\n")}`;
4352
+ }
4353
+ /** Draft handed to Claude after an update-branch merge left conflicts behind. */
4354
+ function composeConflictsPrompt(baseBranch, conflicts) {
4355
+ return `Merging origin/${baseBranch} into the current branch left merge conflicts in the files below. Resolve each conflict preserving the intent of both sides, then commit the merge.\n\n${conflicts.map((file) => `- ${file}`).join("\n")}`;
4356
+ }
4357
+ //#endregion
4358
+ //#region src/client/auto-fix.ts
4359
+ const AUTO_FIX_INTERVAL_MS = 3e4;
4360
+ const AUTO_FIX_FOOTER = "This request was generated automatically by the pull request watcher. After making the changes, commit and push to the pull request branch so the checks re-run.";
4361
+ const EMPTY_MEMORY = { handledCommentIds: /* @__PURE__ */ new Set() };
4362
+ const sessions = /* @__PURE__ */ new Map();
4363
+ function session(sessionId) {
4364
+ let entry = sessions.get(sessionId);
4365
+ if (entry === void 0) {
4366
+ entry = {
4367
+ enabled: false,
4368
+ memory: EMPTY_MEMORY
4369
+ };
4370
+ sessions.set(sessionId, entry);
4371
+ }
4372
+ return entry;
4373
+ }
4374
+ function autoFixEnabled(sessionId) {
4375
+ return session(sessionId).enabled;
4376
+ }
4377
+ function setAutoFixEnabled(sessionId, enabled) {
4378
+ session(sessionId).enabled = enabled;
4379
+ }
4380
+ function autoFixMemory(sessionId) {
4381
+ return session(sessionId).memory;
4382
+ }
4383
+ function rememberAutoFix(sessionId, memory) {
4384
+ session(sessionId).memory = memory;
4385
+ }
4386
+ /** One failing CI run yields one fix attempt: run links change when CI re-runs. */
4387
+ function checksSignature(checks) {
4388
+ if (checks.length === 0) return void 0;
4389
+ return checks.map((check) => `${check.name}|${check.link ?? ""}`).sort().join("\n");
4390
+ }
4391
+ function planAutoFix(memory, comments, checks) {
4392
+ const fresh = comments.filter((comment) => !memory.handledCommentIds.has(comment.id));
4393
+ const signature = checksSignature(checks);
4394
+ const checksChanged = signature !== void 0 && signature !== memory.handledChecksSignature;
4395
+ const sections = [];
4396
+ if (fresh.length > 0) sections.push(composeCommentsPrompt(fresh));
4397
+ if (checksChanged) sections.push(composeChecksPrompt(checks));
4398
+ if (sections.length === 0) return { memory };
4399
+ const nextSignature = checksChanged ? signature : memory.handledChecksSignature;
4400
+ return {
4401
+ prompt: `${sections.join("\n\n")}\n\n${AUTO_FIX_FOOTER}`,
4402
+ memory: {
4403
+ handledCommentIds: /* @__PURE__ */ new Set([...memory.handledCommentIds, ...fresh.map((comment) => comment.id)]),
4404
+ ...nextSignature === void 0 ? {} : { handledChecksSignature: nextSignature }
4405
+ }
4406
+ };
4407
+ }
4408
+ //#endregion
4033
4409
  //#region src/client/ClaudeRepositoryStatus.tsx
4034
4410
  const RATE_LIMIT_TITLE_PREFIX = "Claude rate limit";
4035
4411
  const RATE_LIMIT_BLOCKING_TITLE = "Claude rate limit is blocking requests";
@@ -4051,7 +4427,10 @@ window.__ModuleLoader__.load({
4051
4427
  children: [/* @__PURE__ */ jsx("span", {
4052
4428
  style: repositoryItemDot,
4053
4429
  "aria-hidden": "true"
4054
- }), label]
4430
+ }), /* @__PURE__ */ jsx("span", {
4431
+ style: repositoryItemLabel,
4432
+ children: label
4433
+ })]
4055
4434
  });
4056
4435
  }
4057
4436
  function PullRequestIcon({ size = 16, merged = false }) {
@@ -4155,7 +4534,8 @@ window.__ModuleLoader__.load({
4155
4534
  children: [
4156
4535
  repositoryName(repository.remote),
4157
4536
  " #",
4158
- pullRequest.number
4537
+ pullRequest.number,
4538
+ pullRequest.baseBranch === void 0 ? "" : ` → ${pullRequest.baseBranch}`
4159
4539
  ]
4160
4540
  }),
4161
4541
  age === void 0 ? null : /* @__PURE__ */ jsx("span", {
@@ -4248,6 +4628,360 @@ window.__ModuleLoader__.load({
4248
4628
  })]
4249
4629
  });
4250
4630
  }
4631
+ /** Watches an open pull request and hands new review comments and failing
4632
+ * CI runs to Claude automatically until the user switches it off. */
4633
+ function AutoFixControl({ sessionId, repository, running, t, submitPrompt }) {
4634
+ const pullRequest = repository.pullRequest;
4635
+ const open = pullRequest?.state === "open";
4636
+ const number = pullRequest?.number;
4637
+ const checks = pullRequest?.checks;
4638
+ const [enabled, setEnabled] = useState(() => autoFixEnabled(sessionId));
4639
+ const [focused, setFocused] = useState(false);
4640
+ useEffect(() => {
4641
+ setEnabled(autoFixEnabled(sessionId));
4642
+ }, [sessionId]);
4643
+ useEffect(() => {
4644
+ if (!enabled || !open || running || number === void 0 || submitPrompt === void 0) return;
4645
+ let cancelled = false;
4646
+ const tick = async () => {
4647
+ const [comments, failing] = await Promise.all([loadPullRequestComments(sessionId, number).catch(() => []), checks === "failing" ? loadFailingChecks(sessionId, number).catch(() => []) : Promise.resolve([])]);
4648
+ if (cancelled) return;
4649
+ const plan = planAutoFix(autoFixMemory(sessionId), comments, failing);
4650
+ if (plan.prompt !== void 0 && submitPrompt(plan.prompt, "idle")) rememberAutoFix(sessionId, plan.memory);
4651
+ };
4652
+ tick();
4653
+ const timer = setInterval(() => {
4654
+ tick();
4655
+ }, AUTO_FIX_INTERVAL_MS);
4656
+ return () => {
4657
+ cancelled = true;
4658
+ clearInterval(timer);
4659
+ };
4660
+ }, [
4661
+ checks,
4662
+ enabled,
4663
+ number,
4664
+ open,
4665
+ running,
4666
+ sessionId,
4667
+ submitPrompt
4668
+ ]);
4669
+ if (!open || submitPrompt === void 0) return null;
4670
+ const toggle = () => {
4671
+ const next = !enabled;
4672
+ setEnabled(next);
4673
+ setAutoFixEnabled(sessionId, next);
4674
+ };
4675
+ return /* @__PURE__ */ jsx(Tooltip, {
4676
+ label: `${t("autoFixLabel")} · ${t("autoFixTitle")}`,
4677
+ side: "top",
4678
+ delayMs: 250,
4679
+ maxWidth: 320,
4680
+ children: /* @__PURE__ */ jsx("button", {
4681
+ type: "button",
4682
+ role: "switch",
4683
+ "aria-checked": enabled,
4684
+ "aria-label": t("autoFixLabel"),
4685
+ style: {
4686
+ ...repositoryAutoFix,
4687
+ ...enabled ? repositoryAutoFixActive : {},
4688
+ ...focused ? heroWorktreeToggleFocused : {}
4689
+ },
4690
+ onFocus: () => {
4691
+ setFocused(true);
4692
+ },
4693
+ onBlur: () => {
4694
+ setFocused(false);
4695
+ },
4696
+ onClick: (event) => {
4697
+ toggle();
4698
+ event.currentTarget.blur();
4699
+ },
4700
+ children: /* @__PURE__ */ jsxs("svg", {
4701
+ width: "14",
4702
+ height: "14",
4703
+ viewBox: "0 0 16 16",
4704
+ fill: "none",
4705
+ stroke: "currentColor",
4706
+ strokeWidth: "1.6",
4707
+ strokeLinecap: "round",
4708
+ strokeLinejoin: "round",
4709
+ "aria-hidden": "true",
4710
+ children: [/* @__PURE__ */ jsx("path", { d: "M13.3 6.5A5.5 5.5 0 0 0 3.6 4.6M2.7 9.5a5.5 5.5 0 0 0 9.7 1.9" }), /* @__PURE__ */ jsx("path", { d: "M13.5 2.8v3.7H9.8M2.5 13.2V9.5h3.7" })]
4711
+ })
4712
+ })
4713
+ });
4714
+ }
4715
+ function FailingChecksControl({ sessionId, pullNumber, t, submitPrompt }) {
4716
+ const [open, setOpen] = useState(false);
4717
+ const [loading, setLoading] = useState(false);
4718
+ const [checks, setChecks] = useState([]);
4719
+ const [error, setError] = useState();
4720
+ const frameRef = useRef(null);
4721
+ const controller = useRef();
4722
+ useEffect(() => () => controller.current?.abort(), []);
4723
+ useEffect(() => {
4724
+ if (!open) return;
4725
+ const closeOnOutsidePointer = (event) => {
4726
+ if (event.target instanceof Node && frameRef.current?.contains(event.target) !== true) setOpen(false);
4727
+ };
4728
+ document.addEventListener("pointerdown", closeOnOutsidePointer);
4729
+ return () => {
4730
+ document.removeEventListener("pointerdown", closeOnOutsidePointer);
4731
+ };
4732
+ }, [open]);
4733
+ const toggle = () => {
4734
+ const next = !open;
4735
+ setOpen(next);
4736
+ if (!next) return;
4737
+ controller.current?.abort();
4738
+ const aborter = new AbortController();
4739
+ controller.current = aborter;
4740
+ setLoading(true);
4741
+ setError(void 0);
4742
+ loadFailingChecks(sessionId, pullNumber, aborter.signal).then((value) => {
4743
+ setChecks(value);
4744
+ setLoading(false);
4745
+ }, (reason) => {
4746
+ if (aborter.signal.aborted) return;
4747
+ setError(reason instanceof Error ? reason.message : t("diffActionFailed"));
4748
+ setLoading(false);
4749
+ });
4750
+ };
4751
+ return /* @__PURE__ */ jsxs("span", {
4752
+ ref: frameRef,
4753
+ style: repositoryChecksFrame,
4754
+ children: [/* @__PURE__ */ jsx("button", {
4755
+ type: "button",
4756
+ style: repositoryChecksTrigger,
4757
+ "aria-haspopup": "dialog",
4758
+ "aria-expanded": open,
4759
+ "aria-label": t("repositoryChecksOpen"),
4760
+ onClick: toggle,
4761
+ children: /* @__PURE__ */ jsx(StatusItem, {
4762
+ label: t("repositoryChecks_failing"),
4763
+ tone: "error"
4764
+ })
4765
+ }), open ? /* @__PURE__ */ jsxs("span", {
4766
+ role: "dialog",
4767
+ "aria-label": t("checksCardTitle"),
4768
+ style: repositoryChecksCard,
4769
+ children: [
4770
+ /* @__PURE__ */ jsx("strong", {
4771
+ style: repositoryChecksTitle,
4772
+ children: t("checksCardTitle")
4773
+ }),
4774
+ loading ? /* @__PURE__ */ jsx("span", {
4775
+ style: repositoryChecksHint,
4776
+ children: t("checksCardLoading")
4777
+ }) : null,
4778
+ error === void 0 ? null : /* @__PURE__ */ jsx("span", {
4779
+ role: "alert",
4780
+ style: repositoryChecksError,
4781
+ children: error
4782
+ }),
4783
+ checks.map((check) => /* @__PURE__ */ jsxs("span", {
4784
+ style: repositoryChecksItem,
4785
+ children: [check.link === void 0 ? /* @__PURE__ */ jsx("span", {
4786
+ style: repositoryChecksName,
4787
+ children: check.name
4788
+ }) : /* @__PURE__ */ jsx("a", {
4789
+ href: check.link,
4790
+ target: "_blank",
4791
+ rel: "noopener noreferrer",
4792
+ style: repositoryChecksName,
4793
+ children: check.name
4794
+ }), check.description === void 0 ? null : /* @__PURE__ */ jsx("span", {
4795
+ style: repositoryChecksDesc,
4796
+ children: check.description
4797
+ })]
4798
+ }, check.name)),
4799
+ !loading && error === void 0 && checks.length === 0 ? /* @__PURE__ */ jsx("span", {
4800
+ style: repositoryChecksHint,
4801
+ children: t("checksCardEmpty")
4802
+ }) : null,
4803
+ submitPrompt !== void 0 && checks.length > 0 ? /* @__PURE__ */ jsx("button", {
4804
+ type: "button",
4805
+ style: repositoryChecksFix,
4806
+ onClick: () => {
4807
+ submitPrompt(composeChecksPrompt(checks));
4808
+ setOpen(false);
4809
+ },
4810
+ children: t("checksCardFix")
4811
+ }) : null
4812
+ ]
4813
+ }) : null]
4814
+ });
4815
+ }
4816
+ function UpdateBranchControl({ sessionId, repository, t, submitPrompt }) {
4817
+ const [dialog, setDialog] = useState();
4818
+ const controller = useRef();
4819
+ const pullRequest = repository.pullRequest;
4820
+ const base = pullRequest?.baseBranch;
4821
+ const behind = repository.baseBehind ?? 0;
4822
+ useEffect(() => () => controller.current?.abort(), []);
4823
+ useEffect(() => {
4824
+ if (dialog?.pushed === void 0 || dialog.error !== void 0) return;
4825
+ const timer = setTimeout(() => setDialog(void 0), 1200);
4826
+ return () => clearTimeout(timer);
4827
+ }, [dialog?.error, dialog?.pushed]);
4828
+ if (pullRequest === void 0 || pullRequest.state !== "open" || base === void 0 || repository.detached === true || repository.dirty === true || behind <= 0) return null;
4829
+ const openDialog = () => {
4830
+ controller.current?.abort();
4831
+ setDialog({
4832
+ loading: true,
4833
+ submitting: false
4834
+ });
4835
+ const aborter = new AbortController();
4836
+ controller.current = aborter;
4837
+ loadRepositoryActionPreview(sessionId, aborter.signal).then((preview) => {
4838
+ setDialog({
4839
+ loading: false,
4840
+ submitting: false,
4841
+ fingerprint: preview.fingerprint
4842
+ });
4843
+ }, (reason) => {
4844
+ if (!aborter.signal.aborted) setDialog({
4845
+ loading: false,
4846
+ submitting: false,
4847
+ error: reason instanceof Error ? reason.message : t("diffActionFailed")
4848
+ });
4849
+ });
4850
+ };
4851
+ const closeDialog = () => {
4852
+ if (dialog?.submitting === true) return;
4853
+ controller.current?.abort();
4854
+ controller.current = void 0;
4855
+ setDialog(void 0);
4856
+ };
4857
+ const confirmUpdate = () => {
4858
+ if (dialog?.fingerprint === void 0 || dialog.submitting) return;
4859
+ const { error: _error, ...pending } = dialog;
4860
+ setDialog({
4861
+ ...pending,
4862
+ submitting: true
4863
+ });
4864
+ executeRepositoryAction(sessionId, {
4865
+ action: "update-branch",
4866
+ fingerprint: dialog.fingerprint,
4867
+ message: "",
4868
+ includeUnstaged: false,
4869
+ baseBranch: base
4870
+ }).then((result) => {
4871
+ setDialog({
4872
+ ...pending,
4873
+ submitting: false,
4874
+ ...result.conflicts !== void 0 && result.conflicts.length > 0 ? { conflicts: result.conflicts } : { pushed: result.commit }
4875
+ });
4876
+ }, (reason) => {
4877
+ setDialog({
4878
+ ...pending,
4879
+ submitting: false,
4880
+ error: reason instanceof Error ? reason.message : t("diffActionFailed")
4881
+ });
4882
+ });
4883
+ };
4884
+ const settled = dialog?.pushed !== void 0 || dialog?.conflicts !== void 0;
4885
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [
4886
+ /* @__PURE__ */ jsxs("button", {
4887
+ type: "button",
4888
+ style: repositoryUpdateTrigger,
4889
+ "aria-label": t("repositoryUpdateBranch"),
4890
+ title: `${t("diffUpdateBranchBehind", {
4891
+ base,
4892
+ count: behind
4893
+ })} · ${t("repositoryUpdateBranch")}`,
4894
+ onClick: openDialog,
4895
+ children: ["↓", behind]
4896
+ }),
4897
+ dialog === void 0 ? null : /* @__PURE__ */ jsx("style", {
4898
+ "data-dsh-claude-repository-modal-styles": true,
4899
+ children: diffModalCss
4900
+ }),
4901
+ /* @__PURE__ */ jsx(Modal, {
4902
+ className: "dshClaudeRepositoryActionModal",
4903
+ contentClassName: "dshClaudeRepositoryActionModalContent",
4904
+ open: dialog !== void 0,
4905
+ onClose: closeDialog,
4906
+ title: t("repositoryUpdateBranch"),
4907
+ closeLabel: t("diffCancel"),
4908
+ description: t("diffUpdateBranchDescription", { base }),
4909
+ footer: /* @__PURE__ */ jsxs("div", {
4910
+ style: diffModalFooter,
4911
+ children: [/* @__PURE__ */ jsx("button", {
4912
+ type: "button",
4913
+ style: {
4914
+ ...button,
4915
+ ...diffModalButton
4916
+ },
4917
+ disabled: dialog?.submitting === true,
4918
+ onClick: closeDialog,
4919
+ children: settled ? t("diffDone") : t("diffCancel")
4920
+ }), !settled ? /* @__PURE__ */ jsx("button", {
4921
+ type: "button",
4922
+ style: {
4923
+ ...primaryButton,
4924
+ ...diffModalButton
4925
+ },
4926
+ disabled: dialog?.loading === true || dialog?.submitting === true || dialog?.fingerprint === void 0,
4927
+ onClick: confirmUpdate,
4928
+ children: dialog?.submitting === true ? t("diffSubmitting") : t("diffConfirm")
4929
+ }) : null]
4930
+ }),
4931
+ children: dialog === void 0 ? null : /* @__PURE__ */ jsxs("div", {
4932
+ style: diffModalBody,
4933
+ children: [
4934
+ /* @__PURE__ */ jsxs("div", {
4935
+ style: diffModalMeta,
4936
+ children: [/* @__PURE__ */ jsxs("strong", {
4937
+ style: diffModalMetaText,
4938
+ title: pullRequest.title,
4939
+ children: [
4940
+ repository.branch ?? t("repositoryUnknownBranch"),
4941
+ " ← origin/",
4942
+ base
4943
+ ]
4944
+ }), /* @__PURE__ */ jsx("span", {
4945
+ style: diffModalFileState,
4946
+ children: t("diffUpdateBranchBehind", {
4947
+ base,
4948
+ count: behind
4949
+ })
4950
+ })]
4951
+ }),
4952
+ dialog.pushed === void 0 ? null : /* @__PURE__ */ jsx("p", {
4953
+ style: diffModalSuccess,
4954
+ children: t("diffUpdateBranchCompleted", { commit: dialog.pushed.slice(0, 8) })
4955
+ }),
4956
+ dialog.conflicts === void 0 ? null : /* @__PURE__ */ jsxs(Fragment$1, { children: [
4957
+ /* @__PURE__ */ jsx("p", {
4958
+ style: diffModalStatus,
4959
+ children: t("diffUpdateBranchConflicts")
4960
+ }),
4961
+ /* @__PURE__ */ jsx("ul", {
4962
+ style: diffModalConflicts,
4963
+ children: dialog.conflicts.map((file) => /* @__PURE__ */ jsx("li", { children: file }, file))
4964
+ }),
4965
+ submitPrompt === void 0 ? null : /* @__PURE__ */ jsx("button", {
4966
+ type: "button",
4967
+ style: diffModalConflictResolve,
4968
+ onClick: () => {
4969
+ submitPrompt(composeConflictsPrompt(base, dialog.conflicts ?? []));
4970
+ closeDialog();
4971
+ },
4972
+ children: t("diffUpdateBranchResolve")
4973
+ })
4974
+ ] }),
4975
+ dialog.error === void 0 ? null : /* @__PURE__ */ jsx("p", {
4976
+ role: "alert",
4977
+ style: diffModalError,
4978
+ children: dialog.error
4979
+ })
4980
+ ]
4981
+ })
4982
+ })
4983
+ ] });
4984
+ }
4251
4985
  const MERGE_METHODS = [
4252
4986
  "merge",
4253
4987
  "squash",
@@ -4417,8 +5151,9 @@ window.__ModuleLoader__.load({
4417
5151
  })
4418
5152
  ] });
4419
5153
  }
4420
- function ClaudeRepositoryStatus({ sessionId, useSessions, useClaudeProjection, t, openDiff }) {
5154
+ function ClaudeRepositoryStatus({ sessionId, useSessions, useClaudeProjection, t, openDiff, submitPrompt }) {
4421
5155
  const blank = useSessions((value) => value.byId[sessionId]?.blank === true);
5156
+ const running = useSessions((value) => value.byId[sessionId]?.running === true);
4422
5157
  const projection = useClaudeProjection((value) => value);
4423
5158
  const repository = projection.repository;
4424
5159
  if (blank || !projection.owned || repository === void 0) return null;
@@ -4514,21 +5249,39 @@ window.__ModuleLoader__.load({
4514
5249
  style: repositoryMergedDot,
4515
5250
  "aria-hidden": "true"
4516
5251
  }),
4517
- t("repositoryMergedInto", { branch: pullRequest.baseBranch ?? t("repositoryUnknownBranch") }),
5252
+ t("repositoryState_merged"),
4518
5253
  mergedAge === void 0 ? null : /* @__PURE__ */ jsxs("span", {
4519
5254
  style: repositoryMergedAge,
4520
5255
  children: ["· ", t("repositoryMergedAgo", { age: mergedAge })]
4521
5256
  })
4522
5257
  ]
4523
5258
  }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
4524
- /* @__PURE__ */ jsx(StatusItem, {
5259
+ pullRequest.checks === "failing" ? /* @__PURE__ */ jsx(FailingChecksControl, {
5260
+ sessionId,
5261
+ pullNumber: pullRequest.number,
5262
+ t,
5263
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
5264
+ }) : pullRequest.checks === "none" ? null : /* @__PURE__ */ jsx(StatusItem, {
4525
5265
  label: t(`repositoryChecks_${pullRequest.checks}`),
4526
- tone: pullRequest.checks === "passing" ? "success" : pullRequest.checks === "failing" ? "error" : pullRequest.checks === "pending" ? "warning" : "neutral"
5266
+ tone: pullRequest.checks === "passing" ? "success" : "warning"
4527
5267
  }),
4528
- /* @__PURE__ */ jsx(StatusItem, {
5268
+ pullRequest.review === "none" ? null : /* @__PURE__ */ jsx(StatusItem, {
4529
5269
  label: t(`repositoryReview_${pullRequest.review}`),
4530
5270
  tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral"
4531
5271
  }),
5272
+ /* @__PURE__ */ jsx(AutoFixControl, {
5273
+ sessionId,
5274
+ repository,
5275
+ running,
5276
+ t,
5277
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
5278
+ }),
5279
+ /* @__PURE__ */ jsx(UpdateBranchControl, {
5280
+ sessionId,
5281
+ repository,
5282
+ t,
5283
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
5284
+ }),
4532
5285
  /* @__PURE__ */ jsx(MergePullRequestControl, {
4533
5286
  sessionId,
4534
5287
  repository,
@@ -4837,7 +5590,7 @@ window.__ModuleLoader__.load({
4837
5590
  ]
4838
5591
  });
4839
5592
  }
4840
- function DiffFileSection({ file, initiallyOpen, t, comments, editorAnchor, editorNode, onOpenEditor, onRemoveComment }) {
5593
+ function DiffFileSection({ file, initiallyOpen, t, comments, ghComments, editorAnchor, editorNode, onOpenEditor, onRemoveComment }) {
4841
5594
  const [open, setOpen] = useState(initiallyOpen);
4842
5595
  return /* @__PURE__ */ jsxs("section", {
4843
5596
  style: diffFile,
@@ -4874,6 +5627,7 @@ window.__ModuleLoader__.load({
4874
5627
  children: numberDiffLines(file.lines).map((entry, index) => {
4875
5628
  const anchor = commentAnchorForLine(entry);
4876
5629
  const lineComments = anchor === void 0 ? [] : comments.filter((comment) => comment.line === anchor.line && comment.side === anchor.side);
5630
+ const ghLineComments = anchor === void 0 ? [] : ghComments.filter((comment) => comment.line === anchor.line && comment.side === anchor.side);
4877
5631
  const editorOpen = anchor !== void 0 && editorAnchor !== void 0 && editorAnchor.line === anchor.line && editorAnchor.side === anchor.side;
4878
5632
  return /* @__PURE__ */ jsxs(Fragment, { children: [
4879
5633
  /* @__PURE__ */ jsx(DiffLine, {
@@ -4897,6 +5651,26 @@ window.__ModuleLoader__.load({
4897
5651
  children: comment.text
4898
5652
  })]
4899
5653
  }, comment.id)),
5654
+ ghLineComments.map((comment) => /* @__PURE__ */ jsxs("div", {
5655
+ style: diffCommentBlock,
5656
+ children: [/* @__PURE__ */ jsxs("div", {
5657
+ style: diffCommentCardMeta,
5658
+ children: [/* @__PURE__ */ jsxs("span", {
5659
+ style: diffGhCommentAuthor,
5660
+ children: ["GitHub · @", comment.author]
5661
+ }), /* @__PURE__ */ jsx("a", {
5662
+ href: comment.url,
5663
+ target: "_blank",
5664
+ rel: "noopener noreferrer",
5665
+ style: diffGhCommentLink,
5666
+ "aria-label": comment.url,
5667
+ children: "↗"
5668
+ })]
5669
+ }), /* @__PURE__ */ jsx("p", {
5670
+ style: diffCommentCardText,
5671
+ children: comment.body
5672
+ })]
5673
+ }, `gh-${comment.id}`)),
4900
5674
  editorOpen ? editorNode : null
4901
5675
  ] }, `${index}:${entry.line}`);
4902
5676
  })
@@ -4904,7 +5678,7 @@ window.__ModuleLoader__.load({
4904
5678
  });
4905
5679
  }
4906
5680
  function actionLabel(action, t) {
4907
- return (action === "commit" ? t("diffCommit") : action === "commit-push" ? t("diffCommitPush") : action === "push" ? t("diffPush") : action === "merge-pr" ? t("diffMergePr") : t("diffCreatePr")).replace(/[….]+$/u, "");
5681
+ return (action === "commit" ? t("diffCommit") : action === "commit-push" ? t("diffCommitPush") : action === "push" ? t("diffPush") : action === "merge-pr" ? t("diffMergePr") : action === "update-branch" ? t("diffUpdateBranch") : t("diffCreatePr")).replace(/[….]+$/u, "");
4908
5682
  }
4909
5683
  function repositoryActionAvailability(repository) {
4910
5684
  const ready = repository?.status === "ready" && repository.detached !== true;
@@ -4917,7 +5691,8 @@ window.__ModuleLoader__.load({
4917
5691
  "commit-push": committable && hasRemote,
4918
5692
  "push": pushable,
4919
5693
  "create-pr": (committable || pushable) && hasRemote && !hasOpenPullRequest,
4920
- "merge-pr": ready && hasOpenPullRequest && repository?.pullRequest?.draft !== true
5694
+ "merge-pr": ready && hasOpenPullRequest && repository?.pullRequest?.draft !== true,
5695
+ "update-branch": ready && hasOpenPullRequest && repository?.dirty !== true && (repository?.baseBehind ?? 0) > 0
4921
5696
  };
4922
5697
  }
4923
5698
  function RestorePanelIcon() {
@@ -4930,7 +5705,7 @@ window.__ModuleLoader__.load({
4930
5705
  children: /* @__PURE__ */ jsx("path", { d: "M1.5 5h3V2h1.4v4.4H1.5V5Zm9.9-3h1.4v3h3v1.4h-4.4V2ZM1.5 9.6h4.4V14H4.5v-3h-3V9.6Zm9.9 0h4.4V11h-3v3h-1.4V9.6Z" })
4931
5706
  });
4932
5707
  }
4933
- function ClaudeDiffPanel({ useClaudeProjection, t, sessionId, maximized, closeDetails, toggleMaximized }) {
5708
+ function ClaudeDiffPanel({ useClaudeProjection, t, sessionId, maximized, closeDetails, toggleMaximized, submitPrompt }) {
4934
5709
  const projection = useClaudeProjection((value) => value);
4935
5710
  const repository = projection.repository;
4936
5711
  const diff = repository?.diff;
@@ -4950,6 +5725,17 @@ window.__ModuleLoader__.load({
4950
5725
  const [localComments, setLocalComments] = useState([]);
4951
5726
  const [removedCommentIds, setRemovedCommentIds] = useState(() => /* @__PURE__ */ new Set());
4952
5727
  const actionController = useRef();
5728
+ const [ghComments, setGhComments] = useState([]);
5729
+ const pullNumber = repository?.pullRequest?.state === "open" ? repository.pullRequest.number : void 0;
5730
+ useEffect(() => {
5731
+ setGhComments([]);
5732
+ if (pullNumber === void 0) return;
5733
+ const controller = new AbortController();
5734
+ loadPullRequestComments(sessionId, pullNumber, controller.signal).then(setGhComments, () => void 0);
5735
+ return () => {
5736
+ controller.abort();
5737
+ };
5738
+ }, [pullNumber, sessionId]);
4953
5739
  const diffViewportObserver = useRef();
4954
5740
  const diffBodyRef = useCallback((element) => {
4955
5741
  diffViewportObserver.current?.disconnect();
@@ -5243,7 +6029,10 @@ window.__ModuleLoader__.load({
5243
6029
  "aria-hidden": "true",
5244
6030
  children: "›"
5245
6031
  }),
5246
- /* @__PURE__ */ jsx("span", { children: t("diffWorkingTree") })
6032
+ /* @__PURE__ */ jsx("span", {
6033
+ style: diffHeaderLabel,
6034
+ children: t("diffWorkingTree")
6035
+ })
5247
6036
  ]
5248
6037
  }), /* @__PURE__ */ jsxs("div", {
5249
6038
  style: diffHeaderActions,
@@ -5282,6 +6071,25 @@ window.__ModuleLoader__.load({
5282
6071
  })
5283
6072
  })]
5284
6073
  }),
6074
+ ghComments.length > 0 && submitPrompt !== void 0 ? /* @__PURE__ */ jsxs("button", {
6075
+ type: "button",
6076
+ style: diffPrCommentsButton,
6077
+ title: t("prCommentsSend"),
6078
+ "aria-label": t("prCommentsButton", { count: ghComments.length }),
6079
+ onClick: () => submitPrompt(composeCommentsPrompt(ghComments)),
6080
+ children: [/* @__PURE__ */ jsx("svg", {
6081
+ width: "14",
6082
+ height: "14",
6083
+ viewBox: "0 0 16 16",
6084
+ fill: "none",
6085
+ stroke: "currentColor",
6086
+ strokeWidth: "1.5",
6087
+ strokeLinecap: "round",
6088
+ strokeLinejoin: "round",
6089
+ "aria-hidden": "true",
6090
+ children: /* @__PURE__ */ jsx("path", { d: "M2.75 2.75h10.5a1 1 0 0 1 1 1v6.5a1 1 0 0 1-1 1H8.2l-3.2 2.9v-2.9H2.75a1 1 0 0 1-1-1v-6.5a1 1 0 0 1 1-1Z" })
6091
+ }), ghComments.length]
6092
+ }) : null,
5285
6093
  /* @__PURE__ */ jsx("button", {
5286
6094
  type: "button",
5287
6095
  className: panelIconButtonClass,
@@ -5327,6 +6135,7 @@ window.__ModuleLoader__.load({
5327
6135
  initiallyOpen: index === 0,
5328
6136
  t,
5329
6137
  comments: reviewComments.filter((comment) => comment.path === file.path),
6138
+ ghComments: ghComments.filter((comment) => comment.path === file.path),
5330
6139
  editorAnchor: commentEditor !== void 0 && commentEditor.path === file.path ? commentEditor : void 0,
5331
6140
  editorNode: commentEditorNode,
5332
6141
  onOpenEditor: (anchor) => openCommentEditor(file.path, anchor),
@@ -5581,6 +6390,165 @@ window.__ModuleLoader__.load({
5581
6390
  });
5582
6391
  }
5583
6392
  //#endregion
6393
+ //#region src/client/ClaudeQueueDock.tsx
6394
+ /** Replaces the Host queue strip (same slot cell, lower priority) with one
6395
+ * styled like the repository status bar. Behaviour mirrors the Host strip:
6396
+ * one row inline, several rows behind a collapsible count, edit/remove/steer. */
6397
+ function ClaudeQueueDock({ useSession, t, updateQueue, notify }) {
6398
+ const inbox = useSession((session) => session.queue);
6399
+ const queue = useMemo(() => inbox.filter((row) => row.placement === "queued"), [inbox]);
6400
+ const running = useSession((session) => session.running);
6401
+ const mutable = useSession((session) => session.subagent === null);
6402
+ const [editing, setEditing] = useState();
6403
+ const [busy, setBusy] = useState();
6404
+ const [collapsed, setCollapsed] = useState(true);
6405
+ const listId = useId();
6406
+ useEffect(() => {
6407
+ if (queue.length === 0 && !collapsed) setCollapsed(true);
6408
+ if (editing !== void 0 && (!mutable || !queue.some((row) => row.id === editing.id))) setEditing(void 0);
6409
+ }, [
6410
+ collapsed,
6411
+ editing,
6412
+ mutable,
6413
+ queue
6414
+ ]);
6415
+ if (queue.length === 0) return null;
6416
+ const interacting = mutable && (editing !== void 0 || busy !== void 0);
6417
+ const expanded = !collapsed || interacting;
6418
+ const listVisible = queue.length === 1 || expanded;
6419
+ const apply = async (id, action, failure) => {
6420
+ setBusy(id);
6421
+ try {
6422
+ await updateQueue(id, action);
6423
+ return true;
6424
+ } catch {
6425
+ notify("error", failure);
6426
+ return false;
6427
+ } finally {
6428
+ setBusy((current) => current === id ? void 0 : current);
6429
+ }
6430
+ };
6431
+ const saveEdit = async () => {
6432
+ if (editing === void 0 || editing.text.trim() === "") return;
6433
+ if (await apply(editing.id, {
6434
+ kind: "edit",
6435
+ content: [{
6436
+ type: "text",
6437
+ text: editing.text
6438
+ }]
6439
+ }, t("queueEditFailed"))) setEditing(void 0);
6440
+ };
6441
+ const action = (label, icon, onClick, disabled, hint) => /* @__PURE__ */ jsx(Tooltip, {
6442
+ label: hint ?? label,
6443
+ side: "bottom",
6444
+ delayMs: 400,
6445
+ children: /* @__PURE__ */ jsx("button", {
6446
+ type: "button",
6447
+ className: panelIconButtonClass,
6448
+ "aria-label": label,
6449
+ disabled,
6450
+ onClick,
6451
+ children: icon
6452
+ })
6453
+ });
6454
+ return /* @__PURE__ */ jsxs("div", {
6455
+ style: repositoryBarFrame,
6456
+ "data-claude-queue-dock": "",
6457
+ children: [/* @__PURE__ */ jsx("style", {
6458
+ "data-dsh-claude-queue-styles": true,
6459
+ children: panelIconButtonCss
6460
+ }), /* @__PURE__ */ jsxs("div", {
6461
+ style: queueBar,
6462
+ children: [queue.length > 1 ? /* @__PURE__ */ jsxs("button", {
6463
+ type: "button",
6464
+ style: queueHeader,
6465
+ "aria-controls": listId,
6466
+ "aria-expanded": expanded,
6467
+ disabled: interacting,
6468
+ onClick: () => {
6469
+ setCollapsed((value) => !value);
6470
+ },
6471
+ children: [
6472
+ /* @__PURE__ */ jsx("span", {
6473
+ style: queueLead,
6474
+ "aria-hidden": "true",
6475
+ children: /* @__PURE__ */ jsx(IconQueueOutline14, {})
6476
+ }),
6477
+ /* @__PURE__ */ jsx("span", {
6478
+ style: queueCount,
6479
+ children: t("queueCount", { n: queue.length })
6480
+ }),
6481
+ /* @__PURE__ */ jsx("span", {
6482
+ style: queueLead,
6483
+ "aria-hidden": "true",
6484
+ children: expanded ? /* @__PURE__ */ jsx(IconChevronDownOutline14, {}) : /* @__PURE__ */ jsx(IconChevronUpOutline14, {})
6485
+ })
6486
+ ]
6487
+ }) : null, /* @__PURE__ */ jsx("ul", {
6488
+ id: listId,
6489
+ style: queueList,
6490
+ hidden: !listVisible,
6491
+ children: listVisible ? queue.map((row, index) => /* @__PURE__ */ jsxs("li", {
6492
+ style: {
6493
+ ...queueRow,
6494
+ ...index > 0 ? queueRowDivider : {}
6495
+ },
6496
+ children: [
6497
+ queue.length === 1 ? /* @__PURE__ */ jsx("span", {
6498
+ style: queueLead,
6499
+ "aria-hidden": "true",
6500
+ children: /* @__PURE__ */ jsx(IconQueueOutline14, {})
6501
+ }) : null,
6502
+ editing?.id === row.id ? /* @__PURE__ */ jsx("input", {
6503
+ autoFocus: true,
6504
+ style: queueEditor,
6505
+ "aria-label": t("queueEdit"),
6506
+ value: editing.text,
6507
+ onChange: (event) => {
6508
+ setEditing({
6509
+ id: row.id,
6510
+ text: event.currentTarget.value
6511
+ });
6512
+ },
6513
+ onKeyDown: (event) => {
6514
+ if (event.key === "Escape") setEditing(void 0);
6515
+ else if (event.key === "Enter" && !event.nativeEvent.isComposing) {
6516
+ event.preventDefault();
6517
+ saveEdit();
6518
+ }
6519
+ }
6520
+ }) : /* @__PURE__ */ jsx("span", {
6521
+ style: queuePreview,
6522
+ children: row.preview
6523
+ }),
6524
+ mutable ? /* @__PURE__ */ jsx("span", {
6525
+ style: queueActions,
6526
+ children: editing?.id === row.id ? /* @__PURE__ */ jsxs(Fragment$1, { children: [action(t("queueSave"), /* @__PURE__ */ jsx(IconCheckOutline16, { size: 14 }), () => {
6527
+ saveEdit();
6528
+ }, busy !== void 0 || editing.text.trim() === ""), action(t("queueCancelEdit"), /* @__PURE__ */ jsx(IconCloseOutline16, { size: 14 }), () => {
6529
+ setEditing(void 0);
6530
+ }, busy !== void 0)] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
6531
+ action(t("queueEdit"), /* @__PURE__ */ jsx(IconEditOutline16, { size: 14 }), () => {
6532
+ if (row.text !== null) setEditing({
6533
+ id: row.id,
6534
+ text: row.text
6535
+ });
6536
+ }, busy !== void 0 || row.text === null, row.text === null ? t("queueEditUnsupported") : void 0),
6537
+ action(t("queueRemove"), /* @__PURE__ */ jsx(IconTrashOutline16, { size: 14 }), () => {
6538
+ apply(row.id, { kind: "remove" }, t("queueRemoveFailed"));
6539
+ }, busy !== void 0),
6540
+ action(t("queueSteer"), /* @__PURE__ */ jsx(IconSendOutline14, {}), () => {
6541
+ apply(row.id, { kind: "steer" }, t("queueSteerFailed"));
6542
+ }, busy !== void 0 || !running, running ? void 0 : t("queueSteerUnavailable"))
6543
+ ] })
6544
+ }) : null
6545
+ ]
6546
+ }, row.id)) : null
6547
+ })]
6548
+ })]
6549
+ });
6550
+ }
6551
+ //#endregion
5584
6552
  //#region src/client/hero-dom-bridge.ts
5585
6553
  const PORTAL_ATTRIBUTE = "data-dsh-claude-hero-controls";
5586
6554
  function normalizedText(element) {
@@ -6477,6 +7445,9 @@ window.__ModuleLoader__.load({
6477
7445
  outputStyle: "Output Style",
6478
7446
  worktreeBranchPrefix: "Worktree 分支前缀",
6479
7447
  worktreeBranchPrefixEffect: "分支前缀修改会应用于之后自动创建的 Worktree 分支;显式指定的完整分支名不会被修改。",
7448
+ maxProcessesSetting: "Claude 进程上限",
7449
+ idleTimeoutSetting: "闲置回收时长(分钟)",
7450
+ limitsSettingEffect: "进程上限在下次启动 Claude 进程时生效;闲置回收时长在下一次回合结束后生效。留空或非法值会被拒绝。",
6480
7451
  pluginUpdate: "插件更新",
6481
7452
  pluginUpdateBody: "检查 npm 上的新版本。只有可唯一识别的 npm 安装才能直接更新;本地开发链接不会被替换。",
6482
7453
  updateNotChecked: "尚未检查更新。",
@@ -6570,7 +7541,6 @@ window.__ModuleLoader__.load({
6570
7541
  repositoryState_open: "开放",
6571
7542
  repositoryState_closed: "已关闭",
6572
7543
  repositoryState_merged: "已合并",
6573
- repositoryMergedInto: "已合并到 {branch}",
6574
7544
  repositoryMergedAgo: "{age}前",
6575
7545
  repositoryChecks: "检查",
6576
7546
  repositoryChecks_passing: "检查通过",
@@ -6631,6 +7601,33 @@ window.__ModuleLoader__.load({
6631
7601
  diffMerge_rebase: "Rebase 合并",
6632
7602
  diffMergeDescription: "使用所选方式合并当前分支的 Pull Request。",
6633
7603
  diffMergeCompleted: "已合并 PR #{number}",
7604
+ diffUpdateBranch: "Update branch…",
7605
+ repositoryUpdateBranch: "Update branch",
7606
+ diffUpdateBranchDescription: "将 origin/{base} 合并进当前分支并推送;出现冲突时可交给 Claude 解决。",
7607
+ diffUpdateBranchBehind: "落后 origin/{base} {count} 个 commit",
7608
+ diffUpdateBranchCompleted: "已合并并推送 commit {commit}",
7609
+ diffUpdateBranchConflicts: "合并产生冲突,以下文件需要解决:",
7610
+ diffUpdateBranchResolve: "让 Claude 解决冲突",
7611
+ repositoryChecksOpen: "查看失败的检查",
7612
+ checksCardTitle: "失败的检查",
7613
+ checksCardLoading: "正在读取检查详情…",
7614
+ checksCardEmpty: "未能读取失败详情",
7615
+ checksCardFix: "让 Claude 修复",
7616
+ prCommentsButton: "GitHub 评论 ({count})",
7617
+ prCommentsSend: "让 Claude 处理 GitHub 上的 PR 评论",
7618
+ autoFixLabel: "Auto fix",
7619
+ autoFixTitle: "自动监听这个 PR 的 review 评论与 CI 失败,交给 Claude 修复并推送,直到全部通过;取消勾选即停止。",
7620
+ queueCount: "{n} 条排队消息",
7621
+ queueEdit: "编辑",
7622
+ queueEditUnsupported: "包含非文本内容,无法编辑",
7623
+ queueSave: "保存",
7624
+ queueCancelEdit: "取消编辑",
7625
+ queueRemove: "删除",
7626
+ queueSteer: "插入当前回合",
7627
+ queueSteerUnavailable: "没有正在运行的回合",
7628
+ queueEditFailed: "排队消息编辑失败。",
7629
+ queueRemoveFailed: "排队消息删除失败。",
7630
+ queueSteerFailed: "排队消息插入失败。",
6634
7631
  reviewCommentAdd: "添加行评论",
6635
7632
  reviewCommentPlaceholder: "请求更改",
6636
7633
  reviewCommentSubmit: "注释",
@@ -6686,6 +7683,9 @@ window.__ModuleLoader__.load({
6686
7683
  outputStyle: "Output Style",
6687
7684
  worktreeBranchPrefix: "Worktree branch prefix",
6688
7685
  worktreeBranchPrefixEffect: "Prefix changes apply to subsequently generated Worktree branches. Explicit full branch names remain unchanged.",
7686
+ maxProcessesSetting: "Claude process limit",
7687
+ idleTimeoutSetting: "Idle timeout (minutes)",
7688
+ limitsSettingEffect: "The process limit applies when the next Claude process is admitted; the idle timeout applies after the next completed turn.",
6689
7689
  pluginUpdate: "Plugin updates",
6690
7690
  pluginUpdateBody: "Check npm for new releases. Only a uniquely identified npm installation can update in place; local development links are never replaced.",
6691
7691
  updateNotChecked: "Updates have not been checked yet.",
@@ -6779,7 +7779,6 @@ window.__ModuleLoader__.load({
6779
7779
  repositoryState_open: "Open",
6780
7780
  repositoryState_closed: "Closed",
6781
7781
  repositoryState_merged: "Merged",
6782
- repositoryMergedInto: "Merged into {branch}",
6783
7782
  repositoryMergedAgo: "{age} ago",
6784
7783
  repositoryChecks: "Checks",
6785
7784
  repositoryChecks_passing: "Checks passing",
@@ -6840,6 +7839,33 @@ window.__ModuleLoader__.load({
6840
7839
  diffMerge_rebase: "Rebase and merge",
6841
7840
  diffMergeDescription: "Merge the pull request for this branch with the selected method.",
6842
7841
  diffMergeCompleted: "Merged PR #{number}",
7842
+ diffUpdateBranch: "Update branch…",
7843
+ repositoryUpdateBranch: "Update branch",
7844
+ diffUpdateBranchDescription: "Merge origin/{base} into the current branch and push; hand any conflicts to Claude.",
7845
+ diffUpdateBranchBehind: "{count} commit(s) behind origin/{base}",
7846
+ diffUpdateBranchCompleted: "Merged and pushed commit {commit}",
7847
+ diffUpdateBranchConflicts: "The merge left conflicts in these files:",
7848
+ diffUpdateBranchResolve: "Have Claude resolve the conflicts",
7849
+ repositoryChecksOpen: "Show failing checks",
7850
+ checksCardTitle: "Failing checks",
7851
+ checksCardLoading: "Loading check details…",
7852
+ checksCardEmpty: "No failure details available",
7853
+ checksCardFix: "Have Claude fix these",
7854
+ prCommentsButton: "GitHub comments ({count})",
7855
+ prCommentsSend: "Have Claude address the GitHub pull request comments",
7856
+ autoFixLabel: "Auto fix",
7857
+ autoFixTitle: "Watch this pull request for review comments and failing checks, hand them to Claude to fix and push until everything passes; uncheck to stop.",
7858
+ queueCount: "{n} queued messages",
7859
+ queueEdit: "Edit",
7860
+ queueEditUnsupported: "Contains non-text content and cannot be edited",
7861
+ queueSave: "Save",
7862
+ queueCancelEdit: "Cancel edit",
7863
+ queueRemove: "Remove",
7864
+ queueSteer: "Steer into the running turn",
7865
+ queueSteerUnavailable: "No running turn to steer into",
7866
+ queueEditFailed: "The queued message could not be edited.",
7867
+ queueRemoveFailed: "The queued message could not be removed.",
7868
+ queueSteerFailed: "The queued message could not be steered.",
6843
7869
  reviewCommentAdd: "Add line comment",
6844
7870
  reviewCommentPlaceholder: "Request changes",
6845
7871
  reviewCommentSubmit: "Comment",
@@ -6854,7 +7880,7 @@ window.__ModuleLoader__.load({
6854
7880
  };
6855
7881
  //#endregion
6856
7882
  //#region src/client/index.tsx
6857
- function MaximizedDiff({ source, t, sessionId, closeDetails, restore }) {
7883
+ function MaximizedDiff({ source, t, sessionId, closeDetails, restore, submitPrompt }) {
6858
7884
  const snapshot = useSyncExternalStore(source.subscribe, source.getSnapshot, source.getSnapshot);
6859
7885
  const useClaudeProjection = (selector) => selector(snapshot);
6860
7886
  return /* @__PURE__ */ jsx(ClaudeDiffOverlay, {
@@ -6865,7 +7891,8 @@ window.__ModuleLoader__.load({
6865
7891
  sessionId,
6866
7892
  maximized: true,
6867
7893
  closeDetails,
6868
- toggleMaximized: restore
7894
+ toggleMaximized: restore,
7895
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
6869
7896
  })
6870
7897
  });
6871
7898
  }
@@ -6893,6 +7920,23 @@ window.__ModuleLoader__.load({
6893
7920
  const workspaces = ctx.get("workspaces");
6894
7921
  const conversation = ctx.get("conversation");
6895
7922
  const connection = ctx.get("connection");
7923
+ /** Composer submit hook shared by the repository feedback affordances.
7924
+ * 'append' keeps any user draft and adds the prompt below it; 'idle'
7925
+ * submits only when the composer is empty and reports false otherwise. */
7926
+ const submitPromptFor = (sessionId) => {
7927
+ if (sessions === void 0 || conversation === void 0) return void 0;
7928
+ return (draft, mode = "append") => {
7929
+ const scope = sessions.scope(sessionId);
7930
+ if (scope === void 0) return false;
7931
+ const input = conversation.input.for(scope);
7932
+ const current = input.state.getSnapshot().draft;
7933
+ if (current.trim() === "") input.setDraft(draft);
7934
+ else if (mode === "append") input.setDraft(`${current}\n\n${draft}`);
7935
+ else return false;
7936
+ input.submit();
7937
+ return true;
7938
+ };
7939
+ };
6896
7940
  if (sessions !== void 0) ctx.effect(() => sessions.provide({
6897
7941
  hooks: ["claudeProjection"],
6898
7942
  resolve: (binding) => ({ hooks: { claudeProjection: projections.source(binding.sessionId) } })
@@ -6955,6 +7999,7 @@ window.__ModuleLoader__.load({
6955
7999
  const openDiffPanel = (sessionId) => {
6956
8000
  closePluginDetails();
6957
8001
  detailsSessionId = sessionId;
8002
+ const submitPrompt = submitPromptFor(sessionId);
6958
8003
  const registerDetails = () => {
6959
8004
  try {
6960
8005
  disposePluginDetails = ctx.slots.register({
@@ -6966,7 +8011,8 @@ window.__ModuleLoader__.load({
6966
8011
  sessionId,
6967
8012
  maximized: false,
6968
8013
  closeDetails: closePluginDetails,
6969
- toggleMaximized: maximizeDiff
8014
+ toggleMaximized: maximizeDiff,
8015
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
6970
8016
  })
6971
8017
  }, ClaudeDiffPanel);
6972
8018
  } catch {
@@ -6994,7 +8040,8 @@ window.__ModuleLoader__.load({
6994
8040
  t,
6995
8041
  sessionId,
6996
8042
  closeDetails: closePluginDetails,
6997
- restore: restoreDiff
8043
+ restore: restoreDiff,
8044
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
6998
8045
  }));
6999
8046
  } catch {
7000
8047
  disposeDiffOverlay = void 0;
@@ -7059,11 +8106,33 @@ window.__ModuleLoader__.load({
7059
8106
  id: "claude-repository-status",
7060
8107
  order: 20.5,
7061
8108
  locale: namespace,
7062
- inject: (sessionId) => ({
7063
- t,
7064
- openDiff: () => openDiffPanel(sessionId)
7065
- })
8109
+ inject: (sessionId) => {
8110
+ const submitPrompt = submitPromptFor(sessionId);
8111
+ return {
8112
+ t,
8113
+ openDiff: () => openDiffPanel(sessionId),
8114
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
8115
+ };
8116
+ }
7066
8117
  }, ClaudeRepositoryStatus));
8118
+ if (sessions !== void 0 && conversation !== void 0) ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
8119
+ name: "conversation.input.dock",
8120
+ id: "queue",
8121
+ order: 20,
8122
+ priority: -10,
8123
+ locale: namespace,
8124
+ inject: (sessionId) => {
8125
+ const scope = sessions.scope(sessionId);
8126
+ const target = (scope === void 0 ? void 0 : scope.get("conversation")) ?? conversation;
8127
+ return {
8128
+ t,
8129
+ updateQueue: (itemId, action) => target.updateQueue(itemId, action),
8130
+ notify: (level, text) => {
8131
+ if (scope !== void 0) conversation.input.for(scope).notify(level, text);
8132
+ }
8133
+ };
8134
+ }
8135
+ }, ClaudeQueueDock));
7067
8136
  if (sessions !== void 0 && workspaces !== void 0 && conversation !== void 0 && connection !== void 0) ctx.slots.inject("conversation.input.dock", () => ctx.slots.register({
7068
8137
  name: "conversation.input.dock",
7069
8138
  id: "claude-hero-repository-controls",