@compilr-dev/cli 0.4.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (634) hide show
  1. package/README.md +254 -68
  2. package/dist/.tsbuildinfo.app +1 -0
  3. package/dist/.tsbuildinfo.data +1 -0
  4. package/dist/.tsbuildinfo.domain +1 -0
  5. package/dist/.tsbuildinfo.foundation +1 -0
  6. package/dist/agent.d.ts +134 -4
  7. package/dist/agent.js +345 -166
  8. package/dist/anchors/index.d.ts +9 -0
  9. package/dist/anchors/index.js +9 -0
  10. package/dist/anchors/project-anchors.d.ts +79 -0
  11. package/dist/anchors/project-anchors.js +202 -0
  12. package/dist/auth/api-client.d.ts +124 -0
  13. package/dist/auth/api-client.js +261 -0
  14. package/dist/auth/index.d.ts +172 -0
  15. package/dist/auth/index.js +545 -0
  16. package/dist/auth/storage.d.ts +52 -0
  17. package/dist/auth/storage.js +118 -0
  18. package/dist/changelog/index.d.ts +16 -0
  19. package/dist/changelog/index.js +24 -0
  20. package/dist/changelog/releases.d.ts +17 -0
  21. package/dist/changelog/releases.js +63 -0
  22. package/dist/commands/index.d.ts +2 -1
  23. package/dist/commands-v2/handlers/auth.d.ts +10 -0
  24. package/dist/commands-v2/handlers/auth.js +118 -0
  25. package/dist/commands-v2/handlers/background.d.ts +14 -0
  26. package/dist/commands-v2/handlers/background.js +276 -0
  27. package/dist/commands-v2/handlers/context.d.ts +13 -0
  28. package/dist/commands-v2/handlers/context.js +533 -0
  29. package/dist/commands-v2/handlers/core.d.ts +14 -0
  30. package/dist/commands-v2/handlers/core.js +290 -0
  31. package/dist/commands-v2/handlers/debug.d.ts +11 -0
  32. package/dist/commands-v2/handlers/debug.js +177 -0
  33. package/dist/commands-v2/handlers/delegations.d.ts +8 -0
  34. package/dist/commands-v2/handlers/delegations.js +29 -0
  35. package/dist/commands-v2/handlers/files.d.ts +8 -0
  36. package/dist/commands-v2/handlers/files.js +162 -0
  37. package/dist/commands-v2/handlers/filter.d.ts +9 -0
  38. package/dist/commands-v2/handlers/filter.js +130 -0
  39. package/dist/commands-v2/handlers/games.d.ts +7 -0
  40. package/dist/commands-v2/handlers/games.js +57 -0
  41. package/dist/commands-v2/handlers/index.d.ts +25 -0
  42. package/dist/commands-v2/handlers/index.js +63 -0
  43. package/dist/commands-v2/handlers/mcp.d.ts +8 -0
  44. package/dist/commands-v2/handlers/mcp.js +39 -0
  45. package/dist/commands-v2/handlers/notifications.d.ts +9 -0
  46. package/dist/commands-v2/handlers/notifications.js +34 -0
  47. package/dist/commands-v2/handlers/project.d.ts +22 -0
  48. package/dist/commands-v2/handlers/project.js +1035 -0
  49. package/dist/commands-v2/handlers/reset.d.ts +11 -0
  50. package/dist/commands-v2/handlers/reset.js +118 -0
  51. package/dist/commands-v2/handlers/session.d.ts +161 -0
  52. package/dist/commands-v2/handlers/session.js +805 -0
  53. package/dist/commands-v2/handlers/settings.d.ts +17 -0
  54. package/dist/commands-v2/handlers/settings.js +417 -0
  55. package/dist/commands-v2/handlers/tasks.d.ts +5 -0
  56. package/dist/commands-v2/handlers/tasks.js +36 -0
  57. package/dist/commands-v2/handlers/team.d.ts +9 -0
  58. package/dist/commands-v2/handlers/team.js +549 -0
  59. package/dist/commands-v2/handlers/terminals.d.ts +9 -0
  60. package/dist/commands-v2/handlers/terminals.js +34 -0
  61. package/dist/commands-v2/index.d.ts +14 -0
  62. package/dist/commands-v2/index.js +18 -0
  63. package/dist/commands-v2/registry.d.ts +52 -0
  64. package/dist/commands-v2/registry.js +114 -0
  65. package/dist/commands-v2/types.d.ts +153 -0
  66. package/dist/commands-v2/types.js +7 -0
  67. package/dist/commands.js +123 -7
  68. package/dist/compilr-diff-companion.vsix +0 -0
  69. package/dist/db/index.js +98 -4
  70. package/dist/db/repositories/document-repository.d.ts +2 -0
  71. package/dist/db/repositories/document-repository.js +5 -1
  72. package/dist/db/repositories/index.d.ts +2 -0
  73. package/dist/db/repositories/index.js +1 -0
  74. package/dist/db/repositories/plan-repository.d.ts +101 -0
  75. package/dist/db/repositories/plan-repository.js +275 -0
  76. package/dist/db/repositories/project-repository.d.ts +6 -0
  77. package/dist/db/repositories/project-repository.js +41 -0
  78. package/dist/db/repositories/work-item-repository.d.ts +15 -0
  79. package/dist/db/repositories/work-item-repository.js +69 -4
  80. package/dist/db/schema.d.ts +40 -3
  81. package/dist/db/schema.js +66 -3
  82. package/dist/episodes/index.d.ts +20 -0
  83. package/dist/episodes/index.js +27 -0
  84. package/dist/episodes/recorder.d.ts +51 -0
  85. package/dist/episodes/recorder.js +195 -0
  86. package/dist/episodes/significant-work.d.ts +21 -0
  87. package/dist/episodes/significant-work.js +56 -0
  88. package/dist/episodes/store.d.ts +38 -0
  89. package/dist/episodes/store.js +199 -0
  90. package/dist/episodes/types.d.ts +35 -0
  91. package/dist/episodes/types.js +6 -0
  92. package/dist/episodes/work-at-risk.d.ts +12 -0
  93. package/dist/episodes/work-at-risk.js +38 -0
  94. package/dist/episodes/work-summary-anchor.d.ts +23 -0
  95. package/dist/episodes/work-summary-anchor.js +73 -0
  96. package/dist/games/coins.d.ts +66 -0
  97. package/dist/games/coins.js +165 -0
  98. package/dist/games/game-base.d.ts +84 -0
  99. package/dist/games/game-base.js +204 -0
  100. package/dist/games/index.d.ts +16 -0
  101. package/dist/games/index.js +49 -0
  102. package/dist/games/scores.d.ts +69 -0
  103. package/dist/games/scores.js +191 -0
  104. package/dist/games/tetris/board.d.ts +59 -0
  105. package/dist/games/tetris/board.js +170 -0
  106. package/dist/games/tetris/index.d.ts +109 -0
  107. package/dist/games/tetris/index.js +610 -0
  108. package/dist/games/tetris/pieces.d.ts +44 -0
  109. package/dist/games/tetris/pieces.js +271 -0
  110. package/dist/games/tetris/renderer.d.ts +26 -0
  111. package/dist/games/tetris/renderer.js +77 -0
  112. package/dist/guide/guide-content.d.ts +23 -0
  113. package/dist/guide/guide-content.js +196 -0
  114. package/dist/guide/index.d.ts +8 -0
  115. package/dist/guide/index.js +7 -0
  116. package/dist/guide/shared-content.d.ts +37 -0
  117. package/dist/guide/shared-content.js +1272 -0
  118. package/dist/guide/tutorial-helpers.d.ts +57 -0
  119. package/dist/guide/tutorial-helpers.js +147 -0
  120. package/dist/handlers/ask-user-handlers.d.ts +32 -0
  121. package/dist/handlers/ask-user-handlers.js +104 -0
  122. package/dist/handlers/delegation-handlers.d.ts +34 -0
  123. package/dist/handlers/delegation-handlers.js +291 -0
  124. package/dist/handlers/permission-handler.d.ts +30 -0
  125. package/dist/handlers/permission-handler.js +205 -0
  126. package/dist/index.d.ts +11 -1
  127. package/dist/index.js +615 -179
  128. package/dist/input-handlers/index.d.ts +7 -0
  129. package/dist/input-handlers/index.js +7 -0
  130. package/dist/input-handlers/memory-handler.d.ts +26 -0
  131. package/dist/input-handlers/memory-handler.js +69 -0
  132. package/dist/models/index.d.ts +10 -0
  133. package/dist/models/index.js +12 -0
  134. package/dist/models/model-registry.d.ts +38 -0
  135. package/dist/models/model-registry.js +69 -0
  136. package/dist/models/model-tiers.d.ts +28 -0
  137. package/dist/models/model-tiers.js +71 -0
  138. package/dist/models/model-validation.d.ts +25 -0
  139. package/dist/models/model-validation.js +291 -0
  140. package/dist/models/ollama-models.d.ts +73 -0
  141. package/dist/models/ollama-models.js +178 -0
  142. package/dist/models/provider-types.d.ts +6 -0
  143. package/dist/models/provider-types.js +1 -0
  144. package/dist/models/providers.d.ts +35 -0
  145. package/dist/models/providers.js +58 -0
  146. package/dist/models/types.d.ts +4 -0
  147. package/dist/models/types.js +4 -0
  148. package/dist/multi-agent/activity.d.ts +21 -0
  149. package/dist/multi-agent/activity.js +34 -0
  150. package/dist/multi-agent/agent-selection.d.ts +55 -0
  151. package/dist/multi-agent/agent-selection.js +90 -0
  152. package/dist/multi-agent/artifacts.d.ts +197 -0
  153. package/dist/multi-agent/artifacts.js +379 -0
  154. package/dist/multi-agent/checkpointer.d.ts +138 -0
  155. package/dist/multi-agent/checkpointer.js +471 -0
  156. package/dist/multi-agent/collision-utils.d.ts +16 -0
  157. package/dist/multi-agent/collision-utils.js +28 -0
  158. package/dist/multi-agent/context-resolver.d.ts +97 -0
  159. package/dist/multi-agent/context-resolver.js +316 -0
  160. package/dist/multi-agent/custom-agents.d.ts +83 -0
  161. package/dist/multi-agent/custom-agents.js +227 -0
  162. package/dist/multi-agent/delegation-tracker.d.ts +157 -0
  163. package/dist/multi-agent/delegation-tracker.js +243 -0
  164. package/dist/multi-agent/file-lock-hook.d.ts +29 -0
  165. package/dist/multi-agent/file-lock-hook.js +97 -0
  166. package/dist/multi-agent/file-locks.d.ts +58 -0
  167. package/dist/multi-agent/file-locks.js +194 -0
  168. package/dist/multi-agent/index.d.ts +24 -0
  169. package/dist/multi-agent/index.js +30 -0
  170. package/dist/multi-agent/mention-parser.d.ts +64 -0
  171. package/dist/multi-agent/mention-parser.js +146 -0
  172. package/dist/multi-agent/notification-manager.d.ts +84 -0
  173. package/dist/multi-agent/notification-manager.js +224 -0
  174. package/dist/multi-agent/pending-requests.d.ts +122 -0
  175. package/dist/multi-agent/pending-requests.js +155 -0
  176. package/dist/multi-agent/session-registry.d.ts +139 -0
  177. package/dist/multi-agent/session-registry.js +514 -0
  178. package/dist/multi-agent/shared-context.d.ts +293 -0
  179. package/dist/multi-agent/shared-context.js +671 -0
  180. package/dist/multi-agent/skill-requirements.d.ts +66 -0
  181. package/dist/multi-agent/skill-requirements.js +178 -0
  182. package/dist/multi-agent/task-assignment.d.ts +69 -0
  183. package/dist/multi-agent/task-assignment.js +123 -0
  184. package/dist/multi-agent/task-suggestion.d.ts +31 -0
  185. package/dist/multi-agent/task-suggestion.js +72 -0
  186. package/dist/multi-agent/team-agent.d.ts +201 -0
  187. package/dist/multi-agent/team-agent.js +488 -0
  188. package/dist/multi-agent/team.d.ts +286 -0
  189. package/dist/multi-agent/team.js +610 -0
  190. package/dist/multi-agent/tool-config.d.ts +110 -0
  191. package/dist/multi-agent/tool-config.js +661 -0
  192. package/dist/multi-agent/types.d.ts +211 -0
  193. package/dist/multi-agent/types.js +617 -0
  194. package/dist/prompts/plan-mode-prompt.d.ts +11 -0
  195. package/dist/prompts/plan-mode-prompt.js +95 -0
  196. package/dist/repl-helpers.d.ts +63 -0
  197. package/dist/repl-helpers.js +319 -0
  198. package/dist/repl-v2.d.ts +554 -0
  199. package/dist/repl-v2.js +3286 -0
  200. package/dist/session/index.d.ts +6 -0
  201. package/dist/session/index.js +6 -0
  202. package/dist/session/project-session-manager.d.ts +158 -0
  203. package/dist/session/project-session-manager.js +650 -0
  204. package/dist/settings/index.d.ts +156 -13
  205. package/dist/settings/index.js +377 -24
  206. package/dist/settings/mcp-config.d.ts +76 -0
  207. package/dist/settings/mcp-config.js +143 -0
  208. package/dist/settings/paths.d.ts +114 -0
  209. package/dist/settings/paths.js +270 -0
  210. package/dist/shared-handlers.d.ts +62 -0
  211. package/dist/shared-handlers.js +48 -0
  212. package/dist/system-prompt/builder.d.ts +5 -0
  213. package/dist/system-prompt/builder.js +4 -0
  214. package/dist/system-prompt/index.d.ts +18 -0
  215. package/dist/system-prompt/index.js +18 -0
  216. package/dist/system-prompt/modules.d.ts +5 -0
  217. package/dist/system-prompt/modules.js +4 -0
  218. package/dist/tabbed-menu.js +2 -1
  219. package/dist/templates/compilr-md-import.d.ts +16 -0
  220. package/dist/templates/compilr-md-import.js +241 -0
  221. package/dist/templates/compilr-md.js +10 -58
  222. package/dist/templates/config-json.d.ts +1 -25
  223. package/dist/templates/index.d.ts +2 -0
  224. package/dist/templates/index.js +35 -75
  225. package/dist/themes/colors.js +3 -1
  226. package/dist/themes/registry.d.ts +5 -36
  227. package/dist/themes/registry.js +11 -95
  228. package/dist/themes/types.d.ts +3 -38
  229. package/dist/themes/types.js +2 -2
  230. package/dist/tool-names.d.ts +108 -0
  231. package/dist/tool-names.js +227 -0
  232. package/dist/tools/anchor-tools.d.ts +31 -0
  233. package/dist/tools/anchor-tools.js +255 -0
  234. package/dist/tools/artifact-tools.d.ts +42 -0
  235. package/dist/tools/artifact-tools.js +328 -0
  236. package/dist/tools/ask-user-simple.d.ts +1 -1
  237. package/dist/tools/ask-user-simple.js +2 -1
  238. package/dist/tools/ask-user.d.ts +1 -1
  239. package/dist/tools/ask-user.js +2 -1
  240. package/dist/tools/backlog-wrappers.d.ts +56 -0
  241. package/dist/tools/backlog-wrappers.js +353 -0
  242. package/dist/tools/backlog.d.ts +2 -2
  243. package/dist/tools/backlog.js +2 -2
  244. package/dist/tools/db-tools.d.ts +12 -0
  245. package/dist/tools/db-tools.js +14 -0
  246. package/dist/tools/delegate-background.d.ts +27 -0
  247. package/dist/tools/delegate-background.js +115 -0
  248. package/dist/tools/delegate.d.ts +22 -0
  249. package/dist/tools/delegate.js +97 -0
  250. package/dist/tools/delegation-status.d.ts +16 -0
  251. package/dist/tools/delegation-status.js +128 -0
  252. package/dist/tools/document-db.d.ts +43 -0
  253. package/dist/tools/document-db.js +220 -0
  254. package/dist/tools/guide-tool.d.ts +12 -0
  255. package/dist/tools/guide-tool.js +59 -0
  256. package/dist/tools/handoff.d.ts +25 -0
  257. package/dist/tools/handoff.js +99 -0
  258. package/dist/tools/meta-tools.d.ts +26 -0
  259. package/dist/tools/meta-tools.js +47 -0
  260. package/dist/tools/plan-tools.d.ts +54 -0
  261. package/dist/tools/plan-tools.js +338 -0
  262. package/dist/tools/platform-adapter.d.ts +29 -0
  263. package/dist/tools/platform-adapter.js +394 -0
  264. package/dist/tools/project-db.d.ts +34 -0
  265. package/dist/tools/project-db.js +39 -0
  266. package/dist/tools/recall-work-tool.d.ts +18 -0
  267. package/dist/tools/recall-work-tool.js +82 -0
  268. package/dist/tools/workitem-db.d.ts +135 -0
  269. package/dist/tools/workitem-db.js +730 -0
  270. package/dist/tools.d.ts +67 -2
  271. package/dist/tools.js +238 -38
  272. package/dist/ui/ask-user-overlay.d.ts +2 -2
  273. package/dist/ui/ask-user-overlay.js +443 -535
  274. package/dist/ui/ask-user-simple-overlay.d.ts +2 -2
  275. package/dist/ui/ask-user-simple-overlay.js +182 -209
  276. package/dist/ui/autocomplete-controller.d.ts +42 -0
  277. package/dist/ui/autocomplete-controller.js +384 -0
  278. package/dist/ui/base/index.d.ts +26 -0
  279. package/dist/ui/base/index.js +33 -0
  280. package/dist/ui/base/inline-overlay-utils.d.ts +217 -0
  281. package/dist/ui/base/inline-overlay-utils.js +320 -0
  282. package/dist/ui/base/inline-overlay.d.ts +159 -0
  283. package/dist/ui/base/inline-overlay.js +257 -0
  284. package/dist/ui/base/key-utils.d.ts +15 -0
  285. package/dist/ui/base/key-utils.js +30 -0
  286. package/dist/ui/base/overlay-base-v2.d.ts +203 -0
  287. package/dist/ui/base/overlay-base-v2.js +260 -0
  288. package/dist/ui/base/overlay-base.d.ts +156 -0
  289. package/dist/ui/base/overlay-base.js +238 -0
  290. package/dist/ui/base/overlay-lifecycle.d.ts +65 -0
  291. package/dist/ui/base/overlay-lifecycle.js +159 -0
  292. package/dist/ui/base/overlay-types.d.ts +185 -0
  293. package/dist/ui/base/overlay-types.js +7 -0
  294. package/dist/ui/base/render-utils.d.ts +27 -0
  295. package/dist/ui/base/render-utils.js +36 -0
  296. package/dist/ui/base/screen-stack.d.ts +148 -0
  297. package/dist/ui/base/screen-stack.js +184 -0
  298. package/dist/ui/base/tabbed-list-overlay-v2.d.ts +118 -0
  299. package/dist/ui/base/tabbed-list-overlay-v2.js +335 -0
  300. package/dist/ui/base/tabbed-list-overlay.d.ts +153 -0
  301. package/dist/ui/base/tabbed-list-overlay.js +369 -0
  302. package/dist/ui/constants/labels.d.ts +14 -0
  303. package/dist/ui/constants/labels.js +51 -0
  304. package/dist/ui/conversation-store.d.ts +55 -0
  305. package/dist/ui/conversation-store.js +107 -0
  306. package/dist/ui/conversation.d.ts +75 -4
  307. package/dist/ui/conversation.js +376 -165
  308. package/dist/ui/diff.d.ts +7 -1
  309. package/dist/ui/diff.js +85 -48
  310. package/dist/ui/ephemeral.d.ts +1 -1
  311. package/dist/ui/ephemeral.js +4 -10
  312. package/dist/ui/features/index.d.ts +34 -0
  313. package/dist/ui/features/index.js +34 -0
  314. package/dist/ui/features/input-feature.d.ts +85 -0
  315. package/dist/ui/features/input-feature.js +238 -0
  316. package/dist/ui/features/list-feature.d.ts +155 -0
  317. package/dist/ui/features/list-feature.js +244 -0
  318. package/dist/ui/features/pagination-feature.d.ts +154 -0
  319. package/dist/ui/features/pagination-feature.js +238 -0
  320. package/dist/ui/features/search-feature.d.ts +148 -0
  321. package/dist/ui/features/search-feature.js +185 -0
  322. package/dist/ui/features/tab-feature.d.ts +194 -0
  323. package/dist/ui/features/tab-feature.js +307 -0
  324. package/dist/ui/file-autocomplete.d.ts +24 -0
  325. package/dist/ui/file-autocomplete.js +56 -0
  326. package/dist/ui/footer-renderer.d.ts +69 -0
  327. package/dist/ui/footer-renderer.js +431 -0
  328. package/dist/ui/footer.d.ts +181 -7
  329. package/dist/ui/footer.js +523 -74
  330. package/dist/ui/guardrail-overlay.d.ts +29 -0
  331. package/dist/ui/guardrail-overlay.js +145 -0
  332. package/dist/ui/index.d.ts +1 -1
  333. package/dist/ui/index.js +1 -3
  334. package/dist/ui/input-controller.d.ts +51 -0
  335. package/dist/ui/input-controller.js +176 -0
  336. package/dist/ui/input-prompt.d.ts +135 -33
  337. package/dist/ui/input-prompt.js +728 -337
  338. package/dist/ui/iteration-limit-overlay.d.ts +2 -2
  339. package/dist/ui/iteration-limit-overlay.js +92 -128
  340. package/dist/ui/keyboard-handler.d.ts +57 -0
  341. package/dist/ui/keyboard-handler.js +557 -0
  342. package/dist/ui/keys-overlay.d.ts +1 -0
  343. package/dist/ui/keys-overlay.js +203 -141
  344. package/dist/ui/line-utils.d.ts +88 -0
  345. package/dist/ui/line-utils.js +150 -0
  346. package/dist/ui/live-region-facade.d.ts +42 -0
  347. package/dist/ui/live-region-facade.js +205 -0
  348. package/dist/ui/live-region.d.ts +157 -0
  349. package/dist/ui/live-region.js +379 -0
  350. package/dist/ui/mascot/expressions.d.ts +32 -0
  351. package/dist/ui/mascot/expressions.js +213 -0
  352. package/dist/ui/mascot/index.d.ts +8 -0
  353. package/dist/ui/mascot/index.js +8 -0
  354. package/dist/ui/mascot/renderer.d.ts +19 -0
  355. package/dist/ui/mascot/renderer.js +132 -0
  356. package/dist/ui/overlay/data/tutorial-content.d.ts +9 -0
  357. package/dist/ui/overlay/data/tutorial-content.js +9 -0
  358. package/dist/ui/overlay/data/tutorial-registry.d.ts +12 -0
  359. package/dist/ui/overlay/data/tutorial-registry.js +116 -0
  360. package/dist/ui/overlay/data/tutorial-types.d.ts +35 -0
  361. package/dist/ui/overlay/data/tutorial-types.js +6 -0
  362. package/dist/ui/overlay/data/tutorials/basics/first-conversation.d.ts +7 -0
  363. package/dist/ui/overlay/data/tutorials/basics/first-conversation.js +220 -0
  364. package/dist/ui/overlay/data/tutorials/basics/first-project.d.ts +7 -0
  365. package/dist/ui/overlay/data/tutorials/basics/first-project.js +284 -0
  366. package/dist/ui/overlay/data/tutorials/basics/navigation.d.ts +8 -0
  367. package/dist/ui/overlay/data/tutorials/basics/navigation.js +22 -0
  368. package/dist/ui/overlay/data/tutorials/basics/welcome.d.ts +7 -0
  369. package/dist/ui/overlay/data/tutorials/basics/welcome.js +174 -0
  370. package/dist/ui/overlay/data/tutorials/config/context-management.d.ts +7 -0
  371. package/dist/ui/overlay/data/tutorials/config/context-management.js +158 -0
  372. package/dist/ui/overlay/data/tutorials/config/mcp-servers.d.ts +8 -0
  373. package/dist/ui/overlay/data/tutorials/config/mcp-servers.js +155 -0
  374. package/dist/ui/overlay/data/tutorials/config/model-selection.d.ts +7 -0
  375. package/dist/ui/overlay/data/tutorials/config/model-selection.js +162 -0
  376. package/dist/ui/overlay/data/tutorials/config/permissions-safety.d.ts +7 -0
  377. package/dist/ui/overlay/data/tutorials/config/permissions-safety.js +163 -0
  378. package/dist/ui/overlay/data/tutorials/config/settings-config.d.ts +7 -0
  379. package/dist/ui/overlay/data/tutorials/config/settings-config.js +166 -0
  380. package/dist/ui/overlay/data/tutorials/planning/arch.d.ts +7 -0
  381. package/dist/ui/overlay/data/tutorials/planning/arch.js +168 -0
  382. package/dist/ui/overlay/data/tutorials/planning/backlog.d.ts +7 -0
  383. package/dist/ui/overlay/data/tutorials/planning/backlog.js +103 -0
  384. package/dist/ui/overlay/data/tutorials/planning/build.d.ts +7 -0
  385. package/dist/ui/overlay/data/tutorials/planning/build.js +173 -0
  386. package/dist/ui/overlay/data/tutorials/planning/design.d.ts +7 -0
  387. package/dist/ui/overlay/data/tutorials/planning/design.js +205 -0
  388. package/dist/ui/overlay/data/tutorials/planning/docs.d.ts +7 -0
  389. package/dist/ui/overlay/data/tutorials/planning/docs.js +143 -0
  390. package/dist/ui/overlay/data/tutorials/planning/prd.d.ts +7 -0
  391. package/dist/ui/overlay/data/tutorials/planning/prd.js +173 -0
  392. package/dist/ui/overlay/data/tutorials/planning/scaffold.d.ts +7 -0
  393. package/dist/ui/overlay/data/tutorials/planning/scaffold.js +164 -0
  394. package/dist/ui/overlay/data/tutorials/planning/sketch.d.ts +7 -0
  395. package/dist/ui/overlay/data/tutorials/planning/sketch.js +58 -0
  396. package/dist/ui/overlay/data/tutorials/projects/anchors.d.ts +7 -0
  397. package/dist/ui/overlay/data/tutorials/projects/anchors.js +248 -0
  398. package/dist/ui/overlay/data/tutorials/projects/import-project.d.ts +7 -0
  399. package/dist/ui/overlay/data/tutorials/projects/import-project.js +172 -0
  400. package/dist/ui/overlay/data/tutorials/projects/managing-projects.d.ts +8 -0
  401. package/dist/ui/overlay/data/tutorials/projects/managing-projects.js +212 -0
  402. package/dist/ui/overlay/data/tutorials/projects/new-project.d.ts +7 -0
  403. package/dist/ui/overlay/data/tutorials/projects/new-project.js +251 -0
  404. package/dist/ui/overlay/data/tutorials/projects/session-management.d.ts +7 -0
  405. package/dist/ui/overlay/data/tutorials/projects/session-management.js +169 -0
  406. package/dist/ui/overlay/data/tutorials/teams/background-execution.d.ts +7 -0
  407. package/dist/ui/overlay/data/tutorials/teams/background-execution.js +171 -0
  408. package/dist/ui/overlay/data/tutorials/teams/multi-terminal.d.ts +8 -0
  409. package/dist/ui/overlay/data/tutorials/teams/multi-terminal.js +147 -0
  410. package/dist/ui/overlay/data/tutorials/teams/task-assignment.d.ts +7 -0
  411. package/dist/ui/overlay/data/tutorials/teams/task-assignment.js +204 -0
  412. package/dist/ui/overlay/data/tutorials/teams/team-overview.d.ts +7 -0
  413. package/dist/ui/overlay/data/tutorials/teams/team-overview.js +165 -0
  414. package/dist/ui/overlay/data/tutorials/teams/working-with-agents.d.ts +7 -0
  415. package/dist/ui/overlay/data/tutorials/teams/working-with-agents.js +172 -0
  416. package/dist/ui/overlay/impl/agents-overlay-v2.d.ts +45 -0
  417. package/dist/ui/overlay/impl/agents-overlay-v2.js +814 -0
  418. package/dist/ui/overlay/impl/anchors-overlay-v2.d.ts +47 -0
  419. package/dist/ui/overlay/impl/anchors-overlay-v2.js +749 -0
  420. package/dist/ui/overlay/impl/arch-type-overlay-v2.d.ts +37 -0
  421. package/dist/ui/overlay/impl/arch-type-overlay-v2.js +240 -0
  422. package/dist/ui/overlay/impl/artifact-detail-overlay-v2.d.ts +43 -0
  423. package/dist/ui/overlay/impl/artifact-detail-overlay-v2.js +232 -0
  424. package/dist/ui/overlay/impl/artifact-overlay-v2.d.ts +40 -0
  425. package/dist/ui/overlay/impl/artifact-overlay-v2.js +115 -0
  426. package/dist/ui/overlay/impl/ask-user-overlay-v2.d.ts +72 -0
  427. package/dist/ui/overlay/impl/ask-user-overlay-v2.js +581 -0
  428. package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.d.ts +46 -0
  429. package/dist/ui/overlay/impl/ask-user-simple-overlay-v2.js +204 -0
  430. package/dist/ui/overlay/impl/background-overlay-v2.d.ts +40 -0
  431. package/dist/ui/overlay/impl/background-overlay-v2.js +147 -0
  432. package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +52 -0
  433. package/dist/ui/overlay/impl/backlog-overlay-v2.js +681 -0
  434. package/dist/ui/overlay/impl/changelog-overlay-v2.d.ts +44 -0
  435. package/dist/ui/overlay/impl/changelog-overlay-v2.js +165 -0
  436. package/dist/ui/overlay/impl/commands-overlay-v2.d.ts +33 -0
  437. package/dist/ui/overlay/impl/commands-overlay-v2.js +439 -0
  438. package/dist/ui/overlay/impl/config-overlay-v2.d.ts +111 -0
  439. package/dist/ui/overlay/impl/config-overlay-v2.js +718 -0
  440. package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.d.ts +83 -0
  441. package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.js +711 -0
  442. package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +57 -0
  443. package/dist/ui/overlay/impl/dashboard-overlay-v2.js +382 -0
  444. package/dist/ui/overlay/impl/delegations-overlay-v2.d.ts +28 -0
  445. package/dist/ui/overlay/impl/delegations-overlay-v2.js +279 -0
  446. package/dist/ui/overlay/impl/docs-overlay-v2.d.ts +45 -0
  447. package/dist/ui/overlay/impl/docs-overlay-v2.js +117 -0
  448. package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +84 -0
  449. package/dist/ui/overlay/impl/document-detail-overlay-v2.js +1112 -0
  450. package/dist/ui/overlay/impl/filter-overlay-v2.d.ts +41 -0
  451. package/dist/ui/overlay/impl/filter-overlay-v2.js +110 -0
  452. package/dist/ui/overlay/impl/games-overlay-v2.d.ts +31 -0
  453. package/dist/ui/overlay/impl/games-overlay-v2.js +135 -0
  454. package/dist/ui/overlay/impl/guardrail-overlay-v2.d.ts +43 -0
  455. package/dist/ui/overlay/impl/guardrail-overlay-v2.js +114 -0
  456. package/dist/ui/overlay/impl/help-overlay-v2.d.ts +57 -0
  457. package/dist/ui/overlay/impl/help-overlay-v2.js +287 -0
  458. package/dist/ui/overlay/impl/init-setup-overlay-v2.d.ts +25 -0
  459. package/dist/ui/overlay/impl/init-setup-overlay-v2.js +97 -0
  460. package/dist/ui/overlay/impl/iteration-limit-overlay-v2.d.ts +35 -0
  461. package/dist/ui/overlay/impl/iteration-limit-overlay-v2.js +105 -0
  462. package/dist/ui/overlay/impl/keys-overlay-v2.d.ts +41 -0
  463. package/dist/ui/overlay/impl/keys-overlay-v2.js +248 -0
  464. package/dist/ui/overlay/impl/login-overlay-v2.d.ts +49 -0
  465. package/dist/ui/overlay/impl/login-overlay-v2.js +277 -0
  466. package/dist/ui/overlay/impl/mascot-overlay-v2.d.ts +41 -0
  467. package/dist/ui/overlay/impl/mascot-overlay-v2.js +138 -0
  468. package/dist/ui/overlay/impl/mcp-overlay-v2.d.ts +63 -0
  469. package/dist/ui/overlay/impl/mcp-overlay-v2.js +907 -0
  470. package/dist/ui/overlay/impl/model-overlay-v2.d.ts +93 -0
  471. package/dist/ui/overlay/impl/model-overlay-v2.js +1143 -0
  472. package/dist/ui/overlay/impl/model-warning-overlay-v2.d.ts +46 -0
  473. package/dist/ui/overlay/impl/model-warning-overlay-v2.js +132 -0
  474. package/dist/ui/overlay/impl/new-overlay-v2.d.ts +108 -0
  475. package/dist/ui/overlay/impl/new-overlay-v2.js +1243 -0
  476. package/dist/ui/overlay/impl/notifications-overlay-v2.d.ts +20 -0
  477. package/dist/ui/overlay/impl/notifications-overlay-v2.js +116 -0
  478. package/dist/ui/overlay/impl/onboarding-wizard-overlay-v2.d.ts +76 -0
  479. package/dist/ui/overlay/impl/onboarding-wizard-overlay-v2.js +728 -0
  480. package/dist/ui/overlay/impl/pending-overlay-v2.d.ts +51 -0
  481. package/dist/ui/overlay/impl/pending-overlay-v2.js +445 -0
  482. package/dist/ui/overlay/impl/permission-overlay-v2.d.ts +36 -0
  483. package/dist/ui/overlay/impl/permission-overlay-v2.js +380 -0
  484. package/dist/ui/overlay/impl/permissions-overlay-v2.d.ts +85 -0
  485. package/dist/ui/overlay/impl/permissions-overlay-v2.js +820 -0
  486. package/dist/ui/overlay/impl/plan-approval-overlay-v2.d.ts +35 -0
  487. package/dist/ui/overlay/impl/plan-approval-overlay-v2.js +181 -0
  488. package/dist/ui/overlay/impl/project-edit-overlay-v2.d.ts +36 -0
  489. package/dist/ui/overlay/impl/project-edit-overlay-v2.js +195 -0
  490. package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +37 -0
  491. package/dist/ui/overlay/impl/projects-overlay-v2.js +733 -0
  492. package/dist/ui/overlay/impl/reset-overlay-v2.d.ts +39 -0
  493. package/dist/ui/overlay/impl/reset-overlay-v2.js +107 -0
  494. package/dist/ui/overlay/impl/resume-overlay-v2.d.ts +60 -0
  495. package/dist/ui/overlay/impl/resume-overlay-v2.js +414 -0
  496. package/dist/ui/overlay/impl/session-mode-overlay-v2.d.ts +43 -0
  497. package/dist/ui/overlay/impl/session-mode-overlay-v2.js +124 -0
  498. package/dist/ui/overlay/impl/tasks-overlay-v2.d.ts +28 -0
  499. package/dist/ui/overlay/impl/tasks-overlay-v2.js +283 -0
  500. package/dist/ui/overlay/impl/team-overlay-v2.d.ts +86 -0
  501. package/dist/ui/overlay/impl/team-overlay-v2.js +692 -0
  502. package/dist/ui/overlay/impl/terminals-overlay-v2.d.ts +26 -0
  503. package/dist/ui/overlay/impl/terminals-overlay-v2.js +217 -0
  504. package/dist/ui/overlay/impl/theme-overlay-v2.d.ts +42 -0
  505. package/dist/ui/overlay/impl/theme-overlay-v2.js +135 -0
  506. package/dist/ui/overlay/impl/tools-overlay-v2.d.ts +47 -0
  507. package/dist/ui/overlay/impl/tools-overlay-v2.js +214 -0
  508. package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +45 -0
  509. package/dist/ui/overlay/impl/tutorial-overlay-v2.js +212 -0
  510. package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +80 -0
  511. package/dist/ui/overlay/impl/workflow-overlay-v2.js +641 -0
  512. package/dist/ui/overlay/index.d.ts +52 -0
  513. package/dist/ui/overlay/index.js +54 -0
  514. package/dist/ui/overlay/key-utils.d.ts +6 -0
  515. package/dist/ui/overlay/key-utils.js +6 -0
  516. package/dist/ui/overlay/types.d.ts +140 -0
  517. package/dist/ui/overlay/types.js +22 -0
  518. package/dist/ui/overlay-manager.d.ts +43 -0
  519. package/dist/ui/overlay-manager.js +238 -0
  520. package/dist/ui/overlays.d.ts +0 -4
  521. package/dist/ui/overlays.js +4 -460
  522. package/dist/ui/permission-overlay.d.ts +1 -1
  523. package/dist/ui/permission-overlay.js +189 -300
  524. package/dist/ui/providers/types.d.ts +178 -0
  525. package/dist/ui/providers/types.js +9 -0
  526. package/dist/ui/render-modes.d.ts +36 -0
  527. package/dist/ui/render-modes.js +44 -0
  528. package/dist/ui/startup-menu.d.ts +36 -0
  529. package/dist/ui/startup-menu.js +236 -0
  530. package/dist/ui/status-bar-controller.d.ts +33 -0
  531. package/dist/ui/status-bar-controller.js +99 -0
  532. package/dist/ui/subagent-renderer.d.ts +117 -0
  533. package/dist/ui/subagent-renderer.js +318 -0
  534. package/dist/ui/terminal-autocomplete-utils.d.ts +23 -0
  535. package/dist/ui/terminal-autocomplete-utils.js +83 -0
  536. package/dist/ui/terminal-codes.d.ts +94 -0
  537. package/dist/ui/terminal-codes.js +124 -0
  538. package/dist/ui/terminal-line-builders.d.ts +17 -0
  539. package/dist/ui/terminal-line-builders.js +42 -0
  540. package/dist/ui/terminal-render-item.d.ts +16 -0
  541. package/dist/ui/terminal-render-item.js +267 -0
  542. package/dist/ui/terminal-renderer.d.ts +220 -0
  543. package/dist/ui/terminal-renderer.js +750 -0
  544. package/dist/ui/terminal-types.d.ts +179 -0
  545. package/dist/ui/terminal-types.js +34 -0
  546. package/dist/ui/terminal-ui.d.ts +331 -0
  547. package/dist/ui/terminal-ui.js +819 -0
  548. package/dist/ui/terminal.d.ts +20 -0
  549. package/dist/ui/terminal.js +72 -0
  550. package/dist/ui/todo-zone.d.ts +19 -1
  551. package/dist/ui/todo-zone.js +124 -38
  552. package/dist/ui/tool-formatters.d.ts +16 -0
  553. package/dist/ui/tool-formatters.js +1027 -0
  554. package/dist/ui/turn-metrics.d.ts +56 -0
  555. package/dist/ui/turn-metrics.js +75 -0
  556. package/dist/ui/types.d.ts +28 -0
  557. package/dist/ui/types.js +1 -0
  558. package/dist/ui/vscode-diff-ipc.d.ts +102 -0
  559. package/dist/ui/vscode-diff-ipc.js +385 -0
  560. package/dist/utils/credentials.d.ts +24 -5
  561. package/dist/utils/credentials.js +123 -9
  562. package/dist/utils/debug-log.d.ts +28 -0
  563. package/dist/utils/debug-log.js +57 -0
  564. package/dist/utils/format-tokens.d.ts +13 -0
  565. package/dist/utils/format-tokens.js +18 -0
  566. package/dist/utils/git-config.d.ts +26 -0
  567. package/dist/utils/git-config.js +54 -0
  568. package/dist/utils/message-utils.d.ts +61 -0
  569. package/dist/utils/message-utils.js +72 -0
  570. package/dist/utils/model-tiers.d.ts +8 -1
  571. package/dist/utils/model-tiers.js +39 -17
  572. package/dist/utils/open-browser.d.ts +5 -0
  573. package/dist/utils/open-browser.js +32 -0
  574. package/dist/utils/path-safety.d.ts +56 -0
  575. package/dist/utils/path-safety.js +240 -0
  576. package/dist/utils/project-detection.d.ts +58 -0
  577. package/dist/utils/project-detection.js +424 -0
  578. package/dist/utils/project-memory.js +2 -1
  579. package/dist/utils/project-status.d.ts +2 -2
  580. package/dist/utils/startup-perf.d.ts +18 -0
  581. package/dist/utils/startup-perf.js +60 -0
  582. package/dist/utils/token-tracker.d.ts +62 -0
  583. package/dist/utils/token-tracker.js +150 -0
  584. package/dist/utils/token-types.d.ts +23 -0
  585. package/dist/utils/token-types.js +18 -0
  586. package/dist/utils/types/config-types.d.ts +32 -0
  587. package/dist/utils/types/config-types.js +8 -0
  588. package/dist/utils/update-checker.d.ts +28 -0
  589. package/dist/utils/update-checker.js +106 -0
  590. package/dist/utils/version.d.ts +7 -0
  591. package/dist/utils/version.js +10 -0
  592. package/dist/utils/vscode-detect.d.ts +39 -0
  593. package/dist/utils/vscode-detect.js +137 -0
  594. package/dist/workflow/guided-mode-injector.d.ts +42 -0
  595. package/dist/workflow/guided-mode-injector.js +191 -0
  596. package/dist/workflow/index.d.ts +8 -0
  597. package/dist/workflow/index.js +8 -0
  598. package/dist/workflow/step-criteria.d.ts +62 -0
  599. package/dist/workflow/step-criteria.js +150 -0
  600. package/dist/workflow/step-tracker.d.ts +92 -0
  601. package/dist/workflow/step-tracker.js +141 -0
  602. package/package.json +32 -12
  603. package/dist/index.old.d.ts +0 -7
  604. package/dist/index.old.js +0 -1014
  605. package/dist/repl.d.ts +0 -121
  606. package/dist/repl.js +0 -1878
  607. package/dist/templates/claude-md.d.ts +0 -7
  608. package/dist/templates/claude-md.js +0 -189
  609. package/dist/test-autocomplete.d.ts +0 -7
  610. package/dist/test-autocomplete.js +0 -85
  611. package/dist/test-tabbed-menu.d.ts +0 -7
  612. package/dist/test-tabbed-menu.js +0 -25
  613. package/dist/tool-selector.d.ts +0 -71
  614. package/dist/tool-selector.js +0 -184
  615. package/dist/ui/agents-overlay.d.ts +0 -12
  616. package/dist/ui/agents-overlay.js +0 -501
  617. package/dist/ui/arch-type-overlay.d.ts +0 -20
  618. package/dist/ui/arch-type-overlay.js +0 -229
  619. package/dist/ui/backlog-overlay.d.ts +0 -17
  620. package/dist/ui/backlog-overlay.js +0 -786
  621. package/dist/ui/commands-overlay.d.ts +0 -11
  622. package/dist/ui/commands-overlay.js +0 -410
  623. package/dist/ui/config-overlay.d.ts +0 -34
  624. package/dist/ui/config-overlay.js +0 -977
  625. package/dist/ui/init-overlay.d.ts +0 -24
  626. package/dist/ui/init-overlay.js +0 -525
  627. package/dist/ui/input-prompt-v2.d.ts +0 -179
  628. package/dist/ui/input-prompt-v2.js +0 -991
  629. package/dist/ui/model-warning-overlay.d.ts +0 -30
  630. package/dist/ui/model-warning-overlay.js +0 -171
  631. package/dist/ui/tools-overlay.d.ts +0 -26
  632. package/dist/ui/tools-overlay.js +0 -278
  633. package/dist/ui/tutorial-overlay.d.ts +0 -10
  634. package/dist/ui/tutorial-overlay.js +0 -936
@@ -0,0 +1,1112 @@
1
+ /**
2
+ * Document Detail Overlay V2
3
+ *
4
+ * Fullscreen markdown document viewer AND editor with vim-style navigation.
5
+ * Separate from DocsOverlayV2 (inline list) to allow proper fullscreen rendering.
6
+ *
7
+ * Features:
8
+ * - Full-screen document viewing with markdown rendering
9
+ * - Vim-style navigation (j/k, g/G, PgUp/PgDn)
10
+ * - Edit mode with raw markdown editing
11
+ * - Save to database (Ctrl+S)
12
+ * - Dirty check with save prompt on exit
13
+ */
14
+ import chalk from 'chalk';
15
+ import hljs from 'highlight.js';
16
+ // =============================================================================
17
+ // Alternate Screen Buffer Management
18
+ // =============================================================================
19
+ let inAlternateScreen = false;
20
+ function enterAlternateScreen() {
21
+ if (inAlternateScreen)
22
+ return;
23
+ process.stdout.write('\x1b[?1049h'); // Switch to alternate screen
24
+ process.stdout.write('\x1b[H'); // Move cursor to home
25
+ inAlternateScreen = true;
26
+ }
27
+ function exitAlternateScreen() {
28
+ if (!inAlternateScreen)
29
+ return;
30
+ process.stdout.write('\x1b[?1049l'); // Switch back to main screen
31
+ inAlternateScreen = false;
32
+ }
33
+ // Ensure we exit alternate screen on process termination
34
+ function setupAlternateScreenCleanup() {
35
+ const cleanup = () => {
36
+ exitAlternateScreen();
37
+ };
38
+ // Handle normal exit
39
+ process.on('exit', cleanup);
40
+ // Handle Ctrl+C
41
+ process.on('SIGINT', () => {
42
+ cleanup();
43
+ process.exit(130);
44
+ });
45
+ // Handle termination
46
+ process.on('SIGTERM', () => {
47
+ cleanup();
48
+ process.exit(143);
49
+ });
50
+ // Handle uncaught exceptions
51
+ process.on('uncaughtException', (err) => {
52
+ cleanup();
53
+ console.error('Uncaught exception:', err);
54
+ process.exit(1);
55
+ });
56
+ // Handle unhandled promise rejections
57
+ process.on('unhandledRejection', (reason) => {
58
+ cleanup();
59
+ console.error('Unhandled rejection:', reason);
60
+ process.exit(1);
61
+ });
62
+ }
63
+ // Setup cleanup handlers once when module loads
64
+ setupAlternateScreenCleanup();
65
+ import { marked } from 'marked';
66
+ import { markedTerminal } from 'marked-terminal';
67
+ import { BaseOverlayV2 } from '../../base/overlay-base-v2.js';
68
+ import { renderBorder, isCtrlC, isClose, isNavigateUp, isNavigateDown, isUpArrow, isDownArrow, isLeftArrow, isRightArrow, isHome, isEnd, isPageUp, isPageDown, isSpace, isBackspace, isDelete, isEnter, isTab, isEscape, isE, getPrintableChar, } from '../../base/index.js';
69
+ import { documentRepository } from '../../../db/repositories/document-repository.js';
70
+ import { planRepository } from '../../../db/repositories/plan-repository.js';
71
+ import { getCurrentTheme } from '../../../themes/index.js';
72
+ import * as terminal from '../../terminal.js';
73
+ import { DOC_TYPE_LABELS, PLAN_STATUS_LABELS, PLAN_STATUS_COLORS } from '../../constants/labels.js';
74
+ // =============================================================================
75
+ // Register Additional Languages for Syntax Highlighting
76
+ // =============================================================================
77
+ // Register aliases for common language names that map to existing languages
78
+ const languageAliases = {
79
+ // Shell variants → bash
80
+ 'sh': 'bash', 'zsh': 'bash', 'fish': 'bash',
81
+ 'console': 'bash', 'terminal': 'bash', 'command': 'bash',
82
+ // JSX/TSX → base language (highlighting won't be perfect but won't error)
83
+ 'jsx': 'javascript', 'tsx': 'typescript',
84
+ // HTML variants → xml
85
+ 'htm': 'xml', 'html': 'xml', 'vue': 'xml', 'svelte': 'xml', 'astro': 'xml',
86
+ // Plain text variants
87
+ 'text': 'plaintext', 'txt': 'plaintext', 'log': 'plaintext',
88
+ 'output': 'plaintext', 'result': 'plaintext',
89
+ 'gitignore': 'plaintext', 'dockerignore': 'plaintext', 'ignore': 'plaintext',
90
+ 'requirements': 'plaintext', 'csv': 'plaintext', 'tsv': 'plaintext',
91
+ // Diff variants
92
+ 'patch': 'diff',
93
+ // JSON variants
94
+ 'jsonc': 'json', 'json5': 'json', 'jsonl': 'json', 'ndjson': 'json',
95
+ // Config file variants → ini
96
+ 'conf': 'ini', 'config': 'ini', 'env': 'ini', 'dotenv': 'ini',
97
+ 'editorconfig': 'ini', 'toml': 'ini', 'pipfile': 'ini',
98
+ // Infrastructure as code (approximate)
99
+ 'tf': 'json', 'hcl': 'json', 'terraform': 'json',
100
+ };
101
+ for (const [alias, target] of Object.entries(languageAliases)) {
102
+ try {
103
+ hljs.registerAliases(alias, { languageName: target });
104
+ }
105
+ catch {
106
+ // Ignore if alias already exists
107
+ }
108
+ }
109
+ // Register custom language definitions for diagram/DSL languages
110
+ // Mermaid diagrams
111
+ hljs.registerLanguage('mermaid', () => ({
112
+ name: 'Mermaid',
113
+ case_insensitive: true,
114
+ keywords: {
115
+ keyword: 'graph subgraph end flowchart sequenceDiagram classDiagram stateDiagram erDiagram gantt pie journey gitGraph',
116
+ built_in: 'TD TB BT RL LR participant actor loop alt else opt par and critical break'
117
+ },
118
+ contains: [
119
+ hljs.QUOTE_STRING_MODE,
120
+ hljs.COMMENT('%%', '$'),
121
+ { className: 'operator', begin: /-->|--o|--x|<-->|---|->|<-|==>|==|-.->|-.-/ },
122
+ { className: 'string', begin: /\|/, end: /\|/ },
123
+ { className: 'title', begin: /\[/, end: /\]/ }
124
+ ]
125
+ }));
126
+ // PlantUML diagrams
127
+ hljs.registerLanguage('plantuml', () => ({
128
+ name: 'PlantUML',
129
+ case_insensitive: true,
130
+ keywords: {
131
+ keyword: 'startuml enduml participant actor usecase class interface abstract enum component package node database cloud frame folder rectangle',
132
+ built_in: 'left right up down over note end activate deactivate return'
133
+ },
134
+ contains: [
135
+ hljs.QUOTE_STRING_MODE,
136
+ hljs.COMMENT("'", '$'),
137
+ { className: 'operator', begin: /-->|->|<--|<-|\.\.>|<\.\.|--|-/ }
138
+ ]
139
+ }));
140
+ // GraphQL
141
+ hljs.registerLanguage('graphql', () => ({
142
+ name: 'GraphQL',
143
+ keywords: {
144
+ keyword: 'query mutation subscription fragment on type interface union enum scalar input extend implements directive',
145
+ literal: 'true false null'
146
+ },
147
+ contains: [
148
+ hljs.QUOTE_STRING_MODE,
149
+ hljs.HASH_COMMENT_MODE,
150
+ { className: 'variable', begin: /\$\w+/ },
151
+ { className: 'type', begin: /\b[A-Z]\w*\b/ }
152
+ ]
153
+ }));
154
+ hljs.registerAliases('gql', { languageName: 'graphql' });
155
+ // Graphviz DOT
156
+ hljs.registerLanguage('dot', () => ({
157
+ name: 'DOT',
158
+ keywords: {
159
+ keyword: 'graph digraph subgraph node edge strict',
160
+ built_in: 'shape label color style fillcolor fontcolor fontsize rankdir rank'
161
+ },
162
+ contains: [
163
+ hljs.QUOTE_STRING_MODE,
164
+ hljs.C_LINE_COMMENT_MODE,
165
+ hljs.C_BLOCK_COMMENT_MODE,
166
+ { className: 'operator', begin: /->|--/ }
167
+ ]
168
+ }));
169
+ hljs.registerAliases('graphviz', { languageName: 'dot' });
170
+ // =============================================================================
171
+ // Constants
172
+ // =============================================================================
173
+ // DOC_TYPE_LABELS, PLAN_STATUS_LABELS, PLAN_STATUS_COLORS imported from '../../constants/labels.js'
174
+ // Valid status transitions
175
+ const VALID_TRANSITIONS = {
176
+ draft: ['approved', 'abandoned'],
177
+ approved: ['in_progress', 'abandoned'],
178
+ in_progress: ['completed', 'abandoned'],
179
+ completed: [],
180
+ abandoned: ['draft'],
181
+ };
182
+ const TAB_SIZE = 2;
183
+ // =============================================================================
184
+ // Markdown Rendering
185
+ // =============================================================================
186
+ function getThemedMarkedOptions(termWidth) {
187
+ const theme = getCurrentTheme();
188
+ const primaryColor = chalk.hex(theme.colors.primary);
189
+ const secondaryColor = chalk.hex(theme.colors.secondary || theme.colors.primary);
190
+ const mutedColor = chalk.hex(theme.colors.muted);
191
+ const borderColor = chalk.hex(theme.colors.border);
192
+ const fgColor = chalk.hex(theme.colors.foreground);
193
+ return {
194
+ showSectionPrefix: false,
195
+ reflowText: false,
196
+ width: Math.min(100, termWidth - 4),
197
+ unescape: true,
198
+ tab: 2,
199
+ heading: primaryColor.bold,
200
+ firstHeading: primaryColor.bold,
201
+ strong: fgColor.bold,
202
+ em: fgColor.italic,
203
+ link: secondaryColor,
204
+ href: secondaryColor.underline,
205
+ blockquote: mutedColor.italic,
206
+ del: mutedColor.strikethrough,
207
+ hr: borderColor,
208
+ codespan: secondaryColor,
209
+ code: secondaryColor,
210
+ html: mutedColor,
211
+ table: fgColor,
212
+ listitem: fgColor,
213
+ paragraph: fgColor,
214
+ tableOptions: {
215
+ style: { head: ['bold'], border: [] },
216
+ chars: {
217
+ 'top': '─', 'top-mid': '─', 'top-left': '─', 'top-right': '─',
218
+ 'bottom': '─', 'bottom-mid': '─', 'bottom-left': '─', 'bottom-right': '─',
219
+ 'left': ' ', 'left-mid': ' ', 'mid': '─', 'mid-mid': '─',
220
+ 'right': ' ', 'right-mid': ' ', 'middle': ' ',
221
+ },
222
+ },
223
+ };
224
+ }
225
+ function preprocessMarkdown(content) {
226
+ const lines = content.split('\n');
227
+ return lines.map(line => /^(\s*)\* /.test(line) ? line.replace(/^(\s*)\* /, '$1- ') : line).join('\n');
228
+ }
229
+ function postProcessInlineFormatting(text) {
230
+ return text.replace(/\*\*([^*]+)\*\*/g, (_match, content) => chalk.bold(content));
231
+ }
232
+ function renderMarkdownSync(content, termWidth) {
233
+ const preprocessed = preprocessMarkdown(content);
234
+ const options = getThemedMarkedOptions(termWidth);
235
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
236
+ marked.use(markedTerminal(options));
237
+ const rendered = marked.parse(preprocessed, { async: false });
238
+ const postProcessed = postProcessInlineFormatting(rendered);
239
+ return postProcessed.split('\n');
240
+ }
241
+ // =============================================================================
242
+ // Edit Mode Syntax Highlighting
243
+ // =============================================================================
244
+ // Import cli-highlight for code block highlighting
245
+ import { highlight as cliHighlight, supportsLanguage } from 'cli-highlight';
246
+ /**
247
+ * Highlight a line, considering code block context.
248
+ * Returns the highlighted line and updated code block state.
249
+ */
250
+ function highlightEditLine(line, codeBlockState, theme) {
251
+ const secondary = chalk.hex(theme.colors.secondary || theme.colors.primary);
252
+ // Check for code fence start/end
253
+ const fenceMatch = line.match(/^(`{3,}|~{3,})(\w*)\s*$/);
254
+ if (fenceMatch) {
255
+ const [, fence, lang] = fenceMatch;
256
+ const fenceChar = fence[0];
257
+ const fenceLength = fence.length;
258
+ if (!codeBlockState.inCodeBlock) {
259
+ // Starting a code block
260
+ return {
261
+ highlighted: secondary(line),
262
+ newState: {
263
+ inCodeBlock: true,
264
+ language: lang || 'plaintext',
265
+ fenceChar,
266
+ fenceLength,
267
+ },
268
+ };
269
+ }
270
+ else if (fenceChar === codeBlockState.fenceChar && fenceLength >= codeBlockState.fenceLength) {
271
+ // Ending a code block (matching or longer fence)
272
+ return {
273
+ highlighted: secondary(line),
274
+ newState: { inCodeBlock: false, language: '', fenceChar: '', fenceLength: 0 },
275
+ };
276
+ }
277
+ }
278
+ // Inside a code block - apply language-specific highlighting
279
+ if (codeBlockState.inCodeBlock) {
280
+ return {
281
+ highlighted: highlightCodeLine(line, codeBlockState.language, theme),
282
+ newState: codeBlockState,
283
+ };
284
+ }
285
+ // Regular markdown line
286
+ return {
287
+ highlighted: highlightMarkdownLine(line, theme),
288
+ newState: codeBlockState,
289
+ };
290
+ }
291
+ /**
292
+ * Highlight a single line of code using cli-highlight.
293
+ */
294
+ function highlightCodeLine(line, language, theme) {
295
+ // Map language aliases to supported languages
296
+ const langMap = {
297
+ 'js': 'javascript',
298
+ 'ts': 'typescript',
299
+ 'py': 'python',
300
+ 'rb': 'ruby',
301
+ 'sh': 'bash',
302
+ 'shell': 'bash',
303
+ 'zsh': 'bash',
304
+ 'yml': 'yaml',
305
+ 'md': 'markdown',
306
+ 'jsx': 'javascript',
307
+ 'tsx': 'typescript',
308
+ 'mermaid': 'plaintext', // highlight.js handles via our custom registration
309
+ 'plantuml': 'plaintext',
310
+ 'graphql': 'graphql',
311
+ 'gql': 'graphql',
312
+ 'dot': 'plaintext',
313
+ 'graphviz': 'plaintext',
314
+ };
315
+ const mappedLang = langMap[language.toLowerCase()] || language.toLowerCase();
316
+ // Check if language is supported
317
+ if (!supportsLanguage(mappedLang) && mappedLang !== 'plaintext') {
318
+ // Fall back to plaintext styling for unsupported languages
319
+ const secondary = chalk.hex(theme.colors.secondary || theme.colors.primary);
320
+ return secondary(line);
321
+ }
322
+ try {
323
+ // cli-highlight for supported languages
324
+ if (mappedLang === 'plaintext') {
325
+ const secondary = chalk.hex(theme.colors.secondary || theme.colors.primary);
326
+ return secondary(line);
327
+ }
328
+ return cliHighlight(line, { language: mappedLang, ignoreIllegals: true });
329
+ }
330
+ catch {
331
+ // Fallback to secondary color on error
332
+ const secondary = chalk.hex(theme.colors.secondary || theme.colors.primary);
333
+ return secondary(line);
334
+ }
335
+ }
336
+ /**
337
+ * Apply syntax highlighting to a raw markdown line for edit mode.
338
+ * Shows the raw markdown characters with visual styling.
339
+ */
340
+ function highlightMarkdownLine(line, theme) {
341
+ const primary = chalk.hex(theme.colors.primary);
342
+ const secondary = chalk.hex(theme.colors.secondary || theme.colors.primary);
343
+ const muted = chalk.hex(theme.colors.muted);
344
+ // Empty line
345
+ if (!line.trim()) {
346
+ return line;
347
+ }
348
+ // Headers: # ## ### etc.
349
+ const headerMatch = line.match(/^(#{1,6})\s(.*)$/);
350
+ if (headerMatch) {
351
+ return primary(headerMatch[1]) + ' ' + primary.bold(headerMatch[2]);
352
+ }
353
+ // Blockquote: > text
354
+ const blockquoteMatch = line.match(/^(>\s*)(.*)$/);
355
+ if (blockquoteMatch) {
356
+ return muted(blockquoteMatch[1]) + muted.italic(blockquoteMatch[2]);
357
+ }
358
+ // Horizontal rule: --- or *** or ___
359
+ if (line.match(/^([-*_])\1{2,}\s*$/)) {
360
+ return muted(line);
361
+ }
362
+ // Unordered list: - or * or +
363
+ const ulMatch = line.match(/^(\s*)([-*+])\s+(.*)$/);
364
+ if (ulMatch) {
365
+ const [, indent, bullet, content] = ulMatch;
366
+ return indent + secondary(bullet) + ' ' + highlightInlineMarkdown(content, theme);
367
+ }
368
+ // Ordered list: 1. 2. etc.
369
+ const olMatch = line.match(/^(\s*)(\d+\.)\s+(.*)$/);
370
+ if (olMatch) {
371
+ const [, indent, num, content] = olMatch;
372
+ return indent + secondary(num) + ' ' + highlightInlineMarkdown(content, theme);
373
+ }
374
+ // Regular line - apply inline formatting
375
+ return highlightInlineMarkdown(line, theme);
376
+ }
377
+ /**
378
+ * Apply inline markdown highlighting (bold, italic, code, links).
379
+ */
380
+ function highlightInlineMarkdown(text, theme) {
381
+ const primary = chalk.hex(theme.colors.primary);
382
+ const secondary = chalk.hex(theme.colors.secondary || theme.colors.primary);
383
+ const muted = chalk.hex(theme.colors.muted);
384
+ const fg = chalk.hex(theme.colors.foreground);
385
+ let result = text;
386
+ // Images first (before links): ![alt](url)
387
+ result = result.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (_match, alt, url) => {
388
+ return muted('![') + fg(alt) + muted('](') + secondary(url) + muted(')');
389
+ });
390
+ // Links: [text](url)
391
+ result = result.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_match, linkText, url) => {
392
+ return muted('[') + primary(linkText) + muted('](') + secondary(url) + muted(')');
393
+ });
394
+ // Inline code: `code` (must be before bold/italic to avoid conflicts)
395
+ result = result.replace(/`([^`]+)`/g, (_match, code) => {
396
+ return muted('`') + secondary(code) + muted('`');
397
+ });
398
+ // Bold: **text** or __text__
399
+ result = result.replace(/(\*\*|__)(.+?)\1/g, (_match, marker, content) => {
400
+ return muted(marker) + fg.bold(content) + muted(marker);
401
+ });
402
+ // Italic: *text* or _text_
403
+ result = result.replace(/(\*|_)(.+?)\1/g, (_match, marker, content) => {
404
+ return muted(marker) + fg.italic(content) + muted(marker);
405
+ });
406
+ return result;
407
+ }
408
+ // =============================================================================
409
+ // Key Detection Helpers (local functions not in ui-core)
410
+ // =============================================================================
411
+ // Most key detection functions are imported from '../../base/index.js'.
412
+ // Only custom/specialized ones are defined locally here.
413
+ function isCtrlS(data) {
414
+ return data.length === 1 && data[0] === 0x13;
415
+ }
416
+ function isEditKey(data) {
417
+ // Check if 'e' or 'i' key is pressed (to enter edit mode)
418
+ return isE(data) || (data.length === 1 && data[0] === 0x69); // 'i' = 0x69
419
+ }
420
+ // =============================================================================
421
+ // Document Detail Overlay V2
422
+ // =============================================================================
423
+ /**
424
+ * Fullscreen document viewer and editor overlay.
425
+ * Shows a single document with vim-style scrolling navigation.
426
+ * Supports edit mode for modifying raw markdown content.
427
+ */
428
+ export class DocumentDetailOverlayV2 extends BaseOverlayV2 {
429
+ document;
430
+ // Use 'inline' type so terminal-ui doesn't clear screen - we manage alternate screen ourselves
431
+ type = 'inline';
432
+ id = 'document-detail-overlay-v2';
433
+ // Tell terminal-ui we manage our own screen buffer - skip clearing on close
434
+ usesAlternateScreen = true;
435
+ constructor(document) {
436
+ // Initialize state with rendered markdown
437
+ const termWidth = terminal.getTerminalWidth();
438
+ const contentLines = renderMarkdownSync(document.content, termWidth);
439
+ const rawLines = document.content.split('\n');
440
+ // Initialize plan-specific state
441
+ const isPlan = document.docType === 'plan';
442
+ const planStatus = isPlan ? document.status ?? 'draft' : null;
443
+ const availableStatuses = planStatus ? VALID_TRANSITIONS[planStatus] : [];
444
+ super({
445
+ contentLines,
446
+ scrollOffset: 0,
447
+ isEditMode: false,
448
+ rawLines,
449
+ cursorLine: 0,
450
+ cursorColumn: 0,
451
+ editScrollOffset: 0,
452
+ isDirty: false,
453
+ originalContent: document.content,
454
+ showSavePrompt: false,
455
+ saveMessage: null,
456
+ planStatus,
457
+ showStatusMenu: false,
458
+ statusMenuIndex: 0,
459
+ availableStatuses,
460
+ });
461
+ this.document = document;
462
+ }
463
+ /**
464
+ * Enter alternate screen buffer when overlay mounts.
465
+ * This preserves the main screen content.
466
+ */
467
+ onMount() {
468
+ enterAlternateScreen();
469
+ }
470
+ /**
471
+ * Exit alternate screen buffer when overlay unmounts.
472
+ * This restores the main screen content.
473
+ */
474
+ onUnmount() {
475
+ exitAlternateScreen();
476
+ }
477
+ renderContent(context) {
478
+ if (this.state.isEditMode) {
479
+ return this.renderEditMode(context);
480
+ }
481
+ return this.renderViewMode(context);
482
+ }
483
+ // ===========================================================================
484
+ // View Mode Rendering
485
+ // ===========================================================================
486
+ renderViewMode(context) {
487
+ const s = context.styles;
488
+ const cols = context.width;
489
+ const rows = context.height;
490
+ const border = renderBorder(cols, s);
491
+ const lines = [];
492
+ // Header
493
+ const typeLabel = DOC_TYPE_LABELS[this.document.docType] || this.document.docType.toUpperCase();
494
+ lines.push(border);
495
+ // For plans, show status in header
496
+ if (this.state.planStatus) {
497
+ const statusLabel = PLAN_STATUS_LABELS[this.state.planStatus];
498
+ const statusColor = PLAN_STATUS_COLORS[this.state.planStatus];
499
+ const styledStatus = s[statusColor](statusLabel);
500
+ lines.push(` ${s.primaryBold(typeLabel)}${s.muted(' │ ')}${chalk.bold(this.document.title)} ${styledStatus}`);
501
+ }
502
+ else {
503
+ lines.push(` ${s.primaryBold(typeLabel)}${s.muted(' │ ')}${chalk.bold(this.document.title)}`);
504
+ }
505
+ lines.push(border);
506
+ // Calculate content area
507
+ const headerLines = 3;
508
+ const footerLines = 3;
509
+ const contentHeight = rows - headerLines - footerLines;
510
+ // Get visible lines
511
+ const totalLines = this.state.contentLines.length;
512
+ const visibleLines = [];
513
+ let physicalLinesUsed = 0;
514
+ for (let i = this.state.scrollOffset; i < totalLines && physicalLinesUsed < contentHeight; i++) {
515
+ const line = this.state.contentLines[i];
516
+ // eslint-disable-next-line no-control-regex
517
+ const visualLen = line.replace(/\x1b\[[0-9;]*m/g, '').length;
518
+ const linePhysicalHeight = Math.max(1, Math.ceil(visualLen / cols));
519
+ if (physicalLinesUsed + linePhysicalHeight <= contentHeight) {
520
+ visibleLines.push(line);
521
+ physicalLinesUsed += linePhysicalHeight;
522
+ }
523
+ else {
524
+ break;
525
+ }
526
+ }
527
+ // Content
528
+ for (const line of visibleLines) {
529
+ lines.push(line);
530
+ }
531
+ // Pad remaining space
532
+ for (let i = physicalLinesUsed; i < contentHeight; i++) {
533
+ lines.push('');
534
+ }
535
+ // Footer with position info
536
+ const canScrollUp = this.state.scrollOffset > 0;
537
+ const canScrollDown = this.state.scrollOffset + contentHeight < totalLines;
538
+ const arrows = (canScrollUp ? '▲' : ' ') + (canScrollDown ? '▼' : ' ');
539
+ const position = totalLines > 0
540
+ ? `Line ${String(this.state.scrollOffset + 1)}-${String(Math.min(this.state.scrollOffset + contentHeight, totalLines))} of ${String(totalLines)}`
541
+ : '';
542
+ const scrollPercent = totalLines > contentHeight
543
+ ? Math.round(((this.state.scrollOffset + contentHeight) / totalLines) * 100)
544
+ : 100;
545
+ lines.push(border);
546
+ // Show status menu if open
547
+ if (this.state.showStatusMenu && this.state.availableStatuses.length > 0) {
548
+ const statusOptions = this.state.availableStatuses.map((status, idx) => {
549
+ const label = PLAN_STATUS_LABELS[status];
550
+ return idx === this.state.statusMenuIndex ? s.primary(`[${label}]`) : s.muted(label);
551
+ }).join(' ');
552
+ lines.push(s.warning(' Change status: ') + statusOptions + s.muted(' ↑↓ Select · Enter Confirm · Esc Cancel'));
553
+ }
554
+ else {
555
+ // Normal footer with plan-specific hint
556
+ const planHint = this.state.planStatus && this.state.availableStatuses.length > 0 ? ' · s Status' : '';
557
+ lines.push(s.muted(` ${arrows} ${position} (${String(scrollPercent)}%) ↑↓/jk Scroll · e/i Edit${planHint} · q/Esc Back`));
558
+ }
559
+ lines.push(border);
560
+ return lines;
561
+ }
562
+ // ===========================================================================
563
+ // Edit Mode Rendering
564
+ // ===========================================================================
565
+ renderEditMode(context) {
566
+ const s = context.styles;
567
+ const cols = context.width;
568
+ const rows = context.height;
569
+ const border = renderBorder(cols, s);
570
+ const lines = [];
571
+ // Header with [EDIT] indicator
572
+ const typeLabel = DOC_TYPE_LABELS[this.document.docType] || this.document.docType.toUpperCase();
573
+ const editIndicator = this.state.isDirty ? s.warning('[EDIT*]') : s.primary('[EDIT]');
574
+ lines.push(border);
575
+ lines.push(` ${s.primaryBold(typeLabel)}${s.muted(' │ ')}${chalk.bold(this.document.title)} ${editIndicator}`);
576
+ lines.push(border);
577
+ // Calculate content area
578
+ const headerLines = 3;
579
+ const footerLines = 3;
580
+ const contentHeight = rows - headerLines - footerLines;
581
+ // Ensure cursor is visible (adjust scroll if needed)
582
+ this.ensureCursorVisible(contentHeight);
583
+ // Get visible lines with line numbers
584
+ const totalLines = this.state.rawLines.length;
585
+ const lineNumWidth = String(totalLines).length + 1;
586
+ // Get current theme for syntax highlighting
587
+ const theme = getCurrentTheme();
588
+ // Pre-compute code block state for all lines up to and including visible area
589
+ // This ensures we know if we're inside a code block when rendering
590
+ let codeBlockState = { inCodeBlock: false, language: '', fenceChar: '', fenceLength: 0 };
591
+ const lineStates = [];
592
+ for (let i = 0; i < totalLines; i++) {
593
+ const line = this.state.rawLines[i];
594
+ // Check for code fence (we only need to track state, not highlight)
595
+ const fenceMatch = line.match(/^(`{3,}|~{3,})(\w*)\s*$/);
596
+ if (fenceMatch) {
597
+ const [, fence, lang] = fenceMatch;
598
+ const fenceChar = fence[0];
599
+ const fenceLength = fence.length;
600
+ if (!codeBlockState.inCodeBlock) {
601
+ codeBlockState = { inCodeBlock: true, language: lang || 'plaintext', fenceChar, fenceLength };
602
+ }
603
+ else if (fenceChar === codeBlockState.fenceChar && fenceLength >= codeBlockState.fenceLength) {
604
+ codeBlockState = { inCodeBlock: false, language: '', fenceChar: '', fenceLength: 0 };
605
+ }
606
+ }
607
+ lineStates[i] = { ...codeBlockState };
608
+ }
609
+ for (let i = 0; i < contentHeight; i++) {
610
+ const lineIndex = this.state.editScrollOffset + i;
611
+ if (lineIndex < totalLines) {
612
+ const lineNum = String(lineIndex + 1).padStart(lineNumWidth);
613
+ const lineContent = this.state.rawLines[lineIndex];
614
+ const isCursorLine = lineIndex === this.state.cursorLine;
615
+ // Render line with cursor if this is the cursor line (no highlighting for accurate positioning)
616
+ if (isCursorLine) {
617
+ const renderedLine = this.renderLineWithCursor(lineContent, this.state.cursorColumn, cols - lineNumWidth - 2);
618
+ lines.push(s.muted(`${lineNum}│`) + renderedLine);
619
+ }
620
+ else {
621
+ // Apply syntax highlighting to non-cursor lines
622
+ const maxLen = cols - lineNumWidth - 2;
623
+ const truncated = lineContent.length > maxLen;
624
+ const displayContent = truncated
625
+ ? lineContent.slice(0, maxLen - 1)
626
+ : lineContent;
627
+ // Get the state BEFORE this line to know if we're inside a code block
628
+ const prevState = lineIndex > 0 ? lineStates[lineIndex - 1] : { inCodeBlock: false, language: '', fenceChar: '', fenceLength: 0 };
629
+ const { highlighted } = highlightEditLine(displayContent, prevState, theme);
630
+ lines.push(s.muted(`${lineNum}│`) + highlighted + (truncated ? s.muted('…') : ''));
631
+ }
632
+ }
633
+ else {
634
+ // Empty line beyond document
635
+ const lineNum = ' '.repeat(lineNumWidth);
636
+ lines.push(s.muted(`${lineNum}│`) + s.muted('~'));
637
+ }
638
+ }
639
+ // Footer
640
+ lines.push(border);
641
+ if (this.state.showSavePrompt) {
642
+ // Save prompt
643
+ lines.push(s.warning(' Unsaved changes. Save? ') + s.primary('(y)') + 'es / ' + s.primary('(n)') + 'o / ' + s.primary('(c)') + 'ancel');
644
+ }
645
+ else if (this.state.saveMessage) {
646
+ // Brief save message
647
+ lines.push(s.success(` ${this.state.saveMessage}`));
648
+ }
649
+ else {
650
+ // Normal edit mode footer
651
+ const cursorPos = `Ln ${String(this.state.cursorLine + 1)}, Col ${String(this.state.cursorColumn + 1)}`;
652
+ const modifiedIndicator = this.state.isDirty ? s.warning('[modified]') : '';
653
+ lines.push(s.primaryBold(' ── INSERT ── ') + s.muted(cursorPos) + ' ' + modifiedIndicator + s.muted(' Ctrl+S Save · Esc Exit'));
654
+ }
655
+ lines.push(border);
656
+ return lines;
657
+ }
658
+ renderLineWithCursor(line, cursorCol, maxLen) {
659
+ const theme = getCurrentTheme();
660
+ const cursorStyle = chalk.inverse;
661
+ // Handle cursor beyond line end
662
+ const effectiveCursorCol = Math.min(cursorCol, line.length);
663
+ // Calculate visible portion
664
+ let viewStart = 0;
665
+ if (effectiveCursorCol >= maxLen - 5) {
666
+ viewStart = effectiveCursorCol - maxLen + 10;
667
+ }
668
+ viewStart = Math.max(0, viewStart);
669
+ const viewEnd = viewStart + maxLen;
670
+ const visibleLine = line.slice(viewStart, viewEnd);
671
+ const cursorPosInView = effectiveCursorCol - viewStart;
672
+ // Build the line with cursor
673
+ let result = '';
674
+ for (let i = 0; i < visibleLine.length; i++) {
675
+ if (i === cursorPosInView) {
676
+ result += cursorStyle(visibleLine[i]);
677
+ }
678
+ else {
679
+ result += visibleLine[i];
680
+ }
681
+ }
682
+ // If cursor is at end of line (or beyond), show cursor as block
683
+ if (cursorPosInView >= visibleLine.length) {
684
+ result += cursorStyle(' ');
685
+ }
686
+ // Add truncation indicator
687
+ if (viewStart > 0) {
688
+ result = chalk.hex(theme.colors.muted)('…') + result.slice(1);
689
+ }
690
+ if (line.length > viewEnd) {
691
+ result = result.slice(0, -1) + chalk.hex(theme.colors.muted)('…');
692
+ }
693
+ return result;
694
+ }
695
+ ensureCursorVisible(contentHeight) {
696
+ // Scroll up if cursor is above visible area
697
+ if (this.state.cursorLine < this.state.editScrollOffset) {
698
+ this.state.editScrollOffset = this.state.cursorLine;
699
+ }
700
+ // Scroll down if cursor is below visible area
701
+ if (this.state.cursorLine >= this.state.editScrollOffset + contentHeight) {
702
+ this.state.editScrollOffset = this.state.cursorLine - contentHeight + 1;
703
+ }
704
+ }
705
+ // ===========================================================================
706
+ // Key Handling
707
+ // ===========================================================================
708
+ handleKey(key) {
709
+ const data = key.raw;
710
+ // Handle save prompt state
711
+ if (this.state.showSavePrompt) {
712
+ return this.handleSavePromptKey(data);
713
+ }
714
+ // Handle status menu
715
+ if (this.state.showStatusMenu) {
716
+ return this.handleStatusMenuKey(data);
717
+ }
718
+ // Handle edit mode
719
+ if (this.state.isEditMode) {
720
+ return this.handleEditModeKey(data);
721
+ }
722
+ // Handle view mode
723
+ return this.handleViewModeKey(data);
724
+ }
725
+ // ===========================================================================
726
+ // View Mode Key Handling
727
+ // ===========================================================================
728
+ handleViewModeKey(data) {
729
+ const char = getPrintableChar(data);
730
+ const keyStr = data.toString();
731
+ const rows = terminal.getTerminalHeight();
732
+ const contentHeight = rows - 6;
733
+ const totalLines = this.state.contentLines.length;
734
+ const maxScroll = Math.max(0, totalLines - contentHeight);
735
+ // Ctrl+C closes everything (no going back)
736
+ if (isCtrlC(data)) {
737
+ return this.close({ goBack: false });
738
+ }
739
+ // Escape or q - go back to list
740
+ if (isClose(data)) {
741
+ return this.close({ goBack: true });
742
+ }
743
+ // e or i - enter edit mode
744
+ if (isEditKey(data)) {
745
+ this.state.isEditMode = true;
746
+ this.state.cursorLine = 0;
747
+ this.state.cursorColumn = 0;
748
+ this.state.editScrollOffset = 0;
749
+ this.state.saveMessage = null;
750
+ return this.rerender();
751
+ }
752
+ // s - open status menu (plans only)
753
+ if (char === 's' && this.state.planStatus && this.state.availableStatuses.length > 0) {
754
+ this.state.showStatusMenu = true;
755
+ this.state.statusMenuIndex = 0;
756
+ return this.rerender();
757
+ }
758
+ // Up / k
759
+ if (isNavigateUp(data)) {
760
+ if (this.state.scrollOffset > 0) {
761
+ this.state.scrollOffset--;
762
+ return this.rerender();
763
+ }
764
+ return this.noAction();
765
+ }
766
+ // Down / j
767
+ if (isNavigateDown(data)) {
768
+ if (this.state.scrollOffset < maxScroll) {
769
+ this.state.scrollOffset++;
770
+ return this.rerender();
771
+ }
772
+ return this.noAction();
773
+ }
774
+ // Page Up
775
+ if (keyStr === '\x1b[5~') {
776
+ this.state.scrollOffset = Math.max(0, this.state.scrollOffset - contentHeight);
777
+ return this.rerender();
778
+ }
779
+ // Page Down / Space
780
+ if (keyStr === '\x1b[6~' || isSpace(data)) {
781
+ this.state.scrollOffset = Math.min(maxScroll, this.state.scrollOffset + contentHeight);
782
+ return this.rerender();
783
+ }
784
+ // g = top
785
+ if (char === 'g') {
786
+ this.state.scrollOffset = 0;
787
+ return this.rerender();
788
+ }
789
+ // G = bottom
790
+ if (char === 'G') {
791
+ this.state.scrollOffset = maxScroll;
792
+ return this.rerender();
793
+ }
794
+ // Home
795
+ if (keyStr === '\x1b[H') {
796
+ this.state.scrollOffset = 0;
797
+ return this.rerender();
798
+ }
799
+ // End
800
+ if (keyStr === '\x1b[F') {
801
+ this.state.scrollOffset = maxScroll;
802
+ return this.rerender();
803
+ }
804
+ return this.noAction();
805
+ }
806
+ // ===========================================================================
807
+ // Edit Mode Key Handling
808
+ // ===========================================================================
809
+ handleEditModeKey(data) {
810
+ // Clear save message on any key
811
+ if (this.state.saveMessage) {
812
+ this.state.saveMessage = null;
813
+ }
814
+ // Ctrl+C - exit immediately without saving
815
+ if (isCtrlC(data)) {
816
+ return this.close({ goBack: false });
817
+ }
818
+ // Ctrl+S - save
819
+ if (isCtrlS(data)) {
820
+ this.saveDocument();
821
+ return this.rerender();
822
+ }
823
+ // Escape - exit edit mode (prompt if dirty)
824
+ if (isEscape(data)) {
825
+ if (this.state.isDirty) {
826
+ this.state.showSavePrompt = true;
827
+ return this.rerender();
828
+ }
829
+ // Exit edit mode, re-render markdown
830
+ return this.exitEditMode();
831
+ }
832
+ // Navigation
833
+ if (isUpArrow(data)) {
834
+ return this.moveCursorUp();
835
+ }
836
+ if (isDownArrow(data)) {
837
+ return this.moveCursorDown();
838
+ }
839
+ if (isLeftArrow(data)) {
840
+ return this.moveCursorLeft();
841
+ }
842
+ if (isRightArrow(data)) {
843
+ return this.moveCursorRight();
844
+ }
845
+ if (isHome(data)) {
846
+ this.state.cursorColumn = 0;
847
+ return this.rerender();
848
+ }
849
+ if (isEnd(data)) {
850
+ this.state.cursorColumn = this.getCurrentLine().length;
851
+ return this.rerender();
852
+ }
853
+ if (isPageUp(data)) {
854
+ const rows = terminal.getTerminalHeight();
855
+ const pageSize = rows - 6;
856
+ this.state.cursorLine = Math.max(0, this.state.cursorLine - pageSize);
857
+ this.clampCursorColumn();
858
+ return this.rerender();
859
+ }
860
+ if (isPageDown(data)) {
861
+ const rows = terminal.getTerminalHeight();
862
+ const pageSize = rows - 6;
863
+ this.state.cursorLine = Math.min(this.state.rawLines.length - 1, this.state.cursorLine + pageSize);
864
+ this.clampCursorColumn();
865
+ return this.rerender();
866
+ }
867
+ // Editing
868
+ if (isBackspace(data)) {
869
+ return this.handleBackspace();
870
+ }
871
+ if (isDelete(data)) {
872
+ return this.handleDelete();
873
+ }
874
+ if (isEnter(data)) {
875
+ return this.handleEnter();
876
+ }
877
+ if (isTab(data)) {
878
+ return this.insertText(' '.repeat(TAB_SIZE));
879
+ }
880
+ // Printable characters
881
+ const char = getPrintableChar(data);
882
+ if (char) {
883
+ return this.insertText(char);
884
+ }
885
+ return this.noAction();
886
+ }
887
+ // ===========================================================================
888
+ // Save Prompt Key Handling
889
+ // ===========================================================================
890
+ handleSavePromptKey(data) {
891
+ const char = getPrintableChar(data);
892
+ // y = save and exit edit mode
893
+ if (char === 'y' || char === 'Y') {
894
+ this.saveDocument();
895
+ this.state.showSavePrompt = false;
896
+ return this.exitEditMode();
897
+ }
898
+ // n = discard and exit edit mode
899
+ if (char === 'n' || char === 'N') {
900
+ // Revert to original content
901
+ this.state.rawLines = this.state.originalContent.split('\n');
902
+ this.state.isDirty = false;
903
+ this.state.showSavePrompt = false;
904
+ return this.exitEditMode();
905
+ }
906
+ // c or Escape = cancel, stay in edit mode
907
+ if (char === 'c' || char === 'C' || isEscape(data)) {
908
+ this.state.showSavePrompt = false;
909
+ return this.rerender();
910
+ }
911
+ // Ctrl+C = exit everything
912
+ if (isCtrlC(data)) {
913
+ return this.close({ goBack: false });
914
+ }
915
+ return this.noAction();
916
+ }
917
+ // ===========================================================================
918
+ // Status Menu Key Handling (Plans only)
919
+ // ===========================================================================
920
+ handleStatusMenuKey(data) {
921
+ // Ctrl+C closes everything
922
+ if (isCtrlC(data)) {
923
+ return this.close({ goBack: false });
924
+ }
925
+ // Escape - close status menu
926
+ if (isEscape(data)) {
927
+ this.state.showStatusMenu = false;
928
+ return this.rerender();
929
+ }
930
+ // Up arrow - previous status
931
+ if (isUpArrow(data)) {
932
+ if (this.state.statusMenuIndex > 0) {
933
+ this.state.statusMenuIndex--;
934
+ return this.rerender();
935
+ }
936
+ return this.noAction();
937
+ }
938
+ // Down arrow - next status
939
+ if (isDownArrow(data)) {
940
+ if (this.state.statusMenuIndex < this.state.availableStatuses.length - 1) {
941
+ this.state.statusMenuIndex++;
942
+ return this.rerender();
943
+ }
944
+ return this.noAction();
945
+ }
946
+ // Enter - confirm status change
947
+ if (isEnter(data)) {
948
+ const newStatus = this.state.availableStatuses[this.state.statusMenuIndex];
949
+ return this.changeStatus(newStatus);
950
+ }
951
+ return this.noAction();
952
+ }
953
+ changeStatus(newStatus) {
954
+ try {
955
+ // Update the plan status in the database
956
+ planRepository.update(this.document.id, { status: newStatus });
957
+ // Update local state
958
+ this.state.planStatus = newStatus;
959
+ this.state.availableStatuses = VALID_TRANSITIONS[newStatus];
960
+ this.state.showStatusMenu = false;
961
+ this.state.statusMenuIndex = 0;
962
+ // Also update the document's status field for consistency
963
+ this.document.status = newStatus;
964
+ return this.rerender();
965
+ }
966
+ catch {
967
+ // On error, just close the menu
968
+ this.state.showStatusMenu = false;
969
+ return this.rerender();
970
+ }
971
+ }
972
+ // ===========================================================================
973
+ // Cursor Movement
974
+ // ===========================================================================
975
+ moveCursorUp() {
976
+ if (this.state.cursorLine > 0) {
977
+ this.state.cursorLine--;
978
+ this.clampCursorColumn();
979
+ }
980
+ return this.rerender();
981
+ }
982
+ moveCursorDown() {
983
+ if (this.state.cursorLine < this.state.rawLines.length - 1) {
984
+ this.state.cursorLine++;
985
+ this.clampCursorColumn();
986
+ }
987
+ return this.rerender();
988
+ }
989
+ moveCursorLeft() {
990
+ if (this.state.cursorColumn > 0) {
991
+ this.state.cursorColumn--;
992
+ }
993
+ else if (this.state.cursorLine > 0) {
994
+ // Wrap to end of previous line
995
+ this.state.cursorLine--;
996
+ this.state.cursorColumn = this.getCurrentLine().length;
997
+ }
998
+ return this.rerender();
999
+ }
1000
+ moveCursorRight() {
1001
+ const lineLen = this.getCurrentLine().length;
1002
+ if (this.state.cursorColumn < lineLen) {
1003
+ this.state.cursorColumn++;
1004
+ }
1005
+ else if (this.state.cursorLine < this.state.rawLines.length - 1) {
1006
+ // Wrap to start of next line
1007
+ this.state.cursorLine++;
1008
+ this.state.cursorColumn = 0;
1009
+ }
1010
+ return this.rerender();
1011
+ }
1012
+ clampCursorColumn() {
1013
+ const lineLen = this.getCurrentLine().length;
1014
+ this.state.cursorColumn = Math.min(this.state.cursorColumn, lineLen);
1015
+ }
1016
+ getCurrentLine() {
1017
+ return this.state.rawLines[this.state.cursorLine] || '';
1018
+ }
1019
+ // ===========================================================================
1020
+ // Text Editing
1021
+ // ===========================================================================
1022
+ insertText(text) {
1023
+ const line = this.getCurrentLine();
1024
+ const before = line.slice(0, this.state.cursorColumn);
1025
+ const after = line.slice(this.state.cursorColumn);
1026
+ this.state.rawLines[this.state.cursorLine] = before + text + after;
1027
+ this.state.cursorColumn += text.length;
1028
+ this.state.isDirty = true;
1029
+ return this.rerender();
1030
+ }
1031
+ handleBackspace() {
1032
+ if (this.state.cursorColumn > 0) {
1033
+ // Delete character before cursor
1034
+ const line = this.getCurrentLine();
1035
+ const before = line.slice(0, this.state.cursorColumn - 1);
1036
+ const after = line.slice(this.state.cursorColumn);
1037
+ this.state.rawLines[this.state.cursorLine] = before + after;
1038
+ this.state.cursorColumn--;
1039
+ this.state.isDirty = true;
1040
+ }
1041
+ else if (this.state.cursorLine > 0) {
1042
+ // Join with previous line
1043
+ const currentLine = this.getCurrentLine();
1044
+ const prevLine = this.state.rawLines[this.state.cursorLine - 1];
1045
+ this.state.rawLines[this.state.cursorLine - 1] = prevLine + currentLine;
1046
+ this.state.rawLines.splice(this.state.cursorLine, 1);
1047
+ this.state.cursorLine--;
1048
+ this.state.cursorColumn = prevLine.length;
1049
+ this.state.isDirty = true;
1050
+ }
1051
+ return this.rerender();
1052
+ }
1053
+ handleDelete() {
1054
+ const line = this.getCurrentLine();
1055
+ if (this.state.cursorColumn < line.length) {
1056
+ // Delete character at cursor
1057
+ const before = line.slice(0, this.state.cursorColumn);
1058
+ const after = line.slice(this.state.cursorColumn + 1);
1059
+ this.state.rawLines[this.state.cursorLine] = before + after;
1060
+ this.state.isDirty = true;
1061
+ }
1062
+ else if (this.state.cursorLine < this.state.rawLines.length - 1) {
1063
+ // Join with next line
1064
+ const nextLine = this.state.rawLines[this.state.cursorLine + 1];
1065
+ this.state.rawLines[this.state.cursorLine] = line + nextLine;
1066
+ this.state.rawLines.splice(this.state.cursorLine + 1, 1);
1067
+ this.state.isDirty = true;
1068
+ }
1069
+ return this.rerender();
1070
+ }
1071
+ handleEnter() {
1072
+ const line = this.getCurrentLine();
1073
+ const before = line.slice(0, this.state.cursorColumn);
1074
+ const after = line.slice(this.state.cursorColumn);
1075
+ this.state.rawLines[this.state.cursorLine] = before;
1076
+ this.state.rawLines.splice(this.state.cursorLine + 1, 0, after);
1077
+ this.state.cursorLine++;
1078
+ this.state.cursorColumn = 0;
1079
+ this.state.isDirty = true;
1080
+ return this.rerender();
1081
+ }
1082
+ // ===========================================================================
1083
+ // Save and Exit
1084
+ // ===========================================================================
1085
+ saveDocument() {
1086
+ const content = this.state.rawLines.join('\n');
1087
+ try {
1088
+ documentRepository.update(this.document.id, { content });
1089
+ this.state.originalContent = content;
1090
+ this.state.isDirty = false;
1091
+ this.state.saveMessage = 'Saved!';
1092
+ // Clear message after a delay (will be cleared on next keypress anyway)
1093
+ setTimeout(() => {
1094
+ if (this.state.saveMessage === 'Saved!') {
1095
+ this.state.saveMessage = null;
1096
+ }
1097
+ }, 2000);
1098
+ }
1099
+ catch (error) {
1100
+ this.state.saveMessage = `Error: ${error.message}`;
1101
+ }
1102
+ }
1103
+ exitEditMode() {
1104
+ this.state.isEditMode = false;
1105
+ // Re-render markdown from current content
1106
+ const content = this.state.rawLines.join('\n');
1107
+ const termWidth = terminal.getTerminalWidth();
1108
+ this.state.contentLines = renderMarkdownSync(content, termWidth);
1109
+ this.state.scrollOffset = 0;
1110
+ return this.rerender();
1111
+ }
1112
+ }