tmux-ide 2.1.4 → 2.6.0
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.
- package/README.md +115 -101
- package/bin/cli.js +13678 -4
- package/bin/cli.ts +1143 -260
- package/package.json +27 -17
- package/packages/daemon/dist/__tests__/support.d.ts +7 -0
- package/packages/daemon/dist/__tests__/support.js +33 -0
- package/packages/daemon/dist/agent-explain.d.ts +45 -0
- package/packages/daemon/dist/agent-explain.js +210 -0
- package/packages/daemon/dist/attach.d.ts +3 -0
- package/packages/daemon/dist/attach.js +14 -0
- package/packages/daemon/dist/bin.d.ts +2 -0
- package/packages/daemon/dist/bin.js +3 -0
- package/packages/daemon/dist/canonical.d.ts +2 -0
- package/packages/daemon/dist/canonical.js +1 -0
- package/packages/daemon/dist/cli.d.ts +1 -0
- package/packages/daemon/dist/cli.js +425 -0
- package/packages/daemon/dist/command-center/actions/contract.d.ts +1 -0
- package/packages/daemon/dist/command-center/actions/contract.js +2 -0
- package/packages/daemon/dist/command-center/actions/dispatcher.d.ts +27 -0
- package/packages/daemon/dist/command-center/actions/dispatcher.js +109 -0
- package/packages/daemon/dist/command-center/actions/errors.d.ts +38 -0
- package/packages/daemon/dist/command-center/actions/errors.js +56 -0
- package/packages/daemon/dist/command-center/actions/handlers/_project-context.d.ts +12 -0
- package/packages/daemon/dist/command-center/actions/handlers/_project-context.js +12 -0
- package/packages/daemon/dist/command-center/actions/handlers/_resolve-project.d.ts +42 -0
- package/packages/daemon/dist/command-center/actions/handlers/_resolve-project.js +48 -0
- package/packages/daemon/dist/command-center/actions/handlers/app-set-remote-access.d.ts +23 -0
- package/packages/daemon/dist/command-center/actions/handlers/app-set-remote-access.js +67 -0
- package/packages/daemon/dist/command-center/actions/handlers/config-actions.d.ts +12 -0
- package/packages/daemon/dist/command-center/actions/handlers/config-actions.js +69 -0
- package/packages/daemon/dist/command-center/actions/handlers/daemon-shutdown.d.ts +6 -0
- package/packages/daemon/dist/command-center/actions/handlers/daemon-shutdown.js +24 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-activate.d.ts +7 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-activate.js +19 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-launch.d.ts +18 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-launch.js +58 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-open-terminal.d.ts +32 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-open-terminal.js +69 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-restart.d.ts +17 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-restart.js +27 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-stop.d.ts +24 -0
- package/packages/daemon/dist/command-center/actions/handlers/project-stop.js +38 -0
- package/packages/daemon/dist/command-center/actions/handlers/terminal-respawn.d.ts +24 -0
- package/packages/daemon/dist/command-center/actions/handlers/terminal-respawn.js +88 -0
- package/packages/daemon/dist/command-center/actions/handlers/terminal-stop.d.ts +14 -0
- package/packages/daemon/dist/command-center/actions/handlers/terminal-stop.js +22 -0
- package/packages/daemon/dist/command-center/actions/registry.d.ts +35 -0
- package/packages/daemon/dist/command-center/actions/registry.js +109 -0
- package/packages/daemon/dist/command-center/discovery.d.ts +23 -0
- package/packages/daemon/dist/command-center/discovery.js +67 -0
- package/packages/daemon/dist/command-center/index.d.ts +10 -0
- package/packages/daemon/dist/command-center/index.js +21 -0
- package/packages/daemon/dist/command-center/schemas.d.ts +76 -0
- package/packages/daemon/dist/command-center/schemas.js +68 -0
- package/packages/daemon/dist/command-center/server.d.ts +26 -0
- package/packages/daemon/dist/command-center/server.js +1103 -0
- package/packages/daemon/dist/command-center/ws-events.d.ts +59 -0
- package/packages/daemon/dist/command-center/ws-events.js +277 -0
- package/packages/daemon/dist/config.d.ts +19 -0
- package/packages/daemon/dist/config.js +494 -0
- package/packages/daemon/dist/detect.d.ts +15 -0
- package/packages/daemon/dist/detect.js +228 -0
- package/packages/daemon/dist/doctor.d.ts +21 -0
- package/packages/daemon/dist/doctor.js +154 -0
- package/packages/daemon/dist/embed.d.ts +1 -0
- package/packages/daemon/dist/embed.js +1 -0
- package/packages/daemon/dist/index.d.ts +3 -0
- package/packages/daemon/dist/index.js +2 -0
- package/packages/daemon/dist/init.d.ts +4 -0
- package/packages/daemon/dist/init.js +174 -0
- package/packages/daemon/dist/inspect.d.ts +54 -0
- package/packages/daemon/dist/inspect.js +118 -0
- package/packages/daemon/dist/launch.d.ts +23 -0
- package/packages/daemon/dist/launch.js +250 -0
- package/packages/daemon/dist/lib/active-projects.d.ts +12 -0
- package/packages/daemon/dist/lib/active-projects.js +35 -0
- package/packages/daemon/dist/lib/agent-discovery.d.ts +43 -0
- package/packages/daemon/dist/lib/agent-discovery.js +85 -0
- package/packages/daemon/dist/lib/app-config.d.ts +147 -0
- package/packages/daemon/dist/lib/app-config.js +191 -0
- package/packages/daemon/dist/lib/app-settings.d.ts +9 -0
- package/packages/daemon/dist/lib/app-settings.js +44 -0
- package/packages/daemon/dist/lib/auth/auth-service.d.ts +33 -0
- package/packages/daemon/dist/lib/auth/auth-service.js +172 -0
- package/packages/daemon/dist/lib/auth/middleware.d.ts +16 -0
- package/packages/daemon/dist/lib/auth/middleware.js +43 -0
- package/packages/daemon/dist/lib/auth/types.d.ts +1 -0
- package/packages/daemon/dist/lib/auth/types.js +2 -0
- package/packages/daemon/dist/lib/auth-token.d.ts +1 -0
- package/packages/daemon/dist/lib/auth-token.js +4 -0
- package/packages/daemon/dist/lib/authorship.d.ts +62 -0
- package/packages/daemon/dist/lib/authorship.js +209 -0
- package/packages/daemon/dist/lib/canonical-daemon.d.ts +21 -0
- package/packages/daemon/dist/lib/canonical-daemon.js +111 -0
- package/packages/daemon/dist/lib/cli-action-bridge.d.ts +27 -0
- package/packages/daemon/dist/lib/cli-action-bridge.js +161 -0
- package/packages/daemon/dist/lib/daemon-embed.d.ts +31 -0
- package/packages/daemon/dist/lib/daemon-embed.js +643 -0
- package/packages/daemon/dist/lib/daemon-watchdog.d.ts +16 -0
- package/packages/daemon/dist/lib/daemon-watchdog.js +98 -0
- package/packages/daemon/dist/lib/daemon.d.ts +8 -0
- package/packages/daemon/dist/lib/daemon.js +79 -0
- package/packages/daemon/dist/lib/dot-path.d.ts +2 -0
- package/packages/daemon/dist/lib/dot-path.js +17 -0
- package/packages/daemon/dist/lib/errors.d.ts +37 -0
- package/packages/daemon/dist/lib/errors.js +50 -0
- package/packages/daemon/dist/lib/filesystem-browser.d.ts +85 -0
- package/packages/daemon/dist/lib/filesystem-browser.js +257 -0
- package/packages/daemon/dist/lib/launch-plan.d.ts +6 -0
- package/packages/daemon/dist/lib/launch-plan.js +76 -0
- package/packages/daemon/dist/lib/log.d.ts +40 -0
- package/packages/daemon/dist/lib/log.js +86 -0
- package/packages/daemon/dist/lib/output.d.ts +9 -0
- package/packages/daemon/dist/lib/output.js +65 -0
- package/packages/daemon/dist/lib/project-init-runner.d.ts +46 -0
- package/packages/daemon/dist/lib/project-init-runner.js +117 -0
- package/packages/daemon/dist/lib/project-inspect.d.ts +28 -0
- package/packages/daemon/dist/lib/project-inspect.js +67 -0
- package/packages/daemon/dist/lib/project-onboard.d.ts +58 -0
- package/packages/daemon/dist/lib/project-onboard.js +108 -0
- package/packages/daemon/dist/lib/project-probe.d.ts +35 -0
- package/packages/daemon/dist/lib/project-probe.js +61 -0
- package/packages/daemon/dist/lib/project-registry.d.ts +76 -0
- package/packages/daemon/dist/lib/project-registry.js +230 -0
- package/packages/daemon/dist/lib/session-monitor.d.ts +15 -0
- package/packages/daemon/dist/lib/session-monitor.js +103 -0
- package/packages/daemon/dist/lib/session-options.d.ts +13 -0
- package/packages/daemon/dist/lib/session-options.js +85 -0
- package/packages/daemon/dist/lib/shell.d.ts +5 -0
- package/{src/lib/shell.ts → packages/daemon/dist/lib/shell.js} +3 -3
- package/packages/daemon/dist/lib/sizes.d.ts +16 -0
- package/packages/daemon/dist/lib/sizes.js +36 -0
- package/packages/daemon/dist/lib/skill-sync.d.ts +60 -0
- package/packages/daemon/dist/lib/skill-sync.js +128 -0
- package/packages/daemon/dist/lib/slugify.d.ts +4 -0
- package/packages/daemon/dist/lib/slugify.js +10 -0
- package/packages/daemon/dist/lib/terminals-store.d.ts +27 -0
- package/packages/daemon/dist/lib/terminals-store.js +111 -0
- package/packages/daemon/dist/lib/update-check.d.ts +118 -0
- package/packages/daemon/dist/lib/update-check.js +261 -0
- package/packages/daemon/dist/lib/update.d.ts +65 -0
- package/packages/daemon/dist/lib/update.js +141 -0
- package/packages/daemon/dist/lib/workspace-registry.d.ts +84 -0
- package/packages/daemon/dist/lib/workspace-registry.js +176 -0
- package/packages/daemon/dist/lib/worktree.d.ts +76 -0
- package/packages/daemon/dist/lib/worktree.js +207 -0
- package/packages/daemon/dist/lib/yaml-io.d.ts +10 -0
- package/packages/daemon/dist/lib/yaml-io.js +24 -0
- package/packages/daemon/dist/ls.d.ts +3 -0
- package/packages/daemon/dist/ls.js +35 -0
- package/packages/daemon/dist/restart.d.ts +4 -0
- package/packages/daemon/dist/restart.js +16 -0
- package/packages/daemon/dist/restore.d.ts +86 -0
- package/packages/daemon/dist/restore.js +406 -0
- package/packages/daemon/dist/schemas/domain.d.ts +1 -0
- package/packages/daemon/dist/schemas/domain.js +2 -0
- package/packages/daemon/dist/schemas/filesystem.d.ts +29 -0
- package/packages/daemon/dist/schemas/filesystem.js +29 -0
- package/packages/daemon/dist/schemas/ide-config.d.ts +1 -0
- package/packages/daemon/dist/schemas/ide-config.js +2 -0
- package/packages/daemon/dist/schemas/index.d.ts +12 -0
- package/packages/daemon/dist/schemas/index.js +6 -0
- package/packages/daemon/dist/schemas/inspect.d.ts +53 -0
- package/packages/daemon/dist/schemas/inspect.js +57 -0
- package/packages/daemon/dist/schemas/registry.d.ts +35 -0
- package/packages/daemon/dist/schemas/registry.js +43 -0
- package/packages/daemon/dist/schemas/ws-events.d.ts +72 -0
- package/packages/daemon/dist/schemas/ws-events.js +110 -0
- package/packages/daemon/dist/send.d.ts +27 -0
- package/packages/daemon/dist/send.js +141 -0
- package/packages/daemon/dist/server/index.d.ts +10 -0
- package/packages/daemon/dist/server/index.js +55 -0
- package/packages/daemon/dist/server/pty-bridge.d.ts +174 -0
- package/packages/daemon/dist/server/pty-bridge.js +422 -0
- package/packages/daemon/dist/server/standalone.d.ts +1 -0
- package/packages/daemon/dist/server/standalone.js +14 -0
- package/packages/daemon/dist/server/ws-route.d.ts +74 -0
- package/packages/daemon/dist/server/ws-route.js +379 -0
- package/packages/daemon/dist/status.d.ts +3 -0
- package/packages/daemon/dist/status.js +46 -0
- package/packages/daemon/dist/stop.d.ts +3 -0
- package/packages/daemon/dist/stop.js +21 -0
- package/packages/daemon/dist/terminal/NodePtyAdapter.d.ts +44 -0
- package/packages/daemon/dist/terminal/NodePtyAdapter.js +253 -0
- package/packages/daemon/dist/terminal/PtyAdapter.d.ts +124 -0
- package/packages/daemon/dist/terminal/PtyAdapter.js +43 -0
- package/packages/daemon/dist/terminal/__tests__/MockPtyAdapter.d.ts +77 -0
- package/packages/daemon/dist/terminal/__tests__/MockPtyAdapter.js +155 -0
- package/packages/daemon/dist/types.d.ts +2 -0
- package/packages/daemon/dist/types.js +1 -0
- package/packages/daemon/dist/validate.d.ts +4 -0
- package/packages/daemon/dist/validate.js +184 -0
- package/packages/daemon/dist/widgets/changes/index.d.ts +1 -0
- package/packages/daemon/dist/widgets/changes/index.jsx +575 -0
- package/packages/daemon/dist/widgets/config/index.d.ts +1 -0
- package/packages/daemon/dist/widgets/config/index.jsx +395 -0
- package/packages/daemon/dist/widgets/explorer/breadcrumbs.d.ts +10 -0
- package/packages/daemon/dist/widgets/explorer/breadcrumbs.jsx +51 -0
- package/packages/daemon/dist/widgets/explorer/footer.d.ts +6 -0
- package/packages/daemon/dist/widgets/explorer/footer.jsx +11 -0
- package/packages/daemon/dist/widgets/explorer/index.d.ts +1 -0
- package/packages/daemon/dist/widgets/explorer/index.jsx +393 -0
- package/packages/daemon/dist/widgets/explorer/tree-model.d.ts +13 -0
- package/packages/daemon/dist/widgets/explorer/tree-model.js +69 -0
- package/packages/daemon/dist/widgets/explorer/tree.d.ts +13 -0
- package/packages/daemon/dist/widgets/explorer/tree.jsx +108 -0
- package/packages/daemon/dist/widgets/lib/config-model.d.ts +22 -0
- package/packages/daemon/dist/widgets/lib/config-model.js +99 -0
- package/packages/daemon/dist/widgets/lib/files.d.ts +11 -0
- package/packages/daemon/dist/widgets/lib/files.js +76 -0
- package/packages/daemon/dist/widgets/lib/git.d.ts +11 -0
- package/packages/daemon/dist/widgets/lib/git.js +70 -0
- package/packages/daemon/dist/widgets/lib/grammar.d.ts +79 -0
- package/packages/daemon/dist/widgets/lib/grammar.js +95 -0
- package/packages/daemon/dist/widgets/lib/help-overlay.d.ts +19 -0
- package/packages/daemon/dist/widgets/lib/help-overlay.jsx +69 -0
- package/packages/daemon/dist/widgets/lib/pane-comms.d.ts +28 -0
- package/packages/daemon/dist/widgets/lib/pane-comms.js +189 -0
- package/packages/daemon/dist/widgets/lib/theme.d.ts +44 -0
- package/packages/daemon/dist/widgets/lib/theme.js +153 -0
- package/packages/daemon/dist/widgets/lib/watcher.d.ts +9 -0
- package/packages/daemon/dist/widgets/lib/watcher.js +92 -0
- package/packages/daemon/dist/widgets/preview/index.d.ts +1 -0
- package/packages/daemon/dist/widgets/preview/index.jsx +371 -0
- package/packages/daemon/dist/widgets/resolve.d.ts +20 -0
- package/packages/daemon/dist/widgets/resolve.js +100 -0
- package/packages/daemon/dist/widgets/setup/agent-naming.d.ts +9 -0
- package/packages/daemon/dist/widgets/setup/agent-naming.jsx +81 -0
- package/packages/daemon/dist/widgets/setup/config-tree.d.ts +13 -0
- package/packages/daemon/dist/widgets/setup/config-tree.jsx +203 -0
- package/packages/daemon/dist/widgets/setup/detect-panel.d.ts +14 -0
- package/{src/widgets/setup/detect-panel.tsx → packages/daemon/dist/widgets/setup/detect-panel.jsx} +16 -40
- package/packages/daemon/dist/widgets/setup/field-editor.d.ts +12 -0
- package/packages/daemon/dist/widgets/setup/field-editor.jsx +163 -0
- package/packages/daemon/dist/widgets/setup/footer.d.ts +17 -0
- package/packages/daemon/dist/widgets/setup/footer.jsx +64 -0
- package/packages/daemon/dist/widgets/setup/index.d.ts +1 -0
- package/packages/daemon/dist/widgets/setup/index.jsx +261 -0
- package/packages/daemon/dist/widgets/setup/layout-picker.d.ts +9 -0
- package/packages/daemon/dist/widgets/setup/layout-picker.jsx +69 -0
- package/packages/daemon/dist/widgets/setup/setup-model.d.ts +15 -0
- package/packages/daemon/dist/widgets/setup/setup-model.js +157 -0
- package/packages/daemon/dist/widgets/sidebar/index.d.ts +1 -0
- package/packages/daemon/dist/widgets/sidebar/index.jsx +462 -0
- package/scripts/build-cli.mjs +101 -0
- package/scripts/build-tui.mjs +58 -0
- package/scripts/capture-codex-traffic.mjs +195 -0
- package/scripts/check-src-additions.sh +74 -0
- package/scripts/coverage-summary.mjs +68 -0
- package/scripts/install-git-hooks.js +53 -0
- package/scripts/merge-update-manifests.mjs +58 -0
- package/scripts/merge-update-manifests.test.mjs +82 -0
- package/scripts/pack-check-run.mjs +83 -0
- package/scripts/postinstall.js +28 -6
- package/scripts/prepublish-check.mjs +44 -0
- package/scripts/stress-test.ts +141 -0
- package/scripts/verify-endpoints.sh +90 -0
- package/skill/SKILL.md +203 -236
- package/dashboard/out/404/index.html +0 -1
- package/dashboard/out/404.html +0 -1
- package/dashboard/out/__next.__PAGE__.txt +0 -9
- package/dashboard/out/__next._full.txt +0 -21
- package/dashboard/out/__next._head.txt +0 -5
- package/dashboard/out/__next._index.txt +0 -7
- package/dashboard/out/__next._tree.txt +0 -4
- package/dashboard/out/_next/static/Tl1KoIH7mHCyjo5KtXqQ0/_buildManifest.js +0 -11
- package/dashboard/out/_next/static/Tl1KoIH7mHCyjo5KtXqQ0/_clientMiddlewareManifest.json +0 -1
- package/dashboard/out/_next/static/Tl1KoIH7mHCyjo5KtXqQ0/_ssgManifest.js +0 -1
- package/dashboard/out/_next/static/chunks/048e2449530877e2.js +0 -1
- package/dashboard/out/_next/static/chunks/053c57bda6abb959.js +0 -1
- package/dashboard/out/_next/static/chunks/056760c6c2dd9172.js +0 -1
- package/dashboard/out/_next/static/chunks/06ab47357b6d3e35.js +0 -1
- package/dashboard/out/_next/static/chunks/0921cbe5dfd6738e.js +0 -1
- package/dashboard/out/_next/static/chunks/0b2599bf468cf5ea.js +0 -1
- package/dashboard/out/_next/static/chunks/0c012eac08ef2c4f.js +0 -1
- package/dashboard/out/_next/static/chunks/0c29e87fcdcffac3.js +0 -1
- package/dashboard/out/_next/static/chunks/0e1e98854430c693.js +0 -1
- package/dashboard/out/_next/static/chunks/0e24498976a88976.js +0 -1
- package/dashboard/out/_next/static/chunks/0e5bf11ff0b9ab90.js +0 -1
- package/dashboard/out/_next/static/chunks/0eae0a45ab8416c8.js +0 -1
- package/dashboard/out/_next/static/chunks/104797400d9d38ad.js +0 -1
- package/dashboard/out/_next/static/chunks/10cfcfce475f9d2d.js +0 -1
- package/dashboard/out/_next/static/chunks/11bac38e7cfb4ecc.js +0 -1
- package/dashboard/out/_next/static/chunks/120c5f6501ec3529.js +0 -1
- package/dashboard/out/_next/static/chunks/121fceb2b1dcd79f.js +0 -1
- package/dashboard/out/_next/static/chunks/13726b63e1be6b98.js +0 -1
- package/dashboard/out/_next/static/chunks/140c6ce631514660.js +0 -1
- package/dashboard/out/_next/static/chunks/1435ee3a51174c97.js +0 -1
- package/dashboard/out/_next/static/chunks/14dc927d2e2cca91.js +0 -1
- package/dashboard/out/_next/static/chunks/179c3031b292d98e.js +0 -1
- package/dashboard/out/_next/static/chunks/181e88957c47e5c1.js +0 -1
- package/dashboard/out/_next/static/chunks/18f70ba23873c432.js +0 -1
- package/dashboard/out/_next/static/chunks/1b58303b027fd135.js +0 -1
- package/dashboard/out/_next/static/chunks/1b5f49a358dcc71e.js +0 -1
- package/dashboard/out/_next/static/chunks/1bba44b81585099a.js +0 -1
- package/dashboard/out/_next/static/chunks/1bea8dee19a3e9ae.js +0 -1
- package/dashboard/out/_next/static/chunks/1cfad21646fc250e.js +0 -1
- package/dashboard/out/_next/static/chunks/1d053dc9e1e428ef.js +0 -1
- package/dashboard/out/_next/static/chunks/1e7d7639c6f0ee5e.js +0 -1
- package/dashboard/out/_next/static/chunks/1f42504ca81463f1.js +0 -1
- package/dashboard/out/_next/static/chunks/20c92047399305b4.js +0 -1
- package/dashboard/out/_next/static/chunks/214560e9514a9a4d.js +0 -1
- package/dashboard/out/_next/static/chunks/21d4ef106914e997.js +0 -1
- package/dashboard/out/_next/static/chunks/2586e83fc3dc2588.js +0 -1
- package/dashboard/out/_next/static/chunks/267136a09e94f5c2.js +0 -1
- package/dashboard/out/_next/static/chunks/271c50b329917c10.js +0 -1
- package/dashboard/out/_next/static/chunks/27fccecefffd88b5.js +0 -1
- package/dashboard/out/_next/static/chunks/28f058ed331315b6.js +0 -1
- package/dashboard/out/_next/static/chunks/28f704f2cc5713eb.js +0 -1
- package/dashboard/out/_next/static/chunks/290f67a6cd150a98.js +0 -1
- package/dashboard/out/_next/static/chunks/2ad12f4dcc30d30a.js +0 -1
- package/dashboard/out/_next/static/chunks/2b650b172078ab92.js +0 -1
- package/dashboard/out/_next/static/chunks/2bd91076019a6453.js +0 -1
- package/dashboard/out/_next/static/chunks/2e1278563a8e26be.js +0 -1
- package/dashboard/out/_next/static/chunks/309eb70780a3d67d.js +0 -1
- package/dashboard/out/_next/static/chunks/30f71950992e2307.js +0 -1
- package/dashboard/out/_next/static/chunks/31191873c2075784.js +0 -1
- package/dashboard/out/_next/static/chunks/31a790921a0c035e.js +0 -1
- package/dashboard/out/_next/static/chunks/34f8d7a5a06e8e32.js +0 -1
- package/dashboard/out/_next/static/chunks/36b3716436d9bc9d.js +0 -1
- package/dashboard/out/_next/static/chunks/3770b7d0ff004de3.js +0 -1
- package/dashboard/out/_next/static/chunks/381ab3bd4cffbf4d.js +0 -1
- package/dashboard/out/_next/static/chunks/38aa4eada5dcd1a4.js +0 -1
- package/dashboard/out/_next/static/chunks/39723132b78cb77e.js +0 -1
- package/dashboard/out/_next/static/chunks/399efdcc3fe56e09.js +0 -1
- package/dashboard/out/_next/static/chunks/3a8431a9221b0706.js +0 -1
- package/dashboard/out/_next/static/chunks/3a9b40810ce88cbf.js +0 -1
- package/dashboard/out/_next/static/chunks/3b322e3e9476ecdf.js +0 -1
- package/dashboard/out/_next/static/chunks/3bb14befeeb08c28.js +0 -1
- package/dashboard/out/_next/static/chunks/3c99637ebd462b20.js +0 -1
- package/dashboard/out/_next/static/chunks/3cbb9217d56459d8.js +0 -1
- package/dashboard/out/_next/static/chunks/3d438e0929a762f7.js +0 -1
- package/dashboard/out/_next/static/chunks/3e6d4834e0752f76.js +0 -2
- package/dashboard/out/_next/static/chunks/3e6f8cedaad4e89b.js +0 -1
- package/dashboard/out/_next/static/chunks/3e701259ce1b53e3.js +0 -1
- package/dashboard/out/_next/static/chunks/41562f7ab7c033eb.js +0 -1
- package/dashboard/out/_next/static/chunks/418fadd8a94e2fd7.js +0 -1
- package/dashboard/out/_next/static/chunks/42345437bb922e9c.js +0 -1
- package/dashboard/out/_next/static/chunks/434b6bd78c97b668.js +0 -1
- package/dashboard/out/_next/static/chunks/434febe897d33e2d.js +0 -1
- package/dashboard/out/_next/static/chunks/45d28707dd8ce1c1.js +0 -1
- package/dashboard/out/_next/static/chunks/4620a640e88cb1b7.js +0 -1
- package/dashboard/out/_next/static/chunks/468f8eb604502ea4.js +0 -1
- package/dashboard/out/_next/static/chunks/495f5cedf8afe823.js +0 -1
- package/dashboard/out/_next/static/chunks/49a89d1704d27740.js +0 -1
- package/dashboard/out/_next/static/chunks/49e5c37d15f63def.js +0 -1
- package/dashboard/out/_next/static/chunks/4a46ad186a8587ee.css +0 -2
- package/dashboard/out/_next/static/chunks/4a5c728574935d50.js +0 -1
- package/dashboard/out/_next/static/chunks/4b27ebd4d9304d8f.js +0 -1
- package/dashboard/out/_next/static/chunks/4b965aa320a9b358.js +0 -1
- package/dashboard/out/_next/static/chunks/4bb2da90bbe5794f.js +0 -1
- package/dashboard/out/_next/static/chunks/4d2f1c6f631e4b85.js +0 -1
- package/dashboard/out/_next/static/chunks/4d696d5a64dab42e.js +0 -1
- package/dashboard/out/_next/static/chunks/4f660dadb3f1e9e2.js +0 -1
- package/dashboard/out/_next/static/chunks/507b50d47f949333.js +0 -1
- package/dashboard/out/_next/static/chunks/50b1b7063bb044e2.js +0 -1
- package/dashboard/out/_next/static/chunks/50c0c2e3c4f02508.js +0 -1
- package/dashboard/out/_next/static/chunks/50d7ba9803e65b02.js +0 -1
- package/dashboard/out/_next/static/chunks/51535a6d4c98c7a4.js +0 -1
- package/dashboard/out/_next/static/chunks/526de6cc16c7dd2f.js +0 -1
- package/dashboard/out/_next/static/chunks/5307604f8632b3fd.js +0 -1
- package/dashboard/out/_next/static/chunks/5480bd722260f231.js +0 -1
- package/dashboard/out/_next/static/chunks/54c61c82e5f1dca5.js +0 -1
- package/dashboard/out/_next/static/chunks/555de6ac6bb9034c.js +0 -1
- package/dashboard/out/_next/static/chunks/562b89ee76a4b90c.js +0 -1
- package/dashboard/out/_next/static/chunks/5747f9a32edff429.js +0 -1
- package/dashboard/out/_next/static/chunks/57ee141430b4c05c.js +0 -1
- package/dashboard/out/_next/static/chunks/584c066a0837dd9a.js +0 -1
- package/dashboard/out/_next/static/chunks/5856aed4670a6253.js +0 -1
- package/dashboard/out/_next/static/chunks/58fe563414726511.js +0 -1
- package/dashboard/out/_next/static/chunks/5948196b2729b18c.js +0 -1
- package/dashboard/out/_next/static/chunks/5ab77c69e7306f97.js +0 -1
- package/dashboard/out/_next/static/chunks/5b3fa4c99d61611c.js +0 -1
- package/dashboard/out/_next/static/chunks/5cc87abaef616661.js +0 -1
- package/dashboard/out/_next/static/chunks/5dfa7913f99bb966.js +0 -1
- package/dashboard/out/_next/static/chunks/5e49b008432770f1.js +0 -1
- package/dashboard/out/_next/static/chunks/5e5a33dd81c45c47.js +0 -1
- package/dashboard/out/_next/static/chunks/5ee61bed638eb8a8.js +0 -1
- package/dashboard/out/_next/static/chunks/5eed557b9f45ae4a.js +0 -1
- package/dashboard/out/_next/static/chunks/60446823a7d30c1b.js +0 -1
- package/dashboard/out/_next/static/chunks/605150c490861442.js +0 -1
- package/dashboard/out/_next/static/chunks/609056d51c0bf332.js +0 -1
- package/dashboard/out/_next/static/chunks/60ec91dfeb50071b.js +0 -1
- package/dashboard/out/_next/static/chunks/61bc7be0bba6a33f.js +0 -1
- package/dashboard/out/_next/static/chunks/61f4a5c9ce23e55e.js +0 -1
- package/dashboard/out/_next/static/chunks/63aae3585be04e65.js +0 -1
- package/dashboard/out/_next/static/chunks/64e0e1ee7ef4f01b.js +0 -1
- package/dashboard/out/_next/static/chunks/66e9b4c26ff1aaaf.js +0 -1
- package/dashboard/out/_next/static/chunks/67068847aa1b5e98.js +0 -1
- package/dashboard/out/_next/static/chunks/68d7de1f2e202c26.js +0 -1
- package/dashboard/out/_next/static/chunks/698ca3ea1937ba4f.js +0 -1
- package/dashboard/out/_next/static/chunks/69eb97c24b5b6b9d.js +0 -1
- package/dashboard/out/_next/static/chunks/6b1ac098c228a479.js +0 -1
- package/dashboard/out/_next/static/chunks/6bb8020cb796bcc1.js +0 -1
- package/dashboard/out/_next/static/chunks/6cf8b1db17f2a155.js +0 -1
- package/dashboard/out/_next/static/chunks/6e7613643906ea88.js +0 -1
- package/dashboard/out/_next/static/chunks/6ea27ceb2e6feae5.js +0 -1
- package/dashboard/out/_next/static/chunks/6f95a8dbcf23dded.js +0 -1
- package/dashboard/out/_next/static/chunks/6fd44e759d82f64e.js +0 -1
- package/dashboard/out/_next/static/chunks/716ec29c268c38f6.js +0 -1
- package/dashboard/out/_next/static/chunks/717b399dfcf7c02c.js +0 -1
- package/dashboard/out/_next/static/chunks/72badd90e1c91348.js +0 -1
- package/dashboard/out/_next/static/chunks/72f9296dbb7ae3c4.js +0 -1
- package/dashboard/out/_next/static/chunks/73aa31e1144d8191.js +0 -1
- package/dashboard/out/_next/static/chunks/73f98ded8fe2e879.js +0 -1
- package/dashboard/out/_next/static/chunks/740a2e8ace15e13b.js +0 -1
- package/dashboard/out/_next/static/chunks/74e57c16e7304b6b.js +0 -1
- package/dashboard/out/_next/static/chunks/7628dead4d113df2.js +0 -1
- package/dashboard/out/_next/static/chunks/7717c88c07ed96e6.js +0 -1
- package/dashboard/out/_next/static/chunks/775581f7956d9a27.js +0 -1
- package/dashboard/out/_next/static/chunks/77d3b6661befdb98.js +0 -1
- package/dashboard/out/_next/static/chunks/78435c0e1c77fea7.js +0 -1
- package/dashboard/out/_next/static/chunks/791336748b9c9393.js +0 -1
- package/dashboard/out/_next/static/chunks/79ea68dfae65ef2f.js +0 -1
- package/dashboard/out/_next/static/chunks/7bae777a472eb13c.js +0 -1
- package/dashboard/out/_next/static/chunks/7fd847f47237a35c.js +0 -1
- package/dashboard/out/_next/static/chunks/804d718be0370058.css +0 -1
- package/dashboard/out/_next/static/chunks/807cb3c1923995ab.js +0 -1
- package/dashboard/out/_next/static/chunks/8286b39407d94447.js +0 -1
- package/dashboard/out/_next/static/chunks/84e4305b8dc830ed.js +0 -1
- package/dashboard/out/_next/static/chunks/850f99dbfabb53e0.js +0 -1
- package/dashboard/out/_next/static/chunks/85594127e66b6b7f.js +0 -1
- package/dashboard/out/_next/static/chunks/858c11169c183c9c.js +0 -1
- package/dashboard/out/_next/static/chunks/85e27005dfe4c3e3.js +0 -1
- package/dashboard/out/_next/static/chunks/8707bd3d8ddc1f1c.js +0 -1
- package/dashboard/out/_next/static/chunks/8851e5d7ef894973.js +0 -1
- package/dashboard/out/_next/static/chunks/88ba3782cc614989.js +0 -1
- package/dashboard/out/_next/static/chunks/8a0c9a181784c2ef.js +0 -1
- package/dashboard/out/_next/static/chunks/8ad01ae355a6e7f6.js +0 -1
- package/dashboard/out/_next/static/chunks/8d2ed93b0d0a4b4f.js +0 -1
- package/dashboard/out/_next/static/chunks/8dc352ebd5310d3c.js +0 -1
- package/dashboard/out/_next/static/chunks/8dd1d722c8c1a22c.js +0 -1
- package/dashboard/out/_next/static/chunks/8e60fe307e3e4986.js +0 -1
- package/dashboard/out/_next/static/chunks/8eea4dd71e25f32a.js +0 -1
- package/dashboard/out/_next/static/chunks/8f468a65bac34eaa.js +0 -1
- package/dashboard/out/_next/static/chunks/9057e5382d6a5059.js +0 -1
- package/dashboard/out/_next/static/chunks/931d056437805ecb.js +0 -1
- package/dashboard/out/_next/static/chunks/954eb11648dd8cff.js +0 -1
- package/dashboard/out/_next/static/chunks/955034d876d14bb3.js +0 -1
- package/dashboard/out/_next/static/chunks/966c4895773249f6.js +0 -1
- package/dashboard/out/_next/static/chunks/96aff410a6ab106c.js +0 -1
- package/dashboard/out/_next/static/chunks/99b396c821c1dd2d.js +0 -1
- package/dashboard/out/_next/static/chunks/9a255fd2cf4922ae.js +0 -1
- package/dashboard/out/_next/static/chunks/9b1f6aa73bc864b2.js +0 -1
- package/dashboard/out/_next/static/chunks/9b9ce582c533aa79.js +0 -1
- package/dashboard/out/_next/static/chunks/9c19bd3c773c6611.js +0 -1
- package/dashboard/out/_next/static/chunks/9ceeaa847eb15ca2.js +0 -1
- package/dashboard/out/_next/static/chunks/9d2e6e7b8b65f845.js +0 -1
- package/dashboard/out/_next/static/chunks/9de23802066128ff.js +0 -1
- package/dashboard/out/_next/static/chunks/9e327f94b3701170.js +0 -1
- package/dashboard/out/_next/static/chunks/9e7818421c2d455a.js +0 -1
- package/dashboard/out/_next/static/chunks/9e935acbcf2fb519.js +0 -1
- package/dashboard/out/_next/static/chunks/9ed9f68340343b51.js +0 -1
- package/dashboard/out/_next/static/chunks/9f94a0242455fc20.js +0 -1
- package/dashboard/out/_next/static/chunks/9fff46b5aaecf47e.js +0 -1
- package/dashboard/out/_next/static/chunks/a06d267a5c557657.js +0 -1
- package/dashboard/out/_next/static/chunks/a0eb8c81c54722fe.js +0 -1
- package/dashboard/out/_next/static/chunks/a16808e83106427d.js +0 -1
- package/dashboard/out/_next/static/chunks/a2215e2bc72739ef.js +0 -1
- package/dashboard/out/_next/static/chunks/a2de9e6696eb9c17.js +0 -1
- package/dashboard/out/_next/static/chunks/a33420b8c14090d6.js +0 -1
- package/dashboard/out/_next/static/chunks/a360bffef39d818b.js +0 -1
- package/dashboard/out/_next/static/chunks/a42852fdf5287cf5.js +0 -1
- package/dashboard/out/_next/static/chunks/a4efc88488322b67.js +0 -1
- package/dashboard/out/_next/static/chunks/a696a91d14101bdb.js +0 -1
- package/dashboard/out/_next/static/chunks/a6dad97d9634a72d.js +0 -1
- package/dashboard/out/_next/static/chunks/a6dad97d9634a72d.js.map +0 -1
- package/dashboard/out/_next/static/chunks/a705c7261712bd8e.js +0 -1
- package/dashboard/out/_next/static/chunks/a7d1e4b067ace180.js +0 -1
- package/dashboard/out/_next/static/chunks/a8590c121a7efaa5.js +0 -1
- package/dashboard/out/_next/static/chunks/a95953a83a6df6cf.js +0 -1
- package/dashboard/out/_next/static/chunks/a9d0a757d3b4afed.js +0 -1
- package/dashboard/out/_next/static/chunks/a9dc35514619c872.js +0 -1
- package/dashboard/out/_next/static/chunks/aae0253c73fba984.js +0 -193
- package/dashboard/out/_next/static/chunks/ab1821552066a74d.js +0 -1
- package/dashboard/out/_next/static/chunks/ac96bc0eccebe15a.js +0 -1
- package/dashboard/out/_next/static/chunks/acc03cfaaf6bb30f.js +0 -1
- package/dashboard/out/_next/static/chunks/acc298ae059b9fe4.js +0 -1
- package/dashboard/out/_next/static/chunks/ad076b6e996d250c.js +0 -1
- package/dashboard/out/_next/static/chunks/ae53b64af7ba16d5.js +0 -1
- package/dashboard/out/_next/static/chunks/ae5da7fa4bc5fa95.js +0 -1
- package/dashboard/out/_next/static/chunks/aefcf0eb033a155e.js +0 -1
- package/dashboard/out/_next/static/chunks/b12d43100ee10526.js +0 -1
- package/dashboard/out/_next/static/chunks/b137952dd5566a41.js +0 -1
- package/dashboard/out/_next/static/chunks/b2832d8a2d332a47.js +0 -1
- package/dashboard/out/_next/static/chunks/b417aa09c15f63c6.js +0 -1
- package/dashboard/out/_next/static/chunks/b48e152ba7bf6caf.js +0 -1
- package/dashboard/out/_next/static/chunks/b4cbef8e4714bf92.js +0 -1
- package/dashboard/out/_next/static/chunks/b568ff8383a37f53.js +0 -1
- package/dashboard/out/_next/static/chunks/b6e1495dd89a39e3.js +0 -1
- package/dashboard/out/_next/static/chunks/b73a21bd67528440.js +0 -1
- package/dashboard/out/_next/static/chunks/b77ee62bc71dcec7.js +0 -1
- package/dashboard/out/_next/static/chunks/b7f454615c11d4eb.js +0 -1
- package/dashboard/out/_next/static/chunks/b818ea32a839590f.js +0 -1
- package/dashboard/out/_next/static/chunks/b901ce78c1c65d66.js +0 -1
- package/dashboard/out/_next/static/chunks/b93d647b803be9fa.js +0 -1
- package/dashboard/out/_next/static/chunks/b960b09ff1ecd6bb.js +0 -1
- package/dashboard/out/_next/static/chunks/ba717c7779a778fc.js +0 -1
- package/dashboard/out/_next/static/chunks/bacb0ae7458d18b6.js +0 -1
- package/dashboard/out/_next/static/chunks/bb51f68b27346852.js +0 -1
- package/dashboard/out/_next/static/chunks/bb67f22e1ab632ae.js +0 -1
- package/dashboard/out/_next/static/chunks/bbae97ec58d1bb9d.js +0 -1
- package/dashboard/out/_next/static/chunks/bbaf38ee90307765.js +0 -1
- package/dashboard/out/_next/static/chunks/be01598fe1fce5db.js +0 -1
- package/dashboard/out/_next/static/chunks/bf4cbbc095987fec.js +0 -1
- package/dashboard/out/_next/static/chunks/c18f823797d57446.js +0 -1
- package/dashboard/out/_next/static/chunks/c1bcece34ec5b295.js +0 -1
- package/dashboard/out/_next/static/chunks/c1ccbc3a51adaf0a.js +0 -1
- package/dashboard/out/_next/static/chunks/c1f54a628f27791c.js +0 -1
- package/dashboard/out/_next/static/chunks/c21916bf5d232151.js +0 -1
- package/dashboard/out/_next/static/chunks/c27e570f0fc2f78b.js +0 -1
- package/dashboard/out/_next/static/chunks/c322b8005eebc0d8.js +0 -1
- package/dashboard/out/_next/static/chunks/c3900ac2b009b764.js +0 -1
- package/dashboard/out/_next/static/chunks/c3c597c8eb77ad6b.js +0 -1
- package/dashboard/out/_next/static/chunks/c58d45c1d88e208c.js +0 -1
- package/dashboard/out/_next/static/chunks/c63875998d7a655f.js +0 -1
- package/dashboard/out/_next/static/chunks/c6eaa7c8e7209c8e.js +0 -1
- package/dashboard/out/_next/static/chunks/c6f820f71162a59a.js +0 -1
- package/dashboard/out/_next/static/chunks/c7ce0941d1dfe7ed.js +0 -1
- package/dashboard/out/_next/static/chunks/c877259f784ec8e5.js +0 -1
- package/dashboard/out/_next/static/chunks/cb8057e86aaa1c68.js +0 -1
- package/dashboard/out/_next/static/chunks/ccb4e306ee4859b1.js +0 -1
- package/dashboard/out/_next/static/chunks/ccde62b0fa8112eb.js +0 -1
- package/dashboard/out/_next/static/chunks/cd421f0971c63c31.js +0 -1
- package/dashboard/out/_next/static/chunks/cde0317494d4adb7.js +0 -1
- package/dashboard/out/_next/static/chunks/cfae64434b92b8b6.js +0 -1
- package/dashboard/out/_next/static/chunks/cfc0e19310ec0a36.js +0 -1
- package/dashboard/out/_next/static/chunks/d0f344c7d0bcb59a.js +0 -1
- package/dashboard/out/_next/static/chunks/d1871c73e74e1f50.js +0 -1
- package/dashboard/out/_next/static/chunks/d18f658850711061.js +0 -1
- package/dashboard/out/_next/static/chunks/d25d9c48880697f6.js +0 -1
- package/dashboard/out/_next/static/chunks/d3f0a72bbc3060b0.js +0 -1
- package/dashboard/out/_next/static/chunks/d5fca429bc89060b.js +0 -1
- package/dashboard/out/_next/static/chunks/d6a6c75c9a4bef49.js +0 -1
- package/dashboard/out/_next/static/chunks/d6a8f93aa8f1e345.js +0 -1
- package/dashboard/out/_next/static/chunks/d7deab676b19ba0e.js +0 -1
- package/dashboard/out/_next/static/chunks/d80030dde88cec85.js +0 -1
- package/dashboard/out/_next/static/chunks/da84f9774c076ff1.js +0 -1
- package/dashboard/out/_next/static/chunks/da98ecc6b9b0ceb2.js +0 -1
- package/dashboard/out/_next/static/chunks/db550aabce60b912.js +0 -4
- package/dashboard/out/_next/static/chunks/dc87f77fcc029482.js +0 -1
- package/dashboard/out/_next/static/chunks/dd05f30acdb63a53.js +0 -1
- package/dashboard/out/_next/static/chunks/dea150155499b903.js +0 -1
- package/dashboard/out/_next/static/chunks/df4358754ff1d5e8.js +0 -1
- package/dashboard/out/_next/static/chunks/df8b21ff12d23b0e.js +0 -1
- package/dashboard/out/_next/static/chunks/df8fc68d77debf2c.js +0 -1
- package/dashboard/out/_next/static/chunks/df9ed1ffec90589f.js +0 -1
- package/dashboard/out/_next/static/chunks/dfa65ece1598f934.js +0 -1
- package/dashboard/out/_next/static/chunks/dfaab5cdd41a20d9.js +0 -1
- package/dashboard/out/_next/static/chunks/e00c03c942b5ae3e.js +0 -1
- package/dashboard/out/_next/static/chunks/e02d27cf679bece1.js +0 -1
- package/dashboard/out/_next/static/chunks/e0b747585f78513a.js +0 -1
- package/dashboard/out/_next/static/chunks/e19b71ca23fd7df0.js +0 -1
- package/dashboard/out/_next/static/chunks/e21cbe89d0cda120.js +0 -1
- package/dashboard/out/_next/static/chunks/e2a0386930edd34f.js +0 -1
- package/dashboard/out/_next/static/chunks/e375de19a36e2f38.js +0 -1
- package/dashboard/out/_next/static/chunks/e5241b4a6496a9e0.js +0 -1
- package/dashboard/out/_next/static/chunks/e569dd07c96eb4dd.js +0 -1
- package/dashboard/out/_next/static/chunks/e61c3ea91233f948.js +0 -1
- package/dashboard/out/_next/static/chunks/e73b42c5d34c4c28.js +0 -1
- package/dashboard/out/_next/static/chunks/e7c5b2105f651e87.js +0 -1
- package/dashboard/out/_next/static/chunks/e878e58a69bb01b6.js +0 -1
- package/dashboard/out/_next/static/chunks/e8f090a4dc571062.js +0 -1
- package/dashboard/out/_next/static/chunks/e98dc34dac91cdad.js +0 -1
- package/dashboard/out/_next/static/chunks/ea67cf7a0c5e7233.js +0 -1
- package/dashboard/out/_next/static/chunks/eacc98a1e3512fa9.js +0 -1
- package/dashboard/out/_next/static/chunks/eae9cd74d9bbed8b.js +0 -1
- package/dashboard/out/_next/static/chunks/eb187fd345852b34.js +0 -1
- package/dashboard/out/_next/static/chunks/ecea46df7a40b427.js +0 -1
- package/dashboard/out/_next/static/chunks/ecf48b83f4245d9c.js +0 -1
- package/dashboard/out/_next/static/chunks/eda41732bf966c6d.js +0 -1
- package/dashboard/out/_next/static/chunks/ee174a433049f43a.js +0 -1
- package/dashboard/out/_next/static/chunks/ee66b2d3b76de72e.js +0 -1
- package/dashboard/out/_next/static/chunks/ef058d3041c3d8ab.js +0 -1
- package/dashboard/out/_next/static/chunks/f3544b800b0d4969.js +0 -1
- package/dashboard/out/_next/static/chunks/f3b280e604b97509.js +0 -1
- package/dashboard/out/_next/static/chunks/f42e1d3693232993.js +0 -1
- package/dashboard/out/_next/static/chunks/f5a5fdd80166d304.js +0 -1
- package/dashboard/out/_next/static/chunks/f60adc5dd6169316.js +0 -1
- package/dashboard/out/_next/static/chunks/f6255bc2e6c68ce8.js +0 -1
- package/dashboard/out/_next/static/chunks/f6bb677d2d8840db.js +0 -1
- package/dashboard/out/_next/static/chunks/f6f3bf016239c33a.js +0 -1
- package/dashboard/out/_next/static/chunks/f6f57a46cd074bfe.js +0 -1
- package/dashboard/out/_next/static/chunks/f7feb9c1199e8cf6.js +0 -1
- package/dashboard/out/_next/static/chunks/f831087bf964cc3d.js +0 -1
- package/dashboard/out/_next/static/chunks/fa5a2f7244935aa2.js +0 -1
- package/dashboard/out/_next/static/chunks/fa73f36df4c38fa0.js +0 -1
- package/dashboard/out/_next/static/chunks/faa1461722d6a88d.js +0 -1
- package/dashboard/out/_next/static/chunks/fbf706b9a0edb7e6.js +0 -1
- package/dashboard/out/_next/static/chunks/fc2b8c8b7446bbc2.js +0 -1
- package/dashboard/out/_next/static/chunks/fd516f3930c128c1.js +0 -1
- package/dashboard/out/_next/static/chunks/fd663e7ff8de4887.js +0 -1
- package/dashboard/out/_next/static/chunks/fe5b656cc9bdd60e.js +0 -1
- package/dashboard/out/_next/static/chunks/turbopack-2f5dec4a537c0ee7.js +0 -4
- package/dashboard/out/_next/static/media/02263ebadd758ea4-s.8da66e7f.woff2 +0 -0
- package/dashboard/out/_next/static/media/2fe89d53234c61d4-s.cb53f04b.woff2 +0 -0
- package/dashboard/out/_next/static/media/59b15b4bcd7b1eb5-s.afa48be3.woff2 +0 -0
- package/dashboard/out/_next/static/media/5e05ae5b48faa55e-s.6b5ea6af.woff2 +0 -0
- package/dashboard/out/_next/static/media/68757d6cddeff913-s.e6cd1753.woff2 +0 -0
- package/dashboard/out/_next/static/media/99e609270109b47d-s.p.64b9304e.woff2 +0 -0
- package/dashboard/out/_next/static/media/a7afbb44bec2bb18-s.1dcddae6.woff2 +0 -0
- package/dashboard/out/_next/static/media/e390973e931a41c5-s.a82ecf4e.woff2 +0 -0
- package/dashboard/out/_next/static/media/e532fa1b9921e1cd-s.764b43eb.woff2 +0 -0
- package/dashboard/out/_next/static/media/effe91970fc4db64-s.p.19510058.woff2 +0 -0
- package/dashboard/out/_not-found/__next._full.txt +0 -15
- package/dashboard/out/_not-found/__next._head.txt +0 -5
- package/dashboard/out/_not-found/__next._index.txt +0 -7
- package/dashboard/out/_not-found/__next._not-found.__PAGE__.txt +0 -5
- package/dashboard/out/_not-found/__next._not-found.txt +0 -4
- package/dashboard/out/_not-found/__next._tree.txt +0 -2
- package/dashboard/out/_not-found/index.html +0 -1
- package/dashboard/out/_not-found/index.txt +0 -15
- package/dashboard/out/index.html +0 -1
- package/dashboard/out/index.txt +0 -21
- package/dashboard/out/project/__fallback/__next._full.txt +0 -19
- package/dashboard/out/project/__fallback/__next._head.txt +0 -5
- package/dashboard/out/project/__fallback/__next._index.txt +0 -7
- package/dashboard/out/project/__fallback/__next._tree.txt +0 -5
- package/dashboard/out/project/__fallback/__next.project.$d$name.__PAGE__.txt +0 -7
- package/dashboard/out/project/__fallback/__next.project.$d$name.txt +0 -4
- package/dashboard/out/project/__fallback/__next.project.txt +0 -4
- package/dashboard/out/project/__fallback/index.html +0 -1
- package/dashboard/out/project/__fallback/index.txt +0 -19
- package/src/__tests__/support.ts +0 -186
- package/src/attach.ts +0 -20
- package/src/cli.test.ts +0 -314
- package/src/command-center/discovery.test.ts +0 -265
- package/src/command-center/discovery.ts +0 -296
- package/src/command-center/index.ts +0 -31
- package/src/command-center/schemas.ts +0 -57
- package/src/command-center/server.test.ts +0 -814
- package/src/command-center/server.ts +0 -1427
- package/src/command-center/static.test.ts +0 -105
- package/src/command-center/static.ts +0 -122
- package/src/config-cli.test.ts +0 -86
- package/src/config.test.ts +0 -205
- package/src/config.ts +0 -313
- package/src/detect.test.ts +0 -142
- package/src/detect.ts +0 -248
- package/src/dispatch.ts +0 -102
- package/src/doctor.test.ts +0 -119
- package/src/doctor.ts +0 -167
- package/src/init.test.ts +0 -101
- package/src/init.ts +0 -211
- package/src/inspect.test.ts +0 -67
- package/src/inspect.ts +0 -212
- package/src/integration.test.ts.skip +0 -276
- package/src/js-yaml.d.ts +0 -10
- package/src/launch.test.ts +0 -149
- package/src/launch.ts +0 -583
- package/src/lib/auth/auth-service.test.ts +0 -178
- package/src/lib/auth/auth-service.ts +0 -227
- package/src/lib/auth/middleware.test.ts +0 -119
- package/src/lib/auth/middleware.ts +0 -56
- package/src/lib/auth/types.ts +0 -13
- package/src/lib/authorship.test.ts +0 -242
- package/src/lib/authorship.ts +0 -280
- package/src/lib/cast/recorder.test.ts +0 -127
- package/src/lib/cast/recorder.ts +0 -148
- package/src/lib/daemon-watchdog.ts +0 -102
- package/src/lib/daemon.ts +0 -431
- package/src/lib/dot-path.test.ts +0 -66
- package/src/lib/dot-path.ts +0 -17
- package/src/lib/errors.ts +0 -44
- package/src/lib/event-log.test.ts +0 -189
- package/src/lib/event-log.ts +0 -237
- package/src/lib/github-pr.ts +0 -182
- package/src/lib/hq/client.test.ts +0 -154
- package/src/lib/hq/client.ts +0 -142
- package/src/lib/hq/mdns.test.ts +0 -54
- package/src/lib/hq/mdns.ts +0 -88
- package/src/lib/hq/registry.test.ts +0 -237
- package/src/lib/hq/registry.ts +0 -145
- package/src/lib/hq/types.ts +0 -44
- package/src/lib/ipc/socket-protocol.test.ts +0 -126
- package/src/lib/ipc/socket-protocol.ts +0 -324
- package/src/lib/launch-plan.test.ts +0 -119
- package/src/lib/launch-plan.ts +0 -90
- package/src/lib/log.test.ts +0 -39
- package/src/lib/log.ts +0 -71
- package/src/lib/metrics.test.ts +0 -213
- package/src/lib/metrics.ts +0 -345
- package/src/lib/orchestrator.test.ts +0 -2358
- package/src/lib/orchestrator.ts +0 -1799
- package/src/lib/output.ts +0 -76
- package/src/lib/plan-store.test.ts +0 -148
- package/src/lib/plan-store.ts +0 -131
- package/src/lib/research.test.ts +0 -208
- package/src/lib/research.ts +0 -475
- package/src/lib/round-trip.test.ts +0 -341
- package/src/lib/session-monitor.test.ts +0 -152
- package/src/lib/session-monitor.ts +0 -282
- package/src/lib/session-options.test.ts +0 -146
- package/src/lib/session-options.ts +0 -100
- package/src/lib/shell.test.ts +0 -20
- package/src/lib/sizes.test.ts +0 -73
- package/src/lib/sizes.ts +0 -36
- package/src/lib/skill-registry.test.ts +0 -134
- package/src/lib/skill-registry.ts +0 -86
- package/src/lib/slugify.test.ts +0 -35
- package/src/lib/slugify.ts +0 -10
- package/src/lib/task-store.ts +0 -352
- package/src/lib/tmux.test.ts +0 -500
- package/src/lib/tmux.ts +0 -372
- package/src/lib/token-tracker.test.ts +0 -102
- package/src/lib/token-tracker.ts +0 -70
- package/src/lib/tunnels/cloudflare.test.ts +0 -73
- package/src/lib/tunnels/cloudflare.ts +0 -254
- package/src/lib/tunnels/manager.test.ts +0 -63
- package/src/lib/tunnels/manager.ts +0 -132
- package/src/lib/tunnels/ngrok.test.ts +0 -94
- package/src/lib/tunnels/ngrok.ts +0 -261
- package/src/lib/tunnels/tailscale.test.ts +0 -103
- package/src/lib/tunnels/tailscale.ts +0 -1048
- package/src/lib/tunnels/types.ts +0 -44
- package/src/lib/validation.test.ts +0 -289
- package/src/lib/validation.ts +0 -123
- package/src/lib/webhook.ts +0 -51
- package/src/lib/workflow-store.ts +0 -209
- package/src/lib/ws-v3/protocol.test.ts +0 -127
- package/src/lib/ws-v3/protocol.ts +0 -160
- package/src/lib/yaml-io.test.ts +0 -125
- package/src/lib/yaml-io.ts +0 -27
- package/src/ls.test.ts +0 -76
- package/src/ls.ts +0 -40
- package/src/metrics-cli.ts +0 -177
- package/src/notify.ts +0 -85
- package/src/orchestrator-status.ts +0 -228
- package/src/plan.ts +0 -117
- package/src/postinstall.test.ts +0 -79
- package/src/remote.test.ts +0 -115
- package/src/remote.ts +0 -148
- package/src/restart.ts +0 -24
- package/src/schemas/domain.ts +0 -422
- package/src/schemas/ide-config.ts +0 -148
- package/src/schemas/index.ts +0 -53
- package/src/send.test.ts +0 -70
- package/src/send.ts +0 -181
- package/src/skill.test.ts +0 -114
- package/src/skill.ts +0 -138
- package/src/status.ts +0 -66
- package/src/stop.test.ts +0 -151
- package/src/stop.ts +0 -37
- package/src/task.test.ts +0 -1466
- package/src/task.ts +0 -1143
- package/src/tunnel.test.ts +0 -80
- package/src/tunnel.ts +0 -133
- package/src/types.ts +0 -15
- package/src/ui/index.ts +0 -32
- package/src/ui/terminal/index.ts +0 -9
- package/src/ui/types.ts +0 -91
- package/src/ui/web/base.css +0 -80
- package/src/ui/web/components/Box.tsx +0 -59
- package/src/ui/web/components/Input.tsx +0 -32
- package/src/ui/web/components/ScrollBox.tsx +0 -60
- package/src/ui/web/components/Text.tsx +0 -28
- package/src/ui/web/hooks.ts +0 -106
- package/src/ui/web/index.ts +0 -27
- package/src/ui/web/render.ts +0 -77
- package/src/ui/web/utils/color.test.ts +0 -93
- package/src/ui/web/utils/color.ts +0 -27
- package/src/validate.test.ts +0 -385
- package/src/validate.ts +0 -217
- package/src/widgets/changes/index.tsx +0 -576
- package/src/widgets/config/index.tsx +0 -440
- package/src/widgets/costs/index.tsx +0 -216
- package/src/widgets/explorer/breadcrumbs.tsx +0 -77
- package/src/widgets/explorer/footer.tsx +0 -20
- package/src/widgets/explorer/header.tsx +0 -23
- package/src/widgets/explorer/index.tsx +0 -408
- package/src/widgets/explorer/tree-model.test.ts +0 -214
- package/src/widgets/explorer/tree-model.ts +0 -103
- package/src/widgets/explorer/tree.tsx +0 -156
- package/src/widgets/lib/config-model.ts +0 -116
- package/src/widgets/lib/files.test.ts +0 -103
- package/src/widgets/lib/files.ts +0 -88
- package/src/widgets/lib/git.test.ts +0 -151
- package/src/widgets/lib/git.ts +0 -88
- package/src/widgets/lib/pane-comms.test.ts +0 -178
- package/src/widgets/lib/pane-comms.ts +0 -207
- package/src/widgets/lib/theme.ts +0 -151
- package/src/widgets/lib/watcher.ts +0 -50
- package/src/widgets/mission-control/activity-feed.tsx +0 -59
- package/src/widgets/mission-control/agent-panel.tsx +0 -132
- package/src/widgets/mission-control/command-bar.tsx +0 -63
- package/src/widgets/mission-control/index.tsx +0 -751
- package/src/widgets/mission-control/task-panel.tsx +0 -238
- package/src/widgets/preview/index.tsx +0 -415
- package/src/widgets/resolve.ts +0 -40
- package/src/widgets/setup/agent-naming.tsx +0 -112
- package/src/widgets/setup/config-tree.tsx +0 -238
- package/src/widgets/setup/field-editor.tsx +0 -265
- package/src/widgets/setup/footer.tsx +0 -107
- package/src/widgets/setup/index.tsx +0 -340
- package/src/widgets/setup/layout-picker.tsx +0 -96
- package/src/widgets/setup/orchestrator-panel.tsx +0 -200
- package/src/widgets/setup/review-panel.tsx +0 -140
- package/src/widgets/setup/setup-model.test.ts +0 -303
- package/src/widgets/setup/setup-model.ts +0 -188
- package/src/widgets/tasks/index.tsx +0 -129
- package/src/widgets/tasks/task-detail.tsx +0 -309
- package/src/widgets/tasks/task-form.tsx +0 -193
- package/src/widgets/tasks/task-list.tsx +0 -205
- package/src/widgets/tasks/task-model.test.ts +0 -473
- package/src/widgets/tasks/task-model.ts +0 -157
package/bin/cli.ts
CHANGED
|
@@ -1,26 +1,36 @@
|
|
|
1
|
-
|
|
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 {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
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
|
-
"
|
|
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 =
|
|
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
|
|
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("
|
|
179
|
-
${cyan("tmux-ide
|
|
180
|
-
${cyan("tmux-ide
|
|
181
|
-
|
|
182
|
-
${bold("
|
|
183
|
-
${cyan("tmux-ide
|
|
184
|
-
${
|
|
185
|
-
|
|
186
|
-
${
|
|
187
|
-
${cyan("
|
|
188
|
-
${cyan("tmux-ide
|
|
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
|
+
`Run it from a cloned tmux-ide checkout with bun installed, or install a release that ships the compiled binary.`,
|
|
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
|
-
|
|
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
|
-
|
|
311
|
-
|
|
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 "
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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 "
|
|
333
|
-
const
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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 "
|
|
349
|
-
const
|
|
350
|
-
|
|
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 "
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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 "
|
|
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
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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 "
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
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 "
|
|
417
|
-
const {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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 "
|
|
427
|
-
const {
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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 "
|
|
436
|
-
const
|
|
437
|
-
const
|
|
438
|
-
if (
|
|
439
|
-
|
|
440
|
-
|
|
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 "
|
|
445
|
-
const
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
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 "
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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 "
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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 "
|
|
471
|
-
|
|
472
|
-
|
|
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 "
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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 "
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
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 "
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
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;
|