@compilr-dev/cli 0.4.0 → 0.5.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.
Files changed (315) hide show
  1. package/README.md +30 -12
  2. package/dist/agent.d.ts +74 -1
  3. package/dist/agent.js +259 -76
  4. package/dist/anchors/index.d.ts +9 -0
  5. package/dist/anchors/index.js +9 -0
  6. package/dist/anchors/project-anchors.d.ts +79 -0
  7. package/dist/anchors/project-anchors.js +202 -0
  8. package/dist/commands/handler-types.d.ts +68 -0
  9. package/dist/commands/handler-types.js +8 -0
  10. package/dist/commands/handlers/agent-commands.d.ts +13 -0
  11. package/dist/commands/handlers/agent-commands.js +305 -0
  12. package/dist/commands/handlers/design-commands.d.ts +15 -0
  13. package/dist/commands/handlers/design-commands.js +334 -0
  14. package/dist/commands/handlers/index.d.ts +20 -0
  15. package/dist/commands/handlers/index.js +43 -0
  16. package/dist/commands/handlers/overlay-commands.d.ts +21 -0
  17. package/dist/commands/handlers/overlay-commands.js +287 -0
  18. package/dist/commands/handlers/project-commands.d.ts +11 -0
  19. package/dist/commands/handlers/project-commands.js +167 -0
  20. package/dist/commands/handlers/simple-commands.d.ts +19 -0
  21. package/dist/commands/handlers/simple-commands.js +144 -0
  22. package/dist/commands/index.d.ts +2 -1
  23. package/dist/commands/registry.d.ts +50 -0
  24. package/dist/commands/registry.js +75 -0
  25. package/dist/commands-v2/handlers/context.d.ts +13 -0
  26. package/dist/commands-v2/handlers/context.js +348 -0
  27. package/dist/commands-v2/handlers/core.d.ts +13 -0
  28. package/dist/commands-v2/handlers/core.js +165 -0
  29. package/dist/commands-v2/handlers/debug.d.ts +11 -0
  30. package/dist/commands-v2/handlers/debug.js +159 -0
  31. package/dist/commands-v2/handlers/index.d.ts +12 -0
  32. package/dist/commands-v2/handlers/index.js +24 -0
  33. package/dist/commands-v2/handlers/project.d.ts +22 -0
  34. package/dist/commands-v2/handlers/project.js +814 -0
  35. package/dist/commands-v2/handlers/settings.d.ts +15 -0
  36. package/dist/commands-v2/handlers/settings.js +235 -0
  37. package/dist/commands-v2/index.d.ts +13 -0
  38. package/dist/commands-v2/index.js +15 -0
  39. package/dist/commands-v2/registry.d.ts +37 -0
  40. package/dist/commands-v2/registry.js +80 -0
  41. package/dist/commands-v2/types.d.ts +75 -0
  42. package/dist/commands-v2/types.js +7 -0
  43. package/dist/commands.js +110 -7
  44. package/dist/index.js +288 -29
  45. package/dist/input-handlers/index.d.ts +7 -0
  46. package/dist/input-handlers/index.js +7 -0
  47. package/dist/input-handlers/memory-handler.d.ts +26 -0
  48. package/dist/input-handlers/memory-handler.js +68 -0
  49. package/dist/repl-helpers.d.ts +63 -0
  50. package/dist/repl-helpers.js +318 -0
  51. package/dist/repl-v2.d.ts +155 -0
  52. package/dist/repl-v2.js +774 -0
  53. package/dist/repl.d.ts +32 -4
  54. package/dist/repl.js +250 -977
  55. package/dist/settings/index.d.ts +23 -0
  56. package/dist/settings/index.js +48 -0
  57. package/dist/settings/paths.d.ts +110 -0
  58. package/dist/settings/paths.js +264 -0
  59. package/dist/templates/compilr-md.js +7 -4
  60. package/dist/templates/index.js +3 -4
  61. package/dist/themes/colors.js +3 -1
  62. package/dist/themes/registry.d.ts +5 -36
  63. package/dist/themes/registry.js +11 -95
  64. package/dist/themes/types.d.ts +3 -38
  65. package/dist/themes/types.js +2 -2
  66. package/dist/tools/anchor-tools.d.ts +31 -0
  67. package/dist/tools/anchor-tools.js +255 -0
  68. package/dist/tools/backlog-wrappers.d.ts +54 -0
  69. package/dist/tools/backlog-wrappers.js +338 -0
  70. package/dist/tools/backlog.js +1 -1
  71. package/dist/tools/db-tools.d.ts +65 -0
  72. package/dist/tools/db-tools.js +19 -0
  73. package/dist/tools/document-db.d.ts +43 -0
  74. package/dist/tools/document-db.js +220 -0
  75. package/dist/tools/project-db.d.ts +102 -0
  76. package/dist/tools/project-db.js +370 -0
  77. package/dist/tools/workitem-db.d.ts +103 -0
  78. package/dist/tools/workitem-db.js +549 -0
  79. package/dist/tools.js +13 -3
  80. package/dist/ui/agents-overlay-v2.d.ts +43 -0
  81. package/dist/ui/agents-overlay-v2.js +809 -0
  82. package/dist/ui/agents-overlay.d.ts +5 -5
  83. package/dist/ui/agents-overlay.js +782 -420
  84. package/dist/ui/anchors-overlay.d.ts +12 -0
  85. package/dist/ui/anchors-overlay.js +775 -0
  86. package/dist/ui/arch-type-overlay.d.ts +1 -6
  87. package/dist/ui/arch-type-overlay.js +175 -203
  88. package/dist/ui/ask-user-overlay-v2.d.ts +26 -0
  89. package/dist/ui/ask-user-overlay-v2.js +555 -0
  90. package/dist/ui/ask-user-overlay.d.ts +2 -2
  91. package/dist/ui/ask-user-overlay.js +443 -535
  92. package/dist/ui/ask-user-simple-overlay-v2.d.ts +25 -0
  93. package/dist/ui/ask-user-simple-overlay-v2.js +215 -0
  94. package/dist/ui/ask-user-simple-overlay.d.ts +2 -2
  95. package/dist/ui/ask-user-simple-overlay.js +182 -209
  96. package/dist/ui/backlog-overlay.d.ts +16 -1
  97. package/dist/ui/backlog-overlay.js +525 -659
  98. package/dist/ui/base/index.d.ts +26 -0
  99. package/dist/ui/base/index.js +33 -0
  100. package/dist/ui/base/inline-overlay-utils.d.ts +217 -0
  101. package/dist/ui/base/inline-overlay-utils.js +320 -0
  102. package/dist/ui/base/inline-overlay.d.ts +159 -0
  103. package/dist/ui/base/inline-overlay.js +257 -0
  104. package/dist/ui/base/key-utils.d.ts +15 -0
  105. package/dist/ui/base/key-utils.js +30 -0
  106. package/dist/ui/base/overlay-base-v2.d.ts +193 -0
  107. package/dist/ui/base/overlay-base-v2.js +246 -0
  108. package/dist/ui/base/overlay-base.d.ts +156 -0
  109. package/dist/ui/base/overlay-base.js +238 -0
  110. package/dist/ui/base/overlay-lifecycle.d.ts +65 -0
  111. package/dist/ui/base/overlay-lifecycle.js +159 -0
  112. package/dist/ui/base/overlay-types.d.ts +185 -0
  113. package/dist/ui/base/overlay-types.js +7 -0
  114. package/dist/ui/base/render-utils.d.ts +8 -0
  115. package/dist/ui/base/render-utils.js +11 -0
  116. package/dist/ui/base/screen-stack.d.ts +148 -0
  117. package/dist/ui/base/screen-stack.js +184 -0
  118. package/dist/ui/base/tabbed-list-overlay-v2.d.ts +103 -0
  119. package/dist/ui/base/tabbed-list-overlay-v2.js +317 -0
  120. package/dist/ui/base/tabbed-list-overlay.d.ts +153 -0
  121. package/dist/ui/base/tabbed-list-overlay.js +369 -0
  122. package/dist/ui/commands-overlay-v2.d.ts +33 -0
  123. package/dist/ui/commands-overlay-v2.js +441 -0
  124. package/dist/ui/commands-overlay.d.ts +7 -2
  125. package/dist/ui/commands-overlay.js +384 -355
  126. package/dist/ui/config-overlay.d.ts +5 -4
  127. package/dist/ui/config-overlay.js +243 -513
  128. package/dist/ui/conversation.d.ts +75 -4
  129. package/dist/ui/conversation.js +374 -161
  130. package/dist/ui/docs-overlay.d.ts +17 -0
  131. package/dist/ui/docs-overlay.js +303 -0
  132. package/dist/ui/ephemeral.d.ts +1 -1
  133. package/dist/ui/ephemeral.js +1 -1
  134. package/dist/ui/features/index.d.ts +34 -0
  135. package/dist/ui/features/index.js +34 -0
  136. package/dist/ui/features/input-feature.d.ts +85 -0
  137. package/dist/ui/features/input-feature.js +238 -0
  138. package/dist/ui/features/list-feature.d.ts +155 -0
  139. package/dist/ui/features/list-feature.js +244 -0
  140. package/dist/ui/features/pagination-feature.d.ts +154 -0
  141. package/dist/ui/features/pagination-feature.js +238 -0
  142. package/dist/ui/features/search-feature.d.ts +148 -0
  143. package/dist/ui/features/search-feature.js +185 -0
  144. package/dist/ui/features/tab-feature.d.ts +194 -0
  145. package/dist/ui/features/tab-feature.js +307 -0
  146. package/dist/ui/footer-v2.d.ts +222 -0
  147. package/dist/ui/footer-v2.js +1349 -0
  148. package/dist/ui/footer.d.ts +107 -0
  149. package/dist/ui/footer.js +359 -67
  150. package/dist/ui/guardrail-overlay.d.ts +29 -0
  151. package/dist/ui/guardrail-overlay.js +145 -0
  152. package/dist/ui/help-overlay-v2.d.ts +34 -0
  153. package/dist/ui/help-overlay-v2.js +309 -0
  154. package/dist/ui/help-overlay.d.ts +16 -0
  155. package/dist/ui/help-overlay.js +316 -0
  156. package/dist/ui/index.d.ts +1 -1
  157. package/dist/ui/index.js +1 -3
  158. package/dist/ui/init-overlay-v2.d.ts +34 -0
  159. package/dist/ui/init-overlay-v2.js +600 -0
  160. package/dist/ui/init-overlay.d.ts +12 -2
  161. package/dist/ui/init-overlay.js +349 -270
  162. package/dist/ui/input-prompt-v2.d.ts +1 -0
  163. package/dist/ui/input-prompt-v2.js +14 -6
  164. package/dist/ui/input-prompt.d.ts +116 -33
  165. package/dist/ui/input-prompt.js +536 -337
  166. package/dist/ui/iteration-limit-overlay-v2.d.ts +21 -0
  167. package/dist/ui/iteration-limit-overlay-v2.js +114 -0
  168. package/dist/ui/iteration-limit-overlay.d.ts +2 -2
  169. package/dist/ui/iteration-limit-overlay.js +92 -128
  170. package/dist/ui/keys-overlay-v2.d.ts +41 -0
  171. package/dist/ui/keys-overlay-v2.js +248 -0
  172. package/dist/ui/keys-overlay.d.ts +1 -0
  173. package/dist/ui/keys-overlay.js +203 -141
  174. package/dist/ui/line-utils.d.ts +88 -0
  175. package/dist/ui/line-utils.js +150 -0
  176. package/dist/ui/live-region.d.ts +161 -0
  177. package/dist/ui/live-region.js +387 -0
  178. package/dist/ui/mascot/expressions.d.ts +32 -0
  179. package/dist/ui/mascot/expressions.js +213 -0
  180. package/dist/ui/mascot/index.d.ts +8 -0
  181. package/dist/ui/mascot/index.js +8 -0
  182. package/dist/ui/mascot/renderer.d.ts +19 -0
  183. package/dist/ui/mascot/renderer.js +97 -0
  184. package/dist/ui/mascot-overlay-v2.d.ts +41 -0
  185. package/dist/ui/mascot-overlay-v2.js +138 -0
  186. package/dist/ui/mascot-overlay.d.ts +21 -0
  187. package/dist/ui/mascot-overlay.js +146 -0
  188. package/dist/ui/model-overlay-v2.d.ts +49 -0
  189. package/dist/ui/model-overlay-v2.js +118 -0
  190. package/dist/ui/model-overlay.d.ts +27 -0
  191. package/dist/ui/model-overlay.js +221 -0
  192. package/dist/ui/model-warning-overlay.js +3 -5
  193. package/dist/ui/new-overlay.d.ts +34 -0
  194. package/dist/ui/new-overlay.js +604 -0
  195. package/dist/ui/overlay/impl/agents-overlay-v2.d.ts +45 -0
  196. package/dist/ui/overlay/impl/agents-overlay-v2.js +825 -0
  197. package/dist/ui/overlay/impl/anchors-overlay-v2.d.ts +47 -0
  198. package/dist/ui/overlay/impl/anchors-overlay-v2.js +783 -0
  199. package/dist/ui/overlay/impl/arch-type-overlay-v2.d.ts +37 -0
  200. package/dist/ui/overlay/impl/arch-type-overlay-v2.js +240 -0
  201. package/dist/ui/overlay/impl/ask-user-overlay-v2.d.ts +72 -0
  202. package/dist/ui/overlay/impl/ask-user-overlay-v2.js +584 -0
  203. package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.d.ts +46 -0
  204. package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.js +204 -0
  205. package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +49 -0
  206. package/dist/ui/overlay/impl/backlog-overlay-v2.js +642 -0
  207. package/dist/ui/overlay/impl/commands-overlay-v2.d.ts +33 -0
  208. package/dist/ui/overlay/impl/commands-overlay-v2.js +441 -0
  209. package/dist/ui/overlay/impl/config-overlay-v2.d.ts +100 -0
  210. package/dist/ui/overlay/impl/config-overlay-v2.js +654 -0
  211. package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +55 -0
  212. package/dist/ui/overlay/impl/dashboard-overlay-v2.js +359 -0
  213. package/dist/ui/overlay/impl/docs-overlay-v2.d.ts +45 -0
  214. package/dist/ui/overlay/impl/docs-overlay-v2.js +114 -0
  215. package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +77 -0
  216. package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1071 -0
  217. package/dist/ui/overlay/impl/guardrail-overlay-v2.d.ts +43 -0
  218. package/dist/ui/overlay/impl/guardrail-overlay-v2.js +114 -0
  219. package/dist/ui/overlay/impl/help-overlay-v2.d.ts +34 -0
  220. package/dist/ui/overlay/impl/help-overlay-v2.js +309 -0
  221. package/dist/ui/overlay/impl/init-overlay-v2.d.ts +77 -0
  222. package/dist/ui/overlay/impl/init-overlay-v2.js +593 -0
  223. package/dist/ui/overlay/impl/init-setup-overlay-v2.d.ts +25 -0
  224. package/dist/ui/overlay/impl/init-setup-overlay-v2.js +97 -0
  225. package/dist/ui/overlay/impl/iteration-limit-overlay-v2.d.ts +35 -0
  226. package/dist/ui/overlay/impl/iteration-limit-overlay-v2.js +105 -0
  227. package/dist/ui/overlay/impl/keys-overlay-v2.d.ts +41 -0
  228. package/dist/ui/overlay/impl/keys-overlay-v2.js +248 -0
  229. package/dist/ui/overlay/impl/mascot-overlay-v2.d.ts +41 -0
  230. package/dist/ui/overlay/impl/mascot-overlay-v2.js +138 -0
  231. package/dist/ui/overlay/impl/model-overlay-v2.d.ts +49 -0
  232. package/dist/ui/overlay/impl/model-overlay-v2.js +118 -0
  233. package/dist/ui/overlay/impl/model-warning-overlay-v2.d.ts +46 -0
  234. package/dist/ui/overlay/impl/model-warning-overlay-v2.js +132 -0
  235. package/dist/ui/overlay/impl/new-overlay-v2.d.ts +77 -0
  236. package/dist/ui/overlay/impl/new-overlay-v2.js +593 -0
  237. package/dist/ui/overlay/impl/permission-overlay-v2.d.ts +36 -0
  238. package/dist/ui/overlay/impl/permission-overlay-v2.js +380 -0
  239. package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +36 -0
  240. package/dist/ui/overlay/impl/projects-overlay-v2.js +499 -0
  241. package/dist/ui/overlay/impl/theme-overlay-v2.d.ts +42 -0
  242. package/dist/ui/overlay/impl/theme-overlay-v2.js +135 -0
  243. package/dist/ui/overlay/impl/tools-overlay-v2.d.ts +47 -0
  244. package/dist/ui/overlay/impl/tools-overlay-v2.js +218 -0
  245. package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +31 -0
  246. package/dist/ui/overlay/impl/tutorial-overlay-v2.js +1035 -0
  247. package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +80 -0
  248. package/dist/ui/overlay/impl/workflow-overlay-v2.js +637 -0
  249. package/dist/ui/overlay/index.d.ts +33 -0
  250. package/dist/ui/overlay/index.js +35 -0
  251. package/dist/ui/overlay/key-utils.d.ts +6 -0
  252. package/dist/ui/overlay/key-utils.js +6 -0
  253. package/dist/ui/overlay/overlay-types.d.ts +128 -0
  254. package/dist/ui/overlay/overlay-types.js +22 -0
  255. package/dist/ui/overlay/types.d.ts +135 -0
  256. package/dist/ui/overlay/types.js +22 -0
  257. package/dist/ui/overlays/help-overlay-v2.d.ts +28 -0
  258. package/dist/ui/overlays/help-overlay-v2.js +198 -0
  259. package/dist/ui/overlays/index.d.ts +11 -0
  260. package/dist/ui/overlays/index.js +11 -0
  261. package/dist/ui/overlays.d.ts +0 -4
  262. package/dist/ui/overlays.js +0 -444
  263. package/dist/ui/permission-overlay-v2.d.ts +36 -0
  264. package/dist/ui/permission-overlay-v2.js +380 -0
  265. package/dist/ui/permission-overlay.d.ts +1 -1
  266. package/dist/ui/permission-overlay.js +186 -298
  267. package/dist/ui/projects-overlay.d.ts +19 -0
  268. package/dist/ui/projects-overlay.js +484 -0
  269. package/dist/ui/providers/types.d.ts +178 -0
  270. package/dist/ui/providers/types.js +9 -0
  271. package/dist/ui/render-modes.d.ts +36 -0
  272. package/dist/ui/render-modes.js +44 -0
  273. package/dist/ui/startup-menu.d.ts +36 -0
  274. package/dist/ui/startup-menu.js +236 -0
  275. package/dist/ui/subagent-renderer.d.ts +117 -0
  276. package/dist/ui/subagent-renderer.js +334 -0
  277. package/dist/ui/terminal-codes.d.ts +94 -0
  278. package/dist/ui/terminal-codes.js +124 -0
  279. package/dist/ui/terminal-renderer.d.ts +221 -0
  280. package/dist/ui/terminal-renderer.js +751 -0
  281. package/dist/ui/terminal-ui.d.ts +463 -0
  282. package/dist/ui/terminal-ui.js +2296 -0
  283. package/dist/ui/terminal.d.ts +20 -0
  284. package/dist/ui/terminal.js +72 -0
  285. package/dist/ui/theme-overlay-v2.d.ts +42 -0
  286. package/dist/ui/theme-overlay-v2.js +135 -0
  287. package/dist/ui/theme-overlay.d.ts +24 -0
  288. package/dist/ui/theme-overlay.js +127 -0
  289. package/dist/ui/todo-zone.js +53 -25
  290. package/dist/ui/tool-formatters.d.ts +16 -0
  291. package/dist/ui/tool-formatters.js +516 -0
  292. package/dist/ui/tools-overlay-v2.d.ts +47 -0
  293. package/dist/ui/tools-overlay-v2.js +218 -0
  294. package/dist/ui/tools-overlay.d.ts +10 -2
  295. package/dist/ui/tools-overlay.js +172 -220
  296. package/dist/ui/tutorial-overlay-v2.d.ts +31 -0
  297. package/dist/ui/tutorial-overlay-v2.js +1035 -0
  298. package/dist/ui/tutorial-overlay.d.ts +1 -0
  299. package/dist/ui/tutorial-overlay.js +400 -302
  300. package/dist/ui/workflow-overlay.d.ts +22 -0
  301. package/dist/ui/workflow-overlay.js +636 -0
  302. package/dist/utils/debug-log.d.ts +28 -0
  303. package/dist/utils/debug-log.js +57 -0
  304. package/dist/utils/model-tiers.js +1 -1
  305. package/dist/utils/path-safety.d.ts +56 -0
  306. package/dist/utils/path-safety.js +239 -0
  307. package/dist/workflow/guided-mode-injector.d.ts +42 -0
  308. package/dist/workflow/guided-mode-injector.js +191 -0
  309. package/dist/workflow/index.d.ts +8 -0
  310. package/dist/workflow/index.js +8 -0
  311. package/dist/workflow/step-criteria.d.ts +62 -0
  312. package/dist/workflow/step-criteria.js +150 -0
  313. package/dist/workflow/step-tracker.d.ts +92 -0
  314. package/dist/workflow/step-tracker.js +141 -0
  315. package/package.json +12 -5
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Iteration Limit Overlay (Refactored)
3
+ *
4
+ * Modal overlay shown when the agent reaches its iteration limit.
5
+ * Uses InlineOverlay base class for consistent lifecycle management.
6
+ */
7
+ export type IterationLimitResult = {
8
+ continue: true;
9
+ additionalIterations: number;
10
+ } | {
11
+ continue: false;
12
+ };
13
+ export interface IterationLimitOverlayOptions {
14
+ iteration: number;
15
+ maxIterations: number;
16
+ toolCallCount: number;
17
+ }
18
+ /**
19
+ * Show the iteration limit overlay
20
+ */
21
+ export declare function showIterationLimitOverlay(options: IterationLimitOverlayOptions): Promise<IterationLimitResult>;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Iteration Limit Overlay (Refactored)
3
+ *
4
+ * Modal overlay shown when the agent reaches its iteration limit.
5
+ * Uses InlineOverlay base class for consistent lifecycle management.
6
+ */
7
+ import chalk from 'chalk';
8
+ import { getStyles } from '../themes/index.js';
9
+ import { InlineOverlay } from './base/inline-overlay.js';
10
+ // =============================================================================
11
+ // Constants
12
+ // =============================================================================
13
+ const OPTIONS = [
14
+ { label: 'Yes, continue (+10 iterations)', key: '1', result: { continue: true, additionalIterations: 10 } },
15
+ { label: 'Yes, continue (+20 iterations)', key: '2', result: { continue: true, additionalIterations: 20 } },
16
+ { label: 'No, stop here', key: 'n', result: { continue: false } },
17
+ ];
18
+ // =============================================================================
19
+ // Overlay Implementation
20
+ // =============================================================================
21
+ class IterationLimitOverlayImpl extends InlineOverlay {
22
+ options;
23
+ constructor(options) {
24
+ super();
25
+ this.options = options;
26
+ }
27
+ getInitialState() {
28
+ return {
29
+ selectedIndex: 0, // Default to "Yes, continue (+10)"
30
+ };
31
+ }
32
+ render() {
33
+ const s = getStyles();
34
+ const lines = [];
35
+ const cols = this.getTerminalWidth();
36
+ const border = s.muted('─'.repeat(Math.max(1, cols - 1)));
37
+ // Header
38
+ lines.push(border);
39
+ lines.push(' ' + s.warning('⚠') + ' ' + chalk.bold('Iteration Limit Reached'));
40
+ lines.push('');
41
+ // Stats
42
+ lines.push(' Iterations: ' + s.primary(String(this.options.iteration)) + ' / ' + s.muted(String(this.options.maxIterations)));
43
+ lines.push(' Tool calls: ' + s.primary(String(this.options.toolCallCount)));
44
+ lines.push('');
45
+ lines.push(' ' + s.muted('The agent has reached its iteration limit.'));
46
+ lines.push(' ' + s.muted('Would you like to continue?'));
47
+ lines.push('');
48
+ // Options
49
+ for (let i = 0; i < OPTIONS.length; i++) {
50
+ const isCursor = this.state.selectedIndex === i;
51
+ const prefix = isCursor ? ' ❯ ' : ' ';
52
+ const key = `[${OPTIONS[i].key}] `;
53
+ if (isCursor) {
54
+ lines.push(s.primary(prefix + key + OPTIONS[i].label));
55
+ }
56
+ else {
57
+ lines.push(s.muted(prefix + key + OPTIONS[i].label));
58
+ }
59
+ }
60
+ // Footer
61
+ lines.push('');
62
+ lines.push(s.muted(' ↑↓ Navigate · Enter Select · 1/2/n Quick select'));
63
+ // Bottom border
64
+ lines.push(border);
65
+ return lines;
66
+ }
67
+ handleKey(data) {
68
+ // Ctrl+C or Escape = stop
69
+ if (this.isCtrlCKey(data) || this.isEscapeKey(data)) {
70
+ return { type: 'close', result: { continue: false } };
71
+ }
72
+ // Quick keys
73
+ const key = data.toString();
74
+ if (key === '1') {
75
+ return { type: 'close', result: { continue: true, additionalIterations: 10 } };
76
+ }
77
+ if (key === '2') {
78
+ return { type: 'close', result: { continue: true, additionalIterations: 20 } };
79
+ }
80
+ if (key.toLowerCase() === 'n') {
81
+ return { type: 'close', result: { continue: false } };
82
+ }
83
+ // Arrow navigation
84
+ if (this.isUpArrowKey(data)) {
85
+ this.state.selectedIndex = Math.max(0, this.state.selectedIndex - 1);
86
+ return { type: 'continue' };
87
+ }
88
+ if (this.isDownArrowKey(data)) {
89
+ this.state.selectedIndex = Math.min(OPTIONS.length - 1, this.state.selectedIndex + 1);
90
+ return { type: 'continue' };
91
+ }
92
+ if (this.isEnterKey(data)) {
93
+ return { type: 'close', result: OPTIONS[this.state.selectedIndex].result };
94
+ }
95
+ return { type: 'continue' };
96
+ }
97
+ getCleanupSummary(result) {
98
+ const s = getStyles();
99
+ if (result.continue) {
100
+ return s.muted('Iteration limit: ') + s.success(`Continuing (+${String(result.additionalIterations)})`);
101
+ }
102
+ return s.muted('Iteration limit: ') + s.error('Stopped');
103
+ }
104
+ }
105
+ // =============================================================================
106
+ // Main Export
107
+ // =============================================================================
108
+ /**
109
+ * Show the iteration limit overlay
110
+ */
111
+ export async function showIterationLimitOverlay(options) {
112
+ const overlay = new IterationLimitOverlayImpl(options);
113
+ return overlay.show();
114
+ }
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Iteration Limit Overlay
2
+ * Iteration Limit Overlay (Refactored)
3
3
  *
4
4
  * Modal overlay shown when the agent reaches its iteration limit.
5
- * Asks the user if they want to continue or stop execution.
5
+ * Uses InlineOverlay base class for consistent lifecycle management.
6
6
  */
7
7
  export type IterationLimitResult = {
8
8
  continue: true;
@@ -1,61 +1,106 @@
1
1
  /**
2
- * Iteration Limit Overlay
2
+ * Iteration Limit Overlay (Refactored)
3
3
  *
4
4
  * Modal overlay shown when the agent reaches its iteration limit.
5
- * Asks the user if they want to continue or stop execution.
5
+ * Uses InlineOverlay base class for consistent lifecycle management.
6
6
  */
7
7
  import chalk from 'chalk';
8
- import * as terminal from './terminal.js';
9
8
  import { getStyles } from '../themes/index.js';
9
+ import { InlineOverlay } from './base/inline-overlay.js';
10
10
  // =============================================================================
11
- // Rendering
11
+ // Constants
12
12
  // =============================================================================
13
- function render(options, state, previousLineCount = 0, targetLineCount = 0) {
14
- const s = getStyles();
15
- const lines = [];
16
- const cols = terminal.getTerminalWidth();
17
- const border = s.muted('─'.repeat(Math.max(1, cols - 1)));
18
- // Clear previous render
19
- if (previousLineCount > 0) {
20
- terminal.clearLinesAbove(previousLineCount);
13
+ const OPTIONS = [
14
+ { label: 'Yes, continue (+10 iterations)', key: '1', result: { continue: true, additionalIterations: 10 } },
15
+ { label: 'Yes, continue (+20 iterations)', key: '2', result: { continue: true, additionalIterations: 20 } },
16
+ { label: 'No, stop here', key: 'n', result: { continue: false } },
17
+ ];
18
+ // =============================================================================
19
+ // Overlay Implementation
20
+ // =============================================================================
21
+ class IterationLimitOverlayImpl extends InlineOverlay {
22
+ options;
23
+ constructor(options) {
24
+ super();
25
+ this.options = options;
21
26
  }
22
- // Header
23
- lines.push(border);
24
- lines.push(' ' + s.warning('⚠') + ' ' + chalk.bold('Iteration Limit Reached'));
25
- lines.push('');
26
- // Stats
27
- lines.push(' Iterations: ' + s.primary(String(options.iteration)) + ' / ' + s.muted(String(options.maxIterations)));
28
- lines.push(' Tool calls: ' + s.primary(String(options.toolCallCount)));
29
- lines.push('');
30
- lines.push(' ' + s.muted('The agent has reached its iteration limit.'));
31
- lines.push(' ' + s.muted('Would you like to continue?'));
32
- lines.push('');
33
- // Options
34
- const optionLabels = ['Yes, continue (+10 iterations)', 'Yes, continue (+20 iterations)', 'No, stop here'];
35
- const optionKeys = ['1', '2', 'n'];
36
- for (let i = 0; i < optionLabels.length; i++) {
37
- const isCursor = state.selectedIndex === i;
38
- const prefix = isCursor ? ' ' : ' ';
39
- const key = `[${optionKeys[i]}] `;
40
- if (isCursor) {
41
- lines.push(s.primary(prefix + key + optionLabels[i]));
27
+ getInitialState() {
28
+ return {
29
+ selectedIndex: 0, // Default to "Yes, continue (+10)"
30
+ };
31
+ }
32
+ render() {
33
+ const s = getStyles();
34
+ const lines = [];
35
+ const cols = this.getTerminalWidth();
36
+ const border = s.muted('─'.repeat(Math.max(1, cols - 1)));
37
+ // Header
38
+ lines.push(border);
39
+ lines.push(' ' + s.warning('⚠') + ' ' + chalk.bold('Iteration Limit Reached'));
40
+ lines.push('');
41
+ // Stats
42
+ lines.push(' Iterations: ' + s.primary(String(this.options.iteration)) + ' / ' + s.muted(String(this.options.maxIterations)));
43
+ lines.push(' Tool calls: ' + s.primary(String(this.options.toolCallCount)));
44
+ lines.push('');
45
+ lines.push(' ' + s.muted('The agent has reached its iteration limit.'));
46
+ lines.push(' ' + s.muted('Would you like to continue?'));
47
+ lines.push('');
48
+ // Options
49
+ for (let i = 0; i < OPTIONS.length; i++) {
50
+ const isCursor = this.state.selectedIndex === i;
51
+ const prefix = isCursor ? ' ❯ ' : ' ';
52
+ const key = `[${OPTIONS[i].key}] `;
53
+ if (isCursor) {
54
+ lines.push(s.primary(prefix + key + OPTIONS[i].label));
55
+ }
56
+ else {
57
+ lines.push(s.muted(prefix + key + OPTIONS[i].label));
58
+ }
59
+ }
60
+ // Footer
61
+ lines.push('');
62
+ lines.push(s.muted(' ↑↓ Navigate · Enter Select · 1/2/n Quick select'));
63
+ // Bottom border
64
+ lines.push(border);
65
+ return lines;
66
+ }
67
+ handleKey(data) {
68
+ // Ctrl+C or Escape = stop
69
+ if (this.isCtrlCKey(data) || this.isEscapeKey(data)) {
70
+ return { type: 'close', result: { continue: false } };
71
+ }
72
+ // Quick keys
73
+ const key = data.toString();
74
+ if (key === '1') {
75
+ return { type: 'close', result: { continue: true, additionalIterations: 10 } };
76
+ }
77
+ if (key === '2') {
78
+ return { type: 'close', result: { continue: true, additionalIterations: 20 } };
79
+ }
80
+ if (key.toLowerCase() === 'n') {
81
+ return { type: 'close', result: { continue: false } };
82
+ }
83
+ // Arrow navigation
84
+ if (this.isUpArrowKey(data)) {
85
+ this.state.selectedIndex = Math.max(0, this.state.selectedIndex - 1);
86
+ return { type: 'continue' };
42
87
  }
43
- else {
44
- lines.push(s.muted(prefix + key + optionLabels[i]));
88
+ if (this.isDownArrowKey(data)) {
89
+ this.state.selectedIndex = Math.min(OPTIONS.length - 1, this.state.selectedIndex + 1);
90
+ return { type: 'continue' };
45
91
  }
92
+ if (this.isEnterKey(data)) {
93
+ return { type: 'close', result: OPTIONS[this.state.selectedIndex].result };
94
+ }
95
+ return { type: 'continue' };
46
96
  }
47
- // Footer
48
- lines.push('');
49
- lines.push(s.muted(' ↑↓ Navigate · Enter Select · 1/2/n Quick select'));
50
- // Bottom border
51
- lines.push(border);
52
- // Pad with empty lines to maintain consistent height
53
- while (lines.length < targetLineCount) {
54
- lines.push('');
97
+ getCleanupSummary(result) {
98
+ const s = getStyles();
99
+ if (result.continue) {
100
+ return s.muted('Iteration limit: ') + s.success(`Continuing (+${String(result.additionalIterations)})`);
101
+ }
102
+ return s.muted('Iteration limit: ') + s.error('Stopped');
55
103
  }
56
- // Render all lines
57
- terminal.write(lines.join('\n'));
58
- return lines.length;
59
104
  }
60
105
  // =============================================================================
61
106
  // Main Export
@@ -64,87 +109,6 @@ function render(options, state, previousLineCount = 0, targetLineCount = 0) {
64
109
  * Show the iteration limit overlay
65
110
  */
66
111
  export async function showIterationLimitOverlay(options) {
67
- const state = {
68
- selectedIndex: 0, // Default to "Yes, continue (+10)"
69
- };
70
- let lineCount = 0;
71
- let maxLineCount = 0;
72
- // Ensure we start from a fresh line
73
- terminal.writeLine('');
74
- terminal.hideCursor();
75
- const wasRawMode = process.stdin.isRaw;
76
- terminal.enableRawMode();
77
- // Initial render
78
- lineCount = render(options, state, 0);
79
- maxLineCount = Math.max(maxLineCount, lineCount);
80
- return new Promise((resolve) => {
81
- const cleanup = (result) => {
82
- terminal.clearLinesAbove(maxLineCount);
83
- // Show result summary
84
- const s = getStyles();
85
- if (result.continue) {
86
- terminal.writeLine(s.muted(`Iteration limit: `) + s.success(`Continuing (+${String(result.additionalIterations)})`));
87
- }
88
- else {
89
- terminal.writeLine(s.muted(`Iteration limit: `) + s.error(`Stopped`));
90
- }
91
- terminal.writeLine(''); // Blank line for separation
92
- terminal.showCursor();
93
- if (!wasRawMode) {
94
- terminal.disableRawMode();
95
- }
96
- process.stdin.removeListener('data', handleData);
97
- resolve(result);
98
- };
99
- const handleData = (data) => {
100
- const isEscape = data.length === 1 && data[0] === 0x1b;
101
- const isUpArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x41;
102
- const isDownArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x42;
103
- const isCtrlC = data.length === 1 && data[0] === 0x03;
104
- const isEnter = data.length === 1 && (data[0] === 0x0d || data[0] === 0x0a);
105
- // Ctrl+C or Escape = stop
106
- if (isCtrlC || isEscape) {
107
- cleanup({ continue: false });
108
- return;
109
- }
110
- // Quick keys
111
- const key = data.toString();
112
- if (key === '1') {
113
- cleanup({ continue: true, additionalIterations: 10 });
114
- return;
115
- }
116
- if (key === '2') {
117
- cleanup({ continue: true, additionalIterations: 20 });
118
- return;
119
- }
120
- if (key.toLowerCase() === 'n') {
121
- cleanup({ continue: false });
122
- return;
123
- }
124
- // Arrow navigation
125
- if (isUpArrow) {
126
- state.selectedIndex = Math.max(0, state.selectedIndex - 1);
127
- }
128
- else if (isDownArrow) {
129
- state.selectedIndex = Math.min(2, state.selectedIndex + 1);
130
- }
131
- else if (isEnter) {
132
- // Select based on current index
133
- if (state.selectedIndex === 0) {
134
- cleanup({ continue: true, additionalIterations: 10 });
135
- }
136
- else if (state.selectedIndex === 1) {
137
- cleanup({ continue: true, additionalIterations: 20 });
138
- }
139
- else {
140
- cleanup({ continue: false });
141
- }
142
- return;
143
- }
144
- // Re-render
145
- lineCount = render(options, state, maxLineCount, maxLineCount);
146
- maxLineCount = Math.max(maxLineCount, lineCount);
147
- };
148
- process.stdin.on('data', handleData);
149
- });
112
+ const overlay = new IterationLimitOverlayImpl(options);
113
+ return overlay.show();
150
114
  }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Keys Overlay V2
3
+ *
4
+ * API key management overlay using the new Overlay interface.
5
+ * Shows status of all providers and allows setting/deleting keys.
6
+ *
7
+ * Features:
8
+ * - List all providers with key status
9
+ * - Set new API keys
10
+ * - Delete stored keys
11
+ * - Works with TerminalUI's overlay management
12
+ */
13
+ import { BaseOverlayV2 } from './base/index.js';
14
+ import { getAllProviderStatuses } from '../utils/credentials.js';
15
+ import type { RenderContext, OverlayAction, KeyEvent } from './overlay/index.js';
16
+ export interface KeysOverlayV2Result {
17
+ /** Whether any keys were changed */
18
+ changed: boolean;
19
+ }
20
+ interface KeysState {
21
+ selectedIndex: number;
22
+ changed: boolean;
23
+ providers: ReturnType<typeof getAllProviderStatuses>;
24
+ }
25
+ /**
26
+ * Keys overlay using the new Overlay interface.
27
+ * Manages API keys for LLM providers.
28
+ */
29
+ export declare class KeysOverlayV2 extends BaseOverlayV2<KeysState, KeysOverlayV2Result> {
30
+ readonly type: "inline";
31
+ readonly id = "keys-overlay-v2";
32
+ private readonly screenStack;
33
+ constructor();
34
+ protected renderContent(_context: RenderContext): string[];
35
+ render(context: RenderContext): {
36
+ lines: string[];
37
+ minHeight?: number;
38
+ };
39
+ handleKey(key: KeyEvent): OverlayAction<KeysOverlayV2Result>;
40
+ }
41
+ export {};
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Keys Overlay V2
3
+ *
4
+ * API key management overlay using the new Overlay interface.
5
+ * Shows status of all providers and allows setting/deleting keys.
6
+ *
7
+ * Features:
8
+ * - List all providers with key status
9
+ * - Set new API keys
10
+ * - Delete stored keys
11
+ * - Works with TerminalUI's overlay management
12
+ */
13
+ import * as terminal from './terminal.js';
14
+ import { BaseOverlayV2, BaseScreen, ScreenStack, stay, pushScreen, popScreen, closeOverlay, isEscape, isEnter, isCtrlC, isClose, isNavigateUp, isNavigateDown, isD, renderBorder, } from './base/index.js';
15
+ import { InputFeature } from './features/index.js';
16
+ import { getAllProviderStatuses, setApiKey, deleteApiKey, } from '../utils/credentials.js';
17
+ // =============================================================================
18
+ // Screens
19
+ // =============================================================================
20
+ /**
21
+ * List screen - shows all providers with their key status
22
+ */
23
+ class ListScreen extends BaseScreen {
24
+ state;
25
+ getStyles;
26
+ getWidth;
27
+ constructor(state, getStyles, getWidth) {
28
+ super();
29
+ this.state = state;
30
+ this.getStyles = getStyles;
31
+ this.getWidth = getWidth;
32
+ }
33
+ render() {
34
+ const s = this.getStyles();
35
+ const cols = this.getWidth();
36
+ const border = renderBorder(cols, s);
37
+ const lines = [];
38
+ // Header
39
+ lines.push(border);
40
+ lines.push(` ${s.primaryBold('API Keys')}`);
41
+ lines.push('');
42
+ // Provider list
43
+ for (let i = 0; i < this.state.providers.length; i++) {
44
+ const p = this.state.providers[i];
45
+ const isCursor = this.state.selectedIndex === i;
46
+ const prefix = isCursor ? s.primary(' > ') : ' ';
47
+ // Status indicator
48
+ let status;
49
+ if (p.provider === 'ollama') {
50
+ status = s.secondary('Local (no key needed)');
51
+ }
52
+ else if (p.hasKey) {
53
+ const source = p.fromEnv ? s.muted(' (env)') : '';
54
+ status = s.success(`● ${p.masked ?? '***'}`) + source;
55
+ }
56
+ else {
57
+ status = s.warning('○ Not set');
58
+ }
59
+ // Provider name
60
+ const name = isCursor ? s.primary(p.name.padEnd(18)) : s.muted(p.name.padEnd(18));
61
+ lines.push(`${prefix}${name} ${status}`);
62
+ }
63
+ // Footer
64
+ lines.push('');
65
+ lines.push(border);
66
+ lines.push(` ${s.muted('up/down/jk Navigate . Enter Edit . d Delete . q/Esc Close')}`);
67
+ lines.push(border);
68
+ return lines;
69
+ }
70
+ handleKey(data) {
71
+ // Close keys
72
+ if (isCtrlC(data) || isClose(data)) {
73
+ return closeOverlay({ changed: this.state.changed });
74
+ }
75
+ // Navigation up
76
+ if (isNavigateUp(data)) {
77
+ if (this.state.selectedIndex > 0) {
78
+ this.state.selectedIndex--;
79
+ return stay();
80
+ }
81
+ return stay(false);
82
+ }
83
+ // Navigation down
84
+ if (isNavigateDown(data)) {
85
+ if (this.state.selectedIndex < this.state.providers.length - 1) {
86
+ this.state.selectedIndex++;
87
+ return stay();
88
+ }
89
+ return stay(false);
90
+ }
91
+ // Enter - edit selected provider
92
+ if (isEnter(data)) {
93
+ const selected = this.state.providers[this.state.selectedIndex];
94
+ if (selected.provider !== 'ollama') {
95
+ return pushScreen(new InputScreen(this.state, this.getStyles, this.getWidth, selected.provider));
96
+ }
97
+ return stay(false);
98
+ }
99
+ // Delete key
100
+ if (isD(data)) {
101
+ const selected = this.state.providers[this.state.selectedIndex];
102
+ if (selected.provider !== 'ollama' && selected.hasKey && !selected.fromEnv) {
103
+ deleteApiKey(selected.provider);
104
+ this.state.providers = getAllProviderStatuses();
105
+ this.state.changed = true;
106
+ return stay();
107
+ }
108
+ return stay(false);
109
+ }
110
+ return stay(false);
111
+ }
112
+ }
113
+ /**
114
+ * Input screen - text input for entering API key
115
+ */
116
+ class InputScreen extends BaseScreen {
117
+ state;
118
+ getStyles;
119
+ getWidth;
120
+ provider;
121
+ input;
122
+ constructor(state, getStyles, getWidth, provider) {
123
+ super();
124
+ this.state = state;
125
+ this.getStyles = getStyles;
126
+ this.getWidth = getWidth;
127
+ this.provider = provider;
128
+ this.input = new InputFeature({ placeholder: 'Paste or type your API key...' });
129
+ }
130
+ onEnter() {
131
+ terminal.showCursor();
132
+ }
133
+ onExit() {
134
+ terminal.hideCursor();
135
+ }
136
+ render() {
137
+ const s = this.getStyles();
138
+ const cols = this.getWidth();
139
+ const border = renderBorder(cols, s);
140
+ const lines = [];
141
+ const providerInfo = this.state.providers.find(p => p.provider === this.provider);
142
+ // Header
143
+ lines.push(border);
144
+ lines.push(` ${s.primaryBold('API Keys')}`);
145
+ lines.push('');
146
+ // Input prompt
147
+ lines.push(` Set API key for ${s.primary(providerInfo?.name ?? this.provider)}:`);
148
+ lines.push('');
149
+ lines.push(' ' + this.input.render(s));
150
+ lines.push('');
151
+ // Help text
152
+ if (providerInfo?.keyUrl) {
153
+ lines.push(s.muted(` Get key: ${providerInfo.keyUrl}`));
154
+ lines.push('');
155
+ }
156
+ // Footer
157
+ lines.push(border);
158
+ lines.push(` ${s.muted('Enter Save . Esc Cancel')}`);
159
+ lines.push(border);
160
+ return lines;
161
+ }
162
+ handleKey(data) {
163
+ // Ctrl+C closes overlay
164
+ if (isCtrlC(data)) {
165
+ return closeOverlay({ changed: this.state.changed });
166
+ }
167
+ // Escape goes back to list
168
+ if (isEscape(data)) {
169
+ return popScreen();
170
+ }
171
+ // Enter saves the key
172
+ if (isEnter(data)) {
173
+ const value = this.input.trimmedValue;
174
+ if (value) {
175
+ setApiKey(this.provider, value);
176
+ this.state.providers = getAllProviderStatuses();
177
+ this.state.changed = true;
178
+ }
179
+ return popScreen();
180
+ }
181
+ // Let InputFeature handle the key
182
+ const result = this.input.handleKey(data);
183
+ if (result.handled) {
184
+ return stay(result.render);
185
+ }
186
+ return stay(false);
187
+ }
188
+ getMinHeight() {
189
+ return 12;
190
+ }
191
+ }
192
+ // =============================================================================
193
+ // Keys Overlay V2 Class
194
+ // =============================================================================
195
+ /**
196
+ * Keys overlay using the new Overlay interface.
197
+ * Manages API keys for LLM providers.
198
+ */
199
+ export class KeysOverlayV2 extends BaseOverlayV2 {
200
+ type = 'inline';
201
+ id = 'keys-overlay-v2';
202
+ screenStack;
203
+ constructor() {
204
+ const providers = getAllProviderStatuses();
205
+ const initialState = {
206
+ selectedIndex: 0,
207
+ changed: false,
208
+ providers,
209
+ };
210
+ super(initialState);
211
+ this.minHeight = 14;
212
+ this.screenStack = new ScreenStack();
213
+ this.screenStack.push(new ListScreen(this.state, () => this.getStyles(), () => this.termWidth));
214
+ }
215
+ renderContent(_context) {
216
+ const screen = this.screenStack.current();
217
+ return screen?.render() ?? [];
218
+ }
219
+ render(context) {
220
+ this.styles = context.styles;
221
+ this.termWidth = context.width;
222
+ const lines = this.renderContent(context);
223
+ const screen = this.screenStack.current();
224
+ const screenMinHeight = screen?.getMinHeight?.() ?? 0;
225
+ const effectiveMinHeight = Math.max(this.minHeight, screenMinHeight);
226
+ return effectiveMinHeight > 0 ? { lines, minHeight: effectiveMinHeight } : { lines };
227
+ }
228
+ handleKey(key) {
229
+ const data = key.raw;
230
+ const screen = this.screenStack.current();
231
+ if (!screen) {
232
+ return this.close({ changed: this.state.changed });
233
+ }
234
+ const result = screen.handleKey(data);
235
+ switch (result.action) {
236
+ case 'stay':
237
+ return result.render ? this.rerender() : this.noAction();
238
+ case 'push':
239
+ this.screenStack.push(result.screen);
240
+ return this.rerender();
241
+ case 'pop':
242
+ this.screenStack.pop();
243
+ return this.rerender();
244
+ case 'close':
245
+ return this.close(result.result);
246
+ }
247
+ }
248
+ }