@norman-else/dsh-claude 0.1.26 → 0.1.28

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
@@ -12,6 +12,7 @@ window.__ModuleLoader__.load({
12
12
  const TASK_TOOL_NAMES = /* @__PURE__ */ new Set(["Task", "Agent"]);
13
13
  const CLAUDE_DOCTOR_PATH = "/plugins/dsh-claude/doctor";
14
14
  const CLAUDE_UPDATE_CHECK_PATH = "/plugins/dsh-claude/update/check";
15
+ const CLAUDE_USAGE_PATH = "/plugins/dsh-claude/usage";
15
16
  const CLAUDE_UPDATE_PATH = "/plugins/dsh-claude/update";
16
17
  const CLAUDE_PROJECTION_PATH = "/plugins/dsh-claude/projection";
17
18
  const CLAUDE_GLOBAL_SETTINGS_PATH = "/plugins/dsh-claude/settings/global";
@@ -713,6 +714,63 @@ window.__ModuleLoader__.load({
713
714
  fontWeight: 700,
714
715
  textAlign: "center"
715
716
  };
717
+ const settingHint = {
718
+ display: "inline-grid",
719
+ placeItems: "center",
720
+ width: 14,
721
+ height: 14,
722
+ marginLeft: 6,
723
+ verticalAlign: "text-top",
724
+ borderRadius: "50%",
725
+ border: "1px solid currentColor",
726
+ color: "var(--dsw-alias-label-tertiary)",
727
+ fontSize: 9,
728
+ fontWeight: 600,
729
+ lineHeight: 1,
730
+ cursor: "help",
731
+ userSelect: "none"
732
+ };
733
+ const planUsageMeter = {
734
+ display: "flex",
735
+ alignItems: "center",
736
+ gap: 10,
737
+ minWidth: 0
738
+ };
739
+ const planUsageTrack = {
740
+ flex: "1 1 auto",
741
+ height: 6,
742
+ minWidth: 60,
743
+ borderRadius: 3,
744
+ background: "var(--dsw-alias-bg-layer-2)",
745
+ overflow: "hidden"
746
+ };
747
+ const planUsageFill = {
748
+ display: "block",
749
+ height: "100%",
750
+ borderRadius: 3,
751
+ transition: "width 200ms ease"
752
+ };
753
+ const planUsageMeta = {
754
+ flex: "0 0 auto",
755
+ fontSize: 12,
756
+ whiteSpace: "nowrap"
757
+ };
758
+ /** Bar colour, plus a matching text colour once a window is worth noticing.
759
+ * Below the warning threshold the reading stays quiet: accent bar, muted text. */
760
+ function planUsageTone(utilization) {
761
+ if (utilization !== void 0 && utilization >= 90) return {
762
+ fill: "var(--dsw-alias-state-error-primary)",
763
+ text: "var(--dsw-alias-state-error-primary)"
764
+ };
765
+ if (utilization !== void 0 && utilization >= 75) return {
766
+ fill: "var(--dsw-alias-state-warning-primary, #d69e2e)",
767
+ text: "var(--dsw-alias-state-warning-primary, #d69e2e)"
768
+ };
769
+ return {
770
+ fill: utilization === void 0 ? "transparent" : "var(--dsw-static-blue-450)",
771
+ text: "var(--dsw-alias-label-tertiary)"
772
+ };
773
+ }
716
774
  const settingsActions = {
717
775
  display: "flex",
718
776
  flexWrap: "wrap",
@@ -2317,8 +2375,11 @@ window.__ModuleLoader__.load({
2317
2375
  flex: none;
2318
2376
  display: grid;
2319
2377
  place-items: center;
2320
- align-self: center;
2321
- margin: 0 2px;
2378
+ /* Stay on the line-number row: a wrapped line makes the flex row taller, and
2379
+ centering would float the button into the middle of the wrapped block.
2380
+ The margin centers the 18px button inside the first 22px line box. */
2381
+ align-self: flex-start;
2382
+ margin: 2px 2px 0;
2322
2383
  padding: 0;
2323
2384
  border: none;
2324
2385
  border-radius: 4px;
@@ -2773,19 +2834,21 @@ window.__ModuleLoader__.load({
2773
2834
  background: var(--dsw-alias-bg-layer-2);
2774
2835
  }
2775
2836
  .dshClaudeRepositoryActionModalContent h2 {
2776
- font-size: 24px;
2777
- line-height: 32px;
2837
+ font-size: 18px;
2838
+ line-height: 26px;
2778
2839
  }
2779
2840
  .dshClaudeRepositoryActionModalContent > p {
2780
- font-size: 18px;
2781
- line-height: 28px;
2841
+ font-size: 14px;
2842
+ line-height: 22px;
2782
2843
  }
2783
- .dshClaudeRepositoryActionModal input[type='checkbox'] {
2784
- width: 18px;
2785
- height: 18px;
2844
+ .dshClaudeRepositoryActionModal input:is([type='checkbox'], [type='radio']) {
2845
+ width: 16px;
2846
+ height: 16px;
2847
+ margin: 0;
2848
+ accent-color: var(--dsw-static-blue-450);
2786
2849
  }
2787
2850
  .dshClaudeRepositoryActionModal textarea:focus,
2788
- .dshClaudeRepositoryActionModal input:not([type='checkbox']):focus {
2851
+ .dshClaudeRepositoryActionModal input:not([type='checkbox'], [type='radio']):focus {
2789
2852
  outline: none;
2790
2853
  box-shadow: inset 0 0 0 1px var(--dsw-static-blue-450);
2791
2854
  }
@@ -2804,8 +2867,8 @@ window.__ModuleLoader__.load({
2804
2867
  gap: 16,
2805
2868
  minWidth: 0,
2806
2869
  color: "var(--dsw-alias-label-secondary)",
2807
- fontSize: 16,
2808
- lineHeight: "24px"
2870
+ fontSize: 14,
2871
+ lineHeight: "22px"
2809
2872
  };
2810
2873
  const diffModalMetaText = {
2811
2874
  minWidth: 0,
@@ -2829,8 +2892,8 @@ window.__ModuleLoader__.load({
2829
2892
  padding: "10px 14px",
2830
2893
  borderBottom: "1px solid var(--dsw-alias-border-l2, color-mix(in srgb, currentColor 16%, transparent))",
2831
2894
  color: "var(--dsw-alias-label-secondary)",
2832
- fontSize: 15,
2833
- lineHeight: "22px"
2895
+ fontSize: 13,
2896
+ lineHeight: "20px"
2834
2897
  };
2835
2898
  const diffModalFilePath = {
2836
2899
  minWidth: 0,
@@ -2844,32 +2907,32 @@ window.__ModuleLoader__.load({
2844
2907
  flexDirection: "column",
2845
2908
  gap: 8,
2846
2909
  color: "var(--dsw-alias-label-secondary)",
2847
- fontSize: 16,
2848
- lineHeight: "24px",
2910
+ fontSize: 14,
2911
+ lineHeight: "22px",
2849
2912
  fontWeight: 550
2850
2913
  };
2851
2914
  const diffModalTextarea = {
2852
2915
  ...settingTextInput,
2853
2916
  minHeight: 140,
2854
2917
  padding: "10px 14px",
2855
- fontSize: 16,
2856
- lineHeight: "24px",
2918
+ fontSize: 14,
2919
+ lineHeight: "22px",
2857
2920
  resize: "vertical"
2858
2921
  };
2859
2922
  const diffModalTextInput = {
2860
2923
  ...settingTextInput,
2861
2924
  minHeight: 44,
2862
2925
  padding: "9px 14px",
2863
- fontSize: 16,
2864
- lineHeight: "24px"
2926
+ fontSize: 14,
2927
+ lineHeight: "22px"
2865
2928
  };
2866
2929
  const diffModalCheckbox = {
2867
2930
  display: "flex",
2868
2931
  alignItems: "center",
2869
2932
  gap: 10,
2870
2933
  color: "var(--dsw-alias-label-secondary)",
2871
- fontSize: 16,
2872
- lineHeight: "24px"
2934
+ fontSize: 14,
2935
+ lineHeight: "22px"
2873
2936
  };
2874
2937
  const diffModalFooter = {
2875
2938
  display: "flex",
@@ -2877,28 +2940,28 @@ window.__ModuleLoader__.load({
2877
2940
  gap: 12
2878
2941
  };
2879
2942
  const diffModalButton = {
2880
- minHeight: 42,
2943
+ minHeight: 36,
2881
2944
  padding: "8px 18px",
2882
- fontSize: 16,
2883
- lineHeight: "24px"
2945
+ fontSize: 14,
2946
+ lineHeight: "22px"
2884
2947
  };
2885
2948
  const diffModalStatus = {
2886
2949
  margin: 0,
2887
2950
  color: "var(--dsw-alias-label-secondary)",
2888
- fontSize: 16,
2889
- lineHeight: "24px"
2951
+ fontSize: 14,
2952
+ lineHeight: "22px"
2890
2953
  };
2891
2954
  const diffModalError = {
2892
2955
  margin: "10px 0 0",
2893
2956
  color: "var(--dsw-alias-state-error-primary)",
2894
- fontSize: 16,
2895
- lineHeight: "24px"
2957
+ fontSize: 14,
2958
+ lineHeight: "22px"
2896
2959
  };
2897
2960
  const diffModalSuccess = {
2898
2961
  margin: 0,
2899
2962
  color: "var(--dsw-alias-state-success-primary)",
2900
- fontSize: 16,
2901
- lineHeight: "24px"
2963
+ fontSize: 14,
2964
+ lineHeight: "22px"
2902
2965
  };
2903
2966
  //#endregion
2904
2967
  //#region src/client/token-format.ts
@@ -4418,6 +4481,183 @@ window.__ModuleLoader__.load({
4418
4481
  }) : null]
4419
4482
  });
4420
4483
  }
4484
+ /** Fixed windows carry a translated label; server-named model buckets (e.g.
4485
+ * 'Fable') arrive with their own `label` and are shown verbatim. */
4486
+ const TRANSLATED_WINDOWS = /* @__PURE__ */ new Set([
4487
+ "five_hour",
4488
+ "seven_day",
4489
+ "seven_day_opus",
4490
+ "seven_day_sonnet"
4491
+ ]);
4492
+ /** Per-setting label and the effect note that used to sit as a standalone
4493
+ * paragraph under the card; it now hangs off the label as a hover hint. */
4494
+ const SETTING_COPY = {
4495
+ outputStyle: {
4496
+ label: "outputStyle",
4497
+ hint: "globalSettingsNewSession"
4498
+ },
4499
+ worktreeBranchPrefix: {
4500
+ label: "worktreeBranchPrefix",
4501
+ hint: "worktreeBranchPrefixEffect"
4502
+ },
4503
+ maxProcesses: {
4504
+ label: "maxProcessesSetting",
4505
+ hint: "maxProcessesEffect"
4506
+ },
4507
+ idleTimeoutMinutes: {
4508
+ label: "idleTimeoutSetting",
4509
+ hint: "idleTimeoutEffect"
4510
+ }
4511
+ };
4512
+ /** '?' badge that reveals a setting's effect note on hover or keyboard focus. */
4513
+ function SettingHint({ text, label }) {
4514
+ return /* @__PURE__ */ jsx(Tooltip, {
4515
+ label: text,
4516
+ side: "top",
4517
+ delayMs: 150,
4518
+ maxWidth: 320,
4519
+ children: /* @__PURE__ */ jsx("span", {
4520
+ role: "note",
4521
+ tabIndex: 0,
4522
+ "aria-label": `${label}: ${text}`,
4523
+ style: settingHint,
4524
+ children: "?"
4525
+ })
4526
+ });
4527
+ }
4528
+ function isPlanUsageReport(value) {
4529
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
4530
+ const report = value;
4531
+ return typeof report.available === "boolean" && typeof report.fetchedAt === "number" && Array.isArray(report.windows) && report.windows.every((entry) => typeof entry === "object" && entry !== null && typeof entry.id === "string");
4532
+ }
4533
+ /** Coarse duration for a reset countdown or a fetch age: minutes below an
4534
+ * hour, then hours, then days. Never negative — a passed reset reads '0m'. */
4535
+ function durationLabel(milliseconds) {
4536
+ const minutes = Math.max(0, Math.round(milliseconds / 6e4));
4537
+ if (minutes < 60) return `${minutes}m`;
4538
+ const hours = Math.floor(minutes / 60);
4539
+ if (hours < 24) return minutes % 60 === 0 ? `${hours}h` : `${hours}h ${minutes % 60}m`;
4540
+ return `${Math.floor(hours / 24)}d`;
4541
+ }
4542
+ function PlanUsageMeter({ window: usageWindow, t, now }) {
4543
+ const used = usageWindow.utilization;
4544
+ const tone = planUsageTone(used);
4545
+ const resetsIn = usageWindow.resetsAt === void 0 ? void 0 : Date.parse(usageWindow.resetsAt);
4546
+ return /* @__PURE__ */ jsxs("span", {
4547
+ style: planUsageMeter,
4548
+ children: [/* @__PURE__ */ jsx("span", {
4549
+ style: planUsageTrack,
4550
+ children: /* @__PURE__ */ jsx("span", { style: {
4551
+ ...planUsageFill,
4552
+ width: `${used ?? 0}%`,
4553
+ background: tone.fill
4554
+ } })
4555
+ }), /* @__PURE__ */ jsxs("span", {
4556
+ style: {
4557
+ ...planUsageMeta,
4558
+ color: tone.text
4559
+ },
4560
+ children: [used === void 0 ? "—" : t("planUsageUsed", { percent: Math.round(used) }), resetsIn === void 0 || !Number.isFinite(resetsIn) ? null : ` · ${t("planUsageResets", { age: durationLabel(resetsIn - now) })}`]
4561
+ })]
4562
+ });
4563
+ }
4564
+ /** Fetch the plan usage report; POST forces the backend to re-read it. */
4565
+ async function loadPlanUsage(refresh) {
4566
+ const response = await fetch(CLAUDE_USAGE_PATH, {
4567
+ method: refresh ? "POST" : "GET",
4568
+ credentials: "same-origin",
4569
+ headers: { accept: "application/json" }
4570
+ });
4571
+ const payload = await response.json();
4572
+ if (!response.ok) {
4573
+ const message = typeof payload === "object" && payload !== null && "error" in payload && typeof payload.error === "string" ? payload.error : `HTTP ${response.status}`;
4574
+ throw new Error(message);
4575
+ }
4576
+ if (!isPlanUsageReport(payload)) throw new Error("Invalid plan usage response");
4577
+ return payload;
4578
+ }
4579
+ function PlanUsageCard({ t, load }) {
4580
+ const [report, setReport] = useState();
4581
+ const [busy, setBusy] = useState(false);
4582
+ const [error, setError] = useState();
4583
+ const request = useCallback(async (refresh) => {
4584
+ setBusy(true);
4585
+ setError(void 0);
4586
+ try {
4587
+ setReport(await load(refresh));
4588
+ } catch (cause) {
4589
+ setError(cause instanceof Error ? cause.message : String(cause));
4590
+ } finally {
4591
+ setBusy(false);
4592
+ }
4593
+ }, [load]);
4594
+ useEffect(() => {
4595
+ request(false);
4596
+ }, [request]);
4597
+ const now = Date.now();
4598
+ return /* @__PURE__ */ jsxs("section", {
4599
+ style: settingsCard,
4600
+ children: [
4601
+ /* @__PURE__ */ jsxs("div", {
4602
+ style: settingsCardHeader,
4603
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
4604
+ style: settingsSectionHeading,
4605
+ children: t("planUsage")
4606
+ }), /* @__PURE__ */ jsx("p", {
4607
+ style: settingsBody,
4608
+ children: t("planUsageBody")
4609
+ })] }), /* @__PURE__ */ jsx("button", {
4610
+ type: "button",
4611
+ style: button,
4612
+ disabled: busy,
4613
+ onClick: () => {
4614
+ request(true);
4615
+ },
4616
+ children: busy ? t("planUsageRefreshing") : t("planUsageRefresh")
4617
+ })]
4618
+ }),
4619
+ report === void 0 ? /* @__PURE__ */ jsx("p", {
4620
+ style: notice,
4621
+ children: busy ? t("planUsageLoading") : t("planUsageNever")
4622
+ }) : report.windows.length === 0 ? /* @__PURE__ */ jsx("p", {
4623
+ style: notice,
4624
+ children: report.fetchedAt === 0 ? t("planUsageNever") : t("planUsageUnavailable")
4625
+ }) : /* @__PURE__ */ jsxs("div", {
4626
+ style: diagnosticGrid,
4627
+ children: [report.subscription === void 0 ? null : /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
4628
+ style: diagnosticLabel,
4629
+ children: t("planUsageSubscription")
4630
+ }), /* @__PURE__ */ jsx("span", {
4631
+ style: diagnosticValue,
4632
+ children: report.subscription
4633
+ })] }), report.windows.flatMap((usageWindow) => [/* @__PURE__ */ jsx("span", {
4634
+ style: diagnosticLabel,
4635
+ children: usageWindow.label ?? (TRANSLATED_WINDOWS.has(usageWindow.id) ? t(`planWindow_${usageWindow.id}`) : usageWindow.id)
4636
+ }, `${usageWindow.id}-label`), /* @__PURE__ */ jsx(PlanUsageMeter, {
4637
+ window: usageWindow,
4638
+ t,
4639
+ now
4640
+ }, `${usageWindow.id}-meter`)])]
4641
+ }),
4642
+ report !== void 0 && report.fetchedAt > 0 ? /* @__PURE__ */ jsx("p", {
4643
+ style: notice,
4644
+ children: t("planUsageUpdated", { age: durationLabel(now - report.fetchedAt) })
4645
+ }) : null,
4646
+ error === void 0 ? null : /* @__PURE__ */ jsxs("p", {
4647
+ role: "alert",
4648
+ style: {
4649
+ ...notice,
4650
+ color: "var(--dsw-alias-state-error-primary)"
4651
+ },
4652
+ children: [
4653
+ t("planUsageError"),
4654
+ ": ",
4655
+ error
4656
+ ]
4657
+ })
4658
+ ]
4659
+ });
4660
+ }
4421
4661
  function ClaudeCodeSettings({ t }) {
4422
4662
  const [report, setReport] = useState();
4423
4663
  const [error, setError] = useState();
@@ -4622,6 +4862,10 @@ window.__ModuleLoader__.load({
4622
4862
  })
4623
4863
  ]
4624
4864
  }),
4865
+ /* @__PURE__ */ jsx(PlanUsageCard, {
4866
+ t,
4867
+ load: loadPlanUsage
4868
+ }),
4625
4869
  /* @__PURE__ */ jsxs("section", {
4626
4870
  style: settingsCard,
4627
4871
  children: [
@@ -4635,37 +4879,31 @@ window.__ModuleLoader__.load({
4635
4879
  globalSettings === void 0 ? /* @__PURE__ */ jsx("p", {
4636
4880
  style: notice,
4637
4881
  children: t("globalSettingsLoading")
4638
- }) : globalSettings.settings.map((setting) => /* @__PURE__ */ jsxs("div", {
4639
- style: diagnosticGrid,
4640
- children: [/* @__PURE__ */ jsx("span", {
4641
- style: diagnosticLabel,
4642
- children: setting.key === "outputStyle" ? t("outputStyle") : setting.key === "worktreeBranchPrefix" ? t("worktreeBranchPrefix") : setting.key === "maxProcesses" ? t("maxProcessesSetting") : setting.key === "idleTimeoutMinutes" ? t("idleTimeoutSetting") : setting.key
4643
- }), setting.kind === "select" ? /* @__PURE__ */ jsx(GlobalSettingSelect, {
4644
- setting,
4645
- disabled: globalSettingsBusy,
4646
- onChange: (nextValue) => {
4647
- requestGlobalSettings({ [setting.key]: nextValue });
4648
- }
4649
- }) : /* @__PURE__ */ jsx(GlobalSettingText, {
4650
- setting,
4651
- disabled: globalSettingsBusy,
4652
- onChange: (nextValue) => {
4653
- requestGlobalSettings({ [setting.key]: nextValue });
4654
- }
4655
- })]
4656
- }, setting.key)),
4657
- globalSettings?.settings.some((setting) => setting.effect === "new-session") === true ? /* @__PURE__ */ jsx("p", {
4658
- style: notice,
4659
- children: t("globalSettingsNewSession")
4660
- }) : null,
4661
- globalSettings?.settings.some((setting) => setting.effect === "next-worktree") === true ? /* @__PURE__ */ jsx("p", {
4662
- style: notice,
4663
- children: t("worktreeBranchPrefixEffect")
4664
- }) : null,
4665
- globalSettings?.settings.some((setting) => setting.key === "maxProcesses") === true ? /* @__PURE__ */ jsx("p", {
4666
- style: notice,
4667
- children: t("limitsSettingEffect")
4668
- }) : null,
4882
+ }) : globalSettings.settings.map((setting) => {
4883
+ const copy = SETTING_COPY[setting.key];
4884
+ return /* @__PURE__ */ jsxs("div", {
4885
+ style: diagnosticGrid,
4886
+ children: [/* @__PURE__ */ jsxs("span", {
4887
+ style: diagnosticLabel,
4888
+ children: [copy === void 0 ? setting.key : t(copy.label), copy === void 0 ? null : /* @__PURE__ */ jsx(SettingHint, {
4889
+ text: t(copy.hint),
4890
+ label: t("settingHint")
4891
+ })]
4892
+ }), setting.kind === "select" ? /* @__PURE__ */ jsx(GlobalSettingSelect, {
4893
+ setting,
4894
+ disabled: globalSettingsBusy,
4895
+ onChange: (nextValue) => {
4896
+ requestGlobalSettings({ [setting.key]: nextValue });
4897
+ }
4898
+ }) : /* @__PURE__ */ jsx(GlobalSettingText, {
4899
+ setting,
4900
+ disabled: globalSettingsBusy,
4901
+ onChange: (nextValue) => {
4902
+ requestGlobalSettings({ [setting.key]: nextValue });
4903
+ }
4904
+ })]
4905
+ }, setting.key);
4906
+ }),
4669
4907
  globalSettingsError === void 0 ? null : /* @__PURE__ */ jsxs("p", {
4670
4908
  role: "alert",
4671
4909
  style: {
@@ -5017,12 +5255,15 @@ window.__ModuleLoader__.load({
5017
5255
  }
5018
5256
  return body;
5019
5257
  }
5258
+ /** A wedged host must surface as an error; the hero has no other way out of its loading state. */
5259
+ const BRANCH_LOAD_TIMEOUT_MS = 15e3;
5020
5260
  function loadRepositoryBranches(cwd, signal) {
5261
+ const timeout = AbortSignal.timeout(BRANCH_LOAD_TIMEOUT_MS);
5021
5262
  return response(fetch(`${CLAUDE_REPOSITORY_SETUP_PATH}/branches?cwd=${encodeURIComponent(cwd)}`, {
5022
5263
  method: "GET",
5023
5264
  credentials: "same-origin",
5024
5265
  headers: { accept: "application/json" },
5025
- ...signal === void 0 ? {} : { signal }
5266
+ signal: signal === void 0 ? timeout : AbortSignal.any([signal, timeout])
5026
5267
  }));
5027
5268
  }
5028
5269
  async function prepareRepository(cwd, branch, worktree, branchName, onProgress = () => {}) {
@@ -5173,8 +5414,10 @@ window.__ModuleLoader__.load({
5173
5414
  }).join("\n\n")}`;
5174
5415
  }
5175
5416
  /** Draft handed to Claude after an update-branch merge left conflicts behind. */
5176
- function composeConflictsPrompt(baseBranch, conflicts) {
5177
- 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")}`;
5417
+ function composeConflictsPrompt(baseBranch, conflicts, method = "merge") {
5418
+ const list = conflicts.map((file) => `- ${file}`).join("\n");
5419
+ if (method === "rebase") return `Rebasing the current branch onto origin/${baseBranch} stopped on conflicts in the files below. Resolve each conflict preserving the intent of both sides, stage the files, run \`git rebase --continue\` until the rebase finishes, then push with \`git push --force-with-lease\`.\n\n${list}`;
5420
+ 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${list}`;
5178
5421
  }
5179
5422
  //#endregion
5180
5423
  //#region src/client/auto-fix.ts
@@ -5229,32 +5472,6 @@ window.__ModuleLoader__.load({
5229
5472
  }
5230
5473
  //#endregion
5231
5474
  //#region src/client/ClaudeRepositoryStatus.tsx
5232
- const RATE_LIMIT_TITLE_PREFIX = "Claude rate limit";
5233
- const RATE_LIMIT_BLOCKING_TITLE = "Claude rate limit is blocking requests";
5234
- /** Whether the newest quota update in the activity feed reports a blocked state. */
5235
- function rateLimitBlocked(activities) {
5236
- for (let index = activities.length - 1; index >= 0; index -= 1) {
5237
- const title = activities[index]?.title;
5238
- if (title?.startsWith(RATE_LIMIT_TITLE_PREFIX) === true) return title === RATE_LIMIT_BLOCKING_TITLE;
5239
- }
5240
- return false;
5241
- }
5242
- function StatusItem({ label, tone = "neutral" }) {
5243
- const toneStyle = tone === "success" ? repositoryItemSuccess : tone === "warning" ? repositoryItemWarning : tone === "error" ? repositoryItemError : {};
5244
- return /* @__PURE__ */ jsxs("span", {
5245
- style: {
5246
- ...repositoryItem,
5247
- ...toneStyle
5248
- },
5249
- children: [/* @__PURE__ */ jsx("span", {
5250
- style: repositoryItemDot,
5251
- "aria-hidden": "true"
5252
- }), /* @__PURE__ */ jsx("span", {
5253
- style: repositoryItemLabel,
5254
- children: label
5255
- })]
5256
- });
5257
- }
5258
5475
  /** Icon-only status: the tone carries the state, the full label lives in the tooltip and accessible name. */
5259
5476
  function StatusGlyph({ label, tone, children }) {
5260
5477
  const toneStyle = tone === "success" ? repositoryItemSuccess : tone === "warning" ? repositoryItemWarning : tone === "error" ? repositoryItemError : {};
@@ -5695,6 +5912,7 @@ window.__ModuleLoader__.load({
5695
5912
  }
5696
5913
  function UpdateBranchControl({ sessionId, repository, t, submitPrompt }) {
5697
5914
  const [dialog, setDialog] = useState();
5915
+ const [method, setMethod] = useState("rebase");
5698
5916
  const controller = useRef();
5699
5917
  const pullRequest = repository.pullRequest;
5700
5918
  const base = pullRequest?.baseBranch;
@@ -5746,7 +5964,8 @@ window.__ModuleLoader__.load({
5746
5964
  fingerprint: dialog.fingerprint,
5747
5965
  message: "",
5748
5966
  includeUnstaged: false,
5749
- baseBranch: base
5967
+ baseBranch: base,
5968
+ mergeMethod: method
5750
5969
  }).then((result) => {
5751
5970
  setDialog({
5752
5971
  ...pending,
@@ -5829,6 +6048,17 @@ window.__ModuleLoader__.load({
5829
6048
  })
5830
6049
  })]
5831
6050
  }),
6051
+ ["rebase", "merge"].map((option) => /* @__PURE__ */ jsxs("label", {
6052
+ style: diffModalCheckbox,
6053
+ children: [/* @__PURE__ */ jsx("input", {
6054
+ type: "radio",
6055
+ name: "dsh-claude-update-branch-method",
6056
+ value: option,
6057
+ checked: method === option,
6058
+ disabled: settled || dialog.submitting,
6059
+ onChange: () => setMethod(option)
6060
+ }), t(`diffUpdateBranch_${option}`, { base })]
6061
+ }, option)),
5832
6062
  dialog.pushed === void 0 ? null : /* @__PURE__ */ jsx("p", {
5833
6063
  style: diffModalSuccess,
5834
6064
  children: t("diffUpdateBranchCompleted", { commit: dialog.pushed.slice(0, 8) })
@@ -5846,7 +6076,7 @@ window.__ModuleLoader__.load({
5846
6076
  type: "button",
5847
6077
  style: diffModalConflictResolve,
5848
6078
  onClick: () => {
5849
- submitPrompt(composeConflictsPrompt(base, dialog.conflicts ?? []));
6079
+ submitPrompt(composeConflictsPrompt(base, dialog.conflicts ?? [], method));
5850
6080
  closeDialog();
5851
6081
  },
5852
6082
  children: t("diffUpdateBranchResolve")
@@ -6150,25 +6380,17 @@ window.__ModuleLoader__.load({
6150
6380
  const aheadCount = repository.ahead ?? 0;
6151
6381
  const pushable = repository.remote !== void 0 && repository.detached !== true && (aheadCount > 0 || repository.upstream === false);
6152
6382
  const hasDiff = repository.diff !== void 0 && (repository.diff.additions > 0 || repository.diff.deletions > 0);
6153
- const rateLimited = rateLimitBlocked(projection.activities);
6154
6383
  if (repository.status !== "ready") return /* @__PURE__ */ jsx("div", {
6155
6384
  style: repositoryBarFrame,
6156
6385
  children: /* @__PURE__ */ jsxs("div", {
6157
6386
  style: repositoryBar,
6158
- children: [
6159
- /* @__PURE__ */ jsx("span", {
6160
- style: repositoryPrIcon,
6161
- children: /* @__PURE__ */ jsx(PullRequestIcon, {})
6162
- }),
6163
- /* @__PURE__ */ jsx("span", {
6164
- style: repositoryPrimary,
6165
- children: repository.status === "not-repository" ? t("repositoryNotGit") : t("repositoryUnavailable")
6166
- }),
6167
- rateLimited ? /* @__PURE__ */ jsx(StatusItem, {
6168
- label: t("repositoryRateLimited"),
6169
- tone: "warning"
6170
- }) : null
6171
- ]
6387
+ children: [/* @__PURE__ */ jsx("span", {
6388
+ style: repositoryPrIcon,
6389
+ children: /* @__PURE__ */ jsx(PullRequestIcon, {})
6390
+ }), /* @__PURE__ */ jsx("span", {
6391
+ style: repositoryPrimary,
6392
+ children: repository.status === "not-repository" ? t("repositoryNotGit") : t("repositoryUnavailable")
6393
+ })]
6172
6394
  })
6173
6395
  });
6174
6396
  return /* @__PURE__ */ jsx("div", {
@@ -6215,83 +6437,76 @@ window.__ModuleLoader__.load({
6215
6437
  }) : null,
6216
6438
  /* @__PURE__ */ jsxs("span", {
6217
6439
  style: repositoryStatusItems,
6218
- children: [
6219
- rateLimited ? /* @__PURE__ */ jsx(StatusItem, {
6220
- label: t("repositoryRateLimited"),
6221
- tone: "warning"
6222
- }) : null,
6223
- hasDiff || pushable ? /* @__PURE__ */ jsxs("button", {
6224
- type: "button",
6225
- style: {
6226
- ...diffTrigger,
6227
- ...merged ? diffTriggerMuted : {}
6228
- },
6229
- onClick: openDiff,
6230
- "aria-label": t("diffOpen"),
6231
- children: [hasDiff && repository.diff !== void 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
6232
- style: merged ? diffAddMuted : diffAdd,
6233
- children: ["+", repository.diff.additions]
6234
- }), /* @__PURE__ */ jsxs("span", {
6235
- style: merged ? diffDeleteMuted : diffDelete,
6236
- children: ["", repository.diff.deletions]
6237
- })] }) : null, pushable ? /* @__PURE__ */ jsxs("span", {
6238
- style: merged ? diffAheadMuted : diffAhead,
6239
- children: ["", aheadCount > 0 ? aheadCount : ""]
6240
- }) : null]
6241
- }) : null,
6242
- pullRequest === void 0 ? null : merged ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
6243
- style: repositoryMergedStatus,
6244
- children: [
6245
- /* @__PURE__ */ jsx("span", {
6246
- style: repositoryMergedDot,
6247
- "aria-hidden": "true"
6248
- }),
6249
- t("repositoryState_merged"),
6250
- mergedAge === void 0 ? null : /* @__PURE__ */ jsxs("span", {
6251
- style: repositoryMergedAge,
6252
- children: ["· ", t("repositoryMergedAgo", { age: mergedAge })]
6253
- })
6254
- ]
6255
- }), /* @__PURE__ */ jsx(CleanupControl, {
6256
- repository,
6257
- t,
6258
- ...deleteWorkspace === void 0 ? {} : { deleteWorkspace }
6259
- })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
6260
- pullRequest.checks === "failing" ? /* @__PURE__ */ jsx(FailingChecksControl, {
6261
- sessionId,
6262
- pullNumber: pullRequest.number,
6263
- t,
6264
- ...submitPrompt === void 0 ? {} : { submitPrompt }
6265
- }) : pullRequest.checks === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
6266
- label: t(`repositoryChecks_${pullRequest.checks}`),
6267
- tone: pullRequest.checks === "passing" ? "success" : "warning",
6268
- children: /* @__PURE__ */ jsx(ChecksGlyph, { state: pullRequest.checks })
6269
- }),
6270
- pullRequest.review === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
6271
- label: t(`repositoryReview_${pullRequest.review}`),
6272
- tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral",
6273
- children: /* @__PURE__ */ jsx(ReviewGlyph, {})
6274
- }),
6275
- /* @__PURE__ */ jsx(AutoFixControl, {
6276
- sessionId,
6277
- repository,
6278
- running,
6279
- t,
6280
- ...submitPrompt === void 0 ? {} : { submitPrompt }
6281
- }),
6282
- /* @__PURE__ */ jsx(UpdateBranchControl, {
6283
- sessionId,
6284
- repository,
6285
- t,
6286
- ...submitPrompt === void 0 ? {} : { submitPrompt }
6440
+ children: [hasDiff || pushable ? /* @__PURE__ */ jsxs("button", {
6441
+ type: "button",
6442
+ style: {
6443
+ ...diffTrigger,
6444
+ ...merged ? diffTriggerMuted : {}
6445
+ },
6446
+ onClick: openDiff,
6447
+ "aria-label": t("diffOpen"),
6448
+ children: [hasDiff && repository.diff !== void 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
6449
+ style: merged ? diffAddMuted : diffAdd,
6450
+ children: ["+", repository.diff.additions]
6451
+ }), /* @__PURE__ */ jsxs("span", {
6452
+ style: merged ? diffDeleteMuted : diffDelete,
6453
+ children: ["−", repository.diff.deletions]
6454
+ })] }) : null, pushable ? /* @__PURE__ */ jsxs("span", {
6455
+ style: merged ? diffAheadMuted : diffAhead,
6456
+ children: ["↑", aheadCount > 0 ? aheadCount : ""]
6457
+ }) : null]
6458
+ }) : null, pullRequest === void 0 ? null : merged ? /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("span", {
6459
+ style: repositoryMergedStatus,
6460
+ children: [
6461
+ /* @__PURE__ */ jsx("span", {
6462
+ style: repositoryMergedDot,
6463
+ "aria-hidden": "true"
6287
6464
  }),
6288
- /* @__PURE__ */ jsx(MergePullRequestControl, {
6289
- sessionId,
6290
- repository,
6291
- t
6465
+ t("repositoryState_merged"),
6466
+ mergedAge === void 0 ? null : /* @__PURE__ */ jsxs("span", {
6467
+ style: repositoryMergedAge,
6468
+ children: ["· ", t("repositoryMergedAgo", { age: mergedAge })]
6292
6469
  })
6293
- ] })
6294
- ]
6470
+ ]
6471
+ }), /* @__PURE__ */ jsx(CleanupControl, {
6472
+ repository,
6473
+ t,
6474
+ ...deleteWorkspace === void 0 ? {} : { deleteWorkspace }
6475
+ })] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
6476
+ pullRequest.checks === "failing" ? /* @__PURE__ */ jsx(FailingChecksControl, {
6477
+ sessionId,
6478
+ pullNumber: pullRequest.number,
6479
+ t,
6480
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
6481
+ }) : pullRequest.checks === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
6482
+ label: t(`repositoryChecks_${pullRequest.checks}`),
6483
+ tone: pullRequest.checks === "passing" ? "success" : "warning",
6484
+ children: /* @__PURE__ */ jsx(ChecksGlyph, { state: pullRequest.checks })
6485
+ }),
6486
+ pullRequest.review === "none" ? null : /* @__PURE__ */ jsx(StatusGlyph, {
6487
+ label: t(`repositoryReview_${pullRequest.review}`),
6488
+ tone: pullRequest.review === "approved" ? "success" : pullRequest.review === "changes-requested" ? "error" : "neutral",
6489
+ children: /* @__PURE__ */ jsx(ReviewGlyph, {})
6490
+ }),
6491
+ /* @__PURE__ */ jsx(AutoFixControl, {
6492
+ sessionId,
6493
+ repository,
6494
+ running,
6495
+ t,
6496
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
6497
+ }),
6498
+ /* @__PURE__ */ jsx(UpdateBranchControl, {
6499
+ sessionId,
6500
+ repository,
6501
+ t,
6502
+ ...submitPrompt === void 0 ? {} : { submitPrompt }
6503
+ }),
6504
+ /* @__PURE__ */ jsx(MergePullRequestControl, {
6505
+ sessionId,
6506
+ repository,
6507
+ t
6508
+ })
6509
+ ] })]
6295
6510
  })
6296
6511
  ]
6297
6512
  })
@@ -8588,9 +8803,15 @@ window.__ModuleLoader__.load({
8588
8803
  row = row.parentElement;
8589
8804
  }
8590
8805
  }
8806
+ /** Reuse the row's existing portal even when the host moved a node between it
8807
+ * and the seat: a fresh element would change React's portal identity and
8808
+ * restart (and abort) every effect keyed on it. */
8591
8809
  function ensureClaudeHeroPortal(seat) {
8592
- const sibling = seat.nextElementSibling;
8593
- if (sibling instanceof HTMLElement && sibling.hasAttribute(PORTAL_ATTRIBUTE)) return sibling;
8810
+ const existing = seat.parentElement?.querySelector(`:scope > [${PORTAL_ATTRIBUTE}]`) ?? null;
8811
+ if (existing !== null) {
8812
+ if (existing.previousElementSibling !== seat) seat.insertAdjacentElement("afterend", existing);
8813
+ return existing;
8814
+ }
8594
8815
  const portal = document.createElement("span");
8595
8816
  portal.setAttribute(PORTAL_ATTRIBUTE, "");
8596
8817
  seat.insertAdjacentElement("afterend", portal);
@@ -8635,6 +8856,8 @@ window.__ModuleLoader__.load({
8635
8856
  if (key === "End") return count - 1;
8636
8857
  return (current + (key === "ArrowDown" ? 1 : -1) + count) % count;
8637
8858
  }
8859
+ const BRANCH_LOAD_RETRIES = 2;
8860
+ const BRANCH_LOAD_RETRY_MS = 1e3;
8638
8861
  const WORKTREE_PROGRESS_STAGES = [
8639
8862
  "inspecting",
8640
8863
  "fetching",
@@ -9002,14 +9225,26 @@ window.__ModuleLoader__.load({
9002
9225
  setTicketError(void 0);
9003
9226
  if (portal === void 0 || path === void 0) return;
9004
9227
  const controller = new AbortController();
9005
- loadRepositoryBranches(path, controller.signal).then((value) => {
9006
- setBranches(value);
9007
- setSelected(value.current ?? value.branches[0] ?? "");
9008
- }, (reason) => {
9009
- if (!controller.signal.aborted) setError(reason instanceof Error ? reason.message : String(reason));
9010
- });
9228
+ let timer;
9229
+ const load = (remaining) => {
9230
+ loadRepositoryBranches(path, controller.signal).then((value) => {
9231
+ setBranches(value);
9232
+ setSelected(value.current ?? value.branches[0] ?? "");
9233
+ }, (reason) => {
9234
+ if (controller.signal.aborted) return;
9235
+ if (remaining > 0) {
9236
+ timer = setTimeout(() => {
9237
+ load(remaining - 1);
9238
+ }, BRANCH_LOAD_RETRY_MS);
9239
+ return;
9240
+ }
9241
+ setError(reason instanceof Error ? reason.message : String(reason));
9242
+ });
9243
+ };
9244
+ load(BRANCH_LOAD_RETRIES);
9011
9245
  return () => {
9012
9246
  controller.abort();
9247
+ if (timer !== void 0) clearTimeout(timer);
9013
9248
  };
9014
9249
  }, [
9015
9250
  portal,
@@ -9409,7 +9644,7 @@ window.__ModuleLoader__.load({
9409
9644
  //#endregion
9410
9645
  //#region src/client/details-resize.ts
9411
9646
  const DETAILS_MIN_WIDTH = 300;
9412
- const DETAILS_DEFAULT_WIDTH = 480;
9647
+ const DETAILS_DEFAULT_WIDTH = 720;
9413
9648
  const DETAILS_MAX_RATIO = .5;
9414
9649
  const DRAG_THRESHOLD = 4;
9415
9650
  function clampDetailsWidth(width, frameWidth) {
@@ -9610,14 +9845,16 @@ window.__ModuleLoader__.load({
9610
9845
  globalSettings: "Claude Code 设置",
9611
9846
  globalSettingsBody: "修改受支持的 Claude Code 与插件设置;其他字段会被保留。",
9612
9847
  globalSettingsLoading: "正在加载全局设置…",
9613
- globalSettingsNewSession: "Output Style 修改仅对新建 Claude 会话生效。",
9848
+ globalSettingsNewSession: "修改仅对新建 Claude 会话生效。",
9614
9849
  globalSettingsError: "全局设置保存失败",
9615
9850
  outputStyle: "Output Style",
9616
9851
  worktreeBranchPrefix: "Worktree 分支前缀",
9617
9852
  worktreeBranchPrefixEffect: "分支前缀修改会应用于之后自动创建的 Worktree 分支;显式指定的完整分支名不会被修改。",
9618
9853
  maxProcessesSetting: "Claude 进程上限",
9619
9854
  idleTimeoutSetting: "闲置回收时长(分钟)",
9620
- limitsSettingEffect: "进程上限在下次启动 Claude 进程时生效;闲置回收时长在下一次回合结束后生效。留空或非法值会被拒绝。",
9855
+ maxProcessesEffect: "进程上限在下次启动 Claude 进程时生效。留空或非法值会被拒绝。",
9856
+ idleTimeoutEffect: "闲置回收时长在下一次回合结束后生效。留空或非法值会被拒绝。",
9857
+ settingHint: "查看说明",
9621
9858
  pluginUpdate: "插件更新",
9622
9859
  pluginUpdateBody: "检查 npm 上的新版本。只有可唯一识别的 npm 安装才能直接更新;本地开发链接不会被替换。",
9623
9860
  updateNotChecked: "尚未检查更新。",
@@ -9655,7 +9892,22 @@ window.__ModuleLoader__.load({
9655
9892
  tasksViewActivity: "查看活动",
9656
9893
  tasksHideActivity: "收起活动",
9657
9894
  tasksRunningCount: "{count} 个运行中任务",
9658
- repositoryRateLimited: "Claude 额度限流中",
9895
+ planUsage: "账号额度",
9896
+ planUsageBody: "当前 Claude 订阅的用量窗口,来自 Claude Code 的 /usage 数据。会话空闲时自动刷新,也可随时手动刷新。",
9897
+ planUsageLoading: "读取中…",
9898
+ planUsageRefresh: "刷新额度",
9899
+ planUsageRefreshing: "刷新中…",
9900
+ planUsageUnavailable: "此账号没有订阅额度(API key、Bedrock、Vertex 等不受套餐限流)。",
9901
+ planUsageNever: "尚未获取额度数据,运行一次对话或点击刷新。",
9902
+ planUsageError: "额度读取失败",
9903
+ planUsageSubscription: "订阅",
9904
+ planUsageUpdated: "更新于 {age}前",
9905
+ planUsageResets: "{age}后重置",
9906
+ planUsageUsed: "已用 {percent}%",
9907
+ planWindow_five_hour: "5 小时",
9908
+ planWindow_seven_day: "全部模型 · 每周",
9909
+ planWindow_seven_day_opus: "Opus · 每周",
9910
+ planWindow_seven_day_sonnet: "Sonnet · 每周",
9659
9911
  tasksTurnRunning: "{count} 个任务执行中",
9660
9912
  tasksTurnCompleted: "{count} 个任务已完成",
9661
9913
  tasksTurnFailed: "{failed} 个任务失败,{completed} 个已完成",
@@ -9773,10 +10025,12 @@ window.__ModuleLoader__.load({
9773
10025
  diffMergeCompleted: "已合并 PR #{number}",
9774
10026
  diffUpdateBranch: "Update branch…",
9775
10027
  repositoryUpdateBranch: "Update branch",
9776
- diffUpdateBranchDescription: " origin/{base} 合并进当前分支并推送;出现冲突时可交给 Claude 解决。",
10028
+ diffUpdateBranchDescription: " origin/{base} 更新当前分支并推送;出现冲突时可交给 Claude 解决。",
10029
+ diffUpdateBranch_rebase: "Rebase 到 origin/{base}(改写历史,以 --force-with-lease 推送)",
10030
+ diffUpdateBranch_merge: "将 origin/{base} 合并进当前分支",
9777
10031
  diffUpdateBranchBehind: "落后 origin/{base} {count} 个 commit",
9778
- diffUpdateBranchCompleted: "已合并并推送 commit {commit}",
9779
- diffUpdateBranchConflicts: "合并产生冲突,以下文件需要解决:",
10032
+ diffUpdateBranchCompleted: "已更新并推送 commit {commit}",
10033
+ diffUpdateBranchConflicts: "更新产生冲突,以下文件需要解决:",
9780
10034
  diffUpdateBranchResolve: "让 Claude 解决冲突",
9781
10035
  repositoryChecksOpen: "查看失败的检查",
9782
10036
  checksCardTitle: "失败的检查",
@@ -9907,14 +10161,16 @@ window.__ModuleLoader__.load({
9907
10161
  globalSettings: "Claude Code settings",
9908
10162
  globalSettingsBody: "Modify supported Claude Code and plugin settings while preserving every other field.",
9909
10163
  globalSettingsLoading: "Loading global settings…",
9910
- globalSettingsNewSession: "Output Style changes apply only to new Claude sessions.",
10164
+ globalSettingsNewSession: "Changes apply only to new Claude sessions.",
9911
10165
  globalSettingsError: "Global settings save failed",
9912
10166
  outputStyle: "Output Style",
9913
10167
  worktreeBranchPrefix: "Worktree branch prefix",
9914
10168
  worktreeBranchPrefixEffect: "Prefix changes apply to subsequently generated Worktree branches. Explicit full branch names remain unchanged.",
9915
10169
  maxProcessesSetting: "Claude process limit",
9916
10170
  idleTimeoutSetting: "Idle timeout (minutes)",
9917
- limitsSettingEffect: "The process limit applies when the next Claude process is admitted; the idle timeout applies after the next completed turn.",
10171
+ maxProcessesEffect: "The process limit applies when the next Claude process is admitted. Blank or invalid values are rejected.",
10172
+ idleTimeoutEffect: "The idle timeout applies after the next completed turn. Blank or invalid values are rejected.",
10173
+ settingHint: "Show details",
9918
10174
  pluginUpdate: "Plugin updates",
9919
10175
  pluginUpdateBody: "Check npm for new releases. Only a uniquely identified npm installation can update in place; local development links are never replaced.",
9920
10176
  updateNotChecked: "Updates have not been checked yet.",
@@ -9952,7 +10208,22 @@ window.__ModuleLoader__.load({
9952
10208
  tasksViewActivity: "View activity",
9953
10209
  tasksHideActivity: "Hide activity",
9954
10210
  tasksRunningCount: "{count} running task(s)",
9955
- repositoryRateLimited: "Rate limited",
10211
+ planUsage: "Plan usage",
10212
+ planUsageBody: "Utilization windows for the signed-in Claude subscription, from Claude Code's /usage data. Refreshes whenever a session goes idle, and on demand.",
10213
+ planUsageLoading: "Loading…",
10214
+ planUsageRefresh: "Refresh usage",
10215
+ planUsageRefreshing: "Refreshing…",
10216
+ planUsageUnavailable: "This account has no plan limits (API key, Bedrock, and Vertex sessions are not rate limited by a subscription).",
10217
+ planUsageNever: "No usage data yet — run a turn or refresh.",
10218
+ planUsageError: "Usage lookup failed",
10219
+ planUsageSubscription: "Subscription",
10220
+ planUsageUpdated: "Updated {age} ago",
10221
+ planUsageResets: "Resets in {age}",
10222
+ planUsageUsed: "{percent}% used",
10223
+ planWindow_five_hour: "5-hour",
10224
+ planWindow_seven_day: "All models · weekly",
10225
+ planWindow_seven_day_opus: "Opus · weekly",
10226
+ planWindow_seven_day_sonnet: "Sonnet · weekly",
9956
10227
  tasksTurnRunning: "{count} task(s) running",
9957
10228
  tasksTurnCompleted: "{count} task(s) completed",
9958
10229
  tasksTurnFailed: "{failed} failed, {completed} completed",
@@ -10070,10 +10341,12 @@ window.__ModuleLoader__.load({
10070
10341
  diffMergeCompleted: "Merged PR #{number}",
10071
10342
  diffUpdateBranch: "Update branch…",
10072
10343
  repositoryUpdateBranch: "Update branch",
10073
- diffUpdateBranchDescription: "Merge origin/{base} into the current branch and push; hand any conflicts to Claude.",
10344
+ diffUpdateBranchDescription: "Update the current branch from origin/{base} and push; hand any conflicts to Claude.",
10345
+ diffUpdateBranch_rebase: "Rebase onto origin/{base} (rewrites history, pushes with --force-with-lease)",
10346
+ diffUpdateBranch_merge: "Merge origin/{base} into the current branch",
10074
10347
  diffUpdateBranchBehind: "{count} commit(s) behind origin/{base}",
10075
- diffUpdateBranchCompleted: "Merged and pushed commit {commit}",
10076
- diffUpdateBranchConflicts: "The merge left conflicts in these files:",
10348
+ diffUpdateBranchCompleted: "Updated and pushed commit {commit}",
10349
+ diffUpdateBranchConflicts: "The update left conflicts in these files:",
10077
10350
  diffUpdateBranchResolve: "Have Claude resolve the conflicts",
10078
10351
  repositoryChecksOpen: "Show failing checks",
10079
10352
  checksCardTitle: "Failing checks",