aura-code 0.6.3 → 0.10.1

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 (265) hide show
  1. package/README.md +47 -164
  2. package/dist/agent/affect.d.ts +13 -0
  3. package/dist/agent/affect.js +34 -0
  4. package/dist/agent/affect.js.map +1 -0
  5. package/dist/agent/compactor.d.ts +27 -4
  6. package/dist/agent/compactor.js +185 -54
  7. package/dist/agent/compactor.js.map +1 -1
  8. package/dist/agent/confess.d.ts +35 -0
  9. package/dist/agent/confess.js +296 -0
  10. package/dist/agent/confess.js.map +1 -0
  11. package/dist/agent/context.d.ts +0 -4
  12. package/dist/agent/context.js +0 -38
  13. package/dist/agent/context.js.map +1 -1
  14. package/dist/agent/domain-expertise.d.ts +22 -0
  15. package/dist/agent/domain-expertise.js +110 -0
  16. package/dist/agent/domain-expertise.js.map +1 -0
  17. package/dist/agent/executive-queue.d.ts +26 -0
  18. package/dist/agent/executive-queue.js +50 -0
  19. package/dist/agent/executive-queue.js.map +1 -0
  20. package/dist/agent/generational-flush.d.ts +28 -0
  21. package/dist/agent/generational-flush.js +48 -0
  22. package/dist/agent/generational-flush.js.map +1 -0
  23. package/dist/agent/loop-profile.d.ts +50 -0
  24. package/dist/agent/loop-profile.js +88 -0
  25. package/dist/agent/loop-profile.js.map +1 -0
  26. package/dist/agent/loop.d.ts +14 -5
  27. package/dist/agent/loop.js +167 -39
  28. package/dist/agent/loop.js.map +1 -1
  29. package/dist/agent/memory-consolidate.d.ts +14 -0
  30. package/dist/agent/memory-consolidate.js +141 -0
  31. package/dist/agent/memory-consolidate.js.map +1 -0
  32. package/dist/agent/mixture.d.ts +33 -0
  33. package/dist/agent/mixture.js +138 -0
  34. package/dist/agent/mixture.js.map +1 -0
  35. package/dist/agent/spawner.js +2 -2
  36. package/dist/agent/spawner.js.map +1 -1
  37. package/dist/agent/system-prompt.d.ts +1 -1
  38. package/dist/agent/system-prompt.js +50 -22
  39. package/dist/agent/system-prompt.js.map +1 -1
  40. package/dist/agent/unified-memory.d.ts +15 -0
  41. package/dist/agent/unified-memory.js +164 -0
  42. package/dist/agent/unified-memory.js.map +1 -0
  43. package/dist/checkpoints/engine.d.ts +44 -0
  44. package/dist/checkpoints/engine.js +324 -0
  45. package/dist/checkpoints/engine.js.map +1 -0
  46. package/dist/cli/command-palette.d.ts +26 -0
  47. package/dist/cli/command-palette.js +133 -0
  48. package/dist/cli/command-palette.js.map +1 -0
  49. package/dist/cli/context-health.d.ts +51 -0
  50. package/dist/cli/context-health.js +187 -0
  51. package/dist/cli/context-health.js.map +1 -0
  52. package/dist/cli/diamond.d.ts +67 -0
  53. package/dist/cli/diamond.js +222 -12
  54. package/dist/cli/diamond.js.map +1 -1
  55. package/dist/cli/dic.d.ts +2 -0
  56. package/dist/cli/dic.js +106 -0
  57. package/dist/cli/dic.js.map +1 -0
  58. package/dist/cli/diff-view.d.ts +18 -0
  59. package/dist/cli/diff-view.js +114 -0
  60. package/dist/cli/diff-view.js.map +1 -0
  61. package/dist/cli/display.d.ts +18 -4
  62. package/dist/cli/display.js +74 -151
  63. package/dist/cli/display.js.map +1 -1
  64. package/dist/cli/help-data.d.ts +7 -0
  65. package/dist/cli/help-data.js +80 -0
  66. package/dist/cli/help-data.js.map +1 -0
  67. package/dist/cli/index.js +1002 -852
  68. package/dist/cli/index.js.map +1 -1
  69. package/dist/cli/markdown.d.ts +5 -0
  70. package/dist/cli/markdown.js +128 -0
  71. package/dist/cli/markdown.js.map +1 -0
  72. package/dist/cli/model-select.d.ts +39 -0
  73. package/dist/cli/model-select.js +65 -0
  74. package/dist/cli/model-select.js.map +1 -0
  75. package/dist/cli/tui.d.ts +34 -0
  76. package/dist/cli/tui.js +1176 -0
  77. package/dist/cli/tui.js.map +1 -0
  78. package/dist/config/defaults.d.ts +6 -17
  79. package/dist/config/defaults.js +25 -46
  80. package/dist/config/defaults.js.map +1 -1
  81. package/dist/config/project-config.d.ts +2 -6
  82. package/dist/config/project-config.js +2 -2
  83. package/dist/config/project-config.js.map +1 -1
  84. package/dist/doctor/checks.d.ts +18 -0
  85. package/dist/doctor/checks.js +524 -0
  86. package/dist/doctor/checks.js.map +1 -0
  87. package/dist/doctor/index.d.ts +4 -0
  88. package/dist/doctor/index.js +229 -0
  89. package/dist/doctor/index.js.map +1 -0
  90. package/dist/doctor/repair.d.ts +19 -0
  91. package/dist/doctor/repair.js +126 -0
  92. package/dist/doctor/repair.js.map +1 -0
  93. package/dist/doctor/types.d.ts +38 -0
  94. package/dist/doctor/types.js +10 -0
  95. package/dist/doctor/types.js.map +1 -0
  96. package/dist/dream/dream.d.ts +79 -59
  97. package/dist/dream/dream.js +324 -144
  98. package/dist/dream/dream.js.map +1 -1
  99. package/dist/dream/episode.d.ts +17 -0
  100. package/dist/dream/episode.js +116 -0
  101. package/dist/dream/episode.js.map +1 -0
  102. package/dist/kanban/engine.d.ts +26 -0
  103. package/dist/kanban/engine.js +208 -0
  104. package/dist/kanban/engine.js.map +1 -0
  105. package/dist/kanban/types.d.ts +19 -0
  106. package/dist/kanban/types.js +9 -1
  107. package/dist/kanban/types.js.map +1 -1
  108. package/dist/machina/render-html.js +4 -2
  109. package/dist/machina/render-html.js.map +1 -1
  110. package/dist/machina/render-terminal.js +11 -4
  111. package/dist/machina/render-terminal.js.map +1 -1
  112. package/dist/machina/repair.d.ts +23 -0
  113. package/dist/machina/repair.js +98 -0
  114. package/dist/machina/repair.js.map +1 -0
  115. package/dist/machina/spec.js +12 -12
  116. package/dist/machina/spec.js.map +1 -1
  117. package/dist/machina/verify.d.ts +13 -1
  118. package/dist/machina/verify.js +12 -2
  119. package/dist/machina/verify.js.map +1 -1
  120. package/dist/mining/extract.d.ts +34 -0
  121. package/dist/mining/extract.js +229 -0
  122. package/dist/mining/extract.js.map +1 -0
  123. package/dist/mining/refine.d.ts +28 -0
  124. package/dist/mining/refine.js +256 -0
  125. package/dist/mining/refine.js.map +1 -0
  126. package/dist/perception/extractor.js +5 -3
  127. package/dist/perception/extractor.js.map +1 -1
  128. package/dist/perception/graph-store.d.ts +0 -11
  129. package/dist/perception/graph-store.js +0 -33
  130. package/dist/perception/graph-store.js.map +1 -1
  131. package/dist/perception/index.d.ts +1 -1
  132. package/dist/perception/index.js +1 -2
  133. package/dist/perception/index.js.map +1 -1
  134. package/dist/plugins/commands.d.ts +38 -0
  135. package/dist/plugins/commands.js +134 -0
  136. package/dist/plugins/commands.js.map +1 -0
  137. package/dist/plugins/frontmatter.d.ts +14 -0
  138. package/dist/plugins/frontmatter.js +78 -0
  139. package/dist/plugins/frontmatter.js.map +1 -0
  140. package/dist/plugins/hooks.d.ts +12 -0
  141. package/dist/plugins/hooks.js +148 -0
  142. package/dist/plugins/hooks.js.map +1 -0
  143. package/dist/plugins/loader.d.ts +7 -0
  144. package/dist/plugins/loader.js +255 -0
  145. package/dist/plugins/loader.js.map +1 -0
  146. package/dist/plugins/market.d.ts +23 -0
  147. package/dist/plugins/market.js +281 -0
  148. package/dist/plugins/market.js.map +1 -0
  149. package/dist/plugins/types.d.ts +90 -0
  150. package/dist/plugins/types.js +20 -0
  151. package/dist/plugins/types.js.map +1 -0
  152. package/dist/providers/anthropic-oauth-draft.d.ts +119 -0
  153. package/dist/providers/anthropic-oauth-draft.js +414 -0
  154. package/dist/providers/anthropic-oauth-draft.js.map +1 -0
  155. package/dist/providers/anthropic.d.ts +4 -1
  156. package/dist/providers/anthropic.js +35 -7
  157. package/dist/providers/anthropic.js.map +1 -1
  158. package/dist/providers/factory.d.ts +43 -19
  159. package/dist/providers/factory.js +183 -129
  160. package/dist/providers/factory.js.map +1 -1
  161. package/dist/providers/google.js +9 -22
  162. package/dist/providers/google.js.map +1 -1
  163. package/dist/providers/live-models.d.ts +23 -0
  164. package/dist/providers/live-models.js +145 -0
  165. package/dist/providers/live-models.js.map +1 -0
  166. package/dist/providers/openai-compatible.d.ts +1 -12
  167. package/dist/providers/openai-compatible.js +71 -108
  168. package/dist/providers/openai-compatible.js.map +1 -1
  169. package/dist/providers/resilient-factory.js +1 -1
  170. package/dist/providers/resilient-factory.js.map +1 -1
  171. package/dist/repl/queue.d.ts +22 -0
  172. package/dist/repl/queue.js +165 -0
  173. package/dist/repl/queue.js.map +1 -0
  174. package/dist/repl/side-channel.d.ts +23 -0
  175. package/dist/repl/side-channel.js +63 -0
  176. package/dist/repl/side-channel.js.map +1 -0
  177. package/dist/research/council.d.ts +2 -0
  178. package/dist/research/council.js +29 -4
  179. package/dist/research/council.js.map +1 -1
  180. package/dist/ruby/alternator.d.ts +11 -30
  181. package/dist/ruby/alternator.js +59 -38
  182. package/dist/ruby/alternator.js.map +1 -1
  183. package/dist/ruby/episode-capture.d.ts +0 -10
  184. package/dist/ruby/episode-capture.js +0 -33
  185. package/dist/ruby/episode-capture.js.map +1 -1
  186. package/dist/ruby/types.js +1 -1
  187. package/dist/ruby/types.js.map +1 -1
  188. package/dist/safety/path-jail.d.ts +17 -0
  189. package/dist/safety/path-jail.js +100 -0
  190. package/dist/safety/path-jail.js.map +1 -0
  191. package/dist/safety/permissions.d.ts +12 -21
  192. package/dist/safety/permissions.js +81 -216
  193. package/dist/safety/permissions.js.map +1 -1
  194. package/dist/safety/ssrf.d.ts +29 -0
  195. package/dist/safety/ssrf.js +185 -0
  196. package/dist/safety/ssrf.js.map +1 -0
  197. package/dist/server/index.js +64 -10
  198. package/dist/server/index.js.map +1 -1
  199. package/dist/setup/first-run.d.ts +0 -24
  200. package/dist/setup/first-run.js +10 -344
  201. package/dist/setup/first-run.js.map +1 -1
  202. package/dist/setup/key-store.d.ts +12 -0
  203. package/dist/setup/key-store.js +108 -0
  204. package/dist/setup/key-store.js.map +1 -0
  205. package/dist/setup/provider-registry.js +31 -18
  206. package/dist/setup/provider-registry.js.map +1 -1
  207. package/dist/setup/provider-test.d.ts +7 -0
  208. package/dist/setup/provider-test.js +73 -10
  209. package/dist/setup/provider-test.js.map +1 -1
  210. package/dist/setup/provider-wizard.d.ts +4 -1
  211. package/dist/setup/provider-wizard.js +92 -26
  212. package/dist/setup/provider-wizard.js.map +1 -1
  213. package/dist/setup/xiaomi.d.ts +1 -1
  214. package/dist/setup/xiaomi.js +3 -3
  215. package/dist/setup/xiaomi.js.map +1 -1
  216. package/dist/tools/browser.js +14 -10
  217. package/dist/tools/browser.js.map +1 -1
  218. package/dist/tools/clipboard.js +7 -1
  219. package/dist/tools/clipboard.js.map +1 -1
  220. package/dist/tools/dictate.d.ts +60 -0
  221. package/dist/tools/dictate.js +983 -0
  222. package/dist/tools/dictate.js.map +1 -0
  223. package/dist/tools/dictate_patched.js +1057 -0
  224. package/dist/tools/edit-file.js +10 -2
  225. package/dist/tools/edit-file.js.map +1 -1
  226. package/dist/tools/http-request.js +14 -4
  227. package/dist/tools/http-request.js.map +1 -1
  228. package/dist/tools/image-read.js +34 -2
  229. package/dist/tools/image-read.js.map +1 -1
  230. package/dist/tools/index.d.ts +16 -1
  231. package/dist/tools/index.js +59 -8
  232. package/dist/tools/index.js.map +1 -1
  233. package/dist/tools/mcp.js +12 -0
  234. package/dist/tools/mcp.js.map +1 -1
  235. package/dist/tools/read-file.js +10 -14
  236. package/dist/tools/read-file.js.map +1 -1
  237. package/dist/tools/telegram-audio-policy.d.ts +30 -0
  238. package/dist/tools/telegram-audio-policy.js +49 -0
  239. package/dist/tools/telegram-audio-policy.js.map +1 -0
  240. package/dist/tools/telegram-bot.js +1136 -537
  241. package/dist/tools/telegram-bot.js.map +1 -1
  242. package/dist/tools/telegram-voice.d.ts +18 -5
  243. package/dist/tools/telegram-voice.js +54 -12
  244. package/dist/tools/telegram-voice.js.map +1 -1
  245. package/dist/tools/telegram.d.ts +3 -3
  246. package/dist/tools/telegram.js +5 -84
  247. package/dist/tools/telegram.js.map +1 -1
  248. package/dist/tools/tools.d.ts +2 -14
  249. package/dist/tools/tools.js +79 -144
  250. package/dist/tools/tools.js.map +1 -1
  251. package/dist/tools/web-fetch.js +39 -7
  252. package/dist/tools/web-fetch.js.map +1 -1
  253. package/dist/tools/web-search.d.ts +0 -20
  254. package/dist/tools/web-search.js +40 -137
  255. package/dist/tools/web-search.js.map +1 -1
  256. package/dist/util/errors.js +1 -15
  257. package/dist/util/errors.js.map +1 -1
  258. package/dist/util/json-repair.d.ts +11 -0
  259. package/dist/util/json-repair.js +31 -0
  260. package/dist/util/json-repair.js.map +1 -0
  261. package/dist/util/rate-limiter.js +2 -8
  262. package/dist/util/rate-limiter.js.map +1 -1
  263. package/dist/viz/index.js +793 -792
  264. package/dist/viz/index.js.map +1 -1
  265. package/package.json +12 -32
@@ -0,0 +1,1176 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.inputActive = void 0;
7
+ exports.setAgentMode = setAgentMode;
8
+ exports.getAgentMode = getAgentMode;
9
+ exports.setModeChangeHandler = setModeChangeHandler;
10
+ exports.setFooter = setFooter;
11
+ exports.setPanelContent = setPanelContent;
12
+ exports.setStatusLine = setStatusLine;
13
+ exports.createAbortController = createAbortController;
14
+ exports.clearAbortController = clearAbortController;
15
+ exports.setSessionSwitchHandler = setSessionSwitchHandler;
16
+ exports.enterAltScreen = enterAltScreen;
17
+ exports.leaveAltScreen = leaveAltScreen;
18
+ exports.enterFullscreenPrompt = enterFullscreenPrompt;
19
+ exports.exitFullscreenPrompt = exitFullscreenPrompt;
20
+ exports.writeOutput = writeOutput;
21
+ exports.writeStream = writeStream;
22
+ exports.setBannerLines = setBannerLines;
23
+ exports.askConfirm = askConfirm;
24
+ exports.askInput = askInput;
25
+ exports.startInput = startInput;
26
+ exports.stopInput = stopInput;
27
+ exports.setCallbacks = setCallbacks;
28
+ exports.setChatId = setChatId;
29
+ exports.initTui = initTui;
30
+ exports.destroyTui = destroyTui;
31
+ exports.createTuiDisplay = createTuiDisplay;
32
+ /**
33
+ * TUI v2 — Bottom-input layout: output scrolls at the top, input box
34
+ * pinned at the bottom. Inspired by OpenCode and Hermes Agent.
35
+ *
36
+ * Layout (using DECSTBM scroll region to protect bottom rows):
37
+ * ┌─────────────────────────────────────────────┐
38
+ * │ [banner] │ ← scroll region (top)
39
+ * │ [output scrollback — scrolls here] │
40
+ * │ ──────────────────────────────────────── │
41
+ * │ │ user message 6:42 PM │
42
+ * │ │ ◆ thinking… │
43
+ * │ │ ✓ done │
44
+ * ╞═════════════════════════════════════════════╡ ← scroll region boundary
45
+ * │ -- INSERT -- glm-5.2 · opencode-go │ ← fixed bottom (outside scroll)
46
+ * │ ╭ ask aura ──────────────────────────────╮ │
47
+ * │ │ your input here█ │ │
48
+ * │ ╰────────────────────────────────────────╯ │
49
+ * │ ◆ Context: ████░░░░ 40% · 2.1k/128k · $0.03 │
50
+ * └─────────────────────────────────────────────┘
51
+ *
52
+ * Key bindings:
53
+ * Ctrl+P — Command palette
54
+ * Ctrl+L — Session switcher
55
+ * Tab — Agent switcher (build/plan)
56
+ * Esc — Scroll mode (vim pager)
57
+ * Ctrl+C — Abort task or exit
58
+ */
59
+ const chalk_1 = __importDefault(require("chalk"));
60
+ const context_health_js_1 = require("./context-health.js");
61
+ const diamond_js_1 = require("./diamond.js");
62
+ const command_palette_js_1 = require("./command-palette.js");
63
+ const markdown_js_1 = require("./markdown.js");
64
+ const TEXT = chalk_1.default.hex(diamond_js_1.TEXT_HEX);
65
+ const TEXT_DIM = chalk_1.default.hex(diamond_js_1.TEXT_DIM_HEX);
66
+ const ACCENT = chalk_1.default.hex('#cc785c');
67
+ const RUBY = diamond_js_1.RUBY_ACCENT;
68
+ // ── State ──────────────────────────────────────────────────────────────────
69
+ let inputBuffer = '';
70
+ let cursorPos = 0;
71
+ let inputActive = false;
72
+ exports.inputActive = inputActive;
73
+ let stdinHandler = null;
74
+ let chatId = '';
75
+ let agentMode = 'build';
76
+ let onModeChange = null;
77
+ function setAgentMode(mode) { agentMode = mode; if (onModeChange)
78
+ onModeChange(mode); }
79
+ function getAgentMode() { return agentMode; }
80
+ function setModeChangeHandler(fn) { onModeChange = fn; }
81
+ let overlay = 'none';
82
+ let overlayQuery = '';
83
+ let overlaySelected = 0;
84
+ function openOverlay(type) {
85
+ overlay = type;
86
+ overlayQuery = '';
87
+ overlaySelected = 0;
88
+ drawPromptBottom();
89
+ }
90
+ function closeOverlay() {
91
+ overlay = 'none';
92
+ overlayQuery = '';
93
+ overlaySelected = 0;
94
+ drawPromptBottom();
95
+ }
96
+ // ── Scroll mode ────────────────────────────────────────────────────────────
97
+ let scrollMode = false;
98
+ let scrollOffset = 0;
99
+ let pendingG = false;
100
+ let scrollBuffer = [];
101
+ const MAX_SCROLLBACK = 5000;
102
+ let streamAccum = '';
103
+ let bannerLines = [];
104
+ let activeTool = null;
105
+ function startToolSpinner(name) {
106
+ stopToolSpinner();
107
+ activeTool = { name, startTime: Date.now(), spinnerFrame: 0, intervalHandle: null };
108
+ if (!scrollMode) {
109
+ activeTool.intervalHandle = setInterval(() => {
110
+ if (!activeTool || scrollMode)
111
+ return;
112
+ activeTool.spinnerFrame++;
113
+ const spinners = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
114
+ const s = spinners[activeTool.spinnerFrame % spinners.length];
115
+ const elapsed = ((Date.now() - activeTool.startTime) / 1000).toFixed(1);
116
+ // Write spinner on the last output line (inside scroll region)
117
+ cursorCol(1);
118
+ clearEol();
119
+ rawWrite(ACCENT(` ${s} ${activeTool.name}`) + TEXT_DIM(` ${elapsed}s`));
120
+ cursorCol(1);
121
+ }, 100);
122
+ }
123
+ }
124
+ function stopToolSpinner() {
125
+ if (activeTool?.intervalHandle) {
126
+ clearInterval(activeTool.intervalHandle);
127
+ activeTool.intervalHandle = null;
128
+ }
129
+ if (activeTool && !scrollMode) {
130
+ cursorCol(1);
131
+ clearEol();
132
+ }
133
+ activeTool = null;
134
+ }
135
+ // ── Footer ──────────────────────────────────────────────────────────────────
136
+ let footerActive = false;
137
+ let footerText = '';
138
+ function setFooter(text) {
139
+ footerText = text;
140
+ footerActive = true;
141
+ if (inputActive)
142
+ drawPromptBottom();
143
+ }
144
+ let panelSuggestions = [];
145
+ function setPanelContent(opts) {
146
+ if (opts.suggestions)
147
+ panelSuggestions = opts.suggestions;
148
+ if (inputActive)
149
+ drawPromptBottom();
150
+ }
151
+ let statusLineText = '';
152
+ function setStatusLine(text) {
153
+ statusLineText = text;
154
+ if (inputActive)
155
+ drawPromptBottom();
156
+ }
157
+ function createAbortController() {
158
+ currentAbort = new AbortController();
159
+ return currentAbort;
160
+ }
161
+ function clearAbortController() { currentAbort = null; }
162
+ // ── Session switcher callback ───────────────────────────────────────────────
163
+ let onSessionSwitch = null;
164
+ function setSessionSwitchHandler(fn) { onSessionSwitch = fn; }
165
+ // ── Low-level ──────────────────────────────────────────────────────────────
166
+ let realStdoutWrite = null;
167
+ function rawWrite(s) {
168
+ (realStdoutWrite ?? process.stdout.write.bind(process.stdout))(s);
169
+ }
170
+ function clearEol() { rawWrite('\x1b[0K'); }
171
+ function cursorUp(n) { if (n > 0)
172
+ rawWrite(`\x1b[${n}A`); }
173
+ function cursorDown(n) { if (n > 0)
174
+ rawWrite(`\x1b[${n}B`); }
175
+ function cursorCol(n) { rawWrite(`\x1b[${n}G`); }
176
+ function hideCursor() { rawWrite('\x1b[?25l'); }
177
+ function showCursor() { rawWrite('\x1b[?25h'); }
178
+ let altScreenActive = false;
179
+ function enterAltScreen() {
180
+ altScreenActive = true;
181
+ rawWrite('\x1b[?1049h');
182
+ // OSC 11: set the terminal's default background to the palette's bluish
183
+ // dark. Restored via OSC 111 on leave — no per-line bg painting needed.
184
+ rawWrite(`\x1b]11;${diamond_js_1.BG_HEX}\x07`);
185
+ }
186
+ function leaveAltScreen() {
187
+ if (!altScreenActive)
188
+ return;
189
+ altScreenActive = false;
190
+ rawWrite('\x1b]111\x07'); // OSC 111: reset background to terminal default
191
+ rawWrite('\x1b[?1049l');
192
+ }
193
+ const cols = () => process.stdout.columns ?? 80;
194
+ const screenRows = () => process.stdout.rows ?? 24;
195
+ function handleExternalWrite(chunk) {
196
+ if (!inputActive) {
197
+ rawWrite(chunk);
198
+ return;
199
+ }
200
+ if (chunk.endsWith('\n')) {
201
+ writeOutput(chunk.slice(0, -1));
202
+ }
203
+ else if (scrollMode) {
204
+ streamAccum += chunk;
205
+ }
206
+ else {
207
+ rawWrite(chunk);
208
+ }
209
+ }
210
+ function patchStdout() {
211
+ if (realStdoutWrite)
212
+ return;
213
+ realStdoutWrite = process.stdout.write.bind(process.stdout);
214
+ process.stdout.write = ((chunk) => {
215
+ handleExternalWrite(typeof chunk === 'string' ? chunk : String(chunk));
216
+ return true;
217
+ });
218
+ }
219
+ function unpatchStdout() {
220
+ if (realStdoutWrite) {
221
+ process.stdout.write = realStdoutWrite;
222
+ realStdoutWrite = null;
223
+ }
224
+ }
225
+ process.on('exit', () => {
226
+ try {
227
+ rawWrite('\x1b[r'); // reset scroll region
228
+ leaveAltScreen();
229
+ unpatchStdout();
230
+ }
231
+ catch { /* best effort */ }
232
+ });
233
+ // ── Bottom-input layout via DECSTBM ─────────────────────────────────────────
234
+ //
235
+ // The screen is split into two regions using DECSTBM (scroll region):
236
+ // Rows 1..(sr-FIXED_BOTTOM) — scrollable output region
237
+ // Rows (sr-FIXED_BOTTOM+1)..sr — fixed bottom block (input box etc.)
238
+ //
239
+ // DECSTBM sets the region inside which scrolling/line-feed happens.
240
+ // The cursor jumps to the region's home when set — we account for that.
241
+ // The bottom block is redrawn in place whenever the input changes, by
242
+ // positioning the cursor to the bottom rows directly.
243
+ const BOX_CONTENT_ROWS = 3;
244
+ const HEADER_ROWS = 5; // top border + content + bottom border
245
+ const STATUS_ROW = 1;
246
+ const FOOTER_ROW = 1;
247
+ const FIXED_BOTTOM = HEADER_ROWS + STATUS_ROW + FOOTER_ROW; // 7
248
+ const LEAD = 2;
249
+ const MARGIN = 1;
250
+ function computeLayout() {
251
+ const total = cols();
252
+ return { boxWidth: Math.min(total - LEAD - MARGIN, 100) };
253
+ }
254
+ function wrapInput(innerWidth) {
255
+ const w = Math.max(4, innerWidth);
256
+ const chunks = [];
257
+ for (let i = 0; i < inputBuffer.length || i === 0; i += w) {
258
+ chunks.push(inputBuffer.slice(i, i + w));
259
+ if (inputBuffer.length === 0)
260
+ break;
261
+ }
262
+ let cursorChunk = Math.floor(cursorPos / w);
263
+ let cursorColIdx = cursorPos % w;
264
+ let visible = chunks;
265
+ if (chunks.length > BOX_CONTENT_ROWS) {
266
+ const hidden = chunks.length - BOX_CONTENT_ROWS;
267
+ visible = chunks.slice(hidden);
268
+ cursorChunk -= hidden;
269
+ }
270
+ if (cursorChunk < 0) {
271
+ cursorChunk = 0;
272
+ cursorColIdx = 0;
273
+ }
274
+ while (visible.length < BOX_CONTENT_ROWS)
275
+ visible.push('');
276
+ return { rows: visible, cursorRow: cursorChunk, cursorCol: cursorColIdx };
277
+ }
278
+ function padVisible(s, width) {
279
+ const visibleLen = s.replace(/\x1b\[[0-9;]*m/g, '').length;
280
+ return s + ' '.repeat(Math.max(0, width - visibleLen));
281
+ }
282
+ function truncVisible(s, width) {
283
+ const visibleLen = s.replace(/\x1b\[[0-9;]*m/g, '').length;
284
+ if (visibleLen <= width)
285
+ return s;
286
+ let i = 0, visCount = 0, out = '';
287
+ while (i < s.length && visCount < Math.max(0, width - 1)) {
288
+ const m = s.slice(i).match(/^\x1b\[[0-9;]*m/);
289
+ if (m) {
290
+ out += m[0];
291
+ i += m[0].length;
292
+ continue;
293
+ }
294
+ out += s[i];
295
+ visCount++;
296
+ i++;
297
+ }
298
+ return out + '\x1b[0m…';
299
+ }
300
+ /**
301
+ * Build the bottom block lines: status line, input box, footer.
302
+ * Returns lines in top-to-bottom order.
303
+ */
304
+ function buildBottomRows() {
305
+ const { boxWidth } = computeLayout();
306
+ const idTag = chatId ? ` ${chatId}` : '';
307
+ const label = ` ask aura${idTag} `;
308
+ const innerWidth = boxWidth - 4;
309
+ const wrapped = wrapInput(innerWidth);
310
+ const focused = !scrollMode;
311
+ const modeTag = focused ? ACCENT.bold('-- INSERT --') : ACCENT.bold('-- SCROLL --');
312
+ const agentTag = agentMode === 'plan' ? ACCENT(' [plan]') : '';
313
+ const cursorChar = focused ? ACCENT('█') : '';
314
+ const rows = [];
315
+ // Status line
316
+ rows.push(' '.repeat(LEAD) + padVisible(modeTag + agentTag + TEXT_DIM(` ${statusLineText}`), boxWidth));
317
+ // Input box
318
+ for (let row = 0; row < HEADER_ROWS; row++) {
319
+ let boxPart;
320
+ if (row === 0) {
321
+ const dashes = Math.max(0, boxWidth - label.length - 2);
322
+ boxPart = focused
323
+ ? (0, diamond_js_1.gradient)('╭') + TEXT_DIM(label) + (0, diamond_js_1.gradient)('─'.repeat(dashes)) + (0, diamond_js_1.gradient)('╮')
324
+ : (0, diamond_js_1.CHROME_DIM)('╭' + label + '─'.repeat(dashes) + '╮');
325
+ }
326
+ else if (row === HEADER_ROWS - 1) {
327
+ boxPart = focused
328
+ ? (0, diamond_js_1.gradient)('╰' + '─'.repeat(boxWidth - 2) + '╯')
329
+ : (0, diamond_js_1.CHROME_DIM)('╰' + '─'.repeat(boxWidth - 2) + '╯');
330
+ }
331
+ else {
332
+ const contentRow = row - 1;
333
+ const text = wrapped.rows[contentRow] ?? '';
334
+ const isCursorRow = contentRow === wrapped.cursorRow;
335
+ const showPlaceholder = inputBuffer.length === 0 && contentRow === 0;
336
+ let inner;
337
+ if (showPlaceholder) {
338
+ inner = TEXT_DIM('type a task, :btw, :q, :help...') + cursorChar;
339
+ inner = padVisible(inner, innerWidth);
340
+ }
341
+ else if (isCursorRow && focused) {
342
+ const before = TEXT(text.slice(0, wrapped.cursorCol));
343
+ const after = TEXT(text.slice(wrapped.cursorCol));
344
+ inner = padVisible(before + cursorChar + after, innerWidth);
345
+ }
346
+ else {
347
+ inner = padVisible((focused ? TEXT : TEXT_DIM)(text), innerWidth);
348
+ }
349
+ const border = focused ? (0, diamond_js_1.gradientStopFor)(row, HEADER_ROWS)('│') : (0, diamond_js_1.CHROME_DIM)('│');
350
+ boxPart = border + ' ' + inner + ' ' + border;
351
+ }
352
+ rows.push(' '.repeat(LEAD) + boxPart);
353
+ }
354
+ return rows;
355
+ }
356
+ /**
357
+ * Set the terminal scroll region to exclude the bottom FIXED_BOTTOM rows.
358
+ * After DECSTBM, the cursor moves to the home position of the region.
359
+ */
360
+ function setScrollRegion() {
361
+ const sr = screenRows();
362
+ const scrollEnd = sr - FIXED_BOTTOM;
363
+ if (scrollEnd < 1)
364
+ return;
365
+ // DECSTBM: \x1b[top;bottom;r — set scroll region from row `top` to `bottom`
366
+ rawWrite(`\x1b[1;${scrollEnd}r`);
367
+ // Move cursor to top of scroll region (DECSTBM homes cursor there)
368
+ rawWrite(`\x1b[1;1H`);
369
+ }
370
+ /**
371
+ * Reset scroll region to full screen.
372
+ */
373
+ function resetScrollRegion() {
374
+ rawWrite('\x1b[r');
375
+ }
376
+ /**
377
+ * Draw the bottom block (status + input box + footer) at the bottom of the screen.
378
+ * Uses absolute row positioning to the fixed bottom rows — these are OUTSIDE
379
+ * the scroll region, so they're never scrolled away.
380
+ */
381
+ function drawPromptBottom() {
382
+ if (scrollMode || fullscreenPrompt)
383
+ return;
384
+ const rows = buildBottomRows();
385
+ const sr = screenRows();
386
+ // The bottom block starts at row (sr - FIXED_BOTTOM + 1)
387
+ const startRow = sr - FIXED_BOTTOM + 1;
388
+ for (let i = 0; i < rows.length; i++) {
389
+ const row = startRow + i;
390
+ rawWrite(`\x1b[${row};1H`);
391
+ clearEol();
392
+ rawWrite(rows[i]);
393
+ }
394
+ // Footer on the very last row
395
+ if (footerActive) {
396
+ rawWrite(`\x1b[${sr};1H`);
397
+ clearEol();
398
+ rawWrite(truncVisible(footerText, Math.max(10, cols() - MARGIN)));
399
+ }
400
+ // Return cursor to the scroll region (where output goes)
401
+ // Position at the bottom of the scroll region
402
+ const scrollEnd = sr - FIXED_BOTTOM;
403
+ rawWrite(`\x1b[${scrollEnd};1H`);
404
+ }
405
+ // ── Fullscreen mode for interactive prompts (wizard etc.) ──────────────────
406
+ //
407
+ // When an interactive prompt like the provider wizard needs many rows,
408
+ // collapse the bottom block and expand the scroll region to the full screen.
409
+ // The wizard's own readline handles input; the TUI's input box is hidden.
410
+ let fullscreenPrompt = false;
411
+ function enterFullscreenPrompt() {
412
+ fullscreenPrompt = true;
413
+ resetScrollRegion();
414
+ // Clear the bottom block area
415
+ const sr = screenRows();
416
+ for (let r = sr - FIXED_BOTTOM + 1; r <= sr; r++) {
417
+ rawWrite(`\x1b[${r};1H`);
418
+ clearEol();
419
+ }
420
+ // Move cursor to where output was
421
+ rawWrite(`\x1b[${sr - FIXED_BOTTOM};1H`);
422
+ }
423
+ function exitFullscreenPrompt() {
424
+ fullscreenPrompt = false;
425
+ setScrollRegion();
426
+ drawPromptBottom();
427
+ }
428
+ // ── Output ─────────────────────────────────────────────────────────────────
429
+ function wrapForTerminal(text) {
430
+ const maxWidth = Math.max(10, cols() - MARGIN);
431
+ const physicalLines = [];
432
+ for (const line of text.split('\n')) {
433
+ const visible = line.replace(/\x1b\[[0-9;]*m/g, '');
434
+ if (visible.length <= maxWidth) {
435
+ physicalLines.push(line);
436
+ continue;
437
+ }
438
+ let i = 0, visCount = 0, chunk = '';
439
+ while (i < line.length) {
440
+ const m = line.slice(i).match(/^\x1b\[[0-9;]*m/);
441
+ if (m) {
442
+ chunk += m[0];
443
+ i += m[0].length;
444
+ continue;
445
+ }
446
+ if (visCount >= maxWidth) {
447
+ physicalLines.push(chunk);
448
+ chunk = '';
449
+ visCount = 0;
450
+ continue;
451
+ }
452
+ chunk += line[i];
453
+ visCount++;
454
+ i++;
455
+ }
456
+ physicalLines.push(chunk);
457
+ }
458
+ return { output: physicalLines.join('\n'), lineCount: physicalLines.length };
459
+ }
460
+ function writeOutput(text) {
461
+ if (streamAccum) {
462
+ pushScrollback(wrapForTerminal(streamAccum).output.split('\n'));
463
+ streamAccum = '';
464
+ }
465
+ const { output, lineCount } = wrapForTerminal(text);
466
+ pushScrollback(output.split('\n'));
467
+ if (scrollMode) {
468
+ scrollOffset = Math.min(scrollOffset + lineCount, maxScrollOffset());
469
+ renderScrollView();
470
+ return;
471
+ }
472
+ if (fullscreenPrompt) {
473
+ // Fullscreen mode: just write naturally, no scroll region, no bottom block
474
+ rawWrite(output + '\n');
475
+ return;
476
+ }
477
+ // Write inside the scroll region — output scrolls naturally above the bottom block
478
+ cursorCol(1);
479
+ clearEol();
480
+ rawWrite(output);
481
+ rawWrite('\n');
482
+ }
483
+ function writeStream(text) {
484
+ streamAccum += text;
485
+ if (scrollMode)
486
+ return;
487
+ rawWrite(text);
488
+ }
489
+ function echoUserLine(line) {
490
+ const bar = RUBY('│ ');
491
+ writeOutput(bar + TEXT(line));
492
+ writeOutput(bar + TEXT_DIM(formatTime(new Date())));
493
+ }
494
+ function formatTime(d) {
495
+ let h = d.getHours();
496
+ const m = d.getMinutes().toString().padStart(2, '0');
497
+ const ampm = h >= 12 ? 'PM' : 'AM';
498
+ h = h % 12 || 12;
499
+ return `${h}:${m} ${ampm}`;
500
+ }
501
+ function pushScrollback(lines) {
502
+ for (const line of lines)
503
+ scrollBuffer.push(line);
504
+ if (scrollBuffer.length > MAX_SCROLLBACK) {
505
+ scrollBuffer.splice(0, scrollBuffer.length - MAX_SCROLLBACK);
506
+ }
507
+ }
508
+ function setBannerLines(lines) {
509
+ bannerLines = lines;
510
+ }
511
+ // ── Scroll-mode rendering ──────────────────────────────────────────────────
512
+ function viewHeight() {
513
+ return Math.max(3, screenRows() - FIXED_BOTTOM - 1);
514
+ }
515
+ function maxScrollOffset() {
516
+ return Math.max(0, scrollBuffer.length - viewHeight());
517
+ }
518
+ function renderScrollView() {
519
+ const bottomRows = buildBottomRows();
520
+ const vh = viewHeight();
521
+ scrollOffset = Math.max(0, Math.min(scrollOffset, maxScrollOffset()));
522
+ const start = Math.max(0, scrollBuffer.length - vh - scrollOffset);
523
+ const visible = scrollBuffer.slice(start, start + vh);
524
+ const width = Math.max(10, cols() - MARGIN);
525
+ const sr = screenRows();
526
+ rawWrite('\x1b[2J\x1b[H');
527
+ // Banner
528
+ const withBanner = bannerLines.length > 0 && sr - bannerLines.length - FIXED_BOTTOM - 1 >= 3;
529
+ if (withBanner) {
530
+ bannerLines.forEach(line => { rawWrite(truncVisible(line, width)); rawWrite('\n'); });
531
+ }
532
+ visible.forEach(line => { rawWrite(truncVisible(line, width)); rawWrite('\n'); });
533
+ for (let i = visible.length; i < vh; i++)
534
+ rawWrite('\n');
535
+ // Bottom block
536
+ const startRow = sr - FIXED_BOTTOM + 1;
537
+ for (let i = 0; i < bottomRows.length; i++) {
538
+ rawWrite(`\x1b[${startRow + i};1H`);
539
+ rawWrite(bottomRows[i]);
540
+ }
541
+ const bottom = start + visible.length;
542
+ const pos = scrollOffset === 0 ? 'BOT' : start === 0 ? 'TOP' : `${Math.round((bottom / Math.max(1, scrollBuffer.length)) * 100)}%`;
543
+ const indicator = ACCENT.bold(' -- SCROLL -- ')
544
+ + TEXT_DIM(`${start + 1}-${bottom}/${scrollBuffer.length} ${pos} · j/k · ^d/^u · gg/G · i/Enter/Esc insert`);
545
+ rawWrite(`\x1b[${sr};1H`);
546
+ rawWrite(truncVisible(indicator, width));
547
+ }
548
+ function enterScrollMode(initialOffset) {
549
+ if (scrollBuffer.length === 0)
550
+ return;
551
+ scrollMode = true;
552
+ pendingG = false;
553
+ scrollOffset = initialOffset;
554
+ renderScrollView();
555
+ }
556
+ function exitScrollMode() {
557
+ scrollMode = false;
558
+ pendingG = false;
559
+ scrollOffset = 0;
560
+ redrawLiveView();
561
+ }
562
+ function redrawLiveView() {
563
+ const width = Math.max(10, cols() - MARGIN);
564
+ const sr = screenRows();
565
+ rawWrite('\x1b[2J\x1b[H');
566
+ // Banner
567
+ const withBanner = bannerLines.length > 0 && sr - bannerLines.length - FIXED_BOTTOM - 1 >= 3;
568
+ const banner = withBanner ? bannerLines : [];
569
+ banner.forEach(line => { rawWrite(truncVisible(line, width)); rawWrite('\n'); });
570
+ // Output tail
571
+ const tailMax = Math.max(0, sr - banner.length - FIXED_BOTTOM);
572
+ const tail = scrollBuffer.slice(Math.max(0, scrollBuffer.length - tailMax));
573
+ tail.forEach(line => { rawWrite(truncVisible(line, width)); rawWrite('\n'); });
574
+ // Bottom block
575
+ const bottomRows = buildBottomRows();
576
+ const startRow = sr - FIXED_BOTTOM + 1;
577
+ for (let i = 0; i < bottomRows.length; i++) {
578
+ rawWrite(`\x1b[${startRow + i};1H`);
579
+ clearEol();
580
+ rawWrite(bottomRows[i]);
581
+ }
582
+ // Footer
583
+ if (footerActive) {
584
+ rawWrite(`\x1b[${sr};1H`);
585
+ clearEol();
586
+ rawWrite(truncVisible(footerText, Math.max(10, cols() - MARGIN)));
587
+ }
588
+ }
589
+ // ── Confirm / Input ─────────────────────────────────────────────────────────
590
+ let pendingConfirm = null;
591
+ let pendingInput = null;
592
+ let inputAccumulator = [];
593
+ function askConfirm(message) {
594
+ return new Promise(resolve => {
595
+ writeOutput(chalk_1.default.hex('#d4903a')(` ⚠ ${message} [y/N]`));
596
+ pendingConfirm = (answer) => {
597
+ const a = answer.trim().toLowerCase();
598
+ resolve(a === 'y' || a === 'yes');
599
+ };
600
+ });
601
+ }
602
+ function askInput(prompt) {
603
+ return new Promise(resolve => {
604
+ if (fullscreenPrompt) {
605
+ // In fullscreen mode, write prompt directly and use raw readline-style input
606
+ rawWrite(chalk_1.default.hex('#cc785c')(prompt));
607
+ pendingInput = (text) => {
608
+ rawWrite(text + '\n');
609
+ resolve(text);
610
+ };
611
+ inputAccumulator = [];
612
+ inputBuffer = '';
613
+ cursorPos = 0;
614
+ return;
615
+ }
616
+ writeOutput(chalk_1.default.hex('#cc785c')(prompt));
617
+ pendingInput = (text) => { resolve(text); };
618
+ inputAccumulator = [];
619
+ });
620
+ }
621
+ // ── Input handling ─────────────────────────────────────────────────────────
622
+ function handleChar(ch) {
623
+ if (ch === '\x03') { // Ctrl-C
624
+ if (overlay !== 'none') {
625
+ closeOverlay();
626
+ return;
627
+ }
628
+ if (pendingConfirm) {
629
+ const resolve = pendingConfirm;
630
+ pendingConfirm = null;
631
+ inputBuffer = '';
632
+ cursorPos = 0;
633
+ writeOutput(TEXT_DIM('❯ n (cancelled)'));
634
+ resolve('n');
635
+ return;
636
+ }
637
+ if (pendingInput) {
638
+ const resolve = pendingInput;
639
+ pendingInput = null;
640
+ inputAccumulator = [];
641
+ inputBuffer = '';
642
+ cursorPos = 0;
643
+ writeOutput(TEXT_DIM('❯ (cancelled)'));
644
+ drawPromptBottom();
645
+ resolve('');
646
+ return;
647
+ }
648
+ if (currentAbort && !currentAbort.signal.aborted) {
649
+ currentAbort.abort();
650
+ writeOutput(chalk_1.default.hex('#d4903a')(' ⏹ Aborting current task...'));
651
+ if (onStop)
652
+ onStop();
653
+ return;
654
+ }
655
+ resetScrollRegion();
656
+ unpatchStdout();
657
+ leaveAltScreen();
658
+ showCursor();
659
+ process.exit(0);
660
+ }
661
+ if (ch === '\x04') { // Ctrl-D
662
+ if (pendingInput) {
663
+ const resolve = pendingInput;
664
+ pendingInput = null;
665
+ const finalText = inputAccumulator.join('\n');
666
+ inputAccumulator = [];
667
+ inputBuffer = '';
668
+ cursorPos = 0;
669
+ writeOutput(TEXT_DIM('❯ (end of input)'));
670
+ drawPromptBottom();
671
+ resolve(finalText);
672
+ return;
673
+ }
674
+ }
675
+ if (ch === '\r' || ch === '\n') {
676
+ // Overlay Enter
677
+ if (overlay === 'palette') {
678
+ const commands = (0, command_palette_js_1.filterCommands)(overlayQuery);
679
+ if (commands[overlaySelected]) {
680
+ const cmd = commands[overlaySelected];
681
+ closeOverlay();
682
+ if (onEnter)
683
+ onEnter(cmd.id);
684
+ }
685
+ return;
686
+ }
687
+ if (overlay === 'session') {
688
+ closeOverlay();
689
+ if (onSessionSwitch)
690
+ onSessionSwitch();
691
+ return;
692
+ }
693
+ const line = inputBuffer.trim();
694
+ if (pendingConfirm) {
695
+ const resolve = pendingConfirm;
696
+ pendingConfirm = null;
697
+ writeOutput(TEXT_DIM(`❯ ${line || 'n'}`));
698
+ inputBuffer = '';
699
+ cursorPos = 0;
700
+ drawPromptBottom();
701
+ resolve(line);
702
+ return;
703
+ }
704
+ if (pendingInput) {
705
+ if (fullscreenPrompt) {
706
+ // Fullscreen mode: single-line submit on Enter
707
+ const resolve = pendingInput;
708
+ pendingInput = null;
709
+ const line = inputBuffer;
710
+ if (line)
711
+ rawWrite(line + '\n');
712
+ inputBuffer = '';
713
+ cursorPos = 0;
714
+ resolve(line);
715
+ return;
716
+ }
717
+ // Normal TUI mode: accumulate lines, Ctrl-D submits
718
+ inputAccumulator.push(inputBuffer);
719
+ inputBuffer = '';
720
+ cursorPos = 0;
721
+ drawPromptBottom();
722
+ return;
723
+ }
724
+ if (line) {
725
+ echoUserLine(line);
726
+ }
727
+ inputBuffer = '';
728
+ cursorPos = 0;
729
+ drawPromptBottom();
730
+ if (line && onEnter)
731
+ onEnter(line);
732
+ return;
733
+ }
734
+ if (ch === '\x7f' || ch === '\b') {
735
+ if (overlay !== 'none') {
736
+ if (overlayQuery.length > 0) {
737
+ overlayQuery = overlayQuery.slice(0, -1);
738
+ overlaySelected = 0;
739
+ drawPromptBottom();
740
+ }
741
+ return;
742
+ }
743
+ if (cursorPos > 0) {
744
+ inputBuffer = inputBuffer.slice(0, cursorPos - 1) + inputBuffer.slice(cursorPos);
745
+ cursorPos--;
746
+ if (fullscreenPrompt && pendingInput) {
747
+ rawWrite('\b \b');
748
+ }
749
+ drawPromptBottom();
750
+ }
751
+ return;
752
+ }
753
+ if (ch === '\x15') { // Ctrl-U
754
+ if (overlay !== 'none') {
755
+ overlayQuery = '';
756
+ overlaySelected = 0;
757
+ drawPromptBottom();
758
+ return;
759
+ }
760
+ inputBuffer = '';
761
+ cursorPos = 0;
762
+ drawPromptBottom();
763
+ return;
764
+ }
765
+ if (ch === '\t') { // Tab — agent mode switcher
766
+ agentMode = agentMode === 'build' ? 'plan' : 'build';
767
+ if (onModeChange)
768
+ onModeChange(agentMode);
769
+ drawPromptBottom();
770
+ return;
771
+ }
772
+ if (ch >= ' ' && ch <= '~') {
773
+ if (overlay !== 'none') {
774
+ overlayQuery += ch;
775
+ overlaySelected = 0;
776
+ drawPromptBottom();
777
+ return;
778
+ }
779
+ inputBuffer = inputBuffer.slice(0, cursorPos) + ch + inputBuffer.slice(cursorPos);
780
+ cursorPos++;
781
+ if (fullscreenPrompt && pendingInput) {
782
+ // Echo typed char directly in fullscreen mode
783
+ rawWrite(ch);
784
+ }
785
+ drawPromptBottom();
786
+ return;
787
+ }
788
+ }
789
+ function handleScrollKey(key) {
790
+ const half = Math.floor(viewHeight() / 2);
791
+ const gWasPending = pendingG;
792
+ pendingG = false;
793
+ switch (key) {
794
+ case 'g':
795
+ if (!gWasPending) {
796
+ pendingG = true;
797
+ return;
798
+ }
799
+ scrollOffset = maxScrollOffset();
800
+ break;
801
+ case 'k':
802
+ case '\x1b[A':
803
+ scrollOffset += 1;
804
+ break;
805
+ case 'j':
806
+ case '\x1b[B':
807
+ scrollOffset -= 1;
808
+ break;
809
+ case '\x15':
810
+ case '\x1b[5~':
811
+ scrollOffset += half;
812
+ break;
813
+ case '\x04':
814
+ case '\x1b[6~':
815
+ scrollOffset -= half;
816
+ break;
817
+ case 'G':
818
+ scrollOffset = 0;
819
+ break;
820
+ case 'i':
821
+ case 'q':
822
+ case '\x1b':
823
+ case '\r':
824
+ case '\n':
825
+ case '\x03':
826
+ exitScrollMode();
827
+ return;
828
+ default: return;
829
+ }
830
+ renderScrollView();
831
+ }
832
+ function handleKey(key) {
833
+ if (scrollMode) {
834
+ handleScrollKey(key);
835
+ return;
836
+ }
837
+ // Ctrl+P — command palette (0x10)
838
+ if (key === '\x10') {
839
+ openOverlay('palette');
840
+ return;
841
+ }
842
+ // Ctrl+L — session switcher (0x0c)
843
+ if (key === '\x0c') {
844
+ openOverlay('session');
845
+ return;
846
+ }
847
+ if (key === '\x1b') {
848
+ if (overlay !== 'none') {
849
+ closeOverlay();
850
+ return;
851
+ }
852
+ enterScrollMode(0);
853
+ return;
854
+ }
855
+ if (key === '\x1b[A' && inputBuffer.length === 0) {
856
+ enterScrollMode(1);
857
+ return;
858
+ }
859
+ if (key === '\x1b[5~') {
860
+ enterScrollMode(Math.floor(viewHeight() / 2));
861
+ return;
862
+ }
863
+ if (key === '\x1b[D') {
864
+ if (overlay !== 'none')
865
+ return;
866
+ if (cursorPos > 0) {
867
+ cursorPos--;
868
+ drawPromptBottom();
869
+ }
870
+ return;
871
+ }
872
+ if (key === '\x1b[C') {
873
+ if (overlay !== 'none')
874
+ return;
875
+ if (cursorPos < inputBuffer.length) {
876
+ cursorPos++;
877
+ drawPromptBottom();
878
+ }
879
+ return;
880
+ }
881
+ // Arrow up/down in overlay
882
+ if (overlay !== 'none') {
883
+ if (key === '\x1b[A') {
884
+ overlaySelected = Math.max(0, overlaySelected - 1);
885
+ drawPromptBottom();
886
+ return;
887
+ }
888
+ if (key === '\x1b[B') {
889
+ const commands = (0, command_palette_js_1.filterCommands)(overlayQuery);
890
+ overlaySelected = Math.min(commands.length - 1, overlaySelected + 1);
891
+ drawPromptBottom();
892
+ return;
893
+ }
894
+ }
895
+ if (key.length > 1)
896
+ return;
897
+ handleChar(key);
898
+ }
899
+ function rawHandler(data) {
900
+ let i = 0;
901
+ while (i < data.length) {
902
+ if (data[i] === '\x1b' && data[i + 1] === '[') {
903
+ const m = /^\x1b\[[0-9;]*[A-Za-z~]/.exec(data.slice(i));
904
+ if (m) {
905
+ handleKey(m[0]);
906
+ i += m[0].length;
907
+ continue;
908
+ }
909
+ }
910
+ handleKey(data[i]);
911
+ i++;
912
+ }
913
+ }
914
+ function startInput() {
915
+ if (inputActive)
916
+ return;
917
+ exports.inputActive = inputActive = true;
918
+ inputBuffer = '';
919
+ cursorPos = 0;
920
+ if (process.stdin.isTTY)
921
+ process.stdin.setRawMode(true);
922
+ process.stdin.resume();
923
+ process.stdin.setEncoding('utf8');
924
+ stdinHandler = rawHandler;
925
+ process.stdin.on('data', stdinHandler);
926
+ }
927
+ function stopInput() {
928
+ if (!inputActive)
929
+ return;
930
+ exports.inputActive = inputActive = false;
931
+ if (stdinHandler) {
932
+ process.stdin.removeListener('data', stdinHandler);
933
+ stdinHandler = null;
934
+ }
935
+ if (process.stdin.isTTY)
936
+ process.stdin.setRawMode(false);
937
+ process.stdin.pause();
938
+ }
939
+ let onEnter = null;
940
+ let onStop = null;
941
+ let currentAbort = null;
942
+ function setCallbacks(opts) {
943
+ onEnter = opts.onEnter;
944
+ onStop = opts.onStop ?? null;
945
+ }
946
+ function setChatId(id) {
947
+ chatId = id;
948
+ }
949
+ function initTui() {
950
+ scrollMode = false;
951
+ scrollOffset = 0;
952
+ pendingG = false;
953
+ scrollBuffer = [];
954
+ streamAccum = '';
955
+ hideCursor();
956
+ patchStdout();
957
+ // Clear screen, draw banner
958
+ rawWrite('\x1b[2J\x1b[H');
959
+ const width = Math.max(10, cols() - MARGIN);
960
+ if (bannerLines.length > 0) {
961
+ bannerLines.forEach(line => { rawWrite(truncVisible(line, width)); rawWrite('\n'); });
962
+ }
963
+ // Set scroll region to exclude bottom FIXED_BOTTOM rows
964
+ setScrollRegion();
965
+ // Draw the bottom block
966
+ drawPromptBottom();
967
+ // Divider in the scroll region
968
+ writeOutput((0, diamond_js_1.gradient)('─'.repeat(Math.min(cols(), 100))));
969
+ }
970
+ function destroyTui() {
971
+ stopToolSpinner();
972
+ scrollMode = false;
973
+ stopInput();
974
+ resetScrollRegion();
975
+ unpatchStdout();
976
+ leaveAltScreen();
977
+ showCursor();
978
+ }
979
+ // ── TUI-aware Display ──────────────────────────────────────────────────────
980
+ function toolIcon(name) {
981
+ const icons = {
982
+ read_file: '📄', list_dir: '📁', edit_file: '✏️',
983
+ write_file: '📝', search_code: '🔍', run_shell: '⚡',
984
+ run_tests: '🧪', git_status: '🌿', git_diff: '📊',
985
+ };
986
+ return icons[name] ?? '🔧';
987
+ }
988
+ function fmtIn(name, input) {
989
+ switch (name) {
990
+ case 'read_file': {
991
+ const r = input.start_line ? ` :${input.start_line}-${input.end_line ?? '?'}` : '';
992
+ return `${input.path}${r}`;
993
+ }
994
+ case 'list_dir': return `${input.path ?? '.'}${input.recursive ? ' (recursive)' : ''}`;
995
+ case 'edit_file': return `${input.path}`;
996
+ case 'write_file': return `${input.path}`;
997
+ case 'search_code': return `"${input.pattern}"${input.path ? ` in ${input.path}` : ''}`;
998
+ case 'run_shell': return String(input.command);
999
+ case 'run_tests': return input.file_or_pattern ? String(input.file_or_pattern) : 'all tests';
1000
+ case 'git_diff': return input.path ? String(input.path) : 'all files';
1001
+ default: return JSON.stringify(input).slice(0, 60);
1002
+ }
1003
+ }
1004
+ function sep() {
1005
+ return (0, diamond_js_1.gradient)('─'.repeat(Math.min(cols(), 60)));
1006
+ }
1007
+ function createTuiDisplay() {
1008
+ let inStream = false;
1009
+ let thinkingFrame = 0;
1010
+ let thinkingInterval = null;
1011
+ return {
1012
+ agentThinking() {
1013
+ if (scrollMode)
1014
+ return;
1015
+ if (thinkingInterval)
1016
+ clearInterval(thinkingInterval);
1017
+ const spinners = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
1018
+ thinkingInterval = setInterval(() => {
1019
+ if (scrollMode) {
1020
+ if (thinkingInterval) {
1021
+ clearInterval(thinkingInterval);
1022
+ thinkingInterval = null;
1023
+ }
1024
+ return;
1025
+ }
1026
+ const s = spinners[(thinkingFrame++) % spinners.length];
1027
+ cursorCol(1);
1028
+ clearEol();
1029
+ rawWrite(TEXT_DIM(` ${s} thinking`));
1030
+ cursorCol(1);
1031
+ }, 100);
1032
+ },
1033
+ toolStart(name) {
1034
+ if (thinkingInterval) {
1035
+ clearInterval(thinkingInterval);
1036
+ thinkingInterval = null;
1037
+ }
1038
+ stopToolSpinner();
1039
+ startToolSpinner(name);
1040
+ },
1041
+ streamText(text) {
1042
+ if (!inStream) {
1043
+ inStream = true;
1044
+ stopToolSpinner();
1045
+ if (!scrollMode) {
1046
+ cursorCol(1);
1047
+ clearEol();
1048
+ }
1049
+ }
1050
+ writeStream(TEXT(text));
1051
+ },
1052
+ streamEnd() {
1053
+ if (inStream) {
1054
+ if (streamAccum) {
1055
+ pushScrollback(wrapForTerminal(streamAccum).output.split('\n'));
1056
+ streamAccum = '';
1057
+ }
1058
+ inStream = false;
1059
+ if (scrollMode)
1060
+ return;
1061
+ rawWrite('\n');
1062
+ }
1063
+ },
1064
+ toolCall(name, input) {
1065
+ stopToolSpinner();
1066
+ const icon = toolIcon(name);
1067
+ const label = chalk_1.default.hex('#cc785c').bold(`${icon} ${name}`);
1068
+ const detail = fmtIn(name, input);
1069
+ writeOutput(` ${label} ${TEXT_DIM(detail)}`);
1070
+ },
1071
+ toolResult(name, result, elapsedMs) {
1072
+ stopToolSpinner();
1073
+ const lines = result.split('\n');
1074
+ const preview = lines.length > 8
1075
+ ? lines.slice(0, 8).join('\n') + TEXT_DIM(`\n ... (${lines.length - 8} more lines)`)
1076
+ : result;
1077
+ const elapsed = TEXT_DIM(`${elapsedMs}ms`);
1078
+ const isError = result.startsWith('Error:') || result.startsWith('Tool error');
1079
+ if (isError) {
1080
+ writeOutput(' ' + chalk_1.default.hex('#b15439')('✗ ') + TEXT_DIM(preview.replace(/\n/g, '\n ')));
1081
+ }
1082
+ else {
1083
+ const fl = lines[0] ?? '';
1084
+ if (lines.length <= 3) {
1085
+ writeOutput(' ' + chalk_1.default.hex('#5a9e6e')('✓ ') + TEXT_DIM(result));
1086
+ }
1087
+ else {
1088
+ writeOutput(' ' + chalk_1.default.hex('#5a9e6e')('✓ ') + TEXT_DIM(`${fl}`) + TEXT_DIM(` (+${lines.length - 1} lines) ${elapsed}`));
1089
+ }
1090
+ }
1091
+ },
1092
+ toolBlocked(name, reason) {
1093
+ stopToolSpinner();
1094
+ writeOutput(' ' + chalk_1.default.hex('#d4903a')(`⊘ ${name} blocked: ${reason}`));
1095
+ },
1096
+ warning(msg) {
1097
+ writeOutput('\n' + chalk_1.default.hex('#d4903a')(` ⚠ ${msg}`));
1098
+ },
1099
+ success(msg) {
1100
+ writeOutput('\n' + chalk_1.default.hex('#5a9e6e')(` ✓ ${msg}`));
1101
+ },
1102
+ error(msg) {
1103
+ writeOutput('\n' + chalk_1.default.hex('#b15439')(` ✗ ${msg}`));
1104
+ },
1105
+ header(title, subtitle) {
1106
+ const l = sep();
1107
+ writeOutput('\n' + l);
1108
+ writeOutput(chalk_1.default.hex('#cc785c').bold(` ${title}`));
1109
+ if (subtitle)
1110
+ writeOutput(TEXT_DIM(` ${subtitle}`));
1111
+ writeOutput(l);
1112
+ },
1113
+ summary(text, turns, toolCount) {
1114
+ const l = sep();
1115
+ writeOutput('\n' + l);
1116
+ writeOutput(chalk_1.default.hex('#5a9e6e').bold(' ✓ Done'));
1117
+ writeOutput(TEXT_DIM(` ${turns} turn${turns > 1 ? 's' : ''} · ${toolCount} tool call${toolCount > 1 ? 's' : ''}`));
1118
+ if (text) {
1119
+ const mdLines = (0, markdown_js_1.renderMarkdown)(text);
1120
+ writeOutput('');
1121
+ mdLines.forEach(lx => writeOutput(lx));
1122
+ }
1123
+ writeOutput(l + '\n');
1124
+ },
1125
+ showPlan(plan) {
1126
+ const l = sep();
1127
+ const idxMap = new Map(plan.steps.map((s, i) => [s.id, i + 1]));
1128
+ writeOutput('\n' + l);
1129
+ writeOutput(chalk_1.default.hex('#cc785c').bold(' Execution Plan'));
1130
+ writeOutput(TEXT_DIM(` Goal: ${plan.goal}`));
1131
+ writeOutput(l);
1132
+ plan.steps.forEach((s, i) => {
1133
+ const num = TEXT_DIM(`${i + 1}.`);
1134
+ const spec = chalk_1.default.hex('#cc785c').bold(`[${s.specialist}]`);
1135
+ const task = TEXT(s.task.length > 55 ? s.task.slice(0, 52) + '…' : s.task);
1136
+ const deps = s.dependsOn.length > 0
1137
+ ? TEXT_DIM(` ← ${s.dependsOn.map(d => idxMap.get(d) ?? '?').join(', ')}`)
1138
+ : '';
1139
+ writeOutput(` ${num} ${spec} ${task}${deps}`);
1140
+ });
1141
+ writeOutput(l + '\n');
1142
+ },
1143
+ stepStarted(step) {
1144
+ const spec = chalk_1.default.hex('#d4903a').bold(`[${step.specialist}]`);
1145
+ const task = TEXT_DIM(step.task.length > 70 ? step.task.slice(0, 67) + '…' : step.task);
1146
+ writeOutput('\n' + chalk_1.default.hex('#d4903a')(' →') + ` ${spec} ${task}`);
1147
+ },
1148
+ stepCompleted(step, _result) {
1149
+ const spec = chalk_1.default.hex('#5a9e6e').bold(`[${step.specialist}]`);
1150
+ const ms = step.durationMs != null ? `${step.durationMs}ms` : '?ms';
1151
+ writeOutput(chalk_1.default.hex('#5a9e6e')(' ✓') + ` ${spec} ${TEXT_DIM(`done (${ms})`)}`);
1152
+ },
1153
+ retry(info) {
1154
+ const secs = (info.delayMs / 1000).toFixed(1);
1155
+ writeOutput(chalk_1.default.hex('#d4903a')(` ⟳ ${info.provider} retrying in ${secs}s (attempt ${info.attempt}) — ${info.reason}`));
1156
+ },
1157
+ failover(info) {
1158
+ writeOutput(chalk_1.default.hex('#d4903a')(` ⤳ Failing over ${info.from} → ${info.to} (${info.reason})`));
1159
+ },
1160
+ circuit(info) {
1161
+ const colour = info.state === 'open' ? '#b15439' : info.state === 'half-open' ? '#d4903a' : '#5a9e6e';
1162
+ writeOutput(chalk_1.default.hex(colour)(` ◯ Circuit ${info.provider}: ${info.state}`));
1163
+ },
1164
+ contextBar(health) {
1165
+ setFooter((0, context_health_js_1.formatContextBar)(health));
1166
+ },
1167
+ contextDashboard(health) {
1168
+ writeOutput((0, context_health_js_1.formatContextDashboard)(health));
1169
+ },
1170
+ compactionEvent(info) {
1171
+ const saved = ((1 - info.afterTokens / info.beforeTokens) * 100).toFixed(0);
1172
+ writeOutput(chalk_1.default.hex('#d4903a')(` ⚠ Context compacted: ${info.beforeTokens.toLocaleString()} → ${info.afterTokens.toLocaleString()} tokens (-${saved}%) · gen ${info.generation}`));
1173
+ },
1174
+ };
1175
+ }
1176
+ //# sourceMappingURL=tui.js.map