@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,369 @@
1
+ /**
2
+ * Tabbed List Overlay Base Class
3
+ *
4
+ * A reusable base for overlays that display:
5
+ * - Tabs for filtering/categorizing
6
+ * - A paginated list of items
7
+ * - Search mode (activated with /)
8
+ * - Detail view (via ScreenStack)
9
+ *
10
+ * This provides ~80% of the common overlay functionality,
11
+ * leaving only item-specific rendering to be customized.
12
+ *
13
+ * Usage:
14
+ * ```typescript
15
+ * interface MyItem { name: string; description: string; }
16
+ *
17
+ * const TABS = [
18
+ * { id: 'all', label: 'All' },
19
+ * { id: 'active', label: 'Active' },
20
+ * ];
21
+ *
22
+ * class MyOverlay extends TabbedListOverlay<MyItem, MyResult> {
23
+ * constructor(items: MyItem[]) {
24
+ * super({
25
+ * title: 'My Items',
26
+ * tabs: TABS,
27
+ * items,
28
+ * pageSize: 12,
29
+ * filterByTab: (item, tabId) => tabId === 'all' || item.active,
30
+ * getSearchText: (item) => `${item.name} ${item.description}`,
31
+ * renderItem: (item, isSelected, styles) => {
32
+ * const prefix = isSelected ? '❯ ' : ' ';
33
+ * return prefix + item.name;
34
+ * },
35
+ * });
36
+ * }
37
+ *
38
+ * // Optional: Override to add detail view
39
+ * protected createDetailScreen(item: MyItem): BaseScreen | null {
40
+ * return new MyDetailScreen(item, this.styles);
41
+ * }
42
+ * }
43
+ * ```
44
+ */
45
+ import * as terminal from '../terminal.js';
46
+ import { BaseOverlay } from './overlay-base.js';
47
+ import { BaseScreen, ScreenStack, stay, pushScreen, closeOverlay } from './screen-stack.js';
48
+ import { TabFeature } from '../features/tab-feature.js';
49
+ import { PaginationFeature } from '../features/pagination-feature.js';
50
+ import { SearchFeature } from '../features/search-feature.js';
51
+ import { isCtrlC, isClose, isEscape, isSlash, isEnter } from './key-utils.js';
52
+ import { renderBorder } from './render-utils.js';
53
+ // =============================================================================
54
+ // List Screen (Main View)
55
+ // =============================================================================
56
+ /**
57
+ * The main list screen for TabbedListOverlay.
58
+ * Handles tabs, search, pagination, and item display.
59
+ */
60
+ class ListScreen extends BaseScreen {
61
+ config;
62
+ state;
63
+ styles;
64
+ createDetailScreen;
65
+ tabFeature;
66
+ pagination;
67
+ searchFeature;
68
+ hasBeenPushedTo = false;
69
+ constructor(config, state, styles, createDetailScreen) {
70
+ super();
71
+ this.config = config;
72
+ this.state = state;
73
+ this.styles = styles;
74
+ this.createDetailScreen = createDetailScreen;
75
+ this.tabFeature = new TabFeature(config.tabs, () => {
76
+ this.onTabChange();
77
+ });
78
+ this.pagination = new PaginationFeature({
79
+ pageSize: config.pageSize ?? 12,
80
+ });
81
+ this.searchFeature = new SearchFeature({
82
+ onSearch: () => { this.applyFilters(); },
83
+ escapeClearsSearch: false,
84
+ });
85
+ }
86
+ /**
87
+ * Called when returning from a detail screen.
88
+ * Clear screen if we came back from a full-screen view.
89
+ * (resetRenderState() will handle cursor positioning)
90
+ */
91
+ onEnter() {
92
+ if (this.hasBeenPushedTo && this.config.detailScreensFullScreen !== false) {
93
+ // Returning from a full-screen detail screen - clear screen
94
+ terminal.clearScreen();
95
+ }
96
+ }
97
+ /**
98
+ * Called when navigating to a detail screen.
99
+ */
100
+ onExit() {
101
+ this.hasBeenPushedTo = true;
102
+ }
103
+ onTabChange() {
104
+ this.state.selectedIndex = 0;
105
+ this.state.scrollOffset = 0;
106
+ this.state.searchMode = false;
107
+ this.state.searchQuery = '';
108
+ this.applyFilters();
109
+ }
110
+ applyFilters() {
111
+ const tabId = this.tabFeature.getCurrentTabId(this.state);
112
+ // Filter by tab
113
+ let filtered = this.state.items.filter((item) => this.config.filterByTab(item, tabId));
114
+ // Filter by search
115
+ if (this.state.searchQuery) {
116
+ filtered = this.searchFeature.filterItems(filtered, this.state, this.config.getSearchText);
117
+ }
118
+ this.state.filteredItems = filtered;
119
+ this.state.selectedIndex = 0;
120
+ this.state.scrollOffset = 0;
121
+ }
122
+ render() {
123
+ const s = this.styles;
124
+ const cols = terminal.getTerminalWidth();
125
+ const border = renderBorder(cols, s);
126
+ const pageSize = this.config.pageSize ?? 12;
127
+ const lines = [];
128
+ // Header
129
+ lines.push(border);
130
+ const showCount = this.config.showCount ?? true;
131
+ const countBadge = showCount
132
+ ? s.muted(` [${String(this.state.filteredItems.length)}/${String(this.state.items.length)}]`)
133
+ : '';
134
+ lines.push(` ${s.primaryBold(this.config.title)}${countBadge}`);
135
+ lines.push('');
136
+ // Tab bar with hint
137
+ const tabBar = this.tabFeature.renderTabs(this.state, s);
138
+ const tabHint = s.muted(`(${this.tabFeature.renderHints()})`);
139
+ lines.push(` ${tabBar} ${tabHint}`);
140
+ lines.push('');
141
+ // Search box (if in search mode)
142
+ if (this.state.searchMode) {
143
+ const query = this.state.searchQuery;
144
+ lines.push(` ${s.muted('Search:')} ${query ? s.primary(query) : ''}█`);
145
+ lines.push('');
146
+ }
147
+ // Items
148
+ const visibleItems = this.pagination.getVisibleItems(this.state, this.state.filteredItems);
149
+ if (visibleItems.length === 0) {
150
+ const msg = this.state.searchQuery
151
+ ? (this.config.noResultsMessage ?? 'No items match the search.')
152
+ : (this.config.emptyMessage ?? 'No items available.');
153
+ lines.push(` ${s.muted(msg)}`);
154
+ for (let i = 0; i < pageSize - 1; i++) {
155
+ lines.push('');
156
+ }
157
+ }
158
+ else {
159
+ for (let i = 0; i < visibleItems.length; i++) {
160
+ const item = visibleItems[i];
161
+ const absoluteIndex = this.state.scrollOffset + i;
162
+ const isSelected = absoluteIndex === this.state.selectedIndex;
163
+ lines.push(this.config.renderItem(item, isSelected, s));
164
+ }
165
+ // Pad to fixed height
166
+ for (let i = visibleItems.length; i < pageSize; i++) {
167
+ lines.push('');
168
+ }
169
+ }
170
+ // Pagination indicator
171
+ lines.push('');
172
+ const indicator = this.pagination.renderIndicator(this.state, this.state.filteredItems.length, s);
173
+ if (indicator) {
174
+ lines.push(indicator);
175
+ }
176
+ // Selected item preview (if configured)
177
+ if (this.config.renderSelectedPreview && visibleItems.length > 0) {
178
+ const selectedItem = this.state.filteredItems[this.state.selectedIndex];
179
+ if (selectedItem) {
180
+ lines.push('');
181
+ const previewLines = this.config.renderSelectedPreview(selectedItem, s);
182
+ lines.push(...previewLines);
183
+ }
184
+ }
185
+ // Footer
186
+ lines.push(border);
187
+ lines.push(` ${s.muted(this.getFooterHints())}`);
188
+ lines.push(border);
189
+ return lines;
190
+ }
191
+ getFooterHints() {
192
+ // Use custom footer hints if provided
193
+ if (this.config.footerHints) {
194
+ return this.config.footerHints(this.state.searchMode);
195
+ }
196
+ // Default footer hints
197
+ if (this.state.searchMode) {
198
+ return 'Type to filter · ↑↓/jk Navigate · Enter Details · Esc Exit search';
199
+ }
200
+ return this.pagination.renderHints() + ' · / Search · Enter Details · q/Esc Close';
201
+ }
202
+ handleKey(data) {
203
+ // Ctrl+C always closes
204
+ if (isCtrlC(data)) {
205
+ return closeOverlay(undefined);
206
+ }
207
+ // Search mode handling
208
+ if (this.state.searchMode) {
209
+ if (isEscape(data)) {
210
+ this.state.searchMode = false;
211
+ if (this.state.searchQuery) {
212
+ this.state.searchQuery = '';
213
+ this.applyFilters();
214
+ }
215
+ return stay();
216
+ }
217
+ const searchResult = this.searchFeature.handleKey(data, this.state);
218
+ if (searchResult?.handled) {
219
+ return searchResult.action === 'render' ? stay() : stay(false);
220
+ }
221
+ if (isEnter(data)) {
222
+ return this.handleEnter();
223
+ }
224
+ const paginationResult = this.pagination.handleKey(data, this.state, this.state.filteredItems.length);
225
+ if (paginationResult?.handled) {
226
+ return paginationResult.action === 'render' ? stay() : stay(false);
227
+ }
228
+ return stay(false);
229
+ }
230
+ // Not in search mode
231
+ if (isSlash(data)) {
232
+ this.state.searchMode = true;
233
+ return stay();
234
+ }
235
+ if (isClose(data)) {
236
+ return closeOverlay(undefined);
237
+ }
238
+ // Tab navigation
239
+ const tabResult = this.tabFeature.handleKey(data, this.state);
240
+ if (tabResult?.handled) {
241
+ return tabResult.action === 'render' ? stay() : stay(false);
242
+ }
243
+ // Enter shows detail
244
+ if (isEnter(data)) {
245
+ return this.handleEnter();
246
+ }
247
+ // Pagination
248
+ const paginationResult = this.pagination.handleKey(data, this.state, this.state.filteredItems.length);
249
+ if (paginationResult?.handled) {
250
+ return paginationResult.action === 'render' ? stay() : stay(false);
251
+ }
252
+ return stay(false);
253
+ }
254
+ handleEnter() {
255
+ if (this.state.filteredItems.length === 0) {
256
+ return stay(false);
257
+ }
258
+ const item = this.state.filteredItems[this.state.selectedIndex];
259
+ const detailScreen = this.createDetailScreen(item);
260
+ if (detailScreen) {
261
+ return pushScreen(detailScreen);
262
+ }
263
+ return stay(false);
264
+ }
265
+ }
266
+ // =============================================================================
267
+ // TabbedListOverlay Base Class
268
+ // =============================================================================
269
+ /**
270
+ * Abstract base class for tabbed list overlays.
271
+ *
272
+ * Provides:
273
+ * - Tab-based filtering
274
+ * - Search mode with / toggle
275
+ * - Paginated item display
276
+ * - ScreenStack for detail views
277
+ *
278
+ * Subclasses can override createDetailScreen() to add detail views.
279
+ */
280
+ export class TabbedListOverlay extends BaseOverlay {
281
+ screenStack;
282
+ listConfig;
283
+ resizeHandler = null;
284
+ constructor(config) {
285
+ const initialState = {
286
+ lineCount: 0,
287
+ maxLineCount: 0,
288
+ currentTab: 0,
289
+ selectedIndex: 0,
290
+ scrollOffset: 0,
291
+ searchQuery: '',
292
+ searchMode: false,
293
+ items: config.items,
294
+ filteredItems: config.items.filter((item) => config.filterByTab(item, config.tabs[0]?.id ?? 'all')),
295
+ };
296
+ super(initialState);
297
+ this.listConfig = config;
298
+ this.screenStack = new ScreenStack();
299
+ this.screenStack.push(new ListScreen(config, this.state, this.styles, (item) => this.createDetailScreen(item)));
300
+ }
301
+ /**
302
+ * Override to create a detail screen for an item.
303
+ * Return null to disable detail view.
304
+ */
305
+ createDetailScreen(_item) {
306
+ return null;
307
+ }
308
+ async show() {
309
+ // Add resize handler
310
+ this.resizeHandler = () => {
311
+ this.update();
312
+ };
313
+ process.stdout.on('resize', this.resizeHandler);
314
+ return super.show();
315
+ }
316
+ close(result) {
317
+ if (this.resizeHandler) {
318
+ process.stdout.removeListener('resize', this.resizeHandler);
319
+ this.resizeHandler = null;
320
+ }
321
+ super.close(result);
322
+ }
323
+ render() {
324
+ const screen = this.screenStack.current();
325
+ return screen?.render() ?? [];
326
+ }
327
+ handleKey(data) {
328
+ const screen = this.screenStack.current();
329
+ if (!screen) {
330
+ this.close(undefined);
331
+ return;
332
+ }
333
+ const result = screen.handleKey(data);
334
+ switch (result.action) {
335
+ case 'stay':
336
+ if (result.render) {
337
+ this.update();
338
+ }
339
+ break;
340
+ case 'push':
341
+ this.screenStack.push(result.screen);
342
+ // Reset overlay state after screen change (screen's onEnter may have cleared screen)
343
+ // Skip for in-place rendering (detailScreensFullScreen: false)
344
+ if (this.listConfig.detailScreensFullScreen !== false) {
345
+ this.resetRenderState();
346
+ }
347
+ this.update();
348
+ break;
349
+ case 'pop':
350
+ this.screenStack.pop();
351
+ // Reset overlay state after screen change (screen's onEnter may have cleared screen)
352
+ // Skip for in-place rendering (detailScreensFullScreen: false)
353
+ if (this.listConfig.detailScreensFullScreen !== false) {
354
+ this.resetRenderState();
355
+ }
356
+ this.update();
357
+ break;
358
+ case 'close':
359
+ this.close(result.result);
360
+ break;
361
+ }
362
+ }
363
+ /**
364
+ * Get the currently selected item.
365
+ */
366
+ getSelectedItem() {
367
+ return this.state.filteredItems[this.state.selectedIndex];
368
+ }
369
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Commands Overlay V2
3
+ *
4
+ * Modal overlay for viewing and managing custom command definitions.
5
+ * Uses TabbedListOverlayV2 for consistent navigation patterns.
6
+ *
7
+ * Features:
8
+ * - Tabs: All, Project, Personal
9
+ * - Search with / toggle
10
+ * - Detail view for command information
11
+ * - Wizard for creating new commands
12
+ */
13
+ import { type CustomCommand } from '../commands/index.js';
14
+ import { TabbedListOverlayV2, BaseScreen } from './base/index.js';
15
+ export interface CommandsOverlayV2Result {
16
+ /** Command that was created (if any) */
17
+ created?: string;
18
+ }
19
+ type CommandItem = CustomCommand | {
20
+ type: 'create';
21
+ };
22
+ /**
23
+ * Commands overlay using TabbedListOverlayV2.
24
+ * Displays custom commands in a searchable, tabbed list.
25
+ */
26
+ export declare class CommandsOverlayV2 extends TabbedListOverlayV2<CommandItem, CommandsOverlayV2Result> {
27
+ readonly type: "inline";
28
+ readonly id = "commands-overlay-v2";
29
+ private readonly registry;
30
+ constructor();
31
+ protected createDetailScreen(item: CommandItem): BaseScreen | null;
32
+ }
33
+ export {};