@nghyane/arcane 0.1.8 → 0.1.11

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.
Files changed (131) hide show
  1. package/package.json +6 -6
  2. package/src/config/settings-schema.ts +0 -10
  3. package/src/discovery/helpers.ts +1 -6
  4. package/src/index.ts +1 -0
  5. package/src/main.ts +3 -0
  6. package/src/memories/index.ts +3 -3
  7. package/src/modes/components/model-selector.ts +1 -1
  8. package/src/modes/components/settings-defs.ts +0 -8
  9. package/src/modes/components/status-line.ts +15 -40
  10. package/src/modes/components/user-message.ts +2 -0
  11. package/src/modes/components/welcome.ts +1 -1
  12. package/src/modes/interactive-mode.ts +2 -0
  13. package/src/modes/theme/dark.json +56 -59
  14. package/src/modes/theme/defaults/dark-catppuccin.json +47 -56
  15. package/src/modes/theme/defaults/dark-dracula.json +24 -32
  16. package/src/modes/theme/defaults/dark-gruvbox.json +53 -74
  17. package/src/modes/theme/defaults/dark-solarized.json +33 -35
  18. package/src/modes/theme/defaults/dark-tokyo-night.json +57 -67
  19. package/src/modes/theme/defaults/index.ts +3 -179
  20. package/src/modes/theme/defaults/light-catppuccin.json +42 -50
  21. package/src/modes/theme/defaults/light-github.json +68 -94
  22. package/src/modes/theme/defaults/light-solarized.json +41 -49
  23. package/src/modes/theme/light.json +14 -12
  24. package/src/modes/theme/theme-schema.json +4 -0
  25. package/src/modes/theme/theme.ts +89 -6
  26. package/src/patch/applicator.ts +12 -4
  27. package/src/prompts/agents/task.md +1 -1
  28. package/src/prompts/system/subagent-system-prompt.md +2 -14
  29. package/src/prompts/system/system-prompt.md +12 -14
  30. package/src/prompts/tools/task.md +49 -178
  31. package/src/prompts/tools/todo-write.md +4 -4
  32. package/src/sdk.ts +15 -16
  33. package/src/session/session-manager.ts +1 -3
  34. package/src/task/executor.ts +2 -2
  35. package/src/task/index.ts +5 -5
  36. package/src/task/types.ts +7 -20
  37. package/src/tools/index.ts +16 -33
  38. package/src/tools/subagent-tool.ts +5 -5
  39. package/src/tools/todo-write.ts +0 -37
  40. package/src/tui/output-block.ts +2 -12
  41. package/src/modes/theme/defaults/alabaster.json +0 -93
  42. package/src/modes/theme/defaults/amethyst.json +0 -96
  43. package/src/modes/theme/defaults/anthracite.json +0 -93
  44. package/src/modes/theme/defaults/basalt.json +0 -91
  45. package/src/modes/theme/defaults/birch.json +0 -95
  46. package/src/modes/theme/defaults/dark-abyss.json +0 -91
  47. package/src/modes/theme/defaults/dark-arctic.json +0 -104
  48. package/src/modes/theme/defaults/dark-aurora.json +0 -95
  49. package/src/modes/theme/defaults/dark-cavern.json +0 -91
  50. package/src/modes/theme/defaults/dark-copper.json +0 -95
  51. package/src/modes/theme/defaults/dark-cosmos.json +0 -90
  52. package/src/modes/theme/defaults/dark-cyberpunk.json +0 -102
  53. package/src/modes/theme/defaults/dark-eclipse.json +0 -91
  54. package/src/modes/theme/defaults/dark-ember.json +0 -95
  55. package/src/modes/theme/defaults/dark-equinox.json +0 -90
  56. package/src/modes/theme/defaults/dark-forest.json +0 -96
  57. package/src/modes/theme/defaults/dark-github.json +0 -105
  58. package/src/modes/theme/defaults/dark-lavender.json +0 -95
  59. package/src/modes/theme/defaults/dark-lunar.json +0 -89
  60. package/src/modes/theme/defaults/dark-midnight.json +0 -95
  61. package/src/modes/theme/defaults/dark-monochrome.json +0 -94
  62. package/src/modes/theme/defaults/dark-monokai.json +0 -98
  63. package/src/modes/theme/defaults/dark-nebula.json +0 -90
  64. package/src/modes/theme/defaults/dark-nord.json +0 -97
  65. package/src/modes/theme/defaults/dark-ocean.json +0 -101
  66. package/src/modes/theme/defaults/dark-one.json +0 -100
  67. package/src/modes/theme/defaults/dark-rainforest.json +0 -91
  68. package/src/modes/theme/defaults/dark-reef.json +0 -91
  69. package/src/modes/theme/defaults/dark-retro.json +0 -92
  70. package/src/modes/theme/defaults/dark-rose-pine.json +0 -96
  71. package/src/modes/theme/defaults/dark-sakura.json +0 -95
  72. package/src/modes/theme/defaults/dark-slate.json +0 -95
  73. package/src/modes/theme/defaults/dark-solstice.json +0 -90
  74. package/src/modes/theme/defaults/dark-starfall.json +0 -91
  75. package/src/modes/theme/defaults/dark-sunset.json +0 -99
  76. package/src/modes/theme/defaults/dark-swamp.json +0 -90
  77. package/src/modes/theme/defaults/dark-synthwave.json +0 -103
  78. package/src/modes/theme/defaults/dark-taiga.json +0 -91
  79. package/src/modes/theme/defaults/dark-terminal.json +0 -95
  80. package/src/modes/theme/defaults/dark-tundra.json +0 -91
  81. package/src/modes/theme/defaults/dark-twilight.json +0 -91
  82. package/src/modes/theme/defaults/dark-volcanic.json +0 -91
  83. package/src/modes/theme/defaults/graphite.json +0 -92
  84. package/src/modes/theme/defaults/light-arctic.json +0 -107
  85. package/src/modes/theme/defaults/light-aurora-day.json +0 -91
  86. package/src/modes/theme/defaults/light-canyon.json +0 -91
  87. package/src/modes/theme/defaults/light-cirrus.json +0 -90
  88. package/src/modes/theme/defaults/light-coral.json +0 -95
  89. package/src/modes/theme/defaults/light-cyberpunk.json +0 -96
  90. package/src/modes/theme/defaults/light-dawn.json +0 -90
  91. package/src/modes/theme/defaults/light-dunes.json +0 -91
  92. package/src/modes/theme/defaults/light-eucalyptus.json +0 -95
  93. package/src/modes/theme/defaults/light-forest.json +0 -100
  94. package/src/modes/theme/defaults/light-frost.json +0 -95
  95. package/src/modes/theme/defaults/light-glacier.json +0 -91
  96. package/src/modes/theme/defaults/light-gruvbox.json +0 -108
  97. package/src/modes/theme/defaults/light-haze.json +0 -90
  98. package/src/modes/theme/defaults/light-honeycomb.json +0 -95
  99. package/src/modes/theme/defaults/light-lagoon.json +0 -91
  100. package/src/modes/theme/defaults/light-lavender.json +0 -95
  101. package/src/modes/theme/defaults/light-meadow.json +0 -91
  102. package/src/modes/theme/defaults/light-mint.json +0 -95
  103. package/src/modes/theme/defaults/light-monochrome.json +0 -101
  104. package/src/modes/theme/defaults/light-ocean.json +0 -99
  105. package/src/modes/theme/defaults/light-one.json +0 -99
  106. package/src/modes/theme/defaults/light-opal.json +0 -91
  107. package/src/modes/theme/defaults/light-orchard.json +0 -91
  108. package/src/modes/theme/defaults/light-paper.json +0 -95
  109. package/src/modes/theme/defaults/light-prism.json +0 -90
  110. package/src/modes/theme/defaults/light-retro.json +0 -98
  111. package/src/modes/theme/defaults/light-sand.json +0 -95
  112. package/src/modes/theme/defaults/light-savanna.json +0 -91
  113. package/src/modes/theme/defaults/light-soleil.json +0 -90
  114. package/src/modes/theme/defaults/light-sunset.json +0 -99
  115. package/src/modes/theme/defaults/light-synthwave.json +0 -98
  116. package/src/modes/theme/defaults/light-tokyo-night.json +0 -111
  117. package/src/modes/theme/defaults/light-wetland.json +0 -91
  118. package/src/modes/theme/defaults/light-zenith.json +0 -89
  119. package/src/modes/theme/defaults/limestone.json +0 -94
  120. package/src/modes/theme/defaults/mahogany.json +0 -97
  121. package/src/modes/theme/defaults/marble.json +0 -93
  122. package/src/modes/theme/defaults/obsidian.json +0 -91
  123. package/src/modes/theme/defaults/onyx.json +0 -91
  124. package/src/modes/theme/defaults/pearl.json +0 -93
  125. package/src/modes/theme/defaults/porcelain.json +0 -91
  126. package/src/modes/theme/defaults/quartz.json +0 -96
  127. package/src/modes/theme/defaults/sandstone.json +0 -95
  128. package/src/modes/theme/defaults/titanium.json +0 -90
  129. package/src/prompts/system/subagent-submit-reminder.md +0 -11
  130. package/src/tools/jtd-to-json-schema.ts +0 -247
  131. package/src/tools/submit-result.ts +0 -152
@@ -2,14 +2,11 @@
2
2
  "$schema": "https://raw.githubusercontent.com/nghyane/arcane/main/packages/coding-agent/theme-schema.json",
3
3
  "name": "light-solarized",
4
4
  "vars": {
5
- "base03": "#002b36",
6
- "base02": "#073642",
7
- "base01": "#586e75",
8
- "base00": "#657b83",
9
- "base0": "#839496",
10
- "base1": "#93a1a1",
11
5
  "base2": "#eee8d5",
12
6
  "base3": "#fdf6e3",
7
+ "base00": "#657b83",
8
+ "base01": "#586e75",
9
+ "base1": "#93a1a1",
13
10
  "yellow": "#b58900",
14
11
  "orange": "#cb4b16",
15
12
  "red": "#dc322f",
@@ -17,86 +14,81 @@
17
14
  "violet": "#6c71c4",
18
15
  "blue": "#268bd2",
19
16
  "cyan": "#2aa198",
20
- "green": "#859900",
21
- "selectedBg": "#e3dcc8",
22
- "userMsgBg": "#f5f0e6",
23
- "toolPendingBg": "#eef4f9",
24
- "toolSuccessBg": "#eff5ed",
25
- "toolErrorBg": "#f9eeee",
26
- "customMsgBg": "#f2eff7"
17
+ "green": "#859900"
27
18
  },
28
19
  "colors": {
29
- "accent": "cyan",
30
- "border": "blue",
31
- "borderAccent": "cyan",
20
+ "accent": "blue",
21
+ "border": "cyan",
22
+ "borderAccent": "blue",
32
23
  "borderMuted": "base1",
33
24
  "success": "green",
34
25
  "error": "red",
35
26
  "warning": "yellow",
36
- "muted": "base01",
27
+ "muted": "base00",
37
28
  "dim": "base1",
38
29
  "text": "",
39
- "thinkingText": "base01",
40
- "selectedBg": "selectedBg",
41
- "userMessageBg": "userMsgBg",
30
+ "thinkingText": "base00",
31
+ "selectedBg": "^-2",
32
+ "userMessageBg": "^-2",
42
33
  "userMessageText": "",
43
- "customMessageBg": "customMsgBg",
34
+ "customMessageBg": "^-2",
44
35
  "customMessageText": "",
45
- "customMessageLabel": "violet",
46
- "toolPendingBg": "toolPendingBg",
47
- "toolSuccessBg": "toolSuccessBg",
48
- "toolErrorBg": "toolErrorBg",
36
+ "customMessageLabel": "blue",
37
+ "toolPendingBg": "^-3",
38
+ "toolSuccessBg": "^-2",
39
+ "toolErrorBg": "^-3",
49
40
  "toolTitle": "",
50
- "toolOutput": "base01",
41
+ "toolOutput": "base00",
51
42
  "mdHeading": "yellow",
52
43
  "mdLink": "blue",
53
- "mdLinkUrl": "base1",
44
+ "mdLinkUrl": "base00",
54
45
  "mdCode": "cyan",
55
46
  "mdCodeBlock": "green",
56
47
  "mdCodeBlockBorder": "base1",
57
- "mdQuote": "base01",
48
+ "mdQuote": "base00",
58
49
  "mdQuoteBorder": "base1",
59
50
  "mdHr": "base1",
60
- "mdListBullet": "green",
51
+ "mdListBullet": "cyan",
61
52
  "toolDiffAdded": "green",
62
53
  "toolDiffRemoved": "red",
63
- "toolDiffContext": "base01",
54
+ "toolDiffContext": "base00",
64
55
  "link": "blue",
65
56
  "syntaxComment": "base1",
66
- "syntaxKeyword": "green",
57
+ "syntaxKeyword": "orange",
67
58
  "syntaxFunction": "blue",
68
59
  "syntaxVariable": "cyan",
69
- "syntaxString": "cyan",
60
+ "syntaxString": "green",
70
61
  "syntaxNumber": "magenta",
71
62
  "syntaxType": "yellow",
72
- "syntaxOperator": "base00",
73
- "syntaxPunctuation": "base00",
63
+ "syntaxOperator": "base01",
64
+ "syntaxPunctuation": "base01",
74
65
  "thinkingOff": "base1",
75
- "thinkingMinimal": "base01",
76
- "thinkingLow": "blue",
77
- "thinkingMedium": "cyan",
66
+ "thinkingMinimal": "base00",
67
+ "thinkingLow": "cyan",
68
+ "thinkingMedium": "blue",
78
69
  "thinkingHigh": "violet",
79
70
  "thinkingXhigh": "magenta",
80
71
  "bashMode": "green",
81
- "statusLineBg": "base3",
72
+ "statusLineBg": "^2",
82
73
  "statusLineSep": "base1",
83
- "statusLineModel": "magenta",
74
+ "statusLineModel": "blue",
84
75
  "statusLinePath": "cyan",
85
76
  "statusLineGitClean": "green",
86
77
  "statusLineGitDirty": "yellow",
87
- "statusLineContext": "violet",
78
+ "statusLineContext": "base00",
88
79
  "statusLineSpend": "cyan",
89
- "statusLineStaged": "green",
90
- "statusLineDirty": "orange",
91
- "statusLineUntracked": "blue",
92
- "statusLineOutput": "magenta",
93
- "statusLineCost": "red",
94
- "statusLineSubagents": "cyan",
95
- "pythonMode": "yellow"
80
+ "statusLineStaged": 64,
81
+ "statusLineDirty": 136,
82
+ "statusLineUntracked": 37,
83
+ "statusLineOutput": 37,
84
+ "statusLineCost": 64,
85
+ "statusLineSubagents": "blue",
86
+ "pythonMode": "yellow",
87
+ "appBg": "^0"
96
88
  },
97
89
  "export": {
98
- "pageBg": "base3",
90
+ "pageBg": "#fdf6e3",
99
91
  "cardBg": "#ffffff",
100
- "infoBg": "base2"
92
+ "infoBg": "#eee8d5"
101
93
  }
102
94
  }
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://raw.githubusercontent.com/nghyane/arcane/main/packages/coding-agent/theme-schema.json",
3
3
  "name": "light",
4
4
  "vars": {
5
- "teal": "#5a8080",
5
+ "teal": "#3e8a8a",
6
6
  "blue": "#547da7",
7
7
  "green": "#588458",
8
8
  "red": "#aa5555",
@@ -43,6 +43,7 @@
43
43
  "mdHeading": "yellow",
44
44
  "mdLink": "blue",
45
45
  "mdLinkUrl": "dimGray",
46
+ "link": "blue",
46
47
  "mdCode": "teal",
47
48
  "mdCodeBlock": "green",
48
49
  "mdCodeBlockBorder": "mediumGray",
@@ -53,17 +54,17 @@
53
54
  "toolDiffAdded": "green",
54
55
  "toolDiffRemoved": "red",
55
56
  "toolDiffContext": "mediumGray",
56
- "syntaxComment": "#008000",
57
- "syntaxKeyword": "#0000FF",
58
- "syntaxFunction": "#795E26",
59
- "syntaxVariable": "#001080",
60
- "syntaxString": "#A31515",
61
- "syntaxNumber": "#098658",
62
- "syntaxType": "#267F99",
63
- "syntaxOperator": "#000000",
64
- "syntaxPunctuation": "#000000",
57
+ "syntaxComment": "#8a8a8a",
58
+ "syntaxKeyword": "#a626a4",
59
+ "syntaxFunction": "#4078f2",
60
+ "syntaxVariable": "#986801",
61
+ "syntaxString": "#50a14f",
62
+ "syntaxNumber": "#986801",
63
+ "syntaxType": "#c18401",
64
+ "syntaxOperator": "#4078f2",
65
+ "syntaxPunctuation": "#696c77",
65
66
  "thinkingOff": "lightGray",
66
- "thinkingMinimal": "#767676",
67
+ "thinkingMinimal": "dimGray",
67
68
  "thinkingLow": "blue",
68
69
  "thinkingMedium": "teal",
69
70
  "thinkingHigh": "#875f87",
@@ -83,7 +84,8 @@
83
84
  "statusLineOutput": 133,
84
85
  "statusLineCost": 133,
85
86
  "statusLineSubagents": "teal",
86
- "pythonMode": "yellow"
87
+ "pythonMode": "yellow",
88
+ "appBg": "^0"
87
89
  },
88
90
  "export": {
89
91
  "pageBg": "#f8f8f8",
@@ -315,6 +315,10 @@
315
315
  "$ref": "#/$defs/colorValue",
316
316
  "description": "Status line background"
317
317
  },
318
+ "appBg": {
319
+ "$ref": "#/$defs/colorValue",
320
+ "description": "App-wide background color"
321
+ },
318
322
  "statusLineSep": {
319
323
  "$ref": "#/$defs/colorValue",
320
324
  "description": "Status line separator color"
@@ -6,7 +6,7 @@ import {
6
6
  supportsLanguage as nativeSupportsLanguage,
7
7
  } from "@nghyane/arcane-natives";
8
8
  import type { EditorTheme, MarkdownTheme, SelectListTheme, SymbolTheme } from "@nghyane/arcane-tui";
9
- import { adjustHsv, isEnoent, logger } from "@nghyane/arcane-utils";
9
+ import { adjustHsv, hexToHsv, hsvToHex, isEnoent, logger } from "@nghyane/arcane-utils";
10
10
  import { getCustomThemesDir } from "@nghyane/arcane-utils/dirs";
11
11
  import { type Static, Type } from "@sinclair/typebox";
12
12
  import { TypeCompiler } from "@sinclair/typebox/compiler";
@@ -959,7 +959,8 @@ export type ThemeBg =
959
959
  | "toolPendingBg"
960
960
  | "toolSuccessBg"
961
961
  | "toolErrorBg"
962
- | "statusLineBg";
962
+ | "statusLineBg"
963
+ | "appBg";
963
964
 
964
965
  type ColorMode = "truecolor" | "256color";
965
966
 
@@ -1015,7 +1016,7 @@ function resolveVarRefs(
1015
1016
  vars: Record<string, ColorValue>,
1016
1017
  visited = new Set<string>(),
1017
1018
  ): string | number {
1018
- if (typeof value === "number" || value === "" || value.startsWith("#")) {
1019
+ if (typeof value === "number" || value === "" || value.startsWith("#") || value.startsWith("^")) {
1019
1020
  return value;
1020
1021
  }
1021
1022
  if (visited.has(value)) {
@@ -1171,10 +1172,28 @@ export class Theme {
1171
1172
  return `${ansi}${text}\x1b[39m`; // Reset only foreground color
1172
1173
  }
1173
1174
 
1174
- bg(color: ThemeBg, text: string): string {
1175
+ /**
1176
+ * Wrap text with a background color, stabilizing inner SGR resets.
1177
+ * When terminal bg is not detected, uses reverse video as fallback.
1178
+ * This is the single source of truth for bg wrapping — all bg rendering goes through here.
1179
+ */
1180
+ wrapBg(color: ThemeBg, text: string): string {
1175
1181
  const ansi = this.#bgColors[color];
1176
1182
  if (!ansi) throw new Error(`Unknown theme background color: ${color}`);
1177
- return `${ansi}${text}\x1b[49m`; // Reset only background color
1183
+ if (ansi === "\x1b[49m") {
1184
+ // Transparent fallback: reverse video with fg color preservation
1185
+ const stabilized = text
1186
+ .replace(/\x1b\[(?:0)?m/g, m => `${m}\x1b[7m`)
1187
+ .replace(/\x1b\[(?:3[0-9]m|38;)/g, m => `\x1b[27m${m}`);
1188
+ return `\x1b[7m${stabilized}\x1b[27m`;
1189
+ }
1190
+ // Real bg: stabilize inner resets by re-applying bg after them
1191
+ const stabilized = text.replace(/\x1b\[(?:0)?m/g, m => `${m}${ansi}`).replace(/\x1b\[49m/g, m => `${m}${ansi}`);
1192
+ return `${ansi}${stabilized}${this.#bgColors.appBg}`;
1193
+ }
1194
+
1195
+ bg(color: ThemeBg, text: string): string {
1196
+ return this.wrapBg(color, text);
1178
1197
  }
1179
1198
 
1180
1199
  bold(text: string): string {
@@ -1209,6 +1228,19 @@ export class Theme {
1209
1228
  return ansi;
1210
1229
  }
1211
1230
 
1231
+ getAppBgAnsi(): string {
1232
+ return this.#bgColors.appBg;
1233
+ }
1234
+
1235
+ getAppBgPackedRgb(): number {
1236
+ const ansi = this.#bgColors.appBg;
1237
+ const match = ansi.match(/\x1b\[48;2;(\d+);(\d+);(\d+)m/);
1238
+ if (!match) return 0;
1239
+ return (
1240
+ ((Number(match[1]) & 0xff) << 16) | ((Number(match[2]) & 0xff) << 8) | (Number(match[3]) & 0xff) | 0x01000000
1241
+ );
1242
+ }
1243
+
1212
1244
  getColorMode(): ColorMode {
1213
1245
  return this.mode;
1214
1246
  }
@@ -1563,11 +1595,48 @@ interface CreateThemeOptions {
1563
1595
  mode?: ColorMode;
1564
1596
  symbolPresetOverride?: SymbolPreset;
1565
1597
  colorBlindMode?: boolean;
1598
+ terminalBg?: string;
1566
1599
  }
1567
1600
 
1568
1601
  /** HSV adjustment to shift green toward blue for colorblind mode (red-green colorblindness) */
1569
1602
  const COLORBLIND_ADJUSTMENT = { h: 60, s: 0.71 };
1570
1603
 
1604
+ /**
1605
+ * Resolve a relative bg color value against the terminal background.
1606
+ * Format: "^N" where N is a brightness adjustment percentage.
1607
+ * Positive = lighter, negative = darker. E.g., "^5" or "^-3".
1608
+ * Returns the resolved hex color, or the original value if not relative.
1609
+ */
1610
+ function resolveRelativeBg(value: string | number, terminalBg: string): string | number {
1611
+ if (typeof value !== "string" || !value.startsWith("^")) return value;
1612
+ const delta = parseFloat(value.slice(1));
1613
+ if (Number.isNaN(delta)) return value;
1614
+ const hsv = hexToHsv(terminalBg);
1615
+ hsv.v = Math.max(0, Math.min(1, hsv.v + delta / 100));
1616
+ return hsvToHex(hsv);
1617
+ }
1618
+
1619
+ function detectDefaultSymbolPreset(): SymbolPreset {
1620
+ const termProgram = Bun.env.TERM_PROGRAM ?? "";
1621
+ const term = Bun.env.TERM ?? "";
1622
+
1623
+ // Terminals with known Nerd Font fallback support
1624
+ const nerdFontTerminals = new Set([
1625
+ "iTerm.app",
1626
+ "WezTerm",
1627
+ "Hyper",
1628
+ "vscode",
1629
+ "Termius",
1630
+ "WarpTerminal",
1631
+ "ghostty",
1632
+ "Tabby",
1633
+ ]);
1634
+ if (nerdFontTerminals.has(termProgram)) return "nerd";
1635
+ if (term === "xterm-kitty") return "nerd";
1636
+
1637
+ return "unicode";
1638
+ }
1639
+
1571
1640
  function createTheme(themeJson: ThemeJson, options: CreateThemeOptions = {}): Theme {
1572
1641
  const { mode, symbolPresetOverride, colorBlindMode } = options;
1573
1642
  const colorMode = mode ?? detectColorMode();
@@ -1580,6 +1649,15 @@ function createTheme(themeJson: ThemeJson, options: CreateThemeOptions = {}): Th
1580
1649
  }
1581
1650
  }
1582
1651
 
1652
+ // Resolve relative bg colors (^N format) against terminal background
1653
+ const termBg = options.terminalBg;
1654
+ for (const key of Object.keys(resolvedColors) as Array<keyof typeof resolvedColors>) {
1655
+ const value = resolvedColors[key];
1656
+ if (typeof value === "string" && value.startsWith("^")) {
1657
+ resolvedColors[key] = termBg ? resolveRelativeBg(value, termBg) : "";
1658
+ }
1659
+ }
1660
+
1583
1661
  const fgColors: Record<ThemeColor, string | number> = {} as Record<ThemeColor, string | number>;
1584
1662
  const bgColors: Record<ThemeBg, string | number> = {} as Record<ThemeBg, string | number>;
1585
1663
  const bgColorKeys: Set<string> = new Set([
@@ -1590,6 +1668,7 @@ function createTheme(themeJson: ThemeJson, options: CreateThemeOptions = {}): Th
1590
1668
  "toolSuccessBg",
1591
1669
  "toolErrorBg",
1592
1670
  "statusLineBg",
1671
+ "appBg",
1593
1672
  ]);
1594
1673
  for (const [key, value] of Object.entries(resolvedColors)) {
1595
1674
  if (bgColorKeys.has(key)) {
@@ -1599,7 +1678,7 @@ function createTheme(themeJson: ThemeJson, options: CreateThemeOptions = {}): Th
1599
1678
  }
1600
1679
  }
1601
1680
  // Extract symbol configuration - settings override takes precedence over theme
1602
- const symbolPreset: SymbolPreset = symbolPresetOverride ?? themeJson.symbols?.preset ?? "unicode";
1681
+ const symbolPreset: SymbolPreset = symbolPresetOverride ?? themeJson.symbols?.preset ?? detectDefaultSymbolPreset();
1603
1682
  const symbolOverrides = themeJson.symbols?.overrides ?? {};
1604
1683
  return new Theme(fgColors, bgColors, colorMode, symbolPreset, symbolOverrides);
1605
1684
  }
@@ -1650,6 +1729,7 @@ export function getCurrentThemeName(): string | undefined {
1650
1729
  }
1651
1730
  var currentSymbolPresetOverride: SymbolPreset | undefined;
1652
1731
  var currentColorBlindMode: boolean = false;
1732
+ var currentTerminalBg: string | undefined;
1653
1733
  var themeWatcher: fs.FSWatcher | undefined;
1654
1734
  var sigwinchHandler: (() => void) | undefined;
1655
1735
  var autoDetectedTheme: boolean = false;
@@ -1662,6 +1742,7 @@ function getCurrentThemeOptions(): CreateThemeOptions {
1662
1742
  return {
1663
1743
  symbolPresetOverride: currentSymbolPresetOverride,
1664
1744
  colorBlindMode: currentColorBlindMode,
1745
+ terminalBg: currentTerminalBg,
1665
1746
  };
1666
1747
  }
1667
1748
 
@@ -1671,6 +1752,7 @@ export async function initTheme(
1671
1752
  colorBlindMode?: boolean,
1672
1753
  darkTheme?: string,
1673
1754
  lightTheme?: string,
1755
+ terminalBg?: string,
1674
1756
  ): Promise<void> {
1675
1757
  autoDetectedTheme = true;
1676
1758
  autoDarkTheme = darkTheme ?? "dark";
@@ -1679,6 +1761,7 @@ export async function initTheme(
1679
1761
  currentThemeName = name;
1680
1762
  currentSymbolPresetOverride = symbolPreset;
1681
1763
  currentColorBlindMode = colorBlindMode ?? false;
1764
+ currentTerminalBg = terminalBg;
1682
1765
  try {
1683
1766
  theme = await loadTheme(name, getCurrentThemeOptions());
1684
1767
  if (enableWatcher) {
@@ -890,10 +890,11 @@ function applyCharacterMatch(
890
890
  const adjustedNewText = adjustIndentation(normalizedOldText, matchOutcome.match.actualText, newText);
891
891
 
892
892
  const warnings: string[] = [];
893
- if (matchOutcome.dominantFuzzy && matchOutcome.match) {
893
+ if (matchOutcome.match && matchOutcome.match.confidence < 0.97) {
894
894
  const similarity = Math.round(matchOutcome.match.confidence * 100);
895
+ const qualifier = matchOutcome.dominantFuzzy ? "Dominant fuzzy" : "Fuzzy";
895
896
  warnings.push(
896
- `Dominant fuzzy match selected in ${path} near line ${matchOutcome.match.startLine} (${similarity}% similar).`,
897
+ `${qualifier} match applied in ${path} near line ${matchOutcome.match.startLine} (${similarity}% similar).`,
897
898
  );
898
899
  }
899
900
 
@@ -1152,9 +1153,16 @@ function computeReplacements(
1152
1153
 
1153
1154
  const found = searchResult.index;
1154
1155
 
1155
- if (searchResult.strategy === "fuzzy-dominant") {
1156
+ if (
1157
+ searchResult.strategy === "prefix" ||
1158
+ searchResult.strategy === "substring" ||
1159
+ searchResult.strategy === "fuzzy" ||
1160
+ searchResult.strategy === "fuzzy-dominant"
1161
+ ) {
1156
1162
  const similarity = Math.round(searchResult.confidence * 100);
1157
- warnings.push(`Dominant fuzzy match selected in ${path} near line ${found + 1} (${similarity}% similar).`);
1163
+ warnings.push(
1164
+ `Non-exact match applied in ${path} near line ${found + 1} (${similarity}% similar, strategy: ${searchResult.strategy}).`,
1165
+ );
1158
1166
  }
1159
1167
 
1160
1168
  // Reject if match is ambiguous (prefix/substring matching found multiple matches)
@@ -8,7 +8,7 @@ Finish only the assigned work and return the minimum useful result.
8
8
  - Avoid full-file reads unless necessary.
9
9
  - Prefer edits to existing files over creating new ones.
10
10
  - NEVER create documentation files (*.md) unless explicitly requested.
11
- - When spawning subagents with the Task tool, include a 5-8 word user-facing description.
11
+ - When done, write a concise summary of what you did as your final response. This is your output.
12
12
  - Include the smallest relevant code snippet when discussing code or config.
13
13
  - Follow the main agent's instructions.
14
14
  </directives>
@@ -11,20 +11,8 @@ For additional parent conversation context, check {{contextFile}} (`tail -100` o
11
11
  {{/if}}
12
12
 
13
13
  <critical>
14
- - MUST call `submit_result` exactly once when finished. No JSON in text. No plain-text summary. Pass result via `data` parameter.
15
- - Todo tracking is parent-owned. Do not create or maintain a separate todo list in this subagent.
16
- {{#if outputSchema}}
17
- - If cannot complete, call `submit_result` with `status="aborted"` and error message. Do not provide success result or pretend completion.
18
- {{else}}
19
- - If cannot complete, call `submit_result` with `status="aborted"` and error message. Do not claim success.
20
- {{/if}}
21
- {{#if outputSchema}}
22
- - `data` parameter MUST be valid JSON matching TypeScript interface:
23
- ```ts
24
- {{jtdToTypeScript outputSchema}}
25
- ```
26
- {{/if}}
27
- - If cannot complete, call `submit_result` exactly once with result indicating failure/abort status (use failure/notes field if available). Do not claim success.
14
+ - When done, stop. Your final text response is your output the parent receives it as the task result.
15
+ - If cannot complete, report failure clearly in your final response. Do not claim success.
28
16
  - Do NOT abort due to uncertainty or missing info that can be obtained via tools or repo context. Use `find`/`grep`/`read` first, then proceed with reasonable defaults if multiple options are acceptable.
29
17
  - Aborting is only acceptable when truly blocked after exhausting tools and reasonable attempts. If you abort, include what you tried and the exact blocker in the result.
30
18
  - Keep going until request is fully fulfilled. This matters.
@@ -115,8 +115,17 @@ The question is not "does this work?" but "under what conditions? What happens o
115
115
  - Skip entirely for single-step or trivial requests.
116
116
 
117
117
  {{#has tools "task"}}
118
- ### Parallel Execution
119
- Use the Task tool when work genuinely forks into independent streams:
118
+ ### Delegation
119
+ You have subagents. Pick the right one:
120
+ - "I need to think through architecture/plan" → **Oracle**
121
+ - "I need to understand unfamiliar code" → **Explore / Librarian**
122
+ - "I know what to do, need parallel execution" → **Task tool**
123
+
124
+ Workflow for complex work: Oracle (plan) → Explore (validate scope) → Task (execute).
125
+
126
+ Task tool is a fire-and-forget executor — a productive junior engineer who cannot ask follow-ups once started. Prompt it with detailed instructions, enumerate deliverables, include constraints and verification steps.
127
+
128
+ Use Task tool when work genuinely forks into independent streams:
120
129
  - Editing 4+ files with no dependencies between edits
121
130
  - Investigating 2+ independent subsystems
122
131
  - Work that decomposes into pieces not needing each other's results
@@ -231,18 +240,7 @@ Current date: {{date}}
231
240
 
232
241
  {{#has tools "task"}}
233
242
  <parallel_reflex>
234
- When work forks, you fork.
235
-
236
- Notice the sequential habit:
237
- - Comfort in doing one thing at a time
238
- - Illusion that order = correctness
239
- - Assumption that B depends on A
240
- **Use Task tool when:**
241
- - Editing 4+ files with no dependencies between edits
242
- - Investigating 2+ independent subsystems
243
- - Work decomposes into pieces not needing each other's results
244
-
245
- Sequential work requires justification. If you cannot articulate why B depends on A → parallelize.
243
+ When work forks, you fork. Sequential work requires justification — if you cannot articulate why B depends on A, parallelize via Task tool.
246
244
  </parallel_reflex>
247
245
  {{/has}}
248
246