@compilr-dev/cli 0.5.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 (591) hide show
  1. package/README.md +236 -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 +61 -4
  7. package/dist/agent.js +241 -245
  8. package/dist/anchors/index.d.ts +1 -1
  9. package/dist/anchors/index.js +1 -1
  10. package/dist/anchors/project-anchors.d.ts +2 -2
  11. package/dist/anchors/project-anchors.js +1 -1
  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-v2/handlers/auth.d.ts +10 -0
  23. package/dist/commands-v2/handlers/auth.js +118 -0
  24. package/dist/commands-v2/handlers/background.d.ts +14 -0
  25. package/dist/commands-v2/handlers/background.js +276 -0
  26. package/dist/commands-v2/handlers/context.js +266 -81
  27. package/dist/commands-v2/handlers/core.d.ts +1 -0
  28. package/dist/commands-v2/handlers/core.js +133 -8
  29. package/dist/commands-v2/handlers/debug.js +18 -0
  30. package/dist/commands-v2/handlers/delegations.d.ts +8 -0
  31. package/dist/commands-v2/handlers/delegations.js +29 -0
  32. package/dist/commands-v2/handlers/files.d.ts +8 -0
  33. package/dist/commands-v2/handlers/files.js +162 -0
  34. package/dist/commands-v2/handlers/filter.d.ts +9 -0
  35. package/dist/commands-v2/handlers/filter.js +130 -0
  36. package/dist/commands-v2/handlers/games.d.ts +7 -0
  37. package/dist/commands-v2/handlers/games.js +57 -0
  38. package/dist/commands-v2/handlers/index.d.ts +13 -0
  39. package/dist/commands-v2/handlers/index.js +39 -0
  40. package/dist/commands-v2/handlers/mcp.d.ts +8 -0
  41. package/dist/commands-v2/handlers/mcp.js +39 -0
  42. package/dist/commands-v2/handlers/notifications.d.ts +9 -0
  43. package/dist/commands-v2/handlers/notifications.js +34 -0
  44. package/dist/commands-v2/handlers/project.js +244 -23
  45. package/dist/commands-v2/handlers/reset.d.ts +11 -0
  46. package/dist/commands-v2/handlers/reset.js +118 -0
  47. package/dist/commands-v2/handlers/session.d.ts +161 -0
  48. package/dist/commands-v2/handlers/session.js +805 -0
  49. package/dist/commands-v2/handlers/settings.d.ts +2 -0
  50. package/dist/commands-v2/handlers/settings.js +217 -35
  51. package/dist/commands-v2/handlers/tasks.d.ts +5 -0
  52. package/dist/commands-v2/handlers/tasks.js +36 -0
  53. package/dist/commands-v2/handlers/team.d.ts +9 -0
  54. package/dist/commands-v2/handlers/team.js +549 -0
  55. package/dist/commands-v2/handlers/terminals.d.ts +9 -0
  56. package/dist/commands-v2/handlers/terminals.js +34 -0
  57. package/dist/commands-v2/index.d.ts +3 -2
  58. package/dist/commands-v2/index.js +4 -1
  59. package/dist/commands-v2/registry.d.ts +15 -0
  60. package/dist/commands-v2/registry.js +34 -0
  61. package/dist/commands-v2/types.d.ts +81 -3
  62. package/dist/commands.js +13 -0
  63. package/dist/compilr-diff-companion.vsix +0 -0
  64. package/dist/db/index.js +98 -4
  65. package/dist/db/repositories/document-repository.d.ts +2 -0
  66. package/dist/db/repositories/document-repository.js +5 -1
  67. package/dist/db/repositories/index.d.ts +2 -0
  68. package/dist/db/repositories/index.js +1 -0
  69. package/dist/db/repositories/plan-repository.d.ts +101 -0
  70. package/dist/db/repositories/plan-repository.js +275 -0
  71. package/dist/db/repositories/project-repository.d.ts +6 -0
  72. package/dist/db/repositories/project-repository.js +41 -0
  73. package/dist/db/repositories/work-item-repository.d.ts +15 -0
  74. package/dist/db/repositories/work-item-repository.js +69 -4
  75. package/dist/db/schema.d.ts +40 -3
  76. package/dist/db/schema.js +66 -3
  77. package/dist/episodes/index.d.ts +20 -0
  78. package/dist/episodes/index.js +27 -0
  79. package/dist/episodes/recorder.d.ts +51 -0
  80. package/dist/episodes/recorder.js +195 -0
  81. package/dist/episodes/significant-work.d.ts +21 -0
  82. package/dist/episodes/significant-work.js +56 -0
  83. package/dist/episodes/store.d.ts +38 -0
  84. package/dist/episodes/store.js +199 -0
  85. package/dist/episodes/types.d.ts +35 -0
  86. package/dist/episodes/types.js +6 -0
  87. package/dist/episodes/work-at-risk.d.ts +12 -0
  88. package/dist/episodes/work-at-risk.js +38 -0
  89. package/dist/episodes/work-summary-anchor.d.ts +23 -0
  90. package/dist/episodes/work-summary-anchor.js +73 -0
  91. package/dist/games/coins.d.ts +66 -0
  92. package/dist/games/coins.js +165 -0
  93. package/dist/games/game-base.d.ts +84 -0
  94. package/dist/games/game-base.js +204 -0
  95. package/dist/games/index.d.ts +16 -0
  96. package/dist/games/index.js +49 -0
  97. package/dist/games/scores.d.ts +69 -0
  98. package/dist/games/scores.js +191 -0
  99. package/dist/games/tetris/board.d.ts +59 -0
  100. package/dist/games/tetris/board.js +170 -0
  101. package/dist/games/tetris/index.d.ts +109 -0
  102. package/dist/games/tetris/index.js +610 -0
  103. package/dist/games/tetris/pieces.d.ts +44 -0
  104. package/dist/games/tetris/pieces.js +271 -0
  105. package/dist/games/tetris/renderer.d.ts +26 -0
  106. package/dist/games/tetris/renderer.js +77 -0
  107. package/dist/guide/guide-content.d.ts +23 -0
  108. package/dist/guide/guide-content.js +196 -0
  109. package/dist/guide/index.d.ts +8 -0
  110. package/dist/guide/index.js +7 -0
  111. package/dist/guide/shared-content.d.ts +37 -0
  112. package/dist/guide/shared-content.js +1272 -0
  113. package/dist/guide/tutorial-helpers.d.ts +57 -0
  114. package/dist/guide/tutorial-helpers.js +147 -0
  115. package/dist/handlers/ask-user-handlers.d.ts +32 -0
  116. package/dist/handlers/ask-user-handlers.js +104 -0
  117. package/dist/handlers/delegation-handlers.d.ts +34 -0
  118. package/dist/handlers/delegation-handlers.js +291 -0
  119. package/dist/handlers/permission-handler.d.ts +30 -0
  120. package/dist/handlers/permission-handler.js +205 -0
  121. package/dist/index.d.ts +11 -1
  122. package/dist/index.js +448 -271
  123. package/dist/input-handlers/memory-handler.d.ts +1 -1
  124. package/dist/input-handlers/memory-handler.js +2 -1
  125. package/dist/models/index.d.ts +10 -0
  126. package/dist/models/index.js +12 -0
  127. package/dist/models/model-registry.d.ts +38 -0
  128. package/dist/models/model-registry.js +69 -0
  129. package/dist/models/model-tiers.d.ts +28 -0
  130. package/dist/models/model-tiers.js +71 -0
  131. package/dist/models/model-validation.d.ts +25 -0
  132. package/dist/models/model-validation.js +291 -0
  133. package/dist/models/ollama-models.d.ts +73 -0
  134. package/dist/models/ollama-models.js +178 -0
  135. package/dist/models/provider-types.d.ts +6 -0
  136. package/dist/models/provider-types.js +1 -0
  137. package/dist/models/providers.d.ts +35 -0
  138. package/dist/models/providers.js +58 -0
  139. package/dist/models/types.d.ts +4 -0
  140. package/dist/models/types.js +4 -0
  141. package/dist/multi-agent/activity.d.ts +21 -0
  142. package/dist/multi-agent/activity.js +34 -0
  143. package/dist/multi-agent/agent-selection.d.ts +55 -0
  144. package/dist/multi-agent/agent-selection.js +90 -0
  145. package/dist/multi-agent/artifacts.d.ts +197 -0
  146. package/dist/multi-agent/artifacts.js +379 -0
  147. package/dist/multi-agent/checkpointer.d.ts +138 -0
  148. package/dist/multi-agent/checkpointer.js +471 -0
  149. package/dist/multi-agent/collision-utils.d.ts +16 -0
  150. package/dist/multi-agent/collision-utils.js +28 -0
  151. package/dist/multi-agent/context-resolver.d.ts +97 -0
  152. package/dist/multi-agent/context-resolver.js +316 -0
  153. package/dist/multi-agent/custom-agents.d.ts +83 -0
  154. package/dist/multi-agent/custom-agents.js +227 -0
  155. package/dist/multi-agent/delegation-tracker.d.ts +157 -0
  156. package/dist/multi-agent/delegation-tracker.js +243 -0
  157. package/dist/multi-agent/file-lock-hook.d.ts +29 -0
  158. package/dist/multi-agent/file-lock-hook.js +97 -0
  159. package/dist/multi-agent/file-locks.d.ts +58 -0
  160. package/dist/multi-agent/file-locks.js +194 -0
  161. package/dist/multi-agent/index.d.ts +24 -0
  162. package/dist/multi-agent/index.js +30 -0
  163. package/dist/multi-agent/mention-parser.d.ts +64 -0
  164. package/dist/multi-agent/mention-parser.js +146 -0
  165. package/dist/multi-agent/notification-manager.d.ts +84 -0
  166. package/dist/multi-agent/notification-manager.js +224 -0
  167. package/dist/multi-agent/pending-requests.d.ts +122 -0
  168. package/dist/multi-agent/pending-requests.js +155 -0
  169. package/dist/multi-agent/session-registry.d.ts +139 -0
  170. package/dist/multi-agent/session-registry.js +514 -0
  171. package/dist/multi-agent/shared-context.d.ts +293 -0
  172. package/dist/multi-agent/shared-context.js +671 -0
  173. package/dist/multi-agent/skill-requirements.d.ts +66 -0
  174. package/dist/multi-agent/skill-requirements.js +178 -0
  175. package/dist/multi-agent/task-assignment.d.ts +69 -0
  176. package/dist/multi-agent/task-assignment.js +123 -0
  177. package/dist/multi-agent/task-suggestion.d.ts +31 -0
  178. package/dist/multi-agent/task-suggestion.js +72 -0
  179. package/dist/multi-agent/team-agent.d.ts +201 -0
  180. package/dist/multi-agent/team-agent.js +488 -0
  181. package/dist/multi-agent/team.d.ts +286 -0
  182. package/dist/multi-agent/team.js +610 -0
  183. package/dist/multi-agent/tool-config.d.ts +110 -0
  184. package/dist/multi-agent/tool-config.js +661 -0
  185. package/dist/multi-agent/types.d.ts +211 -0
  186. package/dist/multi-agent/types.js +617 -0
  187. package/dist/prompts/plan-mode-prompt.d.ts +11 -0
  188. package/dist/prompts/plan-mode-prompt.js +95 -0
  189. package/dist/repl-helpers.js +3 -2
  190. package/dist/repl-v2.d.ts +401 -2
  191. package/dist/repl-v2.js +2577 -65
  192. package/dist/session/index.d.ts +6 -0
  193. package/dist/session/index.js +6 -0
  194. package/dist/session/project-session-manager.d.ts +158 -0
  195. package/dist/session/project-session-manager.js +650 -0
  196. package/dist/settings/index.d.ts +133 -13
  197. package/dist/settings/index.js +329 -24
  198. package/dist/settings/mcp-config.d.ts +76 -0
  199. package/dist/settings/mcp-config.js +143 -0
  200. package/dist/settings/paths.d.ts +4 -0
  201. package/dist/settings/paths.js +6 -0
  202. package/dist/shared-handlers.d.ts +62 -0
  203. package/dist/shared-handlers.js +48 -0
  204. package/dist/system-prompt/builder.d.ts +5 -0
  205. package/dist/system-prompt/builder.js +4 -0
  206. package/dist/system-prompt/index.d.ts +18 -0
  207. package/dist/system-prompt/index.js +18 -0
  208. package/dist/system-prompt/modules.d.ts +5 -0
  209. package/dist/system-prompt/modules.js +4 -0
  210. package/dist/tabbed-menu.js +2 -1
  211. package/dist/templates/compilr-md-import.d.ts +16 -0
  212. package/dist/templates/compilr-md-import.js +241 -0
  213. package/dist/templates/compilr-md.js +10 -61
  214. package/dist/templates/config-json.d.ts +1 -25
  215. package/dist/templates/index.d.ts +2 -0
  216. package/dist/templates/index.js +34 -73
  217. package/dist/tool-names.d.ts +108 -0
  218. package/dist/tool-names.js +227 -0
  219. package/dist/tools/anchor-tools.d.ts +4 -4
  220. package/dist/tools/anchor-tools.js +1 -1
  221. package/dist/tools/artifact-tools.d.ts +42 -0
  222. package/dist/tools/artifact-tools.js +328 -0
  223. package/dist/tools/ask-user-simple.d.ts +1 -1
  224. package/dist/tools/ask-user-simple.js +2 -1
  225. package/dist/tools/ask-user.d.ts +1 -1
  226. package/dist/tools/ask-user.js +2 -1
  227. package/dist/tools/backlog-wrappers.d.ts +5 -3
  228. package/dist/tools/backlog-wrappers.js +16 -1
  229. package/dist/tools/backlog.d.ts +2 -2
  230. package/dist/tools/backlog.js +1 -1
  231. package/dist/tools/db-tools.d.ts +8 -61
  232. package/dist/tools/db-tools.js +8 -13
  233. package/dist/tools/delegate-background.d.ts +27 -0
  234. package/dist/tools/delegate-background.js +115 -0
  235. package/dist/tools/delegate.d.ts +22 -0
  236. package/dist/tools/delegate.js +97 -0
  237. package/dist/tools/delegation-status.d.ts +16 -0
  238. package/dist/tools/delegation-status.js +128 -0
  239. package/dist/tools/document-db.d.ts +5 -5
  240. package/dist/tools/document-db.js +1 -1
  241. package/dist/tools/guide-tool.d.ts +12 -0
  242. package/dist/tools/guide-tool.js +59 -0
  243. package/dist/tools/handoff.d.ts +25 -0
  244. package/dist/tools/handoff.js +99 -0
  245. package/dist/tools/meta-tools.d.ts +26 -0
  246. package/dist/tools/meta-tools.js +47 -0
  247. package/dist/tools/plan-tools.d.ts +54 -0
  248. package/dist/tools/plan-tools.js +338 -0
  249. package/dist/tools/platform-adapter.d.ts +29 -0
  250. package/dist/tools/platform-adapter.js +394 -0
  251. package/dist/tools/project-db.d.ts +5 -73
  252. package/dist/tools/project-db.js +5 -336
  253. package/dist/tools/recall-work-tool.d.ts +18 -0
  254. package/dist/tools/recall-work-tool.js +82 -0
  255. package/dist/tools/workitem-db.d.ts +43 -11
  256. package/dist/tools/workitem-db.js +186 -5
  257. package/dist/tools.d.ts +67 -2
  258. package/dist/tools.js +237 -47
  259. package/dist/ui/autocomplete-controller.d.ts +42 -0
  260. package/dist/ui/autocomplete-controller.js +384 -0
  261. package/dist/ui/base/index.d.ts +1 -1
  262. package/dist/ui/base/index.js +1 -1
  263. package/dist/ui/base/overlay-base-v2.d.ts +10 -0
  264. package/dist/ui/base/overlay-base-v2.js +14 -0
  265. package/dist/ui/base/render-utils.d.ts +19 -0
  266. package/dist/ui/base/render-utils.js +25 -0
  267. package/dist/ui/base/tabbed-list-overlay-v2.d.ts +16 -1
  268. package/dist/ui/base/tabbed-list-overlay-v2.js +19 -1
  269. package/dist/ui/constants/labels.d.ts +14 -0
  270. package/dist/ui/constants/labels.js +51 -0
  271. package/dist/ui/conversation-store.d.ts +55 -0
  272. package/dist/ui/conversation-store.js +107 -0
  273. package/dist/ui/conversation.js +11 -13
  274. package/dist/ui/diff.d.ts +7 -1
  275. package/dist/ui/diff.js +85 -48
  276. package/dist/ui/ephemeral.js +3 -9
  277. package/dist/ui/file-autocomplete.d.ts +24 -0
  278. package/dist/ui/file-autocomplete.js +56 -0
  279. package/dist/ui/footer-renderer.d.ts +69 -0
  280. package/dist/ui/footer-renderer.js +431 -0
  281. package/dist/ui/footer.d.ts +74 -7
  282. package/dist/ui/footer.js +173 -16
  283. package/dist/ui/input-controller.d.ts +51 -0
  284. package/dist/ui/input-controller.js +176 -0
  285. package/dist/ui/input-prompt.d.ts +19 -0
  286. package/dist/ui/input-prompt.js +206 -14
  287. package/dist/ui/keyboard-handler.d.ts +57 -0
  288. package/dist/ui/keyboard-handler.js +557 -0
  289. package/dist/ui/live-region-facade.d.ts +42 -0
  290. package/dist/ui/live-region-facade.js +205 -0
  291. package/dist/ui/live-region.d.ts +0 -4
  292. package/dist/ui/live-region.js +6 -14
  293. package/dist/ui/mascot/renderer.d.ts +1 -1
  294. package/dist/ui/mascot/renderer.js +37 -2
  295. package/dist/ui/overlay/data/tutorial-content.d.ts +9 -0
  296. package/dist/ui/overlay/data/tutorial-content.js +9 -0
  297. package/dist/ui/overlay/data/tutorial-registry.d.ts +12 -0
  298. package/dist/ui/overlay/data/tutorial-registry.js +116 -0
  299. package/dist/ui/overlay/data/tutorial-types.d.ts +35 -0
  300. package/dist/ui/overlay/data/tutorial-types.js +6 -0
  301. package/dist/ui/overlay/data/tutorials/basics/first-conversation.d.ts +7 -0
  302. package/dist/ui/overlay/data/tutorials/basics/first-conversation.js +220 -0
  303. package/dist/ui/overlay/data/tutorials/basics/first-project.d.ts +7 -0
  304. package/dist/ui/overlay/data/tutorials/basics/first-project.js +284 -0
  305. package/dist/ui/overlay/data/tutorials/basics/navigation.d.ts +8 -0
  306. package/dist/ui/overlay/data/tutorials/basics/navigation.js +22 -0
  307. package/dist/ui/overlay/data/tutorials/basics/welcome.d.ts +7 -0
  308. package/dist/ui/overlay/data/tutorials/basics/welcome.js +174 -0
  309. package/dist/ui/overlay/data/tutorials/config/context-management.d.ts +7 -0
  310. package/dist/ui/overlay/data/tutorials/config/context-management.js +158 -0
  311. package/dist/ui/overlay/data/tutorials/config/mcp-servers.d.ts +8 -0
  312. package/dist/ui/overlay/data/tutorials/config/mcp-servers.js +155 -0
  313. package/dist/ui/overlay/data/tutorials/config/model-selection.d.ts +7 -0
  314. package/dist/ui/overlay/data/tutorials/config/model-selection.js +162 -0
  315. package/dist/ui/overlay/data/tutorials/config/permissions-safety.d.ts +7 -0
  316. package/dist/ui/overlay/data/tutorials/config/permissions-safety.js +163 -0
  317. package/dist/ui/overlay/data/tutorials/config/settings-config.d.ts +7 -0
  318. package/dist/ui/overlay/data/tutorials/config/settings-config.js +166 -0
  319. package/dist/ui/overlay/data/tutorials/planning/arch.d.ts +7 -0
  320. package/dist/ui/overlay/data/tutorials/planning/arch.js +168 -0
  321. package/dist/ui/overlay/data/tutorials/planning/backlog.d.ts +7 -0
  322. package/dist/ui/overlay/data/tutorials/planning/backlog.js +103 -0
  323. package/dist/ui/overlay/data/tutorials/planning/build.d.ts +7 -0
  324. package/dist/ui/overlay/data/tutorials/planning/build.js +173 -0
  325. package/dist/ui/overlay/data/tutorials/planning/design.d.ts +7 -0
  326. package/dist/ui/overlay/data/tutorials/planning/design.js +205 -0
  327. package/dist/ui/overlay/data/tutorials/planning/docs.d.ts +7 -0
  328. package/dist/ui/overlay/data/tutorials/planning/docs.js +143 -0
  329. package/dist/ui/overlay/data/tutorials/planning/prd.d.ts +7 -0
  330. package/dist/ui/overlay/data/tutorials/planning/prd.js +173 -0
  331. package/dist/ui/overlay/data/tutorials/planning/scaffold.d.ts +7 -0
  332. package/dist/ui/overlay/data/tutorials/planning/scaffold.js +164 -0
  333. package/dist/ui/overlay/data/tutorials/planning/sketch.d.ts +7 -0
  334. package/dist/ui/overlay/data/tutorials/planning/sketch.js +58 -0
  335. package/dist/ui/overlay/data/tutorials/projects/anchors.d.ts +7 -0
  336. package/dist/ui/overlay/data/tutorials/projects/anchors.js +248 -0
  337. package/dist/ui/overlay/data/tutorials/projects/import-project.d.ts +7 -0
  338. package/dist/ui/overlay/data/tutorials/projects/import-project.js +172 -0
  339. package/dist/ui/overlay/data/tutorials/projects/managing-projects.d.ts +8 -0
  340. package/dist/ui/overlay/data/tutorials/projects/managing-projects.js +212 -0
  341. package/dist/ui/overlay/data/tutorials/projects/new-project.d.ts +7 -0
  342. package/dist/ui/overlay/data/tutorials/projects/new-project.js +251 -0
  343. package/dist/ui/overlay/data/tutorials/projects/session-management.d.ts +7 -0
  344. package/dist/ui/overlay/data/tutorials/projects/session-management.js +169 -0
  345. package/dist/ui/overlay/data/tutorials/teams/background-execution.d.ts +7 -0
  346. package/dist/ui/overlay/data/tutorials/teams/background-execution.js +171 -0
  347. package/dist/ui/overlay/data/tutorials/teams/multi-terminal.d.ts +8 -0
  348. package/dist/ui/overlay/data/tutorials/teams/multi-terminal.js +147 -0
  349. package/dist/ui/overlay/data/tutorials/teams/task-assignment.d.ts +7 -0
  350. package/dist/ui/overlay/data/tutorials/teams/task-assignment.js +204 -0
  351. package/dist/ui/overlay/data/tutorials/teams/team-overview.d.ts +7 -0
  352. package/dist/ui/overlay/data/tutorials/teams/team-overview.js +165 -0
  353. package/dist/ui/overlay/data/tutorials/teams/working-with-agents.d.ts +7 -0
  354. package/dist/ui/overlay/data/tutorials/teams/working-with-agents.js +172 -0
  355. package/dist/ui/overlay/impl/agents-overlay-v2.js +6 -17
  356. package/dist/ui/overlay/impl/anchors-overlay-v2.js +30 -64
  357. package/dist/ui/overlay/impl/artifact-detail-overlay-v2.d.ts +43 -0
  358. package/dist/ui/overlay/impl/artifact-detail-overlay-v2.js +232 -0
  359. package/dist/ui/overlay/impl/artifact-overlay-v2.d.ts +40 -0
  360. package/dist/ui/overlay/impl/artifact-overlay-v2.js +115 -0
  361. package/dist/ui/overlay/impl/ask-user-overlay-v2.js +2 -5
  362. package/dist/ui/overlay/impl/background-overlay-v2.d.ts +40 -0
  363. package/dist/ui/overlay/impl/background-overlay-v2.js +147 -0
  364. package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +4 -1
  365. package/dist/ui/overlay/impl/backlog-overlay-v2.js +55 -16
  366. package/dist/ui/overlay/impl/changelog-overlay-v2.d.ts +44 -0
  367. package/dist/ui/overlay/impl/changelog-overlay-v2.js +165 -0
  368. package/dist/ui/overlay/impl/commands-overlay-v2.js +4 -6
  369. package/dist/ui/overlay/impl/config-overlay-v2.d.ts +12 -1
  370. package/dist/ui/overlay/impl/config-overlay-v2.js +164 -100
  371. package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.d.ts +83 -0
  372. package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.js +711 -0
  373. package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +2 -0
  374. package/dist/ui/overlay/impl/dashboard-overlay-v2.js +26 -3
  375. package/dist/ui/overlay/impl/delegations-overlay-v2.d.ts +28 -0
  376. package/dist/ui/overlay/impl/delegations-overlay-v2.js +279 -0
  377. package/dist/ui/overlay/impl/docs-overlay-v2.js +12 -9
  378. package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +7 -0
  379. package/dist/ui/overlay/impl/document-detail-overlay-v2.js +119 -78
  380. package/dist/ui/overlay/impl/filter-overlay-v2.d.ts +41 -0
  381. package/dist/ui/overlay/impl/filter-overlay-v2.js +110 -0
  382. package/dist/ui/overlay/impl/games-overlay-v2.d.ts +31 -0
  383. package/dist/ui/overlay/impl/games-overlay-v2.js +135 -0
  384. package/dist/ui/overlay/impl/help-overlay-v2.d.ts +26 -3
  385. package/dist/ui/overlay/impl/help-overlay-v2.js +20 -42
  386. package/dist/ui/overlay/impl/login-overlay-v2.d.ts +49 -0
  387. package/dist/ui/overlay/impl/login-overlay-v2.js +277 -0
  388. package/dist/ui/overlay/impl/mcp-overlay-v2.d.ts +63 -0
  389. package/dist/ui/overlay/impl/mcp-overlay-v2.js +907 -0
  390. package/dist/ui/overlay/impl/model-overlay-v2.d.ts +57 -13
  391. package/dist/ui/overlay/impl/model-overlay-v2.js +1086 -61
  392. package/dist/ui/overlay/impl/new-overlay-v2.d.ts +37 -6
  393. package/dist/ui/overlay/impl/new-overlay-v2.js +715 -65
  394. package/dist/ui/overlay/impl/notifications-overlay-v2.d.ts +20 -0
  395. package/dist/ui/overlay/impl/notifications-overlay-v2.js +116 -0
  396. package/dist/ui/overlay/impl/onboarding-wizard-overlay-v2.d.ts +76 -0
  397. package/dist/ui/overlay/impl/onboarding-wizard-overlay-v2.js +728 -0
  398. package/dist/ui/overlay/impl/pending-overlay-v2.d.ts +51 -0
  399. package/dist/ui/overlay/impl/pending-overlay-v2.js +445 -0
  400. package/dist/ui/overlay/impl/permission-overlay-v2.js +5 -5
  401. package/dist/ui/overlay/impl/permissions-overlay-v2.d.ts +85 -0
  402. package/dist/ui/overlay/impl/permissions-overlay-v2.js +820 -0
  403. package/dist/ui/overlay/impl/plan-approval-overlay-v2.d.ts +35 -0
  404. package/dist/ui/overlay/impl/plan-approval-overlay-v2.js +181 -0
  405. package/dist/ui/overlay/impl/project-edit-overlay-v2.d.ts +36 -0
  406. package/dist/ui/overlay/impl/project-edit-overlay-v2.js +195 -0
  407. package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +1 -0
  408. package/dist/ui/overlay/impl/projects-overlay-v2.js +278 -44
  409. package/dist/ui/overlay/impl/reset-overlay-v2.d.ts +39 -0
  410. package/dist/ui/overlay/impl/reset-overlay-v2.js +107 -0
  411. package/dist/ui/overlay/impl/resume-overlay-v2.d.ts +60 -0
  412. package/dist/ui/overlay/impl/resume-overlay-v2.js +414 -0
  413. package/dist/ui/overlay/impl/session-mode-overlay-v2.d.ts +43 -0
  414. package/dist/ui/overlay/impl/session-mode-overlay-v2.js +124 -0
  415. package/dist/ui/overlay/impl/tasks-overlay-v2.d.ts +28 -0
  416. package/dist/ui/overlay/impl/tasks-overlay-v2.js +283 -0
  417. package/dist/ui/overlay/impl/team-overlay-v2.d.ts +86 -0
  418. package/dist/ui/overlay/impl/team-overlay-v2.js +692 -0
  419. package/dist/ui/overlay/impl/terminals-overlay-v2.d.ts +26 -0
  420. package/dist/ui/overlay/impl/terminals-overlay-v2.js +217 -0
  421. package/dist/ui/overlay/impl/tools-overlay-v2.js +3 -7
  422. package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +30 -16
  423. package/dist/ui/overlay/impl/tutorial-overlay-v2.js +133 -956
  424. package/dist/ui/overlay/impl/workflow-overlay-v2.js +5 -1
  425. package/dist/ui/overlay/index.d.ts +20 -1
  426. package/dist/ui/overlay/index.js +19 -0
  427. package/dist/ui/overlay/types.d.ts +5 -0
  428. package/dist/ui/overlay-manager.d.ts +43 -0
  429. package/dist/ui/overlay-manager.js +238 -0
  430. package/dist/ui/overlays.js +4 -16
  431. package/dist/ui/permission-overlay.js +6 -5
  432. package/dist/ui/status-bar-controller.d.ts +33 -0
  433. package/dist/ui/status-bar-controller.js +99 -0
  434. package/dist/ui/subagent-renderer.js +3 -19
  435. package/dist/ui/terminal-autocomplete-utils.d.ts +23 -0
  436. package/dist/ui/terminal-autocomplete-utils.js +83 -0
  437. package/dist/ui/terminal-line-builders.d.ts +17 -0
  438. package/dist/ui/terminal-line-builders.js +42 -0
  439. package/dist/ui/terminal-render-item.d.ts +16 -0
  440. package/dist/ui/terminal-render-item.js +267 -0
  441. package/dist/ui/terminal-renderer.d.ts +7 -8
  442. package/dist/ui/terminal-renderer.js +7 -8
  443. package/dist/ui/terminal-types.d.ts +179 -0
  444. package/dist/ui/terminal-types.js +34 -0
  445. package/dist/ui/terminal-ui.d.ts +144 -276
  446. package/dist/ui/terminal-ui.js +384 -1861
  447. package/dist/ui/todo-zone.d.ts +19 -1
  448. package/dist/ui/todo-zone.js +71 -13
  449. package/dist/ui/tool-formatters.js +512 -1
  450. package/dist/ui/turn-metrics.d.ts +56 -0
  451. package/dist/ui/turn-metrics.js +75 -0
  452. package/dist/ui/types.d.ts +28 -0
  453. package/dist/ui/types.js +1 -0
  454. package/dist/ui/vscode-diff-ipc.d.ts +102 -0
  455. package/dist/ui/vscode-diff-ipc.js +385 -0
  456. package/dist/utils/credentials.d.ts +24 -5
  457. package/dist/utils/credentials.js +123 -9
  458. package/dist/utils/format-tokens.d.ts +13 -0
  459. package/dist/utils/format-tokens.js +18 -0
  460. package/dist/utils/git-config.d.ts +26 -0
  461. package/dist/utils/git-config.js +54 -0
  462. package/dist/utils/message-utils.d.ts +61 -0
  463. package/dist/utils/message-utils.js +72 -0
  464. package/dist/utils/model-tiers.d.ts +8 -1
  465. package/dist/utils/model-tiers.js +38 -16
  466. package/dist/utils/open-browser.d.ts +5 -0
  467. package/dist/utils/open-browser.js +32 -0
  468. package/dist/utils/path-safety.js +3 -2
  469. package/dist/utils/project-detection.d.ts +58 -0
  470. package/dist/utils/project-detection.js +424 -0
  471. package/dist/utils/project-memory.js +2 -1
  472. package/dist/utils/project-status.d.ts +2 -2
  473. package/dist/utils/startup-perf.d.ts +18 -0
  474. package/dist/utils/startup-perf.js +60 -0
  475. package/dist/utils/token-tracker.d.ts +62 -0
  476. package/dist/utils/token-tracker.js +150 -0
  477. package/dist/utils/token-types.d.ts +23 -0
  478. package/dist/utils/token-types.js +18 -0
  479. package/dist/utils/types/config-types.d.ts +32 -0
  480. package/dist/utils/types/config-types.js +8 -0
  481. package/dist/utils/update-checker.d.ts +28 -0
  482. package/dist/utils/update-checker.js +106 -0
  483. package/dist/utils/version.d.ts +7 -0
  484. package/dist/utils/version.js +10 -0
  485. package/dist/utils/vscode-detect.d.ts +39 -0
  486. package/dist/utils/vscode-detect.js +137 -0
  487. package/package.json +25 -12
  488. package/dist/commands/handler-types.d.ts +0 -68
  489. package/dist/commands/handler-types.js +0 -8
  490. package/dist/commands/handlers/agent-commands.d.ts +0 -13
  491. package/dist/commands/handlers/agent-commands.js +0 -305
  492. package/dist/commands/handlers/design-commands.d.ts +0 -15
  493. package/dist/commands/handlers/design-commands.js +0 -334
  494. package/dist/commands/handlers/index.d.ts +0 -20
  495. package/dist/commands/handlers/index.js +0 -43
  496. package/dist/commands/handlers/overlay-commands.d.ts +0 -21
  497. package/dist/commands/handlers/overlay-commands.js +0 -287
  498. package/dist/commands/handlers/project-commands.d.ts +0 -11
  499. package/dist/commands/handlers/project-commands.js +0 -167
  500. package/dist/commands/handlers/simple-commands.d.ts +0 -19
  501. package/dist/commands/handlers/simple-commands.js +0 -144
  502. package/dist/commands/registry.d.ts +0 -50
  503. package/dist/commands/registry.js +0 -75
  504. package/dist/index.old.d.ts +0 -7
  505. package/dist/index.old.js +0 -1014
  506. package/dist/repl.d.ts +0 -149
  507. package/dist/repl.js +0 -1151
  508. package/dist/templates/claude-md.d.ts +0 -7
  509. package/dist/templates/claude-md.js +0 -189
  510. package/dist/test-autocomplete.d.ts +0 -7
  511. package/dist/test-autocomplete.js +0 -85
  512. package/dist/test-tabbed-menu.d.ts +0 -7
  513. package/dist/test-tabbed-menu.js +0 -25
  514. package/dist/tool-selector.d.ts +0 -71
  515. package/dist/tool-selector.js +0 -184
  516. package/dist/ui/agents-overlay-v2.d.ts +0 -43
  517. package/dist/ui/agents-overlay-v2.js +0 -809
  518. package/dist/ui/agents-overlay.d.ts +0 -12
  519. package/dist/ui/agents-overlay.js +0 -863
  520. package/dist/ui/anchors-overlay.d.ts +0 -12
  521. package/dist/ui/anchors-overlay.js +0 -775
  522. package/dist/ui/arch-type-overlay.d.ts +0 -15
  523. package/dist/ui/arch-type-overlay.js +0 -201
  524. package/dist/ui/ask-user-overlay-v2.d.ts +0 -26
  525. package/dist/ui/ask-user-overlay-v2.js +0 -555
  526. package/dist/ui/ask-user-simple-overlay-v2.d.ts +0 -25
  527. package/dist/ui/ask-user-simple-overlay-v2.js +0 -215
  528. package/dist/ui/backlog-overlay.d.ts +0 -32
  529. package/dist/ui/backlog-overlay.js +0 -652
  530. package/dist/ui/commands-overlay-v2.d.ts +0 -33
  531. package/dist/ui/commands-overlay-v2.js +0 -441
  532. package/dist/ui/commands-overlay.d.ts +0 -16
  533. package/dist/ui/commands-overlay.js +0 -439
  534. package/dist/ui/config-overlay.d.ts +0 -35
  535. package/dist/ui/config-overlay.js +0 -707
  536. package/dist/ui/docs-overlay.d.ts +0 -17
  537. package/dist/ui/docs-overlay.js +0 -303
  538. package/dist/ui/footer-v2.d.ts +0 -222
  539. package/dist/ui/footer-v2.js +0 -1349
  540. package/dist/ui/help-overlay-v2.d.ts +0 -34
  541. package/dist/ui/help-overlay-v2.js +0 -309
  542. package/dist/ui/help-overlay.d.ts +0 -16
  543. package/dist/ui/help-overlay.js +0 -316
  544. package/dist/ui/init-overlay-v2.d.ts +0 -34
  545. package/dist/ui/init-overlay-v2.js +0 -600
  546. package/dist/ui/init-overlay.d.ts +0 -34
  547. package/dist/ui/init-overlay.js +0 -604
  548. package/dist/ui/input-prompt-v2.d.ts +0 -180
  549. package/dist/ui/input-prompt-v2.js +0 -999
  550. package/dist/ui/iteration-limit-overlay-v2.d.ts +0 -21
  551. package/dist/ui/iteration-limit-overlay-v2.js +0 -114
  552. package/dist/ui/keys-overlay-v2.d.ts +0 -41
  553. package/dist/ui/keys-overlay-v2.js +0 -248
  554. package/dist/ui/mascot-overlay-v2.d.ts +0 -41
  555. package/dist/ui/mascot-overlay-v2.js +0 -138
  556. package/dist/ui/mascot-overlay.d.ts +0 -21
  557. package/dist/ui/mascot-overlay.js +0 -146
  558. package/dist/ui/model-overlay-v2.d.ts +0 -49
  559. package/dist/ui/model-overlay-v2.js +0 -118
  560. package/dist/ui/model-overlay.d.ts +0 -27
  561. package/dist/ui/model-overlay.js +0 -221
  562. package/dist/ui/model-warning-overlay.d.ts +0 -30
  563. package/dist/ui/model-warning-overlay.js +0 -169
  564. package/dist/ui/new-overlay.d.ts +0 -34
  565. package/dist/ui/new-overlay.js +0 -604
  566. package/dist/ui/overlay/impl/init-overlay-v2.d.ts +0 -77
  567. package/dist/ui/overlay/impl/init-overlay-v2.js +0 -593
  568. package/dist/ui/overlay/overlay-types.d.ts +0 -128
  569. package/dist/ui/overlay/overlay-types.js +0 -22
  570. package/dist/ui/overlays/help-overlay-v2.d.ts +0 -28
  571. package/dist/ui/overlays/help-overlay-v2.js +0 -198
  572. package/dist/ui/overlays/index.d.ts +0 -11
  573. package/dist/ui/overlays/index.js +0 -11
  574. package/dist/ui/permission-overlay-v2.d.ts +0 -36
  575. package/dist/ui/permission-overlay-v2.js +0 -380
  576. package/dist/ui/projects-overlay.d.ts +0 -19
  577. package/dist/ui/projects-overlay.js +0 -484
  578. package/dist/ui/theme-overlay-v2.d.ts +0 -42
  579. package/dist/ui/theme-overlay-v2.js +0 -135
  580. package/dist/ui/theme-overlay.d.ts +0 -24
  581. package/dist/ui/theme-overlay.js +0 -127
  582. package/dist/ui/tools-overlay-v2.d.ts +0 -47
  583. package/dist/ui/tools-overlay-v2.js +0 -218
  584. package/dist/ui/tools-overlay.d.ts +0 -34
  585. package/dist/ui/tools-overlay.js +0 -230
  586. package/dist/ui/tutorial-overlay-v2.d.ts +0 -31
  587. package/dist/ui/tutorial-overlay-v2.js +0 -1035
  588. package/dist/ui/tutorial-overlay.d.ts +0 -11
  589. package/dist/ui/tutorial-overlay.js +0 -1034
  590. package/dist/ui/workflow-overlay.d.ts +0 -22
  591. package/dist/ui/workflow-overlay.js +0 -636
@@ -0,0 +1,907 @@
1
+ /**
2
+ * MCP Overlay V2
3
+ *
4
+ * Shows connected MCP servers and their tools.
5
+ * Extends TabbedListOverlayV2 for consistent UI.
6
+ *
7
+ * Features:
8
+ * - Single tab (all servers)
9
+ * - Server list with status and tool count
10
+ * - Detail view with tool list
11
+ * - Restart/disconnect actions
12
+ * - Add server form (with hot-reload)
13
+ * - Empty state with config file instructions
14
+ */
15
+ import { TabbedListOverlayV2, BaseScreen, stay, pushScreen, popScreen, closeOverlay, isEscape, isCtrlC, isQuit, isEnter, isSpace, isTab, isShiftTab, isBackspace, isDelete, isLeftArrow, isRightArrow, isUpArrow, isDownArrow, isHome, isEnd, isCtrlA, isCtrlE, isPrintable, getPrintableChar, renderBorder, truncate, wrapText, } from '../../base/index.js';
16
+ import { getMCPConfigPath, saveMCPServer, getExistingServerNames, } from '../../../settings/mcp-config.js';
17
+ // =============================================================================
18
+ // Constants
19
+ // =============================================================================
20
+ const PAGE_SIZE = 8;
21
+ // =============================================================================
22
+ // Detail Screen
23
+ // =============================================================================
24
+ class ServerDetailScreen extends BaseScreen {
25
+ item;
26
+ manager;
27
+ styles;
28
+ getWidth;
29
+ onRefresh;
30
+ message = null;
31
+ selectedToolIndex = 0;
32
+ toolScrollOffset = 0;
33
+ /** Max tools visible in the scrollable list area */
34
+ static TOOL_PAGE_SIZE = 8;
35
+ constructor(item, manager, styles, getWidth, onRefresh) {
36
+ super();
37
+ this.item = item;
38
+ this.manager = manager;
39
+ this.styles = styles;
40
+ this.getWidth = getWidth;
41
+ this.onRefresh = onRefresh;
42
+ }
43
+ getMinHeight() {
44
+ return 20;
45
+ }
46
+ render() {
47
+ const s = this.styles;
48
+ const cols = this.getWidth();
49
+ const border = renderBorder(cols, s);
50
+ const lines = [];
51
+ // Re-read status from client (may have changed after restart/disconnect)
52
+ const currentStatus = this.item.client.status;
53
+ const statusDisplay = formatStatus(currentStatus, s);
54
+ // Header
55
+ lines.push(border);
56
+ lines.push(` ${s.primaryBold(`MCP Server: ${this.item.name}`)}`);
57
+ lines.push('');
58
+ // Server info
59
+ lines.push(` ${s.secondary('Status:')} ${statusDisplay}`);
60
+ lines.push(` ${s.secondary('Transport:')} ${this.item.transport} ${s.muted(`\u2014 ${this.item.transportDetail}`)}`);
61
+ lines.push('');
62
+ // Message (after restart/disconnect)
63
+ if (this.message) {
64
+ lines.push(` ${s.secondary(this.message)}`);
65
+ lines.push('');
66
+ }
67
+ // Tools
68
+ const tools = this.item.tools;
69
+ if (tools.length > 0) {
70
+ lines.push(` ${s.secondary(`Tools (${String(tools.length)}):`)}`);
71
+ // Clamp selection
72
+ if (this.selectedToolIndex >= tools.length) {
73
+ this.selectedToolIndex = tools.length - 1;
74
+ }
75
+ // Adjust scroll offset to keep selection visible
76
+ const pageSize = ServerDetailScreen.TOOL_PAGE_SIZE;
77
+ if (this.selectedToolIndex < this.toolScrollOffset) {
78
+ this.toolScrollOffset = this.selectedToolIndex;
79
+ }
80
+ else if (this.selectedToolIndex >= this.toolScrollOffset + pageSize) {
81
+ this.toolScrollOffset = this.selectedToolIndex - pageSize + 1;
82
+ }
83
+ // Render visible tools
84
+ const visibleEnd = Math.min(this.toolScrollOffset + pageSize, tools.length);
85
+ // Scroll indicator (top)
86
+ if (this.toolScrollOffset > 0) {
87
+ lines.push(` ${s.muted(`\u2191 ${String(this.toolScrollOffset)} more above`)}`);
88
+ }
89
+ for (let i = this.toolScrollOffset; i < visibleEnd; i++) {
90
+ const tool = tools[i];
91
+ const isSelected = i === this.selectedToolIndex;
92
+ const prefix = isSelected ? s.primary(' \u25ba ') : ' ';
93
+ const toolName = truncate(tool.name, 30);
94
+ const desc = tool.description
95
+ ? s.muted(` \u2014 ${truncate(tool.description, Math.max(cols - 42, 20))}`)
96
+ : '';
97
+ const name = isSelected ? s.primary(toolName) : toolName;
98
+ lines.push(`${prefix}${name}${desc}`);
99
+ }
100
+ // Scroll indicator (bottom)
101
+ const remaining = tools.length - visibleEnd;
102
+ if (remaining > 0) {
103
+ lines.push(` ${s.muted(`\u2193 ${String(remaining)} more below`)}`);
104
+ }
105
+ }
106
+ else if (currentStatus === 'connected') {
107
+ lines.push(` ${s.muted('No tools discovered.')}`);
108
+ }
109
+ else {
110
+ lines.push(` ${s.muted('Server not connected \u2014 tools unavailable.')}`);
111
+ }
112
+ lines.push('');
113
+ // Pad to consistent height
114
+ while (lines.length < 16) {
115
+ lines.push('');
116
+ }
117
+ // Footer
118
+ lines.push(border);
119
+ const footerHint = tools.length > 0
120
+ ? '\u2191\u2193/jk Navigate \u00b7 Enter Details \u00b7 r Restart \u00b7 d Disconnect \u00b7 q/Esc Back'
121
+ : 'r Restart \u00b7 d Disconnect \u00b7 q/Esc Back';
122
+ lines.push(s.muted(` ${footerHint}`));
123
+ return lines;
124
+ }
125
+ handleKey(data) {
126
+ if (isCtrlC(data)) {
127
+ return closeOverlay({ viewed: true });
128
+ }
129
+ if (isEscape(data) || isQuit(data)) {
130
+ return popScreen();
131
+ }
132
+ const char = data.toString();
133
+ const tools = this.item.tools;
134
+ // Tool navigation — Up/Down/j/k
135
+ if (tools.length > 0) {
136
+ if (isUpArrow(data) || char === 'k') {
137
+ if (this.selectedToolIndex > 0) {
138
+ this.selectedToolIndex--;
139
+ }
140
+ return stay(true);
141
+ }
142
+ if (isDownArrow(data) || char === 'j') {
143
+ if (this.selectedToolIndex < tools.length - 1) {
144
+ this.selectedToolIndex++;
145
+ }
146
+ return stay(true);
147
+ }
148
+ // Enter — push tool detail screen
149
+ if (isEnter(data)) {
150
+ const selectedTool = tools[this.selectedToolIndex];
151
+ return pushScreen(new MCPToolDetailScreen(selectedTool, this.item.name, this.styles, this.getWidth));
152
+ }
153
+ }
154
+ // Restart
155
+ if (char === 'r') {
156
+ this.message = 'Restarting...';
157
+ this.onRefresh();
158
+ void (async () => {
159
+ try {
160
+ const client = this.item.client;
161
+ await client.disconnect();
162
+ await client.connect();
163
+ const newTools = await client.listTools();
164
+ this.item.tools = newTools;
165
+ this.item.toolCount = newTools.length;
166
+ this.selectedToolIndex = 0;
167
+ this.toolScrollOffset = 0;
168
+ this.message = `Restarted \u2014 ${String(newTools.length)} tools discovered`;
169
+ }
170
+ catch {
171
+ this.message = 'Restart failed';
172
+ }
173
+ this.onRefresh();
174
+ })();
175
+ return stay(false);
176
+ }
177
+ // Disconnect
178
+ if (char === 'd') {
179
+ this.message = 'Disconnecting...';
180
+ this.onRefresh();
181
+ void (async () => {
182
+ try {
183
+ await this.item.client.disconnect();
184
+ this.item.tools = [];
185
+ this.item.toolCount = 0;
186
+ this.selectedToolIndex = 0;
187
+ this.toolScrollOffset = 0;
188
+ this.message = 'Disconnected';
189
+ this.onRefresh();
190
+ }
191
+ catch {
192
+ this.message = 'Disconnect failed';
193
+ }
194
+ this.onRefresh();
195
+ })();
196
+ return stay(false);
197
+ }
198
+ return stay(false);
199
+ }
200
+ }
201
+ // =============================================================================
202
+ // Tool Detail Screen
203
+ // =============================================================================
204
+ /**
205
+ * Full-screen detail view for a single MCP tool.
206
+ * Shows name, description (word-wrapped), and input schema parameters.
207
+ * Follows the same pattern as ToolDetailScreen in tools-overlay-v2.
208
+ */
209
+ class MCPToolDetailScreen extends BaseScreen {
210
+ tool;
211
+ serverName;
212
+ styles;
213
+ getWidth;
214
+ constructor(tool, serverName, styles, getWidth) {
215
+ super();
216
+ this.tool = tool;
217
+ this.serverName = serverName;
218
+ this.styles = styles;
219
+ this.getWidth = getWidth;
220
+ }
221
+ render() {
222
+ const s = this.styles;
223
+ const cols = this.getWidth();
224
+ const border = renderBorder(cols, s);
225
+ const maxLineWidth = cols - 2;
226
+ const lines = [];
227
+ // Header
228
+ lines.push(border);
229
+ lines.push(` ${s.primaryBold('MCP Tool Details')}`);
230
+ lines.push('');
231
+ // Tool name (prefixed with server name)
232
+ lines.push(` ${s.muted('Name:')} ${s.primaryBold(`mcp_${this.serverName}_${this.tool.name}`)}`);
233
+ lines.push(` ${s.muted('Server:')} ${this.serverName}`);
234
+ lines.push('');
235
+ // Description (word-wrapped, never truncated)
236
+ lines.push(` ${s.muted('Description:')}`);
237
+ const description = this.tool.description ?? 'No description available.';
238
+ const wrappedDesc = wrapText(description, Math.min(maxLineWidth - 4, 70));
239
+ for (const line of wrappedDesc) {
240
+ lines.push(` ${s.secondary(line)}`);
241
+ }
242
+ lines.push('');
243
+ // Input schema parameters
244
+ const props = this.tool.inputSchema.properties;
245
+ const required = new Set(this.tool.inputSchema.required ?? []);
246
+ if (props && Object.keys(props).length > 0) {
247
+ const entries = Object.entries(props);
248
+ // Sort: required first, then optional
249
+ entries.sort(([a], [b]) => {
250
+ const aReq = required.has(a);
251
+ const bReq = required.has(b);
252
+ if (aReq && !bReq)
253
+ return -1;
254
+ if (!aReq && bReq)
255
+ return 1;
256
+ return 0;
257
+ });
258
+ lines.push(` ${s.muted('Parameters:')}`);
259
+ for (const [paramName, paramDef] of entries) {
260
+ const def = paramDef;
261
+ const paramType = typeof def.type === 'string' ? def.type : 'any';
262
+ const isRequired = required.has(paramName);
263
+ const reqLabel = isRequired ? s.warning('*') : ' ';
264
+ const typeStr = s.muted(`(${paramType})`);
265
+ lines.push(` ${reqLabel} ${s.secondary(paramName)} ${typeStr}`);
266
+ // Parameter description (word-wrapped under the param name)
267
+ if (typeof def.description === 'string') {
268
+ const paramDescWrapped = wrapText(def.description, Math.min(maxLineWidth - 10, 64));
269
+ for (const pdLine of paramDescWrapped) {
270
+ lines.push(` ${s.muted(pdLine)}`);
271
+ }
272
+ }
273
+ }
274
+ lines.push('');
275
+ lines.push(` ${s.muted('* = required')}`);
276
+ }
277
+ else {
278
+ lines.push(` ${s.muted('Parameters:')} ${s.muted('None')}`);
279
+ }
280
+ lines.push('');
281
+ // Footer
282
+ lines.push(border);
283
+ lines.push(` ${s.muted('q/Esc Back')}`);
284
+ return lines;
285
+ }
286
+ handleKey(data) {
287
+ if (isCtrlC(data)) {
288
+ return closeOverlay({ viewed: true });
289
+ }
290
+ if (isEscape(data) || isQuit(data)) {
291
+ return popScreen();
292
+ }
293
+ return stay(false);
294
+ }
295
+ getMinHeight() {
296
+ return 20;
297
+ }
298
+ }
299
+ /**
300
+ * Form screen for adding a new MCP server.
301
+ * Text fields accept character input; cycle fields toggle with Enter/Space.
302
+ * Follows the same navigation pattern as /config overlay.
303
+ */
304
+ class AddServerScreen extends BaseScreen {
305
+ agent;
306
+ getManager;
307
+ styles;
308
+ getWidth;
309
+ onServerAdded;
310
+ onRefresh;
311
+ projectRoot;
312
+ formState;
313
+ existingNames;
314
+ constructor(agent, getManager, styles, getWidth, onServerAdded, onRefresh, projectRoot) {
315
+ super();
316
+ this.agent = agent;
317
+ this.getManager = getManager;
318
+ this.styles = styles;
319
+ this.getWidth = getWidth;
320
+ this.onServerAdded = onServerAdded;
321
+ this.onRefresh = onRefresh;
322
+ this.projectRoot = projectRoot;
323
+ this.existingNames = getExistingServerNames(projectRoot);
324
+ const items = [
325
+ { type: 'text', id: 'name', label: 'Name', value: '', hint: 'Unique server name (e.g., filesystem)' },
326
+ { type: 'cycle', id: 'transport', label: 'Transport', value: 'stdio', options: ['stdio', 'http'] },
327
+ { type: 'text', id: 'command', label: 'Command', value: '', hint: 'Command to run (e.g., npx)' },
328
+ { type: 'text', id: 'args', label: 'Args', value: '', hint: 'Space-separated arguments (optional)' },
329
+ ];
330
+ // Add scope toggle only when a project is bound
331
+ if (this.projectRoot) {
332
+ items.push({ type: 'cycle', id: 'scope', label: 'Scope', value: 'Global', options: ['Global', 'Project'] });
333
+ }
334
+ this.formState = {
335
+ items,
336
+ activeIndex: 0,
337
+ cursorPos: 0,
338
+ saving: false,
339
+ message: null,
340
+ };
341
+ }
342
+ getMinHeight() {
343
+ return 20;
344
+ }
345
+ // ── helpers ──────────────────────────────────────────────────────────────
346
+ get activeItem() { return this.formState.items[this.formState.activeIndex]; }
347
+ get isTextItem() { return this.activeItem.type === 'text'; }
348
+ get transport() {
349
+ const t = this.formState.items.find((i) => i.id === 'transport');
350
+ return t ? t.value : 'stdio';
351
+ }
352
+ get scope() {
353
+ const s = this.formState.items.find((i) => i.id === 'scope');
354
+ return s ? s.value : 'Global';
355
+ }
356
+ get itemCount() { return this.formState.items.length; }
357
+ // ── render ───────────────────────────────────────────────────────────────
358
+ render() {
359
+ const s = this.styles;
360
+ const cols = this.getWidth();
361
+ const border = renderBorder(cols, s);
362
+ const lines = [];
363
+ const labelWidth = 12;
364
+ // Header
365
+ lines.push(border);
366
+ lines.push(` ${s.primaryBold('Add MCP Server')}`);
367
+ lines.push('');
368
+ for (let i = 0; i < this.formState.items.length; i++) {
369
+ const item = this.formState.items[i];
370
+ const isActive = i === this.formState.activeIndex && !this.formState.saving;
371
+ const prefix = isActive ? s.primary(' \u276f ') : ' ';
372
+ const label = isActive
373
+ ? s.primary(item.label.padEnd(labelWidth))
374
+ : s.secondary(item.label.padEnd(labelWidth));
375
+ // Skip args/headers row when it doesn't apply
376
+ if (item.id === 'args' && this.transport === 'http')
377
+ continue;
378
+ if (item.type === 'text') {
379
+ if (isActive) {
380
+ const before = item.value.slice(0, this.formState.cursorPos);
381
+ const after = item.value.slice(this.formState.cursorPos);
382
+ const cursor = s.primaryBold('\u2502');
383
+ lines.push(`${prefix}${label}${before}${cursor}${after}`);
384
+ }
385
+ else {
386
+ const display = item.value || s.muted(item.hint);
387
+ lines.push(`${prefix}${label}${display}`);
388
+ }
389
+ if (item.error) {
390
+ lines.push(` ${''.padEnd(labelWidth)}${s.error(item.error)}`);
391
+ }
392
+ }
393
+ else {
394
+ // Cycle toggle — render all options, highlight current
395
+ const optionStr = item.options
396
+ .map((opt) => (opt === item.value ? s.primary(opt) : s.muted(opt)))
397
+ .join(s.muted(' / '));
398
+ lines.push(`${prefix}${label}${optionStr}`);
399
+ }
400
+ }
401
+ lines.push('');
402
+ // Status message
403
+ if (this.formState.message) {
404
+ lines.push(` ${this.formState.saving ? s.warning(this.formState.message) : s.success(this.formState.message)}`);
405
+ }
406
+ // Pad to consistent height
407
+ while (lines.length < 16) {
408
+ lines.push('');
409
+ }
410
+ // Footer
411
+ lines.push(border);
412
+ const hint = this.isTextItem
413
+ ? '\u2191\u2193 Navigate \u00b7 Type to edit \u00b7 Enter Submit \u00b7 Esc Cancel'
414
+ : '\u2191\u2193 Navigate \u00b7 Space Toggle \u00b7 Enter Submit \u00b7 Esc Cancel';
415
+ lines.push(s.muted(` ${hint}`));
416
+ return lines;
417
+ }
418
+ // ── key handling ─────────────────────────────────────────────────────────
419
+ handleKey(data) {
420
+ if (isCtrlC(data)) {
421
+ return closeOverlay({ viewed: true });
422
+ }
423
+ if (this.formState.saving) {
424
+ return stay(false);
425
+ }
426
+ if (isEscape(data)) {
427
+ return popScreen();
428
+ }
429
+ // Navigation — Up/Down (always available)
430
+ if (isUpArrow(data) || isShiftTab(data)) {
431
+ return this.navigate(-1);
432
+ }
433
+ if (isDownArrow(data) || isTab(data)) {
434
+ return this.navigate(1);
435
+ }
436
+ // Enter always submits, regardless of active field
437
+ if (isEnter(data)) {
438
+ return this.handleSubmit();
439
+ }
440
+ // ── Cycle items: Space toggles ──────────────────────────────────────
441
+ if (this.activeItem.type === 'cycle') {
442
+ if (isSpace(data)) {
443
+ return this.cycleValue();
444
+ }
445
+ // Cycle items don't accept other input
446
+ return stay(false);
447
+ }
448
+ // At this point activeItem is guaranteed to be 'text' (cycle returned early above)
449
+ return this.handleTextInput(data);
450
+ return stay(false);
451
+ }
452
+ // ── text input handling ───────────────────────────────────────────────────
453
+ handleTextInput(data) {
454
+ const item = this.formState.items[this.formState.activeIndex];
455
+ if (item.type !== 'text')
456
+ return stay(false);
457
+ if (isBackspace(data)) {
458
+ if (this.formState.cursorPos > 0) {
459
+ item.value = item.value.slice(0, this.formState.cursorPos - 1) + item.value.slice(this.formState.cursorPos);
460
+ this.formState.cursorPos--;
461
+ item.error = undefined;
462
+ }
463
+ return stay(true);
464
+ }
465
+ if (isDelete(data)) {
466
+ if (this.formState.cursorPos < item.value.length) {
467
+ item.value = item.value.slice(0, this.formState.cursorPos) + item.value.slice(this.formState.cursorPos + 1);
468
+ item.error = undefined;
469
+ }
470
+ return stay(true);
471
+ }
472
+ if (isLeftArrow(data)) {
473
+ if (this.formState.cursorPos > 0)
474
+ this.formState.cursorPos--;
475
+ return stay(true);
476
+ }
477
+ if (isRightArrow(data)) {
478
+ if (this.formState.cursorPos < item.value.length)
479
+ this.formState.cursorPos++;
480
+ return stay(true);
481
+ }
482
+ if (isHome(data) || isCtrlA(data)) {
483
+ this.formState.cursorPos = 0;
484
+ return stay(true);
485
+ }
486
+ if (isEnd(data) || isCtrlE(data)) {
487
+ this.formState.cursorPos = item.value.length;
488
+ return stay(true);
489
+ }
490
+ if (isPrintable(data)) {
491
+ const ch = getPrintableChar(data);
492
+ if (ch) {
493
+ item.value = item.value.slice(0, this.formState.cursorPos) + ch + item.value.slice(this.formState.cursorPos);
494
+ this.formState.cursorPos++;
495
+ item.error = undefined;
496
+ }
497
+ return stay(true);
498
+ }
499
+ return stay(false);
500
+ }
501
+ // ── navigation helpers ───────────────────────────────────────────────────
502
+ navigate(direction) {
503
+ let next = this.formState.activeIndex + direction;
504
+ // Skip hidden items (args when transport is http)
505
+ while (next >= 0 && next < this.itemCount) {
506
+ const item = this.formState.items[next];
507
+ if (item.id === 'args' && this.transport === 'http') {
508
+ next += direction;
509
+ continue;
510
+ }
511
+ break;
512
+ }
513
+ if (next < 0 || next >= this.itemCount) {
514
+ return stay(false);
515
+ }
516
+ this.formState.activeIndex = next;
517
+ // Set cursor to end of text value when entering a text field
518
+ const newItem = this.formState.items[next];
519
+ if (newItem.type === 'text') {
520
+ this.formState.cursorPos = newItem.value.length;
521
+ }
522
+ return stay(true);
523
+ }
524
+ cycleValue() {
525
+ const item = this.activeItem;
526
+ if (item.type !== 'cycle')
527
+ return stay(false);
528
+ const currentIdx = item.options.indexOf(item.value);
529
+ const nextIdx = (currentIdx + 1) % item.options.length;
530
+ item.value = item.options[nextIdx];
531
+ // When transport changes, update the command/url field labels
532
+ if (item.id === 'transport') {
533
+ this.onTransportChange();
534
+ }
535
+ return stay(true);
536
+ }
537
+ onTransportChange() {
538
+ const isHttp = this.transport === 'http';
539
+ const cmdField = this.formState.items.find((i) => i.id === 'command' || i.id === 'url');
540
+ if (cmdField && cmdField.type === 'text') {
541
+ cmdField.id = isHttp ? 'url' : 'command';
542
+ cmdField.label = isHttp ? 'URL' : 'Command';
543
+ cmdField.hint = isHttp
544
+ ? 'Server URL (e.g., http://localhost:3000/mcp)'
545
+ : 'Command to run (e.g., npx)';
546
+ cmdField.error = undefined;
547
+ }
548
+ }
549
+ getTextItem(id) {
550
+ const item = this.formState.items.find((i) => i.id === id);
551
+ return item?.type === 'text' ? item : undefined;
552
+ }
553
+ handleSubmit() {
554
+ const nameField = this.getTextItem('name');
555
+ const cmdField = this.getTextItem('command') ?? this.getTextItem('url');
556
+ if (!nameField || !cmdField)
557
+ return stay(false);
558
+ let hasError = false;
559
+ const transport = this.transport;
560
+ // Name validation
561
+ const name = nameField.value.trim();
562
+ if (!name) {
563
+ nameField.error = 'Name is required';
564
+ hasError = true;
565
+ }
566
+ else if (this.existingNames.has(name)) {
567
+ nameField.error = 'Name already exists';
568
+ hasError = true;
569
+ }
570
+ else if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
571
+ nameField.error = 'Only letters, numbers, hyphens, underscores';
572
+ hasError = true;
573
+ }
574
+ // Command/URL validation
575
+ const commandOrUrl = cmdField.value.trim();
576
+ if (!commandOrUrl) {
577
+ cmdField.error = `${transport === 'stdio' ? 'Command' : 'URL'} is required`;
578
+ hasError = true;
579
+ }
580
+ if (hasError)
581
+ return stay(true);
582
+ // Build config entry
583
+ const entry = {};
584
+ if (transport === 'stdio') {
585
+ entry.command = commandOrUrl;
586
+ const argsField = this.getTextItem('args');
587
+ const argsStr = argsField?.value.trim();
588
+ if (argsStr) {
589
+ entry.args = argsStr.split(/\s+/);
590
+ }
591
+ }
592
+ else {
593
+ entry.url = commandOrUrl;
594
+ }
595
+ const scope = this.scope === 'Project' ? 'project' : 'global';
596
+ // Save and connect
597
+ this.formState.saving = true;
598
+ this.formState.message = 'Connecting...';
599
+ this.onRefresh();
600
+ void (async () => {
601
+ try {
602
+ // 1. Save to config file
603
+ saveMCPServer(name, entry, scope, this.projectRoot);
604
+ // 2. Get or create manager
605
+ const manager = await this.getManager();
606
+ // 3. Add server and connect
607
+ const client = await manager.addServer({
608
+ name,
609
+ transport: transport,
610
+ command: entry.command,
611
+ args: entry.args,
612
+ url: entry.url,
613
+ });
614
+ // 4. Discover tools
615
+ let tools = [];
616
+ try {
617
+ tools = await client.listTools();
618
+ }
619
+ catch {
620
+ // Tools may not be available yet
621
+ }
622
+ // 5. Register tools with agent
623
+ if (this.agent && tools.length > 0) {
624
+ const agentTools = await manager.discoverToolsFrom(name);
625
+ this.agent.registerTools(agentTools);
626
+ }
627
+ // 6. Build server item for the list
628
+ const newItem = {
629
+ tabId: 'all',
630
+ name,
631
+ status: client.status,
632
+ transport,
633
+ transportDetail: entry.command ?? entry.url ?? '',
634
+ toolCount: tools.length,
635
+ tools,
636
+ client,
637
+ };
638
+ // 7. Notify parent overlay
639
+ this.onServerAdded(newItem);
640
+ this.formState.saving = false;
641
+ this.formState.message = `Added "${name}" \u2014 ${String(tools.length)} tools`;
642
+ this.onRefresh();
643
+ }
644
+ catch (err) {
645
+ this.formState.saving = false;
646
+ this.formState.message = `Failed: ${err instanceof Error ? err.message : 'Unknown error'}`;
647
+ this.onRefresh();
648
+ }
649
+ })();
650
+ return stay(true);
651
+ }
652
+ }
653
+ // =============================================================================
654
+ // Helpers
655
+ // =============================================================================
656
+ function formatStatus(status, s) {
657
+ switch (status) {
658
+ case 'connected':
659
+ return s.success('connected');
660
+ case 'connecting':
661
+ return s.warning('connecting');
662
+ case 'error':
663
+ return s.error('error');
664
+ case 'disconnected':
665
+ return s.muted('disconnected');
666
+ default:
667
+ return s.muted(status);
668
+ }
669
+ }
670
+ async function buildServerItems(manager) {
671
+ const items = [];
672
+ for (const client of manager.getServers()) {
673
+ let tools = [];
674
+ try {
675
+ if (client.isConnected) {
676
+ tools = await client.listTools();
677
+ }
678
+ }
679
+ catch {
680
+ // Failed to list tools — show 0
681
+ }
682
+ // Determine transport info from the client name
683
+ // We don't have direct access to config, so use what we can
684
+ const transport = client.isConnected ? 'stdio/http' : 'unknown';
685
+ items.push({
686
+ tabId: 'all',
687
+ name: client.name,
688
+ status: client.status,
689
+ transport,
690
+ transportDetail: '',
691
+ toolCount: tools.length,
692
+ tools,
693
+ client,
694
+ });
695
+ }
696
+ return items;
697
+ }
698
+ // =============================================================================
699
+ // MCP Overlay V2
700
+ // =============================================================================
701
+ export class MCPOverlayV2 extends TabbedListOverlayV2 {
702
+ type = 'inline';
703
+ id = 'mcp-overlay-v2';
704
+ manager;
705
+ agent;
706
+ getManager;
707
+ projectRoot;
708
+ initialized = false;
709
+ listMessage = null;
710
+ constructor(manager, agent, getManager, projectRoot) {
711
+ const tabs = [
712
+ { id: 'all', label: 'All' },
713
+ ];
714
+ super({
715
+ title: 'MCP Servers',
716
+ tabs,
717
+ items: [],
718
+ pageSize: PAGE_SIZE,
719
+ filterByTab: () => true,
720
+ getSearchText: (item) => `${item.name} ${item.status} ${item.tools.map((t) => t.name).join(' ')}`,
721
+ renderItem: (item, isSelected, styles) => {
722
+ const prefix = isSelected ? styles.primary(' \u25ba ') : ' ';
723
+ const namePadded = item.name.padEnd(20);
724
+ const statusPadded = formatStatus(item.status, styles).padEnd(20);
725
+ const toolInfo = item.status === 'connected'
726
+ ? styles.muted(`${String(item.toolCount)} tools`)
727
+ : styles.muted('\u2014');
728
+ const name = isSelected ? styles.primary(namePadded) : namePadded;
729
+ return `${prefix}${name} ${statusPadded} ${toolInfo}`;
730
+ },
731
+ footerHints: (searchMode) => {
732
+ if (searchMode) {
733
+ return 'Type to filter \u00b7 \u2191\u2193/jk Navigate \u00b7 Enter Details \u00b7 Esc Exit search';
734
+ }
735
+ return '\u2191\u2193/jk \u00b7 / Search \u00b7 Enter Details \u00b7 a Add \u00b7 r Restart \u00b7 d Disconnect \u00b7 q/Esc Close';
736
+ },
737
+ emptyMessage: '', // We handle empty state in render()
738
+ noResultsMessage: 'No servers match the search.',
739
+ showCount: false,
740
+ });
741
+ this.manager = manager;
742
+ this.agent = agent;
743
+ this.getManager = getManager;
744
+ this.projectRoot = projectRoot;
745
+ this.minHeight = 18;
746
+ }
747
+ /**
748
+ * Load server data on first render.
749
+ */
750
+ async loadItems() {
751
+ if (this.initialized)
752
+ return;
753
+ this.initialized = true;
754
+ if (!this.manager)
755
+ return;
756
+ const items = await buildServerItems(this.manager);
757
+ this.state.items = items;
758
+ this.state.filteredItems = [...items];
759
+ }
760
+ /**
761
+ * Override render to load items on first call and handle empty state.
762
+ */
763
+ render(context) {
764
+ this.styles = context.styles;
765
+ this.termWidth = context.width;
766
+ // Async load — render loading state first, then re-render
767
+ if (!this.initialized) {
768
+ void this.loadItems().then(() => {
769
+ this.renderCallback?.();
770
+ });
771
+ const s = this.getStyles();
772
+ const border = renderBorder(context.width, s);
773
+ return {
774
+ lines: [
775
+ border,
776
+ ` ${s.primaryBold('MCP Servers')}`,
777
+ '',
778
+ ` ${s.muted('Loading...')}`,
779
+ '',
780
+ border,
781
+ s.muted(' q/Esc Close'),
782
+ ],
783
+ minHeight: 18,
784
+ };
785
+ }
786
+ // Empty state — show config instructions (but allow 'a' to add)
787
+ if (this.state.items.length === 0 && this.screenStack.size() <= 1) {
788
+ return this.renderEmptyState(context);
789
+ }
790
+ // Inject list message if present (shown after add)
791
+ const result = super.render(context);
792
+ if (this.listMessage) {
793
+ const s = this.getStyles();
794
+ // Insert message before the footer border
795
+ const msg = ` ${s.success(this.listMessage)}`;
796
+ result.lines.splice(-3, 0, msg);
797
+ // Clear message after a brief display
798
+ setTimeout(() => {
799
+ this.listMessage = null;
800
+ this.renderCallback?.();
801
+ }, 3000);
802
+ }
803
+ return result;
804
+ }
805
+ /**
806
+ * Render helpful empty state with config file instructions.
807
+ */
808
+ renderEmptyState(context) {
809
+ const s = this.getStyles();
810
+ const border = renderBorder(context.width, s);
811
+ const configPath = getMCPConfigPath();
812
+ const lines = [
813
+ border,
814
+ ` ${s.primaryBold('MCP Servers')} ${s.muted('(0 configured)')}`,
815
+ '',
816
+ ` ${s.muted('No MCP servers configured.')}`,
817
+ '',
818
+ ` ${s.secondary('Press')} ${s.primary('a')} ${s.secondary('to add a server, or edit the config file:')}`,
819
+ ` ${s.muted(configPath)}`,
820
+ '',
821
+ ` ${s.muted('{')}`,
822
+ ` ${s.muted(' "mcpServers": {')}`,
823
+ ` ${s.muted(' "filesystem": {')}`,
824
+ ` ${s.muted(' "command": "npx",')}`,
825
+ ` ${s.muted(' "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]')}`,
826
+ ` ${s.muted(' }')}`,
827
+ ` ${s.muted(' }')}`,
828
+ ` ${s.muted('}')}`,
829
+ '',
830
+ border,
831
+ s.muted(' a Add \u00b7 q/Esc Close'),
832
+ ];
833
+ return { lines, minHeight: 18 };
834
+ }
835
+ /**
836
+ * Handle custom keys (a/r/d) on the list screen.
837
+ * Only intercepts when the screen stack is at the root list screen.
838
+ */
839
+ handleKey(key) {
840
+ const char = key.raw.toString();
841
+ // Only handle custom keys when on the list screen (not on detail/add screens)
842
+ if (this.screenStack.size() <= 1 && !this.state.searchMode) {
843
+ // Add server
844
+ if (char === 'a') {
845
+ const styles = this.getStyles();
846
+ const addScreen = new AddServerScreen(this.agent, this.getManager, styles, () => this.termWidth, (newItem) => {
847
+ // Callback: add new server to list, refresh
848
+ this.state.items.push(newItem);
849
+ this.state.filteredItems = [...this.state.items];
850
+ }, () => {
851
+ this.renderCallback?.();
852
+ }, this.projectRoot);
853
+ this.screenStack.push(addScreen);
854
+ return this.rerender();
855
+ }
856
+ // Restart/disconnect only when items exist
857
+ if (this.state.filteredItems.length > 0) {
858
+ const selectedItem = this.state.filteredItems[this.state.selectedIndex];
859
+ // Restart selected server
860
+ if (char === 'r') {
861
+ void (async () => {
862
+ try {
863
+ const client = selectedItem.client;
864
+ await client.disconnect();
865
+ await client.connect();
866
+ const tools = await client.listTools();
867
+ selectedItem.tools = tools;
868
+ selectedItem.toolCount = tools.length;
869
+ selectedItem.status = client.status;
870
+ }
871
+ catch {
872
+ selectedItem.status = selectedItem.client.status;
873
+ }
874
+ this.renderCallback?.();
875
+ })();
876
+ return this.rerender();
877
+ }
878
+ // Disconnect selected server
879
+ if (char === 'd') {
880
+ void (async () => {
881
+ try {
882
+ await selectedItem.client.disconnect();
883
+ selectedItem.tools = [];
884
+ selectedItem.toolCount = 0;
885
+ selectedItem.status = 'disconnected';
886
+ }
887
+ catch {
888
+ selectedItem.status = selectedItem.client.status;
889
+ }
890
+ this.renderCallback?.();
891
+ })();
892
+ return this.rerender();
893
+ }
894
+ }
895
+ }
896
+ return super.handleKey(key);
897
+ }
898
+ createDetailScreen(item) {
899
+ if (!this.manager)
900
+ return null;
901
+ const styles = this.getStyles();
902
+ return new ServerDetailScreen(item, this.manager, styles, () => this.termWidth, () => {
903
+ // Refresh list items after restart/disconnect in detail screen
904
+ this.renderCallback?.();
905
+ });
906
+ }
907
+ }