@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
@@ -2,13 +2,13 @@
2
2
  * Permission Overlay
3
3
  *
4
4
  * Modal overlay for tool permission requests.
5
- * Uses the same pattern as ask-user-simple-overlay for consistent behavior.
5
+ * Renders inline above the footer using InlineOverlay base class.
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
- // Helpers
11
+ // Helpers (unchanged from original)
12
12
  // =============================================================================
13
13
  /**
14
14
  * Format a value for display, handling nested structures
@@ -16,7 +16,6 @@ import { getStyles } from '../themes/index.js';
16
16
  */
17
17
  function formatValue(value, maxLen) {
18
18
  if (typeof value === 'string') {
19
- // Replace all newlines with ↵ to prevent multi-line rendering
20
19
  const singleLine = value.replace(/\r?\n|\r/g, '↵');
21
20
  return singleLine.length > maxLen ? singleLine.slice(0, maxLen) + '...' : singleLine;
22
21
  }
@@ -26,18 +25,19 @@ function formatValue(value, maxLen) {
26
25
  if (Array.isArray(value)) {
27
26
  if (value.length === 0)
28
27
  return '[]';
29
- // Show array contents briefly
30
28
  const items = value.slice(0, 3).map((item) => {
31
29
  if (typeof item === 'object' && item !== null) {
32
- // For objects in array, show key highlights
33
30
  const obj = item;
34
31
  const keys = Object.keys(obj);
35
32
  if (keys.length === 0)
36
33
  return '{}';
37
- const preview = keys.slice(0, 2).map(k => {
34
+ const preview = keys
35
+ .slice(0, 2)
36
+ .map((k) => {
38
37
  const v = obj[k];
39
38
  return `${k}: ${formatValue(v, 20)}`;
40
- }).join(', ');
39
+ })
40
+ .join(', ');
41
41
  return `{${preview}${keys.length > 2 ? ', ...' : ''}}`;
42
42
  }
43
43
  return formatValue(item, 20);
@@ -51,21 +51,20 @@ function formatValue(value, maxLen) {
51
51
  const keys = Object.keys(obj);
52
52
  if (keys.length === 0)
53
53
  return '{}';
54
- const preview = keys.slice(0, 3).map(k => `${k}: ${formatValue(obj[k], 15)}`).join(', ');
54
+ const preview = keys
55
+ .slice(0, 3)
56
+ .map((k) => `${k}: ${formatValue(obj[k], 15)}`)
57
+ .join(', ');
55
58
  return keys.length > 3 ? `{${preview}, ...}` : `{${preview}}`;
56
59
  }
57
60
  return String(value);
58
61
  }
59
62
  /**
60
63
  * Format tool args for display.
61
- * - For bash commands: show the command prominently
62
- * - For file operations: show the path
63
- * - For backlog operations: show action and details clearly
64
- * - Strip JSON syntax for readability
65
64
  */
66
65
  function formatArgs(toolName, args, maxWidth) {
67
66
  const lines = [];
68
- // Special handling for bash commands - show full command
67
+ // Special handling for bash commands
69
68
  if (toolName === 'bash' && typeof args.command === 'string') {
70
69
  const cmd = args.command;
71
70
  const prefix = 'Command: ';
@@ -76,51 +75,13 @@ function formatArgs(toolName, args, maxWidth) {
76
75
  else {
77
76
  lines.push(prefix);
78
77
  const maxCmdLength = availableWidth * 3;
79
- const truncatedCmd = cmd.length > maxCmdLength
80
- ? cmd.slice(0, maxCmdLength) + '...'
81
- : cmd;
78
+ const truncatedCmd = cmd.length > maxCmdLength ? cmd.slice(0, maxCmdLength) + '...' : cmd;
82
79
  lines.push(' ' + truncatedCmd);
83
80
  }
84
81
  return lines;
85
82
  }
86
- // Special handling for backlog_write - show action details clearly
87
- if (toolName === 'backlog_write') {
88
- const action = args.action;
89
- if (action) {
90
- lines.push(`Action: ${action}`);
91
- }
92
- // For updates, show what's being changed
93
- if (action === 'update' && args.id) {
94
- lines.push(`Item: ${typeof args.id === 'string' ? args.id : JSON.stringify(args.id)}`);
95
- if (args.updates && typeof args.updates === 'object') {
96
- const updates = args.updates;
97
- const changes = Object.entries(updates)
98
- .map(([k, v]) => `${k} → ${formatValue(v, 25)}`)
99
- .join(', ');
100
- const maxChangesWidth = maxWidth - 14;
101
- lines.push(`Changes: ${changes.length > maxChangesWidth ? changes.slice(0, maxChangesWidth - 3) + '...' : changes}`);
102
- }
103
- }
104
- // For add, show what's being added
105
- if (action === 'add' && args.item && typeof args.item === 'object') {
106
- const item = args.item;
107
- if (item.id)
108
- lines.push(`ID: ${typeof item.id === 'string' ? item.id : JSON.stringify(item.id)}`);
109
- if (item.title) {
110
- const maxTitleLen = maxWidth - 12;
111
- const titleStr = formatValue(item.title, maxTitleLen);
112
- lines.push(`Title: ${titleStr}`);
113
- }
114
- if (item.type)
115
- lines.push(`Type: ${typeof item.type === 'string' ? item.type : JSON.stringify(item.type)}`);
116
- }
117
- // For delete, show what's being removed
118
- if (action === 'delete' && args.id) {
119
- lines.push(`Deleting: ${typeof args.id === 'string' ? args.id : JSON.stringify(args.id)}`);
120
- }
121
- return lines;
122
- }
123
- // Special handling for edit tool - show what's being changed
83
+ // Note: backlog_write special handling removed - tool deprecated in favor of workitem_* tools
84
+ // Special handling for edit tool
124
85
  if (toolName === 'edit') {
125
86
  const path = args.path ?? args.file_path ?? args.filePath;
126
87
  if (typeof path === 'string') {
@@ -131,24 +92,23 @@ function formatArgs(toolName, args, maxWidth) {
131
92
  const oldText = args.old_text ?? args.oldText ?? args.old_string ?? args.oldString;
132
93
  const newText = args.new_text ?? args.newText ?? args.new_string ?? args.newString;
133
94
  if (typeof oldText === 'string' && typeof newText === 'string') {
134
- const maxPreview = maxWidth - 8; // "- " or "+ " plus buffer
95
+ const maxPreview = maxWidth - 8;
135
96
  lines.push(`- ${formatValue(oldText, maxPreview)}`);
136
97
  lines.push(`+ ${formatValue(newText, maxPreview)}`);
137
98
  }
138
99
  return lines;
139
100
  }
140
- // Special handling for write_file - show path and content preview
101
+ // Special handling for write_file
141
102
  if (toolName === 'write_file') {
142
103
  const path = args.path ?? args.file_path ?? args.filePath;
143
104
  if (typeof path === 'string') {
144
- const maxPathLen = maxWidth - 10; // "File: " + buffer
105
+ const maxPathLen = maxWidth - 10;
145
106
  const truncPath = path.length > maxPathLen ? '...' + path.slice(-(maxPathLen - 3)) : path;
146
107
  lines.push(`File: ${truncPath}`);
147
108
  }
148
109
  const content = args.content;
149
110
  if (typeof content === 'string') {
150
- const maxContentLen = maxWidth - 15; // "Content: " + buffer
151
- // Use formatValue to handle newline replacement
111
+ const maxContentLen = maxWidth - 15;
152
112
  lines.push(`Content: ${formatValue(content, maxContentLen)}`);
153
113
  }
154
114
  return lines;
@@ -160,14 +120,13 @@ function formatArgs(toolName, args, maxWidth) {
160
120
  const truncPath = path.length > maxPathLen ? '...' + path.slice(-(maxPathLen - 3)) : path;
161
121
  lines.push('Path: ' + truncPath);
162
122
  }
163
- // Show other args in a clean format (key: value), one per line for clarity
123
+ // Show other args
164
124
  const skipKeys = ['path', 'file_path', 'filePath', 'command'];
165
125
  for (const [key, value] of Object.entries(args)) {
166
126
  if (skipKeys.includes(key))
167
127
  continue;
168
128
  const valueStr = formatValue(value, maxWidth - key.length - 6);
169
129
  const line = `${key}: ${valueStr}`;
170
- // Truncate if too long
171
130
  if (line.length > maxWidth - 4) {
172
131
  lines.push(line.slice(0, maxWidth - 7) + '...');
173
132
  }
@@ -186,16 +145,13 @@ function formatArgsForDetail(toolName, args, maxWidth) {
186
145
  lines.push('');
187
146
  for (const [key, value] of Object.entries(args)) {
188
147
  if (typeof value === 'string') {
189
- // For strings, show full content with word wrapping
190
148
  lines.push(`${key}:`);
191
- // Split by newlines first, then wrap each line
192
149
  const valueLines = value.split(/\r?\n/);
193
150
  for (const valueLine of valueLines) {
194
151
  if (valueLine.length <= maxWidth - 4) {
195
152
  lines.push(` ${valueLine}`);
196
153
  }
197
154
  else {
198
- // Word wrap long lines
199
155
  let remaining = valueLine;
200
156
  while (remaining.length > 0) {
201
157
  const chunk = remaining.slice(0, maxWidth - 4);
@@ -238,160 +194,181 @@ function formatArgsForDetail(toolName, args, maxWidth) {
238
194
  }
239
195
  return lines;
240
196
  }
241
- // Fixed height for detail view overlay (predictable rendering)
197
+ // Fixed height for detail view
242
198
  const DETAIL_VIEW_CONTENT_LINES = 15;
243
- // Note: Total = CONTENT_LINES + header(4) + footer(3) = 22 lines
244
- /**
245
- * Render the detail view as an overlay (fixed height)
246
- */
247
- function renderDetailView(options, state, contentLines, previousLineCount = 0) {
248
- const s = getStyles();
249
- const cols = terminal.getTerminalWidth();
250
- // Clear previous render
251
- if (previousLineCount > 0) {
252
- terminal.clearLinesAbove(previousLineCount);
199
+ // =============================================================================
200
+ // Permission Overlay Class
201
+ // =============================================================================
202
+ class PermissionOverlayImpl extends InlineOverlay {
203
+ options;
204
+ constructor(options) {
205
+ super();
206
+ this.options = options;
253
207
  }
254
- const lines = [];
255
- const border = s.muted('─'.repeat(Math.max(1, cols - 1)));
256
- // Header
257
- lines.push(border);
258
- lines.push(' ' + s.warning('⚠') + ' ' + chalk.bold('Permission Details') + s.muted(` (${options.toolName})`));
259
- lines.push(border);
260
- lines.push('');
261
- // Fixed visible area
262
- state.visibleLines = DETAIL_VIEW_CONTENT_LINES;
263
- state.totalLines = contentLines.length;
264
- // Show content with scroll
265
- const endLine = Math.min(state.scrollOffset + state.visibleLines, contentLines.length);
266
- for (let i = state.scrollOffset; i < endLine; i++) {
267
- const line = contentLines[i];
268
- // Truncate to prevent wrapping
269
- const safeLine = line.length > cols - 4 ? line.slice(0, cols - 7) + '...' : line;
270
- lines.push(' ' + safeLine);
208
+ getInitialState() {
209
+ return {
210
+ selectedIndex: 0, // Default to "Yes"
211
+ showingDetail: false,
212
+ detailScrollOffset: 0,
213
+ detailContentLines: [],
214
+ };
271
215
  }
272
- // Pad to fixed height
273
- const renderedLines = endLine - state.scrollOffset;
274
- for (let i = renderedLines; i < DETAIL_VIEW_CONTENT_LINES; i++) {
275
- lines.push('');
216
+ render() {
217
+ if (this.state.showingDetail) {
218
+ return this.renderDetailView();
219
+ }
220
+ return this.renderMainView();
276
221
  }
277
- // Footer with scroll indicator
278
- lines.push('');
279
- const scrollInfo = contentLines.length > state.visibleLines
280
- ? s.muted(` [${String(state.scrollOffset + 1)}-${String(endLine)}/${String(contentLines.length)}]`)
281
- : '';
282
- lines.push(border);
283
- lines.push(s.muted(' ↑↓/PgUp/PgDn Scroll · q/Esc Back') + scrollInfo);
284
- // Render all lines
285
- terminal.write(lines.join('\n'));
286
- return lines.length;
287
- }
288
- /**
289
- * Show the detail view (blocking, returns when user presses q/Esc)
290
- * Returns the line count so caller can clear it properly
291
- */
292
- async function showDetailView(options) {
293
- const cols = terminal.getTerminalWidth();
294
- const contentLines = formatArgsForDetail(options.toolName, options.args, cols - 4);
295
- const state = {
296
- scrollOffset: 0,
297
- totalLines: contentLines.length,
298
- visibleLines: DETAIL_VIEW_CONTENT_LINES,
299
- };
300
- let lineCount = 0;
301
- // Initial render (no previous lines to clear)
302
- lineCount = renderDetailView(options, state, contentLines, 0);
303
- return new Promise((resolve) => {
304
- const handleData = (data) => {
305
- const isEscape = data.length === 1 && data[0] === 0x1b;
306
- const isUpArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x41;
307
- const isDownArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x42;
308
- const isPageUp = data.length === 4 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x35 && data[3] === 0x7e;
309
- const isPageDown = data.length === 4 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x36 && data[3] === 0x7e;
310
- const key = data.toString().toLowerCase();
311
- // q or Escape = go back
312
- if (key === 'q' || isEscape) {
313
- process.stdin.removeListener('data', handleData);
314
- // Clear the detail view before returning
315
- terminal.clearLinesAbove(lineCount);
316
- resolve(lineCount);
317
- return;
318
- }
319
- // Scroll up
320
- if (isUpArrow) {
321
- state.scrollOffset = Math.max(0, state.scrollOffset - 1);
322
- }
323
- else if (isPageUp) {
324
- state.scrollOffset = Math.max(0, state.scrollOffset - state.visibleLines);
325
- }
326
- // Scroll down
327
- else if (isDownArrow) {
328
- const maxOffset = Math.max(0, state.totalLines - state.visibleLines);
329
- state.scrollOffset = Math.min(maxOffset, state.scrollOffset + 1);
222
+ renderMainView() {
223
+ const s = getStyles();
224
+ const lines = [];
225
+ const cols = this.getTerminalWidth();
226
+ const border = s.muted(''.repeat(Math.max(1, cols - 1)));
227
+ // Header
228
+ lines.push(border);
229
+ lines.push(' ' + s.warning('⚠') + ' ' + chalk.bold('Permission Required'));
230
+ lines.push('');
231
+ // Tool info
232
+ lines.push(' Tool: ' + s.primary(this.options.toolName));
233
+ // Format and display args
234
+ const maxArgWidth = cols - 6;
235
+ const argLines = formatArgs(this.options.toolName, this.options.args, maxArgWidth);
236
+ for (const argLine of argLines) {
237
+ const safeArg = argLine.length > maxArgWidth ? argLine.slice(0, maxArgWidth - 3) + '...' : argLine;
238
+ lines.push(' ' + s.muted(safeArg));
239
+ }
240
+ lines.push('');
241
+ // Options
242
+ const optionLabels = ['Yes, allow this', 'No, deny', 'Always allow this tool'];
243
+ const optionKeys = ['y', 'n', 'a'];
244
+ for (let i = 0; i < optionLabels.length; i++) {
245
+ const isCursor = this.state.selectedIndex === i;
246
+ const prefix = isCursor ? ' ' : ' ';
247
+ const key = `[${optionKeys[i]}] `;
248
+ if (isCursor) {
249
+ lines.push(s.primary(prefix + key + optionLabels[i]));
330
250
  }
331
- else if (isPageDown) {
332
- const maxOffset = Math.max(0, state.totalLines - state.visibleLines);
333
- state.scrollOffset = Math.min(maxOffset, state.scrollOffset + state.visibleLines);
251
+ else {
252
+ lines.push(s.muted(prefix + key + optionLabels[i]));
334
253
  }
335
- // Re-render with previous line count
336
- lineCount = renderDetailView(options, state, contentLines, lineCount);
337
- };
338
- process.stdin.on('data', handleData);
339
- });
340
- }
341
- // =============================================================================
342
- // Rendering
343
- // =============================================================================
344
- function render(options, state, previousLineCount = 0, targetLineCount = 0) {
345
- const s = getStyles();
346
- const lines = [];
347
- const cols = terminal.getTerminalWidth();
348
- const border = s.muted('─'.repeat(Math.max(1, cols - 1)));
349
- // Clear previous render
350
- if (previousLineCount > 0) {
351
- terminal.clearLinesAbove(previousLineCount);
254
+ }
255
+ // Footer
256
+ lines.push('');
257
+ lines.push(s.muted(' ↑↓ Navigate · Enter Select · y/n/a Quick select · ') + s.primary('d') + s.muted(' Details'));
258
+ lines.push(border);
259
+ return lines;
352
260
  }
353
- // Header
354
- lines.push(border);
355
- lines.push(' ' + s.warning('⚠') + ' ' + chalk.bold('Permission Required'));
356
- lines.push('');
357
- // Tool info
358
- lines.push(' Tool: ' + s.primary(options.toolName));
359
- // Format and display args
360
- // Use cols - 6 to account for ' ' indent and buffer for safety
361
- const maxArgWidth = cols - 6;
362
- const argLines = formatArgs(options.toolName, options.args, maxArgWidth);
363
- for (const argLine of argLines) {
364
- // Final safety truncation to prevent any line from wrapping
365
- const safeArg = argLine.length > maxArgWidth ? argLine.slice(0, maxArgWidth - 3) + '...' : argLine;
366
- lines.push(' ' + s.muted(safeArg));
261
+ renderDetailView() {
262
+ const s = getStyles();
263
+ const cols = this.getTerminalWidth();
264
+ const lines = [];
265
+ const border = s.muted('─'.repeat(Math.max(1, cols - 1)));
266
+ // Header
267
+ lines.push(border);
268
+ lines.push(' ' + s.warning('⚠') + ' ' + chalk.bold('Permission Details') + s.muted(` (${this.options.toolName})`));
269
+ lines.push(border);
270
+ lines.push('');
271
+ // Content with scroll
272
+ const contentLines = this.state.detailContentLines;
273
+ const visibleLines = DETAIL_VIEW_CONTENT_LINES;
274
+ const endLine = Math.min(this.state.detailScrollOffset + visibleLines, contentLines.length);
275
+ for (let i = this.state.detailScrollOffset; i < endLine; i++) {
276
+ const line = contentLines[i];
277
+ const safeLine = line.length > cols - 4 ? line.slice(0, cols - 7) + '...' : line;
278
+ lines.push(' ' + safeLine);
279
+ }
280
+ // Pad to fixed height
281
+ const renderedLines = endLine - this.state.detailScrollOffset;
282
+ for (let i = renderedLines; i < DETAIL_VIEW_CONTENT_LINES; i++) {
283
+ lines.push('');
284
+ }
285
+ // Footer with scroll indicator
286
+ lines.push('');
287
+ const scrollInfo = contentLines.length > visibleLines
288
+ ? s.muted(` [${String(this.state.detailScrollOffset + 1)}-${String(endLine)}/${String(contentLines.length)}]`)
289
+ : '';
290
+ lines.push(border);
291
+ lines.push(s.muted(' ↑↓/PgUp/PgDn Scroll · q/Esc Back') + scrollInfo);
292
+ return lines;
367
293
  }
368
- lines.push('');
369
- // Options
370
- const optionLabels = ['Yes, allow this', 'No, deny', 'Always allow this tool'];
371
- const optionKeys = ['y', 'n', 'a'];
372
- for (let i = 0; i < optionLabels.length; i++) {
373
- const isCursor = state.selectedIndex === i;
374
- const prefix = isCursor ? ' ❯ ' : ' ';
375
- const key = `[${optionKeys[i]}] `;
376
- if (isCursor) {
377
- lines.push(s.primary(prefix + key + optionLabels[i]));
294
+ handleKey(data) {
295
+ if (this.state.showingDetail) {
296
+ return this.handleDetailKey(data);
378
297
  }
379
- else {
380
- lines.push(s.muted(prefix + key + optionLabels[i]));
298
+ return this.handleMainKey(data);
299
+ }
300
+ handleMainKey(data) {
301
+ // Escape or Ctrl+C = deny
302
+ if (this.isEscapeKey(data) || this.isCtrlCKey(data)) {
303
+ return { type: 'close', result: 'deny' };
304
+ }
305
+ // Quick keys
306
+ const key = data.toString().toLowerCase();
307
+ if (key === 'y') {
308
+ return { type: 'close', result: 'allow' };
309
+ }
310
+ if (key === 'n') {
311
+ return { type: 'close', result: 'deny' };
312
+ }
313
+ if (key === 'a') {
314
+ return { type: 'close', result: 'allow-always' };
315
+ }
316
+ if (key === 'd') {
317
+ // Switch to detail view
318
+ const cols = this.getTerminalWidth();
319
+ this.state.showingDetail = true;
320
+ this.state.detailScrollOffset = 0;
321
+ this.state.detailContentLines = formatArgsForDetail(this.options.toolName, this.options.args, cols - 4);
322
+ return { type: 'continue' };
381
323
  }
324
+ // Arrow navigation
325
+ if (this.isUpArrowKey(data)) {
326
+ this.state.selectedIndex = Math.max(0, this.state.selectedIndex - 1);
327
+ }
328
+ else if (this.isDownArrowKey(data)) {
329
+ this.state.selectedIndex = Math.min(2, this.state.selectedIndex + 1);
330
+ }
331
+ else if (this.isEnterKey(data)) {
332
+ const results = ['allow', 'deny', 'allow-always'];
333
+ return { type: 'close', result: results[this.state.selectedIndex] };
334
+ }
335
+ return { type: 'continue' };
382
336
  }
383
- // Footer
384
- lines.push('');
385
- lines.push(s.muted(' ↑↓ Navigate · Enter Select · y/n/a Quick select · ') + s.primary('d') + s.muted(' Details'));
386
- // Bottom border
387
- lines.push(border);
388
- // Pad with empty lines to maintain consistent height
389
- while (lines.length < targetLineCount) {
390
- lines.push('');
337
+ handleDetailKey(data) {
338
+ const key = data.toString().toLowerCase();
339
+ const isPageUp = data.length === 4 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x35 && data[3] === 0x7e;
340
+ const isPageDown = data.length === 4 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x36 && data[3] === 0x7e;
341
+ // q or Escape = go back to main view
342
+ if (key === 'q' || this.isEscapeKey(data)) {
343
+ this.state.showingDetail = false;
344
+ return { type: 'continue' };
345
+ }
346
+ // Scroll
347
+ const visibleLines = DETAIL_VIEW_CONTENT_LINES;
348
+ const maxOffset = Math.max(0, this.state.detailContentLines.length - visibleLines);
349
+ if (this.isUpArrowKey(data)) {
350
+ this.state.detailScrollOffset = Math.max(0, this.state.detailScrollOffset - 1);
351
+ }
352
+ else if (isPageUp) {
353
+ this.state.detailScrollOffset = Math.max(0, this.state.detailScrollOffset - visibleLines);
354
+ }
355
+ else if (this.isDownArrowKey(data)) {
356
+ this.state.detailScrollOffset = Math.min(maxOffset, this.state.detailScrollOffset + 1);
357
+ }
358
+ else if (isPageDown) {
359
+ this.state.detailScrollOffset = Math.min(maxOffset, this.state.detailScrollOffset + visibleLines);
360
+ }
361
+ return { type: 'continue' };
362
+ }
363
+ getCleanupSummary(result) {
364
+ const s = getStyles();
365
+ const resultText = result === 'allow'
366
+ ? s.success('Allowed')
367
+ : result === 'allow-always'
368
+ ? s.primary('Always allowed')
369
+ : s.error('Denied');
370
+ return s.muted(`Permission: ${resultText}`);
391
371
  }
392
- // Render all lines
393
- terminal.write(lines.join('\n'));
394
- return lines.length;
395
372
  }
396
373
  // =============================================================================
397
374
  // Main Export
@@ -400,95 +377,6 @@ function render(options, state, previousLineCount = 0, targetLineCount = 0) {
400
377
  * Show the permission overlay
401
378
  */
402
379
  export async function showPermissionOverlay(options) {
403
- const state = {
404
- selectedIndex: 0, // Default to "Yes"
405
- };
406
- let lineCount = 0;
407
- let maxLineCount = 0;
408
- // NOTE: Footer is already paused by the caller (index.ts handler calls sharedState.pauseFooter)
409
- // Do NOT call pauseForOverlay() here - it causes double-pause issues
410
- // Ensure we start from a fresh line
411
- terminal.writeLine('');
412
- terminal.hideCursor();
413
- const wasRawMode = process.stdin.isRaw;
414
- terminal.enableRawMode();
415
- // Initial render
416
- lineCount = render(options, state, 0);
417
- maxLineCount = Math.max(maxLineCount, lineCount);
418
- return new Promise((resolve) => {
419
- const cleanup = (result) => {
420
- terminal.clearLinesAbove(maxLineCount);
421
- // Show result summary
422
- const s = getStyles();
423
- const resultText = result === 'allow'
424
- ? s.success('Allowed')
425
- : result === 'allow-always'
426
- ? s.primary('Always allowed')
427
- : s.error('Denied');
428
- terminal.writeLine(s.muted(`Permission: ${resultText}`));
429
- terminal.writeLine(''); // Blank line for separation
430
- terminal.showCursor();
431
- if (!wasRawMode) {
432
- terminal.disableRawMode();
433
- }
434
- process.stdin.removeListener('data', handleData);
435
- resolve(result);
436
- };
437
- const handleData = (data) => {
438
- const isEscape = data.length === 1 && data[0] === 0x1b;
439
- const isUpArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x41;
440
- const isDownArrow = data.length === 3 && data[0] === 0x1b && data[1] === 0x5b && data[2] === 0x42;
441
- const isCtrlC = data.length === 1 && data[0] === 0x03;
442
- const isEnter = data.length === 1 && (data[0] === 0x0d || data[0] === 0x0a);
443
- // Ctrl+C or Escape = deny
444
- if (isCtrlC || isEscape) {
445
- cleanup('deny');
446
- return;
447
- }
448
- // Quick keys
449
- const key = data.toString().toLowerCase();
450
- if (key === 'y') {
451
- cleanup('allow');
452
- return;
453
- }
454
- if (key === 'n') {
455
- cleanup('deny');
456
- return;
457
- }
458
- if (key === 'a') {
459
- cleanup('allow-always');
460
- return;
461
- }
462
- if (key === 'd') {
463
- // Show detail view, then return to permission overlay
464
- process.stdin.removeListener('data', handleData);
465
- // First clear the current permission overlay
466
- terminal.clearLinesAbove(maxLineCount);
467
- void showDetailView(options).then(() => {
468
- // Detail view already cleared itself, just re-render permission overlay
469
- lineCount = render(options, state, 0);
470
- maxLineCount = lineCount;
471
- process.stdin.on('data', handleData);
472
- });
473
- return;
474
- }
475
- // Arrow navigation
476
- if (isUpArrow) {
477
- state.selectedIndex = Math.max(0, state.selectedIndex - 1);
478
- }
479
- else if (isDownArrow) {
480
- state.selectedIndex = Math.min(2, state.selectedIndex + 1);
481
- }
482
- else if (isEnter) {
483
- // Select based on current index
484
- const results = ['allow', 'deny', 'allow-always'];
485
- cleanup(results[state.selectedIndex]);
486
- return;
487
- }
488
- // Re-render
489
- lineCount = render(options, state, maxLineCount, maxLineCount);
490
- maxLineCount = Math.max(maxLineCount, lineCount);
491
- };
492
- process.stdin.on('data', handleData);
493
- });
380
+ const overlay = new PermissionOverlayImpl(options);
381
+ return overlay.show();
494
382
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Projects Overlay
3
+ *
4
+ * Interactive overlay for viewing and managing projects.
5
+ * Uses TabbedListOverlay for consistent tabbed list behavior.
6
+ *
7
+ * Features:
8
+ * - Tabbed filtering by status (All, Active, Paused, Completed, Archived)
9
+ * - Paginated list with search
10
+ * - Project detail preview
11
+ * - Archive/Restore workflow
12
+ * - Delete workflow with path validation
13
+ * - Keyboard navigation (vim-style + arrows)
14
+ */
15
+ export interface ProjectsOverlayResult {
16
+ action: 'cancel' | 'open-workflow';
17
+ projectId?: number;
18
+ }
19
+ export declare function showProjectsOverlay(): Promise<ProjectsOverlayResult>;