steward-cli 0.16.0 → 0.17.0

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/dist/cli.js CHANGED
@@ -42222,6 +42222,40 @@ function stringWidth(input, options = {}) {
42222
42222
  // src/tui/engine/cell-layout.ts
42223
42223
  import { appendFileSync } from "node:fs";
42224
42224
 
42225
+ // src/theme/figures.ts
42226
+ var figures = {
42227
+ blackCircle: "●",
42228
+ bullet: "·",
42229
+ bulletSmall: "∙",
42230
+ teardropAsterisk: "✻",
42231
+ asterisk: "*",
42232
+ threeDots: "∴",
42233
+ treeBranch: "└",
42234
+ treeVertical: "│",
42235
+ pointer: ">",
42236
+ pointerBold: "❯",
42237
+ pointerSmall: "›",
42238
+ tick: "✔",
42239
+ cross: "✖",
42240
+ warning: "⚠",
42241
+ info: "ℹ",
42242
+ ellipsis: "…",
42243
+ arrowUp: "↑",
42244
+ arrowDown: "↓",
42245
+ arrowLeft: "←",
42246
+ arrowRight: "→",
42247
+ blockquoteBar: "▎",
42248
+ horizontalLine: "─",
42249
+ heavyHorizontal: "━",
42250
+ dashedLine: "╌",
42251
+ effortLow: "○",
42252
+ effortMedium: "◐",
42253
+ effortHigh: "●",
42254
+ effortMax: "◉",
42255
+ sliderPointer: "▲",
42256
+ sliderDivider: "┆",
42257
+ spinnerFrames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
42258
+ };
42225
42259
  // node_modules/chalk/source/utilities.js
42226
42260
  function stringReplaceAll(string, substring, postfix) {
42227
42261
  let index = string.indexOf(substring);
@@ -42770,357 +42804,419 @@ var chalk = createChalk();
42770
42804
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
42771
42805
  var source_default = chalk;
42772
42806
 
42773
- // src/theme/figures.ts
42774
- import { platform } from "node:os";
42775
- var isDarwin = platform() === "darwin";
42776
- var figures = {
42777
- blackCircle: "●",
42778
- bullet: "·",
42779
- bulletSmall: "∙",
42780
- teardropAsterisk: "✻",
42781
- asterisk: "*",
42782
- threeDots: "∴",
42783
- treeBranch: "└",
42784
- treeVertical: "│",
42785
- pointer: ">",
42786
- pointerBold: "❯",
42787
- pointerSmall: "›",
42788
- tick: "✔",
42789
- cross: "✖",
42790
- warning: "⚠",
42791
- info: "ℹ",
42792
- ellipsis: "…",
42793
- arrowUp: "↑",
42794
- arrowDown: "↓",
42795
- arrowLeft: "←",
42796
- arrowRight: "→",
42797
- blockquoteBar: "▎",
42798
- horizontalLine: "─",
42799
- heavyHorizontal: "━",
42800
- dashedLine: "╌",
42801
- effortLow: "○",
42802
- effortMedium: "◐",
42803
- effortHigh: "●",
42804
- effortMax: "◉",
42805
- sliderPointer: "▲",
42806
- sliderDivider: "┆",
42807
- spinnerFrames: ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
42808
- };
42807
+ // src/theme/apply.ts
42808
+ function resolveThemeColor(color, isBg = false) {
42809
+ if (!color || color === "default" || color === "none" || color === "transparent" || color === "ansi(reset)" || color === "ansi(default)") {
42810
+ return (s) => s;
42811
+ }
42812
+ if (color === "dim" || color === "ansi(dim)") {
42813
+ return isBg ? (s) => s : (s) => source_default.dim(s);
42814
+ }
42815
+ if (color.startsWith("ansi(") && color.endsWith(")")) {
42816
+ const name = color.slice(5, -1).trim();
42817
+ if (name === "reset" || name === "none" || name === "transparent" || name === "default") {
42818
+ return (s) => s;
42819
+ }
42820
+ if (name === "dim") {
42821
+ return isBg ? (s) => s : (s) => source_default.dim(s);
42822
+ }
42823
+ if (isBg && !name.startsWith("bg")) {
42824
+ const bgName = `bg${name.charAt(0).toUpperCase()}${name.slice(1)}`;
42825
+ const fn = source_default[bgName];
42826
+ if (typeof fn === "function")
42827
+ return fn;
42828
+ }
42829
+ const fn = source_default[name];
42830
+ if (typeof fn === "function")
42831
+ return fn;
42832
+ return (s) => s;
42833
+ }
42834
+ if (color.startsWith("rgb(")) {
42835
+ const match = color.match(/\d+/g);
42836
+ if (match && match.length >= 3) {
42837
+ const [r, g, b] = [Number(match[0]), Number(match[1]), Number(match[2])];
42838
+ return isBg ? source_default.bgRgb(r, g, b) : source_default.rgb(r, g, b);
42839
+ }
42840
+ }
42841
+ if (color.startsWith("#")) {
42842
+ return isBg ? source_default.bgHex(color) : source_default.hex(color);
42843
+ }
42844
+ return (s) => s;
42845
+ }
42846
+
42847
+ // src/theme/style.ts
42848
+ var _themeVersion = 0;
42849
+ function themeVersion() {
42850
+ return _themeVersion;
42851
+ }
42852
+ function bumpThemeVersion() {
42853
+ _themeVersion++;
42854
+ }
42855
+ var colorCache = new Map;
42856
+ var cachedVersion = -1;
42857
+ function getCachedColor(token, isBg) {
42858
+ if (source_default.level === 0) {
42859
+ return (s) => s;
42860
+ }
42861
+ const v = _themeVersion;
42862
+ if (v !== cachedVersion) {
42863
+ colorCache.clear();
42864
+ cachedVersion = v;
42865
+ }
42866
+ const key = `${isBg ? "bg:" : "fg:"}${token}`;
42867
+ let fn = colorCache.get(key);
42868
+ if (!fn) {
42869
+ const theme = getTheme();
42870
+ const colorStr = theme[token];
42871
+ fn = resolveThemeColor(colorStr ?? (isBg ? "default" : "default"), isBg);
42872
+ colorCache.set(key, fn);
42873
+ }
42874
+ return fn;
42875
+ }
42876
+ var c = new Proxy({}, {
42877
+ get(_target, prop) {
42878
+ return (s) => getCachedColor(prop, false)(s);
42879
+ }
42880
+ });
42881
+ var bg = new Proxy({}, {
42882
+ get(_target, prop) {
42883
+ return (s) => getCachedColor(prop, true)(s);
42884
+ }
42885
+ });
42886
+ var bold = (s) => source_default.level === 0 ? s : source_default.bold(s);
42887
+ var italic = (s) => source_default.level === 0 ? s : source_default.italic(s);
42888
+ var underline = (s) => source_default.level === 0 ? s : source_default.underline(s);
42889
+ var strikethrough = (s) => source_default.level === 0 ? s : source_default.strikethrough(s);
42890
+
42809
42891
  // src/theme/colors.ts
42810
42892
  var darkTheme = {
42893
+ text: "rgb(255,255,255)",
42894
+ muted: "rgb(110,110,110)",
42895
+ subtle: "rgb(80,80,80)",
42811
42896
  brand: "rgb(215,119,87)",
42812
- brandShimmer: "rgb(235,159,127)",
42813
- permission: "rgb(177,185,249)",
42814
- permissionDim: "rgb(93,100,128)",
42815
- permissionShimmer: "rgb(207,215,255)",
42816
- lavenderHeader: "rgb(129,136,165)",
42817
- lavenderLight: "rgb(183,184,228)",
42818
- bashPink: "rgb(253,93,177)",
42897
+ info: "rgb(123,165,218)",
42819
42898
  success: "rgb(78,186,101)",
42820
- error: "rgb(255,107,128)",
42821
42899
  warning: "rgb(255,193,7)",
42822
- info: "rgb(123,165,218)",
42823
- bulletSuccess: "rgb(75,185,99)",
42824
- bulletError: "rgb(255,107,128)",
42825
- bulletRunning: "rgb(255,255,255)",
42826
- text: "rgb(255,255,255)",
42827
- textMuted: "rgb(110,110,110)",
42828
- subtle: "rgb(80,80,80)",
42829
- inactive: "rgb(153,153,153)",
42900
+ error: "rgb(255,107,128)",
42901
+ permission: "rgb(177,185,249)",
42902
+ selected: "rgb(177,185,249)",
42903
+ current: "rgb(255,193,7)",
42830
42904
  promptBorder: "rgb(136,136,136)",
42831
- userCardBg: "rgb(55,55,55)",
42905
+ rule: "rgb(129,136,165)",
42832
42906
  userChevron: "rgb(82,82,82)",
42833
- toolHeaderBg: "rgb(35,35,40)",
42834
- diffAddBG: "rgb(19,54,14)",
42835
- diffAddFG: "rgb(126,231,135)",
42836
- diffDeleteBG: "rgb(54,5,9)",
42837
- diffDeleteFG: "rgb(255,123,114)",
42838
- dividerRule: "rgb(129,136,165)",
42839
- dashedRule: "rgb(51,51,51)"
42907
+ userBg: "rgb(55,55,55)",
42908
+ diffAddBg: "rgb(19,54,14)",
42909
+ diffDelBg: "rgb(54,5,9)",
42910
+ diffAddFg: "rgb(126,231,135)",
42911
+ diffDelFg: "rgb(255,123,114)",
42912
+ syntax: {
42913
+ keyword: "#ff7b72",
42914
+ string: "#a5d6ff",
42915
+ number: "#79c0ff",
42916
+ literal: "#79c0ff",
42917
+ comment: "#8b949e",
42918
+ function: "#d2a8ff",
42919
+ type: "#ffa657",
42920
+ variable: "#ffa657",
42921
+ tag: "#7ee787",
42922
+ attr: "#79c0ff",
42923
+ meta: "#79c0ff",
42924
+ addition: "#7ee787",
42925
+ deletion: "#ffa198",
42926
+ default: "#c9d1d9"
42927
+ }
42840
42928
  };
42841
42929
  var lightTheme = {
42930
+ text: "default",
42931
+ muted: "rgb(120,120,120)",
42932
+ subtle: "rgb(175,175,175)",
42842
42933
  brand: "rgb(215,119,87)",
42843
- brandShimmer: "rgb(245,149,117)",
42844
- permission: "rgb(87,105,247)",
42845
- permissionDim: "rgb(140,150,200)",
42846
- permissionShimmer: "rgb(137,155,255)",
42847
- lavenderHeader: "rgb(100,110,145)",
42848
- lavenderLight: "rgb(120,130,190)",
42849
- bashPink: "rgb(219,39,119)",
42934
+ info: "rgb(40,100,180)",
42850
42935
  success: "rgb(44,122,57)",
42851
- error: "rgb(171,43,63)",
42852
42936
  warning: "rgb(150,108,30)",
42853
- info: "rgb(40,100,180)",
42854
- bulletSuccess: "rgb(44,122,57)",
42855
- bulletError: "rgb(171,43,63)",
42856
- bulletRunning: "rgb(20,20,20)",
42857
- text: "rgb(0,0,0)",
42858
- textMuted: "rgb(120,120,120)",
42859
- subtle: "rgb(175,175,175)",
42860
- inactive: "rgb(102,102,102)",
42937
+ error: "rgb(171,43,63)",
42938
+ permission: "rgb(87,105,247)",
42939
+ selected: "rgb(87,105,247)",
42940
+ current: "rgb(150,108,30)",
42861
42941
  promptBorder: "rgb(153,153,153)",
42862
- userCardBg: "rgb(240,240,240)",
42942
+ rule: "rgb(120,130,160)",
42863
42943
  userChevron: "rgb(160,160,160)",
42864
- toolHeaderBg: "rgb(230,230,235)",
42865
- diffAddBG: "rgb(220,245,220)",
42866
- diffAddFG: "rgb(30,120,40)",
42867
- diffDeleteBG: "rgb(255,230,230)",
42868
- diffDeleteFG: "rgb(180,40,40)",
42869
- dividerRule: "rgb(120,130,160)",
42870
- dashedRule: "rgb(200,200,200)"
42944
+ userBg: "rgb(240,240,240)",
42945
+ diffAddBg: "rgb(220,245,220)",
42946
+ diffDelBg: "rgb(255,230,230)",
42947
+ diffAddFg: "rgb(30,120,40)",
42948
+ diffDelFg: "rgb(180,40,40)",
42949
+ syntax: {
42950
+ keyword: "#d73a49",
42951
+ string: "#032f62",
42952
+ number: "#005cc5",
42953
+ literal: "#005cc5",
42954
+ comment: "#6a737d",
42955
+ function: "#6f42c1",
42956
+ type: "#e36209",
42957
+ variable: "#e36209",
42958
+ tag: "#22863a",
42959
+ attr: "#005cc5",
42960
+ meta: "#005cc5",
42961
+ addition: "#22863a",
42962
+ deletion: "#b31d28",
42963
+ default: "default"
42964
+ }
42871
42965
  };
42872
42966
  var draculaTheme = {
42967
+ text: "rgb(248,248,242)",
42968
+ muted: "rgb(98,114,164)",
42969
+ subtle: "rgb(68,71,90)",
42873
42970
  brand: "rgb(255,184,108)",
42874
- brandShimmer: "rgb(255,200,140)",
42875
- permission: "rgb(189,147,249)",
42876
- permissionDim: "rgb(98,114,164)",
42877
- permissionShimmer: "rgb(255,121,198)",
42878
- lavenderHeader: "rgb(189,147,249)",
42879
- lavenderLight: "rgb(215,190,252)",
42880
- bashPink: "rgb(255,121,198)",
42971
+ info: "rgb(139,233,253)",
42881
42972
  success: "rgb(80,250,123)",
42882
- error: "rgb(255,85,85)",
42883
42973
  warning: "rgb(255,184,108)",
42884
- info: "rgb(139,233,253)",
42885
- bulletSuccess: "rgb(80,250,123)",
42886
- bulletError: "rgb(255,85,85)",
42887
- bulletRunning: "rgb(248,248,242)",
42888
- text: "rgb(248,248,242)",
42889
- textMuted: "rgb(98,114,164)",
42890
- subtle: "rgb(68,71,90)",
42891
- inactive: "rgb(98,114,164)",
42974
+ error: "rgb(255,85,85)",
42975
+ permission: "rgb(189,147,249)",
42976
+ selected: "rgb(189,147,249)",
42977
+ current: "rgb(255,184,108)",
42892
42978
  promptBorder: "rgb(98,114,164)",
42893
- userCardBg: "rgb(68,71,90)",
42979
+ rule: "rgb(189,147,249)",
42894
42980
  userChevron: "rgb(98,114,164)",
42895
- toolHeaderBg: "rgb(40,42,54)",
42896
- diffAddBG: "rgb(12,38,18)",
42897
- diffAddFG: "rgb(80,250,123)",
42898
- diffDeleteBG: "rgb(45,15,15)",
42899
- diffDeleteFG: "rgb(255,85,85)",
42900
- dividerRule: "rgb(189,147,249)",
42901
- dashedRule: "rgb(68,71,90)"
42981
+ userBg: "rgb(68,71,90)",
42982
+ diffAddBg: "rgb(12,38,18)",
42983
+ diffDelBg: "rgb(45,15,15)",
42984
+ diffAddFg: "rgb(80,250,123)",
42985
+ diffDelFg: "rgb(255,85,85)",
42986
+ syntax: {
42987
+ keyword: "rgb(255,121,198)",
42988
+ string: "rgb(241,250,140)",
42989
+ number: "rgb(189,147,249)",
42990
+ literal: "rgb(189,147,249)",
42991
+ comment: "rgb(98,114,164)",
42992
+ function: "rgb(80,250,123)",
42993
+ type: "rgb(139,233,253)",
42994
+ variable: "rgb(255,184,108)",
42995
+ tag: "rgb(255,121,198)",
42996
+ attr: "rgb(80,250,123)",
42997
+ meta: "rgb(255,121,198)",
42998
+ addition: "rgb(80,250,123)",
42999
+ deletion: "rgb(255,85,85)",
43000
+ default: "rgb(248,248,242)"
43001
+ }
42902
43002
  };
42903
43003
  var darkAnsiTheme = {
43004
+ text: "default",
43005
+ muted: "dim",
43006
+ subtle: "dim",
42904
43007
  brand: "ansi(yellow)",
42905
- brandShimmer: "ansi(yellowBright)",
42906
- permission: "ansi(blue)",
42907
- permissionDim: "ansi(gray)",
42908
- permissionShimmer: "ansi(blueBright)",
42909
- lavenderHeader: "ansi(magenta)",
42910
- lavenderLight: "ansi(magentaBright)",
42911
- bashPink: "ansi(magenta)",
43008
+ info: "ansi(cyan)",
42912
43009
  success: "ansi(green)",
42913
- error: "ansi(red)",
42914
43010
  warning: "ansi(yellow)",
42915
- info: "ansi(cyan)",
42916
- bulletSuccess: "ansi(green)",
42917
- bulletError: "ansi(red)",
42918
- bulletRunning: "ansi(white)",
42919
- text: "ansi(white)",
42920
- textMuted: "ansi(gray)",
42921
- subtle: "ansi(gray)",
42922
- inactive: "ansi(gray)",
42923
- promptBorder: "ansi(gray)",
42924
- userCardBg: "ansi(bgBlackBright)",
42925
- userChevron: "ansi(gray)",
42926
- toolHeaderBg: "ansi(bgBlack)",
42927
- diffAddBG: "ansi(reset)",
42928
- diffAddFG: "ansi(green)",
42929
- diffDeleteBG: "ansi(reset)",
42930
- diffDeleteFG: "ansi(red)",
42931
- dividerRule: "ansi(magenta)",
42932
- dashedRule: "ansi(gray)"
43011
+ error: "ansi(red)",
43012
+ permission: "ansi(blue)",
43013
+ selected: "ansi(blue)",
43014
+ current: "ansi(yellow)",
43015
+ promptBorder: "dim",
43016
+ rule: "dim",
43017
+ userChevron: "dim",
43018
+ userBg: "ansi(bgBlackBright)",
43019
+ diffAddBg: "default",
43020
+ diffDelBg: "default",
43021
+ diffAddFg: "ansi(green)",
43022
+ diffDelFg: "ansi(red)",
43023
+ syntax: {
43024
+ keyword: "ansi(red)",
43025
+ string: "ansi(cyan)",
43026
+ number: "ansi(cyan)",
43027
+ literal: "ansi(cyan)",
43028
+ comment: "ansi(gray)",
43029
+ function: "ansi(magenta)",
43030
+ type: "ansi(yellow)",
43031
+ variable: "ansi(yellow)",
43032
+ tag: "ansi(green)",
43033
+ attr: "ansi(cyan)",
43034
+ meta: "ansi(blue)",
43035
+ addition: "ansi(green)",
43036
+ deletion: "ansi(red)",
43037
+ default: "ansi(white)"
43038
+ }
42933
43039
  };
42934
43040
  var lightAnsiTheme = {
43041
+ text: "default",
43042
+ muted: "dim",
43043
+ subtle: "dim",
42935
43044
  brand: "ansi(yellow)",
42936
- brandShimmer: "ansi(yellowBright)",
42937
- permission: "ansi(blue)",
42938
- permissionDim: "ansi(gray)",
42939
- permissionShimmer: "ansi(blueBright)",
42940
- lavenderHeader: "ansi(magenta)",
42941
- lavenderLight: "ansi(magentaBright)",
42942
- bashPink: "ansi(magenta)",
43045
+ info: "ansi(blue)",
42943
43046
  success: "ansi(green)",
42944
- error: "ansi(red)",
42945
43047
  warning: "ansi(yellow)",
42946
- info: "ansi(blue)",
42947
- bulletSuccess: "ansi(green)",
42948
- bulletError: "ansi(red)",
42949
- bulletRunning: "ansi(black)",
42950
- text: "ansi(black)",
42951
- textMuted: "ansi(gray)",
42952
- subtle: "ansi(gray)",
42953
- inactive: "ansi(gray)",
42954
- promptBorder: "ansi(gray)",
42955
- userCardBg: "ansi(bgWhiteBright)",
42956
- userChevron: "ansi(gray)",
42957
- toolHeaderBg: "ansi(bgWhite)",
42958
- diffAddBG: "ansi(reset)",
42959
- diffAddFG: "ansi(green)",
42960
- diffDeleteBG: "ansi(reset)",
42961
- diffDeleteFG: "ansi(red)",
42962
- dividerRule: "ansi(magenta)",
42963
- dashedRule: "ansi(gray)"
42964
- };
42965
- var darkColorblindTheme = {
42966
- brand: "rgb(86,180,233)",
42967
- brandShimmer: "rgb(136,200,245)",
42968
- permission: "rgb(0,114,178)",
42969
- permissionDim: "rgb(93,100,128)",
42970
- permissionShimmer: "rgb(86,180,233)",
42971
- lavenderHeader: "rgb(204,121,167)",
42972
- lavenderLight: "rgb(220,150,190)",
42973
- bashPink: "rgb(204,121,167)",
42974
- success: "rgb(0,158,115)",
42975
- error: "rgb(213,94,0)",
42976
- warning: "rgb(230,159,0)",
42977
- info: "rgb(0,114,178)",
42978
- bulletSuccess: "rgb(0,158,115)",
42979
- bulletError: "rgb(213,94,0)",
42980
- bulletRunning: "rgb(255,255,255)",
42981
- text: "rgb(255,255,255)",
42982
- textMuted: "rgb(110,110,110)",
42983
- subtle: "rgb(80,80,80)",
42984
- inactive: "rgb(153,153,153)",
42985
- promptBorder: "rgb(136,136,136)",
42986
- userCardBg: "rgb(55,55,55)",
42987
- userChevron: "rgb(82,82,82)",
42988
- toolHeaderBg: "rgb(35,35,40)",
42989
- diffAddBG: "rgb(0,35,25)",
42990
- diffAddFG: "rgb(0,158,115)",
42991
- diffDeleteBG: "rgb(45,20,0)",
42992
- diffDeleteFG: "rgb(213,94,0)",
42993
- dividerRule: "rgb(204,121,167)",
42994
- dashedRule: "rgb(51,51,51)"
42995
- };
42996
- var lightColorblindTheme = {
42997
- brand: "rgb(0,114,178)",
42998
- brandShimmer: "rgb(86,180,233)",
42999
- permission: "rgb(0,114,178)",
43000
- permissionDim: "rgb(140,150,200)",
43001
- permissionShimmer: "rgb(86,180,233)",
43002
- lavenderHeader: "rgb(204,121,167)",
43003
- lavenderLight: "rgb(220,150,190)",
43004
- bashPink: "rgb(204,121,167)",
43005
- success: "rgb(0,158,115)",
43006
- error: "rgb(213,94,0)",
43007
- warning: "rgb(230,159,0)",
43008
- info: "rgb(0,114,178)",
43009
- bulletSuccess: "rgb(0,158,115)",
43010
- bulletError: "rgb(213,94,0)",
43011
- bulletRunning: "rgb(20,20,20)",
43012
- text: "rgb(0,0,0)",
43013
- textMuted: "rgb(120,120,120)",
43014
- subtle: "rgb(175,175,175)",
43015
- inactive: "rgb(102,102,102)",
43016
- promptBorder: "rgb(153,153,153)",
43017
- userCardBg: "rgb(240,240,240)",
43018
- userChevron: "rgb(160,160,160)",
43019
- toolHeaderBg: "rgb(230,230,235)",
43020
- diffAddBG: "rgb(215,245,235)",
43021
- diffAddFG: "rgb(0,158,115)",
43022
- diffDeleteBG: "rgb(255,235,225)",
43023
- diffDeleteFG: "rgb(213,94,0)",
43024
- dividerRule: "rgb(204,121,167)",
43025
- dashedRule: "rgb(200,200,200)"
43048
+ error: "ansi(red)",
43049
+ permission: "ansi(blue)",
43050
+ selected: "ansi(blue)",
43051
+ current: "ansi(yellow)",
43052
+ promptBorder: "dim",
43053
+ rule: "dim",
43054
+ userChevron: "dim",
43055
+ userBg: "ansi(bgWhiteBright)",
43056
+ diffAddBg: "default",
43057
+ diffDelBg: "default",
43058
+ diffAddFg: "ansi(green)",
43059
+ diffDelFg: "ansi(red)",
43060
+ syntax: {
43061
+ keyword: "ansi(red)",
43062
+ string: "ansi(blue)",
43063
+ number: "ansi(blue)",
43064
+ literal: "ansi(blue)",
43065
+ comment: "ansi(gray)",
43066
+ function: "ansi(magenta)",
43067
+ type: "ansi(yellow)",
43068
+ variable: "ansi(yellow)",
43069
+ tag: "ansi(green)",
43070
+ attr: "ansi(blue)",
43071
+ meta: "ansi(blue)",
43072
+ addition: "ansi(green)",
43073
+ deletion: "ansi(red)",
43074
+ default: "default"
43075
+ }
43026
43076
  };
43027
- var THEMES = {
43028
- dark: {
43077
+ var builtInThemes = [
43078
+ {
43029
43079
  name: "dark",
43030
43080
  label: "Dark (Default)",
43031
43081
  description: "Default dark theme with terracotta and purple accents",
43032
- theme: darkTheme
43082
+ theme: darkTheme,
43083
+ source: "built-in"
43033
43084
  },
43034
- light: {
43085
+ {
43035
43086
  name: "light",
43036
43087
  label: "Light",
43037
43088
  description: "Clean light palette optimized for light backgrounds",
43038
- theme: lightTheme
43089
+ theme: lightTheme,
43090
+ source: "built-in"
43091
+ },
43092
+ {
43093
+ name: "dracula",
43094
+ label: "Dracula",
43095
+ description: "Official gothic-inspired vampire color scheme",
43096
+ theme: draculaTheme,
43097
+ source: "built-in"
43039
43098
  },
43040
- "dark-ansi": {
43099
+ {
43041
43100
  name: "dark-ansi",
43042
43101
  label: "Dark ANSI",
43043
43102
  description: "16-color ANSI palette respecting your terminal theme",
43044
- theme: darkAnsiTheme
43103
+ theme: darkAnsiTheme,
43104
+ source: "built-in"
43045
43105
  },
43046
- "light-ansi": {
43106
+ {
43047
43107
  name: "light-ansi",
43048
43108
  label: "Light ANSI",
43049
43109
  description: "16-color ANSI light palette respecting terminal colors",
43050
- theme: lightAnsiTheme
43051
- },
43052
- "dark-colorblind": {
43053
- name: "dark-colorblind",
43054
- label: "Dark Colorblind",
43055
- description: "Okabe–Ito colorblind-accessible dark theme",
43056
- theme: darkColorblindTheme
43057
- },
43058
- "light-colorblind": {
43059
- name: "light-colorblind",
43060
- label: "Light Colorblind",
43061
- description: "Okabe–Ito colorblind-accessible light theme",
43062
- theme: lightColorblindTheme
43063
- },
43064
- dracula: {
43065
- name: "dracula",
43066
- label: "Dracula",
43067
- description: "Official gothic-inspired vampire color scheme",
43068
- theme: draculaTheme
43110
+ theme: lightAnsiTheme,
43111
+ source: "built-in"
43069
43112
  }
43070
- };
43071
- var activeThemeName = "dark";
43072
- function getActiveThemeName() {
43073
- return activeThemeName;
43074
- }
43075
- function setActiveTheme(name) {
43076
- if (name in THEMES) {
43077
- activeThemeName = name;
43078
- }
43079
- }
43080
- function getTheme() {
43081
- return THEMES[activeThemeName]?.theme ?? darkTheme;
43113
+ ];
43114
+ var registry = new Map;
43115
+ for (const t of builtInThemes) {
43116
+ registry.set(t.name, t);
43082
43117
  }
43118
+ var activeThemeId = "dark";
43083
43119
  function listThemes() {
43084
- return Object.values(THEMES);
43120
+ return Array.from(registry.values());
43085
43121
  }
43086
- function findTheme2(query) {
43122
+ function findTheme(query) {
43087
43123
  const q = query.trim().toLowerCase().replace(/^["']|["']$/g, "");
43088
43124
  if (!q)
43089
43125
  return;
43090
43126
  return listThemes().find((t) => t.name.toLowerCase() === q || t.label.toLowerCase() === q || t.label.toLowerCase().startsWith(q));
43091
43127
  }
43128
+ function setActiveTheme(name) {
43129
+ if (registry.has(name)) {
43130
+ activeThemeId = name;
43131
+ bumpThemeVersion();
43132
+ return true;
43133
+ }
43134
+ activeThemeId = "dark";
43135
+ bumpThemeVersion();
43136
+ return false;
43137
+ }
43138
+ function getActiveThemeName() {
43139
+ return activeThemeId;
43140
+ }
43141
+ function getTheme() {
43142
+ return registry.get(activeThemeId)?.theme ?? darkTheme;
43143
+ }
43092
43144
  // src/theme/logo.ts
43093
43145
  var LOGO_LINES = [" ▄▄▄▄▄ ", "▀▙███▟▀", " ▝ ▘ "];
43094
- var LOGO_WIDTH = Math.max(...LOGO_LINES.map((line) => stringWidth(line)));
43095
- // src/theme/apply.ts
43096
- function resolveThemeColor(color, isBg = false) {
43097
- if (!color || color === "none" || color === "transparent" || color === "ansi(reset)") {
43098
- return source_default.visible;
43099
- }
43100
- if (color.startsWith("ansi(") && color.endsWith(")")) {
43101
- const name = color.slice(5, -1).trim();
43102
- if (name === "reset" || name === "none" || name === "transparent" || name === "default") {
43103
- return source_default.visible;
43104
- }
43105
- if (isBg && !name.startsWith("bg")) {
43106
- const bgName = `bg${name.charAt(0).toUpperCase()}${name.slice(1)}`;
43107
- const fn = source_default[bgName];
43108
- if (typeof fn === "function")
43109
- return fn;
43110
- }
43111
- const fn = source_default[name];
43112
- if (typeof fn === "function")
43113
- return fn;
43114
- return source_default.visible;
43146
+ // src/theme/syntax.ts
43147
+ function buildHighlightTheme(theme) {
43148
+ const syn = theme.syntax;
43149
+ const kw = resolveThemeColor(syn.keyword);
43150
+ const str = resolveThemeColor(syn.string);
43151
+ const num = resolveThemeColor(syn.number);
43152
+ const lit = resolveThemeColor(syn.literal);
43153
+ const com = resolveThemeColor(syn.comment);
43154
+ const fn = resolveThemeColor(syn.function);
43155
+ const typ = resolveThemeColor(syn.type);
43156
+ const vr = resolveThemeColor(syn.variable);
43157
+ const tg = resolveThemeColor(syn.tag);
43158
+ const at = resolveThemeColor(syn.attr);
43159
+ const mt = resolveThemeColor(syn.meta);
43160
+ const add = resolveThemeColor(syn.addition);
43161
+ const del = resolveThemeColor(syn.deletion);
43162
+ const def = resolveThemeColor(syn.default);
43163
+ return {
43164
+ keyword: kw,
43165
+ built_in: typ,
43166
+ type: typ,
43167
+ literal: lit,
43168
+ number: num,
43169
+ regexp: tg,
43170
+ string: str,
43171
+ subst: def,
43172
+ symbol: tg,
43173
+ class: typ,
43174
+ function: fn,
43175
+ title: fn,
43176
+ params: def,
43177
+ comment: (s) => com(italic(s)),
43178
+ doctag: kw,
43179
+ meta: mt,
43180
+ "meta-keyword": kw,
43181
+ "meta-string": str,
43182
+ section: (s) => mt(bold(s)),
43183
+ tag: tg,
43184
+ name: tg,
43185
+ "builtin-name": typ,
43186
+ attr: at,
43187
+ attribute: at,
43188
+ variable: vr,
43189
+ bullet: vr,
43190
+ code: def,
43191
+ emphasis: (s) => italic(s),
43192
+ strong: (s) => bold(s),
43193
+ formula: tg,
43194
+ link: (s) => str(underline(s)),
43195
+ quote: com,
43196
+ "selector-tag": tg,
43197
+ "selector-id": (s) => mt(bold(s)),
43198
+ "selector-class": at,
43199
+ "selector-attr": at,
43200
+ "selector-pseudo": at,
43201
+ "template-tag": tg,
43202
+ "template-variable": vr,
43203
+ addition: add,
43204
+ deletion: del,
43205
+ default: def
43206
+ };
43207
+ }
43208
+ var cachedHighlightTheme = null;
43209
+ var cachedHighlightVersion = -1;
43210
+ function getHighlightTheme() {
43211
+ if (source_default.level === 0) {
43212
+ return { default: (s) => s };
43115
43213
  }
43116
- if (color.startsWith("rgb(")) {
43117
- const match = color.match(/\d+/g);
43118
- if (match && match.length >= 3) {
43119
- const [r, g, b] = [Number(match[0]), Number(match[1]), Number(match[2])];
43120
- return isBg ? source_default.bgRgb(r, g, b) : source_default.rgb(r, g, b);
43121
- }
43214
+ const v = themeVersion();
43215
+ if (!cachedHighlightTheme || v !== cachedHighlightVersion) {
43216
+ cachedHighlightTheme = buildHighlightTheme(getTheme());
43217
+ cachedHighlightVersion = v;
43122
43218
  }
43123
- return isBg ? source_default.bgHex(color) : source_default.hex(color);
43219
+ return cachedHighlightTheme;
43124
43220
  }
43125
43221
  // node_modules/marked/lib/marked.esm.js
43126
43222
  function A() {
@@ -44502,94 +44598,6 @@ var pn = x.lex;
44502
44598
  // src/utils/highlight.ts
44503
44599
  var import_cli_highlight = __toESM(require_dist(), 1);
44504
44600
  import { extname, basename } from "node:path";
44505
- var githubDarkHighlightTheme = {
44506
- keyword: source_default.hex("#ff7b72"),
44507
- built_in: source_default.hex("#ffa657"),
44508
- type: source_default.hex("#ffa657"),
44509
- literal: source_default.hex("#79c0ff"),
44510
- number: source_default.hex("#79c0ff"),
44511
- regexp: source_default.hex("#7ee787"),
44512
- string: source_default.hex("#a5d6ff"),
44513
- subst: source_default.hex("#c9d1d9"),
44514
- symbol: source_default.hex("#7ee787"),
44515
- class: source_default.hex("#ffa657"),
44516
- function: source_default.hex("#d2a8ff"),
44517
- title: source_default.hex("#d2a8ff"),
44518
- params: source_default.hex("#c9d1d9"),
44519
- comment: (str) => source_default.hex("#8b949e")(source_default.italic(str)),
44520
- doctag: source_default.hex("#ff7b72"),
44521
- meta: source_default.hex("#79c0ff"),
44522
- "meta-keyword": source_default.hex("#ff7b72"),
44523
- "meta-string": source_default.hex("#a5d6ff"),
44524
- section: source_default.hex("#79c0ff").bold,
44525
- tag: source_default.hex("#7ee787"),
44526
- name: source_default.hex("#7ee787"),
44527
- "builtin-name": source_default.hex("#ffa657"),
44528
- attr: source_default.hex("#79c0ff"),
44529
- attribute: source_default.hex("#79c0ff"),
44530
- variable: source_default.hex("#ffa657"),
44531
- bullet: source_default.hex("#ffa657"),
44532
- code: source_default.hex("#c9d1d9"),
44533
- emphasis: (str) => source_default.italic(str),
44534
- strong: (str) => source_default.bold(str),
44535
- formula: source_default.hex("#7ee787"),
44536
- link: source_default.hex("#a5d6ff").underline,
44537
- quote: source_default.hex("#8b949e"),
44538
- "selector-tag": source_default.hex("#7ee787"),
44539
- "selector-id": source_default.hex("#79c0ff").bold,
44540
- "selector-class": source_default.hex("#79c0ff"),
44541
- "selector-attr": source_default.hex("#79c0ff"),
44542
- "selector-pseudo": source_default.hex("#79c0ff"),
44543
- "template-tag": source_default.hex("#7ee787"),
44544
- "template-variable": source_default.hex("#ffa657"),
44545
- addition: source_default.hex("#7ee787"),
44546
- deletion: source_default.hex("#ffa198"),
44547
- default: source_default.hex("#c9d1d9")
44548
- };
44549
- var ansiHighlightTheme = {
44550
- keyword: source_default.red,
44551
- built_in: source_default.yellow,
44552
- type: source_default.yellow,
44553
- literal: source_default.cyan,
44554
- number: source_default.cyan,
44555
- regexp: source_default.green,
44556
- string: source_default.cyan,
44557
- subst: source_default.white,
44558
- symbol: source_default.green,
44559
- class: source_default.yellow,
44560
- function: source_default.magenta,
44561
- title: source_default.magenta,
44562
- params: source_default.white,
44563
- comment: (str) => source_default.gray(source_default.italic(str)),
44564
- doctag: source_default.red,
44565
- meta: source_default.blue,
44566
- "meta-keyword": source_default.red,
44567
- "meta-string": source_default.cyan,
44568
- section: source_default.blue.bold,
44569
- tag: source_default.green,
44570
- name: source_default.green,
44571
- "builtin-name": source_default.yellow,
44572
- attr: source_default.cyan,
44573
- attribute: source_default.cyan,
44574
- variable: source_default.yellow,
44575
- bullet: source_default.yellow,
44576
- code: source_default.white,
44577
- emphasis: (str) => source_default.italic(str),
44578
- strong: (str) => source_default.bold(str),
44579
- formula: source_default.green,
44580
- link: source_default.cyan.underline,
44581
- quote: source_default.gray,
44582
- "selector-tag": source_default.green,
44583
- "selector-id": source_default.blue.bold,
44584
- "selector-class": source_default.cyan,
44585
- "selector-attr": source_default.cyan,
44586
- "selector-pseudo": source_default.cyan,
44587
- "template-tag": source_default.green,
44588
- "template-variable": source_default.yellow,
44589
- addition: source_default.green,
44590
- deletion: source_default.red,
44591
- default: source_default.white
44592
- };
44593
44601
  var EXTENSION_MAP = {
44594
44602
  ".ts": "typescript",
44595
44603
  ".tsx": "typescript",
@@ -44646,23 +44654,9 @@ function detectLanguageFromPath(filePath) {
44646
44654
  }
44647
44655
  return;
44648
44656
  }
44649
- function getHighlightTheme() {
44650
- if (source_default.level === 0) {
44651
- return {
44652
- default: (str) => str
44653
- };
44654
- }
44655
- const activeTheme = getActiveThemeName();
44656
- if (activeTheme.includes("ansi") || source_default.level === 1) {
44657
- return ansiHighlightTheme;
44658
- }
44659
- return githubDarkHighlightTheme;
44660
- }
44661
44657
  function highlightCode(code, options) {
44662
44658
  if (!code)
44663
44659
  return "";
44664
- if (source_default.level === 0)
44665
- return code;
44666
44660
  const lang = options?.language ?? detectLanguageFromPath(options?.filePath);
44667
44661
  try {
44668
44662
  if (lang && import_cli_highlight.supportsLanguage(lang)) {
@@ -44684,9 +44678,6 @@ function highlightCode(code, options) {
44684
44678
  // src/utils/markdown.ts
44685
44679
  var EOL = `
44686
44680
  `;
44687
- function themeColor(color) {
44688
- return resolveThemeColor(color, false);
44689
- }
44690
44681
  var markedConfigured = false;
44691
44682
  function configureMarked() {
44692
44683
  if (markedConfigured)
@@ -44713,48 +44704,47 @@ function padAligned(content, contentWidth, columnWidth, align) {
44713
44704
  return content + " ".repeat(padding);
44714
44705
  }
44715
44706
  function formatToken(token, listDepth = 0, orderedListNumber = null, parent = null) {
44716
- const theme = getTheme();
44717
44707
  switch (token.type) {
44718
44708
  case "blockquote": {
44719
44709
  const inner = (token.tokens ?? []).map((t) => formatToken(t, 0, null, null)).join("");
44720
- const bar = themeColor(theme.subtle)("│");
44721
- return inner.split(EOL).map((line) => stripAnsi(line).trim() ? `${bar} ${source_default.italic(line)}` : line).join(EOL);
44710
+ const bar = c.subtle("│");
44711
+ return inner.split(EOL).map((line) => stripAnsi(line).trim() ? `${bar} ${italic(line)}` : line).join(EOL);
44722
44712
  }
44723
44713
  case "code": {
44724
44714
  const code = token;
44725
44715
  const highlighted = highlightCode(code.text, { language: code.lang });
44726
- const gutter = themeColor(theme.subtle)("│");
44716
+ const gutter = c.subtle("│");
44727
44717
  const lines = highlighted.split(EOL);
44728
44718
  const formatted = lines.map((line) => ` ${gutter} ${line}`).join(EOL);
44729
44719
  return formatted + EOL + EOL;
44730
44720
  }
44731
44721
  case "codespan": {
44732
- return themeColor(theme.permission)(token.text);
44722
+ return c.permission(token.text);
44733
44723
  }
44734
44724
  case "em": {
44735
- return source_default.italic((token.tokens ?? []).map((t) => formatToken(t, 0, null, parent)).join(""));
44725
+ return italic((token.tokens ?? []).map((t) => formatToken(t, 0, null, parent)).join(""));
44736
44726
  }
44737
44727
  case "strong": {
44738
- return source_default.bold((token.tokens ?? []).map((t) => formatToken(t, 0, null, parent)).join(""));
44728
+ return bold((token.tokens ?? []).map((t) => formatToken(t, 0, null, parent)).join(""));
44739
44729
  }
44740
44730
  case "heading": {
44741
44731
  const heading = token;
44742
44732
  const text = (heading.tokens ?? []).map((t) => formatToken(t, 0, null, null)).join("");
44743
44733
  if (heading.depth === 1) {
44744
- return themeColor(theme.brand).bold.underline(text) + EOL + EOL;
44734
+ return underline(bold(c.brand(text))) + EOL + EOL;
44745
44735
  }
44746
44736
  if (heading.depth === 2) {
44747
- return themeColor(theme.brand).bold(text) + EOL + EOL;
44737
+ return bold(c.brand(text)) + EOL + EOL;
44748
44738
  }
44749
- return source_default.bold(text) + EOL + EOL;
44739
+ return bold(text) + EOL + EOL;
44750
44740
  }
44751
44741
  case "hr": {
44752
- return themeColor(theme.dashedRule)("─".repeat(40)) + EOL + EOL;
44742
+ return c.rule("─".repeat(40)) + EOL + EOL;
44753
44743
  }
44754
44744
  case "link": {
44755
44745
  const link = token;
44756
44746
  const linkText = (link.tokens ?? []).map((t) => formatToken(t, 0, null, link)).join("");
44757
- return linkText ? `${themeColor(theme.info)(linkText)} (${source_default.dim(link.href)})` : link.href;
44747
+ return linkText ? `${c.info(linkText)} (${c.muted(link.href)})` : link.href;
44758
44748
  }
44759
44749
  case "list": {
44760
44750
  const list = token;
@@ -44768,7 +44758,7 @@ function formatToken(token, listDepth = 0, orderedListNumber = null, parent = nu
44768
44758
  const listTokens = item.tokens?.filter((t) => t.type === "list") ?? [];
44769
44759
  const mainContent = nonListTokens.map((t) => formatToken(t, listDepth + 1, orderedListNumber, token)).join("").trim();
44770
44760
  const nestedLists = listTokens.map((t) => formatToken(t, listDepth + 1, null, token)).join("");
44771
- return `${indent}${themeColor(theme.brand)(prefix)} ${mainContent}${EOL}${nestedLists}`;
44761
+ return `${indent}${c.brand(prefix)} ${mainContent}${EOL}${nestedLists}`;
44772
44762
  }
44773
44763
  case "paragraph": {
44774
44764
  return (token.tokens ?? []).map((t) => formatToken(t, 0, null, null)).join("") + EOL + EOL;
@@ -44793,7 +44783,7 @@ function formatToken(token, listDepth = 0, orderedListNumber = null, parent = nu
44793
44783
  const plain = stripAnsi(raw);
44794
44784
  const align = isHeader ? "center" : tableToken.align?.[i] ?? "left";
44795
44785
  const padded = padAligned(raw, stringWidth(plain), w, align);
44796
- return isHeader ? ` ${source_default.bold(padded)} ` : ` ${padded} `;
44786
+ return isHeader ? ` ${bold(padded)} ` : ` ${padded} `;
44797
44787
  });
44798
44788
  return D("│") + parts.join(D("│")) + D("│");
44799
44789
  };
@@ -44806,7 +44796,7 @@ function formatToken(token, listDepth = 0, orderedListNumber = null, parent = nu
44806
44796
  }
44807
44797
  return Math.max(maxWidth, 3);
44808
44798
  });
44809
- const D = themeColor(theme.subtle);
44799
+ const D = (s) => c.subtle(s);
44810
44800
  const hbar = (w) => "─".repeat(w + 2);
44811
44801
  const topBorder = D("┌") + columnWidths.map((w) => D(hbar(w))).join(D("┬")) + D("┐");
44812
44802
  const midBorder = D("├") + columnWidths.map((w) => D(hbar(w))).join(D("┼")) + D("┤");
@@ -44838,12 +44828,9 @@ function applyMarkdown(content) {
44838
44828
  }
44839
44829
 
44840
44830
  // src/tui/utils/format.ts
44841
- function themeColor2(color) {
44831
+ function themeColor(color) {
44842
44832
  return resolveThemeColor(color, false);
44843
44833
  }
44844
- function themeBgColor(color) {
44845
- return resolveThemeColor(color, true);
44846
- }
44847
44834
  function visibleWidth(text) {
44848
44835
  return stringWidth(stripAnsi(text));
44849
44836
  }
@@ -44942,17 +44929,16 @@ function truncateToWidth(styledText, maxWidth) {
44942
44929
  return result.includes("\x1B") && !result.endsWith("\x1B[0m") ? result + "\x1B[0m" : result;
44943
44930
  }
44944
44931
  function getStatusBullet(status, pulse = false) {
44945
- const theme = getTheme();
44946
44932
  if (status === "completed") {
44947
- return themeColor2(theme.success)(figures.blackCircle);
44933
+ return c.success(figures.blackCircle);
44948
44934
  }
44949
44935
  if (status === "failed") {
44950
- return themeColor2(theme.error)(figures.blackCircle);
44936
+ return c.error(figures.blackCircle);
44951
44937
  }
44952
44938
  if (pulse) {
44953
- return source_default.white.bold(figures.blackCircle);
44939
+ return bold(c.text(figures.blackCircle));
44954
44940
  }
44955
- return source_default.dim(figures.blackCircle);
44941
+ return c.muted(figures.blackCircle);
44956
44942
  }
44957
44943
 
44958
44944
  // src/tui/engine/cell-layout.ts
@@ -45649,6 +45635,75 @@ class StateRenderer {
45649
45635
  }
45650
45636
  }
45651
45637
 
45638
+ // src/tui/utils/tool-detail.ts
45639
+ function renderToolDetail(detail) {
45640
+ if (detail.kind === "text") {
45641
+ return detail.text.split(`
45642
+ `).map((l) => c.muted(l)).join(`
45643
+ `);
45644
+ }
45645
+ if (detail.kind === "code") {
45646
+ const highlighted = highlightCode(detail.text, { filePath: detail.filePath });
45647
+ const contentLines = highlighted.split(/\r?\n/);
45648
+ if (contentLines.length === 0 || contentLines.length === 1 && !contentLines[0]) {
45649
+ return "";
45650
+ }
45651
+ const cap = 50;
45652
+ const shown = contentLines.slice(0, cap);
45653
+ const padWidth = String(contentLines.length).length;
45654
+ const lines = shown.map((l, i) => `${c.muted(String(i + 1).padStart(padWidth))} ${l}`);
45655
+ if (contentLines.length > cap) {
45656
+ lines.push(c.muted(` … (${contentLines.length - cap} more lines)`));
45657
+ }
45658
+ return lines.join(`
45659
+ `);
45660
+ }
45661
+ if (detail.kind === "diff") {
45662
+ let maxLineNum = 1;
45663
+ for (const hunk of detail.hunks) {
45664
+ for (const line of hunk.lines) {
45665
+ if (line.oldLineNumber)
45666
+ maxLineNum = Math.max(maxLineNum, line.oldLineNumber);
45667
+ if (line.newLineNumber)
45668
+ maxLineNum = Math.max(maxLineNum, line.newLineNumber);
45669
+ }
45670
+ }
45671
+ const padWidth = Math.max(1, String(maxLineNum).length);
45672
+ const diffLines = [];
45673
+ const cap = 30;
45674
+ let count = 0;
45675
+ let overflow = 0;
45676
+ for (const hunk of detail.hunks) {
45677
+ for (const line of hunk.lines) {
45678
+ if (count >= cap) {
45679
+ overflow++;
45680
+ continue;
45681
+ }
45682
+ count++;
45683
+ if (line.kind === "deletion") {
45684
+ const numStr = String(line.oldLineNumber ?? "").padStart(padWidth, " ");
45685
+ const body = line.spans ? "-" + line.spans.map((s) => s.kind === "deletion" ? bold(s.text) : s.text).join("") : `-${line.text}`;
45686
+ diffLines.push(bg.diffDelBg(c.diffDelFg(`${numStr} ${body}`)));
45687
+ } else if (line.kind === "addition") {
45688
+ const numStr = String(line.newLineNumber ?? "").padStart(padWidth, " ");
45689
+ const body = line.spans ? "+" + line.spans.map((s) => s.kind === "addition" ? bold(s.text) : s.text).join("") : `+${line.text}`;
45690
+ diffLines.push(bg.diffAddBg(c.diffAddFg(`${numStr} ${body}`)));
45691
+ } else {
45692
+ const numStr = String(line.newLineNumber ?? line.oldLineNumber ?? "").padStart(padWidth, " ");
45693
+ const highlightedContext = highlightCode(line.text, { filePath: detail.filePath });
45694
+ diffLines.push(`${c.muted(`${numStr} `)} ${highlightedContext}`);
45695
+ }
45696
+ }
45697
+ }
45698
+ if (overflow > 0) {
45699
+ diffLines.push(c.muted(` … (${overflow} more lines)`));
45700
+ }
45701
+ return diffLines.join(`
45702
+ `);
45703
+ }
45704
+ return "";
45705
+ }
45706
+
45652
45707
  // src/session/logs/store.ts
45653
45708
  import {
45654
45709
  appendFileSync as appendFileSync2,
@@ -45672,7 +45727,6 @@ import {
45672
45727
  readdirSync,
45673
45728
  readFileSync,
45674
45729
  renameSync,
45675
- rmSync,
45676
45730
  unlinkSync,
45677
45731
  writeFileSync,
45678
45732
  writeSync
@@ -49339,10 +49393,10 @@ class $ZodRegistry {
49339
49393
  return this._map.has(schema);
49340
49394
  }
49341
49395
  }
49342
- function registry() {
49396
+ function registry2() {
49343
49397
  return new $ZodRegistry;
49344
49398
  }
49345
- (_a2 = globalThis).__zod_globalRegistry ?? (_a2.__zod_globalRegistry = registry());
49399
+ (_a2 = globalThis).__zod_globalRegistry ?? (_a2.__zod_globalRegistry = registry2());
49346
49400
  var globalRegistry = globalThis.__zod_globalRegistry;
49347
49401
  // node_modules/zod/v4/core/api.js
49348
49402
  function _string(Class, params) {
@@ -52756,9 +52810,7 @@ function buildSessionPresentationProjection(events) {
52756
52810
 
52757
52811
  // src/tui/utils/message-formatter.ts
52758
52812
  function formatUserMessage(content, targetWidth) {
52759
- const theme = getTheme();
52760
52813
  const termCols = typeof targetWidth === "number" && targetWidth > 0 ? targetWidth : process.stdout.columns || 80;
52761
- const bg = themeBgColor(theme.userCardBg);
52762
52814
  const pointer = `${figures.pointerBold} `;
52763
52815
  const prefix = pointer;
52764
52816
  const availableTextWidth = Math.max(10, termCols - 2);
@@ -52774,20 +52826,18 @@ function formatUserMessage(content, targetWidth) {
52774
52826
  isFirstRow = false;
52775
52827
  const visibleLen = visibleWidth(p) + visibleWidth(segment);
52776
52828
  const padLen = Math.max(0, termCols - visibleLen);
52777
- const pStyled = themeColor2(theme.userChevron)(p);
52778
- const textStyled = source_default.white(segment);
52779
- const fullRow = bg(`${pStyled}${textStyled}${" ".repeat(padLen)}`);
52829
+ const pStyled = c.userChevron(p);
52830
+ const textStyled = c.text(segment);
52831
+ const fullRow = bg.userBg(`${pStyled}${textStyled}${" ".repeat(padLen)}`);
52780
52832
  lines.push(fullRow);
52781
52833
  }
52782
52834
  }
52783
52835
  return lines;
52784
52836
  }
52785
52837
  function formatSystemMessage(content) {
52786
- const theme = getTheme();
52787
- const infoColor = themeColor2(theme.permission);
52788
52838
  const rawLines = content.split(`
52789
52839
  `);
52790
- return rawLines.map((l, i) => i === 0 ? ` ${source_default.dim("└ ")}${infoColor(l)}` : ` ${infoColor(l)}`);
52840
+ return rawLines.map((l, i) => i === 0 ? ` ${c.muted("└ ")}${c.permission(l)}` : ` ${c.permission(l)}`);
52791
52841
  }
52792
52842
  function formatAssistantMessage(content) {
52793
52843
  const lines = [];
@@ -52812,7 +52862,7 @@ function formatAssistantMessage(content) {
52812
52862
  continue;
52813
52863
  }
52814
52864
  if (i === 0) {
52815
- const bullet = source_default.white(`${figures.blackCircle} `);
52865
+ const bullet = c.text(`${figures.blackCircle} `);
52816
52866
  lines.push(`${bullet}${l}`);
52817
52867
  } else {
52818
52868
  lines.push(` ${l}`);
@@ -52824,7 +52874,6 @@ function formatAssistantMessage(content) {
52824
52874
  }
52825
52875
  function formatToolStatus(options) {
52826
52876
  const { toolName, displayName, icon, argsSummary, status, error, targetWidth } = options;
52827
- const theme = getTheme();
52828
52877
  const fullTermWidth = typeof targetWidth === "number" && targetWidth > 0 ? targetWidth : process.stdout.columns || 80;
52829
52878
  const bullet = getStatusBullet(status);
52830
52879
  const dispName = displayName ?? icon ?? toolName;
@@ -52833,26 +52882,40 @@ function formatToolStatus(options) {
52833
52882
  const truncatedArg = cleanFirstLine.length > maxArgLen ? truncateMiddle(cleanFirstLine, maxArgLen) : cleanFirstLine;
52834
52883
  let mainLine = `${bullet} ${dispName}`;
52835
52884
  if (truncatedArg) {
52836
- mainLine += `${source_default.dim("(")}${source_default.dim(truncatedArg)}${source_default.dim(")")}`;
52885
+ mainLine += `${c.muted("(")}${c.muted(truncatedArg)}${c.muted(")")}`;
52837
52886
  } else {
52838
- mainLine += `${source_default.dim("()")}`;
52887
+ mainLine += `${c.muted("()")}`;
52839
52888
  }
52840
52889
  const lines = [mainLine];
52841
- if (status === "completed" && options.toolOutput) {
52842
- const cleanOutput = options.toolOutput.trim();
52843
- if (cleanOutput) {
52844
- const outputLines = cleanOutput.split(`
52890
+ const summaryVal = options.summary ?? options.toolOutput;
52891
+ if (status === "completed" && summaryVal) {
52892
+ let headline = "";
52893
+ let detailText = "";
52894
+ if (typeof summaryVal === "string") {
52895
+ const outputLines = summaryVal.trim().split(`
52896
+ `);
52897
+ headline = outputLines[0]?.trim() ?? "";
52898
+ detailText = outputLines.slice(1).join(`
52845
52899
  `);
52846
- const summaryText = outputLines[0]?.trim() ?? "";
52900
+ } else {
52901
+ headline = summaryVal.headline;
52902
+ if (summaryVal.detail) {
52903
+ detailText = renderToolDetail(summaryVal.detail);
52904
+ }
52905
+ }
52906
+ if (headline) {
52847
52907
  const maxOutLen = Math.max(10, fullTermWidth - 6);
52848
- const truncatedSummary = summaryText.length > maxOutLen ? `${summaryText.slice(0, maxOutLen - 1)}…` : summaryText;
52849
- lines.push(` ${source_default.dim("└ ")}${source_default.white(truncatedSummary)}`);
52850
- const maxContentWidth = Math.max(30, Math.min(fullTermWidth - 4, Math.floor(fullTermWidth * 0.85)));
52851
- for (let i = 1;i < outputLines.length; i++) {
52852
- const rawLine = outputLines[i] ?? "";
52853
- const prefixed = ` ${rawLine}`;
52854
- const wrapped = wrapVisualLine(prefixed, maxContentWidth, " ");
52855
- lines.push(...wrapped);
52908
+ const truncatedSummary = headline.length > maxOutLen ? `${headline.slice(0, maxOutLen - 1)}…` : headline;
52909
+ lines.push(` ${c.muted("└ ")}${c.text(truncatedSummary)}`);
52910
+ if (detailText) {
52911
+ const detailLines = detailText.split(`
52912
+ `);
52913
+ const maxContentWidth = Math.max(30, Math.min(fullTermWidth - 4, Math.floor(fullTermWidth * 0.85)));
52914
+ for (const rawLine of detailLines) {
52915
+ const prefixed = ` ${rawLine}`;
52916
+ const wrapped = wrapVisualLine(prefixed, maxContentWidth, " ");
52917
+ lines.push(...wrapped);
52918
+ }
52856
52919
  }
52857
52920
  }
52858
52921
  }
@@ -52862,25 +52925,23 @@ function formatToolStatus(options) {
52862
52925
  `)[0]?.trim() || rawError;
52863
52926
  const maxErrLen = Math.max(10, fullTermWidth - 6);
52864
52927
  const truncatedErr = firstLineErr.length > maxErrLen ? `${firstLineErr.slice(0, maxErrLen - 1)}…` : firstLineErr;
52865
- lines.push(` ${source_default.dim("└ ")}${themeColor2(theme.error)(truncatedErr)}`);
52928
+ lines.push(` ${c.muted("└ ")}${c.error(truncatedErr)}`);
52866
52929
  }
52867
52930
  return lines;
52868
52931
  }
52869
52932
  function formatErrorBadge(error, retryInfo) {
52870
- const theme = getTheme();
52871
- const errColor = themeColor2(theme.error);
52872
- const ast = errColor(figures.asterisk);
52873
- const midDot = source_default.dim(` ${figures.bullet} `);
52933
+ const ast = c.error(figures.asterisk);
52934
+ const midDot = c.muted(` ${figures.bullet} `);
52874
52935
  let msg = error.shortMessage;
52875
52936
  if (retryInfo) {
52876
- const retryStr = source_default.dim(`Retrying in ${retryInfo.countdownSec}s · attempt ${retryInfo.attempt}/${retryInfo.maxAttempts}`);
52877
- msg = `${errColor(error.shortMessage)}${midDot}${retryStr}`;
52937
+ const retryStr = c.muted(`Retrying in ${retryInfo.countdownSec}s · attempt ${retryInfo.attempt}/${retryInfo.maxAttempts}`);
52938
+ msg = `${c.error(error.shortMessage)}${midDot}${retryStr}`;
52878
52939
  } else {
52879
- msg = errColor(error.shortMessage);
52940
+ msg = c.error(error.shortMessage);
52880
52941
  }
52881
52942
  const lines = [`${ast} ${msg}`];
52882
52943
  if (error.suggestedAction) {
52883
- lines.push(` ${source_default.dim("└ ")}${source_default.dim(error.suggestedAction)}`);
52944
+ lines.push(` ${c.muted("└ ")}${c.muted(error.suggestedAction)}`);
52884
52945
  }
52885
52946
  return lines;
52886
52947
  }
@@ -52888,8 +52949,8 @@ function formatTurnStatus(durationMs, timestamp = new Date, verb) {
52888
52949
  const selectedVerb = verb ?? chooseTurnStatusVerb();
52889
52950
  const sec = Math.max(1, Math.round(durationMs / 1000));
52890
52951
  const timeStr = timestamp.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit" });
52891
- const midDot = source_default.dim(` ${figures.bullet} `);
52892
- return `${source_default.dim(`${figures.asterisk} ${selectedVerb} for ${sec}s`)}${midDot}${source_default.dim(`done ${timeStr}`)}`;
52952
+ const midDot = c.muted(` ${figures.bullet} `);
52953
+ return `${c.muted(`${figures.asterisk} ${selectedVerb} for ${sec}s`)}${midDot}${c.muted(`done ${timeStr}`)}`;
52893
52954
  }
52894
52955
 
52895
52956
  // src/tui/engine/HistoryLayoutCache.ts
@@ -53788,15 +53849,7 @@ function saveVoiceLanguage(languageTag) {
53788
53849
  }
53789
53850
  function getSavedTheme() {
53790
53851
  const settings = loadSettings();
53791
- if (settings.theme && typeof settings.theme === "string" && [
53792
- "dark",
53793
- "light",
53794
- "dark-ansi",
53795
- "light-ansi",
53796
- "dark-colorblind",
53797
- "light-colorblind",
53798
- "dracula"
53799
- ].includes(settings.theme)) {
53852
+ if (settings.theme && typeof settings.theme === "string") {
53800
53853
  return settings.theme;
53801
53854
  }
53802
53855
  return;
@@ -54087,6 +54140,25 @@ async function saveCheckpointManifest(workspaceHash, sessionId, manifest) {
54087
54140
  atomicWriteJson(targetPath, manifest);
54088
54141
  });
54089
54142
  }
54143
+ function loadPendingJournal(workspaceHash, sessionId) {
54144
+ const targetPath = getPendingJournalPath(workspaceHash, sessionId);
54145
+ if (!existsSync6(targetPath)) {
54146
+ return null;
54147
+ }
54148
+ try {
54149
+ const raw = readFileSync5(targetPath, "utf-8");
54150
+ const parsed = JSON.parse(raw);
54151
+ const result = PendingJournalSchema.safeParse(parsed);
54152
+ if (result.success) {
54153
+ return result.data;
54154
+ }
54155
+ quarantineCheckpointFile(targetPath);
54156
+ return null;
54157
+ } catch {
54158
+ quarantineCheckpointFile(targetPath);
54159
+ return null;
54160
+ }
54161
+ }
54090
54162
  async function savePendingJournal(workspaceHash, sessionId, journal) {
54091
54163
  const key = `${workspaceHash}:${sessionId}`;
54092
54164
  await storeSerializer.run(key, () => {
@@ -54276,7 +54348,7 @@ class MutationCheckpointTracker {
54276
54348
  };
54277
54349
  await savePendingJournal(this.workspaceHash, this.sessionId, journal);
54278
54350
  }
54279
- async commitTurn(turnId, turnStatus = "complete") {
54351
+ async commitTurn(turnId, _turnStatus = "complete") {
54280
54352
  if (this.activeTurnId !== turnId) {
54281
54353
  return;
54282
54354
  }
@@ -54559,6 +54631,30 @@ async function executeRewind(options) {
54559
54631
  releaseLocks();
54560
54632
  }
54561
54633
  }
54634
+ async function recoverPendingCheckpoint(workspaceRoot, sessionId) {
54635
+ const workspaceHash = computeWorkspaceHash(workspaceRoot);
54636
+ const journal = loadPendingJournal(workspaceHash, sessionId);
54637
+ if (!journal)
54638
+ return;
54639
+ if (journal.kind === "rewind") {
54640
+ if (journal.phase === "files-restored" || journal.phase === "files-pending") {
54641
+ for (const file of journal.files) {
54642
+ if (file.post) {
54643
+ const absPath = resolve3(workspaceRoot, file.relativePath);
54644
+ try {
54645
+ restoreFileStateToDisk(workspaceHash, absPath, file.post);
54646
+ } catch {}
54647
+ }
54648
+ }
54649
+ }
54650
+ await deletePendingJournal(workspaceHash, sessionId);
54651
+ } else {
54652
+ const committedFiles = journal.files.filter((f) => f.mutationCommitted);
54653
+ if (committedFiles.length === 0) {
54654
+ await deletePendingJournal(workspaceHash, sessionId);
54655
+ }
54656
+ }
54657
+ }
54562
54658
  // node_modules/@ai-sdk/provider/dist/index.js
54563
54659
  var marker = "vercel.ai.error";
54564
54660
  var symbol = Symbol.for(marker);
@@ -71405,6 +71501,72 @@ var originalGenerateCallId6 = createIdGenerator({
71405
71501
  });
71406
71502
  var defaultDownload2 = createDownload();
71407
71503
 
71504
+ // src/engine/mode.ts
71505
+ var MODES = {
71506
+ normal: {
71507
+ name: "normal",
71508
+ label: "Normal",
71509
+ description: "All tools with file and bash permission prompts",
71510
+ color: "text",
71511
+ allows: ["read", "write", "exec"],
71512
+ autoApproveFiles: false
71513
+ },
71514
+ chat: {
71515
+ name: "chat",
71516
+ label: "Chat",
71517
+ description: "Conversation only — no tool access",
71518
+ color: "info",
71519
+ allows: [],
71520
+ autoApproveFiles: false
71521
+ },
71522
+ review: {
71523
+ name: "review",
71524
+ label: "Review",
71525
+ description: "Read-only tools only — cannot modify files or run commands",
71526
+ color: "warning",
71527
+ allows: ["read"],
71528
+ autoApproveFiles: false
71529
+ },
71530
+ build: {
71531
+ name: "build",
71532
+ label: "Build",
71533
+ description: "All tools, file mutations auto-approved, bash still prompts",
71534
+ color: "success",
71535
+ allows: ["read", "write", "exec"],
71536
+ autoApproveFiles: true
71537
+ }
71538
+ };
71539
+ var isAllowed = (m, a) => {
71540
+ const modeMeta = MODES[m];
71541
+ if (!modeMeta)
71542
+ return false;
71543
+ return modeMeta.allows.includes(a);
71544
+ };
71545
+ var MODE_ORDER = ["normal", "chat", "review", "build"];
71546
+ var activeMode = "normal";
71547
+ function getActiveMode() {
71548
+ return activeMode;
71549
+ }
71550
+ function setActiveMode(name) {
71551
+ if (name in MODES) {
71552
+ activeMode = name;
71553
+ }
71554
+ }
71555
+ function cycleMode() {
71556
+ const idx = MODE_ORDER.indexOf(activeMode);
71557
+ activeMode = MODE_ORDER[(idx + 1) % MODE_ORDER.length];
71558
+ return activeMode;
71559
+ }
71560
+ function listModes() {
71561
+ return Object.values(MODES);
71562
+ }
71563
+ function findMode(query) {
71564
+ const q = query.trim().toLowerCase();
71565
+ if (!q)
71566
+ return;
71567
+ return listModes().find((m) => m.name === q || m.label.toLowerCase() === q || m.label.toLowerCase().startsWith(q));
71568
+ }
71569
+
71408
71570
  // src/tools/catalog.ts
71409
71571
  class ToolCatalog {
71410
71572
  tools = new Map;
@@ -71423,11 +71585,19 @@ class ToolCatalog {
71423
71585
  }
71424
71586
  toAISDKTools(context) {
71425
71587
  const aiTools = {};
71588
+ const mode = context.mode ?? "normal";
71426
71589
  for (const [name, def] of this.tools.entries()) {
71590
+ if (!isAllowed(mode, def.access)) {
71591
+ continue;
71592
+ }
71427
71593
  aiTools[name] = tool({
71428
71594
  description: def.description,
71429
71595
  inputSchema: def.parameters,
71430
71596
  execute: async (args) => {
71597
+ if (!isAllowed(mode, def.access)) {
71598
+ const modeLabel = MODES[mode]?.label ?? mode;
71599
+ throw new Error(`Tool "${name}" is not available in ${modeLabel} mode.`);
71600
+ }
71431
71601
  return def.execute(args, context);
71432
71602
  }
71433
71603
  });
@@ -71496,6 +71666,7 @@ function isBinaryBuffer(buffer) {
71496
71666
  var readFileTool = {
71497
71667
  name: "read_file",
71498
71668
  displayName: "Read",
71669
+ access: "read",
71499
71670
  description: "Reads the contents of a file. Supports reading specific line ranges via offset and limit. Read is read-only and does not mutate or checkpoint.",
71500
71671
  parameters: readFileInputSchema,
71501
71672
  confirmationPolicy: "never",
@@ -71553,82 +71724,6 @@ var readFileTool = {
71553
71724
  }
71554
71725
  };
71555
71726
 
71556
- // src/engine/chat-mode.ts
71557
- var CHAT_MODES = {
71558
- normal: {
71559
- name: "normal",
71560
- label: "Normal",
71561
- description: "All tools with file and bash permission prompts",
71562
- themeColorKey: "text"
71563
- },
71564
- chat: {
71565
- name: "chat",
71566
- label: "Chat",
71567
- description: "Conversation only — no tool access",
71568
- themeColorKey: "info"
71569
- },
71570
- review: {
71571
- name: "review",
71572
- label: "Review",
71573
- description: "Read-only tools only — cannot modify files or run commands",
71574
- themeColorKey: "warning"
71575
- },
71576
- build: {
71577
- name: "build",
71578
- label: "Build",
71579
- description: "All tools, file mutations auto-approved, bash still prompts",
71580
- themeColorKey: "success"
71581
- }
71582
- };
71583
- var MODE_ORDER = ["normal", "chat", "review", "build"];
71584
- var activeMode = "normal";
71585
- function getActiveMode() {
71586
- return activeMode;
71587
- }
71588
- function setActiveMode(name) {
71589
- if (name in CHAT_MODES)
71590
- activeMode = name;
71591
- }
71592
- function cycleMode() {
71593
- const idx = MODE_ORDER.indexOf(activeMode);
71594
- activeMode = MODE_ORDER[(idx + 1) % MODE_ORDER.length];
71595
- return activeMode;
71596
- }
71597
- function listModes() {
71598
- return Object.values(CHAT_MODES);
71599
- }
71600
- function findMode(query) {
71601
- const q = query.trim().toLowerCase();
71602
- if (!q)
71603
- return;
71604
- return listModes().find((m) => m.name === q || m.label.toLowerCase() === q || m.label.toLowerCase().startsWith(q));
71605
- }
71606
- var REVIEW_ALLOWED_TOOLS = new Set([
71607
- "read_file",
71608
- "glob",
71609
- "grep",
71610
- "list_dir",
71611
- "web_fetch",
71612
- "web_search",
71613
- "todo_read",
71614
- "skill_list",
71615
- "skill_read",
71616
- "task_list",
71617
- "task_read",
71618
- "sleep"
71619
- ]);
71620
- function assertToolAllowed(toolName) {
71621
- const mode = activeMode;
71622
- if (mode === "normal" || mode === "build")
71623
- return;
71624
- if (mode === "chat") {
71625
- throw new Error(`Tool "${toolName}" is not available in Chat mode. Chat mode is for conversation only — no tool access. Switch to Normal or Build mode with /mode or Ctrl+B.`);
71626
- }
71627
- if (mode === "review" && !REVIEW_ALLOWED_TOOLS.has(toolName)) {
71628
- throw new Error(`Tool "${toolName}" is not available in Review mode. Review mode only allows read-only operations. Switch to Normal or Build mode with /mode or Ctrl+B.`);
71629
- }
71630
- }
71631
-
71632
71727
  // src/tools/write-file/index.ts
71633
71728
  import { existsSync as existsSync11, readFileSync as readFileSync9, statSync as statSync3 } from "node:fs";
71634
71729
 
@@ -71688,6 +71783,7 @@ var writeFileInputSchema = object({
71688
71783
  var writeFileTool = {
71689
71784
  name: "write_file",
71690
71785
  displayName: "Write",
71786
+ access: "write",
71691
71787
  description: "Writes or creates a whole file in the workspace. Automatically creates parent directories if needed. Every write mutation participates in checkpointing for /rewind.",
71692
71788
  parameters: writeFileInputSchema,
71693
71789
  confirmationPolicy: "never",
@@ -71695,24 +71791,18 @@ var writeFileTool = {
71695
71791
  const lines = result?.linesWritten ?? 0;
71696
71792
  const filePath = args.file_path;
71697
71793
  const isNew = result?.isNew ?? true;
71698
- const summary = isNew ? `Created ${filePath} (${lines} line${lines === 1 ? "" : "s"})` : `Wrote ${lines} line${lines === 1 ? "" : "s"} to ${filePath}`;
71699
- const highlighted = highlightCode(args.content, { filePath: args.file_path });
71700
- const contentLines = highlighted.split(/\r?\n/);
71701
- if (contentLines.length === 0 || contentLines.length === 1 && !contentLines[0]) {
71702
- return summary;
71703
- }
71704
- const cap = 50;
71705
- const shown = contentLines.slice(0, cap);
71706
- const padWidth = String(contentLines.length).length;
71707
- const detail = shown.map((l, i) => `${source_default.dim(String(i + 1).padStart(padWidth))} ${l}`).join(`
71708
- `);
71709
- const overflow = contentLines.length > cap ? `
71710
- … (${contentLines.length - cap} more lines)` : "";
71711
- return `${summary}
71712
- ${detail}${overflow}`;
71794
+ const headline = isNew ? `Created ${filePath} (${lines} line${lines === 1 ? "" : "s"})` : `Wrote ${lines} line${lines === 1 ? "" : "s"} to ${filePath}`;
71795
+ return {
71796
+ headline,
71797
+ detail: {
71798
+ kind: "code",
71799
+ filePath: args.file_path,
71800
+ text: args.content,
71801
+ totalLines: lines
71802
+ }
71803
+ };
71713
71804
  },
71714
71805
  execute: async (args, context) => {
71715
- assertToolAllowed("write_file");
71716
71806
  const { absolutePath: targetPath, relativePath } = resolveDirectMutationPath(context.cwd, args.file_path);
71717
71807
  const isNew = !existsSync11(targetPath);
71718
71808
  const beforeContent = isNew ? null : readFileSync9(targetPath, "utf-8");
@@ -72041,65 +72131,27 @@ function countOccurrences(content, substring) {
72041
72131
  var editFileTool = {
72042
72132
  name: "edit_file",
72043
72133
  displayName: "Edit",
72134
+ access: "write",
72044
72135
  description: "Performs exact string replacements in an existing file. Every edit mutation participates in checkpointing for /rewind.",
72045
72136
  parameters: editFileInputSchema,
72046
72137
  confirmationPolicy: "never",
72047
72138
  summarize: (args, result) => {
72048
72139
  const added = result?.addedLines ?? 0;
72049
72140
  const removed = result?.removedLines ?? 0;
72050
- const summary = `Added ${added} line${added === 1 ? "" : "s"}, removed ${removed} line${removed === 1 ? "" : "s"}`;
72141
+ const headline = `Added ${added} line${added === 1 ? "" : "s"}, removed ${removed} line${removed === 1 ? "" : "s"}`;
72051
72142
  if (added === 0 && removed === 0)
72052
- return summary;
72143
+ return { headline };
72053
72144
  const diff = buildUnifiedDiff(args.old_string, args.new_string, 2);
72054
- const theme = getTheme();
72055
- const deleteStyle = (str) => themeBgColor(theme.diffDeleteBG)(themeColor2(theme.diffDeleteFG)(str));
72056
- const addStyle = (str) => themeBgColor(theme.diffAddBG)(themeColor2(theme.diffAddFG)(str));
72057
- const contextStyle = (str) => source_default.dim(str);
72058
- let maxLineNum = 1;
72059
- for (const hunk of diff.hunks) {
72060
- for (const line of hunk.lines) {
72061
- if (line.oldLineNumber)
72062
- maxLineNum = Math.max(maxLineNum, line.oldLineNumber);
72063
- if (line.newLineNumber)
72064
- maxLineNum = Math.max(maxLineNum, line.newLineNumber);
72065
- }
72066
- }
72067
- const padWidth = Math.max(1, String(maxLineNum).length);
72068
- const diffLines = [];
72069
- const cap = 30;
72070
- let count = 0;
72071
- let overflow = 0;
72072
- for (const hunk of diff.hunks) {
72073
- for (const line of hunk.lines) {
72074
- if (count >= cap) {
72075
- overflow++;
72076
- continue;
72077
- }
72078
- count++;
72079
- if (line.kind === "deletion") {
72080
- const numStr = String(line.oldLineNumber ?? "").padStart(padWidth, " ");
72081
- const body = line.spans ? "-" + line.spans.map((s) => s.kind === "deletion" ? source_default.bold(s.text) : s.text).join("") : `-${line.text}`;
72082
- diffLines.push(deleteStyle(`${numStr} ${body}`));
72083
- } else if (line.kind === "addition") {
72084
- const numStr = String(line.newLineNumber ?? "").padStart(padWidth, " ");
72085
- const body = line.spans ? "+" + line.spans.map((s) => s.kind === "addition" ? source_default.bold(s.text) : s.text).join("") : `+${line.text}`;
72086
- diffLines.push(addStyle(`${numStr} ${body}`));
72087
- } else {
72088
- const numStr = String(line.newLineNumber ?? line.oldLineNumber ?? "").padStart(padWidth, " ");
72089
- const highlightedContext = highlightCode(line.text, { filePath: args.file_path });
72090
- diffLines.push(`${contextStyle(`${numStr} `)} ${highlightedContext}`);
72091
- }
72145
+ return {
72146
+ headline,
72147
+ detail: {
72148
+ kind: "diff",
72149
+ filePath: args.file_path,
72150
+ hunks: diff.hunks
72092
72151
  }
72093
- }
72094
- if (overflow > 0) {
72095
- diffLines.push(source_default.dim(` … (${overflow} more lines)`));
72096
- }
72097
- return diffLines.length > 0 ? `${summary}
72098
- ${diffLines.join(`
72099
- `)}` : summary;
72152
+ };
72100
72153
  },
72101
72154
  execute: async (args, context) => {
72102
- assertToolAllowed("edit_file");
72103
72155
  const { absolutePath: targetPath, relativePath } = resolveDirectMutationPath(context.cwd, args.file_path);
72104
72156
  if (!existsSync12(targetPath)) {
72105
72157
  throw new Error(`Cannot edit file because it does not exist: "${args.file_path}". Use write_file to create new files.`);
@@ -72239,6 +72291,7 @@ function walkDir(dir, baseDir, matcher, results, limit) {
72239
72291
  var globTool = {
72240
72292
  name: "glob",
72241
72293
  displayName: "Glob",
72294
+ access: "read",
72242
72295
  description: "Finds files matching a glob pattern or file name in the workspace. Read-only search capability with bounded results.",
72243
72296
  parameters: globInputSchema,
72244
72297
  confirmationPolicy: "never",
@@ -72342,6 +72395,7 @@ function searchInDir(dir, baseDir, regex, fileFilter, results, filesWithMatches,
72342
72395
  var grepTool = {
72343
72396
  name: "grep",
72344
72397
  displayName: "Grep",
72398
+ access: "read",
72345
72399
  description: "Searches for text or regex patterns across files in the workspace. Read-only content search with structured match positions.",
72346
72400
  parameters: grepInputSchema,
72347
72401
  confirmationPolicy: "never",
@@ -72421,6 +72475,7 @@ var listDirInputSchema = object({
72421
72475
  var listDirTool = {
72422
72476
  name: "list_dir",
72423
72477
  displayName: "List",
72478
+ access: "read",
72424
72479
  description: "Lists files and folders in a specified directory. Read-only operation.",
72425
72480
  parameters: listDirInputSchema,
72426
72481
  confirmationPolicy: "never",
@@ -72481,6 +72536,7 @@ var sleepInputSchema = object({
72481
72536
  var sleepTool = {
72482
72537
  name: "sleep",
72483
72538
  displayName: "Sleep",
72539
+ access: "read",
72484
72540
  description: "Pauses current agent execution temporarily (between 1 and 300 seconds). Read-only and cancellable.",
72485
72541
  parameters: sleepInputSchema,
72486
72542
  confirmationPolicy: "never",
@@ -72650,7 +72706,7 @@ class ShellExecution {
72650
72706
  };
72651
72707
  child.stdout?.on("data", (chunk) => handleChunk(chunk, false));
72652
72708
  child.stderr?.on("data", (chunk) => handleChunk(chunk, true));
72653
- const onExit = (code, signal) => {
72709
+ const onExit = (code, _signal) => {
72654
72710
  if (!this.isRunning)
72655
72711
  return;
72656
72712
  this.endedAt = new Date().toISOString();
@@ -73106,6 +73162,7 @@ var bashInputSchema = object({
73106
73162
  var bashTool = {
73107
73163
  name: "bash",
73108
73164
  displayName: "Bash",
73165
+ access: "exec",
73109
73166
  description: "Executes a command in the platform shell. An explanation of what the command does and why it is needed is MANDATORY. Commands that exceed the foreground limit (~12s) automatically continue as background shell tasks. Use task_read, task_send_input, and task_kill to manage background tasks. Note: Bash commands are NOT tracked by the file checkpoint system (/rewind).",
73110
73167
  parameters: bashInputSchema,
73111
73168
  confirmationPolicy: "never",
@@ -73120,7 +73177,6 @@ var bashTool = {
73120
73177
  return `Ran successfully · exit code: ${code}`;
73121
73178
  },
73122
73179
  execute: async (args, context) => {
73123
- assertToolAllowed("bash");
73124
73180
  const command = typeof args?.command === "string" ? args.command.trim() : "";
73125
73181
  if (!command) {
73126
73182
  throw new Error("Command is required and cannot be empty.");
@@ -73179,6 +73235,7 @@ var taskReadInputSchema = object({
73179
73235
  var taskReadTool = {
73180
73236
  name: "task_read",
73181
73237
  displayName: "Task Read",
73238
+ access: "read",
73182
73239
  description: "Reads current status, exit code, and recent bounded output snapshot of a background shell task. Non-blocking.",
73183
73240
  parameters: taskReadInputSchema,
73184
73241
  confirmationPolicy: "never",
@@ -73213,6 +73270,7 @@ function normalizeStdinInput(rawInput, appendNewline = true) {
73213
73270
  var taskSendInputTool = {
73214
73271
  name: "task_send_input",
73215
73272
  displayName: "Task Send Input",
73273
+ access: "exec",
73216
73274
  description: "Writes input text to the standard input (stdin) of a running background shell task. Automatically appends a newline unless append_newline is set to false.",
73217
73275
  parameters: taskSendInputSchema,
73218
73276
  confirmationPolicy: "never",
@@ -73220,7 +73278,6 @@ var taskSendInputTool = {
73220
73278
  return `Sent input to ${args.task_id} (${args.input.length} chars)`;
73221
73279
  },
73222
73280
  execute: async (args, context) => {
73223
- assertToolAllowed("task_send_input");
73224
73281
  if (!context.shellTasks) {
73225
73282
  throw new Error("No shell tasks manager available in execution context.");
73226
73283
  }
@@ -73237,6 +73294,7 @@ var taskKillInputSchema = object({
73237
73294
  var taskKillTool = {
73238
73295
  name: "task_kill",
73239
73296
  displayName: "Task Kill",
73297
+ access: "exec",
73240
73298
  description: "Terminates a running background shell task and its descendant process tree.",
73241
73299
  parameters: taskKillInputSchema,
73242
73300
  confirmationPolicy: "never",
@@ -73244,7 +73302,6 @@ var taskKillTool = {
73244
73302
  return `Stopped task ${args.task_id} · status: ${result?.status ?? "killed"}`;
73245
73303
  },
73246
73304
  execute: async (args, context) => {
73247
- assertToolAllowed("task_kill");
73248
73305
  if (!context.shellTasks) {
73249
73306
  throw new Error("No shell tasks manager available in execution context.");
73250
73307
  }
@@ -73257,6 +73314,7 @@ var taskListInputSchema = object({});
73257
73314
  var taskListTool = {
73258
73315
  name: "task_list",
73259
73316
  displayName: "Task List",
73317
+ access: "read",
73260
73318
  description: "Lists all currently tracked background shell tasks along with their IDs, statuses, commands, and exit codes.",
73261
73319
  parameters: taskListInputSchema,
73262
73320
  confirmationPolicy: "never",
@@ -73278,7 +73336,7 @@ var taskListTool = {
73278
73336
  // package.json
73279
73337
  var package_default = {
73280
73338
  name: "steward-cli",
73281
- version: "0.16.0",
73339
+ version: "0.17.0",
73282
73340
  description: "Interactive AI engineering assistant for the terminal with human-in-the-loop control across local and frontier models.",
73283
73341
  author: "sapirrior",
73284
73342
  license: "MIT",
@@ -73340,6 +73398,7 @@ function cleanHtmlContent(html) {
73340
73398
  var webFetchTool = {
73341
73399
  name: "web_fetch",
73342
73400
  displayName: "Web",
73401
+ access: "read",
73343
73402
  description: "Fetches text and documentation content from a public web URL. Automatically cleans HTML markup into readable text.",
73344
73403
  parameters: webFetchInputSchema,
73345
73404
  confirmationPolicy: "never",
@@ -73471,6 +73530,7 @@ async function searchDuckDuckGoDirect(query, limit, signal) {
73471
73530
  var webSearchTool = {
73472
73531
  name: "web_search",
73473
73532
  displayName: "Web Search",
73533
+ access: "read",
73474
73534
  description: "Searches the web directly for up-to-date information, documentation, package releases, and technical answers. Returns structured search results with titles, clean URLs, and snippets.",
73475
73535
  parameters: webSearchInputSchema,
73476
73536
  confirmationPolicy: "never",
@@ -73855,6 +73915,7 @@ var todoWriteTool = {
73855
73915
  name: "todo_write",
73856
73916
  displayName: "TodoWrite",
73857
73917
  icon: "\uD83D\uDCDD",
73918
+ access: "write",
73858
73919
  description: "Initializes or replaces the current session todo list with 2 to 10 items. Use this to establish or replace the multi-step execution plan for the session.",
73859
73920
  parameters: todoWriteParamsSchema,
73860
73921
  summarizeArgs(args) {
@@ -73916,6 +73977,7 @@ var todoUpdateTool = {
73916
73977
  name: "todo_update",
73917
73978
  displayName: "TodoUpdate",
73918
73979
  icon: "✓",
73980
+ access: "write",
73919
73981
  description: "Updates a single todo item status or description in the current session. Cannot create new items or update multiple items at once.",
73920
73982
  parameters: todoUpdateParamsSchema,
73921
73983
  summarizeArgs(args) {
@@ -73981,6 +74043,7 @@ var todoReadTool = {
73981
74043
  name: "todo_read",
73982
74044
  displayName: "TodoRead",
73983
74045
  icon: "\uD83D\uDCCB",
74046
+ access: "read",
73984
74047
  description: "Reads the current session todo list without modifying it. Returns an empty result if no todos have been established yet.",
73985
74048
  parameters: todoReadParamsSchema,
73986
74049
  summarizeArgs() {
@@ -74166,6 +74229,7 @@ var skillListTool = {
74166
74229
  name: "skill_list",
74167
74230
  displayName: "SkillList",
74168
74231
  icon: "\uD83D\uDCA1",
74232
+ access: "read",
74169
74233
  description: "Discovers and lists all available specialized skills and their descriptions. Use this when you need specialized domain knowledge or workflows.",
74170
74234
  parameters: skillListParamsSchema,
74171
74235
  summarizeArgs() {
@@ -74198,6 +74262,7 @@ var skillReadTool = {
74198
74262
  name: "skill_read",
74199
74263
  displayName: "SkillRead",
74200
74264
  icon: "\uD83D\uDCD6",
74265
+ access: "read",
74201
74266
  description: "Loads and reads the instructions (SKILL.md) or a relative resource file of a specialized skill by name. Use this when a task requires specialized guidelines.",
74202
74267
  parameters: skillReadParamsSchema,
74203
74268
  summarizeArgs(args) {
@@ -74216,6 +74281,108 @@ var skillReadTool = {
74216
74281
  return `SkillRead: ${target}${len}`;
74217
74282
  }
74218
74283
  };
74284
+ // src/tools/summary.ts
74285
+ function summarizeToolResult(toolDef, args, result, isError = false) {
74286
+ if (isError)
74287
+ return;
74288
+ if (!toolDef) {
74289
+ if (typeof result === "string") {
74290
+ const firstLine = result.split(`
74291
+ `)[0]?.trim();
74292
+ return firstLine ? { headline: firstLine } : undefined;
74293
+ }
74294
+ if (result && typeof result === "object" && typeof result.message === "string") {
74295
+ return { headline: result.message };
74296
+ }
74297
+ return;
74298
+ }
74299
+ if (toolDef.summarize) {
74300
+ const sum = toolDef.summarize(args, result);
74301
+ if (typeof sum === "string") {
74302
+ const [headline, ...rest] = sum.split(`
74303
+ `);
74304
+ return {
74305
+ headline: headline ?? "",
74306
+ detail: rest.length > 0 ? { kind: "text", text: rest.join(`
74307
+ `) } : undefined
74308
+ };
74309
+ }
74310
+ return sum;
74311
+ }
74312
+ if (typeof result === "string") {
74313
+ const firstLine = result.split(`
74314
+ `)[0]?.trim();
74315
+ return { headline: firstLine || toolDef.displayName };
74316
+ }
74317
+ if (result && typeof result === "object" && typeof result.message === "string") {
74318
+ return { headline: result.message };
74319
+ }
74320
+ return { headline: toolDef.displayName };
74321
+ }
74322
+ function formatPlainToolSummary(summary) {
74323
+ if (!summary)
74324
+ return;
74325
+ if (!summary.detail)
74326
+ return summary.headline;
74327
+ if (summary.detail.kind === "text") {
74328
+ return `${summary.headline}
74329
+ ${summary.detail.text}`;
74330
+ }
74331
+ if (summary.detail.kind === "code") {
74332
+ const lines = summary.detail.text.split(/\r?\n/);
74333
+ const cap = 50;
74334
+ const shown = lines.slice(0, cap);
74335
+ const padWidth = String(lines.length).length;
74336
+ const detail = shown.map((l, i) => `${String(i + 1).padStart(padWidth)} ${l}`).join(`
74337
+ `);
74338
+ const overflow = lines.length > cap ? `
74339
+ … (${lines.length - cap} more lines)` : "";
74340
+ return `${summary.headline}
74341
+ ${detail}${overflow}`;
74342
+ }
74343
+ if (summary.detail.kind === "diff") {
74344
+ const diffLines = [];
74345
+ let maxLineNum = 1;
74346
+ for (const hunk of summary.detail.hunks) {
74347
+ for (const line of hunk.lines) {
74348
+ if (line.oldLineNumber)
74349
+ maxLineNum = Math.max(maxLineNum, line.oldLineNumber);
74350
+ if (line.newLineNumber)
74351
+ maxLineNum = Math.max(maxLineNum, line.newLineNumber);
74352
+ }
74353
+ }
74354
+ const padWidth = Math.max(1, String(maxLineNum).length);
74355
+ const cap = 30;
74356
+ let count = 0;
74357
+ let overflow = 0;
74358
+ for (const hunk of summary.detail.hunks) {
74359
+ for (const line of hunk.lines) {
74360
+ if (count >= cap) {
74361
+ overflow++;
74362
+ continue;
74363
+ }
74364
+ count++;
74365
+ if (line.kind === "deletion") {
74366
+ const numStr = String(line.oldLineNumber ?? "").padStart(padWidth, " ");
74367
+ diffLines.push(`${numStr} -${line.text}`);
74368
+ } else if (line.kind === "addition") {
74369
+ const numStr = String(line.newLineNumber ?? "").padStart(padWidth, " ");
74370
+ diffLines.push(`${numStr} +${line.text}`);
74371
+ } else {
74372
+ const numStr = String(line.newLineNumber ?? line.oldLineNumber ?? "").padStart(padWidth, " ");
74373
+ diffLines.push(`${numStr} ${line.text}`);
74374
+ }
74375
+ }
74376
+ }
74377
+ if (overflow > 0) {
74378
+ diffLines.push(` … (${overflow} more lines)`);
74379
+ }
74380
+ return diffLines.length > 0 ? `${summary.headline}
74381
+ ${diffLines.join(`
74382
+ `)}` : summary.headline;
74383
+ }
74384
+ return summary.headline;
74385
+ }
74219
74386
 
74220
74387
  // src/tools/index.ts
74221
74388
  var builtInTools = [
@@ -118234,8 +118401,7 @@ var PROVIDER_REGISTRY = {
118234
118401
  envVar: "DEEPSEEK_API_KEY",
118235
118402
  apiKey: (c) => c.deepseekApiKey,
118236
118403
  defaultModel: "deepseek-chat",
118237
- create: (apiKey) => createDeepSeek({ apiKey }),
118238
- isTaggedReasoning: () => true
118404
+ create: (apiKey) => createDeepSeek({ apiKey })
118239
118405
  },
118240
118406
  openrouter: {
118241
118407
  name: "openrouter",
@@ -118250,8 +118416,7 @@ var PROVIDER_REGISTRY = {
118250
118416
  "HTTP-Referer": "https://github.com/sapirrior/steward",
118251
118417
  "X-Title": "steward"
118252
118418
  }
118253
- }),
118254
- isTaggedReasoning: (modelId) => isTaggedReasoningModel(modelId)
118419
+ })
118255
118420
  },
118256
118421
  custom: {
118257
118422
  name: "custom",
@@ -118262,20 +118427,9 @@ var PROVIDER_REGISTRY = {
118262
118427
  name: "custom",
118263
118428
  baseURL: cfg.custom.baseURL,
118264
118429
  apiKey: cfg.custom.apiKey
118265
- }),
118266
- isTaggedReasoning: (modelId) => isTaggedReasoningModel(modelId)
118430
+ })
118267
118431
  }
118268
118432
  };
118269
- var DEFAULT_MODELS_BY_PROVIDER = {
118270
- gemini: PROVIDER_REGISTRY.gemini.defaultModel,
118271
- anthropic: PROVIDER_REGISTRY.anthropic.defaultModel,
118272
- openai: PROVIDER_REGISTRY.openai.defaultModel,
118273
- xai: PROVIDER_REGISTRY.xai.defaultModel,
118274
- mistral: PROVIDER_REGISTRY.mistral.defaultModel,
118275
- deepseek: PROVIDER_REGISTRY.deepseek.defaultModel,
118276
- openrouter: PROVIDER_REGISTRY.openrouter.defaultModel,
118277
- custom: PROVIDER_REGISTRY.custom.defaultModel
118278
- };
118279
118433
  var DEFAULT_REASONING_EFFORT = "provider-default";
118280
118434
  var REASONING_EFFORT_MAP = {
118281
118435
  0: "provider-default",
@@ -118285,13 +118439,6 @@ var REASONING_EFFORT_MAP = {
118285
118439
  4: "medium",
118286
118440
  5: "high",
118287
118441
  6: "xhigh",
118288
- "0": "provider-default",
118289
- "1": "none",
118290
- "2": "minimal",
118291
- "3": "low",
118292
- "4": "medium",
118293
- "5": "high",
118294
- "6": "xhigh",
118295
118442
  default: "provider-default",
118296
118443
  "provider-default": "provider-default",
118297
118444
  none: "none",
@@ -118338,7 +118485,7 @@ function resolveActiveModelSelection(requested, config = getEnvConfig()) {
118338
118485
  if (!hasProviderConfig(requested.provider, config)) {
118339
118486
  throw new Error(`Provider "${requested.provider}" was requested, but its credentials are not configured in the environment.`);
118340
118487
  }
118341
- const modelId = requested.provider === "custom" ? config.custom.modelName || DEFAULT_MODELS_BY_PROVIDER.custom : DEFAULT_MODELS_BY_PROVIDER[requested.provider];
118488
+ const modelId = requested.provider === "custom" ? config.custom.modelName || PROVIDER_REGISTRY.custom.defaultModel : PROVIDER_REGISTRY[requested.provider].defaultModel;
118342
118489
  return {
118343
118490
  provider: requested.provider,
118344
118491
  modelId,
@@ -118368,7 +118515,7 @@ function resolveActiveModelSelection(requested, config = getEnvConfig()) {
118368
118515
  }
118369
118516
  for (const provider of PROVIDER_SELECTION_PRIORITY) {
118370
118517
  if (available.includes(provider)) {
118371
- const modelId = provider === "custom" ? config.custom.modelName || DEFAULT_MODELS_BY_PROVIDER.custom : DEFAULT_MODELS_BY_PROVIDER[provider];
118518
+ const modelId = provider === "custom" ? config.custom.modelName || PROVIDER_REGISTRY.custom.defaultModel : PROVIDER_REGISTRY[provider].defaultModel;
118372
118519
  return {
118373
118520
  provider,
118374
118521
  modelId,
@@ -118379,7 +118526,7 @@ function resolveActiveModelSelection(requested, config = getEnvConfig()) {
118379
118526
  const fallbackProvider = available[0];
118380
118527
  return {
118381
118528
  provider: fallbackProvider,
118382
- modelId: DEFAULT_MODELS_BY_PROVIDER[fallbackProvider],
118529
+ modelId: PROVIDER_REGISTRY[fallbackProvider].defaultModel,
118383
118530
  effort
118384
118531
  };
118385
118532
  }
@@ -118393,15 +118540,7 @@ function createModelInstance(selection, config = getEnvConfig()) {
118393
118540
  throw new Error(`${descriptor.envVar} is not configured in the environment.`);
118394
118541
  }
118395
118542
  const modelId = selection.provider === "custom" ? config.custom.modelName || selection.modelId : selection.modelId;
118396
- const baseModel = descriptor.create(apiKey, config)(modelId);
118397
- return applyModelMiddlewarePipeline(baseModel, selection, descriptor);
118398
- }
118399
- function applyModelMiddlewarePipeline(model, _selection, _descriptor) {
118400
- return model;
118401
- }
118402
- function isTaggedReasoningModel(modelId) {
118403
- const lower = modelId.toLowerCase();
118404
- return lower.startsWith("deepseek-r1") || lower.includes("/deepseek-r1") || lower.includes("deepseek-reasoner") || lower === "r1" || lower.endsWith("-r1") || lower.startsWith("qwq") || lower.includes("qwen") && lower.includes("think");
118543
+ return descriptor.create(apiKey, config)(modelId);
118405
118544
  }
118406
118545
  function inferProviderFromModelId(modelId) {
118407
118546
  const lower = modelId.toLowerCase();
@@ -118487,22 +118626,29 @@ ${options.userRules.map((rule) => `- ${rule}`).join(`
118487
118626
  ${options.extraInstructions}
118488
118627
  </additional_instructions>`;
118489
118628
  }
118490
- const modeBlocks = {
118491
- chat: `
118629
+ if (options.chatMode && options.chatMode !== "normal") {
118630
+ const meta = MODES[options.chatMode];
118631
+ if (meta) {
118632
+ if (options.chatMode === "chat") {
118633
+ prompt += `
118634
+
118492
118635
  <operating_mode>
118493
118636
  Mode: CHAT — You have no tool access. Respond conversationally only. Do not attempt to call any tools.
118494
- </operating_mode>`,
118495
- review: `
118637
+ </operating_mode>`;
118638
+ } else if (options.chatMode === "review") {
118639
+ prompt += `
118640
+
118496
118641
  <operating_mode>
118497
- Mode: REVIEW — You may only use read-only tools: read_file, glob, grep, list_dir, web_fetch, web_search, todo_read, skill_list, skill_read, task_list, task_read. Any attempt to write files, run commands, or mutate state will be blocked by the tool itself.
118498
- </operating_mode>`,
118499
- build: `
118642
+ Mode: REVIEW — You may only use read-only tools. Any attempt to write files, run commands, or mutate state will be blocked.
118643
+ </operating_mode>`;
118644
+ } else if (options.chatMode === "build") {
118645
+ prompt += `
118646
+
118500
118647
  <operating_mode>
118501
118648
  Mode: BUILD — You have full tool access. File writes and edits are automatically approved without user confirmation — act decisively and make changes directly. Bash commands still require user approval.
118502
- </operating_mode>`
118503
- };
118504
- if (options.chatMode && modeBlocks[options.chatMode]) {
118505
- prompt += modeBlocks[options.chatMode];
118649
+ </operating_mode>`;
118650
+ }
118651
+ }
118506
118652
  }
118507
118653
  return prompt;
118508
118654
  }
@@ -118655,9 +118801,10 @@ class AgentSession {
118655
118801
  });
118656
118802
  await tracker.beginTurn(turnId, this.sessionData.turns.length + 1);
118657
118803
  const mode = getActiveMode();
118658
- const effectiveFilePermission = mode === "build" ? async (_req) => ({ allowed: true }) : options.requestFilePermission;
118804
+ const effectiveFilePermission = MODES[mode]?.autoApproveFiles ? async (_req) => ({ allowed: true }) : options.requestFilePermission;
118659
118805
  const toolContext = {
118660
118806
  cwd,
118807
+ mode,
118661
118808
  sessionId: this.sessionData.id,
118662
118809
  abortSignal: this.activeAbortController.signal,
118663
118810
  checkpointTracker: tracker,
@@ -118693,7 +118840,8 @@ class AgentSession {
118693
118840
  });
118694
118841
  } else if (event.type === "tool-result") {
118695
118842
  const toolDef = defaultToolCatalog.get(event.toolResult.name);
118696
- const outputSummary = !event.toolResult.isError && toolDef?.summarize ? toolDef.summarize(event.toolResult.args, event.toolResult.result) : formatToolOutputSummary(event.toolResult.result, event.toolResult.isError);
118843
+ const summaryObj = summarizeToolResult(toolDef, event.toolResult.args, event.toolResult.result, event.toolResult.isError);
118844
+ const outputSummary = formatPlainToolSummary(summaryObj);
118697
118845
  const errorMessage = event.toolResult.isError ? typeof event.toolResult.result === "object" && event.toolResult.result !== null ? event.toolResult.result.message ?? JSON.stringify(event.toolResult.result) : String(event.toolResult.result) : undefined;
118698
118846
  const status = event.toolResult.isError ? "failed" : "completed";
118699
118847
  this.sessionLogWriter?.append({
@@ -119442,7 +119590,7 @@ var themeCommand = {
119442
119590
  }
119443
119591
  };
119444
119592
  }
119445
- const matched = findTheme2(args.join(" "));
119593
+ const matched = findTheme(args.join(" "));
119446
119594
  if (!matched) {
119447
119595
  const validNames = listThemes().map((t) => t.name).join(", ");
119448
119596
  return {
@@ -119653,27 +119801,25 @@ class TextElement {
119653
119801
  const effWidth = Math.max(1, maxW);
119654
119802
  let styled = rawContent;
119655
119803
  if (this.props.bold)
119656
- styled = source_default.bold(styled);
119657
- if (this.props.dim)
119658
- styled = source_default.dim(styled);
119804
+ styled = bold(styled);
119659
119805
  if (this.props.italic)
119660
- styled = source_default.italic(styled);
119806
+ styled = italic(styled);
119661
119807
  if (this.props.underline)
119662
- styled = source_default.underline(styled);
119808
+ styled = underline(styled);
119663
119809
  if (this.props.strikethrough)
119664
- styled = source_default.strikethrough(styled);
119810
+ styled = strikethrough(styled);
119665
119811
  if (this.props.color) {
119666
119812
  if (typeof this.props.color === "function") {
119667
119813
  styled = this.props.color(styled);
119668
- } else {
119669
- styled = themeColor2(this.props.color)(styled);
119814
+ } else if (this.props.color in c) {
119815
+ styled = c[this.props.color](styled);
119670
119816
  }
119671
119817
  }
119672
119818
  if (this.props.bgColor) {
119673
119819
  if (typeof this.props.bgColor === "function") {
119674
119820
  styled = this.props.bgColor(styled);
119675
- } else {
119676
- styled = themeBgColor(this.props.bgColor)(styled);
119821
+ } else if (this.props.bgColor in bg) {
119822
+ styled = bg[this.props.bgColor](styled);
119677
119823
  }
119678
119824
  }
119679
119825
  const isWrappable = this.props.wrap ?? true;
@@ -119850,7 +119996,7 @@ class BoxElement {
119850
119996
  applyBorders(lines, totalWidth, border) {
119851
119997
  if (border === "none")
119852
119998
  return lines;
119853
- const colorFn = typeof this.props.borderColor === "function" ? this.props.borderColor : this.props.borderColor ? themeColor2(this.props.borderColor) : (s) => s;
119999
+ const colorFn = typeof this.props.borderColor === "function" ? this.props.borderColor : this.props.borderColor ? themeColor(this.props.borderColor) : (s) => s;
119854
120000
  if (border === "top-bottom") {
119855
120001
  const rule = colorFn(figures.horizontalLine.repeat(totalWidth));
119856
120002
  return [rule, ...lines, rule];
@@ -119877,34 +120023,30 @@ function Box(props, children) {
119877
120023
  }
119878
120024
  // src/tui/primitives/widgets/ModalBox.ts
119879
120025
  function renderModalBox(options) {
119880
- const theme = getTheme();
119881
120026
  const termWidth = options.width ?? process.stdout.columns ?? 80;
119882
120027
  const maxCols = Math.max(1, termWidth);
119883
120028
  const dividerWidth = Math.max(1, termWidth);
119884
- const lavHeader = themeColor2(theme.lavenderHeader);
119885
- const infoColor = themeColor2(theme.info);
119886
- const dashRule = themeColor2(theme.dashedRule);
119887
120029
  const elements = [];
119888
- elements.push(Text(lavHeader(figures.horizontalLine.repeat(dividerWidth)), { clip: true }));
120030
+ elements.push(Text(c.rule(figures.horizontalLine.repeat(dividerWidth)), { clip: true }));
119889
120031
  if (options.subtitle) {
119890
120032
  elements.push(Box({ direction: "row", justify: "space-between", width: maxCols }, [
119891
- Text(options.title, { color: theme.info }),
119892
- Text(options.subtitle, { dim: true })
120033
+ Text(options.title, { color: "info" }),
120034
+ Text(options.subtitle, { color: "muted" })
119893
120035
  ]));
119894
120036
  } else {
119895
- elements.push(Text(options.title, { color: theme.lavenderLight }));
120037
+ elements.push(Text(options.title, { color: "permission" }));
119896
120038
  }
119897
120039
  if (options.queryInput) {
119898
- const pointer = infoColor(`${figures.pointer} `);
119899
- const queryDisplay = options.queryInput.query ? source_default.white(options.queryInput.query) : source_default.dim(options.queryInput.placeholder);
120040
+ const pointer = c.info(`${figures.pointer} `);
120041
+ const queryDisplay = options.queryInput.query ? c.text(options.queryInput.query) : c.muted(options.queryInput.placeholder);
119900
120042
  elements.push(Text(`${pointer}${queryDisplay}`));
119901
- elements.push(Text(dashRule(figures.horizontalLine.repeat(dividerWidth)), { clip: true }));
120043
+ elements.push(Text(c.rule(figures.horizontalLine.repeat(dividerWidth)), { clip: true }));
119902
120044
  }
119903
120045
  for (const child of options.content) {
119904
120046
  elements.push(child);
119905
120047
  }
119906
120048
  if (options.footer) {
119907
- elements.push(Text(source_default.dim.italic(options.footer)));
120049
+ elements.push(Text(italic(c.muted(options.footer))));
119908
120050
  }
119909
120051
  const modalBox = Box({ direction: "column", width: maxCols, clip: true }, elements);
119910
120052
  return modalBox.render(maxCols);
@@ -120147,12 +120289,10 @@ class Header extends Component {
120147
120289
  return rawPath;
120148
120290
  }
120149
120291
  render(_width) {
120150
- const theme = getTheme();
120151
120292
  const version = this.props.version ?? DEFAULT_VERSION;
120152
- const brandColor = themeColor2(theme.brand);
120153
- const logoL0 = brandColor(LOGO_LINES[0] ?? "");
120154
- const logoL1 = brandColor(LOGO_LINES[1] ?? "");
120155
- const logoL2 = brandColor(LOGO_LINES[2] ?? "");
120293
+ const logoL0 = c.brand(LOGO_LINES[0] ?? "");
120294
+ const logoL1 = c.brand(LOGO_LINES[1] ?? "");
120295
+ const logoL2 = c.brand(LOGO_LINES[2] ?? "");
120156
120296
  const modelObj = this.props.model ?? { provider: "anthropic", modelId: "claude-3-7-sonnet" };
120157
120297
  const modelTag = `${modelObj.provider}/${modelObj.modelId}`;
120158
120298
  const cwdFormatted = this.formatCwd(this.props.cwd ?? process.cwd());
@@ -120164,17 +120304,17 @@ class Header extends Component {
120164
120304
  /* @__PURE__ */ jsx(Text, {
120165
120305
  wrap: false,
120166
120306
  clip: false,
120167
- children: `${logoL0} ${source_default.white.bold("Steward")} ${source_default.dim(`v${version}`)}`
120307
+ children: `${logoL0} ${bold(c.text("Steward"))} ${c.muted(`v${version}`)}`
120168
120308
  }),
120169
120309
  /* @__PURE__ */ jsx(Text, {
120170
120310
  wrap: false,
120171
120311
  clip: false,
120172
- children: `${logoL1} ${source_default.dim(modelTag)} ${source_default.dim("·")} ${source_default.dim("API Usage Billing")}`
120312
+ children: `${logoL1} ${c.muted(modelTag)} ${c.muted("·")} ${c.muted("API Usage Billing")}`
120173
120313
  }),
120174
120314
  /* @__PURE__ */ jsx(Text, {
120175
120315
  wrap: false,
120176
120316
  clip: false,
120177
- children: `${logoL2} ${source_default.dim(cwdFormatted)}`
120317
+ children: `${logoL2} ${c.muted(cwdFormatted)}`
120178
120318
  }),
120179
120319
  /* @__PURE__ */ jsx(Text, {
120180
120320
  wrap: false,
@@ -120205,7 +120345,6 @@ class StatusBar extends Component {
120205
120345
  this.state = {
120206
120346
  chatMode: props.chatMode ?? getActiveMode(),
120207
120347
  model: props.model,
120208
- usage: props.usage,
120209
120348
  isBusy: props.isBusy,
120210
120349
  exitPending: props.exitPending,
120211
120350
  warning: props.warning,
@@ -120280,12 +120419,10 @@ class StatusBar extends Component {
120280
120419
  }
120281
120420
  }
120282
120421
  render(width) {
120283
- const theme = getTheme();
120284
120422
  const termWidth = width ?? process.stdout.columns ?? 80;
120285
120423
  const maxCols = Math.max(1, termWidth);
120286
120424
  const {
120287
120425
  model,
120288
- usage,
120289
120426
  isBusy,
120290
120427
  exitPending,
120291
120428
  warning,
@@ -120296,48 +120433,47 @@ class StatusBar extends Component {
120296
120433
  } = this.state;
120297
120434
  let left = "";
120298
120435
  if (warning) {
120299
- left = themeColor2(theme.warning)(warning);
120436
+ left = c.warning(warning);
120300
120437
  } else if (voiceState && voiceState !== "idle") {
120301
120438
  if (voiceState === "connecting") {
120302
- left = `${source_default.white.bold("Connecting...")} ${source_default.dim("Ctrl+T to stop")}`;
120439
+ left = `${bold(c.text("Connecting..."))} ${c.muted("Ctrl+T to stop")}`;
120303
120440
  } else if (voiceState === "recording") {
120304
120441
  const timeStr = formatVoiceDuration(voiceDurationSec ?? 0);
120305
- left = `${source_default.white.bold(`Recording... ${timeStr}`)} ${source_default.dim("Ctrl+T to stop")}`;
120442
+ left = `${bold(c.text(`Recording... ${timeStr}`))} ${c.muted("Ctrl+T to stop")}`;
120306
120443
  } else if (voiceState === "finishing") {
120307
- left = source_default.white.bold("Finishing...");
120444
+ left = bold(c.text("Finishing..."));
120308
120445
  }
120309
120446
  } else if (exitPending) {
120310
- const errColor = themeColor2(theme.error);
120311
- left = `${errColor("▸ ")}${source_default.dim("Press ")}${errColor("Ctrl+C")}${source_default.dim(" again to exit")}`;
120447
+ left = `${c.error("▸ ")}${c.muted("Press ")}${c.error("Ctrl+C")}${c.muted(" again to exit")}`;
120312
120448
  } else if (updateStatus && updateStatus.state !== "idle") {
120313
120449
  if (updateStatus.state === "checking") {
120314
- left = source_default.white(updateStatus.message ?? "Checking for updates...");
120450
+ left = c.text(updateStatus.message ?? "Checking for updates...");
120315
120451
  } else if (updateStatus.state === "available") {
120316
- left = source_default.white(updateStatus.message ?? `Update v${updateStatus.version ?? ""} is available`);
120452
+ left = c.text(updateStatus.message ?? `Update v${updateStatus.version ?? ""} is available`);
120317
120453
  } else if (updateStatus.state === "no-updates") {
120318
- left = source_default.white(updateStatus.message ?? "Steward is up to date");
120454
+ left = c.text(updateStatus.message ?? "Steward is up to date");
120319
120455
  } else if (updateStatus.state === "error" && updateStatus.message) {
120320
- left = themeColor2(theme.error)(updateStatus.message);
120456
+ left = c.error(updateStatus.message);
120321
120457
  } else if (isBusy) {
120322
- left = source_default.dim("esc to interrupt");
120458
+ left = c.muted("esc to interrupt");
120323
120459
  } else {
120324
- left = source_default.dim("? for shortcuts");
120460
+ left = c.muted("? for shortcuts");
120325
120461
  }
120326
120462
  } else if (isBusy) {
120327
- left = source_default.dim("esc to interrupt");
120463
+ left = c.muted("esc to interrupt");
120328
120464
  } else {
120329
- left = source_default.dim("? for shortcuts");
120465
+ left = c.muted("? for shortcuts");
120330
120466
  }
120331
120467
  const mode = chatMode ?? "normal";
120332
- const modeMeta = CHAT_MODES[mode];
120333
- const modeColorKey = modeMeta?.themeColorKey ?? "text";
120468
+ const modeMeta = MODES[mode];
120469
+ const modeColorKey = modeMeta?.color ?? "text";
120334
120470
  const modeLabel = modeMeta?.label ?? mode;
120335
120471
  const parts = [];
120336
- parts.push(themeColor2(theme[modeColorKey])(modeLabel));
120472
+ parts.push(c[modeColorKey](modeLabel));
120337
120473
  const effort = model?.effort ?? "provider-default";
120338
120474
  const effortDisplay = effort === "provider-default" ? "default" : effort;
120339
- parts.push(source_default.dim(effortDisplay));
120340
- const right = parts.length > 0 ? parts.join(` ${figures.bullet} `) : "";
120475
+ parts.push(c.muted(effortDisplay));
120476
+ const right = parts.length > 0 ? parts.join(c.muted(` ${figures.bullet} `)) : "";
120341
120477
  const element = /* @__PURE__ */ jsxs(Box, {
120342
120478
  direction: "row",
120343
120479
  justify: "space-between",
@@ -120457,9 +120593,9 @@ class StreamingView extends Component {
120457
120593
  if (targetArg) {
120458
120594
  const maxArgLen = Math.max(10, maxCols - toolName.length - 8);
120459
120595
  const truncatedArg = targetArg.length > maxArgLen ? truncateMiddle(targetArg, maxArgLen) : targetArg;
120460
- line += `${source_default.dim("(")}${source_default.dim(truncatedArg)}${source_default.dim(")")}`;
120596
+ line += `${c.muted("(")}${c.muted(truncatedArg)}${c.muted(")")}`;
120461
120597
  } else {
120462
- line += `${source_default.dim("()")}`;
120598
+ line += `${c.muted("()")}`;
120463
120599
  }
120464
120600
  lines.push(line);
120465
120601
  if (activeTool.recentLines && activeTool.recentLines.length > 0) {
@@ -120467,16 +120603,16 @@ class StreamingView extends Component {
120467
120603
  const maxLogLen = Math.max(10, maxCols - 6);
120468
120604
  for (let i = 0;i < toShow.length; i++) {
120469
120605
  const l = toShow[i] ?? "";
120470
- const p = i === 0 ? ` ${source_default.dim("└ ")}` : " ";
120606
+ const p = i === 0 ? ` ${c.muted("└ ")}` : " ";
120471
120607
  const truncatedLog = l.length > maxLogLen ? `${l.slice(0, maxLogLen - 1)}…` : l;
120472
- lines.push(`${p}${source_default.dim(truncatedLog)}`);
120608
+ lines.push(`${p}${c.muted(truncatedLog)}`);
120473
120609
  }
120474
120610
  } else {
120475
- lines.push(` ${source_default.dim("└ Running...")}`);
120611
+ lines.push(` ${c.muted("└ Running...")}`);
120476
120612
  }
120477
120613
  } else if (isThinking && !text) {
120478
120614
  const bullet = getStatusBullet("running", pulseFrame % 2 === 0);
120479
- lines.push(`${bullet} ${source_default.bold("Thinking..")}`);
120615
+ lines.push(`${bullet} ${bold(c.text("Thinking.."))}`);
120480
120616
  const elapsedMs = thinkingStartTime ? performance.now() - thinkingStartTime : pulseFrame * 120;
120481
120617
  let subText = "wait...";
120482
120618
  if (elapsedMs < 2000) {
@@ -120488,7 +120624,7 @@ class StreamingView extends Component {
120488
120624
  } else {
120489
120625
  subText = "taking a bit time...";
120490
120626
  }
120491
- lines.push(` ${source_default.dim("└ ")}${source_default.dim(subText)}`);
120627
+ lines.push(` ${c.muted("└ ")}${c.muted(subText)}`);
120492
120628
  }
120493
120629
  if (text) {
120494
120630
  if (lines.length > 0)
@@ -120515,7 +120651,7 @@ class StreamingView extends Component {
120515
120651
  continue;
120516
120652
  }
120517
120653
  if (i === 0) {
120518
- const bullet = source_default.white(`${figures.blackCircle} `);
120654
+ const bullet = c.text(`${figures.blackCircle} `);
120519
120655
  lines.push(`${bullet}${l}`);
120520
120656
  } else {
120521
120657
  lines.push(` ${l}`);
@@ -120731,7 +120867,7 @@ class PromptInput extends Component {
120731
120867
  return true;
120732
120868
  }
120733
120869
  const isSlashMode = this.state.value.startsWith("/") && !this.state.value.includes(" ");
120734
- const matchingCommands = isSlashMode ? defaultCommandRegistry.getAll().filter((c) => `/${c.name}`.toLowerCase().startsWith(this.state.value.toLowerCase())) : [];
120870
+ const matchingCommands = isSlashMode ? defaultCommandRegistry.getAll().filter((c2) => `/${c2.name}`.toLowerCase().startsWith(this.state.value.toLowerCase())) : [];
120735
120871
  if (action.type === "newline") {
120736
120872
  const before = this.state.value.slice(0, this.state.cursorPos);
120737
120873
  const after = this.state.value.slice(this.state.cursorPos);
@@ -120995,7 +121131,6 @@ ${after}`, this.state.cursorPos);
120995
121131
  return this.renderWithCursor(width).lines;
120996
121132
  }
120997
121133
  renderWithCursor(width) {
120998
- const theme = getTheme();
120999
121134
  const termWidth = width ?? process.stdout.columns ?? 80;
121000
121135
  const maxCols = Math.max(1, termWidth);
121001
121136
  const dividerWidth = maxCols;
@@ -121016,12 +121151,12 @@ ${after}`, this.state.cursorPos);
121016
121151
  const lines = [];
121017
121152
  let cursor = null;
121018
121153
  if (escPending) {
121019
- lines.push(themeColor2(theme.permission)("Press Esc again to clear"));
121154
+ lines.push(c.permission("Press Esc again to clear"));
121020
121155
  }
121021
- const borderColor = disabled ? themeColor2(theme.subtle) : themeColor2(theme.promptBorder);
121156
+ const borderColor = disabled ? c.subtle : c.promptBorder;
121022
121157
  if (disabled) {
121023
121158
  lines.push(borderColor(figures.horizontalLine.repeat(dividerWidth)));
121024
- lines.push(truncateToWidth(` ${source_default.dim("Esc to stop")}`, maxCols));
121159
+ lines.push(truncateToWidth(` ${c.muted("Esc to stop")}`, maxCols));
121025
121160
  lines.push(borderColor(figures.horizontalLine.repeat(dividerWidth)));
121026
121161
  return { lines, cursor: null };
121027
121162
  }
@@ -121030,22 +121165,19 @@ ${after}`, this.state.cursorPos);
121030
121165
  const leftDashes = borderColor(figures.horizontalLine.repeat(4));
121031
121166
  const rightLen = Math.max(0, maxCols - (4 + histText.length));
121032
121167
  const rightDashes = borderColor(figures.horizontalLine.repeat(rightLen));
121033
- lines.push(`${leftDashes}${source_default.white(histText)}${rightDashes}`);
121168
+ lines.push(`${leftDashes}${c.text(histText)}${rightDashes}`);
121034
121169
  } else {
121035
121170
  lines.push(borderColor(figures.horizontalLine.repeat(dividerWidth)));
121036
121171
  }
121037
121172
  const displayData = voiceMode !== "idle" && voiceTranscript ? insertTextAtAnchor(value, voiceAnchor, voiceTranscript) : { value, cursorPos };
121038
121173
  const effectiveValue = displayData.value;
121039
121174
  const effectiveCursorPos = displayData.cursorPos;
121040
- const chevColor = themeColor2(theme.userChevron);
121041
- const pointer = chevColor(`${figures.pointerBold} `);
121042
- const prefixLen = 2;
121043
121175
  if (effectiveValue.length === 0) {
121044
121176
  cursor = {
121045
121177
  logicalLineIndex: lines.length,
121046
- characterOffsetWithinLine: prefixLen
121178
+ characterOffsetWithinLine: 0
121047
121179
  };
121048
- lines.push(truncateToWidth(`${pointer}${source_default.dim("Type your message...")}`, maxCols));
121180
+ lines.push(truncateToWidth(c.muted("Type your message..."), maxCols));
121049
121181
  } else {
121050
121182
  const vLines = effectiveValue.split(`
121051
121183
  `);
@@ -121058,37 +121190,35 @@ ${after}`, this.state.cursorPos);
121058
121190
  if (cursor === null && effectiveCursorPos >= currentOffset && (effectiveCursorPos <= lineEndOffset || isLast)) {
121059
121191
  cursor = {
121060
121192
  logicalLineIndex: lines.length,
121061
- characterOffsetWithinLine: prefixLen + (effectiveCursorPos - currentOffset)
121193
+ characterOffsetWithinLine: effectiveCursorPos - currentOffset
121062
121194
  };
121063
121195
  }
121064
- const p = i === 0 ? pointer : " ";
121065
- lines.push(`${p}${source_default.white(l)}`);
121196
+ lines.push(c.text(l));
121066
121197
  currentOffset = lineEndOffset + 1;
121067
121198
  }
121068
121199
  }
121069
121200
  lines.push(borderColor(figures.horizontalLine.repeat(dividerWidth)));
121070
121201
  const isSlashMode = voiceMode === "idle" && effectiveValue.startsWith("/") && !effectiveValue.includes(" ");
121071
- const matchingCommands = isSlashMode ? defaultCommandRegistry.getAll().filter((c) => `/${c.name}`.toLowerCase().startsWith(effectiveValue.toLowerCase())) : [];
121202
+ const matchingCommands = isSlashMode ? defaultCommandRegistry.getAll().filter((cmd) => `/${cmd.name}`.toLowerCase().startsWith(effectiveValue.toLowerCase())) : [];
121072
121203
  if (isSlashMode && matchingCommands.length > 0 && effectiveValue !== `/${matchingCommands[0]?.name} `) {
121073
121204
  for (let i = 0;i < matchingCommands.length; i++) {
121074
121205
  const cmd = matchingCommands[i];
121075
121206
  const isSelected = i === paletteIdx;
121076
121207
  const namePadded = `/${cmd.name}`.padEnd(18);
121077
121208
  if (isSelected) {
121078
- lines.push(truncateToWidth(`${source_default.white.bold(namePadded)}${source_default.white.bold(cmd.description)}`, maxCols));
121209
+ lines.push(truncateToWidth(`${bold(c.text(namePadded))}${bold(c.text(cmd.description))}`, maxCols));
121079
121210
  } else {
121080
- lines.push(truncateToWidth(`${source_default.dim(namePadded)}${source_default.dim(cmd.description)}`, maxCols));
121211
+ lines.push(truncateToWidth(`${c.muted(namePadded)}${c.muted(cmd.description)}`, maxCols));
121081
121212
  }
121082
121213
  }
121083
121214
  }
121084
121215
  if (voiceMode === "idle" && fileMatches.length > 0) {
121085
- const infoColor = themeColor2(theme.info);
121086
- lines.push(source_default.dim("Matching files (@):"));
121216
+ lines.push(c.muted("Matching files (@):"));
121087
121217
  for (let i = 0;i < fileMatches.length; i++) {
121088
121218
  const f = fileMatches[i];
121089
121219
  const isSelected = i === fileSelectIdx;
121090
- const p = isSelected ? infoColor(`${figures.pointerBold} `) : " ";
121091
- const fileText = isSelected ? infoColor(f) : source_default.dim(f);
121220
+ const p = isSelected ? c.info(`${figures.pointerBold} `) : " ";
121221
+ const fileText = isSelected ? c.info(f) : c.muted(f);
121092
121222
  lines.push(truncateToWidth(`${p}${fileText}`, maxCols));
121093
121223
  }
121094
121224
  }
@@ -121145,19 +121275,14 @@ class TrustGate extends Component {
121145
121275
  }
121146
121276
  }
121147
121277
  render(width) {
121148
- const theme = getTheme();
121149
121278
  const termWidth = width ?? process.stdout.columns ?? 80;
121150
121279
  const maxCols = Math.max(1, termWidth);
121151
- const warnColor = themeColor2(theme.warning);
121152
- const permColor = themeColor2(theme.permission);
121153
- const mutedColor = themeColor2(theme.textMuted);
121154
- const dimGuideColor = themeColor2(theme.inactive);
121155
121280
  const { selectedIndex } = this.state;
121156
121281
  const isYesSelected = selectedIndex === 0;
121157
121282
  const isNoSelected = selectedIndex === 1;
121158
121283
  const pointer = figures.pointerBold ?? "❯";
121159
- const yesOptionText = isYesSelected ? `${permColor(pointer)} ${permColor.bold("1. Yes, I trust this folder")}` : ` ${source_default.white("1. Yes, I trust this folder")}`;
121160
- const noOptionText = isNoSelected ? `${permColor(pointer)} ${permColor.bold("2. No, exit")}` : ` ${source_default.white("2. No, exit")}`;
121284
+ const yesOptionText = isYesSelected ? `${c.permission(pointer)} ${bold(c.permission("1. Yes, I trust this folder"))}` : ` ${c.text("1. Yes, I trust this folder")}`;
121285
+ const noOptionText = isNoSelected ? `${c.permission(pointer)} ${bold(c.permission("2. No, exit"))}` : ` ${c.text("2. No, exit")}`;
121161
121286
  const safetyCheckText = "You should only proceed if you trust this workspace. Accessing untrusted workspaces may allow malicious code in the repository to compromise security or mislead the assistant.";
121162
121287
  const capabilityText = "Steward can read files and execute commands to investigate, build, and debug with your explicit permission. Pre-mutation checkpoints ensure every edit is reversible via /rewind.";
121163
121288
  const element = /* @__PURE__ */ jsxs(Box, {
@@ -121169,7 +121294,7 @@ class TrustGate extends Component {
121169
121294
  /* @__PURE__ */ jsx(Text, {
121170
121295
  wrap: false,
121171
121296
  clip: false,
121172
- children: warnColor.bold("Accessing workspace:")
121297
+ children: bold(c.warning("Accessing workspace:"))
121173
121298
  }),
121174
121299
  /* @__PURE__ */ jsx(Text, {
121175
121300
  wrap: false,
@@ -121179,7 +121304,7 @@ class TrustGate extends Component {
121179
121304
  /* @__PURE__ */ jsx(Text, {
121180
121305
  wrap: false,
121181
121306
  clip: false,
121182
- children: source_default.white.bold(this.props.cwd)
121307
+ children: bold(c.text(this.props.cwd))
121183
121308
  }),
121184
121309
  /* @__PURE__ */ jsx(Text, {
121185
121310
  wrap: false,
@@ -121188,7 +121313,7 @@ class TrustGate extends Component {
121188
121313
  }),
121189
121314
  /* @__PURE__ */ jsx(Text, {
121190
121315
  wrap: true,
121191
- children: source_default.white(safetyCheckText)
121316
+ children: c.text(safetyCheckText)
121192
121317
  }),
121193
121318
  /* @__PURE__ */ jsx(Text, {
121194
121319
  wrap: false,
@@ -121197,7 +121322,7 @@ class TrustGate extends Component {
121197
121322
  }),
121198
121323
  /* @__PURE__ */ jsx(Text, {
121199
121324
  wrap: true,
121200
- children: source_default.white(capabilityText)
121325
+ children: c.text(capabilityText)
121201
121326
  }),
121202
121327
  /* @__PURE__ */ jsx(Text, {
121203
121328
  wrap: false,
@@ -121207,7 +121332,7 @@ class TrustGate extends Component {
121207
121332
  /* @__PURE__ */ jsx(Text, {
121208
121333
  wrap: false,
121209
121334
  clip: false,
121210
- children: dimGuideColor("Security guide")
121335
+ children: c.muted("Security guide")
121211
121336
  }),
121212
121337
  /* @__PURE__ */ jsx(Text, {
121213
121338
  wrap: false,
@@ -121232,7 +121357,7 @@ class TrustGate extends Component {
121232
121357
  /* @__PURE__ */ jsx(Text, {
121233
121358
  wrap: false,
121234
121359
  clip: false,
121235
- children: mutedColor(source_default.italic("Enter to confirm · Esc to cancel"))
121360
+ children: italic(c.muted("Enter to confirm · Esc to cancel"))
121236
121361
  })
121237
121362
  ]
121238
121363
  });
@@ -121257,12 +121382,9 @@ class ModelPicker extends SelectList {
121257
121382
  onSelect: props.onSelect,
121258
121383
  onCancel: props.onCancel,
121259
121384
  renderItem: (m, isSelected, maxCols) => {
121260
- const theme = getTheme();
121261
- const selColor = themeColor2(theme.permission);
121262
- const yellowColor = themeColor2(theme.warning);
121263
121385
  const isCurrent = m.provider === props.currentModel.provider && m.model_id === props.currentModel.modelId;
121264
- const pointer = isSelected ? selColor(`${figures.pointer} `) : " ";
121265
- const activeBadge = isCurrent ? yellowColor.bold(" (active)") : "";
121386
+ const pointer = isSelected ? c.selected(`${figures.pointer} `) : " ";
121387
+ const activeBadge = isCurrent ? bold(c.current(" (active)")) : "";
121266
121388
  const providerName = m.provider.toUpperCase();
121267
121389
  const caps = m.capabilities?.reasoning ? "reasoning" : "chat";
121268
121390
  const meta = `${providerName} • ${caps}`;
@@ -121271,14 +121393,14 @@ class ModelPicker extends SelectList {
121271
121393
  width: maxCols,
121272
121394
  children: [
121273
121395
  /* @__PURE__ */ jsx(Text, {
121274
- color: isSelected ? selColor : isCurrent ? yellowColor : source_default.white,
121396
+ color: isSelected ? "selected" : isCurrent ? "current" : "text",
121275
121397
  wrap: false,
121276
121398
  clip: true,
121277
121399
  ellipsis: true,
121278
121400
  children: `${pointer}${m.model_id}${activeBadge}`
121279
121401
  }),
121280
121402
  /* @__PURE__ */ jsx(Text, {
121281
- dim: true,
121403
+ color: "muted",
121282
121404
  wrap: false,
121283
121405
  clip: true,
121284
121406
  ellipsis: true,
@@ -121310,12 +121432,9 @@ class ThemePicker extends SelectList {
121310
121432
  onSelect: props.onSelect,
121311
121433
  onCancel: props.onCancel,
121312
121434
  renderItem: (t, isSelected, maxCols) => {
121313
- const theme = getTheme();
121314
- const selColor = themeColor2(theme.permission);
121315
- const yellowColor = themeColor2(theme.warning);
121316
121435
  const isCurrent = t.name === props.currentTheme;
121317
- const pointer = isSelected ? selColor(`${figures.pointer} `) : " ";
121318
- const activeBadge = isCurrent ? yellowColor.bold(" (active)") : "";
121436
+ const pointer = isSelected ? c.selected(`${figures.pointer} `) : " ";
121437
+ const activeBadge = isCurrent ? bold(c.current(" (active)")) : "";
121319
121438
  const tBrand = resolveThemeColor(t.theme.brand, false)(figures.blackCircle);
121320
121439
  const tSuccess = resolveThemeColor(t.theme.success, false)(figures.blackCircle);
121321
121440
  const tWarning = resolveThemeColor(t.theme.warning, false)(figures.blackCircle);
@@ -121328,14 +121447,14 @@ class ThemePicker extends SelectList {
121328
121447
  width: maxCols,
121329
121448
  children: [
121330
121449
  /* @__PURE__ */ jsx(Text, {
121331
- color: isSelected ? selColor : isCurrent ? yellowColor : source_default.white,
121450
+ color: isSelected ? "selected" : isCurrent ? "current" : "text",
121332
121451
  wrap: false,
121333
121452
  clip: true,
121334
121453
  ellipsis: true,
121335
121454
  children: `${pointer}${t.label}${activeBadge}`
121336
121455
  }),
121337
121456
  /* @__PURE__ */ jsx(Text, {
121338
- dim: true,
121457
+ color: "muted",
121339
121458
  wrap: false,
121340
121459
  clip: true,
121341
121460
  ellipsis: true,
@@ -121370,11 +121489,9 @@ class SessionMenu extends SelectList {
121370
121489
  onSelect: props.onSelect,
121371
121490
  onCancel: props.onCancel,
121372
121491
  renderItem: (s, isSelected, maxCols) => {
121373
- const theme = getTheme();
121374
- const selColor = themeColor2(theme.permission);
121375
121492
  const rawTitle = s.name || s.turns?.[0]?.userPrompt || "Untitled Session";
121376
121493
  const cleanTitle = rawTitle.replace(/\s+/g, " ").trim();
121377
- const pointer = isSelected ? selColor(`${figures.pointer} `) : " ";
121494
+ const pointer = isSelected ? c.selected(`${figures.pointer} `) : " ";
121378
121495
  const shortId = s.id.slice(0, 8);
121379
121496
  const dateStr = s.date ? s.date.split("T")[0] : "";
121380
121497
  const turnsCount = s.turns?.length ?? 0;
@@ -121389,14 +121506,14 @@ class SessionMenu extends SelectList {
121389
121506
  width: maxCols,
121390
121507
  children: [
121391
121508
  /* @__PURE__ */ jsx(Text, {
121392
- color: isSelected ? selColor : source_default.white,
121509
+ color: isSelected ? "selected" : "text",
121393
121510
  wrap: false,
121394
121511
  clip: true,
121395
121512
  ellipsis: true,
121396
121513
  children: `${pointer}${cleanTitle}`
121397
121514
  }),
121398
121515
  /* @__PURE__ */ jsx(Text, {
121399
- dim: true,
121516
+ color: "muted",
121400
121517
  wrap: false,
121401
121518
  clip: true,
121402
121519
  ellipsis: true,
@@ -121452,8 +121569,8 @@ class ShortcutsMenu extends Component {
121452
121569
  ];
121453
121570
  const rows = leftCol.map((left, i) => {
121454
121571
  const right = rightCol[i];
121455
- const leftFormatted = ` ${source_default.white(left.key.padEnd(11))} ${source_default.dim(left.desc.padEnd(18))}`;
121456
- const rightFormatted = `${source_default.white(right.key.padEnd(13))} ${source_default.dim(right.desc)}`;
121572
+ const leftFormatted = ` ${c.text(left.key.padEnd(11))} ${c.muted(left.desc.padEnd(18))}`;
121573
+ const rightFormatted = `${c.text(right.key.padEnd(13))} ${c.muted(right.desc)}`;
121457
121574
  return /* @__PURE__ */ jsxs(Box, {
121458
121575
  direction: "row",
121459
121576
  justify: "start",
@@ -121546,12 +121663,8 @@ class EffortPicker extends Component {
121546
121663
  }
121547
121664
  }
121548
121665
  render(width) {
121549
- const theme = getTheme();
121550
121666
  const termWidth = width ?? process.stdout.columns ?? 80;
121551
121667
  const maxCols = Math.max(1, termWidth);
121552
- const permColor = themeColor2(theme.permission);
121553
- const infoColor = themeColor2(theme.info);
121554
- const trackColor = themeColor2(theme.promptBorder);
121555
121668
  const { selectedIndex } = this.state;
121556
121669
  const activeOption = EFFORT_OPTIONS[selectedIndex] ?? EFFORT_OPTIONS[0];
121557
121670
  const leftPad = 4;
@@ -121561,24 +121674,23 @@ class EffortPicker extends Component {
121561
121674
  const fasterText = "Faster";
121562
121675
  const smarterText = "Smarter";
121563
121676
  const spectrumGap = Math.max(1, totalSliderCols - (fasterText.length + smarterText.length));
121564
- const spectrumRow = `${" ".repeat(leftPad)}${infoColor.bold(fasterText)}${" ".repeat(spectrumGap)}${permColor.bold(smarterText)}`;
121565
- const yellowColor = themeColor2(theme.warning);
121677
+ const spectrumRow = `${" ".repeat(leftPad)}${bold(c.info(fasterText))}${" ".repeat(spectrumGap)}${bold(c.permission(smarterText))}`;
121566
121678
  let trackChars = "";
121567
121679
  for (let i = 0;i < EFFORT_OPTIONS.length; i++) {
121568
121680
  const isSelected = i === selectedIndex;
121569
121681
  const opt = EFFORT_OPTIONS[i];
121570
121682
  const isCurrent = opt.id === this.props.currentEffort;
121571
- const pointerColor = isCurrent ? yellowColor : permColor;
121683
+ const pointerColor = isCurrent ? c.current : c.permission;
121572
121684
  const slotCenter = Math.floor(colWidth / 2);
121573
- for (let c = 0;c < colWidth; c++) {
121574
- if (c === slotCenter) {
121685
+ for (let ch = 0;ch < colWidth; ch++) {
121686
+ if (ch === slotCenter) {
121575
121687
  if (isSelected) {
121576
121688
  trackChars += pointerColor(figures.sliderPointer ?? "▲");
121577
121689
  } else {
121578
- trackChars += trackColor(figures.horizontalLine);
121690
+ trackChars += c.promptBorder(figures.horizontalLine);
121579
121691
  }
121580
121692
  } else {
121581
- trackChars += trackColor(figures.horizontalLine);
121693
+ trackChars += c.promptBorder(figures.horizontalLine);
121582
121694
  }
121583
121695
  }
121584
121696
  }
@@ -121590,13 +121702,13 @@ class EffortPicker extends Component {
121590
121702
  const isCurrent = opt.id === this.props.currentEffort;
121591
121703
  let labelText = opt.label;
121592
121704
  if (isSelected && isCurrent) {
121593
- labelText = yellowColor.bold(labelText);
121705
+ labelText = bold(c.current(labelText));
121594
121706
  } else if (isSelected) {
121595
- labelText = permColor.bold(labelText);
121707
+ labelText = bold(c.permission(labelText));
121596
121708
  } else if (isCurrent) {
121597
- labelText = yellowColor.bold(labelText);
121709
+ labelText = bold(c.current(labelText));
121598
121710
  } else {
121599
- labelText = source_default.white(labelText);
121711
+ labelText = c.text(labelText);
121600
121712
  }
121601
121713
  const textLen = opt.label.length;
121602
121714
  const padLeft = Math.floor((colWidth - textLen) / 2);
@@ -121604,7 +121716,7 @@ class EffortPicker extends Component {
121604
121716
  labelCols += `${" ".repeat(Math.max(0, padLeft))}${labelText}${" ".repeat(Math.max(0, padRight))}`;
121605
121717
  }
121606
121718
  const labelsRow = `${" ".repeat(leftPad)}${labelCols}`;
121607
- const descText = ` ${source_default.white.bold(activeOption.description)}`;
121719
+ const descText = ` ${bold(c.text(activeOption.description))}`;
121608
121720
  const contentElements = [
121609
121721
  /* @__PURE__ */ jsxs(Box, {
121610
121722
  direction: "column",
@@ -121755,30 +121867,28 @@ class RewindMenu extends SelectList {
121755
121867
  onSelect: props.onSelect,
121756
121868
  onCancel: props.onCancel,
121757
121869
  renderItem: (item, isSelected, maxCols) => {
121758
- const theme = getTheme();
121759
- const selColor = themeColor2(theme.permission);
121760
- const pointer = isSelected ? selColor(`${figures.pointer} `) : " ";
121870
+ const pointer = isSelected ? c.selected(`${figures.pointer} `) : " ";
121761
121871
  let summaryText;
121762
121872
  if (item.hasCodeChanges) {
121763
- const filePart = source_default.dim(`${item.changedFileCount} file${item.changedFileCount !== 1 ? "s" : ""} changed`);
121873
+ const filePart = c.muted(`${item.changedFileCount} file${item.changedFileCount !== 1 ? "s" : ""} changed`);
121764
121874
  const diffBadges = [];
121765
121875
  if (item.addedLines > 0) {
121766
- diffBadges.push(themeColor2(theme.diffAddFG)(`+${item.addedLines}`));
121876
+ diffBadges.push(c.diffAddFg(`+${item.addedLines}`));
121767
121877
  }
121768
121878
  if (item.deletedLines > 0) {
121769
- diffBadges.push(themeColor2(theme.diffDeleteFG)(`-${item.deletedLines}`));
121879
+ diffBadges.push(c.diffDelFg(`-${item.deletedLines}`));
121770
121880
  }
121771
121881
  const diffStr = diffBadges.length > 0 ? ` ${diffBadges.join(" ")}` : "";
121772
121882
  summaryText = ` ${filePart}${diffStr}`;
121773
121883
  } else {
121774
- summaryText = ` ${source_default.dim("No code changes")}`;
121884
+ summaryText = ` ${c.muted("No code changes")}`;
121775
121885
  }
121776
121886
  return /* @__PURE__ */ jsxs(Box, {
121777
121887
  direction: "column",
121778
121888
  width: maxCols,
121779
121889
  children: [
121780
121890
  /* @__PURE__ */ jsx(Text, {
121781
- color: isSelected ? selColor : source_default.white,
121891
+ color: isSelected ? "selected" : "text",
121782
121892
  wrap: false,
121783
121893
  clip: true,
121784
121894
  ellipsis: true,
@@ -121879,18 +121989,14 @@ class BashPermissionDock extends Component {
121879
121989
  return Math.max(0, renderedCmdLines.length - maxVisibleReviewLines);
121880
121990
  }
121881
121991
  render(width) {
121882
- const theme = getTheme();
121883
121992
  const termWidth = width ?? process.stdout.columns ?? 80;
121884
121993
  const maxCols = Math.max(1, termWidth);
121885
- const dividerColor = themeColor2(theme.dividerRule);
121886
- const permColor = themeColor2(theme.permission);
121887
- const mutedColor = themeColor2(theme.textMuted);
121888
121994
  const { mode, selectedIndex, scrollOffset } = this.state;
121889
121995
  const { command, explanation } = this.props;
121890
121996
  const pointer = figures.pointerBold ?? "❯";
121891
121997
  const isYesSelected = selectedIndex === 0;
121892
121998
  const isNoSelected = selectedIndex === 1;
121893
- const divider = dividerColor(figures.horizontalLine.repeat(maxCols));
121999
+ const divider = c.rule(figures.horizontalLine.repeat(maxCols));
121894
122000
  if (mode === "REVIEW") {
121895
122001
  const cmdText = new Text(command, { wrap: true, clip: false });
121896
122002
  const renderedCmdLines = cmdText.render(maxCols);
@@ -121918,7 +122024,7 @@ class BashPermissionDock extends Component {
121918
122024
  /* @__PURE__ */ jsx(Text, {
121919
122025
  wrap: false,
121920
122026
  clip: false,
121921
- children: source_default.white.bold("Bash command (review)")
122027
+ children: bold(c.text("Bash command (review)"))
121922
122028
  }),
121923
122029
  /* @__PURE__ */ jsx(Text, {
121924
122030
  wrap: false,
@@ -121928,7 +122034,7 @@ class BashPermissionDock extends Component {
121928
122034
  visibleCmdLines.map((line) => /* @__PURE__ */ jsx(Text, {
121929
122035
  wrap: false,
121930
122036
  clip: false,
121931
- children: ` ${source_default.white(line)}`
122037
+ children: ` ${c.text(line)}`
121932
122038
  })),
121933
122039
  /* @__PURE__ */ jsx(Text, {
121934
122040
  wrap: false,
@@ -121938,7 +122044,7 @@ class BashPermissionDock extends Component {
121938
122044
  /* @__PURE__ */ jsx(Text, {
121939
122045
  wrap: false,
121940
122046
  clip: false,
121941
- children: mutedColor(source_default.italic("↑/↓ scroll · Esc / f to return"))
122047
+ children: italic(c.muted("↑/↓ scroll · Esc / f to return"))
121942
122048
  })
121943
122049
  ]
121944
122050
  });
@@ -121948,8 +122054,8 @@ class BashPermissionDock extends Component {
121948
122054
  const renderedCmdLines = cmdText.render(Math.max(10, maxCols - 4));
121949
122055
  const previewLines = renderedCmdLines.slice(0, 3);
121950
122056
  const hiddenCount = Math.max(0, renderedCmdLines.length - 3);
121951
- const yesOptionText = isYesSelected ? `${permColor(pointer)} ${permColor.bold("1. Yes")}` : ` ${source_default.white("1. Yes")}`;
121952
- const noOptionText = isNoSelected ? `${permColor(pointer)} ${permColor.bold("2. No")}` : ` ${source_default.white("2. No")}`;
122057
+ const yesOptionText = isYesSelected ? `${c.permission(pointer)} ${bold(c.permission("1. Yes"))}` : ` ${c.text("1. Yes")}`;
122058
+ const noOptionText = isNoSelected ? `${c.permission(pointer)} ${bold(c.permission("2. No"))}` : ` ${c.text("2. No")}`;
121953
122059
  const element = /* @__PURE__ */ jsxs(Box, {
121954
122060
  direction: "column",
121955
122061
  width: maxCols,
@@ -121969,7 +122075,7 @@ class BashPermissionDock extends Component {
121969
122075
  /* @__PURE__ */ jsx(Text, {
121970
122076
  wrap: false,
121971
122077
  clip: false,
121972
- children: source_default.white.bold("Bash command")
122078
+ children: bold(c.text("Bash command"))
121973
122079
  }),
121974
122080
  /* @__PURE__ */ jsx(Text, {
121975
122081
  wrap: false,
@@ -121979,12 +122085,12 @@ class BashPermissionDock extends Component {
121979
122085
  previewLines.map((line) => /* @__PURE__ */ jsx(Text, {
121980
122086
  wrap: false,
121981
122087
  clip: false,
121982
- children: ` ${source_default.white(line)}`
122088
+ children: ` ${c.text(line)}`
121983
122089
  })),
121984
122090
  hiddenCount > 0 && /* @__PURE__ */ jsx(Text, {
121985
122091
  wrap: false,
121986
122092
  clip: false,
121987
- children: ` ${source_default.dim(`(+${hiddenCount} hidden)`)}`
122093
+ children: ` ${c.muted(`(+${hiddenCount} hidden)`)}`
121988
122094
  }),
121989
122095
  /* @__PURE__ */ jsx(Text, {
121990
122096
  wrap: false,
@@ -121993,7 +122099,7 @@ class BashPermissionDock extends Component {
121993
122099
  }),
121994
122100
  /* @__PURE__ */ jsx(Text, {
121995
122101
  wrap: true,
121996
- children: ` ${source_default.dim(explanation)}`
122102
+ children: ` ${c.muted(explanation)}`
121997
122103
  }),
121998
122104
  /* @__PURE__ */ jsx(Text, {
121999
122105
  wrap: false,
@@ -122003,7 +122109,7 @@ class BashPermissionDock extends Component {
122003
122109
  /* @__PURE__ */ jsx(Text, {
122004
122110
  wrap: false,
122005
122111
  clip: false,
122006
- children: source_default.white("Do you want to proceed?")
122112
+ children: c.text("Do you want to proceed?")
122007
122113
  }),
122008
122114
  /* @__PURE__ */ jsx(Text, {
122009
122115
  wrap: false,
@@ -122028,7 +122134,7 @@ class BashPermissionDock extends Component {
122028
122134
  /* @__PURE__ */ jsx(Text, {
122029
122135
  wrap: false,
122030
122136
  clip: false,
122031
- children: mutedColor(source_default.italic("Esc to cancel · f to review"))
122137
+ children: italic(c.muted("Esc to cancel · f to review"))
122032
122138
  })
122033
122139
  ]
122034
122140
  });
@@ -122117,13 +122223,8 @@ class FilePermissionDock extends Component {
122117
122223
  return Math.max(0, allContentRows.length - maxVisibleReviewLines);
122118
122224
  }
122119
122225
  renderContentRows(maxCols) {
122120
- const theme = getTheme();
122121
122226
  const { request } = this.props;
122122
122227
  const { kind, before, after } = request;
122123
- const diffAdd = themeColor2(theme.diffAddFG);
122124
- const diffAddBg = themeBgColor(theme.diffAddBG);
122125
- const diffDelete = themeColor2(theme.diffDeleteFG);
122126
- const diffDeleteBg = themeBgColor(theme.diffDeleteBG);
122127
122228
  if (kind === "create" || kind === "overwrite") {
122128
122229
  const highlighted = highlightCode(after, { filePath: request.filePath });
122129
122230
  const rawLines = highlighted.split(/\r?\n/);
@@ -122134,7 +122235,7 @@ class FilePermissionDock extends Component {
122134
122235
  for (let i = 0;i < lines.length; i++) {
122135
122236
  const lineNum = i + 1;
122136
122237
  const lineNumStr = String(lineNum).padStart(gutterWidth, " ");
122137
- const firstPrefix = ` ${source_default.dim(lineNumStr)} `;
122238
+ const firstPrefix = ` ${c.muted(lineNumStr)} `;
122138
122239
  const contPrefix = ` ${" ".repeat(gutterWidth)} `;
122139
122240
  const wrapped = prefixedBlock(firstPrefix, lines[i] ?? "", {
122140
122241
  continuationPrefix: contPrefix,
@@ -122160,30 +122261,30 @@ class FilePermissionDock extends Component {
122160
122261
  for (const line of hunk.lines) {
122161
122262
  if (line.kind === "deletion") {
122162
122263
  const numStr = String(line.oldLineNumber ?? "").padStart(gutterWidth, " ");
122163
- const firstPrefix = ` ${source_default.dim(numStr)} `;
122264
+ const firstPrefix = ` ${c.muted(numStr)} `;
122164
122265
  const contPrefix = ` ${" ".repeat(gutterWidth)} `;
122165
- const bodyText = line.spans ? diffDelete("-") + line.spans.map((s) => s.kind === "deletion" ? source_default.bold(diffDelete(s.text)) : diffDelete(s.text)).join("") : diffDelete(`-${line.text}`);
122266
+ const bodyText = line.spans ? c.diffDelFg("-") + line.spans.map((s) => s.kind === "deletion" ? bold(c.diffDelFg(s.text)) : c.diffDelFg(s.text)).join("") : c.diffDelFg(`-${line.text}`);
122166
122267
  const wrapped = prefixedBlock(firstPrefix, bodyText, {
122167
122268
  continuationPrefix: contPrefix,
122168
122269
  width: maxCols,
122169
- bg: diffDeleteBg
122270
+ bg: bg.diffDelBg
122170
122271
  });
122171
122272
  renderedRows.push(...wrapped);
122172
122273
  } else if (line.kind === "addition") {
122173
122274
  const numStr = String(line.newLineNumber ?? "").padStart(gutterWidth, " ");
122174
- const firstPrefix = ` ${source_default.dim(numStr)} `;
122275
+ const firstPrefix = ` ${c.muted(numStr)} `;
122175
122276
  const contPrefix = ` ${" ".repeat(gutterWidth)} `;
122176
- const bodyText = line.spans ? diffAdd("+") + line.spans.map((s) => s.kind === "addition" ? source_default.bold(diffAdd(s.text)) : diffAdd(s.text)).join("") : diffAdd(`+${line.text}`);
122277
+ const bodyText = line.spans ? c.diffAddFg("+") + line.spans.map((s) => s.kind === "addition" ? bold(c.diffAddFg(s.text)) : c.diffAddFg(s.text)).join("") : c.diffAddFg(`+${line.text}`);
122177
122278
  const wrapped = prefixedBlock(firstPrefix, bodyText, {
122178
122279
  continuationPrefix: contPrefix,
122179
122280
  width: maxCols,
122180
- bg: diffAddBg
122281
+ bg: bg.diffAddBg
122181
122282
  });
122182
122283
  renderedRows.push(...wrapped);
122183
122284
  } else {
122184
122285
  const lineNum = line.newLineNumber ?? line.oldLineNumber ?? "";
122185
122286
  const numStr = String(lineNum).padStart(gutterWidth, " ");
122186
- const firstPrefix = ` ${source_default.dim(numStr)} `;
122287
+ const firstPrefix = ` ${c.muted(numStr)} `;
122187
122288
  const contPrefix = ` ${" ".repeat(gutterWidth)} `;
122188
122289
  const highlightedLine = highlightCode(line.text, { filePath: request.filePath });
122189
122290
  const wrapped = prefixedBlock(firstPrefix, highlightedLine, {
@@ -122197,19 +122298,15 @@ class FilePermissionDock extends Component {
122197
122298
  return renderedRows;
122198
122299
  }
122199
122300
  render(width) {
122200
- const theme = getTheme();
122201
122301
  const termWidth = width ?? process.stdout.columns ?? 80;
122202
122302
  const maxCols = Math.max(1, termWidth);
122203
- const dividerColor = themeColor2(theme.dividerRule);
122204
- const permColor = themeColor2(theme.permission);
122205
- const mutedColor = themeColor2(theme.textMuted);
122206
122303
  const { mode, selectedIndex, scrollOffset } = this.state;
122207
122304
  const { request } = this.props;
122208
122305
  const { kind, filePath } = request;
122209
122306
  const pointer = figures.pointerBold ?? "❯";
122210
122307
  const isYesSelected = selectedIndex === 0;
122211
122308
  const isNoSelected = selectedIndex === 1;
122212
- const divider = dividerColor(figures.horizontalLine.repeat(maxCols));
122309
+ const divider = c.rule(figures.horizontalLine.repeat(maxCols));
122213
122310
  let title = "Edit file";
122214
122311
  let question = `Do you want to make this edit to ${filePath}?`;
122215
122312
  if (kind === "create") {
@@ -122245,12 +122342,12 @@ class FilePermissionDock extends Component {
122245
122342
  /* @__PURE__ */ jsx(Text, {
122246
122343
  wrap: false,
122247
122344
  clip: false,
122248
- children: source_default.white.bold(`${title} (review)`)
122345
+ children: bold(c.text(`${title} (review)`))
122249
122346
  }),
122250
122347
  /* @__PURE__ */ jsx(Text, {
122251
122348
  wrap: false,
122252
122349
  clip: false,
122253
- children: ` ${source_default.dim(filePath)}`
122350
+ children: ` ${c.muted(filePath)}`
122254
122351
  }),
122255
122352
  /* @__PURE__ */ jsx(Text, {
122256
122353
  wrap: false,
@@ -122270,7 +122367,7 @@ class FilePermissionDock extends Component {
122270
122367
  /* @__PURE__ */ jsx(Text, {
122271
122368
  wrap: false,
122272
122369
  clip: false,
122273
- children: mutedColor(source_default.italic("↑/↓ scroll · Esc / f to return"))
122370
+ children: italic(c.muted("↑/↓ scroll · Esc / f to return"))
122274
122371
  })
122275
122372
  ]
122276
122373
  });
@@ -122278,8 +122375,8 @@ class FilePermissionDock extends Component {
122278
122375
  }
122279
122376
  const previewRows = allContentRows.slice(0, 10);
122280
122377
  const hiddenCount = Math.max(0, allContentRows.length - 10);
122281
- const yesOptionText = isYesSelected ? `${permColor(pointer)} ${permColor.bold("1. Yes")}` : ` ${source_default.white("1. Yes")}`;
122282
- const noOptionText = isNoSelected ? `${permColor(pointer)} ${permColor.bold("2. No")}` : ` ${source_default.white("2. No")}`;
122378
+ const yesOptionText = isYesSelected ? `${c.permission(pointer)} ${bold(c.permission("1. Yes"))}` : ` ${c.text("1. Yes")}`;
122379
+ const noOptionText = isNoSelected ? `${c.permission(pointer)} ${bold(c.permission("2. No"))}` : ` ${c.text("2. No")}`;
122283
122380
  const element = /* @__PURE__ */ jsxs(Box, {
122284
122381
  direction: "column",
122285
122382
  width: maxCols,
@@ -122299,12 +122396,12 @@ class FilePermissionDock extends Component {
122299
122396
  /* @__PURE__ */ jsx(Text, {
122300
122397
  wrap: false,
122301
122398
  clip: false,
122302
- children: source_default.white.bold(title)
122399
+ children: bold(c.text(title))
122303
122400
  }),
122304
122401
  /* @__PURE__ */ jsx(Text, {
122305
122402
  wrap: false,
122306
122403
  clip: false,
122307
- children: ` ${source_default.dim(filePath)}`
122404
+ children: ` ${c.muted(filePath)}`
122308
122405
  }),
122309
122406
  /* @__PURE__ */ jsx(Text, {
122310
122407
  wrap: false,
@@ -122319,7 +122416,7 @@ class FilePermissionDock extends Component {
122319
122416
  hiddenCount > 0 && /* @__PURE__ */ jsx(Text, {
122320
122417
  wrap: false,
122321
122418
  clip: false,
122322
- children: ` ${source_default.dim(`(+${hiddenCount} hidden)`)}`
122419
+ children: ` ${c.muted(`(+${hiddenCount} hidden)`)}`
122323
122420
  }),
122324
122421
  /* @__PURE__ */ jsx(Text, {
122325
122422
  wrap: false,
@@ -122329,7 +122426,7 @@ class FilePermissionDock extends Component {
122329
122426
  /* @__PURE__ */ jsx(Text, {
122330
122427
  wrap: false,
122331
122428
  clip: false,
122332
- children: source_default.white(question)
122429
+ children: c.text(question)
122333
122430
  }),
122334
122431
  /* @__PURE__ */ jsx(Text, {
122335
122432
  wrap: false,
@@ -122354,7 +122451,7 @@ class FilePermissionDock extends Component {
122354
122451
  /* @__PURE__ */ jsx(Text, {
122355
122452
  wrap: false,
122356
122453
  clip: false,
122357
- children: mutedColor(source_default.italic("Esc to cancel · f to review"))
122454
+ children: italic(c.muted("Esc to cancel · f to review"))
122358
122455
  })
122359
122456
  ]
122360
122457
  });
@@ -122493,6 +122590,67 @@ class PermissionQueue {
122493
122590
  }
122494
122591
  }
122495
122592
  }
122593
+
122594
+ // src/tui/utils/transcript.ts
122595
+ function formatTurnFooter(engine, turnPresentationEnd) {
122596
+ if (!turnPresentationEnd)
122597
+ return;
122598
+ if (turnPresentationEnd.status === "complete") {
122599
+ engine.commit("system", [
122600
+ "",
122601
+ formatTurnStatus(turnPresentationEnd.durationMs, new Date(turnPresentationEnd.finishedAt), turnPresentationEnd.statusVerb)
122602
+ ]);
122603
+ if (turnPresentationEnd.stopReason === "step-limit") {
122604
+ engine.commit("system", formatSystemMessage("Step budget reached. Generation stopped early."));
122605
+ }
122606
+ } else if ((turnPresentationEnd.status === "errored" || turnPresentationEnd.status === "interrupted") && turnPresentationEnd.errorMessage) {
122607
+ const structured = classifyError(new Error(turnPresentationEnd.errorMessage));
122608
+ engine.commit("system", formatErrorBadge(structured));
122609
+ }
122610
+ }
122611
+ function renderTranscript(engine, sessionData, header) {
122612
+ engine.clearAll();
122613
+ engine.commit("header", header.render());
122614
+ const log = loadSessionLog(sessionData.date, sessionData.id);
122615
+ const projection = log ? buildSessionPresentationProjection(log.events) : null;
122616
+ const items = rehydrateSessionHistory(sessionData, projection);
122617
+ let currentTurnId = undefined;
122618
+ for (const item of items) {
122619
+ if (item.turnId && item.turnId !== currentTurnId) {
122620
+ if (currentTurnId && projection) {
122621
+ const prevTurnPresentation = projection.turns.get(currentTurnId)?.end;
122622
+ formatTurnFooter(engine, prevTurnPresentation);
122623
+ }
122624
+ currentTurnId = item.turnId;
122625
+ }
122626
+ if (item.type === "user") {
122627
+ engine.commitPrompt(item.content);
122628
+ } else if (item.type === "system") {
122629
+ engine.commit("system", formatSystemMessage(item.content));
122630
+ } else if (item.type === "tool" && item.toolData) {
122631
+ const toolData = item.toolData;
122632
+ engine.commit("tool-result", (w) => formatToolStatus({
122633
+ toolName: toolData.toolName,
122634
+ displayName: toolData.displayName,
122635
+ icon: toolData.icon,
122636
+ argsSummary: toolData.argsSummary,
122637
+ status: toolData.status,
122638
+ durationMs: toolData.durationMs,
122639
+ error: toolData.error,
122640
+ toolOutput: toolData.toolOutput,
122641
+ targetWidth: w
122642
+ }), { hangingIndent: 2 });
122643
+ } else if (item.type === "assistant") {
122644
+ engine.commit("assistant-message", formatAssistantMessage(item.content), {
122645
+ hangingIndent: 2
122646
+ });
122647
+ }
122648
+ }
122649
+ if (currentTurnId && projection) {
122650
+ const lastTurnPresentation = projection.turns.get(currentTurnId)?.end;
122651
+ formatTurnFooter(engine, lastTurnPresentation);
122652
+ }
122653
+ }
122496
122654
  // src/voice/model.ts
122497
122655
  var VOICE_MODEL_ID = "gemini-3.5-transcribe-live";
122498
122656
  // src/voice/errors.ts
@@ -122591,7 +122749,7 @@ async function defaultCheckParec() {
122591
122749
  }
122592
122750
  async function checkVoicePrerequisites(options = {}) {
122593
122751
  const config = options.config ?? getEnvConfig();
122594
- const checkRecorder = options.checkParecFn ?? options.checkArecordFn ?? defaultCheckParec;
122752
+ const checkRecorder = options.checkParecFn ?? defaultCheckParec;
122595
122753
  const hasGemini = hasProviderConfig("gemini", config);
122596
122754
  const geminiApiKey = config.geminiApiKey;
122597
122755
  if (!hasGemini || !geminiApiKey) {
@@ -123548,7 +123706,6 @@ class TUIApp {
123548
123706
  });
123549
123707
  this.statusBar = new StatusBar({
123550
123708
  model,
123551
- usage: this.session.session.totalUsage,
123552
123709
  isBusy: false
123553
123710
  });
123554
123711
  this.voiceController = new VoiceController({
@@ -123832,8 +123989,10 @@ class TUIApp {
123832
123989
  onSelect: (selected) => {
123833
123990
  setActiveTheme(selected.name);
123834
123991
  saveThemeSelection(selected.name);
123835
- for (const comp of this.engine.components)
123836
- comp.markDirty();
123992
+ renderTranscript(this.engine, this.session.session, this.header);
123993
+ this.engine.mount(this.streamingView);
123994
+ this.engine.mount(this.promptInput, { keepCursorVisible: true, kind: "input" });
123995
+ this.engine.mount(this.statusBar);
123837
123996
  this.engine.requestFrame(true);
123838
123997
  this.engine.commit("system", formatSystemMessage(`Theme switched to ${selected.label}.`));
123839
123998
  this.closeModal();
@@ -123846,74 +124005,13 @@ class TUIApp {
123846
124005
  }
123847
124006
  switchToSession(selected) {
123848
124007
  this.permissionQueue.clear();
124008
+ recoverPendingCheckpoint(this.cwd, selected.id).catch(() => {});
123849
124009
  this.session.shutdown().catch(() => {});
123850
124010
  this.session = AgentSession.resume(selected);
123851
124011
  const model = this.session.getModel();
123852
124012
  this.header.props.model = model;
123853
- this.statusBar.update({ model, usage: this.session.session.totalUsage });
123854
- this.engine.clearAll();
123855
- this.engine.commit("header", this.header.render());
123856
- const log = loadSessionLog(selected.date, selected.id);
123857
- const projection = log ? buildSessionPresentationProjection(log.events) : null;
123858
- const items = rehydrateSessionHistory(selected, projection);
123859
- let currentTurnId = undefined;
123860
- for (const item of items) {
123861
- if (item.turnId && item.turnId !== currentTurnId) {
123862
- if (currentTurnId && projection) {
123863
- const prevTurnPresentation = projection.turns.get(currentTurnId)?.end;
123864
- if (prevTurnPresentation && prevTurnPresentation.status === "complete") {
123865
- this.engine.commit("system", [
123866
- "",
123867
- formatTurnStatus(prevTurnPresentation.durationMs, new Date(prevTurnPresentation.finishedAt), prevTurnPresentation.statusVerb)
123868
- ]);
123869
- if (prevTurnPresentation.stopReason === "step-limit") {
123870
- this.engine.commit("system", formatSystemMessage("Step budget reached. Generation stopped early."));
123871
- }
123872
- } else if (prevTurnPresentation && (prevTurnPresentation.status === "errored" || prevTurnPresentation.status === "interrupted") && prevTurnPresentation.errorMessage) {
123873
- const structured = classifyError(new Error(prevTurnPresentation.errorMessage));
123874
- this.engine.commit("system", formatErrorBadge(structured));
123875
- }
123876
- }
123877
- currentTurnId = item.turnId;
123878
- }
123879
- if (item.type === "user") {
123880
- this.engine.commitPrompt(item.content);
123881
- } else if (item.type === "system") {
123882
- this.engine.commit("system", formatSystemMessage(item.content));
123883
- } else if (item.type === "tool" && item.toolData) {
123884
- const toolData = item.toolData;
123885
- this.engine.commit("tool-result", (w) => formatToolStatus({
123886
- toolName: toolData.toolName,
123887
- displayName: toolData.displayName,
123888
- icon: toolData.icon,
123889
- argsSummary: toolData.argsSummary,
123890
- status: toolData.status,
123891
- durationMs: toolData.durationMs,
123892
- error: toolData.error,
123893
- toolOutput: toolData.toolOutput,
123894
- targetWidth: w
123895
- }), { hangingIndent: 2 });
123896
- } else if (item.type === "assistant") {
123897
- this.engine.commit("assistant-message", formatAssistantMessage(item.content), {
123898
- hangingIndent: 2
123899
- });
123900
- }
123901
- }
123902
- if (currentTurnId && projection) {
123903
- const lastTurnPresentation = projection.turns.get(currentTurnId)?.end;
123904
- if (lastTurnPresentation && lastTurnPresentation.status === "complete") {
123905
- this.engine.commit("system", [
123906
- "",
123907
- formatTurnStatus(lastTurnPresentation.durationMs, new Date(lastTurnPresentation.finishedAt), lastTurnPresentation.statusVerb)
123908
- ]);
123909
- if (lastTurnPresentation.stopReason === "step-limit") {
123910
- this.engine.commit("system", formatSystemMessage("Step budget reached. Generation stopped early."));
123911
- }
123912
- } else if (lastTurnPresentation && (lastTurnPresentation.status === "errored" || lastTurnPresentation.status === "interrupted") && lastTurnPresentation.errorMessage) {
123913
- const structured = classifyError(new Error(lastTurnPresentation.errorMessage));
123914
- this.engine.commit("system", formatErrorBadge(structured));
123915
- }
123916
- }
124013
+ this.statusBar.update({ model });
124014
+ renderTranscript(this.engine, selected, this.header);
123917
124015
  this.engine.mount(this.streamingView);
123918
124016
  this.engine.mount(this.promptInput, { keepCursorVisible: true, kind: "input" });
123919
124017
  this.engine.mount(this.statusBar);
@@ -124054,8 +124152,7 @@ class TUIApp {
124054
124152
  const updatedModel = this.session.getModel();
124055
124153
  this.header.props.model = updatedModel;
124056
124154
  this.statusBar.update({
124057
- model: updatedModel,
124058
- usage: this.session.session.totalUsage
124155
+ model: updatedModel
124059
124156
  });
124060
124157
  return;
124061
124158
  }
@@ -124111,7 +124208,7 @@ class TUIApp {
124111
124208
  const argsSummary = JSON.stringify(event.toolResult.args);
124112
124209
  const status = event.toolResult.isError ? "failed" : "completed";
124113
124210
  const error = event.toolResult.isError ? typeof event.toolResult.result === "object" && event.toolResult.result !== null ? event.toolResult.result.message ?? JSON.stringify(event.toolResult.result) : String(event.toolResult.result) : undefined;
124114
- const toolOutput = !event.toolResult.isError && toolDef?.summarize ? toolDef.summarize(event.toolResult.args, event.toolResult.result) : undefined;
124211
+ const summary = summarizeToolResult(toolDef, event.toolResult.args, event.toolResult.result, event.toolResult.isError);
124115
124212
  this.engine.commit("tool-result", (w) => formatToolStatus({
124116
124213
  toolName,
124117
124214
  displayName,
@@ -124120,7 +124217,7 @@ class TUIApp {
124120
124217
  status,
124121
124218
  durationMs,
124122
124219
  error,
124123
- toolOutput,
124220
+ summary,
124124
124221
  targetWidth: w
124125
124222
  }), { hangingIndent: 2 });
124126
124223
  this.streamingView.setThinking(true);
@@ -124142,9 +124239,6 @@ class TUIApp {
124142
124239
  "",
124143
124240
  formatTurnStatus(totalDurationMs, finishedAt, event.summary.statusVerb)
124144
124241
  ]);
124145
- this.statusBar.update({
124146
- usage: this.session.session.totalUsage
124147
- });
124148
124242
  if (event.summary.stopReason === "step-limit") {
124149
124243
  this.engine.commit("system", formatSystemMessage("Step budget reached. Generation stopped early."));
124150
124244
  }
@@ -124174,9 +124268,6 @@ class TUIApp {
124174
124268
  this.closeModal();
124175
124269
  }
124176
124270
  this.setBusy(false);
124177
- this.statusBar.update({
124178
- usage: this.session.session.totalUsage
124179
- });
124180
124271
  }
124181
124272
  }
124182
124273
  setBusy(busy) {