tmux-ide 2.1.5 → 2.6.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 (969) hide show
  1. package/README.md +115 -101
  2. package/bin/cli.js +13686 -4
  3. package/bin/cli.ts +1143 -260
  4. package/bunfig.toml +4 -0
  5. package/package.json +36 -18
  6. package/packages/contracts/package.json +22 -0
  7. package/packages/contracts/src/__tests__/ide-config.test.ts +46 -0
  8. package/packages/contracts/src/__tests__/terminals.test.ts +87 -0
  9. package/packages/contracts/src/actions-contract.ts +310 -0
  10. package/packages/contracts/src/actions-errors.ts +41 -0
  11. package/packages/contracts/src/domain.ts +36 -0
  12. package/packages/contracts/src/ide-config.ts +170 -0
  13. package/packages/contracts/src/index.ts +24 -0
  14. package/packages/contracts/src/lib-internal/hq.ts +38 -0
  15. package/packages/contracts/src/terminals.ts +116 -0
  16. package/packages/contracts/src/tmux.ts +60 -0
  17. package/packages/contracts/src/workspace.ts +67 -0
  18. package/packages/daemon/dist/__tests__/support.d.ts +7 -0
  19. package/packages/daemon/dist/__tests__/support.js +33 -0
  20. package/packages/daemon/dist/agent-explain.d.ts +45 -0
  21. package/packages/daemon/dist/agent-explain.js +210 -0
  22. package/packages/daemon/dist/attach.d.ts +3 -0
  23. package/packages/daemon/dist/attach.js +14 -0
  24. package/packages/daemon/dist/bin.d.ts +2 -0
  25. package/packages/daemon/dist/bin.js +3 -0
  26. package/packages/daemon/dist/canonical.d.ts +2 -0
  27. package/packages/daemon/dist/canonical.js +1 -0
  28. package/packages/daemon/dist/cli.d.ts +1 -0
  29. package/packages/daemon/dist/cli.js +425 -0
  30. package/packages/daemon/dist/command-center/actions/contract.d.ts +1 -0
  31. package/packages/daemon/dist/command-center/actions/contract.js +2 -0
  32. package/packages/daemon/dist/command-center/actions/dispatcher.d.ts +27 -0
  33. package/packages/daemon/dist/command-center/actions/dispatcher.js +109 -0
  34. package/packages/daemon/dist/command-center/actions/errors.d.ts +38 -0
  35. package/packages/daemon/dist/command-center/actions/errors.js +56 -0
  36. package/packages/daemon/dist/command-center/actions/handlers/_project-context.d.ts +12 -0
  37. package/packages/daemon/dist/command-center/actions/handlers/_project-context.js +12 -0
  38. package/packages/daemon/dist/command-center/actions/handlers/_resolve-project.d.ts +42 -0
  39. package/packages/daemon/dist/command-center/actions/handlers/_resolve-project.js +48 -0
  40. package/packages/daemon/dist/command-center/actions/handlers/app-set-remote-access.d.ts +23 -0
  41. package/packages/daemon/dist/command-center/actions/handlers/app-set-remote-access.js +67 -0
  42. package/packages/daemon/dist/command-center/actions/handlers/config-actions.d.ts +12 -0
  43. package/packages/daemon/dist/command-center/actions/handlers/config-actions.js +69 -0
  44. package/packages/daemon/dist/command-center/actions/handlers/daemon-shutdown.d.ts +6 -0
  45. package/packages/daemon/dist/command-center/actions/handlers/daemon-shutdown.js +24 -0
  46. package/packages/daemon/dist/command-center/actions/handlers/project-activate.d.ts +7 -0
  47. package/packages/daemon/dist/command-center/actions/handlers/project-activate.js +19 -0
  48. package/packages/daemon/dist/command-center/actions/handlers/project-launch.d.ts +18 -0
  49. package/packages/daemon/dist/command-center/actions/handlers/project-launch.js +58 -0
  50. package/packages/daemon/dist/command-center/actions/handlers/project-open-terminal.d.ts +32 -0
  51. package/packages/daemon/dist/command-center/actions/handlers/project-open-terminal.js +69 -0
  52. package/packages/daemon/dist/command-center/actions/handlers/project-restart.d.ts +17 -0
  53. package/packages/daemon/dist/command-center/actions/handlers/project-restart.js +27 -0
  54. package/packages/daemon/dist/command-center/actions/handlers/project-stop.d.ts +24 -0
  55. package/packages/daemon/dist/command-center/actions/handlers/project-stop.js +38 -0
  56. package/packages/daemon/dist/command-center/actions/handlers/terminal-respawn.d.ts +24 -0
  57. package/packages/daemon/dist/command-center/actions/handlers/terminal-respawn.js +88 -0
  58. package/packages/daemon/dist/command-center/actions/handlers/terminal-stop.d.ts +14 -0
  59. package/packages/daemon/dist/command-center/actions/handlers/terminal-stop.js +22 -0
  60. package/packages/daemon/dist/command-center/actions/registry.d.ts +35 -0
  61. package/packages/daemon/dist/command-center/actions/registry.js +109 -0
  62. package/packages/daemon/dist/command-center/discovery.d.ts +23 -0
  63. package/packages/daemon/dist/command-center/discovery.js +67 -0
  64. package/packages/daemon/dist/command-center/index.d.ts +10 -0
  65. package/packages/daemon/dist/command-center/index.js +21 -0
  66. package/packages/daemon/dist/command-center/schemas.d.ts +76 -0
  67. package/packages/daemon/dist/command-center/schemas.js +68 -0
  68. package/packages/daemon/dist/command-center/server.d.ts +26 -0
  69. package/packages/daemon/dist/command-center/server.js +1103 -0
  70. package/packages/daemon/dist/command-center/ws-events.d.ts +59 -0
  71. package/packages/daemon/dist/command-center/ws-events.js +277 -0
  72. package/packages/daemon/dist/config.d.ts +19 -0
  73. package/packages/daemon/dist/config.js +494 -0
  74. package/packages/daemon/dist/detect.d.ts +15 -0
  75. package/packages/daemon/dist/detect.js +228 -0
  76. package/packages/daemon/dist/doctor.d.ts +21 -0
  77. package/packages/daemon/dist/doctor.js +154 -0
  78. package/packages/daemon/dist/embed.d.ts +1 -0
  79. package/packages/daemon/dist/embed.js +1 -0
  80. package/packages/daemon/dist/index.d.ts +3 -0
  81. package/packages/daemon/dist/index.js +2 -0
  82. package/packages/daemon/dist/init.d.ts +4 -0
  83. package/packages/daemon/dist/init.js +174 -0
  84. package/packages/daemon/dist/inspect.d.ts +54 -0
  85. package/packages/daemon/dist/inspect.js +118 -0
  86. package/packages/daemon/dist/launch.d.ts +23 -0
  87. package/packages/daemon/dist/launch.js +250 -0
  88. package/packages/daemon/dist/lib/active-projects.d.ts +12 -0
  89. package/packages/daemon/dist/lib/active-projects.js +35 -0
  90. package/packages/daemon/dist/lib/agent-discovery.d.ts +43 -0
  91. package/packages/daemon/dist/lib/agent-discovery.js +85 -0
  92. package/packages/daemon/dist/lib/app-config.d.ts +147 -0
  93. package/packages/daemon/dist/lib/app-config.js +191 -0
  94. package/packages/daemon/dist/lib/app-settings.d.ts +9 -0
  95. package/packages/daemon/dist/lib/app-settings.js +44 -0
  96. package/packages/daemon/dist/lib/auth/auth-service.d.ts +33 -0
  97. package/packages/daemon/dist/lib/auth/auth-service.js +172 -0
  98. package/packages/daemon/dist/lib/auth/middleware.d.ts +16 -0
  99. package/packages/daemon/dist/lib/auth/middleware.js +43 -0
  100. package/packages/daemon/dist/lib/auth/types.d.ts +1 -0
  101. package/packages/daemon/dist/lib/auth/types.js +2 -0
  102. package/packages/daemon/dist/lib/auth-token.d.ts +1 -0
  103. package/packages/daemon/dist/lib/auth-token.js +4 -0
  104. package/packages/daemon/dist/lib/authorship.d.ts +62 -0
  105. package/packages/daemon/dist/lib/authorship.js +209 -0
  106. package/packages/daemon/dist/lib/canonical-daemon.d.ts +21 -0
  107. package/packages/daemon/dist/lib/canonical-daemon.js +111 -0
  108. package/packages/daemon/dist/lib/cli-action-bridge.d.ts +27 -0
  109. package/packages/daemon/dist/lib/cli-action-bridge.js +161 -0
  110. package/packages/daemon/dist/lib/daemon-embed.d.ts +31 -0
  111. package/packages/daemon/dist/lib/daemon-embed.js +643 -0
  112. package/packages/daemon/dist/lib/daemon-watchdog.d.ts +16 -0
  113. package/packages/daemon/dist/lib/daemon-watchdog.js +98 -0
  114. package/packages/daemon/dist/lib/daemon.d.ts +8 -0
  115. package/packages/daemon/dist/lib/daemon.js +79 -0
  116. package/packages/daemon/dist/lib/dot-path.d.ts +2 -0
  117. package/packages/daemon/dist/lib/dot-path.js +17 -0
  118. package/packages/daemon/dist/lib/errors.d.ts +37 -0
  119. package/packages/daemon/dist/lib/errors.js +50 -0
  120. package/packages/daemon/dist/lib/filesystem-browser.d.ts +85 -0
  121. package/packages/daemon/dist/lib/filesystem-browser.js +257 -0
  122. package/packages/daemon/dist/lib/launch-plan.d.ts +6 -0
  123. package/packages/daemon/dist/lib/launch-plan.js +76 -0
  124. package/packages/daemon/dist/lib/log.d.ts +40 -0
  125. package/packages/daemon/dist/lib/log.js +86 -0
  126. package/packages/daemon/dist/lib/output.d.ts +9 -0
  127. package/packages/daemon/dist/lib/output.js +65 -0
  128. package/packages/daemon/dist/lib/project-init-runner.d.ts +46 -0
  129. package/packages/daemon/dist/lib/project-init-runner.js +117 -0
  130. package/packages/daemon/dist/lib/project-inspect.d.ts +28 -0
  131. package/packages/daemon/dist/lib/project-inspect.js +67 -0
  132. package/packages/daemon/dist/lib/project-onboard.d.ts +58 -0
  133. package/packages/daemon/dist/lib/project-onboard.js +108 -0
  134. package/packages/daemon/dist/lib/project-probe.d.ts +35 -0
  135. package/packages/daemon/dist/lib/project-probe.js +61 -0
  136. package/packages/daemon/dist/lib/project-registry.d.ts +76 -0
  137. package/packages/daemon/dist/lib/project-registry.js +230 -0
  138. package/packages/daemon/dist/lib/session-monitor.d.ts +15 -0
  139. package/packages/daemon/dist/lib/session-monitor.js +103 -0
  140. package/packages/daemon/dist/lib/session-options.d.ts +13 -0
  141. package/packages/daemon/dist/lib/session-options.js +85 -0
  142. package/packages/daemon/dist/lib/shell.d.ts +5 -0
  143. package/packages/daemon/dist/lib/shell.js +8 -0
  144. package/packages/daemon/dist/lib/sizes.d.ts +16 -0
  145. package/packages/daemon/dist/lib/sizes.js +36 -0
  146. package/packages/daemon/dist/lib/skill-sync.d.ts +60 -0
  147. package/packages/daemon/dist/lib/skill-sync.js +128 -0
  148. package/packages/daemon/dist/lib/slugify.d.ts +4 -0
  149. package/packages/daemon/dist/lib/slugify.js +10 -0
  150. package/packages/daemon/dist/lib/terminals-store.d.ts +27 -0
  151. package/packages/daemon/dist/lib/terminals-store.js +111 -0
  152. package/packages/daemon/dist/lib/update-check.d.ts +118 -0
  153. package/packages/daemon/dist/lib/update-check.js +261 -0
  154. package/packages/daemon/dist/lib/update.d.ts +65 -0
  155. package/packages/daemon/dist/lib/update.js +141 -0
  156. package/packages/daemon/dist/lib/workspace-registry.d.ts +84 -0
  157. package/packages/daemon/dist/lib/workspace-registry.js +176 -0
  158. package/packages/daemon/dist/lib/worktree.d.ts +76 -0
  159. package/packages/daemon/dist/lib/worktree.js +207 -0
  160. package/packages/daemon/dist/lib/yaml-io.d.ts +10 -0
  161. package/packages/daemon/dist/lib/yaml-io.js +24 -0
  162. package/packages/daemon/dist/ls.d.ts +3 -0
  163. package/packages/daemon/dist/ls.js +35 -0
  164. package/packages/daemon/dist/restart.d.ts +4 -0
  165. package/packages/daemon/dist/restart.js +16 -0
  166. package/packages/daemon/dist/restore.d.ts +86 -0
  167. package/packages/daemon/dist/restore.js +406 -0
  168. package/packages/daemon/dist/schemas/domain.d.ts +1 -0
  169. package/packages/daemon/dist/schemas/domain.js +2 -0
  170. package/packages/daemon/dist/schemas/filesystem.d.ts +29 -0
  171. package/packages/daemon/dist/schemas/filesystem.js +29 -0
  172. package/packages/daemon/dist/schemas/ide-config.d.ts +1 -0
  173. package/packages/daemon/dist/schemas/ide-config.js +2 -0
  174. package/packages/daemon/dist/schemas/index.d.ts +12 -0
  175. package/packages/daemon/dist/schemas/index.js +6 -0
  176. package/packages/daemon/dist/schemas/inspect.d.ts +53 -0
  177. package/packages/daemon/dist/schemas/inspect.js +57 -0
  178. package/packages/daemon/dist/schemas/registry.d.ts +35 -0
  179. package/packages/daemon/dist/schemas/registry.js +43 -0
  180. package/packages/daemon/dist/schemas/ws-events.d.ts +72 -0
  181. package/packages/daemon/dist/schemas/ws-events.js +110 -0
  182. package/packages/daemon/dist/send.d.ts +27 -0
  183. package/packages/daemon/dist/send.js +141 -0
  184. package/packages/daemon/dist/server/index.d.ts +10 -0
  185. package/packages/daemon/dist/server/index.js +55 -0
  186. package/packages/daemon/dist/server/pty-bridge.d.ts +174 -0
  187. package/packages/daemon/dist/server/pty-bridge.js +422 -0
  188. package/packages/daemon/dist/server/standalone.d.ts +1 -0
  189. package/packages/daemon/dist/server/standalone.js +14 -0
  190. package/packages/daemon/dist/server/ws-route.d.ts +74 -0
  191. package/packages/daemon/dist/server/ws-route.js +379 -0
  192. package/packages/daemon/dist/status.d.ts +3 -0
  193. package/packages/daemon/dist/status.js +46 -0
  194. package/packages/daemon/dist/stop.d.ts +3 -0
  195. package/packages/daemon/dist/stop.js +21 -0
  196. package/packages/daemon/dist/terminal/NodePtyAdapter.d.ts +44 -0
  197. package/packages/daemon/dist/terminal/NodePtyAdapter.js +253 -0
  198. package/packages/daemon/dist/terminal/PtyAdapter.d.ts +124 -0
  199. package/packages/daemon/dist/terminal/PtyAdapter.js +43 -0
  200. package/packages/daemon/dist/terminal/__tests__/MockPtyAdapter.d.ts +77 -0
  201. package/packages/daemon/dist/terminal/__tests__/MockPtyAdapter.js +155 -0
  202. package/packages/daemon/dist/types.d.ts +2 -0
  203. package/packages/daemon/dist/types.js +1 -0
  204. package/packages/daemon/dist/validate.d.ts +4 -0
  205. package/packages/daemon/dist/validate.js +184 -0
  206. package/packages/daemon/dist/widgets/changes/index.d.ts +1 -0
  207. package/packages/daemon/dist/widgets/changes/index.jsx +575 -0
  208. package/packages/daemon/dist/widgets/config/index.d.ts +1 -0
  209. package/packages/daemon/dist/widgets/config/index.jsx +395 -0
  210. package/packages/daemon/dist/widgets/explorer/breadcrumbs.d.ts +10 -0
  211. package/packages/daemon/dist/widgets/explorer/breadcrumbs.jsx +51 -0
  212. package/packages/daemon/dist/widgets/explorer/footer.d.ts +6 -0
  213. package/packages/daemon/dist/widgets/explorer/footer.jsx +11 -0
  214. package/packages/daemon/dist/widgets/explorer/index.d.ts +1 -0
  215. package/packages/daemon/dist/widgets/explorer/index.jsx +393 -0
  216. package/packages/daemon/dist/widgets/explorer/tree-model.d.ts +13 -0
  217. package/packages/daemon/dist/widgets/explorer/tree-model.js +69 -0
  218. package/packages/daemon/dist/widgets/explorer/tree.d.ts +13 -0
  219. package/packages/daemon/dist/widgets/explorer/tree.jsx +108 -0
  220. package/packages/daemon/dist/widgets/lib/config-model.d.ts +22 -0
  221. package/packages/daemon/dist/widgets/lib/config-model.js +99 -0
  222. package/packages/daemon/dist/widgets/lib/files.d.ts +11 -0
  223. package/packages/daemon/dist/widgets/lib/files.js +76 -0
  224. package/packages/daemon/dist/widgets/lib/git.d.ts +11 -0
  225. package/packages/daemon/dist/widgets/lib/git.js +70 -0
  226. package/packages/daemon/dist/widgets/lib/grammar.d.ts +79 -0
  227. package/packages/daemon/dist/widgets/lib/grammar.js +95 -0
  228. package/packages/daemon/dist/widgets/lib/help-overlay.d.ts +19 -0
  229. package/packages/daemon/dist/widgets/lib/help-overlay.jsx +69 -0
  230. package/packages/daemon/dist/widgets/lib/pane-comms.d.ts +28 -0
  231. package/packages/daemon/dist/widgets/lib/pane-comms.js +189 -0
  232. package/packages/daemon/dist/widgets/lib/theme.d.ts +44 -0
  233. package/packages/daemon/dist/widgets/lib/theme.js +153 -0
  234. package/packages/daemon/dist/widgets/lib/watcher.d.ts +9 -0
  235. package/packages/daemon/dist/widgets/lib/watcher.js +92 -0
  236. package/packages/daemon/dist/widgets/preview/index.d.ts +1 -0
  237. package/packages/daemon/dist/widgets/preview/index.jsx +371 -0
  238. package/packages/daemon/dist/widgets/resolve.d.ts +20 -0
  239. package/packages/daemon/dist/widgets/resolve.js +100 -0
  240. package/packages/daemon/dist/widgets/setup/agent-naming.d.ts +9 -0
  241. package/packages/daemon/dist/widgets/setup/agent-naming.jsx +81 -0
  242. package/packages/daemon/dist/widgets/setup/config-tree.d.ts +13 -0
  243. package/packages/daemon/dist/widgets/setup/config-tree.jsx +203 -0
  244. package/packages/daemon/dist/widgets/setup/detect-panel.d.ts +14 -0
  245. package/packages/daemon/dist/widgets/setup/detect-panel.jsx +48 -0
  246. package/packages/daemon/dist/widgets/setup/field-editor.d.ts +12 -0
  247. package/packages/daemon/dist/widgets/setup/field-editor.jsx +163 -0
  248. package/packages/daemon/dist/widgets/setup/footer.d.ts +17 -0
  249. package/packages/daemon/dist/widgets/setup/footer.jsx +64 -0
  250. package/packages/daemon/dist/widgets/setup/index.d.ts +1 -0
  251. package/packages/daemon/dist/widgets/setup/index.jsx +261 -0
  252. package/packages/daemon/dist/widgets/setup/layout-picker.d.ts +9 -0
  253. package/packages/daemon/dist/widgets/setup/layout-picker.jsx +69 -0
  254. package/packages/daemon/dist/widgets/setup/setup-model.d.ts +15 -0
  255. package/packages/daemon/dist/widgets/setup/setup-model.js +157 -0
  256. package/packages/daemon/dist/widgets/sidebar/index.d.ts +1 -0
  257. package/packages/daemon/dist/widgets/sidebar/index.jsx +462 -0
  258. package/packages/daemon/src/agent-explain.ts +270 -0
  259. package/packages/daemon/src/attach.ts +20 -0
  260. package/packages/daemon/src/bin.ts +4 -0
  261. package/packages/daemon/src/canonical.ts +7 -0
  262. package/packages/daemon/src/cli.ts +499 -0
  263. package/packages/daemon/src/command-center/actions/contract.ts +2 -0
  264. package/packages/daemon/src/command-center/actions/dispatcher.ts +137 -0
  265. package/packages/daemon/src/command-center/actions/errors.ts +105 -0
  266. package/packages/daemon/src/command-center/actions/handlers/_project-context.ts +30 -0
  267. package/packages/daemon/src/command-center/actions/handlers/_resolve-project.ts +78 -0
  268. package/packages/daemon/src/command-center/actions/handlers/app-set-remote-access.ts +118 -0
  269. package/packages/daemon/src/command-center/actions/handlers/config-actions.ts +113 -0
  270. package/packages/daemon/src/command-center/actions/handlers/daemon-shutdown.ts +38 -0
  271. package/packages/daemon/src/command-center/actions/handlers/project-activate.ts +30 -0
  272. package/packages/daemon/src/command-center/actions/handlers/project-launch.ts +70 -0
  273. package/packages/daemon/src/command-center/actions/handlers/project-open-terminal.ts +87 -0
  274. package/packages/daemon/src/command-center/actions/handlers/project-restart.ts +38 -0
  275. package/packages/daemon/src/command-center/actions/handlers/project-stop.ts +62 -0
  276. package/packages/daemon/src/command-center/actions/handlers/terminal-respawn.ts +119 -0
  277. package/packages/daemon/src/command-center/actions/handlers/terminal-stop.ts +35 -0
  278. package/packages/daemon/src/command-center/actions/registry.ts +149 -0
  279. package/packages/daemon/src/command-center/discovery.ts +96 -0
  280. package/packages/daemon/src/command-center/schemas.ts +85 -0
  281. package/packages/daemon/src/command-center/server.ts +1260 -0
  282. package/packages/daemon/src/command-center/ws-events.ts +316 -0
  283. package/packages/daemon/src/config.ts +549 -0
  284. package/packages/daemon/src/doctor.ts +242 -0
  285. package/packages/daemon/src/embed.ts +5 -0
  286. package/packages/daemon/src/index.ts +12 -0
  287. package/packages/daemon/src/init.ts +211 -0
  288. package/packages/daemon/src/inspect.ts +178 -0
  289. package/packages/daemon/src/launch.ts +349 -0
  290. package/packages/daemon/src/lib/active-projects.ts +49 -0
  291. package/packages/daemon/src/lib/agent-discovery.ts +121 -0
  292. package/packages/daemon/src/lib/app-config.ts +336 -0
  293. package/packages/daemon/src/lib/app-settings.ts +53 -0
  294. package/packages/daemon/src/lib/auth/types.ts +2 -0
  295. package/packages/daemon/src/lib/auth-token.ts +5 -0
  296. package/packages/daemon/src/lib/canonical-daemon.ts +122 -0
  297. package/packages/daemon/src/lib/cli-action-bridge.ts +216 -0
  298. package/packages/daemon/src/lib/daemon-embed.ts +782 -0
  299. package/packages/daemon/src/lib/daemon-watchdog.ts +111 -0
  300. package/packages/daemon/src/lib/daemon.ts +79 -0
  301. package/packages/daemon/src/lib/errors.ts +67 -0
  302. package/packages/daemon/src/lib/filesystem-browser.ts +292 -0
  303. package/packages/daemon/src/lib/log.ts +134 -0
  304. package/packages/daemon/src/lib/output.ts +76 -0
  305. package/packages/daemon/src/lib/project-init-runner.ts +150 -0
  306. package/packages/daemon/src/lib/project-inspect.ts +80 -0
  307. package/packages/daemon/src/lib/project-onboard.ts +149 -0
  308. package/packages/daemon/src/lib/project-probe.ts +92 -0
  309. package/packages/daemon/src/lib/project-registry.ts +296 -0
  310. package/packages/daemon/src/lib/session-monitor.ts +122 -0
  311. package/packages/daemon/src/lib/skill-sync.ts +155 -0
  312. package/packages/daemon/src/lib/terminals-store.ts +125 -0
  313. package/packages/daemon/src/lib/update-check.ts +298 -0
  314. package/packages/daemon/src/lib/update.ts +158 -0
  315. package/packages/daemon/src/lib/workspace-registry.ts +229 -0
  316. package/packages/daemon/src/lib/worktree.ts +289 -0
  317. package/packages/daemon/src/restart.ts +24 -0
  318. package/packages/daemon/src/restore.ts +514 -0
  319. package/packages/daemon/src/schemas/domain.ts +2 -0
  320. package/packages/daemon/src/schemas/filesystem.ts +34 -0
  321. package/packages/daemon/src/schemas/ide-config.ts +2 -0
  322. package/packages/daemon/src/schemas/index.ts +59 -0
  323. package/packages/daemon/src/schemas/inspect.ts +67 -0
  324. package/packages/daemon/src/schemas/registry.ts +55 -0
  325. package/packages/daemon/src/schemas/ws-events.ts +135 -0
  326. package/packages/daemon/src/send.ts +171 -0
  327. package/packages/daemon/src/server/README.md +15 -0
  328. package/packages/daemon/src/server/index.ts +74 -0
  329. package/packages/daemon/src/server/pty-bridge.ts +532 -0
  330. package/packages/daemon/src/server/standalone.ts +18 -0
  331. package/packages/daemon/src/server/ws-route.ts +483 -0
  332. package/packages/daemon/src/status.ts +59 -0
  333. package/packages/daemon/src/stop.ts +28 -0
  334. package/packages/daemon/src/terminal/NodePtyAdapter.ts +271 -0
  335. package/packages/daemon/src/terminal/PtyAdapter.ts +140 -0
  336. package/packages/daemon/src/terminal/README.md +92 -0
  337. package/packages/daemon/src/tui/chrome/cheatsheet.ts +260 -0
  338. package/packages/daemon/src/tui/chrome/chip.ts +30 -0
  339. package/packages/daemon/src/tui/chrome/events.ts +119 -0
  340. package/packages/daemon/src/tui/chrome/kitty-keys.ts +55 -0
  341. package/packages/daemon/src/tui/chrome/menu.ts +289 -0
  342. package/packages/daemon/src/tui/chrome/notify.ts +195 -0
  343. package/packages/daemon/src/tui/chrome/panels.ts +111 -0
  344. package/packages/daemon/src/tui/chrome/sidebar.ts +222 -0
  345. package/packages/daemon/src/tui/chrome/snapshot.ts +425 -0
  346. package/packages/daemon/src/tui/chrome/statusline.ts +595 -0
  347. package/packages/daemon/src/tui/chrome/updater.ts +428 -0
  348. package/packages/daemon/src/tui/chrome/welcome.ts +124 -0
  349. package/packages/daemon/src/tui/compiled.ts +113 -0
  350. package/packages/daemon/src/tui/detect/classify.ts +193 -0
  351. package/packages/daemon/src/tui/detect/manifest-loader.ts +192 -0
  352. package/packages/daemon/src/tui/detect/manifest.ts +184 -0
  353. package/packages/daemon/src/tui/detect/manifests.ts +226 -0
  354. package/packages/daemon/src/tui/detect/process-tree.ts +197 -0
  355. package/packages/daemon/src/tui/detect/snapshot.ts +70 -0
  356. package/packages/daemon/src/tui/integrations/claude.ts +176 -0
  357. package/packages/daemon/src/tui/integrations/offer.ts +145 -0
  358. package/packages/daemon/src/tui/main.ts +70 -0
  359. package/packages/daemon/src/tui/mirror/control-client.ts +143 -0
  360. package/packages/daemon/src/tui/mirror/control.ts +97 -0
  361. package/packages/daemon/src/tui/mirror/pane-mirror.ts +81 -0
  362. package/packages/daemon/src/tui/mirror/viewer.tsx +166 -0
  363. package/packages/daemon/src/tui/team/CONTROL.md +50 -0
  364. package/packages/daemon/src/tui/team/entry.ts +11 -0
  365. package/packages/daemon/src/tui/team/fuzzy.ts +133 -0
  366. package/packages/daemon/src/tui/team/home.ts +170 -0
  367. package/packages/daemon/src/tui/team/index.tsx +1521 -0
  368. package/packages/daemon/src/tui/team/input.ts +34 -0
  369. package/packages/daemon/src/tui/team/keymap.ts +127 -0
  370. package/packages/daemon/src/tui/team/mouse.ts +29 -0
  371. package/packages/daemon/src/tui/team/nav.ts +31 -0
  372. package/packages/daemon/src/tui/team/preview.ts +34 -0
  373. package/packages/daemon/src/tui/team/projects.ts +191 -0
  374. package/packages/daemon/src/tui/team/report.ts +73 -0
  375. package/packages/daemon/src/tui/team/sessions.ts +344 -0
  376. package/packages/daemon/src/tui/team/tree.ts +62 -0
  377. package/packages/daemon/src/types.ts +13 -0
  378. package/packages/daemon/src/widgets/changes/README.md +3 -0
  379. package/packages/daemon/src/widgets/changes/index.tsx +691 -0
  380. package/packages/daemon/src/widgets/config/README.md +3 -0
  381. package/packages/daemon/src/widgets/config/index.tsx +481 -0
  382. package/packages/daemon/src/widgets/explorer/README.md +3 -0
  383. package/packages/daemon/src/widgets/explorer/index.tsx +456 -0
  384. package/packages/daemon/src/widgets/explorer/tree.tsx +165 -0
  385. package/packages/daemon/src/widgets/lib/grammar.ts +126 -0
  386. package/packages/daemon/src/widgets/lib/help-overlay.tsx +101 -0
  387. package/packages/daemon/src/widgets/lib/pane-comms.ts +209 -0
  388. package/packages/daemon/src/widgets/lib/theme.ts +194 -0
  389. package/packages/daemon/src/widgets/lib/watcher.ts +132 -0
  390. package/packages/daemon/src/widgets/preview/README.md +3 -0
  391. package/packages/daemon/src/widgets/preview/index.tsx +416 -0
  392. package/packages/daemon/src/widgets/resolve.ts +121 -0
  393. package/packages/daemon/src/widgets/setup/README.md +3 -0
  394. package/packages/daemon/src/widgets/setup/config-tree.tsx +246 -0
  395. package/packages/daemon/src/widgets/setup/index.tsx +341 -0
  396. package/packages/daemon/src/widgets/sidebar/index.tsx +527 -0
  397. package/packages/tmux-bridge/package.json +22 -0
  398. package/packages/tmux-bridge/src/errors.ts +28 -0
  399. package/packages/tmux-bridge/src/index.ts +31 -0
  400. package/packages/tmux-bridge/src/monitor.ts +77 -0
  401. package/packages/tmux-bridge/src/panes.ts +136 -0
  402. package/packages/tmux-bridge/src/runner.test.ts +501 -0
  403. package/packages/tmux-bridge/src/runner.ts +91 -0
  404. package/packages/tmux-bridge/src/sessions.ts +126 -0
  405. package/packages/tmux-bridge/src/targeting.test.ts +107 -0
  406. package/packages/tmux-bridge/src/targeting.ts +90 -0
  407. package/scripts/build-cli.mjs +101 -0
  408. package/scripts/build-tui.mjs +58 -0
  409. package/scripts/capture-codex-traffic.mjs +195 -0
  410. package/scripts/check-src-additions.sh +74 -0
  411. package/scripts/coverage-summary.mjs +68 -0
  412. package/scripts/install-git-hooks.js +53 -0
  413. package/scripts/merge-update-manifests.mjs +58 -0
  414. package/scripts/merge-update-manifests.test.mjs +82 -0
  415. package/scripts/pack-check-run.mjs +83 -0
  416. package/scripts/postinstall.js +53 -7
  417. package/scripts/prepublish-check.mjs +44 -0
  418. package/scripts/stress-test.ts +141 -0
  419. package/scripts/verify-endpoints.sh +90 -0
  420. package/skill/SKILL.md +203 -236
  421. package/dashboard/out/404/index.html +0 -1
  422. package/dashboard/out/404.html +0 -1
  423. package/dashboard/out/__next.__PAGE__.txt +0 -9
  424. package/dashboard/out/__next._full.txt +0 -21
  425. package/dashboard/out/__next._head.txt +0 -5
  426. package/dashboard/out/__next._index.txt +0 -7
  427. package/dashboard/out/__next._tree.txt +0 -4
  428. package/dashboard/out/_next/static/BDqbxLkiJrlXDfMXNb3cK/_buildManifest.js +0 -11
  429. package/dashboard/out/_next/static/BDqbxLkiJrlXDfMXNb3cK/_clientMiddlewareManifest.json +0 -1
  430. package/dashboard/out/_next/static/BDqbxLkiJrlXDfMXNb3cK/_ssgManifest.js +0 -1
  431. package/dashboard/out/_next/static/chunks/048e2449530877e2.js +0 -1
  432. package/dashboard/out/_next/static/chunks/053c57bda6abb959.js +0 -1
  433. package/dashboard/out/_next/static/chunks/056760c6c2dd9172.js +0 -1
  434. package/dashboard/out/_next/static/chunks/06ab47357b6d3e35.js +0 -1
  435. package/dashboard/out/_next/static/chunks/0921cbe5dfd6738e.js +0 -1
  436. package/dashboard/out/_next/static/chunks/0b2599bf468cf5ea.js +0 -1
  437. package/dashboard/out/_next/static/chunks/0c012eac08ef2c4f.js +0 -1
  438. package/dashboard/out/_next/static/chunks/0c29e87fcdcffac3.js +0 -1
  439. package/dashboard/out/_next/static/chunks/0e1e98854430c693.js +0 -1
  440. package/dashboard/out/_next/static/chunks/0e24498976a88976.js +0 -1
  441. package/dashboard/out/_next/static/chunks/0e5bf11ff0b9ab90.js +0 -1
  442. package/dashboard/out/_next/static/chunks/0eae0a45ab8416c8.js +0 -1
  443. package/dashboard/out/_next/static/chunks/104797400d9d38ad.js +0 -1
  444. package/dashboard/out/_next/static/chunks/10cfcfce475f9d2d.js +0 -1
  445. package/dashboard/out/_next/static/chunks/11bac38e7cfb4ecc.js +0 -1
  446. package/dashboard/out/_next/static/chunks/120c5f6501ec3529.js +0 -1
  447. package/dashboard/out/_next/static/chunks/121fceb2b1dcd79f.js +0 -1
  448. package/dashboard/out/_next/static/chunks/13726b63e1be6b98.js +0 -1
  449. package/dashboard/out/_next/static/chunks/140c6ce631514660.js +0 -1
  450. package/dashboard/out/_next/static/chunks/1435ee3a51174c97.js +0 -1
  451. package/dashboard/out/_next/static/chunks/14dc927d2e2cca91.js +0 -1
  452. package/dashboard/out/_next/static/chunks/179c3031b292d98e.js +0 -1
  453. package/dashboard/out/_next/static/chunks/181e88957c47e5c1.js +0 -1
  454. package/dashboard/out/_next/static/chunks/18f70ba23873c432.js +0 -1
  455. package/dashboard/out/_next/static/chunks/1b58303b027fd135.js +0 -1
  456. package/dashboard/out/_next/static/chunks/1b5f49a358dcc71e.js +0 -1
  457. package/dashboard/out/_next/static/chunks/1bba44b81585099a.js +0 -1
  458. package/dashboard/out/_next/static/chunks/1bea8dee19a3e9ae.js +0 -1
  459. package/dashboard/out/_next/static/chunks/1cfad21646fc250e.js +0 -1
  460. package/dashboard/out/_next/static/chunks/1d053dc9e1e428ef.js +0 -1
  461. package/dashboard/out/_next/static/chunks/1e7d7639c6f0ee5e.js +0 -1
  462. package/dashboard/out/_next/static/chunks/1f42504ca81463f1.js +0 -1
  463. package/dashboard/out/_next/static/chunks/20c92047399305b4.js +0 -1
  464. package/dashboard/out/_next/static/chunks/214560e9514a9a4d.js +0 -1
  465. package/dashboard/out/_next/static/chunks/21d4ef106914e997.js +0 -1
  466. package/dashboard/out/_next/static/chunks/2586e83fc3dc2588.js +0 -1
  467. package/dashboard/out/_next/static/chunks/267136a09e94f5c2.js +0 -1
  468. package/dashboard/out/_next/static/chunks/271c50b329917c10.js +0 -1
  469. package/dashboard/out/_next/static/chunks/27fccecefffd88b5.js +0 -1
  470. package/dashboard/out/_next/static/chunks/28f058ed331315b6.js +0 -1
  471. package/dashboard/out/_next/static/chunks/28f704f2cc5713eb.js +0 -1
  472. package/dashboard/out/_next/static/chunks/290f67a6cd150a98.js +0 -1
  473. package/dashboard/out/_next/static/chunks/2ad12f4dcc30d30a.js +0 -1
  474. package/dashboard/out/_next/static/chunks/2b650b172078ab92.js +0 -1
  475. package/dashboard/out/_next/static/chunks/2bd91076019a6453.js +0 -1
  476. package/dashboard/out/_next/static/chunks/2e1278563a8e26be.js +0 -1
  477. package/dashboard/out/_next/static/chunks/309eb70780a3d67d.js +0 -1
  478. package/dashboard/out/_next/static/chunks/30f71950992e2307.js +0 -1
  479. package/dashboard/out/_next/static/chunks/31191873c2075784.js +0 -1
  480. package/dashboard/out/_next/static/chunks/31a790921a0c035e.js +0 -1
  481. package/dashboard/out/_next/static/chunks/34f8d7a5a06e8e32.js +0 -1
  482. package/dashboard/out/_next/static/chunks/36b3716436d9bc9d.js +0 -1
  483. package/dashboard/out/_next/static/chunks/3770b7d0ff004de3.js +0 -1
  484. package/dashboard/out/_next/static/chunks/381ab3bd4cffbf4d.js +0 -1
  485. package/dashboard/out/_next/static/chunks/38aa4eada5dcd1a4.js +0 -1
  486. package/dashboard/out/_next/static/chunks/39723132b78cb77e.js +0 -1
  487. package/dashboard/out/_next/static/chunks/399efdcc3fe56e09.js +0 -1
  488. package/dashboard/out/_next/static/chunks/3a8431a9221b0706.js +0 -1
  489. package/dashboard/out/_next/static/chunks/3a9b40810ce88cbf.js +0 -1
  490. package/dashboard/out/_next/static/chunks/3b322e3e9476ecdf.js +0 -1
  491. package/dashboard/out/_next/static/chunks/3bb14befeeb08c28.js +0 -1
  492. package/dashboard/out/_next/static/chunks/3c99637ebd462b20.js +0 -1
  493. package/dashboard/out/_next/static/chunks/3cbb9217d56459d8.js +0 -1
  494. package/dashboard/out/_next/static/chunks/3d438e0929a762f7.js +0 -1
  495. package/dashboard/out/_next/static/chunks/3e6d4834e0752f76.js +0 -2
  496. package/dashboard/out/_next/static/chunks/3e6f8cedaad4e89b.js +0 -1
  497. package/dashboard/out/_next/static/chunks/3e701259ce1b53e3.js +0 -1
  498. package/dashboard/out/_next/static/chunks/41562f7ab7c033eb.js +0 -1
  499. package/dashboard/out/_next/static/chunks/418fadd8a94e2fd7.js +0 -1
  500. package/dashboard/out/_next/static/chunks/42345437bb922e9c.js +0 -1
  501. package/dashboard/out/_next/static/chunks/434b6bd78c97b668.js +0 -1
  502. package/dashboard/out/_next/static/chunks/434febe897d33e2d.js +0 -1
  503. package/dashboard/out/_next/static/chunks/45d28707dd8ce1c1.js +0 -1
  504. package/dashboard/out/_next/static/chunks/4620a640e88cb1b7.js +0 -1
  505. package/dashboard/out/_next/static/chunks/468f8eb604502ea4.js +0 -1
  506. package/dashboard/out/_next/static/chunks/495f5cedf8afe823.js +0 -1
  507. package/dashboard/out/_next/static/chunks/49a89d1704d27740.js +0 -1
  508. package/dashboard/out/_next/static/chunks/49e5c37d15f63def.js +0 -1
  509. package/dashboard/out/_next/static/chunks/4a46ad186a8587ee.css +0 -2
  510. package/dashboard/out/_next/static/chunks/4a5c728574935d50.js +0 -1
  511. package/dashboard/out/_next/static/chunks/4b27ebd4d9304d8f.js +0 -1
  512. package/dashboard/out/_next/static/chunks/4b965aa320a9b358.js +0 -1
  513. package/dashboard/out/_next/static/chunks/4bb2da90bbe5794f.js +0 -1
  514. package/dashboard/out/_next/static/chunks/4d2f1c6f631e4b85.js +0 -1
  515. package/dashboard/out/_next/static/chunks/4d696d5a64dab42e.js +0 -1
  516. package/dashboard/out/_next/static/chunks/4f660dadb3f1e9e2.js +0 -1
  517. package/dashboard/out/_next/static/chunks/507b50d47f949333.js +0 -1
  518. package/dashboard/out/_next/static/chunks/50b1b7063bb044e2.js +0 -1
  519. package/dashboard/out/_next/static/chunks/50c0c2e3c4f02508.js +0 -1
  520. package/dashboard/out/_next/static/chunks/50d7ba9803e65b02.js +0 -1
  521. package/dashboard/out/_next/static/chunks/51535a6d4c98c7a4.js +0 -1
  522. package/dashboard/out/_next/static/chunks/526de6cc16c7dd2f.js +0 -1
  523. package/dashboard/out/_next/static/chunks/5307604f8632b3fd.js +0 -1
  524. package/dashboard/out/_next/static/chunks/5480bd722260f231.js +0 -1
  525. package/dashboard/out/_next/static/chunks/54c61c82e5f1dca5.js +0 -1
  526. package/dashboard/out/_next/static/chunks/555de6ac6bb9034c.js +0 -1
  527. package/dashboard/out/_next/static/chunks/562b89ee76a4b90c.js +0 -1
  528. package/dashboard/out/_next/static/chunks/5747f9a32edff429.js +0 -1
  529. package/dashboard/out/_next/static/chunks/57ee141430b4c05c.js +0 -1
  530. package/dashboard/out/_next/static/chunks/584c066a0837dd9a.js +0 -1
  531. package/dashboard/out/_next/static/chunks/5856aed4670a6253.js +0 -1
  532. package/dashboard/out/_next/static/chunks/58fe563414726511.js +0 -1
  533. package/dashboard/out/_next/static/chunks/5948196b2729b18c.js +0 -1
  534. package/dashboard/out/_next/static/chunks/5ab77c69e7306f97.js +0 -1
  535. package/dashboard/out/_next/static/chunks/5b3fa4c99d61611c.js +0 -1
  536. package/dashboard/out/_next/static/chunks/5cc87abaef616661.js +0 -1
  537. package/dashboard/out/_next/static/chunks/5dfa7913f99bb966.js +0 -1
  538. package/dashboard/out/_next/static/chunks/5e49b008432770f1.js +0 -1
  539. package/dashboard/out/_next/static/chunks/5e5a33dd81c45c47.js +0 -1
  540. package/dashboard/out/_next/static/chunks/5ee61bed638eb8a8.js +0 -1
  541. package/dashboard/out/_next/static/chunks/5eed557b9f45ae4a.js +0 -1
  542. package/dashboard/out/_next/static/chunks/60446823a7d30c1b.js +0 -1
  543. package/dashboard/out/_next/static/chunks/605150c490861442.js +0 -1
  544. package/dashboard/out/_next/static/chunks/609056d51c0bf332.js +0 -1
  545. package/dashboard/out/_next/static/chunks/60ec91dfeb50071b.js +0 -1
  546. package/dashboard/out/_next/static/chunks/61bc7be0bba6a33f.js +0 -1
  547. package/dashboard/out/_next/static/chunks/61f4a5c9ce23e55e.js +0 -1
  548. package/dashboard/out/_next/static/chunks/63aae3585be04e65.js +0 -1
  549. package/dashboard/out/_next/static/chunks/64e0e1ee7ef4f01b.js +0 -1
  550. package/dashboard/out/_next/static/chunks/66e9b4c26ff1aaaf.js +0 -1
  551. package/dashboard/out/_next/static/chunks/67068847aa1b5e98.js +0 -1
  552. package/dashboard/out/_next/static/chunks/68d7de1f2e202c26.js +0 -1
  553. package/dashboard/out/_next/static/chunks/698ca3ea1937ba4f.js +0 -1
  554. package/dashboard/out/_next/static/chunks/69eb97c24b5b6b9d.js +0 -1
  555. package/dashboard/out/_next/static/chunks/6b1ac098c228a479.js +0 -1
  556. package/dashboard/out/_next/static/chunks/6bb8020cb796bcc1.js +0 -1
  557. package/dashboard/out/_next/static/chunks/6cf8b1db17f2a155.js +0 -1
  558. package/dashboard/out/_next/static/chunks/6e7613643906ea88.js +0 -1
  559. package/dashboard/out/_next/static/chunks/6ea27ceb2e6feae5.js +0 -1
  560. package/dashboard/out/_next/static/chunks/6f95a8dbcf23dded.js +0 -1
  561. package/dashboard/out/_next/static/chunks/6fd44e759d82f64e.js +0 -1
  562. package/dashboard/out/_next/static/chunks/716ec29c268c38f6.js +0 -1
  563. package/dashboard/out/_next/static/chunks/717b399dfcf7c02c.js +0 -1
  564. package/dashboard/out/_next/static/chunks/72badd90e1c91348.js +0 -1
  565. package/dashboard/out/_next/static/chunks/72f9296dbb7ae3c4.js +0 -1
  566. package/dashboard/out/_next/static/chunks/73aa31e1144d8191.js +0 -1
  567. package/dashboard/out/_next/static/chunks/73f98ded8fe2e879.js +0 -1
  568. package/dashboard/out/_next/static/chunks/740a2e8ace15e13b.js +0 -1
  569. package/dashboard/out/_next/static/chunks/74e57c16e7304b6b.js +0 -1
  570. package/dashboard/out/_next/static/chunks/7628dead4d113df2.js +0 -1
  571. package/dashboard/out/_next/static/chunks/7717c88c07ed96e6.js +0 -1
  572. package/dashboard/out/_next/static/chunks/775581f7956d9a27.js +0 -1
  573. package/dashboard/out/_next/static/chunks/77d3b6661befdb98.js +0 -1
  574. package/dashboard/out/_next/static/chunks/78435c0e1c77fea7.js +0 -1
  575. package/dashboard/out/_next/static/chunks/791336748b9c9393.js +0 -1
  576. package/dashboard/out/_next/static/chunks/79ea68dfae65ef2f.js +0 -1
  577. package/dashboard/out/_next/static/chunks/7bae777a472eb13c.js +0 -1
  578. package/dashboard/out/_next/static/chunks/7fd847f47237a35c.js +0 -1
  579. package/dashboard/out/_next/static/chunks/804d718be0370058.css +0 -1
  580. package/dashboard/out/_next/static/chunks/807cb3c1923995ab.js +0 -1
  581. package/dashboard/out/_next/static/chunks/8286b39407d94447.js +0 -1
  582. package/dashboard/out/_next/static/chunks/84e4305b8dc830ed.js +0 -1
  583. package/dashboard/out/_next/static/chunks/850f99dbfabb53e0.js +0 -1
  584. package/dashboard/out/_next/static/chunks/85594127e66b6b7f.js +0 -1
  585. package/dashboard/out/_next/static/chunks/858c11169c183c9c.js +0 -1
  586. package/dashboard/out/_next/static/chunks/85e27005dfe4c3e3.js +0 -1
  587. package/dashboard/out/_next/static/chunks/8707bd3d8ddc1f1c.js +0 -1
  588. package/dashboard/out/_next/static/chunks/8851e5d7ef894973.js +0 -1
  589. package/dashboard/out/_next/static/chunks/88ba3782cc614989.js +0 -1
  590. package/dashboard/out/_next/static/chunks/8a0c9a181784c2ef.js +0 -1
  591. package/dashboard/out/_next/static/chunks/8ad01ae355a6e7f6.js +0 -1
  592. package/dashboard/out/_next/static/chunks/8d2ed93b0d0a4b4f.js +0 -1
  593. package/dashboard/out/_next/static/chunks/8dc352ebd5310d3c.js +0 -1
  594. package/dashboard/out/_next/static/chunks/8dd1d722c8c1a22c.js +0 -1
  595. package/dashboard/out/_next/static/chunks/8e60fe307e3e4986.js +0 -1
  596. package/dashboard/out/_next/static/chunks/8eea4dd71e25f32a.js +0 -1
  597. package/dashboard/out/_next/static/chunks/8f468a65bac34eaa.js +0 -1
  598. package/dashboard/out/_next/static/chunks/9057e5382d6a5059.js +0 -1
  599. package/dashboard/out/_next/static/chunks/931d056437805ecb.js +0 -1
  600. package/dashboard/out/_next/static/chunks/954eb11648dd8cff.js +0 -1
  601. package/dashboard/out/_next/static/chunks/955034d876d14bb3.js +0 -1
  602. package/dashboard/out/_next/static/chunks/966c4895773249f6.js +0 -1
  603. package/dashboard/out/_next/static/chunks/96aff410a6ab106c.js +0 -1
  604. package/dashboard/out/_next/static/chunks/99b396c821c1dd2d.js +0 -1
  605. package/dashboard/out/_next/static/chunks/9a255fd2cf4922ae.js +0 -1
  606. package/dashboard/out/_next/static/chunks/9b1f6aa73bc864b2.js +0 -1
  607. package/dashboard/out/_next/static/chunks/9b9ce582c533aa79.js +0 -1
  608. package/dashboard/out/_next/static/chunks/9c19bd3c773c6611.js +0 -1
  609. package/dashboard/out/_next/static/chunks/9ceeaa847eb15ca2.js +0 -1
  610. package/dashboard/out/_next/static/chunks/9d2e6e7b8b65f845.js +0 -1
  611. package/dashboard/out/_next/static/chunks/9de23802066128ff.js +0 -1
  612. package/dashboard/out/_next/static/chunks/9e327f94b3701170.js +0 -1
  613. package/dashboard/out/_next/static/chunks/9e7818421c2d455a.js +0 -1
  614. package/dashboard/out/_next/static/chunks/9e935acbcf2fb519.js +0 -1
  615. package/dashboard/out/_next/static/chunks/9ed9f68340343b51.js +0 -1
  616. package/dashboard/out/_next/static/chunks/9f94a0242455fc20.js +0 -1
  617. package/dashboard/out/_next/static/chunks/9fff46b5aaecf47e.js +0 -1
  618. package/dashboard/out/_next/static/chunks/a06d267a5c557657.js +0 -1
  619. package/dashboard/out/_next/static/chunks/a0eb8c81c54722fe.js +0 -1
  620. package/dashboard/out/_next/static/chunks/a16808e83106427d.js +0 -1
  621. package/dashboard/out/_next/static/chunks/a2215e2bc72739ef.js +0 -1
  622. package/dashboard/out/_next/static/chunks/a2de9e6696eb9c17.js +0 -1
  623. package/dashboard/out/_next/static/chunks/a33420b8c14090d6.js +0 -1
  624. package/dashboard/out/_next/static/chunks/a360bffef39d818b.js +0 -1
  625. package/dashboard/out/_next/static/chunks/a42852fdf5287cf5.js +0 -1
  626. package/dashboard/out/_next/static/chunks/a4efc88488322b67.js +0 -1
  627. package/dashboard/out/_next/static/chunks/a696a91d14101bdb.js +0 -1
  628. package/dashboard/out/_next/static/chunks/a6dad97d9634a72d.js +0 -1
  629. package/dashboard/out/_next/static/chunks/a6dad97d9634a72d.js.map +0 -1
  630. package/dashboard/out/_next/static/chunks/a705c7261712bd8e.js +0 -1
  631. package/dashboard/out/_next/static/chunks/a7d1e4b067ace180.js +0 -1
  632. package/dashboard/out/_next/static/chunks/a8590c121a7efaa5.js +0 -1
  633. package/dashboard/out/_next/static/chunks/a95953a83a6df6cf.js +0 -1
  634. package/dashboard/out/_next/static/chunks/a9d0a757d3b4afed.js +0 -1
  635. package/dashboard/out/_next/static/chunks/a9dc35514619c872.js +0 -1
  636. package/dashboard/out/_next/static/chunks/aae0253c73fba984.js +0 -193
  637. package/dashboard/out/_next/static/chunks/ab1821552066a74d.js +0 -1
  638. package/dashboard/out/_next/static/chunks/ac96bc0eccebe15a.js +0 -1
  639. package/dashboard/out/_next/static/chunks/acc03cfaaf6bb30f.js +0 -1
  640. package/dashboard/out/_next/static/chunks/acc298ae059b9fe4.js +0 -1
  641. package/dashboard/out/_next/static/chunks/ad076b6e996d250c.js +0 -1
  642. package/dashboard/out/_next/static/chunks/ae53b64af7ba16d5.js +0 -1
  643. package/dashboard/out/_next/static/chunks/ae5da7fa4bc5fa95.js +0 -1
  644. package/dashboard/out/_next/static/chunks/aefcf0eb033a155e.js +0 -1
  645. package/dashboard/out/_next/static/chunks/b12d43100ee10526.js +0 -1
  646. package/dashboard/out/_next/static/chunks/b137952dd5566a41.js +0 -1
  647. package/dashboard/out/_next/static/chunks/b2832d8a2d332a47.js +0 -1
  648. package/dashboard/out/_next/static/chunks/b417aa09c15f63c6.js +0 -1
  649. package/dashboard/out/_next/static/chunks/b48e152ba7bf6caf.js +0 -1
  650. package/dashboard/out/_next/static/chunks/b4cbef8e4714bf92.js +0 -1
  651. package/dashboard/out/_next/static/chunks/b568ff8383a37f53.js +0 -1
  652. package/dashboard/out/_next/static/chunks/b6e1495dd89a39e3.js +0 -1
  653. package/dashboard/out/_next/static/chunks/b73a21bd67528440.js +0 -1
  654. package/dashboard/out/_next/static/chunks/b77ee62bc71dcec7.js +0 -1
  655. package/dashboard/out/_next/static/chunks/b7f454615c11d4eb.js +0 -1
  656. package/dashboard/out/_next/static/chunks/b818ea32a839590f.js +0 -1
  657. package/dashboard/out/_next/static/chunks/b901ce78c1c65d66.js +0 -1
  658. package/dashboard/out/_next/static/chunks/b93d647b803be9fa.js +0 -1
  659. package/dashboard/out/_next/static/chunks/b960b09ff1ecd6bb.js +0 -1
  660. package/dashboard/out/_next/static/chunks/ba717c7779a778fc.js +0 -1
  661. package/dashboard/out/_next/static/chunks/bacb0ae7458d18b6.js +0 -1
  662. package/dashboard/out/_next/static/chunks/bb51f68b27346852.js +0 -1
  663. package/dashboard/out/_next/static/chunks/bb67f22e1ab632ae.js +0 -1
  664. package/dashboard/out/_next/static/chunks/bbae97ec58d1bb9d.js +0 -1
  665. package/dashboard/out/_next/static/chunks/bbaf38ee90307765.js +0 -1
  666. package/dashboard/out/_next/static/chunks/be01598fe1fce5db.js +0 -1
  667. package/dashboard/out/_next/static/chunks/bf4cbbc095987fec.js +0 -1
  668. package/dashboard/out/_next/static/chunks/c18f823797d57446.js +0 -1
  669. package/dashboard/out/_next/static/chunks/c1bcece34ec5b295.js +0 -1
  670. package/dashboard/out/_next/static/chunks/c1ccbc3a51adaf0a.js +0 -1
  671. package/dashboard/out/_next/static/chunks/c1f54a628f27791c.js +0 -1
  672. package/dashboard/out/_next/static/chunks/c21916bf5d232151.js +0 -1
  673. package/dashboard/out/_next/static/chunks/c27e570f0fc2f78b.js +0 -1
  674. package/dashboard/out/_next/static/chunks/c322b8005eebc0d8.js +0 -1
  675. package/dashboard/out/_next/static/chunks/c3900ac2b009b764.js +0 -1
  676. package/dashboard/out/_next/static/chunks/c3c597c8eb77ad6b.js +0 -1
  677. package/dashboard/out/_next/static/chunks/c58d45c1d88e208c.js +0 -1
  678. package/dashboard/out/_next/static/chunks/c63875998d7a655f.js +0 -1
  679. package/dashboard/out/_next/static/chunks/c6eaa7c8e7209c8e.js +0 -1
  680. package/dashboard/out/_next/static/chunks/c6f820f71162a59a.js +0 -1
  681. package/dashboard/out/_next/static/chunks/c7ce0941d1dfe7ed.js +0 -1
  682. package/dashboard/out/_next/static/chunks/c877259f784ec8e5.js +0 -1
  683. package/dashboard/out/_next/static/chunks/cb8057e86aaa1c68.js +0 -1
  684. package/dashboard/out/_next/static/chunks/ccb4e306ee4859b1.js +0 -1
  685. package/dashboard/out/_next/static/chunks/ccde62b0fa8112eb.js +0 -1
  686. package/dashboard/out/_next/static/chunks/cd421f0971c63c31.js +0 -1
  687. package/dashboard/out/_next/static/chunks/cde0317494d4adb7.js +0 -1
  688. package/dashboard/out/_next/static/chunks/cfae64434b92b8b6.js +0 -1
  689. package/dashboard/out/_next/static/chunks/cfc0e19310ec0a36.js +0 -1
  690. package/dashboard/out/_next/static/chunks/d0f344c7d0bcb59a.js +0 -1
  691. package/dashboard/out/_next/static/chunks/d1871c73e74e1f50.js +0 -1
  692. package/dashboard/out/_next/static/chunks/d18f658850711061.js +0 -1
  693. package/dashboard/out/_next/static/chunks/d25d9c48880697f6.js +0 -1
  694. package/dashboard/out/_next/static/chunks/d3f0a72bbc3060b0.js +0 -1
  695. package/dashboard/out/_next/static/chunks/d5fca429bc89060b.js +0 -1
  696. package/dashboard/out/_next/static/chunks/d6a6c75c9a4bef49.js +0 -1
  697. package/dashboard/out/_next/static/chunks/d6a8f93aa8f1e345.js +0 -1
  698. package/dashboard/out/_next/static/chunks/d7deab676b19ba0e.js +0 -1
  699. package/dashboard/out/_next/static/chunks/d80030dde88cec85.js +0 -1
  700. package/dashboard/out/_next/static/chunks/da84f9774c076ff1.js +0 -1
  701. package/dashboard/out/_next/static/chunks/da98ecc6b9b0ceb2.js +0 -1
  702. package/dashboard/out/_next/static/chunks/db550aabce60b912.js +0 -4
  703. package/dashboard/out/_next/static/chunks/dc87f77fcc029482.js +0 -1
  704. package/dashboard/out/_next/static/chunks/dd05f30acdb63a53.js +0 -1
  705. package/dashboard/out/_next/static/chunks/dea150155499b903.js +0 -1
  706. package/dashboard/out/_next/static/chunks/df4358754ff1d5e8.js +0 -1
  707. package/dashboard/out/_next/static/chunks/df8b21ff12d23b0e.js +0 -1
  708. package/dashboard/out/_next/static/chunks/df8fc68d77debf2c.js +0 -1
  709. package/dashboard/out/_next/static/chunks/df9ed1ffec90589f.js +0 -1
  710. package/dashboard/out/_next/static/chunks/dfa65ece1598f934.js +0 -1
  711. package/dashboard/out/_next/static/chunks/dfaab5cdd41a20d9.js +0 -1
  712. package/dashboard/out/_next/static/chunks/e00c03c942b5ae3e.js +0 -1
  713. package/dashboard/out/_next/static/chunks/e02d27cf679bece1.js +0 -1
  714. package/dashboard/out/_next/static/chunks/e0b747585f78513a.js +0 -1
  715. package/dashboard/out/_next/static/chunks/e19b71ca23fd7df0.js +0 -1
  716. package/dashboard/out/_next/static/chunks/e21cbe89d0cda120.js +0 -1
  717. package/dashboard/out/_next/static/chunks/e2a0386930edd34f.js +0 -1
  718. package/dashboard/out/_next/static/chunks/e375de19a36e2f38.js +0 -1
  719. package/dashboard/out/_next/static/chunks/e5241b4a6496a9e0.js +0 -1
  720. package/dashboard/out/_next/static/chunks/e569dd07c96eb4dd.js +0 -1
  721. package/dashboard/out/_next/static/chunks/e61c3ea91233f948.js +0 -1
  722. package/dashboard/out/_next/static/chunks/e73b42c5d34c4c28.js +0 -1
  723. package/dashboard/out/_next/static/chunks/e7c5b2105f651e87.js +0 -1
  724. package/dashboard/out/_next/static/chunks/e878e58a69bb01b6.js +0 -1
  725. package/dashboard/out/_next/static/chunks/e8f090a4dc571062.js +0 -1
  726. package/dashboard/out/_next/static/chunks/e98dc34dac91cdad.js +0 -1
  727. package/dashboard/out/_next/static/chunks/ea67cf7a0c5e7233.js +0 -1
  728. package/dashboard/out/_next/static/chunks/eacc98a1e3512fa9.js +0 -1
  729. package/dashboard/out/_next/static/chunks/eae9cd74d9bbed8b.js +0 -1
  730. package/dashboard/out/_next/static/chunks/eb187fd345852b34.js +0 -1
  731. package/dashboard/out/_next/static/chunks/ecea46df7a40b427.js +0 -1
  732. package/dashboard/out/_next/static/chunks/ecf48b83f4245d9c.js +0 -1
  733. package/dashboard/out/_next/static/chunks/eda41732bf966c6d.js +0 -1
  734. package/dashboard/out/_next/static/chunks/ee174a433049f43a.js +0 -1
  735. package/dashboard/out/_next/static/chunks/ee66b2d3b76de72e.js +0 -1
  736. package/dashboard/out/_next/static/chunks/ef058d3041c3d8ab.js +0 -1
  737. package/dashboard/out/_next/static/chunks/f3544b800b0d4969.js +0 -1
  738. package/dashboard/out/_next/static/chunks/f3b280e604b97509.js +0 -1
  739. package/dashboard/out/_next/static/chunks/f42e1d3693232993.js +0 -1
  740. package/dashboard/out/_next/static/chunks/f5a5fdd80166d304.js +0 -1
  741. package/dashboard/out/_next/static/chunks/f60adc5dd6169316.js +0 -1
  742. package/dashboard/out/_next/static/chunks/f6255bc2e6c68ce8.js +0 -1
  743. package/dashboard/out/_next/static/chunks/f6bb677d2d8840db.js +0 -1
  744. package/dashboard/out/_next/static/chunks/f6f3bf016239c33a.js +0 -1
  745. package/dashboard/out/_next/static/chunks/f6f57a46cd074bfe.js +0 -1
  746. package/dashboard/out/_next/static/chunks/f7feb9c1199e8cf6.js +0 -1
  747. package/dashboard/out/_next/static/chunks/f831087bf964cc3d.js +0 -1
  748. package/dashboard/out/_next/static/chunks/fa5a2f7244935aa2.js +0 -1
  749. package/dashboard/out/_next/static/chunks/fa73f36df4c38fa0.js +0 -1
  750. package/dashboard/out/_next/static/chunks/faa1461722d6a88d.js +0 -1
  751. package/dashboard/out/_next/static/chunks/fbf706b9a0edb7e6.js +0 -1
  752. package/dashboard/out/_next/static/chunks/fc2b8c8b7446bbc2.js +0 -1
  753. package/dashboard/out/_next/static/chunks/fd516f3930c128c1.js +0 -1
  754. package/dashboard/out/_next/static/chunks/fd663e7ff8de4887.js +0 -1
  755. package/dashboard/out/_next/static/chunks/fe5b656cc9bdd60e.js +0 -1
  756. package/dashboard/out/_next/static/chunks/turbopack-2f5dec4a537c0ee7.js +0 -4
  757. package/dashboard/out/_next/static/media/02263ebadd758ea4-s.8da66e7f.woff2 +0 -0
  758. package/dashboard/out/_next/static/media/2fe89d53234c61d4-s.cb53f04b.woff2 +0 -0
  759. package/dashboard/out/_next/static/media/59b15b4bcd7b1eb5-s.afa48be3.woff2 +0 -0
  760. package/dashboard/out/_next/static/media/5e05ae5b48faa55e-s.6b5ea6af.woff2 +0 -0
  761. package/dashboard/out/_next/static/media/68757d6cddeff913-s.e6cd1753.woff2 +0 -0
  762. package/dashboard/out/_next/static/media/99e609270109b47d-s.p.64b9304e.woff2 +0 -0
  763. package/dashboard/out/_next/static/media/a7afbb44bec2bb18-s.1dcddae6.woff2 +0 -0
  764. package/dashboard/out/_next/static/media/e390973e931a41c5-s.a82ecf4e.woff2 +0 -0
  765. package/dashboard/out/_next/static/media/e532fa1b9921e1cd-s.764b43eb.woff2 +0 -0
  766. package/dashboard/out/_next/static/media/effe91970fc4db64-s.p.19510058.woff2 +0 -0
  767. package/dashboard/out/_not-found/__next._full.txt +0 -15
  768. package/dashboard/out/_not-found/__next._head.txt +0 -5
  769. package/dashboard/out/_not-found/__next._index.txt +0 -7
  770. package/dashboard/out/_not-found/__next._not-found.__PAGE__.txt +0 -5
  771. package/dashboard/out/_not-found/__next._not-found.txt +0 -4
  772. package/dashboard/out/_not-found/__next._tree.txt +0 -2
  773. package/dashboard/out/_not-found/index.html +0 -1
  774. package/dashboard/out/_not-found/index.txt +0 -15
  775. package/dashboard/out/index.html +0 -1
  776. package/dashboard/out/index.txt +0 -21
  777. package/dashboard/out/project/__fallback/__next._full.txt +0 -19
  778. package/dashboard/out/project/__fallback/__next._head.txt +0 -5
  779. package/dashboard/out/project/__fallback/__next._index.txt +0 -7
  780. package/dashboard/out/project/__fallback/__next._tree.txt +0 -5
  781. package/dashboard/out/project/__fallback/__next.project.$d$name.__PAGE__.txt +0 -7
  782. package/dashboard/out/project/__fallback/__next.project.$d$name.txt +0 -4
  783. package/dashboard/out/project/__fallback/__next.project.txt +0 -4
  784. package/dashboard/out/project/__fallback/index.html +0 -1
  785. package/dashboard/out/project/__fallback/index.txt +0 -19
  786. package/src/__tests__/support.ts +0 -186
  787. package/src/attach.ts +0 -20
  788. package/src/cli.test.ts +0 -314
  789. package/src/command-center/discovery.test.ts +0 -265
  790. package/src/command-center/discovery.ts +0 -296
  791. package/src/command-center/schemas.ts +0 -57
  792. package/src/command-center/server.test.ts +0 -814
  793. package/src/command-center/server.ts +0 -1427
  794. package/src/command-center/static.test.ts +0 -105
  795. package/src/command-center/static.ts +0 -122
  796. package/src/config-cli.test.ts +0 -86
  797. package/src/config.test.ts +0 -205
  798. package/src/config.ts +0 -313
  799. package/src/detect.test.ts +0 -142
  800. package/src/dispatch.ts +0 -102
  801. package/src/doctor.test.ts +0 -119
  802. package/src/doctor.ts +0 -167
  803. package/src/init.test.ts +0 -101
  804. package/src/init.ts +0 -211
  805. package/src/inspect.test.ts +0 -67
  806. package/src/inspect.ts +0 -212
  807. package/src/integration.test.ts.skip +0 -276
  808. package/src/launch.test.ts +0 -149
  809. package/src/launch.ts +0 -583
  810. package/src/lib/auth/auth-service.test.ts +0 -178
  811. package/src/lib/auth/middleware.test.ts +0 -119
  812. package/src/lib/authorship.test.ts +0 -242
  813. package/src/lib/cast/recorder.test.ts +0 -127
  814. package/src/lib/cast/recorder.ts +0 -148
  815. package/src/lib/daemon-watchdog.ts +0 -102
  816. package/src/lib/daemon.ts +0 -440
  817. package/src/lib/dot-path.test.ts +0 -66
  818. package/src/lib/errors.ts +0 -44
  819. package/src/lib/event-log.test.ts +0 -189
  820. package/src/lib/event-log.ts +0 -237
  821. package/src/lib/github-pr.ts +0 -182
  822. package/src/lib/hq/client.test.ts +0 -154
  823. package/src/lib/hq/client.ts +0 -142
  824. package/src/lib/hq/mdns.test.ts +0 -54
  825. package/src/lib/hq/mdns.ts +0 -88
  826. package/src/lib/hq/registry.test.ts +0 -237
  827. package/src/lib/hq/registry.ts +0 -145
  828. package/src/lib/hq/types.ts +0 -44
  829. package/src/lib/ipc/socket-protocol.test.ts +0 -126
  830. package/src/lib/ipc/socket-protocol.ts +0 -324
  831. package/src/lib/launch-plan.test.ts +0 -119
  832. package/src/lib/log.test.ts +0 -39
  833. package/src/lib/log.ts +0 -71
  834. package/src/lib/metrics.test.ts +0 -213
  835. package/src/lib/metrics.ts +0 -345
  836. package/src/lib/orchestrator.test.ts +0 -2358
  837. package/src/lib/orchestrator.ts +0 -1799
  838. package/src/lib/output.ts +0 -76
  839. package/src/lib/plan-store.test.ts +0 -148
  840. package/src/lib/plan-store.ts +0 -131
  841. package/src/lib/research.test.ts +0 -208
  842. package/src/lib/research.ts +0 -475
  843. package/src/lib/round-trip.test.ts +0 -341
  844. package/src/lib/session-monitor.test.ts +0 -152
  845. package/src/lib/session-monitor.ts +0 -284
  846. package/src/lib/session-options.test.ts +0 -146
  847. package/src/lib/shell.test.ts +0 -20
  848. package/src/lib/sizes.test.ts +0 -73
  849. package/src/lib/skill-registry.test.ts +0 -134
  850. package/src/lib/skill-registry.ts +0 -86
  851. package/src/lib/slugify.test.ts +0 -35
  852. package/src/lib/task-store.ts +0 -352
  853. package/src/lib/tmux.test.ts +0 -500
  854. package/src/lib/tmux.ts +0 -372
  855. package/src/lib/token-tracker.test.ts +0 -102
  856. package/src/lib/token-tracker.ts +0 -70
  857. package/src/lib/tunnels/cloudflare.test.ts +0 -73
  858. package/src/lib/tunnels/cloudflare.ts +0 -254
  859. package/src/lib/tunnels/manager.test.ts +0 -63
  860. package/src/lib/tunnels/manager.ts +0 -132
  861. package/src/lib/tunnels/ngrok.test.ts +0 -94
  862. package/src/lib/tunnels/ngrok.ts +0 -261
  863. package/src/lib/tunnels/tailscale.test.ts +0 -103
  864. package/src/lib/tunnels/tailscale.ts +0 -1048
  865. package/src/lib/tunnels/types.ts +0 -44
  866. package/src/lib/validation.test.ts +0 -289
  867. package/src/lib/validation.ts +0 -123
  868. package/src/lib/webhook.ts +0 -51
  869. package/src/lib/workflow-store.ts +0 -209
  870. package/src/lib/ws-v3/protocol.test.ts +0 -127
  871. package/src/lib/ws-v3/protocol.ts +0 -160
  872. package/src/lib/yaml-io.test.ts +0 -125
  873. package/src/ls.test.ts +0 -76
  874. package/src/metrics-cli.ts +0 -177
  875. package/src/notify.ts +0 -85
  876. package/src/orchestrator-status.ts +0 -228
  877. package/src/plan.ts +0 -117
  878. package/src/postinstall.test.ts +0 -79
  879. package/src/remote.test.ts +0 -115
  880. package/src/remote.ts +0 -148
  881. package/src/restart.ts +0 -24
  882. package/src/schemas/domain.ts +0 -422
  883. package/src/schemas/ide-config.ts +0 -148
  884. package/src/schemas/index.ts +0 -53
  885. package/src/send.test.ts +0 -70
  886. package/src/send.ts +0 -181
  887. package/src/skill.test.ts +0 -114
  888. package/src/skill.ts +0 -138
  889. package/src/status.ts +0 -66
  890. package/src/stop.test.ts +0 -151
  891. package/src/stop.ts +0 -37
  892. package/src/task.test.ts +0 -1466
  893. package/src/task.ts +0 -1143
  894. package/src/tunnel.test.ts +0 -80
  895. package/src/tunnel.ts +0 -133
  896. package/src/types.ts +0 -15
  897. package/src/ui/web/utils/color.test.ts +0 -93
  898. package/src/validate.test.ts +0 -385
  899. package/src/widgets/changes/index.tsx +0 -576
  900. package/src/widgets/config/index.tsx +0 -440
  901. package/src/widgets/costs/index.tsx +0 -216
  902. package/src/widgets/explorer/index.tsx +0 -408
  903. package/src/widgets/explorer/tree-model.test.ts +0 -214
  904. package/src/widgets/explorer/tree.tsx +0 -156
  905. package/src/widgets/lib/files.test.ts +0 -103
  906. package/src/widgets/lib/git.test.ts +0 -151
  907. package/src/widgets/lib/pane-comms.test.ts +0 -178
  908. package/src/widgets/lib/pane-comms.ts +0 -207
  909. package/src/widgets/lib/theme.ts +0 -151
  910. package/src/widgets/lib/watcher.ts +0 -50
  911. package/src/widgets/mission-control/activity-feed.tsx +0 -59
  912. package/src/widgets/mission-control/agent-panel.tsx +0 -132
  913. package/src/widgets/mission-control/command-bar.tsx +0 -63
  914. package/src/widgets/mission-control/index.tsx +0 -751
  915. package/src/widgets/mission-control/task-panel.tsx +0 -238
  916. package/src/widgets/preview/index.tsx +0 -415
  917. package/src/widgets/resolve.ts +0 -40
  918. package/src/widgets/setup/config-tree.tsx +0 -238
  919. package/src/widgets/setup/index.tsx +0 -340
  920. package/src/widgets/setup/setup-model.test.ts +0 -303
  921. package/src/widgets/tasks/index.tsx +0 -129
  922. package/src/widgets/tasks/task-detail.tsx +0 -309
  923. package/src/widgets/tasks/task-form.tsx +0 -193
  924. package/src/widgets/tasks/task-list.tsx +0 -205
  925. package/src/widgets/tasks/task-model.test.ts +0 -473
  926. package/src/widgets/tasks/task-model.ts +0 -157
  927. /package/{src/lib/auth/types.ts → packages/contracts/src/lib-internal/auth.ts} +0 -0
  928. /package/{src → packages/daemon/src}/command-center/index.ts +0 -0
  929. /package/{src → packages/daemon/src}/detect.ts +0 -0
  930. /package/{src → packages/daemon/src}/js-yaml.d.ts +0 -0
  931. /package/{src → packages/daemon/src}/lib/auth/auth-service.ts +0 -0
  932. /package/{src → packages/daemon/src}/lib/auth/middleware.ts +0 -0
  933. /package/{src → packages/daemon/src}/lib/authorship.ts +0 -0
  934. /package/{src → packages/daemon/src}/lib/dot-path.ts +0 -0
  935. /package/{src → packages/daemon/src}/lib/launch-plan.ts +0 -0
  936. /package/{src → packages/daemon/src}/lib/session-options.ts +0 -0
  937. /package/{src → packages/daemon/src}/lib/shell.ts +0 -0
  938. /package/{src → packages/daemon/src}/lib/sizes.ts +0 -0
  939. /package/{src → packages/daemon/src}/lib/slugify.ts +0 -0
  940. /package/{src → packages/daemon/src}/lib/yaml-io.ts +0 -0
  941. /package/{src → packages/daemon/src}/ls.ts +0 -0
  942. /package/{src → packages/daemon/src}/ui/index.ts +0 -0
  943. /package/{src → packages/daemon/src}/ui/terminal/index.ts +0 -0
  944. /package/{src → packages/daemon/src}/ui/types.ts +0 -0
  945. /package/{src → packages/daemon/src}/ui/web/base.css +0 -0
  946. /package/{src → packages/daemon/src}/ui/web/components/Box.tsx +0 -0
  947. /package/{src → packages/daemon/src}/ui/web/components/Input.tsx +0 -0
  948. /package/{src → packages/daemon/src}/ui/web/components/ScrollBox.tsx +0 -0
  949. /package/{src → packages/daemon/src}/ui/web/components/Text.tsx +0 -0
  950. /package/{src → packages/daemon/src}/ui/web/hooks.ts +0 -0
  951. /package/{src → packages/daemon/src}/ui/web/index.ts +0 -0
  952. /package/{src → packages/daemon/src}/ui/web/render.ts +0 -0
  953. /package/{src → packages/daemon/src}/ui/web/utils/color.ts +0 -0
  954. /package/{src → packages/daemon/src}/validate.ts +0 -0
  955. /package/{src → packages/daemon/src}/widgets/explorer/breadcrumbs.tsx +0 -0
  956. /package/{src → packages/daemon/src}/widgets/explorer/footer.tsx +0 -0
  957. /package/{src → packages/daemon/src}/widgets/explorer/header.tsx +0 -0
  958. /package/{src → packages/daemon/src}/widgets/explorer/tree-model.ts +0 -0
  959. /package/{src → packages/daemon/src}/widgets/lib/config-model.ts +0 -0
  960. /package/{src → packages/daemon/src}/widgets/lib/files.ts +0 -0
  961. /package/{src → packages/daemon/src}/widgets/lib/git.ts +0 -0
  962. /package/{src → packages/daemon/src}/widgets/setup/agent-naming.tsx +0 -0
  963. /package/{src → packages/daemon/src}/widgets/setup/detect-panel.tsx +0 -0
  964. /package/{src → packages/daemon/src}/widgets/setup/field-editor.tsx +0 -0
  965. /package/{src → packages/daemon/src}/widgets/setup/footer.tsx +0 -0
  966. /package/{src → packages/daemon/src}/widgets/setup/layout-picker.tsx +0 -0
  967. /package/{src → packages/daemon/src}/widgets/setup/orchestrator-panel.tsx +0 -0
  968. /package/{src → packages/daemon/src}/widgets/setup/review-panel.tsx +0 -0
  969. /package/{src → packages/daemon/src}/widgets/setup/setup-model.ts +0 -0
@@ -0,0 +1,1260 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
4
+ import { join, dirname, basename } from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import { Hono, type MiddlewareHandler } from "hono";
7
+ import { streamSSE } from "hono/streaming";
8
+ import { cors } from "hono/cors";
9
+ import {
10
+ discoverSessions,
11
+ buildOverviews,
12
+ buildProjectDetail,
13
+ type SessionOverview,
14
+ } from "./discovery.ts";
15
+ import {
16
+ listSessionPanes,
17
+ sendCommand,
18
+ sendEnterToPane,
19
+ sendLiteralToPane,
20
+ sendText,
21
+ getPaneBusyStatus,
22
+ } from "../widgets/lib/pane-comms.ts";
23
+ import { resolvePane } from "../send.ts";
24
+ import { getSessionState, killSession, stopSessionMonitor } from "@tmux-ide/tmux-bridge";
25
+ import { readConfig, writeConfig } from "../lib/yaml-io.ts";
26
+ import { IdeConfigSchema } from "../schemas/ide-config.ts";
27
+ import { getLogBuffer, subscribeLogs, type LogEntry } from "../lib/log.ts";
28
+ import { zValidator } from "@hono/zod-validator";
29
+ import {
30
+ getDefaultWorkspaceRegistry,
31
+ WorkspaceAlreadyExistsError,
32
+ WorkspaceNotFoundError,
33
+ } from "../lib/workspace-registry.ts";
34
+ import { AddWorkspaceRequestSchemaZ } from "@tmux-ide/contracts";
35
+ import { sendCommandSchema } from "./schemas.ts";
36
+ import {
37
+ createScriptTerminalId,
38
+ terminalCreateRequestSchema,
39
+ terminalRenameRequestSchema,
40
+ type Terminal,
41
+ type TerminalListResponse,
42
+ type TerminalRuntime,
43
+ } from "@tmux-ide/contracts";
44
+ import {
45
+ deleteTerminal as deleteTerminalRecord,
46
+ loadTerminals,
47
+ renameTerminal as renameTerminalRecord,
48
+ upsertTerminal as upsertTerminalRecord,
49
+ } from "../lib/terminals-store.ts";
50
+ import { defaultPtyBridgeRegistry } from "../server/ws-route.ts";
51
+ import { broadcastTerminalsChanged } from "./ws-events.ts";
52
+ import { AuthService } from "../lib/auth/auth-service.ts";
53
+ import { authMiddleware } from "../lib/auth/middleware.ts";
54
+ import type { AuthConfig } from "../lib/auth/types.ts";
55
+ import { handleWsEventsConnection, broadcastInitOutput, broadcastInitError } from "./ws-events.ts";
56
+ import { createActionDispatcher } from "./actions/dispatcher.ts";
57
+ import {
58
+ listProjects,
59
+ getProject,
60
+ registerProject,
61
+ unregisterProject,
62
+ refreshProject,
63
+ ProjectAlreadyRegisteredError,
64
+ ProjectDirNotFoundError,
65
+ ProjectNotFoundError,
66
+ } from "../lib/project-registry.ts";
67
+ import {
68
+ runInit,
69
+ ProjectInitFailedError,
70
+ ProjectInitTimeoutError,
71
+ } from "../lib/project-init-runner.ts";
72
+ import {
73
+ RegisterProjectRequestSchemaZ,
74
+ InitProjectRequestSchemaZ,
75
+ type ProjectTemplate,
76
+ } from "../schemas/registry.ts";
77
+ import { OnboardProjectRequestSchemaZ } from "../schemas/inspect.ts";
78
+ import { SandboxViolationError, assertInsideSandbox } from "../lib/filesystem-browser.ts";
79
+ import { inspectProject, InspectDirNotFoundError } from "../lib/project-inspect.ts";
80
+ import {
81
+ composeIdeYmlConfig,
82
+ assertNoExistingIdeYml,
83
+ OnboardConflictError,
84
+ OnboardInvalidInputError,
85
+ } from "../lib/project-onboard.ts";
86
+ import { realpathSync } from "node:fs";
87
+ import { homedir } from "node:os";
88
+ import { isAbsolute, resolve as pathResolve } from "node:path";
89
+ import { randomUUID } from "node:crypto";
90
+ import { WebSocketServer } from "ws";
91
+ export interface CreateAppOptions {
92
+ authService?: AuthService;
93
+ authConfig?: AuthConfig;
94
+ remoteAccess?: {
95
+ bindHostname?: string;
96
+ token?: string | null;
97
+ localBypassToken?: string | null;
98
+ };
99
+ }
100
+
101
+ const __dirname = dirname(fileURLToPath(import.meta.url));
102
+ // Resolve our package.json's version. The lookup needs to handle BOTH
103
+ // dev (this file lives at src/command-center/, so the workspace root
104
+ // is two levels up) AND the packaged Electron bundle (this file is
105
+ // flattened into app.asar/dist-electron/, so the bundled package.json
106
+ // is ONE level up; two levels up escapes the asar). Try the candidates
107
+ // in order; fall back to a sentinel if neither is readable.
108
+ function resolvePackageVersion(): string {
109
+ const candidates = [join(__dirname, "../../package.json"), join(__dirname, "../package.json")];
110
+ for (const candidate of candidates) {
111
+ try {
112
+ const parsed = JSON.parse(readFileSync(candidate, "utf-8")) as { version?: string };
113
+ if (typeof parsed.version === "string") return parsed.version;
114
+ } catch {
115
+ /* try the next candidate */
116
+ }
117
+ }
118
+ return "0.0.0";
119
+ }
120
+ const pkgVersion: string = resolvePackageVersion();
121
+ let projectStreamConnections = 0;
122
+
123
+ function bearerToken(authHeader: string | undefined): string | null {
124
+ if (!authHeader?.startsWith("Bearer ")) return null;
125
+ return authHeader.slice("Bearer ".length);
126
+ }
127
+
128
+ function requireAuth(token: string | null, localBypassToken: string | null): MiddlewareHandler {
129
+ return async (c, next) => {
130
+ if (!token) return next();
131
+ const url = new URL(c.req.url);
132
+ const suppliedToken =
133
+ bearerToken(c.req.header("Authorization")) ?? url.searchParams.get("token");
134
+ if (suppliedToken === token || (localBypassToken && suppliedToken === localBypassToken)) {
135
+ return next();
136
+ }
137
+ return c.json({ error: "Remote access token required" }, 401);
138
+ };
139
+ }
140
+
141
+ function remoteAccessAuth(options: CreateAppOptions): {
142
+ token: string | null;
143
+ localBypassToken: string | null;
144
+ } {
145
+ const bindHostname = options.remoteAccess?.bindHostname ?? "127.0.0.1";
146
+ return {
147
+ token: bindHostname === "127.0.0.1" ? null : (options.remoteAccess?.token ?? null),
148
+ localBypassToken: options.remoteAccess?.localBypassToken ?? null,
149
+ };
150
+ }
151
+
152
+ const sseMetrics = {
153
+ connections: 0,
154
+ messagesSent: 0,
155
+ };
156
+
157
+ export function getSseMetrics(): { connections: number; messagesSent: number } {
158
+ return { ...sseMetrics };
159
+ }
160
+
161
+ /**
162
+ * Resolve a BottomPanel Output-tab channel id to a `LogEntry` predicate.
163
+ * Channels are simple component-prefix filters over the single in-process
164
+ * structured logger. Returns `null` for unknown channels (handler emits
165
+ * 404). Add new channels here when adding new log components.
166
+ */
167
+ function matchLogChannel(channel: string): ((entry: LogEntry) => boolean) | null {
168
+ switch (channel) {
169
+ case "daemon":
170
+ return () => true;
171
+ case "hq":
172
+ return (entry) => entry.component.startsWith("hq") || entry.component.startsWith("remote");
173
+ case "watchdog":
174
+ return (entry) => entry.component.startsWith("watchdog");
175
+ default:
176
+ return null;
177
+ }
178
+ }
179
+
180
+ function freezePayload<T>(payload: T): T {
181
+ if (payload && typeof payload === "object") {
182
+ for (const value of Object.values(payload as Record<string, unknown>)) {
183
+ freezePayload(value);
184
+ }
185
+ Object.freeze(payload);
186
+ }
187
+ return payload;
188
+ }
189
+
190
+ type DiscoveredSession = ReturnType<typeof discoverSessions>[number];
191
+
192
+ function buildProjectStreamSnapshot(session: DiscoveredSession) {
193
+ return {
194
+ project: buildProjectDetail(session),
195
+ };
196
+ }
197
+
198
+ /**
199
+ * Resolve a user-supplied directory to a canonical absolute path and verify
200
+ * it lives inside the filesystem-browser sandbox. Used by `/api/filesystem/
201
+ * inspect` and `/api/projects/onboard` so unregistered directories get the
202
+ * same protection as the directory browser. Returns either the canonical
203
+ * path or a structured error suitable for `c.json`.
204
+ *
205
+ * Tilde-expansion mirrors `/api/filesystem/browse`: `~` and `~/sub` map to
206
+ * `homedir()`. The sandbox roots are owned by `assertInsideSandbox`.
207
+ */
208
+ type SandboxResolveOk = { canonical: string };
209
+ type SandboxResolveErr = {
210
+ error: "invalid-path" | "not-found" | "outside-sandbox";
211
+ message: string;
212
+ status: 400 | 403 | 404;
213
+ };
214
+ function sandboxResolveDir(rawDir: string): SandboxResolveOk | SandboxResolveErr {
215
+ const trimmed = rawDir.trim();
216
+ if (!trimmed) return { error: "invalid-path", message: "Path must not be empty", status: 400 };
217
+ if (trimmed.includes("\0")) {
218
+ return { error: "invalid-path", message: "Path contains a null byte", status: 400 };
219
+ }
220
+ const home =
221
+ process.env.TMUX_IDE_HOME_OVERRIDE && process.env.TMUX_IDE_HOME_OVERRIDE.trim().length > 0
222
+ ? process.env.TMUX_IDE_HOME_OVERRIDE
223
+ : homedir();
224
+ let candidate = trimmed;
225
+ if (candidate === "~") {
226
+ candidate = home;
227
+ } else if (candidate.startsWith("~/")) {
228
+ candidate = `${home.replace(/\/+$/, "")}/${candidate.slice(2)}`;
229
+ }
230
+ if (!isAbsolute(candidate)) {
231
+ return { error: "invalid-path", message: "Path must be absolute", status: 400 };
232
+ }
233
+ const resolved = pathResolve(candidate);
234
+ let canonical: string;
235
+ try {
236
+ canonical = realpathSync(resolved);
237
+ } catch (err) {
238
+ const code = (err as NodeJS.ErrnoException).code;
239
+ if (code === "ENOENT" || code === "ENOTDIR") {
240
+ return {
241
+ error: "not-found",
242
+ message: `Path "${resolved}" does not exist`,
243
+ status: 404,
244
+ };
245
+ }
246
+ throw err;
247
+ }
248
+ try {
249
+ assertInsideSandbox(canonical, home);
250
+ } catch (err) {
251
+ if (err instanceof SandboxViolationError) {
252
+ return { error: "outside-sandbox", message: err.message, status: 403 };
253
+ }
254
+ throw err;
255
+ }
256
+ return { canonical };
257
+ }
258
+
259
+ export function createApp(options: CreateAppOptions = {}): Hono {
260
+ const authConfig: AuthConfig = options.authConfig ?? { method: "none", token_expiry: 86400 };
261
+ const authService = options.authService ?? new AuthService();
262
+
263
+ const app = new Hono();
264
+
265
+ // Allow cross-origin (Next.js dashboard, Tailscale, etc.)
266
+ app.use("/*", cors());
267
+
268
+ // Remote access bearer gate. Local Electron access uses a per-daemon
269
+ // bypass token from preload; loopback IPs are not implicitly trusted.
270
+ const remoteAuth = remoteAccessAuth(options);
271
+ app.use("/api/*", requireAuth(remoteAuth.token, remoteAuth.localBypassToken));
272
+
273
+ // Auth middleware — passes through when method is "none"
274
+ app.use("/*", authMiddleware(authService, authConfig));
275
+
276
+ // Global error handler
277
+ app.onError((err, c) => {
278
+ console.error("[command-center]", err.message);
279
+ return c.json({ error: err.message }, 500);
280
+ });
281
+
282
+ // --- Auth routes (always available, bypassed by middleware) ---
283
+
284
+ app.post("/api/auth/challenge", async (c) => {
285
+ const body = await c.req.json();
286
+ const userId = body.userId ?? authService.getCurrentUser();
287
+ const challenge = authService.createChallenge(userId);
288
+ return c.json(challenge);
289
+ });
290
+
291
+ app.post("/api/auth/verify", async (c) => {
292
+ const body = await c.req.json();
293
+ const result = await authService.authenticateWithSSHKey({
294
+ publicKey: body.publicKey,
295
+ signature: body.signature,
296
+ challengeId: body.challengeId,
297
+ });
298
+ if (!result.success) {
299
+ return c.json({ error: result.error }, 401);
300
+ }
301
+ return c.json({ token: result.token, userId: result.userId });
302
+ });
303
+
304
+ app.post("/api/auth/token", async (c) => {
305
+ if (authConfig.method !== "none") {
306
+ return c.json({ error: "Direct token generation requires auth method 'none'" }, 403);
307
+ }
308
+ const body = await c.req.json();
309
+ const userId = body.userId ?? authService.getCurrentUser();
310
+ const token = authService.generateToken(userId);
311
+ return c.json({ token, userId });
312
+ });
313
+
314
+ // --- v2 action dispatcher (single typed entry-point for state-changing
315
+ // project / terminal operations — see src/command-center/actions/) ---
316
+
317
+ app.post("/api/v2/action/:name", createActionDispatcher());
318
+
319
+ app.get("/api/widget/:name/spawn", async (c) => {
320
+ const { resolveWidgetSpawn, WIDGET_TYPES } = await import("../widgets/resolve.ts");
321
+ const name = c.req.param("name");
322
+ if (!WIDGET_TYPES.includes(name)) {
323
+ return c.json({ error: `unknown widget: ${name}`, available: WIDGET_TYPES }, 404);
324
+ }
325
+ const session = c.req.query("session");
326
+ const dir = c.req.query("dir");
327
+ if (!session || !dir) {
328
+ return c.json({ error: "session and dir query params are required" }, 400);
329
+ }
330
+ const target = c.req.query("target") ?? null;
331
+ const themeRaw = c.req.query("theme");
332
+ let theme: unknown = null;
333
+ if (themeRaw) {
334
+ try {
335
+ theme = JSON.parse(themeRaw);
336
+ } catch {
337
+ return c.json({ error: "theme must be valid JSON" }, 400);
338
+ }
339
+ }
340
+ try {
341
+ const spec = resolveWidgetSpawn(name, {
342
+ session,
343
+ dir,
344
+ target,
345
+ theme: theme as never,
346
+ });
347
+ return c.json(spec);
348
+ } catch (err) {
349
+ return c.json({ error: err instanceof Error ? err.message : String(err) }, 500);
350
+ }
351
+ });
352
+
353
+ // T067: /healthz — minimal liveness probe used by daemon-client.
354
+ // Intentionally NOT under /api so it bypasses the auth middleware on
355
+ // every consumer. Returns ok + version + uptime (ms since boot).
356
+ const HEALTHZ_BOOTED_AT = Date.now();
357
+ app.get("/healthz", (c) => {
358
+ return c.json({
359
+ ok: true,
360
+ version: process.env.npm_package_version ?? "dev",
361
+ uptimeMs: Date.now() - HEALTHZ_BOOTED_AT,
362
+ });
363
+ });
364
+
365
+ app.get("/api/sessions", (c) => {
366
+ const sessions = discoverSessions();
367
+ const overviews = buildOverviews(sessions);
368
+ return c.json({ sessions: overviews });
369
+ });
370
+
371
+ // ---------------------------------------------------------------------
372
+ // /api/workspaces — registry-backed CRUD. The registry is the source of
373
+ // truth for which projects the daemon serves. WS frames `workspace.added`
374
+ // and `workspace.removed` are emitted by the registry's emitter, picked
375
+ // up by ws-events' ensureWorkspaceRegistryListener and fanned to clients.
376
+ // ---------------------------------------------------------------------
377
+
378
+ app.get("/api/workspaces", (c) => {
379
+ const registry = getDefaultWorkspaceRegistry();
380
+ return c.json({ workspaces: registry.list() });
381
+ });
382
+
383
+ app.get("/api/workspaces/:name", (c) => {
384
+ const name = c.req.param("name");
385
+ const registry = getDefaultWorkspaceRegistry();
386
+ const workspace = registry.get(name);
387
+ if (!workspace) return c.json({ error: "Workspace not found" }, 404);
388
+ return c.json({ workspace });
389
+ });
390
+
391
+ app.post("/api/workspaces", zValidator("json", AddWorkspaceRequestSchemaZ), (c) => {
392
+ const body = c.req.valid("json");
393
+ const registry = getDefaultWorkspaceRegistry();
394
+ const name = body.name ?? basename(body.projectDir);
395
+ if (!name || name.length === 0) {
396
+ return c.json({ error: "Cannot derive workspace name from projectDir" }, 400);
397
+ }
398
+ try {
399
+ const workspace = registry.add({
400
+ name,
401
+ sessionName: body.sessionName,
402
+ projectDir: body.projectDir,
403
+ ideConfigPath: body.ideConfigPath ?? null,
404
+ });
405
+ return c.json({ workspace }, 201);
406
+ } catch (err) {
407
+ if (err instanceof WorkspaceAlreadyExistsError) {
408
+ return c.json({ error: err.message, code: err.code }, 409);
409
+ }
410
+ throw err;
411
+ }
412
+ });
413
+
414
+ // GET /api/chat/providers — discovery (claude-code / codex binaries on
415
+ // PATH). Distinct from `/api/providers`, which serves the redacted
416
+ // user-configured `ProviderInstanceSummary` set (T079).
417
+ app.delete("/api/workspaces/:name", (c) => {
418
+ const name = c.req.param("name");
419
+ const registry = getDefaultWorkspaceRegistry();
420
+ try {
421
+ registry.remove(name);
422
+ return c.body(null, 204);
423
+ } catch (err) {
424
+ if (err instanceof WorkspaceNotFoundError) {
425
+ return c.json({ error: err.message, code: err.code }, 404);
426
+ }
427
+ throw err;
428
+ }
429
+ });
430
+
431
+ app.get("/api/project/:name", (c) => {
432
+ const name = c.req.param("name");
433
+ const sessions = discoverSessions();
434
+ const session = sessions.find((s) => s.name === name);
435
+ if (!session) {
436
+ return c.json({ error: "Session not found" }, 404);
437
+ }
438
+ const detail = buildProjectDetail(session);
439
+ return c.json({ ...detail });
440
+ });
441
+
442
+ app.get("/api/project/:name/panes", (c) => {
443
+ const name = c.req.param("name");
444
+ let panes: ReturnType<typeof listSessionPanes>;
445
+ try {
446
+ panes = listSessionPanes(name);
447
+ } catch {
448
+ return c.json({ error: "Session not found" }, 404);
449
+ }
450
+ if (panes.length === 0) {
451
+ // Verify the session actually exists before returning empty
452
+ const sessions = discoverSessions();
453
+ if (!sessions.find((s) => s.name === name)) {
454
+ return c.json({ error: "Session not found" }, 404);
455
+ }
456
+ }
457
+ return c.json({
458
+ panes: panes.map((p) => ({
459
+ id: p.id,
460
+ index: p.index,
461
+ title: p.title,
462
+ currentCommand: p.currentCommand,
463
+ width: p.width,
464
+ height: p.height,
465
+ active: p.active,
466
+ role: p.role,
467
+ name: p.name,
468
+ type: p.type,
469
+ })),
470
+ });
471
+ });
472
+
473
+ app.get("/api/project/:name/terminals", async (c) => {
474
+ const name = c.req.param("name");
475
+ const sessions = discoverSessions();
476
+ const session = sessions.find((s) => s.name === name);
477
+ if (!session) return c.json({ error: "Session not found" }, 404);
478
+ const records = loadTerminals(session.dir);
479
+ const terminals = records.map((t) => {
480
+ const bridge = defaultPtyBridgeRegistry.peek(t.id) as
481
+ | (Parameters<typeof defaultPtyBridgeRegistry.peek>[0] extends never ? never : null)
482
+ | (Record<string, unknown> & {
483
+ running?: boolean;
484
+ cols?: number | null;
485
+ rows?: number | null;
486
+ getReplayBuffer?: () => Buffer;
487
+ })
488
+ | null;
489
+ let runtime: TerminalRuntime = { running: false };
490
+ if (bridge) {
491
+ const cols = typeof bridge.cols === "number" ? bridge.cols : undefined;
492
+ const rows = typeof bridge.rows === "number" ? bridge.rows : undefined;
493
+ const replay =
494
+ typeof bridge.getReplayBuffer === "function"
495
+ ? bridge.getReplayBuffer().byteLength
496
+ : undefined;
497
+ runtime = {
498
+ running: bridge.running !== false,
499
+ ...(cols !== undefined ? { cols } : {}),
500
+ ...(rows !== undefined ? { rows } : {}),
501
+ ...(replay !== undefined ? { replayBytes: replay } : {}),
502
+ };
503
+ }
504
+ return { ...t, runtime };
505
+ });
506
+ return c.json({ terminals } satisfies TerminalListResponse);
507
+ });
508
+
509
+ app.post(
510
+ "/api/project/:name/terminals",
511
+ zValidator("json", terminalCreateRequestSchema),
512
+ async (c) => {
513
+ const name = c.req.param("name");
514
+ const sessions = discoverSessions();
515
+ const session = sessions.find((s) => s.name === name);
516
+ if (!session) return c.json({ error: "Session not found" }, 404);
517
+ const body = c.req.valid("json");
518
+ // Pick the id: explicit > deterministic (when script provided) >
519
+ // UUID. The script-derived id collapse is the load-bearing bit
520
+ // for "two callers asking for the same run-script tab share a
521
+ // bridge + scrollback".
522
+ let id = body.id;
523
+ let scripted = false;
524
+ const kind = body.kind ?? "shell";
525
+ if (!id && body.script) {
526
+ id = await createScriptTerminalId({
527
+ projectId: name,
528
+ scopeId: body.scopeId,
529
+ kind,
530
+ script: body.script,
531
+ });
532
+ scripted = true;
533
+ }
534
+ if (!id) id = randomUUID();
535
+ try {
536
+ const upsertInput: Parameters<typeof upsertTerminalRecord>[1] = {
537
+ id,
538
+ projectId: name,
539
+ scopeId: body.scopeId,
540
+ name: body.name,
541
+ kind,
542
+ };
543
+ if (scripted) upsertInput.scripted = true;
544
+ const record = upsertTerminalRecord(session.dir, upsertInput);
545
+ broadcastTerminalsChanged(name);
546
+ return c.json({ ok: true, terminal: record satisfies Terminal });
547
+ } catch (err) {
548
+ return c.json({ error: (err as Error).message }, 400);
549
+ }
550
+ },
551
+ );
552
+
553
+ app.post(
554
+ "/api/project/:name/terminals/:id/rename",
555
+ zValidator("json", terminalRenameRequestSchema),
556
+ async (c) => {
557
+ const name = c.req.param("name");
558
+ const id = c.req.param("id");
559
+ const sessions = discoverSessions();
560
+ const session = sessions.find((s) => s.name === name);
561
+ if (!session) return c.json({ error: "Session not found" }, 404);
562
+ try {
563
+ const record = renameTerminalRecord(session.dir, id, c.req.valid("json").name);
564
+ if (!record) return c.json({ error: "Terminal not found" }, 404);
565
+ broadcastTerminalsChanged(name);
566
+ return c.json({ ok: true, terminal: record satisfies Terminal });
567
+ } catch (err) {
568
+ return c.json({ error: (err as Error).message }, 400);
569
+ }
570
+ },
571
+ );
572
+
573
+ app.delete("/api/project/:name/terminals/:id", async (c) => {
574
+ const name = c.req.param("name");
575
+ const id = c.req.param("id");
576
+ const sessions = discoverSessions();
577
+ const session = sessions.find((s) => s.name === name);
578
+ if (!session) return c.json({ error: "Session not found" }, 404);
579
+ const removedRecord = deleteTerminalRecord(session.dir, id);
580
+ // Kill the live bridge too — keep store + registry consistent.
581
+ const killed = defaultPtyBridgeRegistry.delete(id);
582
+ if (!removedRecord && !killed) {
583
+ return c.json({ error: "Terminal not found" }, 404);
584
+ }
585
+ broadcastTerminalsChanged(name);
586
+ return c.json({ ok: true });
587
+ });
588
+
589
+ // --- Project event/stream endpoints ---
590
+ // The orchestrator/task event feed moved out of tmux-ide (now in sfora.ai),
591
+ // so these surfaces only carry the live pane/project snapshot.
592
+
593
+ app.get("/api/project/:name/events", (c) => {
594
+ const name = c.req.param("name");
595
+ const session = discoverSessions().find((s) => s.name === name);
596
+ if (!session) {
597
+ return c.json({ error: "Session not found" }, 404);
598
+ }
599
+ return c.json({ events: [] });
600
+ });
601
+
602
+ app.get("/api/project/:name/stream", (c) => {
603
+ const name = c.req.param("name");
604
+ const session = discoverSessions().find((s) => s.name === name);
605
+ if (!session) {
606
+ return c.json({ error: "Session not found" }, 404);
607
+ }
608
+
609
+ return streamSSE(c, async (stream) => {
610
+ projectStreamConnections += 1;
611
+ sseMetrics.connections = projectStreamConnections;
612
+ let closed = false;
613
+ let previousSnapshotHash = "";
614
+ let lastPing = Date.now();
615
+
616
+ function writeSse(event: string, payload: unknown): void {
617
+ sseMetrics.messagesSent += 1;
618
+ void stream.writeSSE({ event, data: JSON.stringify(freezePayload(payload)) });
619
+ }
620
+
621
+ function writeChanges(currentSession: DiscoveredSession): void {
622
+ const snapshot = buildProjectStreamSnapshot(currentSession);
623
+ const snapshotHash = JSON.stringify(snapshot);
624
+ if (snapshotHash !== previousSnapshotHash) {
625
+ writeSse("snapshot", snapshot);
626
+ previousSnapshotHash = snapshotHash;
627
+ }
628
+ }
629
+
630
+ try {
631
+ stream.onAbort(() => {
632
+ closed = true;
633
+ });
634
+ writeChanges(session);
635
+ while (!closed) {
636
+ await stream.sleep(250);
637
+ const current = discoverSessions().find((candidate) => candidate.name === name);
638
+ if (!current) break;
639
+ writeChanges(current);
640
+ const now = Date.now();
641
+ if (now - lastPing >= 25_000) {
642
+ writeSse("ping", { at: new Date().toISOString() });
643
+ lastPing = now;
644
+ }
645
+ }
646
+ } finally {
647
+ projectStreamConnections = Math.max(0, projectStreamConnections - 1);
648
+ sseMetrics.connections = projectStreamConnections;
649
+ }
650
+ });
651
+ });
652
+
653
+ app.post("/api/project/:name/inject", async (c) => {
654
+ const name = c.req.param("name");
655
+ const sessions = discoverSessions();
656
+ const session = sessions.find((s) => s.name === name);
657
+ if (!session) {
658
+ return c.json({ error: "Session not found" }, 404);
659
+ }
660
+
661
+ let body: unknown;
662
+ try {
663
+ body = await c.req.json();
664
+ } catch {
665
+ return c.json({ error: "Invalid JSON body" }, 400);
666
+ }
667
+
668
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
669
+ return c.json({ error: "Invalid request body" }, 400);
670
+ }
671
+
672
+ const text = (body as { text?: unknown }).text;
673
+ const paneId = (body as { paneId?: unknown }).paneId;
674
+ const sendEnter = (body as { sendEnter?: unknown }).sendEnter;
675
+
676
+ if (typeof text !== "string" || text.trim().length === 0) {
677
+ return c.json({ error: "text must be a non-empty string" }, 400);
678
+ }
679
+ if (paneId !== undefined && (typeof paneId !== "string" || !/^%\d+$/.test(paneId))) {
680
+ return c.json({ error: "paneId must match /^%\\d+$/" }, 400);
681
+ }
682
+ if (sendEnter !== undefined && typeof sendEnter !== "boolean") {
683
+ return c.json({ error: "sendEnter must be a boolean" }, 400);
684
+ }
685
+
686
+ const panes = listSessionPanes(name);
687
+ const pane = paneId
688
+ ? panes.find((candidate) => candidate.id === paneId)
689
+ : panes.find((p) => p.active);
690
+ if (!pane) {
691
+ return c.json({ error: "Pane not found" }, 404);
692
+ }
693
+
694
+ sendLiteralToPane(name, pane.id, text);
695
+ if (sendEnter) sendEnterToPane(name, pane.id);
696
+
697
+ return c.json({ ok: true });
698
+ });
699
+
700
+ // Send message to a pane by name/title/role/ID
701
+ app.post("/api/project/:name/send", zValidator("json", sendCommandSchema), async (c) => {
702
+ const name = c.req.param("name");
703
+ const sessions = discoverSessions();
704
+ const session = sessions.find((s) => s.name === name);
705
+ if (!session) {
706
+ return c.json({ error: "Session not found" }, 404);
707
+ }
708
+
709
+ const { target, message, noEnter } = c.req.valid("json");
710
+
711
+ const panes = listSessionPanes(name);
712
+ const pane = resolvePane(panes, target);
713
+ if (!pane) {
714
+ const available = panes.map((p) => ({
715
+ id: p.id,
716
+ title: p.title,
717
+ name: p.name,
718
+ role: p.role,
719
+ }));
720
+ return c.json({ error: "Pane not found", target, available }, 404);
721
+ }
722
+
723
+ const busyStatus = getPaneBusyStatus(name, pane.id);
724
+
725
+ // Collapse multiline for agent panes
726
+ const prepared = busyStatus === "agent" ? message.replace(/\n+/g, " ").trim() : message;
727
+
728
+ if (noEnter) {
729
+ sendText(name, pane.id, prepared);
730
+ } else {
731
+ sendCommand(name, pane.id, prepared);
732
+ }
733
+
734
+ return c.json({
735
+ ok: true,
736
+ session: name,
737
+ target: {
738
+ paneId: pane.id,
739
+ name: pane.name,
740
+ title: pane.title,
741
+ role: pane.role,
742
+ },
743
+ busyStatus,
744
+ });
745
+ });
746
+
747
+ // GET /api/project/:name/config — read parsed ide.yml + raw text. Used by
748
+ // the v2 Config editor to hydrate the form.
749
+ app.get("/api/project/:name/config", (c) => {
750
+ const name = c.req.param("name");
751
+ const sessions = discoverSessions();
752
+ const session = sessions.find((s) => s.name === name);
753
+ if (!session) return c.json({ error: "Session not found" }, 404);
754
+ try {
755
+ const { config, configPath } = readConfig(session.dir);
756
+ return c.json({ ok: true, config, configPath });
757
+ } catch (err) {
758
+ const message = err instanceof Error ? err.message : String(err);
759
+ return c.json({ error: "Failed to read ide.yml", detail: message }, 500);
760
+ }
761
+ });
762
+
763
+ // POST /api/project/:name/config — accept a full IdeConfig payload, validate
764
+ // against IdeConfigSchema, and write to ide.yml. Returns the persisted
765
+ // config so the client can re-hydrate without a follow-up GET.
766
+ app.post("/api/project/:name/config", async (c) => {
767
+ const name = c.req.param("name");
768
+ const sessions = discoverSessions();
769
+ const session = sessions.find((s) => s.name === name);
770
+ if (!session) return c.json({ error: "Session not found" }, 404);
771
+ let body: unknown;
772
+ try {
773
+ body = await c.req.json();
774
+ } catch {
775
+ return c.json({ error: "Invalid JSON body" }, 400);
776
+ }
777
+ const parsed = IdeConfigSchema.safeParse(body);
778
+ if (!parsed.success) {
779
+ return c.json({ error: "Invalid config", details: parsed.error.issues }, 400);
780
+ }
781
+ try {
782
+ const configPath = writeConfig(session.dir, parsed.data);
783
+ return c.json({ ok: true, config: parsed.data, configPath });
784
+ } catch (err) {
785
+ const message = err instanceof Error ? err.message : String(err);
786
+ return c.json({ error: "Failed to write ide.yml", detail: message }, 500);
787
+ }
788
+ });
789
+
790
+ // Launch a tmux-ide session (shells out to CLI since launch has complex side effects)
791
+ const execFileAsync = promisify(execFile);
792
+
793
+ // POST /api/project/:name/restart — fire `tmux-ide restart` async. The CLI
794
+ // handles stop+launch; this endpoint is fire-and-forget aside from a short
795
+ // 30s timeout so the client can retry on its own.
796
+ app.post("/api/project/:name/restart", async (c) => {
797
+ const name = c.req.param("name");
798
+ const sessions = discoverSessions();
799
+ const session = sessions.find((s) => s.name === name);
800
+ if (!session) return c.json({ error: "Session not found" }, 404);
801
+ try {
802
+ await execFileAsync("tmux-ide", ["restart", "--json"], {
803
+ cwd: session.dir,
804
+ timeout: 30000,
805
+ env: { ...process.env, TMUX: "" },
806
+ });
807
+ return c.json({ ok: true, session: name, status: "restarted" });
808
+ } catch (err) {
809
+ const message = err instanceof Error ? err.message : String(err);
810
+ return c.json({ error: "Restart failed", detail: message }, 500);
811
+ }
812
+ });
813
+
814
+ app.post("/api/project/:name/launch", async (c) => {
815
+ const name = c.req.param("name");
816
+ const sessions = discoverSessions();
817
+ const session = sessions.find((s) => s.name === name);
818
+ if (!session) {
819
+ return c.json({ error: "Session not found" }, 404);
820
+ }
821
+
822
+ // Check if already running
823
+ const state = getSessionState(name);
824
+ if (state.running) {
825
+ return c.json({ ok: true, session: name, status: "already_running" });
826
+ }
827
+
828
+ try {
829
+ await execFileAsync("tmux-ide", ["--json"], {
830
+ cwd: session.dir,
831
+ timeout: 30000,
832
+ env: { ...process.env, TMUX: "" }, // Clear TMUX to avoid nesting
833
+ });
834
+ return c.json({ ok: true, session: name, status: "launched" });
835
+ } catch (err: unknown) {
836
+ const message = err instanceof Error ? err.message : String(err);
837
+ return c.json({ error: "Launch failed", detail: message }, 500);
838
+ }
839
+ });
840
+
841
+ // Stop a tmux-ide session
842
+ app.post("/api/project/:name/stop", async (c) => {
843
+ const name = c.req.param("name");
844
+ const sessions = discoverSessions();
845
+ const session = sessions.find((s) => s.name === name);
846
+ if (!session) {
847
+ return c.json({ error: "Session not found" }, 404);
848
+ }
849
+
850
+ const state = getSessionState(name);
851
+ if (!state.running) {
852
+ return c.json({ ok: true, session: name, status: "not_running" });
853
+ }
854
+
855
+ stopSessionMonitor(name);
856
+ const result = killSession(name);
857
+ if (result.stopped) {
858
+ return c.json({ ok: true, session: name, status: "stopped" });
859
+ }
860
+ return c.json({ error: "Stop failed", reason: result.reason }, 500);
861
+ });
862
+
863
+ // SSE endpoint — cursor-based event streaming with orchestrator state
864
+ app.get("/api/events", (c) => {
865
+ return streamSSE(c, async (stream) => {
866
+ let prevOverviews: SessionOverview[] = [];
867
+
868
+ const poll = () => {
869
+ const sessions = discoverSessions();
870
+ const overviews = buildOverviews(sessions);
871
+
872
+ const prevNames = new Set(prevOverviews.map((s) => s.name));
873
+ const currNames = new Set(overviews.map((s) => s.name));
874
+
875
+ for (const overview of overviews) {
876
+ if (!prevNames.has(overview.name)) {
877
+ stream.writeSSE({ event: "session_added", data: JSON.stringify(overview) });
878
+ }
879
+ }
880
+
881
+ for (const prev of prevOverviews) {
882
+ if (!currNames.has(prev.name)) {
883
+ stream.writeSSE({
884
+ event: "session_removed",
885
+ data: JSON.stringify({ name: prev.name }),
886
+ });
887
+ }
888
+ }
889
+
890
+ prevOverviews = overviews;
891
+ };
892
+
893
+ poll();
894
+ while (true) {
895
+ await stream.sleep(2000);
896
+ poll();
897
+ }
898
+ });
899
+ });
900
+
901
+ // ---------------------------------------------------------------------
902
+ // GET /api/logs/:channel — SSE stream of structured logger entries.
903
+ //
904
+ // Channels are filtered views over the single in-process logger:
905
+ // - "daemon" → no component filter (all entries)
906
+ // - "hq" → component starts with "hq" or "remote"
907
+ // - "watchdog" → component starts with "watchdog"
908
+ // The dashboard BottomPanel Output tab opens one EventSource per
909
+ // selected channel. Backfill from the in-memory ring buffer is sent
910
+ // first as `event: "backfill"` followed by a `bookmark` event so the
911
+ // client can render history immediately; new entries arrive as
912
+ // `event: "entry"` data.
913
+ // ---------------------------------------------------------------------
914
+ app.get("/api/logs/:channel", (c) => {
915
+ const channel = c.req.param("channel");
916
+ const match = matchLogChannel(channel);
917
+ if (!match) {
918
+ return c.json({ error: `Unknown log channel: ${channel}` }, 404);
919
+ }
920
+ return streamSSE(c, async (stream) => {
921
+ // 1. Backfill from the ring buffer.
922
+ const backfill = getLogBuffer().filter(match);
923
+ for (const entry of backfill) {
924
+ await stream.writeSSE({ event: "entry", data: JSON.stringify(entry) });
925
+ }
926
+ await stream.writeSSE({ event: "bookmark", data: String(backfill.length) });
927
+ // 2. Subscribe to live entries.
928
+ const queue: LogEntry[] = [];
929
+ let cancelled = false;
930
+ const unsub = subscribeLogs((entry) => {
931
+ if (cancelled) return;
932
+ if (match(entry)) queue.push(entry);
933
+ });
934
+ try {
935
+ while (!cancelled) {
936
+ if (queue.length === 0) {
937
+ await stream.sleep(500);
938
+ continue;
939
+ }
940
+ const drained = queue.splice(0, queue.length);
941
+ for (const entry of drained) {
942
+ await stream.writeSSE({ event: "entry", data: JSON.stringify(entry) });
943
+ }
944
+ }
945
+ } finally {
946
+ cancelled = true;
947
+ unsub();
948
+ }
949
+ });
950
+ });
951
+
952
+ app.get("/health", (c) => {
953
+ return c.json({
954
+ ok: true,
955
+ uptime: Math.round(process.uptime()),
956
+ version: pkgVersion,
957
+ });
958
+ });
959
+
960
+ // --- Project registry ---
961
+
962
+ app.get("/api/projects", (c) => {
963
+ return c.json({ projects: listProjects() });
964
+ });
965
+
966
+ app.get("/api/projects/templates", (c) => {
967
+ return c.json({ templates: listAvailableTemplates() });
968
+ });
969
+
970
+ app.post("/api/projects", async (c) => {
971
+ let body: unknown;
972
+ try {
973
+ body = await c.req.json();
974
+ } catch {
975
+ return c.json({ error: "Invalid JSON body" }, 400);
976
+ }
977
+ const parsed = RegisterProjectRequestSchemaZ.safeParse(body);
978
+ if (!parsed.success) {
979
+ return c.json({ error: "Invalid request", details: parsed.error.issues }, 400);
980
+ }
981
+ try {
982
+ const project = await registerProject({
983
+ dir: parsed.data.dir,
984
+ name: parsed.data.name,
985
+ });
986
+ return c.json({ project }, 201);
987
+ } catch (err) {
988
+ if (err instanceof ProjectDirNotFoundError) {
989
+ return c.json({ error: err.message, code: err.code }, 400);
990
+ }
991
+ if (err instanceof ProjectAlreadyRegisteredError) {
992
+ return c.json({ error: err.message, code: err.code, suggestion: err.suggestion }, 409);
993
+ }
994
+ throw err;
995
+ }
996
+ });
997
+
998
+ app.delete("/api/projects/:name", (c) => {
999
+ const name = c.req.param("name");
1000
+ try {
1001
+ unregisterProject(name);
1002
+ return c.json({ ok: true });
1003
+ } catch (err) {
1004
+ if (err instanceof ProjectNotFoundError) {
1005
+ return c.json({ error: err.message, code: err.code }, 404);
1006
+ }
1007
+ throw err;
1008
+ }
1009
+ });
1010
+
1011
+ app.post("/api/projects/:name/probe", async (c) => {
1012
+ const name = c.req.param("name");
1013
+ if (!getProject(name)) {
1014
+ return c.json({ error: `Project "${name}" not found in registry`, code: "NOT_FOUND" }, 404);
1015
+ }
1016
+ try {
1017
+ const project = await refreshProject(name);
1018
+ return c.json({ project });
1019
+ } catch (err) {
1020
+ if (err instanceof ProjectNotFoundError) {
1021
+ return c.json({ error: err.message, code: err.code }, 404);
1022
+ }
1023
+ throw err;
1024
+ }
1025
+ });
1026
+
1027
+ app.post("/api/projects/init", async (c) => {
1028
+ let body: unknown;
1029
+ try {
1030
+ body = await c.req.json();
1031
+ } catch {
1032
+ return c.json({ error: "Invalid JSON body" }, 400);
1033
+ }
1034
+ const parsed = InitProjectRequestSchemaZ.safeParse(body);
1035
+ if (!parsed.success) {
1036
+ return c.json({ error: "Invalid request", details: parsed.error.issues }, 400);
1037
+ }
1038
+ if (!existsSync(parsed.data.dir)) {
1039
+ return c.json({ error: `Directory "${parsed.data.dir}" does not exist` }, 400);
1040
+ }
1041
+
1042
+ const jobId = randomUUID();
1043
+ const command = process.env.TMUX_IDE_INIT_COMMAND ?? "tmux-ide";
1044
+
1045
+ // Fire-and-forget — runs in the background and streams chunks via WS.
1046
+ void (async () => {
1047
+ try {
1048
+ await runInit({
1049
+ cwd: parsed.data.dir,
1050
+ template: parsed.data.template,
1051
+ command,
1052
+ onChunk: (chunk) => {
1053
+ broadcastInitOutput(jobId, chunk);
1054
+ },
1055
+ });
1056
+ // Mark stream complete
1057
+ broadcastInitOutput(jobId, "", true);
1058
+
1059
+ // Probe + register the freshly-init'd project so it shows up in
1060
+ // the registry — also broadcasts `projects.changed`.
1061
+ try {
1062
+ await registerProject({ dir: parsed.data.dir });
1063
+ } catch (err) {
1064
+ // Already-registered is benign here; report anything else.
1065
+ if (
1066
+ !(err instanceof ProjectAlreadyRegisteredError) &&
1067
+ !(err instanceof ProjectDirNotFoundError)
1068
+ ) {
1069
+ broadcastInitError(jobId, (err as Error).message);
1070
+ }
1071
+ }
1072
+ } catch (err) {
1073
+ if (err instanceof ProjectInitTimeoutError) {
1074
+ broadcastInitError(jobId, err.message);
1075
+ } else if (err instanceof ProjectInitFailedError) {
1076
+ broadcastInitError(jobId, err.message);
1077
+ } else {
1078
+ broadcastInitError(jobId, (err as Error).message);
1079
+ }
1080
+ }
1081
+ })();
1082
+
1083
+ return c.json({ jobId }, 202);
1084
+ });
1085
+
1086
+ // -------------------------------------------------------------------------
1087
+ // POST /api/filesystem/inspect — registry-agnostic directory inspection.
1088
+ // POST /api/projects/onboard — generate ide.yml + register the project.
1089
+ // -------------------------------------------------------------------------
1090
+
1091
+ app.post("/api/projects/onboard", async (c) => {
1092
+ let body: unknown;
1093
+ try {
1094
+ body = await c.req.json();
1095
+ } catch {
1096
+ return c.json({ error: "Invalid JSON body" }, 400);
1097
+ }
1098
+ const parsed = OnboardProjectRequestSchemaZ.safeParse(body);
1099
+ if (!parsed.success) {
1100
+ return c.json({ error: "Invalid request", details: parsed.error.issues }, 400);
1101
+ }
1102
+ const sandboxResult = sandboxResolveDir(parsed.data.dir);
1103
+ if ("error" in sandboxResult) {
1104
+ return c.json(
1105
+ { error: sandboxResult.error, message: sandboxResult.message },
1106
+ sandboxResult.status,
1107
+ );
1108
+ }
1109
+
1110
+ const dir = sandboxResult.canonical;
1111
+ let inspect;
1112
+ try {
1113
+ inspect = await inspectProject(dir);
1114
+ } catch (err) {
1115
+ if (err instanceof InspectDirNotFoundError) {
1116
+ return c.json({ error: "not-found", message: err.message }, 404);
1117
+ }
1118
+ throw err;
1119
+ }
1120
+
1121
+ // Never overwrite an existing ide.yml.
1122
+ try {
1123
+ assertNoExistingIdeYml(dir);
1124
+ } catch (err) {
1125
+ if (err instanceof OnboardConflictError) {
1126
+ return c.json({ error: err.message, code: err.code }, 409);
1127
+ }
1128
+ throw err;
1129
+ }
1130
+
1131
+ // Compose the config from inputs (defaults to inspect.name).
1132
+ const finalName = parsed.data.name?.trim() || inspect.name;
1133
+ let config;
1134
+ try {
1135
+ config = composeIdeYmlConfig({
1136
+ name: finalName,
1137
+ agents: parsed.data.agents,
1138
+ agentNames: parsed.data.agentNames,
1139
+ devCommand: parsed.data.devCommand ?? null,
1140
+ testCommand: parsed.data.testCommand ?? null,
1141
+ lintCommand: parsed.data.lintCommand ?? null,
1142
+ });
1143
+ } catch (err) {
1144
+ if (err instanceof OnboardInvalidInputError) {
1145
+ return c.json({ error: err.message, code: err.code }, 400);
1146
+ }
1147
+ throw err;
1148
+ }
1149
+
1150
+ writeConfig(dir, config);
1151
+
1152
+ // Now register — this also broadcasts `projects.changed`.
1153
+ try {
1154
+ const project = await registerProject({ dir, name: finalName });
1155
+ return c.json({ project }, 201);
1156
+ } catch (err) {
1157
+ if (err instanceof ProjectAlreadyRegisteredError) {
1158
+ return c.json({ error: err.message, code: err.code, suggestion: err.suggestion }, 409);
1159
+ }
1160
+ if (err instanceof ProjectDirNotFoundError) {
1161
+ return c.json({ error: err.message, code: err.code }, 400);
1162
+ }
1163
+ throw err;
1164
+ }
1165
+ });
1166
+
1167
+ return app;
1168
+ }
1169
+
1170
+ /**
1171
+ * Discover bundled templates by reading `templates/*.yml`. Hardcoded
1172
+ * descriptions for the canonical set; unknown templates surface with a
1173
+ * generic label so we don't break if templates are added without updating
1174
+ * this map.
1175
+ */
1176
+ function listAvailableTemplates(): ProjectTemplate[] {
1177
+ const __filename = fileURLToPath(import.meta.url);
1178
+ const __dir = dirname(__filename);
1179
+ // Repo-root templates/ — 4 levels up from packages/daemon/src/command-center/.
1180
+ // Pre-fold this lived at <pkg>/templates (..,.. worked); post-fold the
1181
+ // canonical templates dir is at the repo root.
1182
+ const templatesDir = join(__dir, "..", "..", "..", "..", "templates");
1183
+ if (!existsSync(templatesDir)) return [];
1184
+ const labels: Record<string, { label: string; description: string }> = {
1185
+ default: { label: "Default", description: "Single Claude pane + dev/shell row" },
1186
+ nextjs: {
1187
+ label: "Next.js",
1188
+ description: "Two Claude panes + Next.js dev server + shell",
1189
+ },
1190
+ vite: { label: "Vite", description: "Vite dev server + Claude + shell" },
1191
+ convex: {
1192
+ label: "Convex",
1193
+ description: "Convex dev + Next.js + Claude pane",
1194
+ },
1195
+ python: { label: "Python", description: "Python project with Claude + tests" },
1196
+ go: { label: "Go", description: "Go project with Claude + tests + shell" },
1197
+ "agent-team": {
1198
+ label: "Agent Team",
1199
+ description: "Lead + teammate Claude panes for coordinated multi-agent work",
1200
+ },
1201
+ "agent-team-nextjs": {
1202
+ label: "Agent Team — Next.js",
1203
+ description: "Agent team layout tuned for a Next.js app",
1204
+ },
1205
+ "agent-team-monorepo": {
1206
+ label: "Agent Team — Monorepo",
1207
+ description: "Agent team layout for monorepos with multiple apps",
1208
+ },
1209
+ missions: {
1210
+ label: "Missions",
1211
+ description: "Mission-driven layout with planner, validator, and researcher",
1212
+ },
1213
+ };
1214
+ const entries = readdirSync(templatesDir).filter((f) => f.endsWith(".yml"));
1215
+ return entries
1216
+ .map((file) => {
1217
+ const id = file.replace(/\.yml$/, "");
1218
+ const meta = labels[id];
1219
+ return {
1220
+ id,
1221
+ label: meta?.label ?? id,
1222
+ description: meta?.description ?? `Template: ${id}`,
1223
+ };
1224
+ })
1225
+ .sort((a, b) => a.id.localeCompare(b.id));
1226
+ }
1227
+
1228
+ /**
1229
+ * Attach the unified `/ws/events` push channel to a Node HTTP server. The
1230
+ * daemon calls this once after binding the command-center port. Existing
1231
+ * SSE endpoints (`/api/events`, `/api/project/<name>/stream`) continue to
1232
+ * work alongside this — they will be retired in a follow-up slice.
1233
+ */
1234
+ export function attachWsEvents(server: import("node:http").Server): {
1235
+ close: () => void;
1236
+ } {
1237
+ const wss = new WebSocketServer({ noServer: true });
1238
+
1239
+ const upgradeListener = (
1240
+ req: import("node:http").IncomingMessage,
1241
+ socket: import("node:net").Socket,
1242
+ head: Buffer,
1243
+ ): void => {
1244
+ const url = req.url ?? "/";
1245
+ const pathname = url.split("?")[0];
1246
+ if (pathname !== "/ws/events") return;
1247
+ wss.handleUpgrade(req, socket, head, (ws) => {
1248
+ handleWsEventsConnection(ws);
1249
+ });
1250
+ };
1251
+
1252
+ server.on("upgrade", upgradeListener);
1253
+
1254
+ return {
1255
+ close: () => {
1256
+ server.off("upgrade", upgradeListener);
1257
+ wss.close();
1258
+ },
1259
+ };
1260
+ }