ccstatusline 2.2.23 → 2.2.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.
@@ -53003,13 +53003,14 @@ var init_Widget = __esm(() => {
53003
53003
  });
53004
53004
 
53005
53005
  // src/types/Settings.ts
53006
- var CURRENT_VERSION = 3, InstallationMetadataSchema, SettingsSchema_v1, SettingsSchema, DEFAULT_SETTINGS;
53006
+ var CURRENT_VERSION = 3, DefaultPaddingSideSchema, InstallationMetadataSchema, SettingsSchema_v1, SettingsSchema, DEFAULT_SETTINGS;
53007
53007
  var init_Settings = __esm(() => {
53008
53008
  init_zod();
53009
53009
  init_ColorLevel();
53010
53010
  init_FlexMode();
53011
53011
  init_PowerlineConfig();
53012
53012
  init_Widget();
53013
+ DefaultPaddingSideSchema = exports_external.enum(["both", "left", "right"]);
53013
53014
  InstallationMetadataSchema = exports_external.discriminatedUnion("method", [
53014
53015
  exports_external.object({
53015
53016
  method: exports_external.literal("auto-update"),
@@ -53060,6 +53061,7 @@ var init_Settings = __esm(() => {
53060
53061
  colorLevel: ColorLevelSchema.default(2),
53061
53062
  defaultSeparator: exports_external.string().optional(),
53062
53063
  defaultPadding: exports_external.string().optional(),
53064
+ defaultPaddingSide: DefaultPaddingSideSchema.default("both"),
53063
53065
  inheritSeparatorColors: exports_external.boolean().default(false),
53064
53066
  overrideBackgroundColor: exports_external.string().optional(),
53065
53067
  overrideForegroundColor: exports_external.string().optional(),
@@ -55591,187 +55593,6 @@ var init_GitUntrackedFiles = __esm(() => {
55591
55593
  init_git_no_git();
55592
55594
  });
55593
55595
 
55594
- // src/widgets/GitCleanStatus.ts
55595
- class GitCleanStatusWidget {
55596
- getDefaultColor() {
55597
- return "green";
55598
- }
55599
- getDescription() {
55600
- return "Shows ✓ when the working tree is clean and ✗ when it is dirty";
55601
- }
55602
- getDisplayName() {
55603
- return "Git Clean Status";
55604
- }
55605
- getCategory() {
55606
- return "Git";
55607
- }
55608
- getEditorDisplay(item) {
55609
- return {
55610
- displayText: this.getDisplayName(),
55611
- modifierText: getHideNoGitModifierText(item)
55612
- };
55613
- }
55614
- handleEditorAction(action, item) {
55615
- return handleToggleNoGitAction(action, item);
55616
- }
55617
- render(item, context, _settings) {
55618
- const hideNoGit = isHideNoGitEnabled(item);
55619
- if (context.isPreview) {
55620
- return item.rawValue ? "clean" : "✓";
55621
- }
55622
- if (!isInsideGitWorkTree(context)) {
55623
- return hideNoGit ? null : "(no git)";
55624
- }
55625
- const clean = this.isClean(context);
55626
- if (item.rawValue) {
55627
- return clean ? "clean" : "dirty";
55628
- }
55629
- return clean ? "✓" : "✗";
55630
- }
55631
- isClean(context) {
55632
- const status = getGitStatus(context);
55633
- return !status.staged && !status.unstaged && !status.untracked && !status.conflicts;
55634
- }
55635
- getCustomKeybinds() {
55636
- return getHideNoGitKeybinds();
55637
- }
55638
- supportsRawValue() {
55639
- return true;
55640
- }
55641
- supportsColors(_item) {
55642
- return true;
55643
- }
55644
- }
55645
- var init_GitCleanStatus = __esm(() => {
55646
- init_git();
55647
- init_git_no_git();
55648
- });
55649
-
55650
- // src/widgets/GitRootDir.ts
55651
- class GitRootDirWidget {
55652
- getDefaultColor() {
55653
- return "cyan";
55654
- }
55655
- getDescription() {
55656
- return "Shows the git repository root directory name";
55657
- }
55658
- getDisplayName() {
55659
- return "Git Root Dir";
55660
- }
55661
- getCategory() {
55662
- return "Git";
55663
- }
55664
- getEditorDisplay(item) {
55665
- const ideLinkMode = this.getIdeLinkMode(item);
55666
- const modifiers = [];
55667
- const noGitText = getHideNoGitModifierText(item);
55668
- if (noGitText)
55669
- modifiers.push("hide 'no git'");
55670
- if (ideLinkMode)
55671
- modifiers.push(IDE_LINK_LABELS[ideLinkMode]);
55672
- const maxWidthText = getMaxWidthModifier(item);
55673
- if (maxWidthText)
55674
- modifiers.push(maxWidthText);
55675
- return {
55676
- displayText: this.getDisplayName(),
55677
- modifierText: makeModifierText(modifiers)
55678
- };
55679
- }
55680
- handleEditorAction(action, item) {
55681
- if (action === TOGGLE_LINK_ACTION2) {
55682
- return this.cycleIdeLinkMode(item);
55683
- }
55684
- return handleToggleNoGitAction(action, item);
55685
- }
55686
- render(item, context, _settings) {
55687
- const hideNoGit = isHideNoGitEnabled(item);
55688
- const ideLinkMode = this.getIdeLinkMode(item);
55689
- if (context.isPreview) {
55690
- const name2 = "my-repo";
55691
- return ideLinkMode ? renderOsc8Link(buildIdeFileUrl("/Users/example/my-repo", ideLinkMode), name2) : name2;
55692
- }
55693
- if (!isInsideGitWorkTree(context)) {
55694
- return hideNoGit ? null : "no git";
55695
- }
55696
- const rootDir = this.getGitRootDir(context);
55697
- if (!rootDir) {
55698
- return hideNoGit ? null : "no git";
55699
- }
55700
- const name = applyMaxWidth(this.getRootDirName(rootDir), item.maxWidth);
55701
- if (ideLinkMode) {
55702
- return renderOsc8Link(buildIdeFileUrl(rootDir, ideLinkMode), name);
55703
- }
55704
- return name;
55705
- }
55706
- getGitRootDir(context) {
55707
- return runGit("rev-parse --show-toplevel", context);
55708
- }
55709
- getRootDirName(rootDir) {
55710
- const trimmedRootDir = rootDir.replace(/[\\/]+$/, "");
55711
- const normalizedRootDir = trimmedRootDir.length > 0 ? trimmedRootDir : rootDir;
55712
- const parts = normalizedRootDir.split(/[\\/]/).filter(Boolean);
55713
- const lastPart = parts[parts.length - 1];
55714
- return lastPart && lastPart.length > 0 ? lastPart : normalizedRootDir;
55715
- }
55716
- getCustomKeybinds() {
55717
- return [
55718
- ...getHideNoGitKeybinds(),
55719
- { key: "l", label: "(l)ink to IDE", action: TOGGLE_LINK_ACTION2 },
55720
- getMaxWidthKeybind()
55721
- ];
55722
- }
55723
- renderEditor(props) {
55724
- if (props.action === MAX_WIDTH_ACTION) {
55725
- return renderMaxWidthEditor(props);
55726
- }
55727
- return null;
55728
- }
55729
- supportsRawValue() {
55730
- return false;
55731
- }
55732
- supportsColors(item) {
55733
- return true;
55734
- }
55735
- getIdeLinkMode(item) {
55736
- const configuredMode = item.metadata?.[IDE_LINK_KEY];
55737
- if (configuredMode && IDE_LINK_MODES.includes(configuredMode)) {
55738
- return configuredMode;
55739
- }
55740
- if (isMetadataFlagEnabled(item, LEGACY_CURSOR_LINK_KEY)) {
55741
- return "cursor";
55742
- }
55743
- return null;
55744
- }
55745
- cycleIdeLinkMode(item) {
55746
- const currentMode = this.getIdeLinkMode(item);
55747
- const currentIndex = currentMode ? IDE_LINK_MODES.indexOf(currentMode) : -1;
55748
- const nextMode = currentIndex === IDE_LINK_MODES.length - 1 ? null : IDE_LINK_MODES[currentIndex + 1] ?? null;
55749
- const {
55750
- [IDE_LINK_KEY]: removedIdeLink,
55751
- [LEGACY_CURSOR_LINK_KEY]: removedLegacyLink,
55752
- ...restMetadata
55753
- } = item.metadata ?? {};
55754
- return {
55755
- ...item,
55756
- metadata: nextMode ? {
55757
- ...restMetadata,
55758
- [IDE_LINK_KEY]: nextMode
55759
- } : Object.keys(restMetadata).length > 0 ? restMetadata : undefined
55760
- };
55761
- }
55762
- }
55763
- var IDE_LINK_KEY = "linkToIDE", LEGACY_CURSOR_LINK_KEY = "linkToCursor", TOGGLE_LINK_ACTION2 = "toggle-link", IDE_LINK_LABELS;
55764
- var init_GitRootDir = __esm(async () => {
55765
- init_git();
55766
- init_hyperlink();
55767
- init_git_no_git();
55768
- await init_max_width();
55769
- IDE_LINK_LABELS = {
55770
- vscode: "link-vscode",
55771
- cursor: "link-cursor"
55772
- };
55773
- });
55774
-
55775
55596
  // src/utils/git-review-cache.ts
55776
55597
  import { execFileSync as execFileSync2 } from "child_process";
55777
55598
  import {
@@ -55784,6 +55605,52 @@ import {
55784
55605
  import { createHash as createHash2 } from "node:crypto";
55785
55606
  import os4 from "node:os";
55786
55607
  import path2 from "node:path";
55608
+ function readField(entry, key) {
55609
+ const value = entry[key];
55610
+ return typeof value === "string" ? value.toUpperCase() : "";
55611
+ }
55612
+ function classifyCheck(entry) {
55613
+ if (typeof entry.status === "string") {
55614
+ if (entry.status.toUpperCase() !== "COMPLETED")
55615
+ return "pending";
55616
+ const conclusion = readField(entry, "conclusion");
55617
+ if (conclusion === "SUCCESS")
55618
+ return "success";
55619
+ if (conclusion === "NEUTRAL" || conclusion === "SKIPPED")
55620
+ return "ignored";
55621
+ return "failed";
55622
+ }
55623
+ const state = readField(entry, "state");
55624
+ if (state === "SUCCESS")
55625
+ return "success";
55626
+ if (state === "PENDING" || state === "EXPECTED")
55627
+ return "pending";
55628
+ return "failed";
55629
+ }
55630
+ function computeCiRollup(rollup) {
55631
+ if (!Array.isArray(rollup) || rollup.length === 0)
55632
+ return null;
55633
+ let failing = 0;
55634
+ let pending = 0;
55635
+ let success2 = 0;
55636
+ let seen = 0;
55637
+ for (const entry of rollup) {
55638
+ if (typeof entry !== "object" || entry === null)
55639
+ continue;
55640
+ seen++;
55641
+ const kind = classifyCheck(entry);
55642
+ if (kind === "failed")
55643
+ failing++;
55644
+ else if (kind === "pending")
55645
+ pending++;
55646
+ else if (kind === "success")
55647
+ success2++;
55648
+ }
55649
+ if (seen === 0)
55650
+ return null;
55651
+ const state = failing > 0 ? "failing" : pending > 0 ? "pending" : "passing";
55652
+ return { state, failing, pending, success: success2 };
55653
+ }
55787
55654
  function getCacheDir2(deps) {
55788
55655
  return path2.join(deps.getHomedir(), ".cache", "ccstatusline");
55789
55656
  }
@@ -55966,6 +55833,19 @@ function mapGlabState(state) {
55966
55833
  return "LOCKED";
55967
55834
  return state.toUpperCase();
55968
55835
  }
55836
+ function queryGhPr(cwd2, args, fields, deps) {
55837
+ const output = deps.execFileSync("gh", [...args, "--json", fields], {
55838
+ encoding: "utf8",
55839
+ stdio: ["pipe", "pipe", "ignore"],
55840
+ cwd: cwd2,
55841
+ timeout: CLI_TIMEOUT,
55842
+ windowsHide: true
55843
+ }).trim();
55844
+ if (output.length === 0) {
55845
+ return null;
55846
+ }
55847
+ return JSON.parse(output);
55848
+ }
55969
55849
  function fetchFromGh(cwd2, repoRef, deps) {
55970
55850
  const args = ["pr", "view"];
55971
55851
  if (repoRef) {
@@ -55975,18 +55855,15 @@ function fetchFromGh(cwd2, repoRef, deps) {
55975
55855
  }
55976
55856
  args.push(branch, "--repo", repoRef);
55977
55857
  }
55978
- args.push("--json", "url,number,title,state,reviewDecision");
55979
- const output = deps.execFileSync("gh", args, {
55980
- encoding: "utf8",
55981
- stdio: ["pipe", "pipe", "ignore"],
55982
- cwd: cwd2,
55983
- timeout: CLI_TIMEOUT,
55984
- windowsHide: true
55985
- }).trim();
55986
- if (output.length === 0) {
55858
+ let parsed;
55859
+ try {
55860
+ parsed = queryGhPr(cwd2, args, GH_PR_WITH_CHECKS_FIELDS, deps);
55861
+ } catch {
55862
+ parsed = queryGhPr(cwd2, args, GH_PR_METADATA_FIELDS, deps);
55863
+ }
55864
+ if (!parsed) {
55987
55865
  return null;
55988
55866
  }
55989
- const parsed = JSON.parse(output);
55990
55867
  if (typeof parsed.number !== "number" || typeof parsed.url !== "string") {
55991
55868
  return null;
55992
55869
  }
@@ -55996,7 +55873,8 @@ function fetchFromGh(cwd2, repoRef, deps) {
55996
55873
  title: typeof parsed.title === "string" ? parsed.title : "",
55997
55874
  state: typeof parsed.state === "string" ? parsed.state : "",
55998
55875
  reviewDecision: typeof parsed.reviewDecision === "string" ? parsed.reviewDecision : "",
55999
- provider: "gh"
55876
+ provider: "gh",
55877
+ checks: computeCiRollup(parsed.statusCheckRollup) ?? undefined
56000
55878
  };
56001
55879
  }
56002
55880
  function fetchFromGlab(cwd2, repoRef, deps) {
@@ -56043,61 +55921,333 @@ function fetchFromProvider(provider, cwd2, repoRef, deps) {
56043
55921
  if (repoRef) {
56044
55922
  return fetchFn(cwd2, repoRef, deps);
56045
55923
  }
56046
- return null;
56047
- }
56048
- function fetchGitReviewData(cwd2, deps = DEFAULT_GIT_REVIEW_CACHE_DEPS) {
56049
- const cachePath = getCachePath2(cwd2, getCacheRef(cwd2, deps), deps);
56050
- const cached2 = readCache(cachePath, deps);
56051
- if (cached2 !== "miss") {
56052
- return cached2;
55924
+ return null;
55925
+ }
55926
+ function fetchGitReviewData(cwd2, deps = DEFAULT_GIT_REVIEW_CACHE_DEPS) {
55927
+ const cachePath = getCachePath2(cwd2, getCacheRef(cwd2, deps), deps);
55928
+ const cached2 = readCache(cachePath, deps);
55929
+ if (cached2 !== "miss") {
55930
+ return cached2;
55931
+ }
55932
+ const repoRef = getOriginRepoRef(cwd2, deps);
55933
+ for (const provider of getProviderCandidates(cwd2, deps)) {
55934
+ if (!isCliAvailable(provider, deps)) {
55935
+ continue;
55936
+ }
55937
+ try {
55938
+ const data = fetchFromProvider(provider, cwd2, repoRef, deps);
55939
+ if (data) {
55940
+ writeCache(cachePath, data, deps);
55941
+ return data;
55942
+ }
55943
+ } catch {}
55944
+ }
55945
+ writeCache(cachePath, null, deps);
55946
+ return null;
55947
+ }
55948
+ function getGitReviewStatusLabel(state, reviewDecision) {
55949
+ if (state === "MERGED")
55950
+ return "MERGED";
55951
+ if (state === "CLOSED")
55952
+ return "CLOSED";
55953
+ if (reviewDecision === "APPROVED")
55954
+ return "APPROVED";
55955
+ if (reviewDecision === "CHANGES_REQUESTED")
55956
+ return "CHANGES_REQ";
55957
+ if (state === "OPEN")
55958
+ return "OPEN";
55959
+ return state;
55960
+ }
55961
+ function truncateTitle(title, maxWidth) {
55962
+ const limit = maxWidth ?? DEFAULT_TITLE_MAX_WIDTH;
55963
+ if (title.length <= limit)
55964
+ return title;
55965
+ return `${title.slice(0, limit - 1)}…`;
55966
+ }
55967
+ var GIT_REVIEW_CACHE_TTL = 30000, CLI_TIMEOUT = 5000, DEFAULT_TITLE_MAX_WIDTH = 30, GH_PR_METADATA_FIELDS = "url,number,title,state,reviewDecision", GH_PR_WITH_CHECKS_FIELDS, DEFAULT_GIT_REVIEW_CACHE_DEPS;
55968
+ var init_git_review_cache = __esm(() => {
55969
+ init_git_remote();
55970
+ GH_PR_WITH_CHECKS_FIELDS = `${GH_PR_METADATA_FIELDS},statusCheckRollup`;
55971
+ DEFAULT_GIT_REVIEW_CACHE_DEPS = {
55972
+ execFileSync: execFileSync2,
55973
+ existsSync: existsSync2,
55974
+ mkdirSync: mkdirSync2,
55975
+ readFileSync: readFileSync3,
55976
+ statSync: statSync2,
55977
+ writeFileSync: writeFileSync2,
55978
+ getHomedir: os4.homedir,
55979
+ now: Date.now
55980
+ };
55981
+ });
55982
+
55983
+ // src/widgets/GitCiStatus.ts
55984
+ function buildDisplay(checks3, rawValue) {
55985
+ if (rawValue)
55986
+ return checks3.state;
55987
+ const parts = [];
55988
+ if (checks3.failing > 0)
55989
+ parts.push(`${SYMBOLS.failing}${checks3.failing}`);
55990
+ if (checks3.pending > 0)
55991
+ parts.push(`${SYMBOLS.pending}${checks3.pending}`);
55992
+ if (checks3.success > 0)
55993
+ parts.push(`${SYMBOLS.success}${checks3.success}`);
55994
+ return parts.length > 0 ? parts.join(" ") : `${SYMBOLS[checks3.state]}0`;
55995
+ }
55996
+
55997
+ class GitCiStatusWidget {
55998
+ deps;
55999
+ constructor(deps = DEFAULT_DEPS) {
56000
+ this.deps = deps;
56001
+ }
56002
+ getDefaultColor() {
56003
+ return "green";
56004
+ }
56005
+ getDescription() {
56006
+ return "Shows CI check status for the current branch's PR (GitHub only)";
56007
+ }
56008
+ getDisplayName() {
56009
+ return "Git CI Status";
56010
+ }
56011
+ getCategory() {
56012
+ return "Git";
56013
+ }
56014
+ getEditorDisplay(item) {
56015
+ return {
56016
+ displayText: this.getDisplayName(),
56017
+ modifierText: getHideNoGitModifierText(item)
56018
+ };
56019
+ }
56020
+ handleEditorAction(action, item) {
56021
+ return handleToggleNoGitAction(action, item);
56022
+ }
56023
+ render(item, context, _settings) {
56024
+ const rawValue = item.rawValue ?? false;
56025
+ if (context.isPreview) {
56026
+ return buildDisplay(PREVIEW_CHECKS, rawValue);
56027
+ }
56028
+ if (!this.deps.isInsideGitWorkTree(context)) {
56029
+ return isHideNoGitEnabled(item) ? null : "(no git)";
56030
+ }
56031
+ const cwd2 = this.deps.resolveGitCwd(context) ?? this.deps.getProcessCwd();
56032
+ const checks3 = this.deps.fetchGitReviewData(cwd2)?.checks;
56033
+ if (!checks3) {
56034
+ return NO_CHECKS;
56035
+ }
56036
+ return buildDisplay(checks3, rawValue);
56037
+ }
56038
+ getCustomKeybinds() {
56039
+ return getHideNoGitKeybinds();
56040
+ }
56041
+ supportsRawValue() {
56042
+ return true;
56043
+ }
56044
+ supportsColors(_item) {
56045
+ return true;
56046
+ }
56047
+ }
56048
+ var NO_CHECKS = "-", SYMBOLS, DEFAULT_DEPS, PREVIEW_CHECKS;
56049
+ var init_GitCiStatus = __esm(() => {
56050
+ init_git();
56051
+ init_git_review_cache();
56052
+ init_git_no_git();
56053
+ SYMBOLS = {
56054
+ success: "✓",
56055
+ passing: "✓",
56056
+ failing: "✗",
56057
+ pending: "●"
56058
+ };
56059
+ DEFAULT_DEPS = {
56060
+ fetchGitReviewData,
56061
+ getProcessCwd: () => process.cwd(),
56062
+ isInsideGitWorkTree,
56063
+ resolveGitCwd
56064
+ };
56065
+ PREVIEW_CHECKS = {
56066
+ state: "failing",
56067
+ failing: 1,
56068
+ pending: 1,
56069
+ success: 5
56070
+ };
56071
+ });
56072
+
56073
+ // src/widgets/GitCleanStatus.ts
56074
+ class GitCleanStatusWidget {
56075
+ getDefaultColor() {
56076
+ return "green";
56077
+ }
56078
+ getDescription() {
56079
+ return "Shows ✓ when the working tree is clean and ✗ when it is dirty";
56080
+ }
56081
+ getDisplayName() {
56082
+ return "Git Clean Status";
56083
+ }
56084
+ getCategory() {
56085
+ return "Git";
56086
+ }
56087
+ getEditorDisplay(item) {
56088
+ return {
56089
+ displayText: this.getDisplayName(),
56090
+ modifierText: getHideNoGitModifierText(item)
56091
+ };
56092
+ }
56093
+ handleEditorAction(action, item) {
56094
+ return handleToggleNoGitAction(action, item);
56095
+ }
56096
+ render(item, context, _settings) {
56097
+ const hideNoGit = isHideNoGitEnabled(item);
56098
+ if (context.isPreview) {
56099
+ return item.rawValue ? "clean" : "✓";
56100
+ }
56101
+ if (!isInsideGitWorkTree(context)) {
56102
+ return hideNoGit ? null : "(no git)";
56103
+ }
56104
+ const clean = this.isClean(context);
56105
+ if (item.rawValue) {
56106
+ return clean ? "clean" : "dirty";
56107
+ }
56108
+ return clean ? "✓" : "✗";
56109
+ }
56110
+ isClean(context) {
56111
+ const status = getGitStatus(context);
56112
+ return !status.staged && !status.unstaged && !status.untracked && !status.conflicts;
56113
+ }
56114
+ getCustomKeybinds() {
56115
+ return getHideNoGitKeybinds();
56116
+ }
56117
+ supportsRawValue() {
56118
+ return true;
56119
+ }
56120
+ supportsColors(_item) {
56121
+ return true;
56122
+ }
56123
+ }
56124
+ var init_GitCleanStatus = __esm(() => {
56125
+ init_git();
56126
+ init_git_no_git();
56127
+ });
56128
+
56129
+ // src/widgets/GitRootDir.ts
56130
+ class GitRootDirWidget {
56131
+ getDefaultColor() {
56132
+ return "cyan";
56133
+ }
56134
+ getDescription() {
56135
+ return "Shows the git repository root directory name";
56136
+ }
56137
+ getDisplayName() {
56138
+ return "Git Root Dir";
56139
+ }
56140
+ getCategory() {
56141
+ return "Git";
56142
+ }
56143
+ getEditorDisplay(item) {
56144
+ const ideLinkMode = this.getIdeLinkMode(item);
56145
+ const modifiers = [];
56146
+ const noGitText = getHideNoGitModifierText(item);
56147
+ if (noGitText)
56148
+ modifiers.push("hide 'no git'");
56149
+ if (ideLinkMode)
56150
+ modifiers.push(IDE_LINK_LABELS[ideLinkMode]);
56151
+ const maxWidthText = getMaxWidthModifier(item);
56152
+ if (maxWidthText)
56153
+ modifiers.push(maxWidthText);
56154
+ return {
56155
+ displayText: this.getDisplayName(),
56156
+ modifierText: makeModifierText(modifiers)
56157
+ };
56158
+ }
56159
+ handleEditorAction(action, item) {
56160
+ if (action === TOGGLE_LINK_ACTION2) {
56161
+ return this.cycleIdeLinkMode(item);
56162
+ }
56163
+ return handleToggleNoGitAction(action, item);
56164
+ }
56165
+ render(item, context, _settings) {
56166
+ const hideNoGit = isHideNoGitEnabled(item);
56167
+ const ideLinkMode = this.getIdeLinkMode(item);
56168
+ if (context.isPreview) {
56169
+ const name2 = "my-repo";
56170
+ return ideLinkMode ? renderOsc8Link(buildIdeFileUrl("/Users/example/my-repo", ideLinkMode), name2) : name2;
56171
+ }
56172
+ if (!isInsideGitWorkTree(context)) {
56173
+ return hideNoGit ? null : "no git";
56174
+ }
56175
+ const rootDir = this.getGitRootDir(context);
56176
+ if (!rootDir) {
56177
+ return hideNoGit ? null : "no git";
56178
+ }
56179
+ const name = applyMaxWidth(this.getRootDirName(rootDir), item.maxWidth);
56180
+ if (ideLinkMode) {
56181
+ return renderOsc8Link(buildIdeFileUrl(rootDir, ideLinkMode), name);
56182
+ }
56183
+ return name;
56184
+ }
56185
+ getGitRootDir(context) {
56186
+ return runGit("rev-parse --show-toplevel", context);
56187
+ }
56188
+ getRootDirName(rootDir) {
56189
+ const trimmedRootDir = rootDir.replace(/[\\/]+$/, "");
56190
+ const normalizedRootDir = trimmedRootDir.length > 0 ? trimmedRootDir : rootDir;
56191
+ const parts = normalizedRootDir.split(/[\\/]/).filter(Boolean);
56192
+ const lastPart = parts[parts.length - 1];
56193
+ return lastPart && lastPart.length > 0 ? lastPart : normalizedRootDir;
56194
+ }
56195
+ getCustomKeybinds() {
56196
+ return [
56197
+ ...getHideNoGitKeybinds(),
56198
+ { key: "l", label: "(l)ink to IDE", action: TOGGLE_LINK_ACTION2 },
56199
+ getMaxWidthKeybind()
56200
+ ];
56201
+ }
56202
+ renderEditor(props) {
56203
+ if (props.action === MAX_WIDTH_ACTION) {
56204
+ return renderMaxWidthEditor(props);
56205
+ }
56206
+ return null;
56207
+ }
56208
+ supportsRawValue() {
56209
+ return false;
56053
56210
  }
56054
- const repoRef = getOriginRepoRef(cwd2, deps);
56055
- for (const provider of getProviderCandidates(cwd2, deps)) {
56056
- if (!isCliAvailable(provider, deps)) {
56057
- continue;
56211
+ supportsColors(item) {
56212
+ return true;
56213
+ }
56214
+ getIdeLinkMode(item) {
56215
+ const configuredMode = item.metadata?.[IDE_LINK_KEY];
56216
+ if (configuredMode && IDE_LINK_MODES.includes(configuredMode)) {
56217
+ return configuredMode;
56058
56218
  }
56059
- try {
56060
- const data = fetchFromProvider(provider, cwd2, repoRef, deps);
56061
- if (data) {
56062
- writeCache(cachePath, data, deps);
56063
- return data;
56064
- }
56065
- } catch {}
56219
+ if (isMetadataFlagEnabled(item, LEGACY_CURSOR_LINK_KEY)) {
56220
+ return "cursor";
56221
+ }
56222
+ return null;
56223
+ }
56224
+ cycleIdeLinkMode(item) {
56225
+ const currentMode = this.getIdeLinkMode(item);
56226
+ const currentIndex = currentMode ? IDE_LINK_MODES.indexOf(currentMode) : -1;
56227
+ const nextMode = currentIndex === IDE_LINK_MODES.length - 1 ? null : IDE_LINK_MODES[currentIndex + 1] ?? null;
56228
+ const {
56229
+ [IDE_LINK_KEY]: removedIdeLink,
56230
+ [LEGACY_CURSOR_LINK_KEY]: removedLegacyLink,
56231
+ ...restMetadata
56232
+ } = item.metadata ?? {};
56233
+ return {
56234
+ ...item,
56235
+ metadata: nextMode ? {
56236
+ ...restMetadata,
56237
+ [IDE_LINK_KEY]: nextMode
56238
+ } : Object.keys(restMetadata).length > 0 ? restMetadata : undefined
56239
+ };
56066
56240
  }
56067
- writeCache(cachePath, null, deps);
56068
- return null;
56069
- }
56070
- function getGitReviewStatusLabel(state, reviewDecision) {
56071
- if (state === "MERGED")
56072
- return "MERGED";
56073
- if (state === "CLOSED")
56074
- return "CLOSED";
56075
- if (reviewDecision === "APPROVED")
56076
- return "APPROVED";
56077
- if (reviewDecision === "CHANGES_REQUESTED")
56078
- return "CHANGES_REQ";
56079
- if (state === "OPEN")
56080
- return "OPEN";
56081
- return state;
56082
- }
56083
- function truncateTitle(title, maxWidth) {
56084
- const limit = maxWidth ?? DEFAULT_TITLE_MAX_WIDTH;
56085
- if (title.length <= limit)
56086
- return title;
56087
- return `${title.slice(0, limit - 1)}…`;
56088
56241
  }
56089
- var GIT_REVIEW_CACHE_TTL = 30000, CLI_TIMEOUT = 5000, DEFAULT_TITLE_MAX_WIDTH = 30, DEFAULT_GIT_REVIEW_CACHE_DEPS;
56090
- var init_git_review_cache = __esm(() => {
56091
- init_git_remote();
56092
- DEFAULT_GIT_REVIEW_CACHE_DEPS = {
56093
- execFileSync: execFileSync2,
56094
- existsSync: existsSync2,
56095
- mkdirSync: mkdirSync2,
56096
- readFileSync: readFileSync3,
56097
- statSync: statSync2,
56098
- writeFileSync: writeFileSync2,
56099
- getHomedir: os4.homedir,
56100
- now: Date.now
56242
+ var IDE_LINK_KEY = "linkToIDE", LEGACY_CURSOR_LINK_KEY = "linkToCursor", TOGGLE_LINK_ACTION2 = "toggle-link", IDE_LINK_LABELS;
56243
+ var init_GitRootDir = __esm(async () => {
56244
+ init_git();
56245
+ init_hyperlink();
56246
+ init_git_no_git();
56247
+ await init_max_width();
56248
+ IDE_LINK_LABELS = {
56249
+ vscode: "link-vscode",
56250
+ cursor: "link-cursor"
56101
56251
  };
56102
56252
  });
56103
56253
 
@@ -56118,7 +56268,7 @@ function resolvePrNoun(pr, context, deps) {
56118
56268
  }
56119
56269
  return "PR";
56120
56270
  }
56121
- function buildDisplay(item, pr, showStatus, showTitle, noun) {
56271
+ function buildDisplay2(item, pr, showStatus, showTitle, noun) {
56122
56272
  const linkText = item.rawValue ? `#${pr.number}` : `${noun} #${pr.number}`;
56123
56273
  const parts = [renderOsc8Link(pr.url, linkText)];
56124
56274
  if (showStatus) {
@@ -56178,7 +56328,7 @@ class GitPrWidget {
56178
56328
  const showStatus = !isMetadataFlagEnabled(item, HIDE_STATUS_KEY);
56179
56329
  const showTitle = !isMetadataFlagEnabled(item, HIDE_TITLE_KEY);
56180
56330
  if (context.isPreview) {
56181
- return buildDisplay(item, PREVIEW_PR, showStatus, showTitle, resolvePrNoun(PREVIEW_PR, context, this.deps));
56331
+ return buildDisplay2(item, PREVIEW_PR, showStatus, showTitle, resolvePrNoun(PREVIEW_PR, context, this.deps));
56182
56332
  }
56183
56333
  if (!this.deps.isInsideGitWorkTree(context)) {
56184
56334
  return hideNoGit ? null : `(no ${resolvePrNoun(null, context, this.deps)})`;
@@ -56188,7 +56338,7 @@ class GitPrWidget {
56188
56338
  if (!prData) {
56189
56339
  return hideNoGit ? null : `(no ${resolvePrNoun(null, context, this.deps)})`;
56190
56340
  }
56191
- return buildDisplay(item, prData, showStatus, showTitle, resolvePrNoun(prData, context, this.deps));
56341
+ return buildDisplay2(item, prData, showStatus, showTitle, resolvePrNoun(prData, context, this.deps));
56192
56342
  }
56193
56343
  getCustomKeybinds() {
56194
56344
  return [
@@ -57977,7 +58127,7 @@ function getTerminalWidth() {
57977
58127
  function canDetectTerminalWidth() {
57978
58128
  return probeTerminalWidth() !== null;
57979
58129
  }
57980
- var __dirname = "/home/runner/work/ccstatusline/ccstatusline/src/utils", PACKAGE_VERSION = "2.2.23";
58130
+ var __dirname = "/home/runner/work/ccstatusline/ccstatusline/src/utils", PACKAGE_VERSION = "2.2.24";
57981
58131
  var init_terminal = () => {};
57982
58132
 
57983
58133
  // src/utils/format-tokens.ts
@@ -57997,6 +58147,13 @@ function maybeApplyForegroundGradient(line, settings, colorLevel) {
57997
58147
  const stops = parseGradientSpec(settings.overrideForegroundColor);
57998
58148
  return stops ? applyLineGradient(line, stops, colorLevel) : line;
57999
58149
  }
58150
+ function resolvePaddingSides(padding, side) {
58151
+ if (side === "left")
58152
+ return { leading: padding, trailing: "" };
58153
+ if (side === "right")
58154
+ return { leading: "", trailing: padding };
58155
+ return { leading: padding, trailing: padding };
58156
+ }
58000
58157
  function resolveEffectiveTerminalWidth(detectedWidth, settings, context) {
58001
58158
  if (!detectedWidth) {
58002
58159
  return null;
@@ -58117,6 +58274,7 @@ function renderPowerlineStatusLine(widgets, settings, context, lineIndex = 0, gl
58117
58274
  }
58118
58275
  if (widgetText) {
58119
58276
  const padding = settings.defaultPadding ?? "";
58277
+ const { leading: sideLeadingPadding, trailing: sideTrailingPadding } = resolvePaddingSides(padding, settings.defaultPaddingSide);
58120
58278
  if (settings.overrideForegroundColor && settings.overrideForegroundColor !== "none" && widget.type === "custom-command" && widget.preserveColors) {
58121
58279
  widgetText = stripSgrCodes(widgetText);
58122
58280
  }
@@ -58125,8 +58283,8 @@ function renderPowerlineStatusLine(widgets, settings, context, lineIndex = 0, gl
58125
58283
  const mergesWithNext = canMergeWithNextRenderedWidget(actualPreRenderedIndex);
58126
58284
  const omitLeadingPadding = previousRenderedWidget?.merge === "no-padding" && canMergeWithNextRenderedWidget(previousRenderedIndex ?? undefined);
58127
58285
  const omitTrailingPadding = widget.merge === "no-padding" && mergesWithNext;
58128
- const leadingPadding = omitLeadingPadding ? "" : padding;
58129
- const trailingPadding = omitTrailingPadding ? "" : padding;
58286
+ const leadingPadding = omitLeadingPadding ? "" : sideLeadingPadding;
58287
+ const trailingPadding = omitTrailingPadding ? "" : sideTrailingPadding;
58130
58288
  const paddedText = `${leadingPadding}${widgetText}${trailingPadding}`;
58131
58289
  let fgColor = widget.color ?? defaultColor;
58132
58290
  let bgColor = widget.backgroundColor;
@@ -58507,7 +58665,8 @@ function preRenderAllWidgets(allLinesWidgets, settings, context) {
58507
58665
  function calculateMaxWidthsFromPreRendered(preRenderedLines, settings) {
58508
58666
  const maxWidths = [];
58509
58667
  const defaultPadding = settings.defaultPadding ?? "";
58510
- const paddingLength = defaultPadding.length;
58668
+ const { leading: sideLeadingPadding, trailing: sideTrailingPadding } = resolvePaddingSides(defaultPadding, settings.defaultPaddingSide);
58669
+ const paddingPairLength = sideLeadingPadding.length + sideTrailingPadding.length;
58511
58670
  for (const preRenderedLine of preRenderedLines) {
58512
58671
  const isSeparatorBoundary = (entry) => entry?.widget.type === "separator" || entry?.widget.type === "flex-separator";
58513
58672
  const hasNextRenderedWidgetBeforeSeparator = (originalIndex) => {
@@ -58533,7 +58692,7 @@ function calculateMaxWidthsFromPreRendered(preRenderedLines, settings) {
58533
58692
  continue;
58534
58693
  if (widget.widget.excludeFromAutoAlign)
58535
58694
  break;
58536
- let totalWidth = widget.plainLength + paddingLength * 2;
58695
+ let totalWidth = widget.plainLength + paddingPairLength;
58537
58696
  let j = i;
58538
58697
  while (j < renderedWidgets.length - 1 && renderedWidgets[j]?.mergesWithNext) {
58539
58698
  j++;
@@ -58542,7 +58701,7 @@ function calculateMaxWidthsFromPreRendered(preRenderedLines, settings) {
58542
58701
  if (renderedWidgets[j - 1]?.widget.merge === "no-padding") {
58543
58702
  totalWidth += nextWidget.plainLength;
58544
58703
  } else {
58545
- totalWidth += nextWidget.plainLength + paddingLength * 2;
58704
+ totalWidth += nextWidget.plainLength + paddingPairLength;
58546
58705
  }
58547
58706
  }
58548
58707
  }
@@ -58675,6 +58834,7 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
58675
58834
  }
58676
58835
  const finalElements = [];
58677
58836
  const padding = settings.defaultPadding ?? "";
58837
+ const { leading: sideLeadingPadding, trailing: sideTrailingPadding } = resolvePaddingSides(padding, settings.defaultPaddingSide);
58678
58838
  const defaultSep = settings.defaultSeparator ? formatSeparator(settings.defaultSeparator) : "";
58679
58839
  elements.forEach((elem, index) => {
58680
58840
  const prevElem = index > 0 ? elements[index - 1] : null;
@@ -58708,14 +58868,13 @@ function renderStatusLine(widgets, settings, context, preRenderedWidgets, preCal
58708
58868
  const omitTrailingPadding = elem.widget?.merge === "no-padding" && nextElem && nextElem.type !== "separator" && nextElem.type !== "flex-separator";
58709
58869
  const hasColorOverride = Boolean(settings.overrideBackgroundColor && settings.overrideBackgroundColor !== "none") || Boolean(settings.overrideForegroundColor && settings.overrideForegroundColor !== "none");
58710
58870
  if (padding && (elem.widget?.backgroundColor || hasColorOverride)) {
58711
- const leadingPadding = omitLeadingPadding ? "" : applyColorsWithOverride(padding, undefined, elem.widget?.backgroundColor);
58712
- const trailingPadding = omitTrailingPadding ? "" : applyColorsWithOverride(padding, undefined, elem.widget?.backgroundColor);
58871
+ const leadingPadding = omitLeadingPadding || !sideLeadingPadding ? "" : applyColorsWithOverride(sideLeadingPadding, undefined, elem.widget?.backgroundColor);
58872
+ const trailingPadding = omitTrailingPadding || !sideTrailingPadding ? "" : applyColorsWithOverride(sideTrailingPadding, undefined, elem.widget?.backgroundColor);
58713
58873
  const paddedContent = leadingPadding + elem.content + trailingPadding;
58714
58874
  finalElements.push(paddedContent);
58715
58875
  } else if (padding) {
58716
- const protectedPadding = source_default.reset(padding);
58717
- const leadingPadding = omitLeadingPadding ? "" : protectedPadding;
58718
- const trailingPadding = omitTrailingPadding ? "" : protectedPadding;
58876
+ const leadingPadding = omitLeadingPadding || !sideLeadingPadding ? "" : source_default.reset(sideLeadingPadding);
58877
+ const trailingPadding = omitTrailingPadding || !sideTrailingPadding ? "" : source_default.reset(sideTrailingPadding);
58719
58878
  finalElements.push(leadingPadding + elem.content + trailingPadding);
58720
58879
  } else {
58721
58880
  finalElements.push(elem.content);
@@ -69084,26 +69243,43 @@ function getFormat(item) {
69084
69243
  const f = item.metadata?.format;
69085
69244
  return FORMATS.includes(f ?? "") ? f : DEFAULT_FORMAT;
69086
69245
  }
69246
+ function canUseNerdFont(item) {
69247
+ const format = getFormat(item);
69248
+ return format === "icon-dash-letter" || format === "icon-letter" || format === "icon";
69249
+ }
69250
+ function removeNerdFont(item) {
69251
+ const { [NERD_FONT_METADATA_KEY]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
69252
+ return {
69253
+ ...item,
69254
+ metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69255
+ };
69256
+ }
69087
69257
  function setFormat(item, format) {
69258
+ let updatedItem;
69088
69259
  if (format === DEFAULT_FORMAT) {
69089
69260
  const { format: removedFormat, ...restMetadata } = item.metadata ?? {};
69090
- return {
69261
+ updatedItem = {
69091
69262
  ...item,
69092
69263
  metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69093
69264
  };
69265
+ } else {
69266
+ updatedItem = {
69267
+ ...item,
69268
+ metadata: {
69269
+ ...item.metadata ?? {},
69270
+ format
69271
+ }
69272
+ };
69094
69273
  }
69095
- return {
69096
- ...item,
69097
- metadata: {
69098
- ...item.metadata ?? {},
69099
- format
69100
- }
69101
- };
69274
+ return canUseNerdFont(updatedItem) ? updatedItem : removeNerdFont(updatedItem);
69102
69275
  }
69103
69276
  function isNerdFontEnabled(item) {
69104
- return item.metadata?.[NERD_FONT_METADATA_KEY] === "true";
69277
+ return canUseNerdFont(item) && item.metadata?.[NERD_FONT_METADATA_KEY] === "true";
69105
69278
  }
69106
69279
  function toggleNerdFont(item) {
69280
+ if (!canUseNerdFont(item)) {
69281
+ return removeNerdFont(item);
69282
+ }
69107
69283
  if (!isNerdFontEnabled(item)) {
69108
69284
  return {
69109
69285
  ...item,
@@ -69113,11 +69289,7 @@ function toggleNerdFont(item) {
69113
69289
  }
69114
69290
  };
69115
69291
  }
69116
- const { [NERD_FONT_METADATA_KEY]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
69117
- return {
69118
- ...item,
69119
- metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69120
- };
69292
+ return removeNerdFont(item);
69121
69293
  }
69122
69294
  function formatMode(mode, format, icon) {
69123
69295
  const letter = mode === "NORMAL" ? "N" : mode === "INSERT" ? "I" : mode[0] ?? mode;
@@ -69179,11 +69351,14 @@ class VimModeWidget {
69179
69351
  return null;
69180
69352
  return formatMode(mode, format, icon);
69181
69353
  }
69182
- getCustomKeybinds() {
69183
- return [
69184
- { key: "f", label: "(f)ormat", action: CYCLE_FORMAT_ACTION },
69185
- { key: "n", label: "(n)erd font", action: TOGGLE_NERD_FONT_ACTION }
69354
+ getCustomKeybinds(item) {
69355
+ const keybinds = [
69356
+ { key: "f", label: "(f)ormat", action: CYCLE_FORMAT_ACTION }
69186
69357
  ];
69358
+ if (item === undefined || canUseNerdFont(item)) {
69359
+ keybinds.push({ key: "n", label: "(n)erd font", action: TOGGLE_NERD_FONT_ACTION });
69360
+ }
69361
+ return keybinds;
69187
69362
  }
69188
69363
  supportsRawValue() {
69189
69364
  return false;
@@ -69408,7 +69583,7 @@ function getFormat2(item) {
69408
69583
  const format = item.metadata?.format;
69409
69584
  return FORMATS2.includes(format ?? "") ? format : DEFAULT_FORMAT2;
69410
69585
  }
69411
- function removeNerdFont(item) {
69586
+ function removeNerdFont2(item) {
69412
69587
  const { [NERD_FONT_METADATA_KEY2]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
69413
69588
  return {
69414
69589
  ...item,
@@ -69513,7 +69688,7 @@ function formatStats(data, item, icon) {
69513
69688
  }
69514
69689
  function toggleNerdFont2(item) {
69515
69690
  if (getFormat2(item) !== DEFAULT_FORMAT2) {
69516
- return removeNerdFont(item);
69691
+ return removeNerdFont2(item);
69517
69692
  }
69518
69693
  if (!isNerdFontEnabled2(item)) {
69519
69694
  return {
@@ -69524,7 +69699,7 @@ function toggleNerdFont2(item) {
69524
69699
  }
69525
69700
  };
69526
69701
  }
69527
- return removeNerdFont(item);
69702
+ return removeNerdFont2(item);
69528
69703
  }
69529
69704
  function formatCount(count, format, icon) {
69530
69705
  switch (format) {
@@ -69658,59 +69833,217 @@ var init_CompactionCounter = __esm(async () => {
69658
69833
  });
69659
69834
  });
69660
69835
 
69661
- // src/widgets/VoiceStatus.ts
69836
+ // src/widgets/SandboxStatus.ts
69662
69837
  function getFormat3(item) {
69663
69838
  const f = item.metadata?.format;
69664
69839
  return FORMATS3.includes(f ?? "") ? f : DEFAULT_FORMAT3;
69665
69840
  }
69841
+ function canUseNerdFont2(item) {
69842
+ return getFormat3(item) === "glyph";
69843
+ }
69844
+ function removeNerdFont3(item) {
69845
+ const { [NERD_FONT_METADATA_KEY3]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
69846
+ return {
69847
+ ...item,
69848
+ metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69849
+ };
69850
+ }
69666
69851
  function setFormat3(item, format) {
69852
+ let updatedItem;
69667
69853
  if (format === DEFAULT_FORMAT3) {
69668
69854
  const { format: removedFormat, ...restMetadata } = item.metadata ?? {};
69669
- return {
69855
+ updatedItem = {
69670
69856
  ...item,
69671
69857
  metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69672
69858
  };
69859
+ } else {
69860
+ updatedItem = {
69861
+ ...item,
69862
+ metadata: {
69863
+ ...item.metadata ?? {},
69864
+ format
69865
+ }
69866
+ };
69867
+ }
69868
+ return canUseNerdFont2(updatedItem) ? updatedItem : removeNerdFont3(updatedItem);
69869
+ }
69870
+ function isNerdFontEnabled3(item) {
69871
+ return canUseNerdFont2(item) && item.metadata?.[NERD_FONT_METADATA_KEY3] === "true";
69872
+ }
69873
+ function toggleNerdFont3(item) {
69874
+ if (!canUseNerdFont2(item)) {
69875
+ return removeNerdFont3(item);
69876
+ }
69877
+ if (!isNerdFontEnabled3(item)) {
69878
+ return {
69879
+ ...item,
69880
+ metadata: {
69881
+ ...item.metadata ?? {},
69882
+ [NERD_FONT_METADATA_KEY3]: "true"
69883
+ }
69884
+ };
69885
+ }
69886
+ return removeNerdFont3(item);
69887
+ }
69888
+ function formatStatus(enabled, format, nerdFont, rawValue) {
69889
+ const stateText = enabled ? "ON" : "OFF";
69890
+ const glyph = nerdFont ? enabled ? LOCK_NERD_FONT : UNLOCK_NERD_FONT : enabled ? DOT_ON : DOT_OFF;
69891
+ switch (format) {
69892
+ case "glyph":
69893
+ return rawValue ? glyph : `SB: ${glyph}`;
69894
+ case "text":
69895
+ return rawValue ? stateText : `SB: ${stateText}`;
69896
+ case "word":
69897
+ return rawValue ? stateText : `Sandbox: ${stateText}`;
69898
+ }
69899
+ }
69900
+ function resolveSandboxConfigCwd(context) {
69901
+ const candidates = [
69902
+ context.data?.workspace?.project_dir,
69903
+ context.data?.cwd,
69904
+ context.data?.workspace?.current_dir
69905
+ ];
69906
+ return candidates.find((candidate) => typeof candidate === "string" && candidate.trim().length > 0);
69907
+ }
69908
+
69909
+ class SandboxStatusWidget {
69910
+ getDefaultColor() {
69911
+ return "green";
69912
+ }
69913
+ getDescription() {
69914
+ return [
69915
+ "Shows whether Claude Code bash sandbox mode is enabled",
69916
+ "Best effort: may not reflect active sandboxing when managed or CLI settings override it, or when sandbox initialization fails."
69917
+ ].join(`
69918
+ `);
69919
+ }
69920
+ getDisplayName() {
69921
+ return "Sandbox Status";
69922
+ }
69923
+ getCategory() {
69924
+ return "Core";
69925
+ }
69926
+ getEditorDisplay(item) {
69927
+ const modifiers = [getFormat3(item)];
69928
+ if (isNerdFontEnabled3(item)) {
69929
+ modifiers.push("nerd font");
69930
+ }
69931
+ return {
69932
+ displayText: this.getDisplayName(),
69933
+ modifierText: `(${modifiers.join(", ")})`
69934
+ };
69935
+ }
69936
+ handleEditorAction(action, item) {
69937
+ if (action === CYCLE_FORMAT_ACTION3) {
69938
+ const currentFormat = getFormat3(item);
69939
+ const nextFormat = FORMATS3[(FORMATS3.indexOf(currentFormat) + 1) % FORMATS3.length] ?? DEFAULT_FORMAT3;
69940
+ return setFormat3(item, nextFormat);
69941
+ }
69942
+ if (action === TOGGLE_NERD_FONT_ACTION3) {
69943
+ return toggleNerdFont3(item);
69944
+ }
69945
+ return null;
69946
+ }
69947
+ render(item, context, _settings) {
69948
+ const format = getFormat3(item);
69949
+ const nerdFont = isNerdFontEnabled3(item);
69950
+ if (context.isPreview) {
69951
+ return formatStatus(true, format, nerdFont, item.rawValue ?? false);
69952
+ }
69953
+ const config2 = getSandboxConfig(resolveSandboxConfigCwd(context));
69954
+ if (config2 === null) {
69955
+ return null;
69956
+ }
69957
+ return formatStatus(config2.enabled, format, nerdFont, item.rawValue ?? false);
69958
+ }
69959
+ getCustomKeybinds(item) {
69960
+ const keybinds = [
69961
+ { key: "f", label: "(f)ormat", action: CYCLE_FORMAT_ACTION3 }
69962
+ ];
69963
+ if (item === undefined || canUseNerdFont2(item)) {
69964
+ keybinds.push({ key: "n", label: "(n)erd font", action: TOGGLE_NERD_FONT_ACTION3 });
69965
+ }
69966
+ return keybinds;
69967
+ }
69968
+ supportsRawValue() {
69969
+ return true;
69970
+ }
69971
+ supportsColors(_item) {
69972
+ return true;
69673
69973
  }
69974
+ }
69975
+ var DOT_ON = "●", DOT_OFF = "○", LOCK_NERD_FONT = "", UNLOCK_NERD_FONT = "", FORMATS3, DEFAULT_FORMAT3 = "glyph", CYCLE_FORMAT_ACTION3 = "cycle-format", TOGGLE_NERD_FONT_ACTION3 = "toggle-nerd-font", NERD_FONT_METADATA_KEY3 = "nerdFont";
69976
+ var init_SandboxStatus = __esm(async () => {
69977
+ await init_claude_settings();
69978
+ FORMATS3 = ["glyph", "text", "word"];
69979
+ });
69980
+
69981
+ // src/widgets/VoiceStatus.ts
69982
+ function getFormat4(item) {
69983
+ const f = item.metadata?.format;
69984
+ return FORMATS4.includes(f ?? "") ? f : DEFAULT_FORMAT4;
69985
+ }
69986
+ function canUseNerdFont3(item) {
69987
+ const format = getFormat4(item);
69988
+ return format === "icon" || format === "icon-text" && !item.rawValue;
69989
+ }
69990
+ function removeNerdFont4(item) {
69991
+ const { [NERD_FONT_METADATA_KEY4]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
69674
69992
  return {
69675
69993
  ...item,
69676
- metadata: {
69677
- ...item.metadata ?? {},
69678
- format
69679
- }
69994
+ metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69680
69995
  };
69681
69996
  }
69682
- function isNerdFontEnabled3(item) {
69683
- return item.metadata?.[NERD_FONT_METADATA_KEY3] === "true";
69997
+ function setFormat4(item, format) {
69998
+ let updatedItem;
69999
+ if (format === DEFAULT_FORMAT4) {
70000
+ const { format: removedFormat, ...restMetadata } = item.metadata ?? {};
70001
+ updatedItem = {
70002
+ ...item,
70003
+ metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
70004
+ };
70005
+ } else {
70006
+ updatedItem = {
70007
+ ...item,
70008
+ metadata: {
70009
+ ...item.metadata ?? {},
70010
+ format
70011
+ }
70012
+ };
70013
+ }
70014
+ return canUseNerdFont3(updatedItem) ? updatedItem : removeNerdFont4(updatedItem);
70015
+ }
70016
+ function isNerdFontEnabled4(item) {
70017
+ return canUseNerdFont3(item) && item.metadata?.[NERD_FONT_METADATA_KEY4] === "true";
69684
70018
  }
69685
- function toggleNerdFont3(item) {
69686
- if (!isNerdFontEnabled3(item)) {
70019
+ function toggleNerdFont4(item) {
70020
+ if (!canUseNerdFont3(item)) {
70021
+ return removeNerdFont4(item);
70022
+ }
70023
+ if (!isNerdFontEnabled4(item)) {
69687
70024
  return {
69688
70025
  ...item,
69689
70026
  metadata: {
69690
70027
  ...item.metadata ?? {},
69691
- [NERD_FONT_METADATA_KEY3]: "true"
70028
+ [NERD_FONT_METADATA_KEY4]: "true"
69692
70029
  }
69693
70030
  };
69694
70031
  }
69695
- const { [NERD_FONT_METADATA_KEY3]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
69696
- return {
69697
- ...item,
69698
- metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69699
- };
70032
+ return removeNerdFont4(item);
69700
70033
  }
69701
- function formatStatus(enabled, format, nerdFont) {
70034
+ function formatStatus2(enabled, format, nerdFont, rawValue) {
69702
70035
  const stateText = enabled ? "on" : "off";
69703
70036
  const stateDot = enabled ? STATE_DOT_ON : STATE_DOT_OFF;
69704
70037
  const icon = nerdFont ? enabled ? MIC_NERD_FONT : MIC_SLASH_NERD_FONT : MIC_EMOJI;
69705
70038
  switch (format) {
69706
70039
  case "icon":
69707
- return nerdFont ? icon : `${icon} ${stateDot}`;
70040
+ return nerdFont ? icon : rawValue ? stateDot : `${icon} ${stateDot}`;
69708
70041
  case "icon-text":
69709
- return `${icon} ${stateText}`;
70042
+ return rawValue ? stateText : `${icon} ${stateText}`;
69710
70043
  case "text":
69711
70044
  return stateText;
69712
70045
  case "word":
69713
- return `voice ${stateText}`;
70046
+ return rawValue ? stateText : `voice ${stateText}`;
69714
70047
  }
69715
70048
  }
69716
70049
  function resolveVoiceConfigCwd(context) {
@@ -69736,8 +70069,8 @@ class VoiceStatusWidget {
69736
70069
  return "Core";
69737
70070
  }
69738
70071
  getEditorDisplay(item) {
69739
- const modifiers = [getFormat3(item)];
69740
- if (isNerdFontEnabled3(item)) {
70072
+ const modifiers = [getFormat4(item)];
70073
+ if (isNerdFontEnabled4(item)) {
69741
70074
  modifiers.push("nerd font");
69742
70075
  }
69743
70076
  return {
@@ -69746,39 +70079,36 @@ class VoiceStatusWidget {
69746
70079
  };
69747
70080
  }
69748
70081
  handleEditorAction(action, item) {
69749
- if (action === CYCLE_FORMAT_ACTION3) {
69750
- const currentFormat = getFormat3(item);
69751
- const nextFormat = FORMATS3[(FORMATS3.indexOf(currentFormat) + 1) % FORMATS3.length] ?? DEFAULT_FORMAT3;
69752
- return setFormat3(item, nextFormat);
70082
+ if (action === CYCLE_FORMAT_ACTION4) {
70083
+ const currentFormat = getFormat4(item);
70084
+ const nextFormat = FORMATS4[(FORMATS4.indexOf(currentFormat) + 1) % FORMATS4.length] ?? DEFAULT_FORMAT4;
70085
+ return setFormat4(item, nextFormat);
69753
70086
  }
69754
- if (action === TOGGLE_NERD_FONT_ACTION3) {
69755
- return toggleNerdFont3(item);
70087
+ if (action === TOGGLE_NERD_FONT_ACTION4) {
70088
+ return toggleNerdFont4(item);
69756
70089
  }
69757
70090
  return null;
69758
70091
  }
69759
70092
  render(item, context, _settings) {
69760
- const format = getFormat3(item);
69761
- const nerdFont = isNerdFontEnabled3(item);
70093
+ const format = getFormat4(item);
70094
+ const nerdFont = isNerdFontEnabled4(item);
69762
70095
  if (context.isPreview) {
69763
- if (item.rawValue) {
69764
- return "on";
69765
- }
69766
- return formatStatus(true, format, nerdFont);
70096
+ return formatStatus2(true, format, nerdFont, item.rawValue ?? false);
69767
70097
  }
69768
70098
  const config2 = getVoiceConfig(resolveVoiceConfigCwd(context));
69769
70099
  if (config2 === null) {
69770
70100
  return null;
69771
70101
  }
69772
- if (item.rawValue) {
69773
- return config2.enabled ? "on" : "off";
69774
- }
69775
- return formatStatus(config2.enabled, format, nerdFont);
70102
+ return formatStatus2(config2.enabled, format, nerdFont, item.rawValue ?? false);
69776
70103
  }
69777
- getCustomKeybinds() {
69778
- return [
69779
- { key: "f", label: "(f)ormat", action: CYCLE_FORMAT_ACTION3 },
69780
- { key: "n", label: "(n)erd font", action: TOGGLE_NERD_FONT_ACTION3 }
70104
+ getCustomKeybinds(item) {
70105
+ const keybinds = [
70106
+ { key: "f", label: "(f)ormat", action: CYCLE_FORMAT_ACTION4 }
69781
70107
  ];
70108
+ if (item === undefined || canUseNerdFont3(item)) {
70109
+ keybinds.push({ key: "n", label: "(n)erd font", action: TOGGLE_NERD_FONT_ACTION4 });
70110
+ }
70111
+ return keybinds;
69782
70112
  }
69783
70113
  supportsRawValue() {
69784
70114
  return true;
@@ -69787,69 +70117,82 @@ class VoiceStatusWidget {
69787
70117
  return true;
69788
70118
  }
69789
70119
  }
69790
- var MIC_EMOJI = "\uD83C\uDFA4", MIC_NERD_FONT = "", MIC_SLASH_NERD_FONT = "", STATE_DOT_OFF = "○", STATE_DOT_ON = "◉", FORMATS3, DEFAULT_FORMAT3 = "icon", CYCLE_FORMAT_ACTION3 = "cycle-format", TOGGLE_NERD_FONT_ACTION3 = "toggle-nerd-font", NERD_FONT_METADATA_KEY3 = "nerdFont";
70120
+ var MIC_EMOJI = "\uD83C\uDFA4", MIC_NERD_FONT = "", MIC_SLASH_NERD_FONT = "", STATE_DOT_OFF = "○", STATE_DOT_ON = "◉", FORMATS4, DEFAULT_FORMAT4 = "icon", CYCLE_FORMAT_ACTION4 = "cycle-format", TOGGLE_NERD_FONT_ACTION4 = "toggle-nerd-font", NERD_FONT_METADATA_KEY4 = "nerdFont";
69791
70121
  var init_VoiceStatus = __esm(async () => {
69792
70122
  await init_claude_settings();
69793
- FORMATS3 = ["icon", "icon-text", "text", "word"];
70123
+ FORMATS4 = ["icon", "icon-text", "text", "word"];
69794
70124
  });
69795
70125
 
69796
70126
  // src/widgets/RemoteControlStatus.ts
69797
- function getFormat4(item) {
70127
+ function getFormat5(item) {
69798
70128
  const f = item.metadata?.format;
69799
- return FORMATS4.includes(f ?? "") ? f : DEFAULT_FORMAT4;
70129
+ return FORMATS5.includes(f ?? "") ? f : DEFAULT_FORMAT5;
69800
70130
  }
69801
- function setFormat4(item, format) {
69802
- if (format === DEFAULT_FORMAT4) {
70131
+ function canUseNerdFont4(item) {
70132
+ const format = getFormat5(item);
70133
+ return format === "icon" || format === "icon-text" && !item.rawValue;
70134
+ }
70135
+ function removeNerdFont5(item) {
70136
+ const { [NERD_FONT_METADATA_KEY5]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
70137
+ return {
70138
+ ...item,
70139
+ metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
70140
+ };
70141
+ }
70142
+ function setFormat5(item, format) {
70143
+ let updatedItem;
70144
+ if (format === DEFAULT_FORMAT5) {
69803
70145
  const { format: removedFormat, ...restMetadata } = item.metadata ?? {};
69804
- return {
70146
+ updatedItem = {
69805
70147
  ...item,
69806
70148
  metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69807
70149
  };
70150
+ } else {
70151
+ updatedItem = {
70152
+ ...item,
70153
+ metadata: {
70154
+ ...item.metadata ?? {},
70155
+ format
70156
+ }
70157
+ };
69808
70158
  }
69809
- return {
69810
- ...item,
69811
- metadata: {
69812
- ...item.metadata ?? {},
69813
- format
69814
- }
69815
- };
70159
+ return canUseNerdFont4(updatedItem) ? updatedItem : removeNerdFont5(updatedItem);
69816
70160
  }
69817
- function isNerdFontEnabled4(item) {
69818
- return item.metadata?.[NERD_FONT_METADATA_KEY4] === "true";
70161
+ function isNerdFontEnabled5(item) {
70162
+ return canUseNerdFont4(item) && item.metadata?.[NERD_FONT_METADATA_KEY5] === "true";
69819
70163
  }
69820
- function toggleNerdFont4(item) {
69821
- if (!isNerdFontEnabled4(item)) {
70164
+ function toggleNerdFont5(item) {
70165
+ if (!canUseNerdFont4(item)) {
70166
+ return removeNerdFont5(item);
70167
+ }
70168
+ if (!isNerdFontEnabled5(item)) {
69822
70169
  return {
69823
70170
  ...item,
69824
70171
  metadata: {
69825
70172
  ...item.metadata ?? {},
69826
- [NERD_FONT_METADATA_KEY4]: "true"
70173
+ [NERD_FONT_METADATA_KEY5]: "true"
69827
70174
  }
69828
70175
  };
69829
70176
  }
69830
- const { [NERD_FONT_METADATA_KEY4]: removedNerdFont, ...restMetadata } = item.metadata ?? {};
69831
- return {
69832
- ...item,
69833
- metadata: Object.keys(restMetadata).length > 0 ? restMetadata : undefined
69834
- };
70177
+ return removeNerdFont5(item);
69835
70178
  }
69836
- function formatStatus2(enabled, format, nerdFont) {
70179
+ function formatStatus3(enabled, format, nerdFont, rawValue) {
69837
70180
  const stateText = enabled ? "on" : "off";
69838
70181
  const stateDot = enabled ? STATE_DOT_ON2 : STATE_DOT_OFF2;
69839
70182
  const icon = nerdFont ? enabled ? SATELLITE_NERD_FONT : SATELLITE_SLASH_NERD_FONT : SATELLITE_EMOJI;
69840
70183
  switch (format) {
69841
70184
  case "icon":
69842
- return nerdFont ? icon : `${icon} ${stateDot}`;
70185
+ return nerdFont ? icon : rawValue ? stateDot : `${icon} ${stateDot}`;
69843
70186
  case "icon-text":
69844
- return `${icon} ${stateText}`;
70187
+ return rawValue ? stateText : `${icon} ${stateText}`;
69845
70188
  case "text":
69846
70189
  return stateText;
69847
70190
  case "word":
69848
- return `remote ${stateText}`;
70191
+ return rawValue ? stateText : `remote ${stateText}`;
69849
70192
  case "label-check":
69850
- return `remote ${enabled ? CHECK_EMOJI : CROSS_EMOJI}`;
70193
+ return rawValue ? enabled ? CHECK_EMOJI : CROSS_EMOJI : `remote ${enabled ? CHECK_EMOJI : CROSS_EMOJI}`;
69851
70194
  case "label-mark":
69852
- return `remote ${enabled ? CHECK_MARK : CROSS_MARK}`;
70195
+ return rawValue ? enabled ? CHECK_MARK : CROSS_MARK : `remote ${enabled ? CHECK_MARK : CROSS_MARK}`;
69853
70196
  }
69854
70197
  }
69855
70198
 
@@ -69867,8 +70210,8 @@ class RemoteControlStatusWidget {
69867
70210
  return "Core";
69868
70211
  }
69869
70212
  getEditorDisplay(item) {
69870
- const modifiers = [getFormat4(item)];
69871
- if (isNerdFontEnabled4(item)) {
70213
+ const modifiers = [getFormat5(item)];
70214
+ if (isNerdFontEnabled5(item)) {
69872
70215
  modifiers.push("nerd font");
69873
70216
  }
69874
70217
  return {
@@ -69877,40 +70220,246 @@ class RemoteControlStatusWidget {
69877
70220
  };
69878
70221
  }
69879
70222
  handleEditorAction(action, item) {
69880
- if (action === CYCLE_FORMAT_ACTION4) {
69881
- const currentFormat = getFormat4(item);
69882
- const nextFormat = FORMATS4[(FORMATS4.indexOf(currentFormat) + 1) % FORMATS4.length] ?? DEFAULT_FORMAT4;
69883
- return setFormat4(item, nextFormat);
70223
+ if (action === CYCLE_FORMAT_ACTION5) {
70224
+ const currentFormat = getFormat5(item);
70225
+ const nextFormat = FORMATS5[(FORMATS5.indexOf(currentFormat) + 1) % FORMATS5.length] ?? DEFAULT_FORMAT5;
70226
+ return setFormat5(item, nextFormat);
69884
70227
  }
69885
- if (action === TOGGLE_NERD_FONT_ACTION4) {
69886
- return toggleNerdFont4(item);
70228
+ if (action === TOGGLE_NERD_FONT_ACTION5) {
70229
+ return toggleNerdFont5(item);
69887
70230
  }
69888
70231
  return null;
69889
70232
  }
69890
70233
  render(item, context, _settings) {
69891
- const format = getFormat4(item);
69892
- const nerdFont = isNerdFontEnabled4(item);
70234
+ const format = getFormat5(item);
70235
+ const nerdFont = isNerdFontEnabled5(item);
69893
70236
  if (context.isPreview) {
69894
- if (item.rawValue) {
69895
- return "on";
69896
- }
69897
- return formatStatus2(true, format, nerdFont);
70237
+ return formatStatus3(true, format, nerdFont, item.rawValue ?? false);
69898
70238
  }
69899
70239
  const status = getRemoteControlStatus(context.data?.session_id);
69900
70240
  if (status === null) {
69901
70241
  return null;
69902
70242
  }
69903
- if (item.rawValue) {
69904
- return status.enabled ? "on" : "off";
70243
+ return formatStatus3(status.enabled, format, nerdFont, item.rawValue ?? false);
70244
+ }
70245
+ getCustomKeybinds(item) {
70246
+ const keybinds = [
70247
+ { key: "f", label: "(f)ormat", action: CYCLE_FORMAT_ACTION5 }
70248
+ ];
70249
+ if (item === undefined || canUseNerdFont4(item)) {
70250
+ keybinds.push({ key: "n", label: "(n)erd font", action: TOGGLE_NERD_FONT_ACTION5 });
70251
+ }
70252
+ return keybinds;
70253
+ }
70254
+ supportsRawValue() {
70255
+ return true;
70256
+ }
70257
+ supportsColors(_item) {
70258
+ return true;
70259
+ }
70260
+ }
70261
+ var SATELLITE_EMOJI = "\uD83D\uDCE1", SATELLITE_NERD_FONT = "", SATELLITE_SLASH_NERD_FONT = "", STATE_DOT_OFF2 = "○", STATE_DOT_ON2 = "◉", FORMATS5, CHECK_EMOJI = "✅", CROSS_EMOJI = "❌", CHECK_MARK = "✓", CROSS_MARK = "✗", DEFAULT_FORMAT5 = "icon", CYCLE_FORMAT_ACTION5 = "cycle-format", TOGGLE_NERD_FONT_ACTION5 = "toggle-nerd-font", NERD_FONT_METADATA_KEY5 = "nerdFont";
70262
+ var init_RemoteControlStatus = __esm(async () => {
70263
+ await init_claude_settings();
70264
+ FORMATS5 = ["icon", "icon-text", "text", "word", "label-check", "label-mark"];
70265
+ });
70266
+
70267
+ // src/widgets/CacheTimer.ts
70268
+ import * as fs12 from "fs";
70269
+ function hasCacheActivity(entry) {
70270
+ const usage = entry.message?.usage;
70271
+ if (!usage) {
70272
+ return true;
70273
+ }
70274
+ return (usage.cache_read_input_tokens ?? 0) + (usage.cache_creation_input_tokens ?? 0) > 0;
70275
+ }
70276
+ function readFileTail(filePath, bytes) {
70277
+ try {
70278
+ const fd = fs12.openSync(filePath, "r");
70279
+ try {
70280
+ const size2 = fs12.fstatSync(fd).size;
70281
+ const readSize = Math.min(bytes, size2);
70282
+ const buf = Buffer.alloc(readSize);
70283
+ fs12.readSync(fd, buf, 0, readSize, size2 - readSize);
70284
+ return { text: buf.toString("utf-8"), isComplete: readSize === size2 };
70285
+ } finally {
70286
+ fs12.closeSync(fd);
70287
+ }
70288
+ } catch {
70289
+ return null;
70290
+ }
70291
+ }
70292
+ function getTranscriptState(transcriptPath) {
70293
+ for (let bytes = INITIAL_TAIL_BYTES;; bytes *= 2) {
70294
+ const tail2 = readFileTail(transcriptPath, bytes);
70295
+ if (!tail2 || tail2.text.length === 0) {
70296
+ return { isWorking: false, lastAssistant: null };
70297
+ }
70298
+ const state = scanTailForState(tail2.text);
70299
+ if (state) {
70300
+ return state;
70301
+ }
70302
+ if (tail2.isComplete) {
70303
+ return { isWorking: false, lastAssistant: null };
70304
+ }
70305
+ }
70306
+ }
70307
+ function scanTailForState(tail2) {
70308
+ const lines = tail2.split(`
70309
+ `).reverse();
70310
+ let turnFinished = false;
70311
+ for (const line of lines) {
70312
+ const trimmed = line.trim();
70313
+ if (!trimmed) {
70314
+ continue;
69905
70315
  }
69906
- return formatStatus2(status.enabled, format, nerdFont);
70316
+ try {
70317
+ const entry = JSON.parse(trimmed);
70318
+ if (entry.isSidechain === true) {
70319
+ continue;
70320
+ }
70321
+ if (entry.type === "assistant") {
70322
+ turnFinished = true;
70323
+ if (entry.isApiErrorMessage !== true && hasCacheActivity(entry) && entry.timestamp) {
70324
+ const parsed = new Date(entry.timestamp);
70325
+ if (!Number.isNaN(parsed.getTime())) {
70326
+ return { isWorking: false, lastAssistant: parsed };
70327
+ }
70328
+ }
70329
+ continue;
70330
+ }
70331
+ if (entry.type === "user" && !turnFinished) {
70332
+ return { isWorking: true };
70333
+ }
70334
+ } catch {
70335
+ continue;
70336
+ }
70337
+ }
70338
+ return null;
70339
+ }
70340
+ function getTtlSeconds(item) {
70341
+ const raw = item.metadata?.[TTL_METADATA_KEY];
70342
+ if (raw === undefined) {
70343
+ return DEFAULT_TTL_SECONDS;
70344
+ }
70345
+ const parsed = Number.parseInt(raw, 10);
70346
+ return Number.isFinite(parsed) && parsed > SAFETY_MARGIN ? parsed : DEFAULT_TTL_SECONDS;
70347
+ }
70348
+ function cycleTtl(item) {
70349
+ const current = getTtlSeconds(item);
70350
+ const index = TTL_OPTIONS.indexOf(current);
70351
+ const next = TTL_OPTIONS[(index + 1) % TTL_OPTIONS.length] ?? DEFAULT_TTL_SECONDS;
70352
+ if (next === DEFAULT_TTL_SECONDS) {
70353
+ return removeMetadataKeys(item, [TTL_METADATA_KEY]);
70354
+ }
70355
+ return {
70356
+ ...item,
70357
+ metadata: {
70358
+ ...item.metadata,
70359
+ [TTL_METADATA_KEY]: String(next)
70360
+ }
70361
+ };
70362
+ }
70363
+ function formatTtlLabel(ttlSeconds) {
70364
+ return ttlSeconds % 3600 === 0 ? `${ttlSeconds / 3600}h` : `${Math.round(ttlSeconds / 60)}m`;
70365
+ }
70366
+ function getRemainingSeconds(lastAssistant, ttlSeconds) {
70367
+ const elapsedSeconds = (Date.now() - lastAssistant.getTime()) / 1000;
70368
+ return ttlSeconds - SAFETY_MARGIN - elapsedSeconds;
70369
+ }
70370
+ function formatCountdown(remaining) {
70371
+ if (remaining <= 0) {
70372
+ return "COLD";
70373
+ }
70374
+ const m = Math.floor(remaining / 60);
70375
+ const s = Math.floor(remaining % 60);
70376
+ return `${m}:${s.toString().padStart(2, "0")}`;
70377
+ }
70378
+ function getStateSymbol(item, remaining, ttlSeconds) {
70379
+ if (remaining <= 0) {
70380
+ return getSlotSymbol(item, COLD_SLOT);
70381
+ }
70382
+ const pct = remaining / (ttlSeconds - SAFETY_MARGIN);
70383
+ if (pct > 0.5) {
70384
+ return getSlotSymbol(item, FRESH_SLOT);
70385
+ }
70386
+ if (pct > 0.2) {
70387
+ return getSlotSymbol(item, DRAINING_SLOT);
70388
+ }
70389
+ return getSlotSymbol(item, URGENT_SLOT);
70390
+ }
70391
+ function withGlyph(symbol2, text) {
70392
+ return symbol2.length > 0 ? `${symbol2} ${text}` : text;
70393
+ }
70394
+
70395
+ class CacheTimerWidget {
70396
+ getDefaultColor() {
70397
+ return "brightCyan";
70398
+ }
70399
+ getDescription() {
70400
+ return "Shows time remaining on the prompt cache TTL (5m by default, 1h configurable)";
70401
+ }
70402
+ getDisplayName() {
70403
+ return "Cache Timer";
70404
+ }
70405
+ getCategory() {
70406
+ return "Session";
70407
+ }
70408
+ getEditorDisplay(item) {
70409
+ const modifiers = [];
70410
+ const ttlSeconds = getTtlSeconds(item);
70411
+ if (ttlSeconds !== DEFAULT_TTL_SECONDS) {
70412
+ modifiers.push(`ttl ${formatTtlLabel(ttlSeconds)}`);
70413
+ }
70414
+ if (isMetadataFlagEnabled(item, HIDE_WHEN_EMPTY_KEY3)) {
70415
+ modifiers.push("hide when empty");
70416
+ }
70417
+ return {
70418
+ displayText: this.getDisplayName(),
70419
+ modifierText: makeModifierText(modifiers)
70420
+ };
70421
+ }
70422
+ handleEditorAction(action, item) {
70423
+ if (action === TOGGLE_HIDE_ACTION2) {
70424
+ return toggleMetadataFlag(item, HIDE_WHEN_EMPTY_KEY3);
70425
+ }
70426
+ if (action === TOGGLE_TTL_ACTION) {
70427
+ return cycleTtl(item);
70428
+ }
70429
+ return null;
70430
+ }
70431
+ render(item, context, _settings) {
70432
+ const hideWhenEmpty = isMetadataFlagEnabled(item, HIDE_WHEN_EMPTY_KEY3);
70433
+ if (context.isPreview) {
70434
+ return formatRawOrLabeledValue(item, "Cache: ", withGlyph(getSlotSymbol(item, FRESH_SLOT), "4:52"));
70435
+ }
70436
+ const transcriptPath = context.data?.transcript_path;
70437
+ if (!transcriptPath) {
70438
+ return hideWhenEmpty ? null : formatRawOrLabeledValue(item, "Cache: ", "n/a");
70439
+ }
70440
+ const state = getTranscriptState(transcriptPath);
70441
+ if (state.isWorking) {
70442
+ return formatRawOrLabeledValue(item, "Cache: ", withGlyph(getSlotSymbol(item, HOT_SLOT), "HOT"));
70443
+ }
70444
+ const { lastAssistant } = state;
70445
+ if (!lastAssistant) {
70446
+ return hideWhenEmpty ? null : formatRawOrLabeledValue(item, "Cache: ", "n/a");
70447
+ }
70448
+ const ttlSeconds = getTtlSeconds(item);
70449
+ const remaining = getRemainingSeconds(lastAssistant, ttlSeconds);
70450
+ const glyph = getStateSymbol(item, remaining, ttlSeconds);
70451
+ return formatRawOrLabeledValue(item, "Cache: ", withGlyph(glyph, formatCountdown(remaining)));
69907
70452
  }
69908
70453
  getCustomKeybinds() {
69909
70454
  return [
69910
- { key: "f", label: "(f)ormat", action: CYCLE_FORMAT_ACTION4 },
69911
- { key: "n", label: "(n)erd font", action: TOGGLE_NERD_FONT_ACTION4 }
70455
+ { key: "t", label: "(t)tl", action: TOGGLE_TTL_ACTION },
70456
+ { key: "h", label: "(h)ide when empty", action: TOGGLE_HIDE_ACTION2 },
70457
+ getSymbolKeybind()
69912
70458
  ];
69913
70459
  }
70460
+ renderEditor(props) {
70461
+ return renderSymbolSlotsEditor(props, SYMBOL_SLOTS);
70462
+ }
69914
70463
  supportsRawValue() {
69915
70464
  return true;
69916
70465
  }
@@ -69918,10 +70467,16 @@ class RemoteControlStatusWidget {
69918
70467
  return true;
69919
70468
  }
69920
70469
  }
69921
- var SATELLITE_EMOJI = "\uD83D\uDCE1", SATELLITE_NERD_FONT = "", SATELLITE_SLASH_NERD_FONT = "", STATE_DOT_OFF2 = "○", STATE_DOT_ON2 = "◉", FORMATS4, CHECK_EMOJI = "", CROSS_EMOJI = "❌", CHECK_MARK = "✓", CROSS_MARK = "✗", DEFAULT_FORMAT4 = "icon", CYCLE_FORMAT_ACTION4 = "cycle-format", TOGGLE_NERD_FONT_ACTION4 = "toggle-nerd-font", NERD_FONT_METADATA_KEY4 = "nerdFont";
69922
- var init_RemoteControlStatus = __esm(async () => {
69923
- await init_claude_settings();
69924
- FORMATS4 = ["icon", "icon-text", "text", "word", "label-check", "label-mark"];
70470
+ var HIDE_WHEN_EMPTY_KEY3 = "hideWhenEmpty", TOGGLE_HIDE_ACTION2 = "toggle-hide", TTL_METADATA_KEY = "ttlSeconds", DEFAULT_TTL_SECONDS = 300, TTL_OPTIONS, TOGGLE_TTL_ACTION = "toggle-ttl", SAFETY_MARGIN = 5, HOT_SLOT, FRESH_SLOT, DRAINING_SLOT, URGENT_SLOT, COLD_SLOT, SYMBOL_SLOTS, INITIAL_TAIL_BYTES = 32768;
70471
+ var init_CacheTimer = __esm(async () => {
70472
+ await init_symbol_override();
70473
+ TTL_OPTIONS = [300, 3600];
70474
+ HOT_SLOT = { id: "symbolHot", label: "Working", defaultSymbol: "\uD83D\uDD25" };
70475
+ FRESH_SLOT = { id: "symbolFresh", label: "Fresh", defaultSymbol: "\uD83D\uDFE2" };
70476
+ DRAINING_SLOT = { id: "symbolDraining", label: "Draining", defaultSymbol: "\uD83D\uDFE1" };
70477
+ URGENT_SLOT = { id: "symbolUrgent", label: "Urgent", defaultSymbol: "\uD83D\uDD34" };
70478
+ COLD_SLOT = { id: "symbolCold", label: "Cold", defaultSymbol: "❄️" };
70479
+ SYMBOL_SLOTS = [HOT_SLOT, FRESH_SLOT, DRAINING_SLOT, URGENT_SLOT, COLD_SLOT];
69925
70480
  });
69926
70481
 
69927
70482
  // src/widgets/index.ts
@@ -69932,6 +70487,7 @@ var init_widgets = __esm(async () => {
69932
70487
  init_GitStagedFiles();
69933
70488
  init_GitUnstagedFiles();
69934
70489
  init_GitUntrackedFiles();
70490
+ init_GitCiStatus();
69935
70491
  init_GitCleanStatus();
69936
70492
  init_GitPr();
69937
70493
  init_GitSha();
@@ -69999,8 +70555,10 @@ var init_widgets = __esm(async () => {
69999
70555
  init_ThinkingEffort(),
70000
70556
  init_GitWorktreeMode(),
70001
70557
  init_CompactionCounter(),
70558
+ init_SandboxStatus(),
70002
70559
  init_VoiceStatus(),
70003
- init_RemoteControlStatus()
70560
+ init_RemoteControlStatus(),
70561
+ init_CacheTimer()
70004
70562
  ]);
70005
70563
  });
70006
70564
 
@@ -70021,6 +70579,7 @@ var init_widget_manifest = __esm(async () => {
70021
70579
  { type: "git-clean-status", create: () => new GitCleanStatusWidget },
70022
70580
  { type: "git-root-dir", create: () => new GitRootDirWidget },
70023
70581
  { type: "git-review", create: () => new GitPrWidget },
70582
+ { type: "git-ci-status", create: () => new GitCiStatusWidget },
70024
70583
  { type: "git-worktree", create: () => new GitWorktreeWidget },
70025
70584
  { type: "git-status", create: () => new GitStatusWidget },
70026
70585
  { type: "git-staged", create: () => new GitStagedWidget },
@@ -70070,6 +70629,7 @@ var init_widget_manifest = __esm(async () => {
70070
70629
  { type: "link", create: () => new LinkWidget },
70071
70630
  { type: "claude-session-id", create: () => new ClaudeSessionIdWidget },
70072
70631
  { type: "claude-account-email", create: () => new ClaudeAccountEmailWidget },
70632
+ { type: "sandbox-status", create: () => new SandboxStatusWidget },
70073
70633
  { type: "session-name", create: () => new SessionNameWidget },
70074
70634
  { type: "free-memory", create: () => new FreeMemoryWidget },
70075
70635
  { type: "session-usage", create: () => new SessionUsageWidget },
@@ -70091,7 +70651,8 @@ var init_widget_manifest = __esm(async () => {
70091
70651
  { type: "worktree-name", create: () => new GitWorktreeNameWidget },
70092
70652
  { type: "worktree-branch", create: () => new GitWorktreeBranchWidget },
70093
70653
  { type: "worktree-original-branch", create: () => new GitWorktreeOriginalBranchWidget },
70094
- { type: "compaction-counter", create: () => new CompactionCounterWidget }
70654
+ { type: "compaction-counter", create: () => new CompactionCounterWidget },
70655
+ { type: "cache-timer", create: () => new CacheTimerWidget }
70095
70656
  ];
70096
70657
  LAYOUT_WIDGET_MANIFEST = [
70097
70658
  {
@@ -70295,7 +70856,7 @@ var init_hooks = __esm(async () => {
70295
70856
  });
70296
70857
 
70297
70858
  // src/utils/config.ts
70298
- import * as fs12 from "fs";
70859
+ import * as fs13 from "fs";
70299
70860
  import * as os9 from "os";
70300
70861
  import * as path8 from "path";
70301
70862
  function getConfigLoadError() {
@@ -70385,7 +70946,7 @@ async function loadSettings() {
70385
70946
  lastLoadError = null;
70386
70947
  const paths = getSettingsPaths();
70387
70948
  try {
70388
- if (!fs12.existsSync(paths.settingsPath))
70949
+ if (!fs13.existsSync(paths.settingsPath))
70389
70950
  return await writeDefaultSettings(paths);
70390
70951
  const content = await readFile3(paths.settingsPath, "utf-8");
70391
70952
  let rawData;
@@ -70444,7 +71005,7 @@ async function saveSettings(settings) {
70444
71005
  }
70445
71006
  async function saveInstallationMetadata(metadata) {
70446
71007
  const paths = getSettingsPaths();
70447
- if (!metadata && !fs12.existsSync(paths.settingsPath)) {
71008
+ if (!metadata && !fs13.existsSync(paths.settingsPath)) {
70448
71009
  return;
70449
71010
  }
70450
71011
  const settings = await loadSettings();
@@ -70468,21 +71029,21 @@ var init_config = __esm(async () => {
70468
71029
  init_Settings();
70469
71030
  init_migrations();
70470
71031
  await init_widgets2();
70471
- readFile3 = fs12.promises.readFile;
70472
- writeFile = fs12.promises.writeFile;
70473
- mkdir = fs12.promises.mkdir;
70474
- rename = fs12.promises.rename;
70475
- unlink = fs12.promises.unlink;
70476
- lstat = fs12.promises.lstat;
70477
- readlink = fs12.promises.readlink;
70478
- realpath2 = fs12.promises.realpath;
71032
+ readFile3 = fs13.promises.readFile;
71033
+ writeFile = fs13.promises.writeFile;
71034
+ mkdir = fs13.promises.mkdir;
71035
+ rename = fs13.promises.rename;
71036
+ unlink = fs13.promises.unlink;
71037
+ lstat = fs13.promises.lstat;
71038
+ readlink = fs13.promises.readlink;
71039
+ realpath2 = fs13.promises.realpath;
70479
71040
  DEFAULT_SETTINGS_PATH = path8.join(os9.homedir(), ".config", "ccstatusline", "settings.json");
70480
71041
  settingsPath = DEFAULT_SETTINGS_PATH;
70481
71042
  });
70482
71043
 
70483
71044
  // src/utils/claude-settings.ts
70484
71045
  import { execSync as execSync4 } from "child_process";
70485
- import * as fs13 from "fs";
71046
+ import * as fs14 from "fs";
70486
71047
  import * as os10 from "os";
70487
71048
  import * as path9 from "path";
70488
71049
  function isKnownCommand(command) {
@@ -70509,8 +71070,8 @@ function getClaudeConfigDir() {
70509
71070
  if (envConfigDir) {
70510
71071
  try {
70511
71072
  const resolvedPath = path9.resolve(envConfigDir);
70512
- if (fs13.existsSync(resolvedPath)) {
70513
- const stats = fs13.statSync(resolvedPath);
71073
+ if (fs14.existsSync(resolvedPath)) {
71074
+ const stats = fs14.statSync(resolvedPath);
70514
71075
  if (stats.isDirectory()) {
70515
71076
  return resolvedPath;
70516
71077
  }
@@ -70536,7 +71097,7 @@ async function backupClaudeSettings(suffix = ".bak") {
70536
71097
  const settingsPath2 = getClaudeSettingsPath();
70537
71098
  const backupPath = settingsPath2 + suffix;
70538
71099
  try {
70539
- if (fs13.existsSync(settingsPath2)) {
71100
+ if (fs14.existsSync(settingsPath2)) {
70540
71101
  const content = await readFile4(settingsPath2, "utf-8");
70541
71102
  await writeFile2(backupPath, content, "utf-8");
70542
71103
  return backupPath;
@@ -70549,11 +71110,11 @@ async function backupClaudeSettings(suffix = ".bak") {
70549
71110
  function loadClaudeSettingsSync(options = {}) {
70550
71111
  const { logErrors = true } = options;
70551
71112
  const settingsPath2 = getClaudeSettingsPath();
70552
- if (!fs13.existsSync(settingsPath2)) {
71113
+ if (!fs14.existsSync(settingsPath2)) {
70553
71114
  return {};
70554
71115
  }
70555
71116
  try {
70556
- const content = fs13.readFileSync(settingsPath2, "utf-8");
71117
+ const content = fs14.readFileSync(settingsPath2, "utf-8");
70557
71118
  return JSON.parse(content);
70558
71119
  } catch (error51) {
70559
71120
  if (logErrors) {
@@ -70565,7 +71126,7 @@ function loadClaudeSettingsSync(options = {}) {
70565
71126
  async function loadClaudeSettings(options = {}) {
70566
71127
  const { logErrors = true } = options;
70567
71128
  const settingsPath2 = getClaudeSettingsPath();
70568
- if (!fs13.existsSync(settingsPath2)) {
71129
+ if (!fs14.existsSync(settingsPath2)) {
70569
71130
  return {};
70570
71131
  }
70571
71132
  try {
@@ -70718,7 +71279,7 @@ function classifyInstallation(command, metadata) {
70718
71279
  }
70719
71280
  async function loadSavedSettingsForHookSync() {
70720
71281
  const configPath = getConfigPath();
70721
- if (!fs13.existsSync(configPath)) {
71282
+ if (!fs14.existsSync(configPath)) {
70722
71283
  return null;
70723
71284
  }
70724
71285
  try {
@@ -70817,7 +71378,7 @@ async function setRefreshInterval(interval) {
70817
71378
  }
70818
71379
  await saveClaudeSettings(settings);
70819
71380
  }
70820
- function getVoiceConfigCandidatePathsByPriority(cwd2) {
71381
+ function getLayeredSettingsCandidatePathsByPriority(cwd2) {
70821
71382
  const userDir = getClaudeConfigDir();
70822
71383
  const projectDir = path9.join(cwd2, ".claude");
70823
71384
  const candidates = [
@@ -70831,7 +71392,7 @@ function getVoiceConfigCandidatePathsByPriority(cwd2) {
70831
71392
  function tryReadVoiceLayer(filePath) {
70832
71393
  let content;
70833
71394
  try {
70834
- content = fs13.readFileSync(filePath, "utf-8");
71395
+ content = fs14.readFileSync(filePath, "utf-8");
70835
71396
  } catch (error51) {
70836
71397
  const isMissing = error51.code === "ENOENT";
70837
71398
  return { fileExisted: !isMissing, enabled: undefined };
@@ -70850,7 +71411,7 @@ function tryReadVoiceLayer(filePath) {
70850
71411
  }
70851
71412
  function getVoiceConfig(cwd2 = process.cwd()) {
70852
71413
  let anyFileExisted = false;
70853
- for (const filePath of getVoiceConfigCandidatePathsByPriority(cwd2)) {
71414
+ for (const filePath of getLayeredSettingsCandidatePathsByPriority(cwd2)) {
70854
71415
  const layer = tryReadVoiceLayer(filePath);
70855
71416
  if (layer.fileExisted) {
70856
71417
  anyFileExisted = true;
@@ -70861,6 +71422,39 @@ function getVoiceConfig(cwd2 = process.cwd()) {
70861
71422
  }
70862
71423
  return anyFileExisted ? { enabled: false } : null;
70863
71424
  }
71425
+ function tryReadSandboxLayer(filePath) {
71426
+ let content;
71427
+ try {
71428
+ content = fs14.readFileSync(filePath, "utf-8");
71429
+ } catch (error51) {
71430
+ const isMissing = error51.code === "ENOENT";
71431
+ return { fileExisted: !isMissing, enabled: undefined };
71432
+ }
71433
+ try {
71434
+ const parsed = JSON.parse(content);
71435
+ const sandbox = parsed.sandbox;
71436
+ if (sandbox === undefined || sandbox === null) {
71437
+ return { fileExisted: true, enabled: undefined };
71438
+ }
71439
+ const result2 = SandboxConfigSchema.safeParse(sandbox);
71440
+ return { fileExisted: true, enabled: result2.success ? result2.data.enabled : undefined };
71441
+ } catch {
71442
+ return { fileExisted: true, enabled: undefined };
71443
+ }
71444
+ }
71445
+ function getSandboxConfig(cwd2 = process.cwd()) {
71446
+ let anyFileExisted = false;
71447
+ for (const filePath of getLayeredSettingsCandidatePathsByPriority(cwd2)) {
71448
+ const layer = tryReadSandboxLayer(filePath);
71449
+ if (layer.fileExisted) {
71450
+ anyFileExisted = true;
71451
+ }
71452
+ if (layer.enabled !== undefined) {
71453
+ return { enabled: layer.enabled };
71454
+ }
71455
+ }
71456
+ return anyFileExisted ? { enabled: false } : null;
71457
+ }
70864
71458
  function getRemoteControlStatus(sessionId) {
70865
71459
  if (!sessionId) {
70866
71460
  return null;
@@ -70868,7 +71462,7 @@ function getRemoteControlStatus(sessionId) {
70868
71462
  const sessionsDir = path9.join(getClaudeConfigDir(), "sessions");
70869
71463
  let entries;
70870
71464
  try {
70871
- entries = fs13.readdirSync(sessionsDir);
71465
+ entries = fs14.readdirSync(sessionsDir);
70872
71466
  } catch {
70873
71467
  return null;
70874
71468
  }
@@ -70878,7 +71472,7 @@ function getRemoteControlStatus(sessionId) {
70878
71472
  }
70879
71473
  let content;
70880
71474
  try {
70881
- content = fs13.readFileSync(path9.join(sessionsDir, entry), "utf-8");
71475
+ content = fs14.readFileSync(path9.join(sessionsDir, entry), "utf-8");
70882
71476
  } catch {
70883
71477
  continue;
70884
71478
  }
@@ -70897,14 +71491,14 @@ function getRemoteControlStatus(sessionId) {
70897
71491
  }
70898
71492
  return null;
70899
71493
  }
70900
- var readFile4, writeFile2, mkdir2, CCSTATUSLINE_COMMANDS, PINNED_INSTALL_COMMANDS, VoiceConfigSchema, RemoteSessionFileSchema;
71494
+ var readFile4, writeFile2, mkdir2, CCSTATUSLINE_COMMANDS, PINNED_INSTALL_COMMANDS, VoiceConfigSchema, SandboxConfigSchema, RemoteSessionFileSchema;
70901
71495
  var init_claude_settings = __esm(async () => {
70902
71496
  init_zod();
70903
71497
  init_Settings();
70904
71498
  await init_config();
70905
- readFile4 = fs13.promises.readFile;
70906
- writeFile2 = fs13.promises.writeFile;
70907
- mkdir2 = fs13.promises.mkdir;
71499
+ readFile4 = fs14.promises.readFile;
71500
+ writeFile2 = fs14.promises.writeFile;
71501
+ mkdir2 = fs14.promises.mkdir;
70908
71502
  CCSTATUSLINE_COMMANDS = {
70909
71503
  AUTO_NPX: "npx -y ccstatusline@latest",
70910
71504
  AUTO_BUNX: "bunx -y ccstatusline@latest",
@@ -70918,6 +71512,7 @@ var init_claude_settings = __esm(async () => {
70918
71512
  BUN: (version2) => `bun add -g ccstatusline@${version2}`
70919
71513
  };
70920
71514
  VoiceConfigSchema = exports_external.object({ enabled: exports_external.boolean().optional() });
71515
+ SandboxConfigSchema = exports_external.object({ enabled: exports_external.boolean().optional() });
70921
71516
  RemoteSessionFileSchema = exports_external.object({
70922
71517
  sessionId: exports_external.string().optional(),
70923
71518
  bridgeSessionId: exports_external.string().nullable().optional()
@@ -71678,7 +72273,7 @@ import {
71678
72273
  execFile,
71679
72274
  execFileSync as execFileSync6
71680
72275
  } from "child_process";
71681
- import * as fs14 from "fs";
72276
+ import * as fs15 from "fs";
71682
72277
  var GLOBAL_PACKAGE_TIMEOUT_MS = 120000;
71683
72278
  var VERSION_LOOKUP_TIMEOUT_MS = 5000;
71684
72279
  var WINDOWS_SHIM_EXTENSIONS = [
@@ -71727,7 +72322,7 @@ function getBinaryPathCandidates(binDir, platform2) {
71727
72322
  return extensions.map((extension) => appendPathSegment(binDir, `ccstatusline${extension}`));
71728
72323
  }
71729
72324
  function hasBinaryOnDisk(binDir, platform2) {
71730
- return getBinaryPathCandidates(binDir, platform2).some((candidate) => getFilesystemPathVariants(candidate).some((variant) => fs14.existsSync(variant)));
72325
+ return getBinaryPathCandidates(binDir, platform2).some((candidate) => getFilesystemPathVariants(candidate).some((variant) => fs15.existsSync(variant)));
71731
72326
  }
71732
72327
  function hasResolvedBinaryInDir(resolvedPaths, binDir) {
71733
72328
  return resolvedPaths.some((resolvedPath) => isPathInsideDir(resolvedPath, binDir));
@@ -71760,10 +72355,10 @@ function formatPathList2(paths) {
71760
72355
  function readPackageVersion(packageJsonPath) {
71761
72356
  for (const variant of getFilesystemPathVariants(packageJsonPath)) {
71762
72357
  try {
71763
- if (!fs14.existsSync(variant)) {
72358
+ if (!fs15.existsSync(variant)) {
71764
72359
  continue;
71765
72360
  }
71766
- const packageJson = JSON.parse(fs14.readFileSync(variant, "utf-8"));
72361
+ const packageJson = JSON.parse(fs15.readFileSync(variant, "utf-8"));
71767
72362
  return typeof packageJson.version === "string" ? packageJson.version : null;
71768
72363
  } catch {
71769
72364
  return null;
@@ -71989,7 +72584,7 @@ function openExternalUrl(url2) {
71989
72584
 
71990
72585
  // src/utils/powerline.ts
71991
72586
  import { execSync as execSync5 } from "child_process";
71992
- import * as fs15 from "fs";
72587
+ import * as fs16 from "fs";
71993
72588
  import * as os12 from "os";
71994
72589
  import * as path11 from "path";
71995
72590
  var fontsInstalledThisSession = false;
@@ -72040,9 +72635,9 @@ function checkPowerlineFonts() {
72040
72635
  /fira.*code.*nerd/i
72041
72636
  ];
72042
72637
  for (const fontPath of fontPaths) {
72043
- if (fs15.existsSync(fontPath)) {
72638
+ if (fs16.existsSync(fontPath)) {
72044
72639
  try {
72045
- const files = fs15.readdirSync(fontPath);
72640
+ const files = fs16.readdirSync(fontPath);
72046
72641
  for (const file2 of files) {
72047
72642
  for (const pattern of powerlineFontPatterns) {
72048
72643
  if (pattern.test(file2)) {
@@ -72117,13 +72712,13 @@ async function installPowerlineFonts() {
72117
72712
  message: "Unsupported platform for font installation"
72118
72713
  };
72119
72714
  }
72120
- if (!fs15.existsSync(fontDir)) {
72121
- fs15.mkdirSync(fontDir, { recursive: true });
72715
+ if (!fs16.existsSync(fontDir)) {
72716
+ fs16.mkdirSync(fontDir, { recursive: true });
72122
72717
  }
72123
72718
  const tempDir = path11.join(os12.tmpdir(), `ccstatusline-powerline-fonts-${Date.now()}`);
72124
72719
  try {
72125
- if (fs15.existsSync(tempDir)) {
72126
- fs15.rmSync(tempDir, { recursive: true, force: true });
72720
+ if (fs16.existsSync(tempDir)) {
72721
+ fs16.rmSync(tempDir, { recursive: true, force: true });
72127
72722
  }
72128
72723
  execSync5(`git clone --depth=1 https://github.com/powerline/fonts.git "${tempDir}"`, {
72129
72724
  stdio: "pipe",
@@ -72132,8 +72727,8 @@ async function installPowerlineFonts() {
72132
72727
  });
72133
72728
  if (platform4 === "darwin" || platform4 === "linux") {
72134
72729
  const installScript = path11.join(tempDir, "install.sh");
72135
- if (fs15.existsSync(installScript)) {
72136
- fs15.chmodSync(installScript, 493);
72730
+ if (fs16.existsSync(installScript)) {
72731
+ fs16.chmodSync(installScript, 493);
72137
72732
  execSync5(`cd "${tempDir}" && ./install.sh`, {
72138
72733
  stdio: "pipe",
72139
72734
  encoding: "utf8",
@@ -72161,10 +72756,10 @@ async function installPowerlineFonts() {
72161
72756
  }
72162
72757
  } else {
72163
72758
  let findFontFiles = function(dir) {
72164
- const files = fs15.readdirSync(dir);
72759
+ const files = fs16.readdirSync(dir);
72165
72760
  for (const file2 of files) {
72166
72761
  const filePath = path11.join(dir, file2);
72167
- const stat2 = fs15.statSync(filePath);
72762
+ const stat2 = fs16.statSync(filePath);
72168
72763
  if (stat2.isDirectory() && !file2.startsWith(".")) {
72169
72764
  findFontFiles(filePath);
72170
72765
  } else if (file2.endsWith(".ttf") || file2.endsWith(".otf")) {
@@ -72181,7 +72776,7 @@ async function installPowerlineFonts() {
72181
72776
  const fileName = path11.basename(fontFile);
72182
72777
  const destPath = path11.join(fontDir, fileName);
72183
72778
  try {
72184
- fs15.copyFileSync(fontFile, destPath);
72779
+ fs16.copyFileSync(fontFile, destPath);
72185
72780
  installedCount++;
72186
72781
  } catch {}
72187
72782
  }
@@ -72199,9 +72794,9 @@ async function installPowerlineFonts() {
72199
72794
  message: "Platform-specific installation not implemented"
72200
72795
  };
72201
72796
  } finally {
72202
- if (fs15.existsSync(tempDir)) {
72797
+ if (fs16.existsSync(tempDir)) {
72203
72798
  try {
72204
- fs15.rmSync(tempDir, { recursive: true, force: true });
72799
+ fs16.rmSync(tempDir, { recursive: true, force: true });
72205
72800
  } catch {}
72206
72801
  }
72207
72802
  }
@@ -73819,6 +74414,7 @@ var ColorMenu = ({ widgets, lineIndex, settings, onUpdate, onBack }) => {
73819
74414
  };
73820
74415
  // src/tui/components/GlobalOverridesMenu.tsx
73821
74416
  init_ColorLevel();
74417
+ init_Settings();
73822
74418
  init_colors();
73823
74419
  init_gradient();
73824
74420
  init_input_guards();
@@ -74005,6 +74601,15 @@ var GlobalOverridesMenu = ({ settings, onUpdate, onBack }) => {
74005
74601
  overrideForegroundColor: undefined
74006
74602
  };
74007
74603
  onUpdate(updatedSettings);
74604
+ } else if (input === "d" || input === "D") {
74605
+ const paddingSides = DefaultPaddingSideSchema.options;
74606
+ const currentIndex = paddingSides.indexOf(settings.defaultPaddingSide);
74607
+ const nextSide = paddingSides[(currentIndex + 1) % paddingSides.length] ?? "both";
74608
+ const updatedSettings = {
74609
+ ...settings,
74610
+ defaultPaddingSide: nextSide
74611
+ };
74612
+ onUpdate(updatedSettings);
74008
74613
  }
74009
74614
  }
74010
74615
  });
@@ -74116,7 +74721,7 @@ var GlobalOverridesMenu = ({ settings, onUpdate, onBack }) => {
74116
74721
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
74117
74722
  children: [
74118
74723
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
74119
- children: "Enter default padding (applied to left and right of each widget): "
74724
+ children: "Enter default padding (applied per the Padding Side setting): "
74120
74725
  }, undefined, false, undefined, this),
74121
74726
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
74122
74727
  color: "cyan",
@@ -74242,6 +74847,21 @@ var GlobalOverridesMenu = ({ settings, onUpdate, onBack }) => {
74242
74847
  }, undefined, false, undefined, this)
74243
74848
  ]
74244
74849
  }, undefined, true, undefined, this),
74850
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
74851
+ children: [
74852
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
74853
+ children: " Padding Side: "
74854
+ }, undefined, false, undefined, this),
74855
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
74856
+ color: "cyan",
74857
+ children: settings.defaultPaddingSide === "left" ? "Left only" : settings.defaultPaddingSide === "right" ? "Right only" : "Both"
74858
+ }, undefined, false, undefined, this),
74859
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
74860
+ dimColor: true,
74861
+ children: " - Press (d) to cycle"
74862
+ }, undefined, false, undefined, this)
74863
+ ]
74864
+ }, undefined, true, undefined, this),
74245
74865
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Box_default, {
74246
74866
  children: [
74247
74867
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
@@ -74370,6 +74990,11 @@ var GlobalOverridesMenu = ({ settings, onUpdate, onBack }) => {
74370
74990
  wrap: "wrap",
74371
74991
  children: "Note: These settings are applied during rendering and don't add widgets to your widget list."
74372
74992
  }, undefined, false, undefined, this),
74993
+ /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
74994
+ dimColor: true,
74995
+ wrap: "wrap",
74996
+ children: "• Padding Side: Choose whether default padding applies to both sides, left only, or right only"
74997
+ }, undefined, false, undefined, this),
74373
74998
  /* @__PURE__ */ jsx_dev_runtime15.jsxDEV(Text, {
74374
74999
  dimColor: true,
74375
75000
  wrap: "wrap",
@@ -79303,11 +79928,11 @@ init_compaction();
79303
79928
  await init_config();
79304
79929
 
79305
79930
  // src/utils/hook-handler.ts
79306
- import * as fs17 from "fs";
79931
+ import * as fs18 from "fs";
79307
79932
  import * as path13 from "path";
79308
79933
 
79309
79934
  // src/utils/skills.ts
79310
- import * as fs16 from "fs";
79935
+ import * as fs17 from "fs";
79311
79936
  import * as os14 from "os";
79312
79937
  import * as path12 from "path";
79313
79938
  var EMPTY = { totalInvocations: 0, uniqueSkills: [], lastSkill: null };
@@ -79319,11 +79944,11 @@ function getSkillsFilePath(sessionId) {
79319
79944
  }
79320
79945
  function getSkillsMetrics(sessionId) {
79321
79946
  const filePath = getSkillsFilePath(sessionId);
79322
- if (!fs16.existsSync(filePath)) {
79947
+ if (!fs17.existsSync(filePath)) {
79323
79948
  return EMPTY;
79324
79949
  }
79325
79950
  try {
79326
- const invocations = fs16.readFileSync(filePath, "utf-8").trim().split(`
79951
+ const invocations = fs17.readFileSync(filePath, "utf-8").trim().split(`
79327
79952
  `).filter((line) => line.trim()).map((line) => {
79328
79953
  try {
79329
79954
  return JSON.parse(line);
@@ -79377,14 +80002,14 @@ function handleHookInput(input) {
79377
80002
  return;
79378
80003
  }
79379
80004
  const filePath = getSkillsFilePath(sessionId);
79380
- fs17.mkdirSync(path13.dirname(filePath), { recursive: true });
80005
+ fs18.mkdirSync(path13.dirname(filePath), { recursive: true });
79381
80006
  const entry = JSON.stringify({
79382
80007
  timestamp: new Date().toISOString(),
79383
80008
  session_id: sessionId,
79384
80009
  skill: skillName,
79385
80010
  source: data.hook_event_name
79386
80011
  });
79387
- fs17.appendFileSync(filePath, entry + `
80012
+ fs18.appendFileSync(filePath, entry + `
79388
80013
  `);
79389
80014
  } catch {}
79390
80015
  }