@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
package/dist/ui/footer.js CHANGED
@@ -1,23 +1,32 @@
1
1
  /**
2
+ * @deprecated DEAD CODE — This class is never instantiated. Do NOT modify this file.
3
+ *
4
+ * The active footer/render pipeline is in TerminalUI (src/ui/terminal-ui.ts).
5
+ * TerminalUI has its own inline render loop with numbered sections (1-8),
6
+ * status bar items, mode indicator, etc. All footer changes should go there.
7
+ *
8
+ * This file is kept only because it is type-imported by terminal-renderer.ts
9
+ * and memory-handler.ts. It can be safely deleted once those imports are removed.
10
+ *
11
+ * --- Original description ---
2
12
  * Footer Orchestrator
3
13
  *
4
14
  * Manages all persistent UI elements below the scrolling zone:
5
15
  * - TodoZone (spinner + todo list)
6
16
  * - Queued input display
7
17
  * - InputPrompt
8
- *
9
- * Handles:
10
- * - Coordinated rendering via single render loop
11
- * - Event forwarding from InputPrompt
12
- * - Clearing for scrolling output
13
- * - State management for agent running/idle modes
14
18
  */
15
19
  import { EventEmitter } from 'events';
16
20
  import { MODE_INFO } from './types.js';
17
21
  import { getStyles } from '../themes/index.js';
18
22
  import * as terminal from './terminal.js';
19
23
  import { TodoZone } from './todo-zone.js';
20
- import { InputPrompt, DEFAULT_COMMANDS } from './input-prompt-v2.js';
24
+ import { InputPrompt, DEFAULT_COMMANDS } from './input-prompt.js';
25
+ import { SubagentRenderer } from './subagent-renderer.js';
26
+ import { debugLog, debugRender } from '../utils/debug-log.js';
27
+ import { getPhysicalLineCount, getVisibleLength } from './line-utils.js';
28
+ import { getPendingRequestsManager } from '../multi-agent/index.js';
29
+ import { getSessionRegistry } from '../multi-agent/session-registry.js';
21
30
  // =============================================================================
22
31
  // Footer Class
23
32
  // =============================================================================
@@ -25,13 +34,18 @@ export class Footer extends EventEmitter {
25
34
  // Child components
26
35
  todoZone;
27
36
  inputPrompt;
37
+ subagentRenderer;
28
38
  // State
29
39
  agentRunning = false;
30
40
  mode;
31
41
  lastRenderHeight = 0;
32
42
  isRunning = false;
33
43
  isPaused = false; // Prevents rendering even if callback is queued
44
+ isRendering = false; // Prevents re-entrant renders
34
45
  cursorLineFromBottom = 0; // Track cursor position for clear()
46
+ projectName = null; // Current active project name
47
+ externalRendererEnabled = false; // When true, skip internal render loop
48
+ activeTeamAgent = null; // Active team agent
35
49
  // Render loop
36
50
  renderInterval;
37
51
  renderTimer = null;
@@ -48,10 +62,15 @@ export class Footer extends EventEmitter {
48
62
  showSeparators: options.showSeparators ?? true,
49
63
  commands: DEFAULT_COMMANDS,
50
64
  });
65
+ this.subagentRenderer = new SubagentRenderer();
51
66
  // Wire up TodoZone animation callback
52
67
  this.todoZone.setAnimationCallback(() => {
53
68
  this.needsRender = true;
54
69
  });
70
+ // Wire up SubagentRenderer update callback
71
+ this.subagentRenderer.setUpdateCallback(() => {
72
+ this.needsRender = true;
73
+ });
55
74
  // Wire up InputPrompt events
56
75
  this.inputPrompt.on('submit', (input) => {
57
76
  this.emit('submit', input);
@@ -71,6 +90,23 @@ export class Footer extends EventEmitter {
71
90
  this.inputPrompt.on('change', () => {
72
91
  this.needsRender = true;
73
92
  });
93
+ // Toggle subagent expand on Ctrl+O
94
+ this.inputPrompt.on('toggleSubagentExpand', () => {
95
+ this.subagentRenderer.toggleExpand();
96
+ this.needsRender = true;
97
+ });
98
+ // Phase 3b: Listen to pending requests changes for footer indicator
99
+ const pendingManager = getPendingRequestsManager();
100
+ pendingManager.on('count-changed', () => {
101
+ this.needsRender = true;
102
+ });
103
+ // Multi-terminal: Listen to session count changes from heartbeat
104
+ const registry = getSessionRegistry();
105
+ if (registry) {
106
+ registry.onCountChange(() => {
107
+ this.needsRender = true;
108
+ });
109
+ }
74
110
  }
75
111
  // ===========================================================================
76
112
  // Public API
@@ -88,7 +124,7 @@ export class Footer extends EventEmitter {
88
124
  // Start render loop
89
125
  this.render();
90
126
  this.renderTimer = setInterval(() => {
91
- if (this.needsRender && !this.isPaused) {
127
+ if (this.isRunning && this.needsRender && !this.isPaused) {
92
128
  this.render();
93
129
  this.needsRender = false;
94
130
  }
@@ -121,14 +157,31 @@ export class Footer extends EventEmitter {
121
157
  this.agentRunning = running;
122
158
  this.todoZone.setAgentRunning(running);
123
159
  this.inputPrompt.setQueueMode(running);
124
- // When stopping, immediately clear and re-render to remove spinner
125
- // This prevents ghost spinner from render interval races
126
- if (wasRunning && !running) {
127
- this.clear();
128
- this.render();
160
+ // When starting a new run, clear previous subagents
161
+ if (!wasRunning && running) {
162
+ this.subagentRenderer.clear();
163
+ // When external renderer manages rendering, just mark needsRender
164
+ if (this.externalRendererEnabled) {
165
+ this.needsRender = true;
166
+ }
167
+ else {
168
+ // Legacy mode: IMMEDIATELY render so lastRenderHeight includes spinner
169
+ this.clear();
170
+ this.render();
171
+ }
129
172
  }
130
- else {
131
- this.needsRender = true;
173
+ // When stopping, clear subagents
174
+ if (wasRunning && !running) {
175
+ this.subagentRenderer.clear();
176
+ // When external renderer manages rendering, just mark needsRender
177
+ if (this.externalRendererEnabled) {
178
+ this.needsRender = true;
179
+ }
180
+ else {
181
+ // Legacy mode: immediately re-render to remove spinner
182
+ this.clear();
183
+ this.render();
184
+ }
132
185
  }
133
186
  }
134
187
  /**
@@ -150,6 +203,39 @@ export class Footer extends EventEmitter {
150
203
  getMode() {
151
204
  return this.mode;
152
205
  }
206
+ /**
207
+ * Set the current project name (displayed in footer)
208
+ */
209
+ setProjectName(name) {
210
+ this.projectName = name;
211
+ this.needsRender = true;
212
+ }
213
+ /**
214
+ * Get the current project name
215
+ */
216
+ getProjectName() {
217
+ return this.projectName;
218
+ }
219
+ /**
220
+ * Set the active team agent (displayed in footer)
221
+ * Pass null to clear (default agent or no team)
222
+ */
223
+ setActiveTeamAgent(agent) {
224
+ this.activeTeamAgent = agent;
225
+ this.needsRender = true;
226
+ }
227
+ /**
228
+ * Set the callback to get available team agents for $ autocomplete
229
+ */
230
+ setAgentSuggestionsCallback(callback) {
231
+ this.inputPrompt.setAgentSuggestionsCallback(callback);
232
+ }
233
+ /**
234
+ * Get the active team agent
235
+ */
236
+ getActiveTeamAgent() {
237
+ return this.activeTeamAgent;
238
+ }
153
239
  /**
154
240
  * Update the todo list
155
241
  */
@@ -180,11 +266,94 @@ export class Footer extends EventEmitter {
180
266
  this.needsRender = true;
181
267
  }
182
268
  /**
183
- * Add tokens to the spinner counter
269
+ * Add tokens to the spinner counter (legacy)
184
270
  */
185
271
  addTokens(count) {
186
272
  this.todoZone.addTokens(count);
187
273
  }
274
+ /**
275
+ * Add input/output tokens separately (new API for live display)
276
+ */
277
+ addTokensDetailed(inputTokens, outputTokens) {
278
+ this.todoZone.addTokensDetailed(inputTokens, outputTokens);
279
+ }
280
+ /**
281
+ * Get current token counts
282
+ */
283
+ getTokenCounts() {
284
+ return this.todoZone.getTokenCounts();
285
+ }
286
+ /**
287
+ * Set whether extended thinking mode is active
288
+ * Shows "thinking" indicator in status line
289
+ */
290
+ setThinking(thinking) {
291
+ this.todoZone.setThinking(thinking);
292
+ this.needsRender = true;
293
+ }
294
+ // ===========================================================================
295
+ // Subagent API
296
+ // ===========================================================================
297
+ /**
298
+ * Called when a subagent starts
299
+ */
300
+ onSubagentStart(agentId, agentType, description) {
301
+ this.subagentRenderer.onSubagentStart(agentId, agentType, description);
302
+ }
303
+ /**
304
+ * Called when a subagent uses a tool
305
+ */
306
+ onSubagentToolUse(agentId, toolName, summary) {
307
+ this.subagentRenderer.onToolUse(agentId, toolName, summary);
308
+ }
309
+ /**
310
+ * Called when a subagent completes
311
+ *
312
+ * CRITICAL (legacy mode only): We must pause rendering immediately to prevent a race condition.
313
+ * The render loop could fire between onSubagentEnd and clearForOutput, which would:
314
+ * 1. See the subagent as 'done'
315
+ * 2. Render with 0 subagent lines
316
+ * 3. Update lastRenderHeight to a smaller value
317
+ * 4. Then clearForOutput would not clear enough lines → ghost lines!
318
+ *
319
+ * In external renderer mode: No pause needed since the internal render loop is disabled.
320
+ */
321
+ onSubagentEnd(agentId, success, tokenCount, error) {
322
+ // Only pause in legacy mode (internal render loop is running)
323
+ // In external renderer mode, the loop is already stopped
324
+ if (!this.externalRendererEnabled) {
325
+ // Pause rendering BEFORE updating state to prevent race condition
326
+ // The caller (repl.ts) will call clearForOutput() and forceRender() which will unpause
327
+ this.isPaused = true;
328
+ }
329
+ this.subagentRenderer.onSubagentEnd(agentId, success, tokenCount, error);
330
+ this.needsRender = true;
331
+ }
332
+ /**
333
+ * Toggle expanded view for subagents (Ctrl+O)
334
+ */
335
+ toggleSubagentExpand() {
336
+ this.subagentRenderer.toggleExpand();
337
+ }
338
+ /**
339
+ * Check if there are active subagents
340
+ */
341
+ hasActiveSubagents() {
342
+ return this.subagentRenderer.hasActiveSubagents();
343
+ }
344
+ /**
345
+ * Clear subagent tracking (after completion displayed)
346
+ */
347
+ clearSubagents() {
348
+ this.subagentRenderer.clear();
349
+ this.needsRender = true;
350
+ }
351
+ /**
352
+ * Get the last subagent's stats before clearing
353
+ */
354
+ getLastSubagentStats() {
355
+ return this.subagentRenderer.getLastAgentStats();
356
+ }
188
357
  /**
189
358
  * Get queued inputs
190
359
  */
@@ -217,22 +386,58 @@ export class Footer extends EventEmitter {
217
386
  /**
218
387
  * Clear footer before scrolling output
219
388
  * Call this before writing to the scrolling zone
389
+ * Pauses interval rendering to prevent ghost lines during output
390
+ *
391
+ * When external renderer is enabled (scroll region mode):
392
+ * - Footer doesn't need clearing (it's in a separate scroll region)
393
+ * - Just mark that we need a re-render
220
394
  */
221
395
  clearForOutput() {
396
+ // When external renderer manages rendering, footer is in a fixed region
397
+ // and doesn't need to be cleared before output
398
+ if (this.externalRendererEnabled) {
399
+ debugRender('Footer:clearForOutput', 'external renderer mode - skipping clear');
400
+ return;
401
+ }
402
+ // Pause interval rendering to prevent ghost lines during output
403
+ this.isPaused = true;
404
+ debugRender('Footer:clearForOutput', `lastRenderHeight=${String(this.lastRenderHeight)}`);
405
+ // Clear the footer
222
406
  this.clear();
223
407
  }
224
408
  /**
225
409
  * Force an immediate render
410
+ * Resumes interval rendering after clearForOutput()
411
+ *
412
+ * When external renderer is enabled (scroll region mode):
413
+ * - Just mark that we need a re-render (TerminalRenderer's loop will pick it up)
226
414
  */
227
415
  forceRender() {
416
+ // When external renderer manages rendering, just mark that we need re-render
417
+ if (this.externalRendererEnabled) {
418
+ debugRender('Footer:forceRender', 'external renderer mode - marking needsRender');
419
+ this.needsRender = true;
420
+ return;
421
+ }
422
+ // Resume interval rendering BEFORE calling render (so render() isn't skipped)
423
+ this.isPaused = false;
228
424
  this.render();
229
425
  this.needsRender = false;
230
426
  }
427
+ /**
428
+ * Restart input prompt after a command completes
429
+ * Use this for non-overlay commands where finishInput() stopped the prompt
430
+ */
431
+ restartInput() {
432
+ this.inputPrompt.start();
433
+ this.render();
434
+ }
231
435
  /**
232
436
  * Pause footer completely (for overlays)
233
437
  * Stops render loop, input capture, and animation
234
438
  */
235
439
  pauseAnimation() {
440
+ debugLog('Footer:pauseAnimation', 'start');
236
441
  // Set paused flag FIRST - this prevents any queued render callbacks from executing
237
442
  this.isPaused = true;
238
443
  // Stop render loop
@@ -240,12 +445,16 @@ export class Footer extends EventEmitter {
240
445
  clearInterval(this.renderTimer);
241
446
  this.renderTimer = null;
242
447
  }
448
+ debugLog('Footer:pauseAnimation', 'render loop stopped');
243
449
  // Stop input capture
244
450
  this.inputPrompt.stop();
451
+ debugLog('Footer:pauseAnimation', 'input stopped');
245
452
  // Stop animation
246
453
  this.todoZone.pauseAnimation();
454
+ debugLog('Footer:pauseAnimation', 'animation stopped');
247
455
  // Clear footer from screen
248
456
  this.clear();
457
+ debugLog('Footer:pauseAnimation', 'footer cleared');
249
458
  }
250
459
  /**
251
460
  * Resume footer after pause
@@ -261,7 +470,7 @@ export class Footer extends EventEmitter {
261
470
  // Restart render loop
262
471
  this.render();
263
472
  this.renderTimer = setInterval(() => {
264
- if (this.needsRender && !this.isPaused) {
473
+ if (this.isRunning && this.needsRender && !this.isPaused) {
265
474
  this.render();
266
475
  this.needsRender = false;
267
476
  }
@@ -273,6 +482,128 @@ export class Footer extends EventEmitter {
273
482
  getLastRenderHeight() {
274
483
  return this.lastRenderHeight;
275
484
  }
485
+ /**
486
+ * Get all footer lines for rendering (for TerminalRenderer integration)
487
+ * Returns the lines WITHOUT writing to terminal
488
+ */
489
+ getFooterLines() {
490
+ const allLines = [];
491
+ const s = getStyles();
492
+ // 1. Subagent zone (only if agent is running)
493
+ if (this.agentRunning) {
494
+ const subagentLines = this.subagentRenderer.render();
495
+ allLines.push(...subagentLines);
496
+ }
497
+ // 2. Todo zone (spinner + todos)
498
+ const todoLines = this.todoZone.render();
499
+ allLines.push(...todoLines);
500
+ // 3. Agent indicator (only if team agent is active and not default)
501
+ const agentIndicator = this.renderAgentIndicator();
502
+ if (agentIndicator) {
503
+ allLines.push(agentIndicator);
504
+ }
505
+ // 3b. Pending requests indicator (Phase 3b)
506
+ const pendingIndicator = this.renderPendingRequestsIndicator();
507
+ if (pendingIndicator) {
508
+ allLines.push(pendingIndicator);
509
+ }
510
+ // 3c. Terminal count indicator (multi-terminal awareness)
511
+ const terminalIndicator = this.renderTerminalCountIndicator();
512
+ if (terminalIndicator) {
513
+ allLines.push(terminalIndicator);
514
+ }
515
+ // 4. Queued inputs
516
+ const queuedInputs = this.inputPrompt.getQueuedInputs();
517
+ for (const queued of queuedInputs) {
518
+ allLines.push(s.muted(`queued: "${queued}"`));
519
+ }
520
+ // 5. Input prompt
521
+ const inputLines = this.inputPrompt.render();
522
+ allLines.push(...inputLines);
523
+ // 6. Mode indicator (below input, before autocomplete)
524
+ allLines.push(this.renderModeIndicator());
525
+ // 7. Autocomplete dropdown (if active)
526
+ const autocompleteLines = this.inputPrompt.getAutocompleteLines();
527
+ allLines.push(...autocompleteLines);
528
+ return allLines;
529
+ }
530
+ /**
531
+ * Get cursor position within footer content (for TerminalRenderer)
532
+ * Returns { row, col } where row is 0-indexed from start of footer lines
533
+ */
534
+ getFooterCursorPosition() {
535
+ const cursorInfo = this.inputPrompt.getCursorInfo();
536
+ // Calculate lines before input prompt
537
+ let linesBeforeInput = 0;
538
+ // Subagent lines
539
+ if (this.agentRunning) {
540
+ linesBeforeInput += this.subagentRenderer.render().length;
541
+ }
542
+ // Todo lines
543
+ linesBeforeInput += this.todoZone.render().length;
544
+ // Agent indicator line (if active team agent and not default)
545
+ if (this.activeTeamAgent && this.activeTeamAgent.id !== 'default') {
546
+ linesBeforeInput += 1;
547
+ }
548
+ // Pending indicator line (Phase 3b)
549
+ const pendingIndicator = this.renderPendingRequestsIndicator();
550
+ if (pendingIndicator) {
551
+ linesBeforeInput += 1;
552
+ }
553
+ // Terminal count indicator (multi-terminal awareness)
554
+ const terminalIndicator = this.renderTerminalCountIndicator();
555
+ if (terminalIndicator) {
556
+ linesBeforeInput += 1;
557
+ }
558
+ // Queued inputs
559
+ linesBeforeInput += this.inputPrompt.getQueuedInputs().length;
560
+ // cursorInfo.row is 1-indexed (row 1 = first line after separator)
561
+ // Convert to 0-indexed row within footer
562
+ const row = linesBeforeInput + cursorInfo.row - 1;
563
+ return { row, col: cursorInfo.col };
564
+ }
565
+ /**
566
+ * Enable external renderer mode (TerminalRenderer manages rendering)
567
+ * When enabled:
568
+ * - Footer's internal render loop is disabled
569
+ * - Input capture remains active
570
+ * - Event forwarding remains active
571
+ * - TerminalRenderer calls getFooterLines() and renders
572
+ */
573
+ setExternalRenderer(enabled) {
574
+ this.externalRendererEnabled = enabled;
575
+ if (enabled && this.renderTimer) {
576
+ // Stop the internal render loop (TerminalRenderer will handle rendering)
577
+ clearInterval(this.renderTimer);
578
+ this.renderTimer = null;
579
+ debugLog('Footer:setExternalRenderer', 'enabled - internal render loop stopped');
580
+ }
581
+ else if (!enabled && this.isRunning && !this.renderTimer) {
582
+ // Restart the internal render loop
583
+ this.renderTimer = setInterval(() => {
584
+ if (this.isRunning && this.needsRender && !this.isPaused) {
585
+ this.render();
586
+ this.needsRender = false;
587
+ }
588
+ }, this.renderInterval);
589
+ debugLog('Footer:setExternalRenderer', 'disabled - internal render loop restarted');
590
+ }
591
+ }
592
+ /**
593
+ * Check if external renderer is enabled
594
+ */
595
+ isExternalRendererEnabled() {
596
+ return this.externalRendererEnabled;
597
+ }
598
+ /**
599
+ * Request a render from external renderer
600
+ * Call this to notify TerminalRenderer that footer needs re-rendering
601
+ */
602
+ requestExternalRender() {
603
+ this.needsRender = true;
604
+ // External renderer will poll this or listen for events
605
+ // For now, just set the flag
606
+ }
276
607
  /**
277
608
  * Refresh the prompt with current theme colors
278
609
  * Call after theme changes to apply new colors immediately
@@ -287,17 +618,26 @@ export class Footer extends EventEmitter {
287
618
  // ===========================================================================
288
619
  /**
289
620
  * Clear the footer area
621
+ *
622
+ * Strategy: Simply move to the top of the CURRENT footer and clear to end.
623
+ * - When footer SHRINKS: clearToEndOfScreen handles the extra lines
624
+ * - When footer GROWS: terminal scrolls naturally when we write more lines
625
+ *
626
+ * We NEVER move up into the scrolling zone - that would eat content!
290
627
  */
291
628
  clear() {
629
+ debugRender('Footer:clear', `lastHeight=${String(this.lastRenderHeight)} cursorFromBottom=${String(this.cursorLineFromBottom)}`);
292
630
  if (this.lastRenderHeight > 0) {
293
631
  // Move to start of current line
294
632
  terminal.moveCursorToLineStart();
295
- // First move DOWN to the last line of footer (cursor may be positioned in input area)
296
- if (this.cursorLineFromBottom > 0) {
297
- terminal.moveCursorDown(this.cursorLineFromBottom);
633
+ // Calculate DIRECT movement to top of footer
634
+ const cursorRowFromTop = this.lastRenderHeight - this.cursorLineFromBottom;
635
+ const rowsToMoveUp = cursorRowFromTop - 1;
636
+ debugRender('Footer:clear', `cursorRowFromTop=${String(cursorRowFromTop)} rowsToMoveUp=${String(rowsToMoveUp)}`);
637
+ if (rowsToMoveUp > 0) {
638
+ terminal.moveCursorUp(rowsToMoveUp);
298
639
  }
299
- // Now move up to the first line of footer
300
- terminal.moveCursorUp(this.lastRenderHeight - 1);
640
+ // Clear from here to end of screen
301
641
  terminal.clearToEndOfScreen();
302
642
  }
303
643
  this.lastRenderHeight = 0;
@@ -307,47 +647,89 @@ export class Footer extends EventEmitter {
307
647
  * Render the entire footer
308
648
  */
309
649
  render() {
310
- // Clear and redraw footer
311
- this.clear();
312
- const allLines = [];
313
- // 1. Todo zone (spinner + todos)
314
- const todoLines = this.todoZone.render();
315
- allLines.push(...todoLines);
316
- // 2. Queued inputs
317
- const s = getStyles();
318
- const queuedInputs = this.inputPrompt.getQueuedInputs();
319
- for (const queued of queuedInputs) {
320
- allLines.push(s.muted(`queued: "${queued}"`));
321
- }
322
- // 3. Input prompt
323
- const inputLines = this.inputPrompt.render();
324
- allLines.push(...inputLines);
325
- // 4. Mode indicator (below input, before autocomplete)
326
- allLines.push(this.renderModeIndicator());
327
- // 5. Autocomplete dropdown (if active)
328
- const autocompleteLines = this.inputPrompt.getAutocompleteLines();
329
- allLines.push(...autocompleteLines);
330
- // Write all lines
331
- for (let i = 0; i < allLines.length; i++) {
332
- terminal.write(allLines[i]);
333
- if (i < allLines.length - 1) {
334
- terminal.write('\n');
650
+ // Don't render if footer has been stopped, we're paused, or already rendering
651
+ if (!this.isRunning || this.isPaused || this.isRendering)
652
+ return;
653
+ // Prevent re-entrant renders
654
+ this.isRendering = true;
655
+ try {
656
+ // Build all lines FIRST to know new height before clearing
657
+ const allLines = [];
658
+ let subagentLineCount = 0;
659
+ // 1. Subagent zone (only if agent is running - prevents showing after completion)
660
+ if (this.agentRunning) {
661
+ const subagentLines = this.subagentRenderer.render();
662
+ subagentLineCount = subagentLines.length;
663
+ allLines.push(...subagentLines);
664
+ }
665
+ // 2. Todo zone (spinner + todos)
666
+ const todoLines = this.todoZone.render();
667
+ allLines.push(...todoLines);
668
+ // 3. Agent indicator (only if team agent is active and not default)
669
+ let agentIndicatorLineCount = 0;
670
+ const agentIndicator = this.renderAgentIndicator();
671
+ if (agentIndicator) {
672
+ allLines.push(agentIndicator);
673
+ agentIndicatorLineCount = 1;
674
+ }
675
+ // 3b. Pending requests indicator (Phase 3b: Background Agents)
676
+ let pendingIndicatorLineCount = 0;
677
+ const pendingIndicator = this.renderPendingRequestsIndicator();
678
+ if (pendingIndicator) {
679
+ allLines.push(pendingIndicator);
680
+ pendingIndicatorLineCount = 1;
681
+ }
682
+ // 3c. Terminal count indicator (multi-terminal awareness)
683
+ let terminalIndicatorLineCount = 0;
684
+ const terminalIndicator = this.renderTerminalCountIndicator();
685
+ if (terminalIndicator) {
686
+ allLines.push(terminalIndicator);
687
+ terminalIndicatorLineCount = 1;
688
+ }
689
+ // 4. Queued inputs
690
+ const s = getStyles();
691
+ const queuedInputs = this.inputPrompt.getQueuedInputs();
692
+ for (const queued of queuedInputs) {
693
+ allLines.push(s.muted(`queued: "${queued}"`));
335
694
  }
695
+ // 5. Input prompt
696
+ const inputLines = this.inputPrompt.render();
697
+ allLines.push(...inputLines);
698
+ // 6. Mode indicator (below input, before autocomplete)
699
+ allLines.push(this.renderModeIndicator());
700
+ // 7. Autocomplete dropdown (if active)
701
+ const autocompleteLines = this.inputPrompt.getAutocompleteLines();
702
+ allLines.push(...autocompleteLines);
703
+ // Calculate new height BEFORE clearing (to clear extra lines if growing)
704
+ const termWidth = process.stdout.columns || 80;
705
+ let newHeight = 0;
706
+ const lineHeights = [];
707
+ for (const line of allLines) {
708
+ // Use unified line-utils for consistent height calculation
709
+ const lineHeight = getPhysicalLineCount(line, termWidth);
710
+ lineHeights.push(lineHeight);
711
+ newHeight += lineHeight;
712
+ }
713
+ debugRender('Footer:render', `subagent=${String(subagentLineCount)} todo=${String(todoLines.length)} queued=${String(queuedInputs.length)} input=${String(inputLines.length)} autocomplete=${String(autocompleteLines.length)}`);
714
+ debugRender('Footer:render', `termWidth=${String(termWidth)} lineHeights=[${lineHeights.join(',')}] newHeight=${String(newHeight)}`);
715
+ // Clear the current footer (terminal scrolls naturally if we write more lines)
716
+ this.clear();
717
+ // Write all lines
718
+ for (let i = 0; i < allLines.length; i++) {
719
+ terminal.write(allLines[i]);
720
+ if (i < allLines.length - 1) {
721
+ terminal.write('\n');
722
+ }
723
+ }
724
+ // Track height for next clear
725
+ this.lastRenderHeight = newHeight;
726
+ debugRender('Footer:render', `lastRenderHeight set to ${String(newHeight)}`);
727
+ // Position cursor within input prompt
728
+ this.positionCursor(allLines, subagentLineCount + todoLines.length + agentIndicatorLineCount + pendingIndicatorLineCount + terminalIndicatorLineCount + queuedInputs.length);
336
729
  }
337
- // Track height - account for line wrapping in terminal
338
- const termWidth = process.stdout.columns || 80;
339
- let actualTerminalRows = 0;
340
- for (const line of allLines) {
341
- // Strip ANSI codes to get visible length
342
- // eslint-disable-next-line no-control-regex
343
- const visibleLength = line.replace(/\x1b\[[0-9;]*m/g, '').length;
344
- // Each line takes at least 1 row, plus extra rows if it wraps
345
- actualTerminalRows += Math.max(1, Math.ceil(visibleLength / termWidth));
730
+ finally {
731
+ this.isRendering = false;
346
732
  }
347
- this.lastRenderHeight = actualTerminalRows;
348
- // Position cursor within input prompt
349
- // linesBeforeInput = todoLines + queuedInputs (mode indicator is now AFTER input)
350
- this.positionCursor(allLines, todoLines.length + queuedInputs.length);
351
733
  }
352
734
  /**
353
735
  * Render mode indicator line
@@ -355,30 +737,91 @@ export class Footer extends EventEmitter {
355
737
  renderModeIndicator() {
356
738
  const s = getStyles();
357
739
  const modeInfo = MODE_INFO[this.mode];
740
+ const termWidth = process.stdout.columns || 80;
741
+ // Build left side (mode indicator)
742
+ let leftPart;
358
743
  switch (this.mode) {
359
744
  case 'normal':
360
- // Subtle indicator in normal mode
361
- return s.muted(`mode: ${modeInfo.label} (Shift+Tab to change)`);
745
+ leftPart = s.muted(`mode: ${modeInfo.label} (Shift+Tab to change)`);
746
+ break;
362
747
  case 'auto-accept':
363
- // Warning color for auto-accept
364
- return s.warning(`⚡ mode: ${modeInfo.label}`) + s.muted(' (Shift+Tab to change)');
748
+ leftPart = s.warning(`⚡ mode: ${modeInfo.label}`) + s.muted(' (Shift+Tab to change)');
749
+ break;
365
750
  case 'plan':
366
- // Different color for plan mode
367
- return s.info(`📋 mode: ${modeInfo.label}`) + s.muted(' (Shift+Tab to change)');
751
+ leftPart = s.info(`📋 mode: ${modeInfo.label}`) + s.muted(' (Shift+Tab to change)');
752
+ break;
368
753
  default:
369
- return s.muted(`mode: ${modeInfo.label} (Shift+Tab to change)`);
754
+ leftPart = s.muted(`mode: ${modeInfo.label} (Shift+Tab to change)`);
755
+ }
756
+ // If no project, just return the mode indicator
757
+ if (!this.projectName) {
758
+ return leftPart;
759
+ }
760
+ // Build right side (project name)
761
+ const projectText = `Project: ${this.projectName}`;
762
+ const rightPart = s.muted(projectText);
763
+ // Calculate visible lengths (using unified line-utils)
764
+ const leftVisible = getVisibleLength(leftPart);
765
+ const rightVisible = projectText.length;
766
+ // Calculate padding to right-align project name
767
+ const padding = Math.max(2, termWidth - leftVisible - rightVisible);
768
+ return leftPart + ' '.repeat(padding) + rightPart;
769
+ }
770
+ /**
771
+ * Render agent indicator line (only when team agent is active and not default)
772
+ * Returns empty string if no team agent or default agent.
773
+ * Format: "[◈_◈] $arch (Solution Architect) /team to switch"
774
+ */
775
+ renderAgentIndicator() {
776
+ if (!this.activeTeamAgent || this.activeTeamAgent.id === 'default') {
777
+ return '';
370
778
  }
779
+ const s = getStyles();
780
+ const agent = this.activeTeamAgent;
781
+ const label = `${agent.mascot} $${agent.id} (${agent.displayName})`;
782
+ const hint = '/team to switch';
783
+ return s.secondary(label) + ' ' + s.muted(hint);
784
+ }
785
+ /**
786
+ * Render pending requests indicator (Phase 3b: Background Agents)
787
+ * Shows count of pending requests from background agents if any.
788
+ * Format: "⚠ 2 pending requests [/pending to view]"
789
+ * Returns empty string if no pending requests.
790
+ */
791
+ renderPendingRequestsIndicator() {
792
+ const pendingManager = getPendingRequestsManager();
793
+ const count = pendingManager.getCount();
794
+ if (count === 0) {
795
+ return '';
796
+ }
797
+ const s = getStyles();
798
+ const countText = count === 1 ? '1 pending request' : `${String(count)} pending requests`;
799
+ return s.warning(`⚠ ${countText}`) + ' ' + s.muted('[/pending to view]');
800
+ }
801
+ /**
802
+ * Render terminal count indicator (multi-terminal awareness).
803
+ * Shows count of active terminal sessions if more than 1.
804
+ * Format: "+ 2 terminals [/terminals]"
805
+ * Returns empty string if only this terminal is active.
806
+ */
807
+ renderTerminalCountIndicator() {
808
+ const registry = getSessionRegistry();
809
+ if (!registry)
810
+ return '';
811
+ const count = registry.getActiveSessionCount();
812
+ if (count <= 1)
813
+ return '';
814
+ const s = getStyles();
815
+ const text = `${String(count)} terminals`;
816
+ return s.muted(`+ ${text}`) + ' ' + s.muted('[/terminals]');
371
817
  }
372
818
  /**
373
819
  * Calculate how many terminal rows a line takes (accounting for wrapping)
820
+ * Uses unified line-utils for consistent calculation across all components.
374
821
  */
375
822
  getTerminalRowsForLine(line) {
376
823
  const termWidth = process.stdout.columns || 80;
377
- // Strip ANSI codes to get visible length
378
- // eslint-disable-next-line no-control-regex
379
- const visibleLength = line.replace(/\x1b\[[0-9;]*m/g, '').length;
380
- // Each line takes at least 1 row, plus extra rows if it wraps
381
- return Math.max(1, Math.ceil(visibleLength / termWidth));
824
+ return getPhysicalLineCount(line, termWidth);
382
825
  }
383
826
  /**
384
827
  * Position cursor correctly within the input prompt
@@ -406,11 +849,17 @@ export class Footer extends EventEmitter {
406
849
  for (let i = inputEndIndex; i < allLines.length; i++) {
407
850
  rowsAfterInput += this.getTerminalRowsForLine(allLines[i]);
408
851
  }
409
- // Cursor target row from start of footer = rows before input + cursor row within input
852
+ // Cursor target row from start of footer (1-indexed) = rows before input + cursor row within input
410
853
  const cursorRowFromStart = rowsBeforeInput + cursorInfo.row;
411
- // Total rows to move up from end = total rows - cursor row - 1
854
+ // Total rows in footer
412
855
  const totalRows = rowsBeforeInput + inputTotalRows + rowsAfterInput;
856
+ // After writing all lines, cursor is at the END of the last row (row totalRows).
857
+ // cursorInfo.row starts at 1 (after separator), so actual footer row = cursorRowFromStart + 1
858
+ // To move to actual row, we move up: totalRows - (cursorRowFromStart + 1) = totalRows - cursorRowFromStart - 1
859
+ // Example: totalRows=7, cursorRowFromStart=4, actual row=5 → move up 2 rows (from row 7 to row 5)
413
860
  const rowsToMoveUp = totalRows - cursorRowFromStart - 1;
861
+ debugRender('Footer:positionCursor', `cursorInfo={row:${String(cursorInfo.row)},col:${String(cursorInfo.col)}} rowsBefore=${String(rowsBeforeInput)} inputRows=${String(inputTotalRows)} rowsAfter=${String(rowsAfterInput)}`);
862
+ debugRender('Footer:positionCursor', `totalRows=${String(totalRows)} cursorRowFromStart=${String(cursorRowFromStart)} rowsToMoveUp=${String(rowsToMoveUp)}`);
414
863
  if (rowsToMoveUp > 0) {
415
864
  terminal.moveCursorUp(rowsToMoveUp);
416
865
  }