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
package/bin/cli.ts CHANGED
@@ -1,26 +1,36 @@
1
- #!/usr/bin/env bun
1
+ // No shebang in source. The published bin is the compiled `bin/cli.js`
2
+ // (see scripts/build-cli.mjs) which adds `#!/usr/bin/env node` via the
3
+ // esbuild banner. Dev iteration uses `bun bin/cli.ts` directly, which
4
+ // doesn't need a shebang.
2
5
  import { parseArgs } from "node:util";
3
- import { resolve, dirname } from "node:path";
6
+ import { resolve, dirname, join } from "node:path";
4
7
  import { execFileSync } from "node:child_process";
8
+ import { existsSync } from "node:fs";
5
9
  import { fileURLToPath } from "node:url";
6
10
 
7
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
8
- import { launch } from "../src/launch.ts";
9
- import { init } from "../src/init.ts";
10
- import { stop } from "../src/stop.ts";
11
- import { attach } from "../src/attach.ts";
12
- import { ls } from "../src/ls.ts";
13
- import { doctor } from "../src/doctor.ts";
14
- import { status } from "../src/status.ts";
15
- import { inspect } from "../src/inspect.ts";
16
- import { validate } from "../src/validate.ts";
17
- import { detect } from "../src/detect.ts";
18
- import { config } from "../src/config.ts";
19
- import { restart } from "../src/restart.ts";
20
- import { taskCommand } from "../src/task.ts";
21
- import { send } from "../src/send.ts";
22
- import { IdeError } from "../src/lib/errors.ts";
23
- import { printCommandError } from "../src/lib/output.ts";
12
+ import { launch } from "../packages/daemon/src/launch.ts";
13
+ import { shouldOpenCockpit } from "../packages/daemon/src/tui/team/entry.ts";
14
+ import {
15
+ resolveTuiLaunch,
16
+ findCompiledTui,
17
+ isBunAvailable,
18
+ } from "../packages/daemon/src/tui/compiled.ts";
19
+ import { init } from "../packages/daemon/src/init.ts";
20
+ import { stop } from "../packages/daemon/src/stop.ts";
21
+ import { attach } from "../packages/daemon/src/attach.ts";
22
+ import { ls } from "../packages/daemon/src/ls.ts";
23
+ import { doctor } from "../packages/daemon/src/doctor.ts";
24
+ import { status } from "../packages/daemon/src/status.ts";
25
+ import { inspect } from "../packages/daemon/src/inspect.ts";
26
+ import { validate } from "../packages/daemon/src/validate.ts";
27
+ import { detect } from "../packages/daemon/src/detect.ts";
28
+ import { config } from "../packages/daemon/src/config.ts";
29
+ import { restart } from "../packages/daemon/src/restart.ts";
30
+ import { restore } from "../packages/daemon/src/restore.ts";
31
+ import { send } from "../packages/daemon/src/send.ts";
32
+ import { IdeError } from "../packages/daemon/src/lib/errors.ts";
33
+ import { printCommandError } from "../packages/daemon/src/lib/output.ts";
24
34
 
25
35
  const { positionals, values } = parseArgs({
26
36
  allowPositionals: true,
@@ -38,37 +48,47 @@ const { positionals, values } = parseArgs({
38
48
  verbose: { type: "boolean", default: false },
39
49
  help: { type: "boolean", short: "h" },
40
50
  version: { type: "boolean", short: "v" },
41
- // task command flags
42
- description: { type: "string", short: "d" },
43
- acceptance: { type: "string" },
44
- priority: { type: "string", short: "p" },
45
- status: { type: "string", short: "s" },
46
- assign: { type: "string", short: "a" },
47
- goal: { type: "string", short: "g" },
48
- tags: { type: "string", short: "t" },
49
- proof: { type: "string" },
50
- depends: { type: "string" },
51
- pr: { type: "boolean" },
52
- specialty: { type: "string" },
53
- milestone: { type: "string" },
54
- fulfills: { type: "string" },
55
- summary: { type: "string" },
56
- sequence: { type: "string" },
57
- evidence: { type: "string" },
58
51
  port: { type: "string" },
59
- // tunnel command flags
60
- provider: { type: "string" },
61
- domain: { type: "string" },
62
- authtoken: { type: "string" },
63
52
  // setup command flags
64
53
  edit: { type: "boolean" },
65
54
  wizard: { type: "boolean" },
66
- // remote command flags
67
- url: { type: "string" },
68
- "hq-url": { type: "string" },
69
55
  // send command flags
70
56
  to: { type: "string" },
71
57
  "no-enter": { type: "boolean" },
58
+ // wait command flags
59
+ status: { type: "string" },
60
+ timeout: { type: "string" },
61
+ match: { type: "string" },
62
+ // events command flag
63
+ follow: { type: "boolean" },
64
+ // force the team cockpit instead of launching a project
65
+ team: { type: "boolean" },
66
+ // adopt every live (non-internal) session at once
67
+ all: { type: "boolean" },
68
+ // restore: print the plan without touching tmux
69
+ "dry-run": { type: "boolean" },
70
+ // restore: replay recorded pane commands (off by default for safety)
71
+ "run-commands": { type: "boolean" },
72
+ // restore: revive agent conversations via `claude --resume <id>`
73
+ "resume-agents": { type: "boolean" },
74
+ // statusline: the session whose bar is being rendered
75
+ active: { type: "string" },
76
+ // switcher: the tmux client the popup was invoked on (see `switcher` case)
77
+ client: { type: "string" },
78
+ // team --popup: run the home cockpit as a popup over a tmux client (M-h)
79
+ popup: { type: "boolean" },
80
+ // sidebar-toggle: the session whose nav column is toggled (see `sidebar-toggle`)
81
+ session: { type: "string" },
82
+ // menu: the click position (mouse binds forward #{mouse_x}/#{mouse_y}) so the
83
+ // actions menu opens at the pointer instead of centered (see `menu` case)
84
+ x: { type: "string" },
85
+ y: { type: "string" },
86
+ // worktree: base ref for a new branch, the worktree checkout dir override,
87
+ // skip creating a session, and force-remove a dirty worktree (see `worktree`)
88
+ from: { type: "string" },
89
+ dir: { type: "string" },
90
+ "no-session": { type: "boolean" },
91
+ force: { type: "boolean" },
72
92
  },
73
93
  });
74
94
 
@@ -78,6 +98,7 @@ const knownCommands = new Set([
78
98
  "stop",
79
99
  "attach",
80
100
  "restart",
101
+ "restore",
81
102
  "ls",
82
103
  "doctor",
83
104
  "status",
@@ -85,23 +106,29 @@ const knownCommands = new Set([
85
106
  "validate",
86
107
  "detect",
87
108
  "config",
88
- "mission",
89
- "milestone",
90
- "goal",
91
- "task",
92
- "research",
93
- "plan",
94
- "skill",
95
- "metrics",
96
109
  "setup",
97
110
  "send",
98
- "dispatch",
99
- "notify",
100
- "orchestrator",
101
111
  "settings",
112
+ "team",
113
+ "switcher",
114
+ "wait",
115
+ "events",
116
+ "statusline",
117
+ "adopt",
118
+ "unadopt",
119
+ "agent",
120
+ "integration",
121
+ "chrome-updater",
122
+ "cheatsheet",
123
+ "welcome",
124
+ "menu",
125
+ "popup",
126
+ "sidebar-toggle",
127
+ "worktree",
128
+ "update",
129
+ "skill-sync",
102
130
  "command-center",
103
- "tunnel",
104
- "remote",
131
+ "server",
105
132
  "help",
106
133
  ]);
107
134
 
@@ -116,17 +143,8 @@ if (values.verbose) {
116
143
  globalThis.__tmuxIdeVerbose = true;
117
144
  }
118
145
 
119
- const ALIASES: Record<string, string> = {
120
- t: "task",
121
- g: "goal",
122
- m: "mission",
123
- ms: "milestone",
124
- orch: "orchestrator",
125
- o: "orchestrator",
126
- met: "metrics",
127
- };
128
146
  const firstPositional = positionals[0];
129
- const resolved = ALIASES[firstPositional] ?? firstPositional;
147
+ const resolved = firstPositional;
130
148
  const hasKnownCommand = resolved ? knownCommands.has(resolved) : false;
131
149
  const command = hasKnownCommand ? resolved : "start";
132
150
  const startTargetDir = hasKnownCommand ? positionals[1] : firstPositional;
@@ -146,19 +164,45 @@ function printHelp() {
146
164
  console.log(`${bold("tmux-ide")} — Terminal IDE powered by tmux
147
165
 
148
166
  ${bold("Usage:")}
149
- ${cyan("tmux-ide")} ${dim("Launch IDE from ide.yml")}
150
- ${cyan("tmux-ide <path>")} ${dim("Launch from a specific directory")}
167
+ ${cyan("tmux-ide")} ${dim("Launch ide.yml, or open the team cockpit if none")}
168
+ ${cyan("tmux-ide <path>")} ${dim("Launch from a specific directory (cockpit if no ide.yml)")}
151
169
  ${cyan("tmux-ide setup")} ${dim("Interactive TUI setup wizard")}
152
170
  ${cyan("tmux-ide setup --edit")} ${dim("Open config tree editor")}
153
171
  ${cyan("tmux-ide settings")} ${dim("Interactive TUI config manager")}
154
172
  ${cyan("tmux-ide init")} [--template] ${dim("Scaffold a new ide.yml (auto-detects stack)")}
155
173
  ${cyan("tmux-ide stop")} ${dim("Kill the current IDE session")}
156
174
  ${cyan("tmux-ide restart")} ${dim("Stop and relaunch the IDE session")}
175
+ ${cyan("tmux-ide restore")} [--dry-run] [--run-commands] [--resume-agents] [--json]
176
+ ${dim("Rebuild the fleet from the last snapshot after a tmux crash")}
177
+ ${dim("(--resume-agents revives claude conversations via claude --resume)")}
157
178
  ${cyan("tmux-ide attach")} ${dim("Reattach to a running session")}
179
+ ${cyan("tmux-ide team")} [--json] ${dim("TUI over all tmux sessions (--json prints fleet state)")}
180
+ ${cyan("tmux-ide switcher")} ${dim("Compact session picker (opens in the M-p popup on adopted sessions)")}
181
+ ${cyan("tmux-ide wait agent-status")} <session> --status <s> [--timeout <ms>]
182
+ ${dim("Block until a session reaches a status (exit 0 match / 1 timeout)")}
183
+ ${cyan("tmux-ide wait output")} <pane|session> --match <regex> [--timeout <ms>]
184
+ ${dim("Block until a pane's output matches a regex (exit 0 match / 1 timeout)")}
185
+ ${cyan("tmux-ide events")} [--follow] [--json] ${dim("Stream agent-status transitions (needs an adopted session)")}
186
+ ${cyan("tmux-ide adopt")} <session> ${dim("Add the live tmux-ide status bar to a session")}
187
+ ${cyan("tmux-ide adopt --all")} ${dim("Adopt every live (non-internal) session")}
188
+ ${cyan("tmux-ide unadopt")} <session> ${dim("Remove the status bar")}
189
+ ${cyan("tmux-ide integration install claude")} ${dim("Authoritative agent status via Claude Code hooks")}
190
+ ${cyan("tmux-ide agent explain")} <pane> [--json] ${dim("Debug how a pane's agent state is detected")}
191
+ ${cyan("tmux-ide cheatsheet")} ${dim("Print the key cheat sheet (⌥k / [ ? keys ] popup)")}
192
+ ${cyan("tmux-ide menu")} [--client N] ${dim("Open the right-click actions menu (⌥m / right-click any pane or the bar)")}
193
+ ${cyan("tmux-ide popup")} <widget> ${dim("Open a widget as a floating panel (explorer/changes/config; ⌥e/⌥g/⌥,)")}
194
+ ${cyan("tmux-ide sidebar-toggle")} [--session S] ${dim("Toggle the app nav column (⌥b on adopted sessions)")}
195
+ ${cyan("tmux-ide worktree create")} <branch> [--from <ref>] [--dir <path>] [--no-session]
196
+ ${dim("Add a git worktree (new branch) + open a session in it")}
197
+ ${cyan("tmux-ide worktree open")} <branch> ${dim("Open (or switch to) the session for an existing worktree")}
198
+ ${cyan("tmux-ide worktree list")} [--json] ${dim("List worktrees joined with their session status")}
199
+ ${cyan("tmux-ide worktree remove")} <branch> [--force] ${dim("Kill the worktree's session + remove the worktree")}
158
200
  ${cyan("tmux-ide ls")} ${dim("List all tmux sessions")}
159
201
  ${cyan("tmux-ide status")} [--json] ${dim("Show session status")}
160
202
  ${cyan("tmux-ide inspect")} [--json] ${dim("Show effective config and runtime state")}
161
203
  ${cyan("tmux-ide doctor")} ${dim("Check system requirements")}
204
+ ${cyan("tmux-ide update")} [--dry-run] ${dim("Update tmux-ide (detects dev checkout vs npm/pnpm/bun global)")}
205
+ ${cyan("tmux-ide skill-sync")} ${dim("Refresh the bundled Claude Code skill in ~/.claude/skills/tmux-ide")}
162
206
  ${cyan("tmux-ide validate")} [--json] ${dim("Validate ide.yml")}
163
207
  ${cyan("tmux-ide detect")} [--json] ${dim("Detect project stack")}
164
208
  ${cyan("tmux-ide detect --write")} ${dim("Detect and write ide.yml")}
@@ -175,27 +219,17 @@ ${bold("Pane Messaging:")}
175
219
  ${cyan("tmux-ide send")} --to <name> <message> ${dim("Target by name, title, role, or ID")}
176
220
  ${cyan("tmux-ide send")} <target> --no-enter msg ${dim("Send text without pressing Enter")}
177
221
 
178
- ${bold("Dispatch:")}
179
- ${cyan("tmux-ide dispatch")} <id> [--json] ${dim("Print task context to stdout")}
180
- ${cyan("tmux-ide notify")} <message> [--json] ${dim("Send notification to lead pane")}
181
-
182
- ${bold("Orchestrator:")}
183
- ${cyan("tmux-ide orchestrator")} [--json] ${dim("Show orchestrator status")}
184
- ${cyan("tmux-ide orch")} ${dim("Alias for orchestrator")}
185
-
186
- ${bold("Task Management:")}
187
- ${cyan("tmux-ide mission set")} "title" ${dim("Set the project mission")}
188
- ${cyan("tmux-ide mission show")} ${dim("Show current mission")}
189
- ${cyan("tmux-ide goal list")} ${dim("List goals")}
190
- ${cyan("tmux-ide goal create")} "title" ${dim("Create a goal")}
191
- ${cyan("tmux-ide goal show")} <id> ${dim("Show goal with tasks")}
192
- ${cyan("tmux-ide task list")} [--status X --goal Y] ${dim("List tasks")}
193
- ${cyan("tmux-ide task create")} "title" [--goal id] ${dim("Create a task")}
194
- ${cyan("tmux-ide task claim")} <id> [--assign name] ${dim("Claim a task")}
195
- ${cyan("tmux-ide task done")} <id> [--proof "..."] ${dim("Complete a task")}
196
- ${cyan("tmux-ide task show")} <id> ${dim("Show task with full context")}
197
- ${cyan("tmux-ide research status")} ${dim("Show research agent state")}
198
- ${cyan("tmux-ide research trigger")} <type> ${dim("Manually dispatch a research task")}
222
+ ${bold("Server:")}
223
+ ${cyan("tmux-ide command-center")} [--port N] ${dim("Start the command-center HTTP API")}
224
+ ${cyan("tmux-ide server")} [--port N] ${dim("Start HTTP + PTY WebSocket server")}
225
+
226
+ ${bold("Discover (in the TUI):")}
227
+ ${dim("Bare")} ${cyan("tmux-ide")} ${dim("with no ide.yml opens the HOME cockpit — the fleet home screen.")}
228
+ ${dim("Once a session is adopted, the whole UI is one keystroke away:")}
229
+ ${cyan("⌥h")} ${dim("home cockpit from anywhere ")}${cyan("⌥p")} ${dim("switch session")}
230
+ ${cyan("⌥k")} ${dim("cheat sheet (all keys) ")}${cyan("⌥m")} ${dim("actions menu (or right-click any pane / the bar)")}
231
+ ${cyan("⌥e ⌥g ⌥,")} ${dim("file / changes / config panels ")}${cyan("⌥b")} ${dim("sidebar")}
232
+ ${dim("A first-run welcome card names these keys once. Run")} ${cyan("tmux-ide cheatsheet")} ${dim("to see the full sheet.")}
199
233
 
200
234
  ${bold("Flags:")}
201
235
  ${cyan("--json")} ${dim("Output as JSON (all commands)")}
@@ -206,11 +240,110 @@ ${bold("Flags:")}
206
240
  ${cyan("-v, --version")} ${dim("Show version number")}`);
207
241
  }
208
242
 
243
+ // The TUI surfaces are OpenTUI/Solid `.tsx` that need the `bun` runtime and the
244
+ // checkout sources. On a clean `npm i -g tmux-ide` neither is present, so we
245
+ // fall back to the compiled `tmux-ide-tui` binary (see scripts/build-tui.mjs).
246
+ // `resolveTuiLaunch` encodes the "checkout first, binary second" order; when
247
+ // nothing is available it hands back an actionable reason set for an IdeError.
248
+ function execBunWidget(
249
+ surface: string,
250
+ scriptPath: string,
251
+ args: string[],
252
+ commandLabel: string,
253
+ extraEnv: Record<string, string> = {},
254
+ ): void {
255
+ const launch = resolveTuiLaunch({
256
+ surface,
257
+ scriptPath,
258
+ args,
259
+ checkoutExists: existsSync(scriptPath),
260
+ bunAvailable: isBunAvailable(),
261
+ compiledBinary: findCompiledTui(),
262
+ });
263
+
264
+ if (launch.mode === "unavailable") {
265
+ throw new IdeError(
266
+ `\`tmux-ide ${commandLabel}\` is unavailable because ${launch.reasons.join(" and ")}.\n` +
267
+ `Install bun (https://bun.sh) — the TUI surfaces run on it. Sources ship with the npm package since v2.6.1.`,
268
+ { code: "USAGE", exitCode: 1 },
269
+ );
270
+ }
271
+
272
+ const env = { ...process.env, TMUX_IDE_CWD: process.cwd(), ...extraEnv };
273
+ if (launch.mode === "bun") {
274
+ // Spawn from the repo root so bun finds `bunfig.toml` (the @opentui/solid
275
+ // JSX preload). Without this, running from any other cwd — e.g. bare
276
+ // `tmux-ide` in a project dir — falls back to the React JSX runtime and the
277
+ // widget fails to load. The real invocation dir rides in env so in-widget
278
+ // prompts (register / new session) still default to where the user is.
279
+ execFileSync(launch.bin, launch.argv, {
280
+ stdio: "inherit",
281
+ cwd: resolve(__dirname, ".."),
282
+ env,
283
+ });
284
+ return;
285
+ }
286
+
287
+ // Compiled binary: the JSX transform and native dylib are already baked in,
288
+ // so there is no bunfig to find — run from the user's actual cwd (also avoids
289
+ // a stray repo-root bunfig.toml preload the standalone binary can't resolve).
290
+ execFileSync(launch.bin, launch.argv, { stdio: "inherit", env });
291
+ }
292
+
293
+ // The scriptable control surface for the cockpit: print the fleet state as JSON
294
+ // and exit without spawning the (bun/OpenTUI) TUI. Shared by `tmux-ide team
295
+ // --json` and bare `tmux-ide --json` when there's no ide.yml to launch. Dynamic
296
+ // imports keep the interactive path free of the data-layer modules.
297
+ async function printFleetJson(): Promise<void> {
298
+ const { createStatusTracker } = await import("../packages/daemon/src/tui/detect/classify.ts");
299
+ const { listTeamProjects } = await import("../packages/daemon/src/tui/team/projects.ts");
300
+ const { toFleetJson } = await import("../packages/daemon/src/tui/team/report.ts");
301
+ console.log(JSON.stringify(toFleetJson(listTeamProjects(createStatusTracker())), null, 2));
302
+ }
303
+
304
+ const teamScriptPath = resolve(__dirname, "../packages/daemon/src/tui/team/index.tsx");
305
+
306
+ // `tmux-ide team` runs the standalone full-screen cockpit (the OpenTUI app owns
307
+ // the whole terminal). The floating switcher popup (M-p on adopted sessions)
308
+ // supersedes the old nested `[ switcher | main ]` host shell.
309
+ function launchTeamCockpit(): void {
310
+ execBunWidget("team", teamScriptPath, [], "team");
311
+ }
312
+
209
313
  try {
210
314
  switch (command) {
211
- case "start":
315
+ case "start": {
316
+ // npm-style staleness nudge: one dim stderr line when a newer version is
317
+ // cached (never on --json, never blocking — best-effort, and stderr so it
318
+ // can't corrupt piped stdout). The dock is the primary surface; this is the
319
+ // hint for the moment you actually run the command.
320
+ if (!json) {
321
+ try {
322
+ const { getUpdateStatus } = await import("../packages/daemon/src/lib/update-check.ts");
323
+ const { latest, updateAvailable } = getUpdateStatus();
324
+ if (updateAvailable && latest) {
325
+ process.stderr.write(
326
+ dim(`⬆ tmux-ide v${latest} available — run \`tmux-ide update\`\n`),
327
+ );
328
+ }
329
+ } catch {
330
+ // never let the update hint interfere with launching
331
+ }
332
+ }
333
+ const targetDir = resolve(startTargetDir || ".");
334
+ const hasIdeYml = existsSync(join(targetDir, "ide.yml"));
335
+ if (shouldOpenCockpit(hasIdeYml, values.team === true)) {
336
+ // No project here (or --team): the cockpit is the front door.
337
+ if (json) {
338
+ await printFleetJson();
339
+ break;
340
+ }
341
+ launchTeamCockpit();
342
+ break;
343
+ }
212
344
  await launch(startTargetDir, { json });
213
345
  break;
346
+ }
214
347
 
215
348
  case "init":
216
349
  await init({ template: values.template, json });
@@ -228,6 +361,15 @@ try {
228
361
  await restart(positionals[1], { json });
229
362
  break;
230
363
 
364
+ case "restore":
365
+ await restore({
366
+ json,
367
+ dryRun: values["dry-run"] === true,
368
+ runCommands: values["run-commands"] === true,
369
+ resumeAgents: values["resume-agents"] === true,
370
+ });
371
+ break;
372
+
231
373
  case "ls":
232
374
  await ls({ json });
233
375
  break;
@@ -244,31 +386,9 @@ try {
244
386
  await inspect(positionals[1], { json });
245
387
  break;
246
388
 
247
- case "validate": {
248
- const valSub = positionals[1];
249
- if (
250
- valSub === "assert" ||
251
- valSub === "show" ||
252
- valSub === "report" ||
253
- valSub === "coverage" ||
254
- valSub === "help"
255
- ) {
256
- await taskCommand(null, {
257
- json,
258
- action: "validate",
259
- sub: valSub,
260
- args: positionals.slice(2),
261
- values: {
262
- status: values.status,
263
- evidence: values.evidence,
264
- assign: values.assign,
265
- },
266
- });
267
- } else {
268
- await validate(valSub, { json });
269
- }
389
+ case "validate":
390
+ await validate(positionals[1], { json });
270
391
  break;
271
- }
272
392
 
273
393
  case "detect":
274
394
  await detect(positionals[1], { json, write: values.write });
@@ -306,10 +426,13 @@ try {
306
426
  action = "disable-team";
307
427
  configArgs = [];
308
428
  } else if (sub === "edit") {
309
- const scriptPath = resolve(__dirname, "../src/widgets/setup/index.tsx");
310
- execFileSync("bun", [scriptPath, "--dir=" + resolve(startTargetDir || "."), "--edit"], {
311
- stdio: "inherit",
312
- });
429
+ const scriptPath = resolve(__dirname, "../packages/daemon/src/widgets/setup/index.tsx");
430
+ execBunWidget(
431
+ "setup",
432
+ scriptPath,
433
+ ["--dir=" + resolve(startTargetDir || "."), "--edit"],
434
+ "config edit",
435
+ );
313
436
  break;
314
437
  }
315
438
 
@@ -317,206 +440,966 @@ try {
317
440
  break;
318
441
  }
319
442
 
320
- case "mission": {
321
- const sub = positionals[1];
322
- await taskCommand(null, {
323
- json,
324
- action: "mission",
325
- sub,
326
- args: positionals.slice(2),
327
- values: { description: values.description },
328
- });
443
+ case "setup": {
444
+ const scriptPath = resolve(__dirname, "../packages/daemon/src/widgets/setup/index.tsx");
445
+ const setupArgs = ["--dir=" + resolve(startTargetDir || ".")];
446
+ if (positionals[1] === "--edit" || values.edit) setupArgs.push("--edit");
447
+ if (positionals[1] === "--wizard" || values.wizard) setupArgs.push("--wizard");
448
+ execBunWidget("setup", scriptPath, setupArgs, "setup");
329
449
  break;
330
450
  }
331
451
 
332
- case "milestone": {
333
- const sub = positionals[1];
334
- await taskCommand(null, {
335
- json,
336
- action: "milestone",
337
- sub,
338
- args: positionals.slice(2),
339
- values: {
340
- description: values.description,
341
- status: values.status,
342
- sequence: values.sequence,
343
- },
344
- });
452
+ case "send": {
453
+ const target = values.to ?? positionals[1];
454
+ const messageStart = values.to ? 1 : 2;
455
+ let message = positionals.slice(messageStart).join(" ");
456
+ if (!message && !process.stdin.isTTY) {
457
+ const { readFileSync } = await import("node:fs");
458
+ message = readFileSync(0, "utf-8").trim();
459
+ }
460
+ await send(null, { json, to: target, message, noEnter: values["no-enter"] });
345
461
  break;
346
462
  }
347
463
 
348
- case "goal": {
349
- const sub = positionals[1];
350
- await taskCommand(null, {
351
- json,
352
- action: "goal",
353
- sub,
354
- args: positionals.slice(2),
355
- values: {
356
- description: values.description,
357
- acceptance: values.acceptance,
358
- priority: values.priority,
359
- status: values.status,
360
- specialty: values.specialty,
361
- },
362
- });
464
+ case "settings": {
465
+ const scriptPath = resolve(__dirname, "../packages/daemon/src/widgets/config/index.tsx");
466
+ execBunWidget("config", scriptPath, ["--dir=" + resolve(startTargetDir || ".")], "settings");
363
467
  break;
364
468
  }
365
469
 
366
- case "task": {
367
- const sub = positionals[1];
368
- await taskCommand(null, {
369
- json,
370
- action: "task",
371
- sub,
372
- args: positionals.slice(2),
373
- values: {
374
- title: values.title,
375
- description: values.description,
376
- priority: values.priority,
377
- status: values.status,
378
- assign: values.assign,
379
- goal: values.goal,
380
- tags: values.tags,
381
- proof: values.proof,
382
- depends: values.depends,
383
- pr: values.pr,
384
- specialty: values.specialty,
385
- milestone: values.milestone,
386
- fulfills: values.fulfills,
387
- summary: values.summary,
388
- },
389
- });
470
+ case "team": {
471
+ // `--json` is the scriptable control surface: print the fleet state and
472
+ // exit without spawning the (bun/OpenTUI) TUI.
473
+ if (json) {
474
+ await printFleetJson();
475
+ break;
476
+ }
477
+ // `--popup` runs the FULL home cockpit inside a tmux `display-popup` (bound
478
+ // to `M-h` on adopt / the dock's `[ ⌂ home ⌥h ]` trigger). Like the
479
+ // switcher, `TMUX_IDE_POPUP_CLIENT` flips popup mode (Enter switch-clients
480
+ // the invoking client + closes) and carries an optional explicit client;
481
+ // empty means "resolve it yourself from inside the popup". Unlike the
482
+ // switcher it keeps the full two-column layout, not the compact picker.
483
+ if (values.popup === true) {
484
+ const clientArg = typeof values.client === "string" ? values.client : "";
485
+ execBunWidget("team", teamScriptPath, [], "team --popup", {
486
+ TMUX_IDE_POPUP_CLIENT: clientArg,
487
+ });
488
+ break;
489
+ }
490
+ launchTeamCockpit();
390
491
  break;
391
492
  }
392
493
 
393
- case "research": {
494
+ case "switcher": {
495
+ // Runs the team app in PICKER mode inside a tmux `display-popup` (bound to
496
+ // `M-p` on adopt). Picking a session `switch-client`s the invoking client
497
+ // there and the app exits, closing the popup. `TMUX_IDE_PICKER_CLIENT`
498
+ // both flips the app into picker mode and carries an optional explicit
499
+ // client name; empty means "resolve it yourself from inside the popup".
500
+ const clientArg = typeof values.client === "string" ? values.client : "";
501
+ execBunWidget("team", teamScriptPath, [], "switcher", { TMUX_IDE_PICKER_CLIENT: clientArg });
502
+ break;
503
+ }
504
+
505
+ case "wait": {
394
506
  const sub = positionals[1];
395
- await taskCommand(null, {
396
- json,
397
- action: "research",
398
- sub,
399
- args: positionals.slice(2),
400
- values: {},
507
+
508
+ // `wait output <pane|session> --match <regex>` — block until a pane's
509
+ // captured text matches. The target may be a pane id (%N) or a session
510
+ // name; tmux resolves both (a session targets its active pane).
511
+ if (sub === "output") {
512
+ const target = positionals[2];
513
+ const pattern = values.match;
514
+ if (!target || typeof pattern !== "string" || pattern.length === 0) {
515
+ console.error(
516
+ "Usage: tmux-ide wait output <pane|session> --match <regex> [--timeout <ms>]",
517
+ );
518
+ process.exit(1);
519
+ }
520
+ try {
521
+ new RegExp(pattern!); // validate up front; a bad pattern is a usage error
522
+ } catch (err) {
523
+ console.error(`Invalid --match regex: ${(err as Error).message}`);
524
+ process.exit(1);
525
+ }
526
+ const { capturePane } = await import("../packages/tmux-bridge/src/index.ts");
527
+ const outTimeout = Number(values.timeout ?? "60000");
528
+ const outStart = Date.now();
529
+ const nap = (ms: number) => new Promise((r) => setTimeout(r, ms));
530
+ while (true) {
531
+ let text = "";
532
+ try {
533
+ text = capturePane(target!, { lines: 200 });
534
+ } catch {
535
+ // pane/session not (yet) available — keep polling until timeout
536
+ }
537
+ const lines = text.split("\n");
538
+ // Fresh regex per test so a user-supplied /g flag can't carry lastIndex
539
+ // between calls. Report the specific matching line when we can.
540
+ let hit: string | null = null;
541
+ for (const line of lines) {
542
+ if (new RegExp(pattern!).test(line)) {
543
+ hit = line;
544
+ break;
545
+ }
546
+ }
547
+ if (hit === null && new RegExp(pattern!).test(text)) hit = lines[lines.length - 1] ?? "";
548
+ if (hit !== null) {
549
+ if (json) console.log(JSON.stringify({ matched: hit }));
550
+ else console.log(hit);
551
+ process.exit(0);
552
+ }
553
+ if (Date.now() - outStart >= outTimeout) {
554
+ console.error(
555
+ `Timed out after ${outTimeout}ms waiting for ${target} output to match /${pattern}/`,
556
+ );
557
+ process.exit(1);
558
+ }
559
+ await nap(500);
560
+ }
561
+ }
562
+
563
+ const { createStatusTracker } = await import("../packages/daemon/src/tui/detect/classify.ts");
564
+ const { listTeamSessions } = await import("../packages/daemon/src/tui/team/sessions.ts");
565
+ const { findSessionStatus } = await import("../packages/daemon/src/tui/team/report.ts");
566
+
567
+ const VALID = new Set(["blocked", "working", "done", "idle", "unknown"]);
568
+ const sessionName = positionals[2];
569
+ const want = values.status;
570
+
571
+ if (sub !== "agent-status" || !sessionName || typeof want !== "string" || !VALID.has(want)) {
572
+ console.error(
573
+ "Usage: tmux-ide wait agent-status <session> --status <blocked|working|done|idle|unknown> [--timeout <ms>]",
574
+ );
575
+ process.exit(1);
576
+ }
577
+
578
+ const timeout = Number(values.timeout ?? "60000");
579
+ const started = Date.now();
580
+ const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
581
+ // One tracker persists across polls so the working→idle `done` transition
582
+ // can be observed (it's inherently cross-tick).
583
+ const tracker = createStatusTracker();
584
+
585
+ while (true) {
586
+ const sessions = listTeamSessions(tracker);
587
+ const status = findSessionStatus(sessions, sessionName!);
588
+ if (status === want) {
589
+ if (json) {
590
+ console.log(JSON.stringify({ session: sessionName, status, ok: true }));
591
+ } else {
592
+ console.log(`${sessionName} reached status: ${status}`);
593
+ }
594
+ process.exit(0);
595
+ }
596
+ if (Date.now() - started >= timeout) {
597
+ console.error(
598
+ `Timed out after ${timeout}ms waiting for ${sessionName} to reach status "${want}" (last: ${status ?? "absent"})`,
599
+ );
600
+ process.exit(1);
601
+ }
602
+ await sleep(750);
603
+ }
604
+ }
605
+
606
+ case "events": {
607
+ // Stream agent-status transitions from the log the chrome updater writes.
608
+ const { readFileSync, existsSync, statSync, openSync, readSync, closeSync } =
609
+ await import("node:fs");
610
+ const { eventsPath, formatEventLine } =
611
+ await import("../packages/daemon/src/tui/chrome/events.ts");
612
+ type Status = "blocked" | "working" | "done" | "idle" | "unknown";
613
+ type EventLike = { ts: string; session: string; from: Status | null; to: Status };
614
+
615
+ const path = eventsPath();
616
+ if (!existsSync(path)) {
617
+ console.log("no events yet — is a session adopted? (the chrome updater writes events)");
618
+ break;
619
+ }
620
+
621
+ // Status → ANSI color, matching the chrome bar's palette in spirit.
622
+ const paintStatus = (status: Status | null, text: string): string => {
623
+ if (noColor || status === null) return text;
624
+ const code =
625
+ status === "blocked"
626
+ ? "203"
627
+ : status === "working"
628
+ ? "221"
629
+ : status === "done"
630
+ ? "111"
631
+ : status === "idle"
632
+ ? "114"
633
+ : "244";
634
+ return `\x1b[38;5;${code}m${text}\x1b[39m`;
635
+ };
636
+ const printLine = (raw: string): void => {
637
+ if (json) {
638
+ console.log(raw);
639
+ return;
640
+ }
641
+ try {
642
+ const ev = JSON.parse(raw) as EventLike;
643
+ console.log(formatEventLine(ev, paintStatus));
644
+ } catch {
645
+ // skip malformed line
646
+ }
647
+ };
648
+
649
+ const allLines = readFileSync(path, "utf8")
650
+ .split("\n")
651
+ .filter((l) => l.trim().length > 0);
652
+ for (const line of allLines.slice(-50)) printLine(line);
653
+
654
+ if (!values.follow) break;
655
+
656
+ // Follow: poll the file for appended bytes and stream complete new lines.
657
+ let offset = statSync(path).size;
658
+ let leftover = "";
659
+ const timer = setInterval(() => {
660
+ let size: number;
661
+ try {
662
+ size = statSync(path).size;
663
+ } catch {
664
+ return;
665
+ }
666
+ if (size < offset) {
667
+ // rotated/truncated — restart from the top of the new file
668
+ offset = 0;
669
+ leftover = "";
670
+ }
671
+ if (size <= offset) return;
672
+ const fd = openSync(path, "r");
673
+ try {
674
+ const buf = Buffer.alloc(size - offset);
675
+ readSync(fd, buf, 0, buf.length, offset);
676
+ offset = size;
677
+ const parts = (leftover + buf.toString("utf8")).split("\n");
678
+ leftover = parts.pop() ?? "";
679
+ for (const line of parts) if (line.trim().length > 0) printLine(line);
680
+ } finally {
681
+ closeSync(fd);
682
+ }
683
+ }, 500);
684
+ process.on("SIGINT", () => {
685
+ clearInterval(timer);
686
+ process.exit(0);
401
687
  });
688
+ // Keep the process alive; the interval + SIGINT handler own the lifecycle.
689
+ await new Promise(() => {});
402
690
  break;
403
691
  }
404
692
 
405
- case "plan": {
406
- const { planCommand } = await import("../src/plan.ts");
407
- await planCommand(null, {
408
- json,
409
- sub: positionals[1],
410
- args: positionals.slice(2),
411
- values: { status: values.status },
412
- });
693
+ case "statusline": {
694
+ // Called by tmux via #() every status-interval — keep it lean and never
695
+ // let an error corrupt the bar (print a minimal brand instead).
696
+ try {
697
+ const { createStatusTracker } =
698
+ await import("../packages/daemon/src/tui/detect/classify.ts");
699
+ const { listTeamProjects } = await import("../packages/daemon/src/tui/team/projects.ts");
700
+ const { buildStatusline } = await import("../packages/daemon/src/tui/chrome/statusline.ts");
701
+ const { getAppConfig } = await import("../packages/daemon/src/lib/app-config.ts");
702
+ const projects = listTeamProjects(createStatusTracker());
703
+ console.log(buildStatusline(projects, values.active ?? null, 12, getAppConfig().theme));
704
+ } catch {
705
+ console.log("#[fg=colour75,bold] tmux-ide #[default]");
706
+ }
413
707
  break;
414
708
  }
415
709
 
416
- case "skill": {
417
- const { skillCommand } = await import("../src/skill.ts");
418
- await skillCommand(null, {
419
- json,
420
- sub: positionals[1],
421
- args: positionals.slice(2),
422
- });
710
+ case "adopt": {
711
+ const { adoptSession, adoptableSessionNames } =
712
+ await import("../packages/daemon/src/tui/chrome/statusline.ts");
713
+ if (values.all) {
714
+ // Adopt every live session that isn't internal (`_`-prefixed plumbing).
715
+ const raw = execFileSync("tmux", ["list-sessions", "-F", "#{session_name}"], {
716
+ encoding: "utf8",
717
+ stdio: ["ignore", "pipe", "ignore"],
718
+ }).trim();
719
+ const targets = raw ? adoptableSessionNames(raw.split("\n")) : [];
720
+ if (targets.length === 0) {
721
+ console.log("no adoptable sessions");
722
+ break;
723
+ }
724
+ for (const name of targets) {
725
+ adoptSession(name);
726
+ console.log(`adopted ${name}`);
727
+ }
728
+ break;
729
+ }
730
+ const target = positionals[1];
731
+ if (!target) {
732
+ console.error("Usage: tmux-ide adopt <session> | tmux-ide adopt --all");
733
+ process.exit(1);
734
+ }
735
+ adoptSession(target);
736
+ console.log(`adopted ${target} — chrome row active (unadopt to remove)`);
423
737
  break;
424
738
  }
425
739
 
426
- case "metrics": {
427
- const { metricsCommand } = await import("../src/metrics-cli.ts");
428
- await metricsCommand(null, {
429
- json,
430
- sub: positionals[1],
431
- });
740
+ case "unadopt": {
741
+ const { unadoptSession } = await import("../packages/daemon/src/tui/chrome/statusline.ts");
742
+ const target = positionals[1];
743
+ if (!target) {
744
+ console.error("Usage: tmux-ide unadopt <session>");
745
+ process.exit(1);
746
+ }
747
+ unadoptSession(target);
748
+ console.log(`unadopted ${target}`);
432
749
  break;
433
750
  }
434
751
 
435
- case "setup": {
436
- const scriptPath = resolve(__dirname, "../src/widgets/setup/index.tsx");
437
- const setupArgs = [scriptPath, "--dir=" + resolve(startTargetDir || ".")];
438
- if (positionals[1] === "--edit" || values.edit) setupArgs.push("--edit");
439
- if (positionals[1] === "--wizard" || values.wizard) setupArgs.push("--wizard");
440
- execFileSync("bun", setupArgs, { stdio: "inherit" });
752
+ case "agent": {
753
+ const sub = positionals[1];
754
+ const target = positionals[2];
755
+ if (sub !== "explain" || !target) {
756
+ console.error(
757
+ "Usage: tmux-ide agent explain <pane> [--json]\n" +
758
+ " <pane> a pane id (%N) or a session name (uses its active pane)\n" +
759
+ " Prints how the fleet detector classifies the pane: authority,\n" +
760
+ " hint, resolved manifest, per-state rule results, and the snapshot.",
761
+ );
762
+ process.exit(1);
763
+ }
764
+ const { agentExplain } = await import("../packages/daemon/src/agent-explain.ts");
765
+ agentExplain(target, { json });
441
766
  break;
442
767
  }
443
768
 
444
- case "send": {
445
- const target = values.to ?? positionals[1];
446
- const messageStart = values.to ? 1 : 2;
447
- let message = positionals.slice(messageStart).join(" ");
448
- if (!message && !process.stdin.isTTY) {
449
- const { readFileSync } = await import("node:fs");
450
- message = readFileSync(0, "utf-8").trim();
769
+ case "integration": {
770
+ const sub = positionals[1];
771
+ const agent = positionals[2];
772
+ // `status` and `offer` need no agent arg; install/uninstall are claude-only.
773
+ const needsClaude = sub === "install" || sub === "uninstall";
774
+ if (!sub || (needsClaude && agent !== "claude")) {
775
+ console.error(
776
+ "Usage: tmux-ide integration <install|uninstall|status|offer> [claude]\n" +
777
+ " install hook Claude Code lifecycle events into tmux pane state\n" +
778
+ " uninstall remove exactly the tmux-ide hook entries\n" +
779
+ " status list discovered agents + integration state\n" +
780
+ " offer one-time first-adopt install prompt (used by the popup)",
781
+ );
782
+ process.exit(1);
783
+ }
784
+ const mod = await import("../packages/daemon/src/tui/integrations/claude.ts");
785
+ if (sub === "install") {
786
+ const { scriptPath, settingsPath } = mod.installClaudeIntegration();
787
+ // Hooks + skill = the complete agent setup, so one command does both:
788
+ // the lifecycle hooks (authoritative status) AND a fresh copy of the
789
+ // skill that tells the agent how to drive tmux-ide.
790
+ const { syncSkill } = await import("../packages/daemon/src/lib/skill-sync.ts");
791
+ const skill = syncSkill();
792
+ console.log(`hook script: ${scriptPath}`);
793
+ console.log(`settings: ${settingsPath} (backup written once as .tmux-ide.bak)`);
794
+ console.log(`skill: ${skill.action} → ${skill.path} (v${skill.to})`);
795
+ console.log(
796
+ "installed — NEW Claude Code sessions now report working/blocked/done " +
797
+ "authoritatively into the tmux-ide chrome.",
798
+ );
799
+ } else if (sub === "uninstall") {
800
+ const { wasInstalled } = mod.uninstallClaudeIntegration();
801
+ console.log(wasInstalled ? "uninstalled — hook entries removed" : "was not installed");
802
+ } else if (sub === "offer") {
803
+ // The one-time first-adopt prompt, run inside a `display-popup` by
804
+ // adoptSession (see ../packages/daemon/src/tui/integrations/offer.ts). It
805
+ // reads ONE key: `y` installs, anything else skips — and writes the
806
+ // marker either way so it never asks twice. Must never throw or hang.
807
+ const offerMod = await import("../packages/daemon/src/tui/integrations/offer.ts");
808
+ try {
809
+ console.log(offerMod.buildOfferText());
810
+ } catch {
811
+ console.log("Claude Code detected — install the tmux-ide integration? [y/N]");
812
+ }
813
+ const act = (key: string): void => {
814
+ offerMod.markIntegrationOffered();
815
+ if (key === "y" || key === "Y") {
816
+ try {
817
+ mod.installClaudeIntegration();
818
+ console.log("\ninstalled — new Claude Code sessions now report state to tmux-ide.");
819
+ } catch (e) {
820
+ console.log(`\ninstall failed: ${(e as Error).message}`);
821
+ }
822
+ } else {
823
+ console.log("\nskipped — run `tmux-ide integration install claude` anytime.");
824
+ }
825
+ };
826
+ // Test/automation hook: a forced key exits immediately, no stdin — lets
827
+ // the offer flow be exercised deterministically without a live keypress.
828
+ const forced = process.env.TMUX_IDE_OFFER_KEY;
829
+ if (forced !== undefined) {
830
+ act(forced);
831
+ process.exit(0);
832
+ }
833
+ const closeOffer = () => process.exit(0);
834
+ const offerTimer = setTimeout(closeOffer, 60_000);
835
+ offerTimer.unref?.();
836
+ try {
837
+ process.stdin.setRawMode?.(true);
838
+ process.stdin.resume();
839
+ process.stdin.once("data", (data) => {
840
+ act(data.toString());
841
+ console.log("\n[ press any key to close ]");
842
+ process.stdin.once("data", closeOffer);
843
+ process.stdin.once("end", closeOffer);
844
+ });
845
+ process.stdin.once("end", closeOffer);
846
+ } catch {
847
+ closeOffer();
848
+ }
849
+ } else {
850
+ // status — the discovery table: every known agent, whether it's on PATH,
851
+ // and (for agents we integrate) whether the integration is installed.
852
+ const { discoverAgents } = await import("../packages/daemon/src/lib/agent-discovery.ts");
853
+ const agents = discoverAgents();
854
+ if (json) {
855
+ console.log(JSON.stringify({ agents }, null, 2));
856
+ break;
857
+ }
858
+ for (const a of agents) {
859
+ let state: string;
860
+ if (a.path === null) state = "not found";
861
+ else if (a.integration)
862
+ state = a.installed ? "integration installed ✓" : "on PATH — integration not installed";
863
+ else state = "detected (no integration)";
864
+ console.log(` ${a.id.padEnd(10)} ${state}`);
865
+ }
451
866
  }
452
- await send(null, { json, to: target, message, noEnter: values["no-enter"] });
453
867
  break;
454
868
  }
455
869
 
456
- case "dispatch": {
457
- const { dispatch: dispatchCmd } = await import("../src/dispatch.ts");
458
- const taskId = positionals[1];
459
- await dispatchCmd(null, { taskId, json });
870
+ case "chrome-updater": {
871
+ // The background loop that keeps every adopted session's status var fresh.
872
+ // Hosted in the hidden `_tmux-ide-chrome` tmux session (started on adopt);
873
+ // blocks forever. Never let a boot error crash it — a dead updater just
874
+ // means stale bars, not broken sessions.
875
+ try {
876
+ const { runUpdaterLoop } = await import("../packages/daemon/src/tui/chrome/updater.ts");
877
+ runUpdaterLoop();
878
+ } catch {
879
+ process.exit(0);
880
+ }
460
881
  break;
461
882
  }
462
883
 
463
- case "notify": {
464
- const { notify: notifyCmd } = await import("../src/notify.ts");
465
- const notifyMessage = positionals.slice(1).join(" ");
466
- await notifyCmd(null, { message: notifyMessage || undefined, json });
884
+ case "cheatsheet": {
885
+ // Renders the static key cheat sheet, then blocks until ANY key closes it
886
+ // (the popup exits). Runs inside a tmux `display-popup` (bound to M-k on
887
+ // adopt / the `[ ? keys ]` bar trigger), so it must never throw — a broken
888
+ // render should still print something and still close on a keypress.
889
+ try {
890
+ const { buildCheatsheet } = await import("../packages/daemon/src/tui/chrome/cheatsheet.ts");
891
+ const { getAppConfig } = await import("../packages/daemon/src/lib/app-config.ts");
892
+ const cfg = getAppConfig();
893
+ console.log(
894
+ buildCheatsheet({
895
+ width: process.stdout.columns ?? 100,
896
+ keys: cfg.keys,
897
+ theme: cfg.theme,
898
+ }),
899
+ );
900
+ } catch {
901
+ console.log("tmux-ide — press ⌥p for the switcher, ⌥k for this sheet. Any key closes.");
902
+ }
903
+ // Wait for a single keypress, then exit 0 so the popup closes. Fall back to
904
+ // an auto-close after 60s if stdin never delivers (e.g. no raw mode).
905
+ const close = () => process.exit(0);
906
+ const timer = setTimeout(close, 60_000);
907
+ timer.unref?.();
908
+ try {
909
+ process.stdin.setRawMode?.(true);
910
+ process.stdin.resume();
911
+ process.stdin.once("data", close);
912
+ // A closed/redirected stdin (`</dev/null`, piped) hits EOF instead of
913
+ // ever delivering a key — close on that too so the command can't hang.
914
+ process.stdin.once("end", close);
915
+ } catch {
916
+ close();
917
+ }
467
918
  break;
468
919
  }
469
920
 
470
- case "orchestrator": {
471
- const { orchestratorStatus } = await import("../src/orchestrator-status.ts");
472
- await orchestratorStatus(positionals[1], { json });
921
+ case "welcome": {
922
+ // Prints the one-time first-run welcome card, then blocks until ANY key
923
+ // closes it (the popup exits). Floated by `adoptSession` via a
924
+ // `display-popup -E "tmux-ide welcome"` on first adopt (see
925
+ // ./chrome/welcome.ts). Mirrors the cheatsheet case — must never throw, and
926
+ // must close on a key / EOF / a 60s fallback so the popup can't hang.
927
+ try {
928
+ const { buildWelcomeText } = await import("../packages/daemon/src/tui/chrome/welcome.ts");
929
+ const { getAppConfig } = await import("../packages/daemon/src/lib/app-config.ts");
930
+ console.log(buildWelcomeText(getAppConfig().keys));
931
+ } catch {
932
+ console.log(
933
+ "Welcome to tmux-ide. Right-click for the menu · ⌥h home · ⌥p switch · ⌥k all keys.",
934
+ );
935
+ }
936
+ const closeWelcome = () => process.exit(0);
937
+ const welcomeTimer = setTimeout(closeWelcome, 60_000);
938
+ welcomeTimer.unref?.();
939
+ try {
940
+ process.stdin.setRawMode?.(true);
941
+ process.stdin.resume();
942
+ process.stdin.once("data", closeWelcome);
943
+ process.stdin.once("end", closeWelcome);
944
+ } catch {
945
+ closeWelcome();
946
+ }
473
947
  break;
474
948
  }
475
949
 
476
- case "settings": {
477
- const scriptPath = resolve(__dirname, "../src/widgets/config/index.tsx");
478
- execFileSync("bun", [scriptPath, "--dir=" + resolve(startTargetDir || ".")], {
479
- stdio: "inherit",
480
- });
950
+ case "menu": {
951
+ // Build the native tmux actions menu at CLICK TIME (the session list is
952
+ // live) and display it on the invoking client. Bound via `run-shell -b` so
953
+ // `#{client_name}` format-expands into `--client` (verified live on tmux
954
+ // 3.6 — it resolves to the triggering / most-recently-active client). Runs
955
+ // inside tmux's key/mouse dispatch, so it must never throw or HANG — every
956
+ // tmux call below is capped at 2s and a missing client degrades to a no-op.
957
+ try {
958
+ // Every tmux shell-out gets a hard 2s cap: the old fallback
959
+ // (`display-message -p '#{client_name}'` from outside a client) could
960
+ // block indefinitely and wedge the bind. `timeout` throws on expiry,
961
+ // caught below → silent no-op.
962
+ const tmuxCap = {
963
+ encoding: "utf8" as const,
964
+ stdio: ["ignore", "pipe", "ignore"] as const,
965
+ timeout: 2000,
966
+ };
967
+ // Resolve the target client. Prefer the `--client` the bind expanded; if
968
+ // it's empty or an unexpanded `#{…}` literal, fall back to the
969
+ // most-recently-active attached client (list-clients sorted by
970
+ // client_activity desc). No clients at all → exit 0 silently (fired from
971
+ // tmux dispatch, a no-op beats an error).
972
+ const rawClient = typeof values.client === "string" ? values.client : "";
973
+ let client = rawClient && !rawClient.includes("#{") ? rawClient : "";
974
+ if (!client) {
975
+ const raw = execFileSync(
976
+ "tmux",
977
+ ["list-clients", "-F", "#{client_activity} #{client_name}"],
978
+ tmuxCap,
979
+ ).trim();
980
+ const newest = raw
981
+ .split("\n")
982
+ .filter(Boolean)
983
+ .map((line) => {
984
+ const sp = line.indexOf(" ");
985
+ return { activity: Number(line.slice(0, sp)), name: line.slice(sp + 1) };
986
+ })
987
+ .sort((a, b) => b.activity - a.activity)[0];
988
+ client = newest?.name ?? "";
989
+ }
990
+ if (!client) break; // no attached clients — nothing to show
991
+ const { createStatusTracker } =
992
+ await import("../packages/daemon/src/tui/detect/classify.ts");
993
+ const { listTeamSessions } = await import("../packages/daemon/src/tui/team/sessions.ts");
994
+ const { buildMenu, menuPositionArgs } =
995
+ await import("../packages/daemon/src/tui/chrome/menu.ts");
996
+ const { getAppConfig } = await import("../packages/daemon/src/lib/app-config.ts");
997
+ const { getUpdateStatus } = await import("../packages/daemon/src/lib/update-check.ts");
998
+ // listTeamSessions already drops internal `_`-prefixed plumbing.
999
+ const sessions = listTeamSessions(createStatusTracker()).map((s) => ({
1000
+ name: s.name,
1001
+ status: s.status,
1002
+ }));
1003
+ // Position flags from a mouse bind's forwarded coords; empty (→ centered)
1004
+ // for the keyboard path or unexpanded #{mouse_*} literals. Must precede
1005
+ // the menu spec (buildMenu opens with -T), so they slot in right after -c.
1006
+ const position = menuPositionArgs(
1007
+ typeof values.x === "string" ? values.x : undefined,
1008
+ typeof values.y === "string" ? values.y : undefined,
1009
+ );
1010
+ const args = [
1011
+ "display-menu",
1012
+ "-c",
1013
+ client,
1014
+ ...position,
1015
+ ...buildMenu(sessions, getAppConfig().theme, getUpdateStatus()),
1016
+ ];
1017
+ execFileSync("tmux", args, { stdio: "ignore", timeout: 2000 });
1018
+ } catch {
1019
+ // no client / tmux unavailable / a call timed out — nothing to show
1020
+ }
481
1021
  break;
482
1022
  }
483
1023
 
484
- case "tunnel": {
485
- const { tunnelCommand } = await import("../src/tunnel.ts");
486
- await tunnelCommand(null, {
487
- json,
488
- sub: positionals[1],
489
- args: positionals.slice(2),
490
- values: {
491
- provider: values.provider,
492
- port: values.port,
493
- domain: values.domain,
494
- authtoken: values.authtoken,
495
- },
496
- });
1024
+ case "popup": {
1025
+ // Open a widget as a floating panel. This CLI invocation IS the popup
1026
+ // process (a root-table key or a menu row ran `display-popup -E "tmux-ide
1027
+ // popup <widget>"`), so we exec the bun widget SYNCHRONOUSLY into the
1028
+ // popup's PTY; when the widget exits (esc/q) the popup closes.
1029
+ const { POPUP_WIDGETS } = await import("../packages/daemon/src/tui/chrome/panels.ts");
1030
+ const widget = positionals[1];
1031
+ if (!widget || !POPUP_WIDGETS.includes(widget)) {
1032
+ throw new IdeError(
1033
+ `Usage: tmux-ide popup <widget>\nKnown panels: ${POPUP_WIDGETS.join(", ")}.`,
1034
+ { code: "USAGE", exitCode: 1 },
1035
+ );
1036
+ }
1037
+ // Resolve the widget entry from THIS file's dir (bin/), mirroring the
1038
+ // setup/config cases — the bundler rewrites `import.meta.url` to the bin/
1039
+ // bundle, so a `resolve.ts`-relative path would miss the sources.
1040
+ const scriptPath = resolve(__dirname, "../packages/daemon/src/widgets", widget, "index.tsx");
1041
+ // The popup opened with `-d '#{pane_current_path}'`, so our cwd IS the
1042
+ // pane's project dir — forward it as `--dir`. Resolve the session so the
1043
+ // widget's tmux side-channels (preview file, "send to claude") target it;
1044
+ // best-effort — an empty session just disables those (the widget still
1045
+ // renders and browses).
1046
+ let popupSession = "";
1047
+ try {
1048
+ popupSession = execFileSync("tmux", ["display-message", "-p", "#{session_name}"], {
1049
+ encoding: "utf8",
1050
+ stdio: ["ignore", "pipe", "ignore"],
1051
+ timeout: 2000,
1052
+ }).trim();
1053
+ } catch {
1054
+ // not inside a tmux client — leave session empty
1055
+ }
1056
+ const popupArgs = [`--dir=${process.cwd()}`];
1057
+ if (popupSession) popupArgs.push(`--session=${popupSession}`);
1058
+ execBunWidget(widget, scriptPath, popupArgs, `popup ${widget}`);
497
1059
  break;
498
1060
  }
499
1061
 
500
- case "remote": {
501
- const { remoteCommand } = await import("../src/remote.ts");
502
- await remoteCommand(null, {
503
- json,
504
- sub: positionals[1],
505
- args: positionals.slice(2),
506
- values: {
507
- url: values.url,
508
- "hq-url": values["hq-url"],
509
- },
1062
+ case "sidebar-toggle": {
1063
+ // Toggle the app nav column in a session (bound to `keys.sidebar`, default
1064
+ // M-b, via `run-shell` which expands `--session '#{session_name}'`). If a
1065
+ // sidebar pane already exists → close it; else split a full-height left
1066
+ // column running the sidebar widget. Runs inside tmux key dispatch, so it
1067
+ // stays best-effort — a failure is a silent no-op, never a wedged bind.
1068
+ try {
1069
+ const {
1070
+ findSidebarPane,
1071
+ openSidebarPane,
1072
+ closeSidebarPane,
1073
+ resolveSidebarConfig,
1074
+ DEFAULT_SIDEBAR_WIDTH,
1075
+ } = await import("../packages/daemon/src/tui/chrome/sidebar.ts");
1076
+ // Resolve the target session: the explicit --session, else the invoking
1077
+ // client's session via display-message.
1078
+ let session = typeof values.session === "string" ? values.session.trim() : "";
1079
+ if (!session || session.includes("#{")) {
1080
+ try {
1081
+ session = execFileSync("tmux", ["display-message", "-p", "#{session_name}"], {
1082
+ encoding: "utf8",
1083
+ stdio: ["ignore", "pipe", "ignore"],
1084
+ timeout: 2000,
1085
+ }).trim();
1086
+ } catch {
1087
+ session = "";
1088
+ }
1089
+ }
1090
+ if (!session) break; // no session context — nothing to toggle
1091
+ const existing = findSidebarPane(session);
1092
+ if (existing) {
1093
+ closeSidebarPane(existing);
1094
+ break;
1095
+ }
1096
+ // Opening: resolve the session's cwd + best-effort sidebar width/theme
1097
+ // from an ide.yml there (any adopted session may have none → defaults).
1098
+ const { getSessionCwd } = await import("../packages/tmux-bridge/src/index.ts");
1099
+ let dir = process.cwd();
1100
+ try {
1101
+ dir = getSessionCwd(session) ?? dir;
1102
+ } catch {
1103
+ // no cwd — fall back to the CLI's cwd
1104
+ }
1105
+ let width = DEFAULT_SIDEBAR_WIDTH;
1106
+ let theme = null;
1107
+ try {
1108
+ const { readConfig } = await import("../packages/daemon/src/lib/yaml-io.ts");
1109
+ const { config } = readConfig(dir);
1110
+ theme = config.theme ?? null;
1111
+ const sb = resolveSidebarConfig(config.sidebar);
1112
+ if (sb.enabled) width = sb.width;
1113
+ } catch {
1114
+ // no/invalid ide.yml — defaults are fine
1115
+ }
1116
+ openSidebarPane(session, dir, width, theme);
1117
+ } catch {
1118
+ // tmux unavailable / widget missing — silent no-op (fired from a bind)
1119
+ }
1120
+ break;
1121
+ }
1122
+
1123
+ case "worktree": {
1124
+ const sub = positionals[1];
1125
+ const KNOWN_SUBS = new Set(["create", "open", "list", "remove"]);
1126
+ if (!sub || !KNOWN_SUBS.has(sub)) {
1127
+ throw new IdeError(
1128
+ "Usage: tmux-ide worktree <create|open|list|remove> <branch> [flags]\n" +
1129
+ " create <branch> [--from <ref>] [--dir <path>] [--no-session]\n" +
1130
+ " open <branch>\n" +
1131
+ " list [--json]\n" +
1132
+ " remove <branch> [--force]",
1133
+ { code: "USAGE", exitCode: 1 },
1134
+ );
1135
+ }
1136
+
1137
+ const {
1138
+ worktreeSessionName,
1139
+ worktreePath,
1140
+ listWorktrees,
1141
+ createWorktree,
1142
+ removeWorktree,
1143
+ WorktreeError,
1144
+ } = await import("../packages/daemon/src/lib/worktree.ts");
1145
+ const { getSessionName } = await import("../packages/daemon/src/lib/yaml-io.ts");
1146
+ const { getSessionCwd, hasSession, killSession, createDetachedSession } =
1147
+ await import("../packages/tmux-bridge/src/index.ts");
1148
+
1149
+ // The repo the command targets: the --session's cwd when invoked from the
1150
+ // menu (run-shell's own cwd is the tmux server's, not the pane's — verified
1151
+ // live), else the CLI's cwd.
1152
+ let repoDir = process.cwd();
1153
+ const sessionArg = typeof values.session === "string" ? values.session.trim() : "";
1154
+ if (sessionArg && !sessionArg.includes("#{")) {
1155
+ try {
1156
+ const cwd = getSessionCwd(sessionArg);
1157
+ if (cwd) repoDir = cwd;
1158
+ } catch {
1159
+ // fall back to the CLI cwd
1160
+ }
1161
+ }
1162
+
1163
+ // The project identity for session names: the MAIN worktree's ide.yml name
1164
+ // (or its dir basename). `git worktree list` returns the main checkout first.
1165
+ const worktrees = listWorktrees(repoDir);
1166
+ const mainPath = worktrees[0]?.path ?? repoDir;
1167
+ const projectName = getSessionName(mainPath).name;
1168
+
1169
+ // Start a session in a worktree checkout: full IDE layout when it has an
1170
+ // ide.yml (launch under the worktree's own session name so it never
1171
+ // collides with the parent repo's session), else a plain adopted session.
1172
+ // Never auto-attaches — the caller may be inside tmux (the menu) — it prints
1173
+ // how to switch instead.
1174
+ async function openWorktreeSession(wtPath: string, name: string): Promise<void> {
1175
+ if (existsSync(join(wtPath, "ide.yml"))) {
1176
+ await launch(wtPath, { attach: false, sessionName: name });
1177
+ } else {
1178
+ if (!hasSession(name)) createDetachedSession(name, wtPath);
1179
+ const { adoptSession } = await import("../packages/daemon/src/tui/chrome/statusline.ts");
1180
+ adoptSession(name);
1181
+ }
1182
+ }
1183
+
1184
+ function printSwitchHint(name: string, wtPath: string): void {
1185
+ console.log(`Worktree ready: ${wtPath}`);
1186
+ console.log(`Session: ${name}`);
1187
+ if (process.env.TMUX) {
1188
+ console.log(`Switch to it: tmux switch-client -t '${name}'`);
1189
+ } else {
1190
+ console.log(`Attach to it: tmux attach -t '${name}'`);
1191
+ }
1192
+ }
1193
+
1194
+ if (sub === "create") {
1195
+ const branch = positionals[2];
1196
+ if (!branch) {
1197
+ throw new IdeError(
1198
+ "Usage: tmux-ide worktree create <branch> [--from <ref>] [--dir <path>] [--no-session]",
1199
+ { code: "USAGE", exitCode: 1 },
1200
+ );
1201
+ }
1202
+ const { getAppConfig } = await import("../packages/daemon/src/lib/app-config.ts");
1203
+ const dirOverride =
1204
+ typeof values.dir === "string" && values.dir.length > 0
1205
+ ? values.dir
1206
+ : getAppConfig().worktrees.dir || null;
1207
+ const wtPath = worktreePath(repoDir, branch, dirOverride);
1208
+ const from = typeof values.from === "string" ? values.from : null;
1209
+
1210
+ // Default: create a NEW branch off `from` (HEAD when absent). If the
1211
+ // branch already exists and no explicit base was given, fall back to
1212
+ // checking it out into the worktree instead of failing.
1213
+ try {
1214
+ createWorktree(repoDir, branch, wtPath, { newBranch: true, from });
1215
+ } catch (err) {
1216
+ if (err instanceof WorktreeError && err.code === "BRANCH_EXISTS" && !from) {
1217
+ createWorktree(repoDir, branch, wtPath, { newBranch: false });
1218
+ } else {
1219
+ throw err;
1220
+ }
1221
+ }
1222
+
1223
+ const sessionName = worktreeSessionName(projectName, branch);
1224
+ if (!values["no-session"]) {
1225
+ await openWorktreeSession(wtPath, sessionName);
1226
+ }
1227
+
1228
+ if (json) {
1229
+ console.log(
1230
+ JSON.stringify({
1231
+ branch,
1232
+ path: wtPath,
1233
+ session: values["no-session"] ? null : sessionName,
1234
+ }),
1235
+ );
1236
+ } else if (values["no-session"]) {
1237
+ console.log(`Worktree ready: ${wtPath}`);
1238
+ console.log(`Open a session later: tmux-ide worktree open '${branch}'`);
1239
+ } else {
1240
+ printSwitchHint(sessionName, wtPath);
1241
+ }
1242
+ break;
1243
+ }
1244
+
1245
+ if (sub === "open") {
1246
+ const branch = positionals[2];
1247
+ if (!branch) {
1248
+ throw new IdeError("Usage: tmux-ide worktree open <branch>", {
1249
+ code: "USAGE",
1250
+ exitCode: 1,
1251
+ });
1252
+ }
1253
+ const entry = worktrees.find((w) => w.branch === branch);
1254
+ if (!entry) {
1255
+ throw new IdeError(
1256
+ `No worktree for branch "${branch}". Create one with: tmux-ide worktree create '${branch}'`,
1257
+ { code: "USAGE", exitCode: 1 },
1258
+ );
1259
+ }
1260
+ const sessionName = worktreeSessionName(projectName, branch);
1261
+ const already = hasSession(sessionName);
1262
+ if (!already) await openWorktreeSession(entry.path, sessionName);
1263
+ if (json) {
1264
+ console.log(
1265
+ JSON.stringify({ branch, path: entry.path, session: sessionName, created: !already }),
1266
+ );
1267
+ } else {
1268
+ if (already) console.log(`Session already running.`);
1269
+ printSwitchHint(sessionName, entry.path);
1270
+ }
1271
+ break;
1272
+ }
1273
+
1274
+ if (sub === "remove") {
1275
+ const branch = positionals[2];
1276
+ if (!branch) {
1277
+ throw new IdeError("Usage: tmux-ide worktree remove <branch> [--force]", {
1278
+ code: "USAGE",
1279
+ exitCode: 1,
1280
+ });
1281
+ }
1282
+ const entry = worktrees.find((w) => w.branch === branch);
1283
+ if (!entry) {
1284
+ throw new IdeError(`No worktree for branch "${branch}".`, {
1285
+ code: "USAGE",
1286
+ exitCode: 1,
1287
+ });
1288
+ }
1289
+ // Remove the worktree FIRST so a failed removal (e.g. dirty without
1290
+ // --force, which throws here) never orphan-kills the still-usable
1291
+ // session. Only after a clean removal do we kill ONLY this worktree's
1292
+ // own session (never the parent repo's or a user session — the name is
1293
+ // fully derived from the worktree's branch).
1294
+ removeWorktree(repoDir, entry.path, { force: values.force === true });
1295
+ const sessionName = worktreeSessionName(projectName, branch);
1296
+ const killed = hasSession(sessionName) ? killSession(sessionName).stopped : false;
1297
+ if (json) {
1298
+ console.log(
1299
+ JSON.stringify({ branch, path: entry.path, sessionKilled: killed, removed: true }),
1300
+ );
1301
+ } else {
1302
+ console.log(`Removed worktree ${entry.path}${killed ? ` (killed ${sessionName})` : ""}.`);
1303
+ }
1304
+ break;
1305
+ }
1306
+
1307
+ // sub === "list"
1308
+ const { createStatusTracker } = await import("../packages/daemon/src/tui/detect/classify.ts");
1309
+ const { listTeamSessions } = await import("../packages/daemon/src/tui/team/sessions.ts");
1310
+ const sessions = listTeamSessions(createStatusTracker());
1311
+ const rows = worktrees.map((wt) => {
1312
+ const isPrimary = wt.path === mainPath;
1313
+ const candidates: string[] = [];
1314
+ if (isPrimary) candidates.push(projectName);
1315
+ if (wt.branch) candidates.push(worktreeSessionName(projectName, wt.branch));
1316
+ const match = sessions.find((s) => candidates.includes(s.name)) ?? null;
1317
+ return {
1318
+ path: wt.path,
1319
+ branch: wt.branch,
1320
+ primary: isPrimary,
1321
+ session: match?.name ?? null,
1322
+ running: match !== null,
1323
+ status: match?.status ?? null,
1324
+ };
510
1325
  });
1326
+ if (json) {
1327
+ console.log(JSON.stringify({ repo: mainPath, worktrees: rows }, null, 2));
1328
+ } else if (rows.length === 0) {
1329
+ console.log("No worktrees.");
1330
+ } else {
1331
+ for (const r of rows) {
1332
+ const tag = r.primary ? " (primary)" : "";
1333
+ const state = r.running ? `${r.status} · ${r.session}` : "no session";
1334
+ console.log(`${r.branch ?? "(detached)"}${tag} ${state}\n ${r.path}`);
1335
+ }
1336
+ }
1337
+ break;
1338
+ }
1339
+
1340
+ case "update": {
1341
+ // Detect how tmux-ide was installed and act on the pending update: a dev
1342
+ // checkout prints the `git pull` hint; a global install prints (with
1343
+ // --dry-run) or runs its package manager's update command. `__dirname` is
1344
+ // this CLI's own directory — the anchor for the git-checkout probe + the
1345
+ // package-manager path heuristic (see lib/update.ts).
1346
+ const { runUpdate } = await import("../packages/daemon/src/lib/update.ts");
1347
+ const dryRun = values["dry-run"] === true;
1348
+ const plan = runUpdate({ cliDir: __dirname, dryRun });
1349
+ if (!dryRun) {
1350
+ // The managed skill copy has to track the CLI. A global install refreshes
1351
+ // it via the package's own postinstall (which just ran); a dev checkout
1352
+ // has no postinstall, so `tmux-ide update` IS the checkout's refresh path
1353
+ // — sync the skill directly here.
1354
+ const { syncSkill } = await import("../packages/daemon/src/lib/skill-sync.ts");
1355
+ if (plan.method === "dev") {
1356
+ const result = syncSkill();
1357
+ console.log("");
1358
+ console.log(`skill: ${result.action} → ${result.path} (v${result.to})`);
1359
+ } else {
1360
+ console.log("");
1361
+ console.log("skill: refreshed by the package postinstall (~/.claude/skills/tmux-ide)");
1362
+ }
1363
+ }
1364
+ break;
1365
+ }
1366
+
1367
+ case "skill-sync": {
1368
+ // The universal manual refresh of the managed Claude Code skill copy.
1369
+ // Fully-managed dir: overwrite is correct; version-equal is a no-op.
1370
+ const { syncSkill } = await import("../packages/daemon/src/lib/skill-sync.ts");
1371
+ const result = syncSkill();
1372
+ if (json) {
1373
+ console.log(JSON.stringify(result, null, 2));
1374
+ } else {
1375
+ const detail =
1376
+ result.action === "updated" && result.from
1377
+ ? ` (v${result.from} → v${result.to})`
1378
+ : ` (v${result.to})`;
1379
+ console.log(`skill ${result.action}${detail}: ${result.path}`);
1380
+ }
511
1381
  break;
512
1382
  }
513
1383
 
514
1384
  case "command-center": {
515
- const { startCommandCenter } = await import("../src/command-center/index.ts");
1385
+ const { startCommandCenter } = await import("../packages/daemon/src/command-center/index.ts");
516
1386
  await startCommandCenter({ port: parseInt(values.port ?? "4000") });
517
1387
  break;
518
1388
  }
519
1389
 
1390
+ case "server": {
1391
+ if ("bun" in process.versions) {
1392
+ const scriptPath = resolve(__dirname, "../packages/daemon/src/server/standalone.ts");
1393
+ const serverArgs = ["--experimental-strip-types", scriptPath];
1394
+ if (values.port) serverArgs.push("--port", values.port);
1395
+ execFileSync("node", serverArgs, { stdio: "inherit" });
1396
+ } else {
1397
+ const { start } = await import("../packages/daemon/src/server/index.ts");
1398
+ await start(values.port ? parseInt(values.port, 10) : undefined);
1399
+ }
1400
+ break;
1401
+ }
1402
+
520
1403
  case "help":
521
1404
  printHelp();
522
1405
  break;