@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,154 @@
1
+ /**
2
+ * Pagination Feature
3
+ *
4
+ * Composable feature for paginated list navigation.
5
+ * Handles page up/down, scroll offset tracking, and visibility.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * interface MyState extends OverlayState, PaginationState {
10
+ * items: string[];
11
+ * }
12
+ *
13
+ * class MyScreen extends BaseScreen {
14
+ * private pagination = new PaginationFeature({ pageSize: 12 });
15
+ *
16
+ * handleKey(data: Buffer): ScreenResult {
17
+ * const result = this.pagination.handleKey(data, this.state, this.state.items.length);
18
+ * if (result?.handled) {
19
+ * return result.action === 'render' ? stay() : stay(false);
20
+ * }
21
+ * // ... other key handling
22
+ * }
23
+ *
24
+ * render(): string[] {
25
+ * const visible = this.pagination.getVisibleItems(this.state, this.state.items);
26
+ * // render visible items...
27
+ * return [
28
+ * ...itemLines,
29
+ * this.pagination.renderIndicator(this.state, this.state.items.length, styles)
30
+ * ];
31
+ * }
32
+ * }
33
+ * ```
34
+ */
35
+ /**
36
+ * State interface for pagination.
37
+ * Overlay state should extend this.
38
+ */
39
+ export interface PaginationState {
40
+ /** Currently selected index (0-based) */
41
+ selectedIndex: number;
42
+ /** First visible item index */
43
+ scrollOffset: number;
44
+ }
45
+ /**
46
+ * Configuration for PaginationFeature.
47
+ */
48
+ export interface PaginationConfig {
49
+ /** Number of items visible per page */
50
+ pageSize: number;
51
+ /**
52
+ * Whether left/right arrows trigger page navigation.
53
+ * Default: true
54
+ */
55
+ useArrowsForPaging?: boolean;
56
+ }
57
+ /**
58
+ * Result from handling a key.
59
+ */
60
+ export interface PaginationKeyResult {
61
+ /** Whether the key was handled */
62
+ handled: boolean;
63
+ /** Action to take */
64
+ action?: 'render' | 'none';
65
+ }
66
+ /**
67
+ * Feature for paginated list navigation.
68
+ *
69
+ * Handles:
70
+ * - Up/Down arrows and j/k for item navigation
71
+ * - Left/Right arrows and h/l for page navigation
72
+ * - Page Up/Page Down for page navigation
73
+ * - Scroll offset tracking
74
+ * - Visibility management (ensure selected item is visible)
75
+ */
76
+ export declare class PaginationFeature {
77
+ private readonly pageSize;
78
+ private readonly useArrowsForPaging;
79
+ constructor(config: PaginationConfig);
80
+ /**
81
+ * Handle a key press.
82
+ *
83
+ * @param data - Raw key buffer
84
+ * @param state - State containing selectedIndex and scrollOffset
85
+ * @param totalItems - Total number of items in the list
86
+ * @returns Result if handled, null otherwise
87
+ */
88
+ handleKey(data: Buffer, state: PaginationState, totalItems: number): PaginationKeyResult | null;
89
+ /**
90
+ * Ensure the selected item is visible by adjusting scrollOffset.
91
+ *
92
+ * @param state - State to adjust
93
+ * @param totalItems - Total number of items
94
+ */
95
+ ensureVisible(state: PaginationState, totalItems: number): void;
96
+ /**
97
+ * Get the visible slice of items.
98
+ *
99
+ * @param state - State containing scrollOffset
100
+ * @param items - All items
101
+ * @returns Visible items
102
+ */
103
+ getVisibleItems<T>(state: PaginationState, items: T[]): T[];
104
+ /**
105
+ * Get the visible range info.
106
+ *
107
+ * @param state - State containing scrollOffset
108
+ * @param totalItems - Total number of items
109
+ * @returns Object with start, end, total, canScrollUp, canScrollDown
110
+ */
111
+ getVisibleRange(state: PaginationState, totalItems: number): {
112
+ start: number;
113
+ end: number;
114
+ total: number;
115
+ canScrollUp: boolean;
116
+ canScrollDown: boolean;
117
+ };
118
+ /**
119
+ * Render a scroll indicator line.
120
+ *
121
+ * @param state - State containing scrollOffset
122
+ * @param totalItems - Total number of items
123
+ * @param styles - Theme styles with muted() function
124
+ * @returns Formatted indicator string (empty if no pagination needed)
125
+ */
126
+ renderIndicator(state: PaginationState, totalItems: number, styles: {
127
+ muted: (s: string) => string;
128
+ }): string;
129
+ /**
130
+ * Render navigation hints for the footer.
131
+ *
132
+ * @param includeArrows - Whether to include ←→/hl hints
133
+ * @returns Hint string
134
+ */
135
+ renderHints(includeArrows?: boolean): string;
136
+ /**
137
+ * Get the page size.
138
+ */
139
+ getPageSize(): number;
140
+ /**
141
+ * Reset pagination state to beginning.
142
+ *
143
+ * @param state - State to reset
144
+ */
145
+ reset(state: PaginationState): void;
146
+ /**
147
+ * Jump to a specific index and ensure it's visible.
148
+ *
149
+ * @param state - State to update
150
+ * @param index - Target index
151
+ * @param totalItems - Total number of items
152
+ */
153
+ jumpTo(state: PaginationState, index: number, totalItems: number): void;
154
+ }
@@ -0,0 +1,238 @@
1
+ /**
2
+ * Pagination Feature
3
+ *
4
+ * Composable feature for paginated list navigation.
5
+ * Handles page up/down, scroll offset tracking, and visibility.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * interface MyState extends OverlayState, PaginationState {
10
+ * items: string[];
11
+ * }
12
+ *
13
+ * class MyScreen extends BaseScreen {
14
+ * private pagination = new PaginationFeature({ pageSize: 12 });
15
+ *
16
+ * handleKey(data: Buffer): ScreenResult {
17
+ * const result = this.pagination.handleKey(data, this.state, this.state.items.length);
18
+ * if (result?.handled) {
19
+ * return result.action === 'render' ? stay() : stay(false);
20
+ * }
21
+ * // ... other key handling
22
+ * }
23
+ *
24
+ * render(): string[] {
25
+ * const visible = this.pagination.getVisibleItems(this.state, this.state.items);
26
+ * // render visible items...
27
+ * return [
28
+ * ...itemLines,
29
+ * this.pagination.renderIndicator(this.state, this.state.items.length, styles)
30
+ * ];
31
+ * }
32
+ * }
33
+ * ```
34
+ */
35
+ import { isNavigateUp, isNavigateDown, isNavigateLeft, isNavigateRight, isPageUp, isPageDown, } from '../base/key-utils.js';
36
+ // =============================================================================
37
+ // PaginationFeature Class
38
+ // =============================================================================
39
+ /**
40
+ * Feature for paginated list navigation.
41
+ *
42
+ * Handles:
43
+ * - Up/Down arrows and j/k for item navigation
44
+ * - Left/Right arrows and h/l for page navigation
45
+ * - Page Up/Page Down for page navigation
46
+ * - Scroll offset tracking
47
+ * - Visibility management (ensure selected item is visible)
48
+ */
49
+ export class PaginationFeature {
50
+ pageSize;
51
+ useArrowsForPaging;
52
+ constructor(config) {
53
+ this.pageSize = config.pageSize;
54
+ this.useArrowsForPaging = config.useArrowsForPaging ?? true;
55
+ }
56
+ // ===========================================================================
57
+ // Key Handling
58
+ // ===========================================================================
59
+ /**
60
+ * Handle a key press.
61
+ *
62
+ * @param data - Raw key buffer
63
+ * @param state - State containing selectedIndex and scrollOffset
64
+ * @param totalItems - Total number of items in the list
65
+ * @returns Result if handled, null otherwise
66
+ */
67
+ handleKey(data, state, totalItems) {
68
+ if (totalItems === 0) {
69
+ return null;
70
+ }
71
+ // Navigate up (single item)
72
+ if (isNavigateUp(data)) {
73
+ if (state.selectedIndex > 0) {
74
+ state.selectedIndex--;
75
+ this.ensureVisible(state, totalItems);
76
+ return { handled: true, action: 'render' };
77
+ }
78
+ return { handled: true, action: 'none' };
79
+ }
80
+ // Navigate down (single item)
81
+ if (isNavigateDown(data)) {
82
+ if (state.selectedIndex < totalItems - 1) {
83
+ state.selectedIndex++;
84
+ this.ensureVisible(state, totalItems);
85
+ return { handled: true, action: 'render' };
86
+ }
87
+ return { handled: true, action: 'none' };
88
+ }
89
+ // Page up (PgUp or ←/h if enabled)
90
+ const isPageUpKey = isPageUp(data) || (this.useArrowsForPaging && isNavigateLeft(data));
91
+ if (isPageUpKey) {
92
+ const newIndex = Math.max(0, state.selectedIndex - this.pageSize);
93
+ if (newIndex !== state.selectedIndex) {
94
+ state.selectedIndex = newIndex;
95
+ this.ensureVisible(state, totalItems);
96
+ return { handled: true, action: 'render' };
97
+ }
98
+ return { handled: true, action: 'none' };
99
+ }
100
+ // Page down (PgDn or →/l if enabled)
101
+ const isPageDownKey = isPageDown(data) || (this.useArrowsForPaging && isNavigateRight(data));
102
+ if (isPageDownKey) {
103
+ const newIndex = Math.min(totalItems - 1, state.selectedIndex + this.pageSize);
104
+ if (newIndex !== state.selectedIndex) {
105
+ state.selectedIndex = newIndex;
106
+ this.ensureVisible(state, totalItems);
107
+ return { handled: true, action: 'render' };
108
+ }
109
+ return { handled: true, action: 'none' };
110
+ }
111
+ return null;
112
+ }
113
+ // ===========================================================================
114
+ // Visibility Management
115
+ // ===========================================================================
116
+ /**
117
+ * Ensure the selected item is visible by adjusting scrollOffset.
118
+ *
119
+ * @param state - State to adjust
120
+ * @param totalItems - Total number of items
121
+ */
122
+ ensureVisible(state, totalItems) {
123
+ // Clamp selectedIndex first
124
+ if (state.selectedIndex < 0) {
125
+ state.selectedIndex = 0;
126
+ }
127
+ else if (state.selectedIndex >= totalItems) {
128
+ state.selectedIndex = Math.max(0, totalItems - 1);
129
+ }
130
+ // Adjust scrollOffset to keep selection visible
131
+ if (state.selectedIndex < state.scrollOffset) {
132
+ state.scrollOffset = state.selectedIndex;
133
+ }
134
+ else if (state.selectedIndex >= state.scrollOffset + this.pageSize) {
135
+ state.scrollOffset = state.selectedIndex - this.pageSize + 1;
136
+ }
137
+ // Clamp scrollOffset
138
+ const maxOffset = Math.max(0, totalItems - this.pageSize);
139
+ if (state.scrollOffset > maxOffset) {
140
+ state.scrollOffset = maxOffset;
141
+ }
142
+ if (state.scrollOffset < 0) {
143
+ state.scrollOffset = 0;
144
+ }
145
+ }
146
+ // ===========================================================================
147
+ // Item Access
148
+ // ===========================================================================
149
+ /**
150
+ * Get the visible slice of items.
151
+ *
152
+ * @param state - State containing scrollOffset
153
+ * @param items - All items
154
+ * @returns Visible items
155
+ */
156
+ getVisibleItems(state, items) {
157
+ return items.slice(state.scrollOffset, state.scrollOffset + this.pageSize);
158
+ }
159
+ /**
160
+ * Get the visible range info.
161
+ *
162
+ * @param state - State containing scrollOffset
163
+ * @param totalItems - Total number of items
164
+ * @returns Object with start, end, total, canScrollUp, canScrollDown
165
+ */
166
+ getVisibleRange(state, totalItems) {
167
+ const start = state.scrollOffset + 1; // 1-based for display
168
+ const end = Math.min(state.scrollOffset + this.pageSize, totalItems);
169
+ return {
170
+ start,
171
+ end,
172
+ total: totalItems,
173
+ canScrollUp: state.scrollOffset > 0,
174
+ canScrollDown: state.scrollOffset + this.pageSize < totalItems,
175
+ };
176
+ }
177
+ // ===========================================================================
178
+ // Rendering Helpers
179
+ // ===========================================================================
180
+ /**
181
+ * Render a scroll indicator line.
182
+ *
183
+ * @param state - State containing scrollOffset
184
+ * @param totalItems - Total number of items
185
+ * @param styles - Theme styles with muted() function
186
+ * @returns Formatted indicator string (empty if no pagination needed)
187
+ */
188
+ renderIndicator(state, totalItems, styles) {
189
+ if (totalItems <= this.pageSize) {
190
+ return ''; // No pagination needed
191
+ }
192
+ const range = this.getVisibleRange(state, totalItems);
193
+ const info = `${String(range.start)}-${String(range.end)} of ${String(range.total)}`;
194
+ const arrows = (range.canScrollUp ? '↑' : ' ') + (range.canScrollDown ? '↓' : ' ');
195
+ return ` ${styles.muted(info)} ${styles.muted(arrows)}`;
196
+ }
197
+ /**
198
+ * Render navigation hints for the footer.
199
+ *
200
+ * @param includeArrows - Whether to include ←→/hl hints
201
+ * @returns Hint string
202
+ */
203
+ renderHints(includeArrows = true) {
204
+ if (includeArrows) {
205
+ return '↑↓/jk Navigate · ←→/hl Page';
206
+ }
207
+ return '↑↓/jk Navigate · PgUp/PgDn Page';
208
+ }
209
+ // ===========================================================================
210
+ // Utilities
211
+ // ===========================================================================
212
+ /**
213
+ * Get the page size.
214
+ */
215
+ getPageSize() {
216
+ return this.pageSize;
217
+ }
218
+ /**
219
+ * Reset pagination state to beginning.
220
+ *
221
+ * @param state - State to reset
222
+ */
223
+ reset(state) {
224
+ state.selectedIndex = 0;
225
+ state.scrollOffset = 0;
226
+ }
227
+ /**
228
+ * Jump to a specific index and ensure it's visible.
229
+ *
230
+ * @param state - State to update
231
+ * @param index - Target index
232
+ * @param totalItems - Total number of items
233
+ */
234
+ jumpTo(state, index, totalItems) {
235
+ state.selectedIndex = Math.max(0, Math.min(index, totalItems - 1));
236
+ this.ensureVisible(state, totalItems);
237
+ }
238
+ }
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Search Feature
3
+ *
4
+ * Composable feature for search/filter text input in overlays.
5
+ * Handles typing, backspace, and escape to clear.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * interface MyState extends OverlayState, SearchState {
10
+ * items: string[];
11
+ * }
12
+ *
13
+ * class MyScreen extends BaseScreen {
14
+ * private search = new SearchFeature({
15
+ * onSearch: (query) => this.filterItems(query),
16
+ * });
17
+ *
18
+ * handleKey(data: Buffer): ScreenResult {
19
+ * const result = this.search.handleKey(data, this.state);
20
+ * if (result?.handled) {
21
+ * return result.action === 'render' ? stay() : stay(false);
22
+ * }
23
+ * // ... other key handling
24
+ * }
25
+ *
26
+ * render(): string[] {
27
+ * return [
28
+ * this.search.renderSearchBox(this.state, styles, { label: 'Search' }),
29
+ * ...filteredItemLines,
30
+ * ];
31
+ * }
32
+ * }
33
+ * ```
34
+ */
35
+ /**
36
+ * State interface for search.
37
+ * Overlay state should extend this.
38
+ */
39
+ export interface SearchState {
40
+ /** Current search query */
41
+ searchQuery: string;
42
+ }
43
+ /**
44
+ * Configuration for SearchFeature.
45
+ */
46
+ export interface SearchConfig {
47
+ /**
48
+ * Callback when search query changes.
49
+ * Use this to trigger filtering/re-rendering.
50
+ */
51
+ onSearch?: (query: string) => void;
52
+ /**
53
+ * Whether Escape clears the search (default: true).
54
+ * If false, Escape is not handled by this feature.
55
+ */
56
+ escapeClearsSearch?: boolean;
57
+ /**
58
+ * Placeholder text when search is empty.
59
+ */
60
+ placeholder?: string;
61
+ }
62
+ /**
63
+ * Result from handling a key.
64
+ */
65
+ export interface SearchKeyResult {
66
+ /** Whether the key was handled */
67
+ handled: boolean;
68
+ /** Action to take */
69
+ action?: 'render' | 'none';
70
+ /** Whether the search was cleared (Escape pressed) */
71
+ cleared?: boolean;
72
+ }
73
+ /**
74
+ * Options for rendering the search box.
75
+ */
76
+ export interface SearchBoxOptions {
77
+ /** Label before the search box (default: 'Search') */
78
+ label?: string;
79
+ /** Whether to show cursor (default: true) */
80
+ showCursor?: boolean;
81
+ /** Prefix before the input (default: ' ') */
82
+ prefix?: string;
83
+ }
84
+ /**
85
+ * Feature for search/filter text input.
86
+ *
87
+ * Handles:
88
+ * - Printable character input
89
+ * - Backspace to delete
90
+ * - Escape to clear (optional)
91
+ */
92
+ export declare class SearchFeature {
93
+ private readonly config;
94
+ constructor(config?: SearchConfig);
95
+ /**
96
+ * Handle a key press.
97
+ *
98
+ * @param data - Raw key buffer
99
+ * @param state - State containing searchQuery
100
+ * @returns Result if handled, null otherwise
101
+ */
102
+ handleKey(data: Buffer, state: SearchState): SearchKeyResult | null;
103
+ /**
104
+ * Render a search box with optional cursor.
105
+ *
106
+ * @param state - State containing searchQuery
107
+ * @param styles - Theme styles
108
+ * @param options - Rendering options
109
+ * @returns Formatted search box string
110
+ */
111
+ renderSearchBox(state: SearchState, styles: {
112
+ muted: (s: string) => string;
113
+ primary?: (s: string) => string;
114
+ }, options?: SearchBoxOptions): string;
115
+ /**
116
+ * Render search hints for the footer.
117
+ *
118
+ * @param hasQuery - Whether there's an active search query
119
+ * @returns Hint string
120
+ */
121
+ renderHints(hasQuery?: boolean): string;
122
+ /**
123
+ * Check if there's an active search query.
124
+ */
125
+ hasQuery(state: SearchState): boolean;
126
+ /**
127
+ * Get the current search query.
128
+ */
129
+ getQuery(state: SearchState): string;
130
+ /**
131
+ * Clear the search query.
132
+ */
133
+ clear(state: SearchState): void;
134
+ /**
135
+ * Set the search query programmatically.
136
+ */
137
+ setQuery(state: SearchState, query: string): void;
138
+ /**
139
+ * Filter items based on search query.
140
+ * Generic helper that works with any item type.
141
+ *
142
+ * @param items - Items to filter
143
+ * @param state - State containing searchQuery
144
+ * @param getSearchableText - Function to extract searchable text from item
145
+ * @returns Filtered items
146
+ */
147
+ filterItems<T>(items: T[], state: SearchState, getSearchableText: (item: T) => string): T[];
148
+ }