@compilr-dev/cli 0.5.0 → 0.5.2

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 (587) hide show
  1. package/LICENSE +108 -0
  2. package/README.md +237 -69
  3. package/dist/.tsbuildinfo.app +1 -0
  4. package/dist/.tsbuildinfo.data +1 -0
  5. package/dist/.tsbuildinfo.domain +1 -0
  6. package/dist/.tsbuildinfo.foundation +1 -0
  7. package/dist/agent.d.ts +61 -4
  8. package/dist/agent.js +241 -245
  9. package/dist/anchors/index.d.ts +1 -1
  10. package/dist/anchors/index.js +1 -1
  11. package/dist/anchors/project-anchors.d.ts +2 -2
  12. package/dist/anchors/project-anchors.js +1 -1
  13. package/dist/auth/api-client.d.ts +124 -0
  14. package/dist/auth/api-client.js +261 -0
  15. package/dist/auth/index.d.ts +172 -0
  16. package/dist/auth/index.js +545 -0
  17. package/dist/auth/storage.d.ts +52 -0
  18. package/dist/auth/storage.js +118 -0
  19. package/dist/changelog/index.d.ts +16 -0
  20. package/dist/changelog/index.js +24 -0
  21. package/dist/changelog/releases.d.ts +17 -0
  22. package/dist/changelog/releases.js +63 -0
  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.js +286 -81
  28. package/dist/commands-v2/handlers/core.d.ts +1 -0
  29. package/dist/commands-v2/handlers/core.js +133 -8
  30. package/dist/commands-v2/handlers/debug.js +18 -0
  31. package/dist/commands-v2/handlers/delegations.d.ts +8 -0
  32. package/dist/commands-v2/handlers/delegations.js +29 -0
  33. package/dist/commands-v2/handlers/files.d.ts +8 -0
  34. package/dist/commands-v2/handlers/files.js +162 -0
  35. package/dist/commands-v2/handlers/filter.d.ts +9 -0
  36. package/dist/commands-v2/handlers/filter.js +130 -0
  37. package/dist/commands-v2/handlers/games.d.ts +7 -0
  38. package/dist/commands-v2/handlers/games.js +57 -0
  39. package/dist/commands-v2/handlers/index.d.ts +13 -0
  40. package/dist/commands-v2/handlers/index.js +39 -0
  41. package/dist/commands-v2/handlers/mcp.d.ts +8 -0
  42. package/dist/commands-v2/handlers/mcp.js +39 -0
  43. package/dist/commands-v2/handlers/notifications.d.ts +9 -0
  44. package/dist/commands-v2/handlers/notifications.js +34 -0
  45. package/dist/commands-v2/handlers/project.js +295 -31
  46. package/dist/commands-v2/handlers/reset.d.ts +11 -0
  47. package/dist/commands-v2/handlers/reset.js +118 -0
  48. package/dist/commands-v2/handlers/session.d.ts +161 -0
  49. package/dist/commands-v2/handlers/session.js +805 -0
  50. package/dist/commands-v2/handlers/settings.d.ts +2 -0
  51. package/dist/commands-v2/handlers/settings.js +217 -35
  52. package/dist/commands-v2/handlers/tasks.d.ts +5 -0
  53. package/dist/commands-v2/handlers/tasks.js +36 -0
  54. package/dist/commands-v2/handlers/team.d.ts +9 -0
  55. package/dist/commands-v2/handlers/team.js +549 -0
  56. package/dist/commands-v2/handlers/terminals.d.ts +9 -0
  57. package/dist/commands-v2/handlers/terminals.js +34 -0
  58. package/dist/commands-v2/index.d.ts +3 -2
  59. package/dist/commands-v2/index.js +4 -1
  60. package/dist/commands-v2/registry.d.ts +15 -0
  61. package/dist/commands-v2/registry.js +34 -0
  62. package/dist/commands-v2/types.d.ts +81 -3
  63. package/dist/commands.js +13 -0
  64. package/dist/compilr-diff-companion.vsix +0 -0
  65. package/dist/db/index.js +98 -4
  66. package/dist/db/repositories/document-repository.d.ts +2 -0
  67. package/dist/db/repositories/document-repository.js +6 -1
  68. package/dist/db/repositories/index.d.ts +2 -0
  69. package/dist/db/repositories/index.js +1 -0
  70. package/dist/db/repositories/plan-repository.d.ts +101 -0
  71. package/dist/db/repositories/plan-repository.js +275 -0
  72. package/dist/db/repositories/project-repository.d.ts +6 -0
  73. package/dist/db/repositories/project-repository.js +41 -0
  74. package/dist/db/repositories/work-item-repository.d.ts +15 -0
  75. package/dist/db/repositories/work-item-repository.js +69 -4
  76. package/dist/db/schema.d.ts +40 -3
  77. package/dist/db/schema.js +66 -3
  78. package/dist/episodes/index.d.ts +20 -0
  79. package/dist/episodes/index.js +27 -0
  80. package/dist/episodes/recorder.d.ts +51 -0
  81. package/dist/episodes/recorder.js +195 -0
  82. package/dist/episodes/significant-work.d.ts +21 -0
  83. package/dist/episodes/significant-work.js +56 -0
  84. package/dist/episodes/store.d.ts +38 -0
  85. package/dist/episodes/store.js +199 -0
  86. package/dist/episodes/types.d.ts +35 -0
  87. package/dist/episodes/types.js +6 -0
  88. package/dist/episodes/work-at-risk.d.ts +12 -0
  89. package/dist/episodes/work-at-risk.js +38 -0
  90. package/dist/episodes/work-summary-anchor.d.ts +23 -0
  91. package/dist/episodes/work-summary-anchor.js +73 -0
  92. package/dist/games/coins.d.ts +66 -0
  93. package/dist/games/coins.js +165 -0
  94. package/dist/games/game-base.d.ts +84 -0
  95. package/dist/games/game-base.js +204 -0
  96. package/dist/games/index.d.ts +16 -0
  97. package/dist/games/index.js +49 -0
  98. package/dist/games/scores.d.ts +69 -0
  99. package/dist/games/scores.js +191 -0
  100. package/dist/games/tetris/board.d.ts +59 -0
  101. package/dist/games/tetris/board.js +170 -0
  102. package/dist/games/tetris/index.d.ts +109 -0
  103. package/dist/games/tetris/index.js +610 -0
  104. package/dist/games/tetris/pieces.d.ts +44 -0
  105. package/dist/games/tetris/pieces.js +271 -0
  106. package/dist/games/tetris/renderer.d.ts +26 -0
  107. package/dist/games/tetris/renderer.js +77 -0
  108. package/dist/guide/guide-content.d.ts +23 -0
  109. package/dist/guide/guide-content.js +196 -0
  110. package/dist/guide/index.d.ts +8 -0
  111. package/dist/guide/index.js +7 -0
  112. package/dist/guide/shared-content.d.ts +37 -0
  113. package/dist/guide/shared-content.js +1272 -0
  114. package/dist/guide/tutorial-helpers.d.ts +57 -0
  115. package/dist/guide/tutorial-helpers.js +147 -0
  116. package/dist/handlers/ask-user-handlers.d.ts +32 -0
  117. package/dist/handlers/ask-user-handlers.js +104 -0
  118. package/dist/handlers/delegation-handlers.d.ts +34 -0
  119. package/dist/handlers/delegation-handlers.js +291 -0
  120. package/dist/handlers/permission-handler.d.ts +30 -0
  121. package/dist/handlers/permission-handler.js +205 -0
  122. package/dist/index.d.ts +11 -1
  123. package/dist/index.js +448 -271
  124. package/dist/input-handlers/memory-handler.d.ts +1 -1
  125. package/dist/input-handlers/memory-handler.js +2 -1
  126. package/dist/models/index.d.ts +10 -0
  127. package/dist/models/index.js +12 -0
  128. package/dist/models/model-registry.d.ts +38 -0
  129. package/dist/models/model-registry.js +69 -0
  130. package/dist/models/model-tiers.d.ts +28 -0
  131. package/dist/models/model-tiers.js +71 -0
  132. package/dist/models/model-validation.d.ts +25 -0
  133. package/dist/models/model-validation.js +291 -0
  134. package/dist/models/ollama-models.d.ts +73 -0
  135. package/dist/models/ollama-models.js +178 -0
  136. package/dist/models/provider-types.d.ts +6 -0
  137. package/dist/models/provider-types.js +1 -0
  138. package/dist/models/providers.d.ts +35 -0
  139. package/dist/models/providers.js +58 -0
  140. package/dist/models/types.d.ts +4 -0
  141. package/dist/models/types.js +4 -0
  142. package/dist/multi-agent/activity.d.ts +21 -0
  143. package/dist/multi-agent/activity.js +34 -0
  144. package/dist/multi-agent/agent-selection.d.ts +55 -0
  145. package/dist/multi-agent/agent-selection.js +90 -0
  146. package/dist/multi-agent/artifacts.d.ts +197 -0
  147. package/dist/multi-agent/artifacts.js +379 -0
  148. package/dist/multi-agent/checkpointer.d.ts +138 -0
  149. package/dist/multi-agent/checkpointer.js +471 -0
  150. package/dist/multi-agent/collision-utils.d.ts +16 -0
  151. package/dist/multi-agent/collision-utils.js +28 -0
  152. package/dist/multi-agent/context-resolver.d.ts +97 -0
  153. package/dist/multi-agent/context-resolver.js +316 -0
  154. package/dist/multi-agent/custom-agents.d.ts +83 -0
  155. package/dist/multi-agent/custom-agents.js +227 -0
  156. package/dist/multi-agent/delegation-tracker.d.ts +157 -0
  157. package/dist/multi-agent/delegation-tracker.js +243 -0
  158. package/dist/multi-agent/file-lock-hook.d.ts +29 -0
  159. package/dist/multi-agent/file-lock-hook.js +97 -0
  160. package/dist/multi-agent/file-locks.d.ts +58 -0
  161. package/dist/multi-agent/file-locks.js +194 -0
  162. package/dist/multi-agent/index.d.ts +24 -0
  163. package/dist/multi-agent/index.js +30 -0
  164. package/dist/multi-agent/mention-parser.d.ts +64 -0
  165. package/dist/multi-agent/mention-parser.js +146 -0
  166. package/dist/multi-agent/notification-manager.d.ts +84 -0
  167. package/dist/multi-agent/notification-manager.js +224 -0
  168. package/dist/multi-agent/pending-requests.d.ts +122 -0
  169. package/dist/multi-agent/pending-requests.js +155 -0
  170. package/dist/multi-agent/session-registry.d.ts +139 -0
  171. package/dist/multi-agent/session-registry.js +514 -0
  172. package/dist/multi-agent/shared-context.d.ts +293 -0
  173. package/dist/multi-agent/shared-context.js +671 -0
  174. package/dist/multi-agent/skill-requirements.d.ts +66 -0
  175. package/dist/multi-agent/skill-requirements.js +178 -0
  176. package/dist/multi-agent/task-assignment.d.ts +69 -0
  177. package/dist/multi-agent/task-assignment.js +123 -0
  178. package/dist/multi-agent/task-suggestion.d.ts +31 -0
  179. package/dist/multi-agent/task-suggestion.js +72 -0
  180. package/dist/multi-agent/team-agent.d.ts +201 -0
  181. package/dist/multi-agent/team-agent.js +488 -0
  182. package/dist/multi-agent/team.d.ts +286 -0
  183. package/dist/multi-agent/team.js +610 -0
  184. package/dist/multi-agent/tool-config.d.ts +110 -0
  185. package/dist/multi-agent/tool-config.js +661 -0
  186. package/dist/multi-agent/types.d.ts +211 -0
  187. package/dist/multi-agent/types.js +617 -0
  188. package/dist/prompts/plan-mode-prompt.d.ts +11 -0
  189. package/dist/prompts/plan-mode-prompt.js +95 -0
  190. package/dist/repl-helpers.js +5 -2
  191. package/dist/repl-v2.d.ts +401 -2
  192. package/dist/repl-v2.js +2588 -65
  193. package/dist/session/index.d.ts +6 -0
  194. package/dist/session/index.js +6 -0
  195. package/dist/session/project-session-manager.d.ts +158 -0
  196. package/dist/session/project-session-manager.js +650 -0
  197. package/dist/settings/index.d.ts +133 -13
  198. package/dist/settings/index.js +329 -24
  199. package/dist/settings/mcp-config.d.ts +76 -0
  200. package/dist/settings/mcp-config.js +143 -0
  201. package/dist/settings/paths.d.ts +4 -0
  202. package/dist/settings/paths.js +6 -0
  203. package/dist/shared-handlers.d.ts +62 -0
  204. package/dist/shared-handlers.js +48 -0
  205. package/dist/system-prompt/builder.d.ts +5 -0
  206. package/dist/system-prompt/builder.js +4 -0
  207. package/dist/system-prompt/index.d.ts +18 -0
  208. package/dist/system-prompt/index.js +18 -0
  209. package/dist/system-prompt/modules.d.ts +5 -0
  210. package/dist/system-prompt/modules.js +4 -0
  211. package/dist/tabbed-menu.js +2 -1
  212. package/dist/templates/compilr-md-import.d.ts +16 -0
  213. package/dist/templates/compilr-md-import.js +241 -0
  214. package/dist/templates/compilr-md.js +10 -61
  215. package/dist/templates/config-json.d.ts +1 -25
  216. package/dist/templates/index.d.ts +2 -0
  217. package/dist/templates/index.js +34 -73
  218. package/dist/tool-names.d.ts +113 -0
  219. package/dist/tool-names.js +239 -0
  220. package/dist/tools/ask-user-simple.d.ts +1 -1
  221. package/dist/tools/ask-user-simple.js +2 -1
  222. package/dist/tools/ask-user.d.ts +1 -1
  223. package/dist/tools/ask-user.js +2 -1
  224. package/dist/tools/backlog.d.ts +2 -2
  225. package/dist/tools/backlog.js +1 -1
  226. package/dist/tools/db-tools.d.ts +13 -61
  227. package/dist/tools/db-tools.js +12 -13
  228. package/dist/tools/delegate-background.d.ts +27 -0
  229. package/dist/tools/delegate-background.js +115 -0
  230. package/dist/tools/delegate.d.ts +22 -0
  231. package/dist/tools/delegate.js +97 -0
  232. package/dist/tools/delegation-status.d.ts +16 -0
  233. package/dist/tools/delegation-status.js +128 -0
  234. package/dist/tools/guide-tool.d.ts +12 -0
  235. package/dist/tools/guide-tool.js +59 -0
  236. package/dist/tools/handoff.d.ts +25 -0
  237. package/dist/tools/handoff.js +99 -0
  238. package/dist/tools/meta-tools.d.ts +26 -0
  239. package/dist/tools/meta-tools.js +47 -0
  240. package/dist/tools/platform-adapter.d.ts +35 -0
  241. package/dist/tools/platform-adapter.js +404 -0
  242. package/dist/tools/project-db.d.ts +5 -73
  243. package/dist/tools/project-db.js +5 -336
  244. package/dist/tools.d.ts +67 -2
  245. package/dist/tools.js +240 -48
  246. package/dist/ui/autocomplete-controller.d.ts +42 -0
  247. package/dist/ui/autocomplete-controller.js +384 -0
  248. package/dist/ui/base/index.d.ts +1 -1
  249. package/dist/ui/base/index.js +1 -1
  250. package/dist/ui/base/overlay-base-v2.d.ts +10 -0
  251. package/dist/ui/base/overlay-base-v2.js +14 -0
  252. package/dist/ui/base/render-utils.d.ts +19 -0
  253. package/dist/ui/base/render-utils.js +25 -0
  254. package/dist/ui/base/tabbed-list-overlay-v2.d.ts +16 -1
  255. package/dist/ui/base/tabbed-list-overlay-v2.js +19 -1
  256. package/dist/ui/constants/labels.d.ts +14 -0
  257. package/dist/ui/constants/labels.js +52 -0
  258. package/dist/ui/conversation-store.d.ts +55 -0
  259. package/dist/ui/conversation-store.js +107 -0
  260. package/dist/ui/conversation.js +11 -13
  261. package/dist/ui/diff.d.ts +7 -1
  262. package/dist/ui/diff.js +85 -48
  263. package/dist/ui/ephemeral.js +3 -9
  264. package/dist/ui/file-autocomplete.d.ts +24 -0
  265. package/dist/ui/file-autocomplete.js +56 -0
  266. package/dist/ui/footer-renderer.d.ts +69 -0
  267. package/dist/ui/footer-renderer.js +431 -0
  268. package/dist/ui/footer.d.ts +74 -7
  269. package/dist/ui/footer.js +173 -16
  270. package/dist/ui/input-controller.d.ts +51 -0
  271. package/dist/ui/input-controller.js +176 -0
  272. package/dist/ui/input-prompt.d.ts +19 -0
  273. package/dist/ui/input-prompt.js +206 -14
  274. package/dist/ui/keyboard-handler.d.ts +57 -0
  275. package/dist/ui/keyboard-handler.js +557 -0
  276. package/dist/ui/live-region-facade.d.ts +42 -0
  277. package/dist/ui/live-region-facade.js +205 -0
  278. package/dist/ui/live-region.d.ts +0 -4
  279. package/dist/ui/live-region.js +6 -14
  280. package/dist/ui/mascot/renderer.d.ts +1 -1
  281. package/dist/ui/mascot/renderer.js +37 -2
  282. package/dist/ui/overlay/data/tutorial-content.d.ts +9 -0
  283. package/dist/ui/overlay/data/tutorial-content.js +9 -0
  284. package/dist/ui/overlay/data/tutorial-registry.d.ts +12 -0
  285. package/dist/ui/overlay/data/tutorial-registry.js +116 -0
  286. package/dist/ui/overlay/data/tutorial-types.d.ts +35 -0
  287. package/dist/ui/overlay/data/tutorial-types.js +6 -0
  288. package/dist/ui/overlay/data/tutorials/basics/first-conversation.d.ts +7 -0
  289. package/dist/ui/overlay/data/tutorials/basics/first-conversation.js +220 -0
  290. package/dist/ui/overlay/data/tutorials/basics/first-project.d.ts +7 -0
  291. package/dist/ui/overlay/data/tutorials/basics/first-project.js +284 -0
  292. package/dist/ui/overlay/data/tutorials/basics/navigation.d.ts +8 -0
  293. package/dist/ui/overlay/data/tutorials/basics/navigation.js +22 -0
  294. package/dist/ui/overlay/data/tutorials/basics/welcome.d.ts +7 -0
  295. package/dist/ui/overlay/data/tutorials/basics/welcome.js +174 -0
  296. package/dist/ui/overlay/data/tutorials/config/context-management.d.ts +7 -0
  297. package/dist/ui/overlay/data/tutorials/config/context-management.js +158 -0
  298. package/dist/ui/overlay/data/tutorials/config/mcp-servers.d.ts +8 -0
  299. package/dist/ui/overlay/data/tutorials/config/mcp-servers.js +155 -0
  300. package/dist/ui/overlay/data/tutorials/config/model-selection.d.ts +7 -0
  301. package/dist/ui/overlay/data/tutorials/config/model-selection.js +162 -0
  302. package/dist/ui/overlay/data/tutorials/config/permissions-safety.d.ts +7 -0
  303. package/dist/ui/overlay/data/tutorials/config/permissions-safety.js +163 -0
  304. package/dist/ui/overlay/data/tutorials/config/settings-config.d.ts +7 -0
  305. package/dist/ui/overlay/data/tutorials/config/settings-config.js +166 -0
  306. package/dist/ui/overlay/data/tutorials/planning/arch.d.ts +7 -0
  307. package/dist/ui/overlay/data/tutorials/planning/arch.js +168 -0
  308. package/dist/ui/overlay/data/tutorials/planning/backlog.d.ts +7 -0
  309. package/dist/ui/overlay/data/tutorials/planning/backlog.js +103 -0
  310. package/dist/ui/overlay/data/tutorials/planning/build.d.ts +7 -0
  311. package/dist/ui/overlay/data/tutorials/planning/build.js +173 -0
  312. package/dist/ui/overlay/data/tutorials/planning/design.d.ts +7 -0
  313. package/dist/ui/overlay/data/tutorials/planning/design.js +205 -0
  314. package/dist/ui/overlay/data/tutorials/planning/docs.d.ts +7 -0
  315. package/dist/ui/overlay/data/tutorials/planning/docs.js +143 -0
  316. package/dist/ui/overlay/data/tutorials/planning/prd.d.ts +7 -0
  317. package/dist/ui/overlay/data/tutorials/planning/prd.js +173 -0
  318. package/dist/ui/overlay/data/tutorials/planning/scaffold.d.ts +7 -0
  319. package/dist/ui/overlay/data/tutorials/planning/scaffold.js +164 -0
  320. package/dist/ui/overlay/data/tutorials/planning/sketch.d.ts +7 -0
  321. package/dist/ui/overlay/data/tutorials/planning/sketch.js +58 -0
  322. package/dist/ui/overlay/data/tutorials/projects/anchors.d.ts +7 -0
  323. package/dist/ui/overlay/data/tutorials/projects/anchors.js +248 -0
  324. package/dist/ui/overlay/data/tutorials/projects/import-project.d.ts +7 -0
  325. package/dist/ui/overlay/data/tutorials/projects/import-project.js +172 -0
  326. package/dist/ui/overlay/data/tutorials/projects/managing-projects.d.ts +8 -0
  327. package/dist/ui/overlay/data/tutorials/projects/managing-projects.js +212 -0
  328. package/dist/ui/overlay/data/tutorials/projects/new-project.d.ts +7 -0
  329. package/dist/ui/overlay/data/tutorials/projects/new-project.js +251 -0
  330. package/dist/ui/overlay/data/tutorials/projects/session-management.d.ts +7 -0
  331. package/dist/ui/overlay/data/tutorials/projects/session-management.js +169 -0
  332. package/dist/ui/overlay/data/tutorials/teams/background-execution.d.ts +7 -0
  333. package/dist/ui/overlay/data/tutorials/teams/background-execution.js +171 -0
  334. package/dist/ui/overlay/data/tutorials/teams/multi-terminal.d.ts +8 -0
  335. package/dist/ui/overlay/data/tutorials/teams/multi-terminal.js +147 -0
  336. package/dist/ui/overlay/data/tutorials/teams/task-assignment.d.ts +7 -0
  337. package/dist/ui/overlay/data/tutorials/teams/task-assignment.js +204 -0
  338. package/dist/ui/overlay/data/tutorials/teams/team-overview.d.ts +7 -0
  339. package/dist/ui/overlay/data/tutorials/teams/team-overview.js +165 -0
  340. package/dist/ui/overlay/data/tutorials/teams/working-with-agents.d.ts +7 -0
  341. package/dist/ui/overlay/data/tutorials/teams/working-with-agents.js +172 -0
  342. package/dist/ui/overlay/impl/agents-overlay-v2.js +6 -17
  343. package/dist/ui/overlay/impl/anchors-overlay-v2.js +30 -64
  344. package/dist/ui/overlay/impl/artifact-detail-overlay-v2.d.ts +43 -0
  345. package/dist/ui/overlay/impl/artifact-detail-overlay-v2.js +232 -0
  346. package/dist/ui/overlay/impl/artifact-overlay-v2.d.ts +40 -0
  347. package/dist/ui/overlay/impl/artifact-overlay-v2.js +115 -0
  348. package/dist/ui/overlay/impl/ask-user-overlay-v2.js +2 -5
  349. package/dist/ui/overlay/impl/background-overlay-v2.d.ts +40 -0
  350. package/dist/ui/overlay/impl/background-overlay-v2.js +147 -0
  351. package/dist/ui/overlay/impl/backlog-overlay-v2.d.ts +4 -1
  352. package/dist/ui/overlay/impl/backlog-overlay-v2.js +55 -16
  353. package/dist/ui/overlay/impl/changelog-overlay-v2.d.ts +44 -0
  354. package/dist/ui/overlay/impl/changelog-overlay-v2.js +165 -0
  355. package/dist/ui/overlay/impl/commands-overlay-v2.js +4 -6
  356. package/dist/ui/overlay/impl/config-overlay-v2.d.ts +12 -1
  357. package/dist/ui/overlay/impl/config-overlay-v2.js +164 -100
  358. package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.d.ts +83 -0
  359. package/dist/ui/overlay/impl/custom-agent-form-overlay-v2.js +711 -0
  360. package/dist/ui/overlay/impl/dashboard-overlay-v2.d.ts +2 -0
  361. package/dist/ui/overlay/impl/dashboard-overlay-v2.js +26 -3
  362. package/dist/ui/overlay/impl/delegations-overlay-v2.d.ts +28 -0
  363. package/dist/ui/overlay/impl/delegations-overlay-v2.js +279 -0
  364. package/dist/ui/overlay/impl/docs-overlay-v2.js +12 -9
  365. package/dist/ui/overlay/impl/document-detail-overlay-v2.d.ts +7 -0
  366. package/dist/ui/overlay/impl/document-detail-overlay-v2.js +119 -78
  367. package/dist/ui/overlay/impl/filter-overlay-v2.d.ts +41 -0
  368. package/dist/ui/overlay/impl/filter-overlay-v2.js +110 -0
  369. package/dist/ui/overlay/impl/games-overlay-v2.d.ts +31 -0
  370. package/dist/ui/overlay/impl/games-overlay-v2.js +135 -0
  371. package/dist/ui/overlay/impl/help-overlay-v2.d.ts +26 -3
  372. package/dist/ui/overlay/impl/help-overlay-v2.js +20 -42
  373. package/dist/ui/overlay/impl/login-overlay-v2.d.ts +49 -0
  374. package/dist/ui/overlay/impl/login-overlay-v2.js +277 -0
  375. package/dist/ui/overlay/impl/mcp-overlay-v2.d.ts +63 -0
  376. package/dist/ui/overlay/impl/mcp-overlay-v2.js +907 -0
  377. package/dist/ui/overlay/impl/model-overlay-v2.d.ts +57 -13
  378. package/dist/ui/overlay/impl/model-overlay-v2.js +1086 -61
  379. package/dist/ui/overlay/impl/new-overlay-v2.d.ts +37 -6
  380. package/dist/ui/overlay/impl/new-overlay-v2.js +715 -65
  381. package/dist/ui/overlay/impl/notifications-overlay-v2.d.ts +20 -0
  382. package/dist/ui/overlay/impl/notifications-overlay-v2.js +116 -0
  383. package/dist/ui/overlay/impl/onboarding-wizard-overlay-v2.d.ts +76 -0
  384. package/dist/ui/overlay/impl/onboarding-wizard-overlay-v2.js +728 -0
  385. package/dist/ui/overlay/impl/pending-overlay-v2.d.ts +51 -0
  386. package/dist/ui/overlay/impl/pending-overlay-v2.js +445 -0
  387. package/dist/ui/overlay/impl/permission-overlay-v2.js +5 -5
  388. package/dist/ui/overlay/impl/permissions-overlay-v2.d.ts +85 -0
  389. package/dist/ui/overlay/impl/permissions-overlay-v2.js +820 -0
  390. package/dist/ui/overlay/impl/plan-approval-overlay-v2.d.ts +35 -0
  391. package/dist/ui/overlay/impl/plan-approval-overlay-v2.js +181 -0
  392. package/dist/ui/overlay/impl/project-edit-overlay-v2.d.ts +36 -0
  393. package/dist/ui/overlay/impl/project-edit-overlay-v2.js +195 -0
  394. package/dist/ui/overlay/impl/projects-overlay-v2.d.ts +1 -0
  395. package/dist/ui/overlay/impl/projects-overlay-v2.js +278 -44
  396. package/dist/ui/overlay/impl/reset-overlay-v2.d.ts +39 -0
  397. package/dist/ui/overlay/impl/reset-overlay-v2.js +107 -0
  398. package/dist/ui/overlay/impl/resume-overlay-v2.d.ts +60 -0
  399. package/dist/ui/overlay/impl/resume-overlay-v2.js +414 -0
  400. package/dist/ui/overlay/impl/session-mode-overlay-v2.d.ts +43 -0
  401. package/dist/ui/overlay/impl/session-mode-overlay-v2.js +124 -0
  402. package/dist/ui/overlay/impl/tasks-overlay-v2.d.ts +28 -0
  403. package/dist/ui/overlay/impl/tasks-overlay-v2.js +283 -0
  404. package/dist/ui/overlay/impl/team-overlay-v2.d.ts +86 -0
  405. package/dist/ui/overlay/impl/team-overlay-v2.js +692 -0
  406. package/dist/ui/overlay/impl/terminals-overlay-v2.d.ts +26 -0
  407. package/dist/ui/overlay/impl/terminals-overlay-v2.js +217 -0
  408. package/dist/ui/overlay/impl/tools-overlay-v2.js +3 -7
  409. package/dist/ui/overlay/impl/tutorial-overlay-v2.d.ts +30 -16
  410. package/dist/ui/overlay/impl/tutorial-overlay-v2.js +133 -956
  411. package/dist/ui/overlay/impl/workflow-overlay-v2.d.ts +1 -0
  412. package/dist/ui/overlay/impl/workflow-overlay-v2.js +10 -4
  413. package/dist/ui/overlay/index.d.ts +20 -1
  414. package/dist/ui/overlay/index.js +19 -0
  415. package/dist/ui/overlay/types.d.ts +5 -0
  416. package/dist/ui/overlay-manager.d.ts +43 -0
  417. package/dist/ui/overlay-manager.js +238 -0
  418. package/dist/ui/overlays.js +4 -16
  419. package/dist/ui/permission-overlay.js +6 -5
  420. package/dist/ui/status-bar-controller.d.ts +33 -0
  421. package/dist/ui/status-bar-controller.js +99 -0
  422. package/dist/ui/subagent-renderer.js +3 -19
  423. package/dist/ui/terminal-autocomplete-utils.d.ts +23 -0
  424. package/dist/ui/terminal-autocomplete-utils.js +83 -0
  425. package/dist/ui/terminal-line-builders.d.ts +17 -0
  426. package/dist/ui/terminal-line-builders.js +42 -0
  427. package/dist/ui/terminal-render-item.d.ts +16 -0
  428. package/dist/ui/terminal-render-item.js +267 -0
  429. package/dist/ui/terminal-renderer.d.ts +7 -8
  430. package/dist/ui/terminal-renderer.js +7 -8
  431. package/dist/ui/terminal-types.d.ts +179 -0
  432. package/dist/ui/terminal-types.js +34 -0
  433. package/dist/ui/terminal-ui.d.ts +144 -276
  434. package/dist/ui/terminal-ui.js +384 -1861
  435. package/dist/ui/todo-zone.d.ts +19 -1
  436. package/dist/ui/todo-zone.js +71 -13
  437. package/dist/ui/tool-formatters.js +696 -1
  438. package/dist/ui/turn-metrics.d.ts +56 -0
  439. package/dist/ui/turn-metrics.js +75 -0
  440. package/dist/ui/types.d.ts +28 -0
  441. package/dist/ui/types.js +1 -0
  442. package/dist/ui/vscode-diff-ipc.d.ts +102 -0
  443. package/dist/ui/vscode-diff-ipc.js +385 -0
  444. package/dist/utils/credentials.d.ts +24 -5
  445. package/dist/utils/credentials.js +123 -9
  446. package/dist/utils/format-tokens.d.ts +13 -0
  447. package/dist/utils/format-tokens.js +18 -0
  448. package/dist/utils/git-config.d.ts +26 -0
  449. package/dist/utils/git-config.js +54 -0
  450. package/dist/utils/message-utils.d.ts +61 -0
  451. package/dist/utils/message-utils.js +72 -0
  452. package/dist/utils/model-tiers.d.ts +8 -1
  453. package/dist/utils/model-tiers.js +38 -16
  454. package/dist/utils/open-browser.d.ts +5 -0
  455. package/dist/utils/open-browser.js +32 -0
  456. package/dist/utils/path-safety.js +3 -2
  457. package/dist/utils/project-detection.d.ts +58 -0
  458. package/dist/utils/project-detection.js +424 -0
  459. package/dist/utils/project-memory.js +2 -1
  460. package/dist/utils/project-status.d.ts +2 -2
  461. package/dist/utils/startup-perf.d.ts +18 -0
  462. package/dist/utils/startup-perf.js +60 -0
  463. package/dist/utils/token-tracker.d.ts +62 -0
  464. package/dist/utils/token-tracker.js +150 -0
  465. package/dist/utils/token-types.d.ts +23 -0
  466. package/dist/utils/token-types.js +18 -0
  467. package/dist/utils/types/config-types.d.ts +32 -0
  468. package/dist/utils/types/config-types.js +8 -0
  469. package/dist/utils/update-checker.d.ts +28 -0
  470. package/dist/utils/update-checker.js +106 -0
  471. package/dist/utils/version.d.ts +7 -0
  472. package/dist/utils/version.js +10 -0
  473. package/dist/utils/vscode-detect.d.ts +39 -0
  474. package/dist/utils/vscode-detect.js +137 -0
  475. package/package.json +27 -13
  476. package/dist/commands/handler-types.d.ts +0 -68
  477. package/dist/commands/handler-types.js +0 -8
  478. package/dist/commands/handlers/agent-commands.d.ts +0 -13
  479. package/dist/commands/handlers/agent-commands.js +0 -305
  480. package/dist/commands/handlers/design-commands.d.ts +0 -15
  481. package/dist/commands/handlers/design-commands.js +0 -334
  482. package/dist/commands/handlers/index.d.ts +0 -20
  483. package/dist/commands/handlers/index.js +0 -43
  484. package/dist/commands/handlers/overlay-commands.d.ts +0 -21
  485. package/dist/commands/handlers/overlay-commands.js +0 -287
  486. package/dist/commands/handlers/project-commands.d.ts +0 -11
  487. package/dist/commands/handlers/project-commands.js +0 -167
  488. package/dist/commands/handlers/simple-commands.d.ts +0 -19
  489. package/dist/commands/handlers/simple-commands.js +0 -144
  490. package/dist/commands/registry.d.ts +0 -50
  491. package/dist/commands/registry.js +0 -75
  492. package/dist/index.old.d.ts +0 -7
  493. package/dist/index.old.js +0 -1014
  494. package/dist/repl.d.ts +0 -149
  495. package/dist/repl.js +0 -1151
  496. package/dist/templates/claude-md.d.ts +0 -7
  497. package/dist/templates/claude-md.js +0 -189
  498. package/dist/test-autocomplete.d.ts +0 -7
  499. package/dist/test-autocomplete.js +0 -85
  500. package/dist/test-tabbed-menu.d.ts +0 -7
  501. package/dist/test-tabbed-menu.js +0 -25
  502. package/dist/tool-selector.d.ts +0 -71
  503. package/dist/tool-selector.js +0 -184
  504. package/dist/tools/anchor-tools.d.ts +0 -31
  505. package/dist/tools/anchor-tools.js +0 -255
  506. package/dist/tools/backlog-wrappers.d.ts +0 -54
  507. package/dist/tools/backlog-wrappers.js +0 -338
  508. package/dist/tools/document-db.d.ts +0 -43
  509. package/dist/tools/document-db.js +0 -220
  510. package/dist/tools/workitem-db.d.ts +0 -103
  511. package/dist/tools/workitem-db.js +0 -549
  512. package/dist/ui/agents-overlay-v2.d.ts +0 -43
  513. package/dist/ui/agents-overlay-v2.js +0 -809
  514. package/dist/ui/agents-overlay.d.ts +0 -12
  515. package/dist/ui/agents-overlay.js +0 -863
  516. package/dist/ui/anchors-overlay.d.ts +0 -12
  517. package/dist/ui/anchors-overlay.js +0 -775
  518. package/dist/ui/arch-type-overlay.d.ts +0 -15
  519. package/dist/ui/arch-type-overlay.js +0 -201
  520. package/dist/ui/ask-user-overlay-v2.d.ts +0 -26
  521. package/dist/ui/ask-user-overlay-v2.js +0 -555
  522. package/dist/ui/ask-user-simple-overlay-v2.d.ts +0 -25
  523. package/dist/ui/ask-user-simple-overlay-v2.js +0 -215
  524. package/dist/ui/backlog-overlay.d.ts +0 -32
  525. package/dist/ui/backlog-overlay.js +0 -652
  526. package/dist/ui/commands-overlay-v2.d.ts +0 -33
  527. package/dist/ui/commands-overlay-v2.js +0 -441
  528. package/dist/ui/commands-overlay.d.ts +0 -16
  529. package/dist/ui/commands-overlay.js +0 -439
  530. package/dist/ui/config-overlay.d.ts +0 -35
  531. package/dist/ui/config-overlay.js +0 -707
  532. package/dist/ui/docs-overlay.d.ts +0 -17
  533. package/dist/ui/docs-overlay.js +0 -303
  534. package/dist/ui/footer-v2.d.ts +0 -222
  535. package/dist/ui/footer-v2.js +0 -1349
  536. package/dist/ui/help-overlay-v2.d.ts +0 -34
  537. package/dist/ui/help-overlay-v2.js +0 -309
  538. package/dist/ui/help-overlay.d.ts +0 -16
  539. package/dist/ui/help-overlay.js +0 -316
  540. package/dist/ui/init-overlay-v2.d.ts +0 -34
  541. package/dist/ui/init-overlay-v2.js +0 -600
  542. package/dist/ui/init-overlay.d.ts +0 -34
  543. package/dist/ui/init-overlay.js +0 -604
  544. package/dist/ui/input-prompt-v2.d.ts +0 -180
  545. package/dist/ui/input-prompt-v2.js +0 -999
  546. package/dist/ui/iteration-limit-overlay-v2.d.ts +0 -21
  547. package/dist/ui/iteration-limit-overlay-v2.js +0 -114
  548. package/dist/ui/keys-overlay-v2.d.ts +0 -41
  549. package/dist/ui/keys-overlay-v2.js +0 -248
  550. package/dist/ui/mascot-overlay-v2.d.ts +0 -41
  551. package/dist/ui/mascot-overlay-v2.js +0 -138
  552. package/dist/ui/mascot-overlay.d.ts +0 -21
  553. package/dist/ui/mascot-overlay.js +0 -146
  554. package/dist/ui/model-overlay-v2.d.ts +0 -49
  555. package/dist/ui/model-overlay-v2.js +0 -118
  556. package/dist/ui/model-overlay.d.ts +0 -27
  557. package/dist/ui/model-overlay.js +0 -221
  558. package/dist/ui/model-warning-overlay.d.ts +0 -30
  559. package/dist/ui/model-warning-overlay.js +0 -169
  560. package/dist/ui/new-overlay.d.ts +0 -34
  561. package/dist/ui/new-overlay.js +0 -604
  562. package/dist/ui/overlay/impl/init-overlay-v2.d.ts +0 -77
  563. package/dist/ui/overlay/impl/init-overlay-v2.js +0 -593
  564. package/dist/ui/overlay/overlay-types.d.ts +0 -128
  565. package/dist/ui/overlay/overlay-types.js +0 -22
  566. package/dist/ui/overlays/help-overlay-v2.d.ts +0 -28
  567. package/dist/ui/overlays/help-overlay-v2.js +0 -198
  568. package/dist/ui/overlays/index.d.ts +0 -11
  569. package/dist/ui/overlays/index.js +0 -11
  570. package/dist/ui/permission-overlay-v2.d.ts +0 -36
  571. package/dist/ui/permission-overlay-v2.js +0 -380
  572. package/dist/ui/projects-overlay.d.ts +0 -19
  573. package/dist/ui/projects-overlay.js +0 -484
  574. package/dist/ui/theme-overlay-v2.d.ts +0 -42
  575. package/dist/ui/theme-overlay-v2.js +0 -135
  576. package/dist/ui/theme-overlay.d.ts +0 -24
  577. package/dist/ui/theme-overlay.js +0 -127
  578. package/dist/ui/tools-overlay-v2.d.ts +0 -47
  579. package/dist/ui/tools-overlay-v2.js +0 -218
  580. package/dist/ui/tools-overlay.d.ts +0 -34
  581. package/dist/ui/tools-overlay.js +0 -230
  582. package/dist/ui/tutorial-overlay-v2.d.ts +0 -31
  583. package/dist/ui/tutorial-overlay-v2.js +0 -1035
  584. package/dist/ui/tutorial-overlay.d.ts +0 -11
  585. package/dist/ui/tutorial-overlay.js +0 -1034
  586. package/dist/ui/workflow-overlay.d.ts +0 -22
  587. 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
+ }