commandmate 0.27.1 → 0.29.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/.env.example +28 -0
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +441 -404
- package/.next/app-path-routes-manifest.json +34 -29
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +9 -9
- package/.next/react-loadable-manifest.json +0 -6
- package/.next/required-server-files.json +1 -1
- package/.next/routes-manifest.json +32 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route.js +1 -1
- package/.next/server/app/api/app/update/route.js.nft.json +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/session/route.js +1 -1
- package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/start/route.js +32 -1
- package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/terminal/route.js +34 -3
- package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route.js +1 -1
- package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route.js +1 -1
- package/.next/server/app/api/external-apps/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route.js +1 -1
- package/.next/server/app/api/fs/browse/route.js.nft.json +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route.js.nft.json +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route.js +1 -1
- package/.next/server/app/api/metrics/vibe/route.js.nft.json +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route.js +1 -1
- package/.next/server/app/api/push/escalation/route.js.nft.json +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route.js +7 -1
- package/.next/server/app/api/push/subscriptions/route.js.nft.json +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route.js +1 -1
- package/.next/server/app/api/push/vapid/route.js.nft.json +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route.js +2 -0
- package/.next/server/app/api/remote/pair/route.js.nft.json +1 -0
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/repositories/[id]/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route.js +1 -1
- package/.next/server/app/api/repositories/excluded/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route.js +1 -1
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route.js.nft.json +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route.js +1 -1
- package/.next/server/app/api/skills/installations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route.js +1 -1
- package/.next/server/app/api/skills/operations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route.js +1 -1
- package/.next/server/app/api/skills/reindex/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route.js.nft.json +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route.js +2 -2
- package/.next/server/app/api/templates/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route.js +2 -2
- package/.next/server/app/api/templates/route.js.nft.json +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/todos/route.js +1 -1
- package/.next/server/app/api/todos/route.js.nft.json +1 -1
- package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route.js.nft.json +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route.js +1 -1
- package/.next/server/app/api/verification/runs/route.js.nft.json +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/logs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route.js +4 -4
- package/.next/server/app/api/worktrees/[id]/marp-render/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +5 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +6 -2
- package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +7 -3
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -3
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page.js +2 -2
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route.js +1 -1
- package/.next/server/app/proxy/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page.js +1 -1
- package/.next/server/app/review/page.js.nft.json +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +15 -10
- package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page.js +2 -2
- package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +34 -29
- package/.next/server/chunks/1058.js +1 -0
- package/.next/server/chunks/1068.js +1 -3
- package/.next/server/chunks/1162.js +1 -1
- package/.next/server/chunks/1191.js +13 -0
- package/.next/server/chunks/1296.js +1 -1
- package/.next/server/chunks/1601.js +2 -2
- package/.next/server/chunks/1714.js +7 -0
- package/.next/server/chunks/1886.js +5 -0
- package/.next/server/chunks/1944.js +1 -0
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/221.js +19 -0
- package/.next/server/chunks/222.js +1 -0
- package/.next/server/chunks/2328.js +1 -1
- package/.next/server/chunks/2366.js +1 -0
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/243.js +1 -0
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/2759.js +1 -1
- package/.next/server/chunks/3346.js +1 -1
- package/.next/server/chunks/3440.js +1 -1
- package/.next/server/chunks/3480.js +17 -1
- package/.next/server/chunks/3543.js +1 -1
- package/.next/server/chunks/3558.js +1 -0
- package/.next/server/chunks/3945.js +1 -1
- package/.next/server/chunks/4299.js +1 -0
- package/.next/server/chunks/4393.js +1 -1
- package/.next/server/chunks/5017.js +1 -1
- package/.next/server/chunks/5089.js +1 -1
- package/.next/server/chunks/5354.js +1 -1
- package/.next/server/chunks/5571.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6274.js +11 -10
- package/.next/server/chunks/6285.js +1 -1
- package/.next/server/chunks/6337.js +1 -0
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/663.js +78 -0
- package/.next/server/chunks/7472.js +1 -1
- package/.next/server/chunks/7824.js +1 -0
- package/.next/server/chunks/7905.js +1 -0
- package/.next/server/chunks/880.js +6 -6
- package/.next/server/chunks/8807.js +84 -18
- package/.next/server/chunks/9123.js +2 -2
- package/.next/server/chunks/9130.js +5 -0
- package/.next/server/chunks/9328.js +1 -1
- package/.next/server/chunks/9358.js +1 -1
- package/.next/server/chunks/9508.js +1 -1
- package/.next/server/chunks/9584.js +1 -0
- package/.next/server/chunks/9627.js +274 -0
- package/.next/server/chunks/9798.js +2 -0
- package/.next/server/chunks/9938.js +1 -1
- package/.next/server/functions-config-manifest.json +3 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/server/src/middleware.js +1 -1
- package/.next/server/src/middleware.js.map +1 -1
- package/.next/static/chunks/1188-8567ee5ecfef02ee.js +1 -0
- package/.next/static/chunks/3361-aa1b6e7c1d7eeeb4.js +1 -0
- package/.next/static/chunks/3968-8d8ca15657748bfb.js +1 -0
- package/.next/static/chunks/5229-580b581fce5aeb52.js +1 -0
- package/.next/static/chunks/6381-c8d93ec301dbc380.js +1 -0
- package/.next/static/chunks/app/api/app/update/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/app/update-check/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/assistant/conversation/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/assistant/current-output/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/assistant/messages/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/assistant/session/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/assistant/start/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/assistant/terminal/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/assistant/tools/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/auth/login/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/auth/logout/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/auth/status/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/capabilities/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/daily-summary/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/daily-summary/status/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/external-apps/[id]/health/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/external-apps/[id]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/external-apps/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/fs/browse/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/fs/recent-paths/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/hooks/agent-event/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/hooks/claude-done/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/hooks/permission-request/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/metrics/vibe/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/ollama/models/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/push/escalation/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/push/subscriptions/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/push/vapid/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/remote/pair/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/todos/[todoId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/todos/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/clone/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/excluded/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/restore/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/scan/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/sync/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/repositories/validate-path/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/sidebar/group-order/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/skills/[id]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/skills/installations/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/skills/operations/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/skills/reindex/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/skills/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/slash-commands/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/tasks/[taskId]/cancel/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/tasks/[taskId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/templates/[id]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/templates/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/todos/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/verification/runs/[runId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/verification/runs/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/capture/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/clear-composer/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/env/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/instances/opencode/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/logs/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/memos/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/messages/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/diff/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/session/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/share/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/resolve-target/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/respond/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/search/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/send/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update-plan/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/start-polling/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tasks/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/timers/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/todos/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tree/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/api/worktrees/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/login/page-03659dded846ef1d.js +1 -0
- package/.next/static/chunks/app/manifest.webmanifest/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/more/page-03867ab635d197c7.js +1 -0
- package/.next/static/chunks/app/proxy/[...path]/route-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/review/page-9a6d18ddcccbb63c.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/layout-e3626364434d521b.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-c07b23b6ca58091c.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/page-00ad5d9a62a71cab.js +1 -0
- package/.next/static/chunks/webpack-7e79064bfce988d7.js +1 -0
- package/.next/static/css/b6990f889f4f9515.css +1 -0
- package/.next/static/uulKcSOgyxChTo4SipUSF/_buildManifest.js +1 -0
- package/.next/trace +13 -13
- package/.next/types/app/api/remote/pair/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/instances/opencode/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/opencode/diff/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/opencode/session/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/opencode/share/route.ts +347 -0
- package/.next/types/routes.d.ts +6 -1
- package/.next/types/validator.ts +45 -0
- package/README.md +24 -4
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +66 -0
- package/dist/cli/commands/instances.d.ts.map +1 -1
- package/dist/cli/commands/instances.js +46 -1
- package/dist/cli/commands/interrupt.d.ts +25 -0
- package/dist/cli/commands/interrupt.d.ts.map +1 -0
- package/dist/cli/commands/interrupt.js +146 -0
- package/dist/cli/commands/remote.d.ts +248 -0
- package/dist/cli/commands/remote.d.ts.map +1 -0
- package/dist/cli/commands/remote.js +849 -0
- package/dist/cli/commands/report.d.ts.map +1 -1
- package/dist/cli/commands/report.js +11 -4
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +146 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +104 -0
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +39 -1
- package/dist/cli/config/agent-target-options.d.ts +12 -0
- package/dist/cli/config/agent-target-options.d.ts.map +1 -1
- package/dist/cli/config/agent-target-options.js +15 -1
- package/dist/cli/config/security-messages.d.ts +25 -0
- package/dist/cli/config/security-messages.d.ts.map +1 -1
- package/dist/cli/config/security-messages.js +43 -1
- package/dist/cli/docs/agent-operations.d.ts +1 -1
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +34 -0
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/program.js +12 -0
- package/dist/cli/types/api-responses.d.ts +375 -0
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/types/index.d.ts +83 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/types/index.js +31 -1
- package/dist/cli/utils/daemon.d.ts.map +1 -1
- package/dist/cli/utils/daemon.js +3 -0
- package/dist/cli/utils/env-setup.d.ts +24 -0
- package/dist/cli/utils/env-setup.d.ts.map +1 -1
- package/dist/cli/utils/env-setup.js +70 -0
- package/dist/cli/utils/qr-terminal.d.ts +54 -0
- package/dist/cli/utils/qr-terminal.d.ts.map +1 -0
- package/dist/cli/utils/qr-terminal.js +181 -0
- package/dist/cli/utils/remote-state.d.ts +123 -0
- package/dist/cli/utils/remote-state.d.ts.map +1 -0
- package/dist/cli/utils/remote-state.js +193 -0
- package/dist/cli/utils/vapid-keygen.d.ts +74 -0
- package/dist/cli/utils/vapid-keygen.d.ts.map +1 -0
- package/dist/cli/utils/vapid-keygen.js +111 -0
- package/dist/config/auth-config.d.ts +1 -1
- package/dist/config/auth-config.d.ts.map +1 -1
- package/dist/config/auth-config.js +5 -0
- package/dist/lib/cli-tools/types.d.ts +11 -1
- package/dist/lib/cli-tools/types.d.ts.map +1 -1
- package/dist/lib/detection/tools/verified-against.d.ts +14 -3
- package/dist/lib/detection/tools/verified-against.d.ts.map +1 -1
- package/dist/lib/detection/tools/verified-against.js +14 -3
- package/dist/lib/push/vapid.d.ts +178 -0
- package/dist/lib/push/vapid.d.ts.map +1 -0
- package/dist/lib/push/vapid.js +293 -0
- package/dist/lib/remote/cloudflare.d.ts +285 -0
- package/dist/lib/remote/cloudflare.d.ts.map +1 -0
- package/dist/lib/remote/cloudflare.js +619 -0
- package/dist/lib/remote/index.d.ts +17 -0
- package/dist/lib/remote/index.d.ts.map +1 -0
- package/dist/lib/remote/index.js +64 -0
- package/dist/lib/remote/provider-registry.d.ts +29 -0
- package/dist/lib/remote/provider-registry.d.ts.map +1 -0
- package/dist/lib/remote/provider-registry.js +73 -0
- package/dist/lib/remote/tailscale.d.ts +268 -0
- package/dist/lib/remote/tailscale.d.ts.map +1 -0
- package/dist/lib/remote/tailscale.js +546 -0
- package/dist/lib/remote/types.d.ts +127 -0
- package/dist/lib/remote/types.d.ts.map +1 -0
- package/dist/lib/remote/types.js +53 -0
- package/dist/lib/security/pairing-code.d.ts +182 -0
- package/dist/lib/security/pairing-code.d.ts.map +1 -0
- package/dist/lib/security/pairing-code.js +265 -0
- package/dist/lib/server/localhost-self-check.d.ts +203 -0
- package/dist/lib/server/localhost-self-check.d.ts.map +1 -0
- package/dist/lib/server/localhost-self-check.js +333 -0
- package/dist/server/locales/en/notifications.json +23 -1
- package/dist/server/locales/ja/notifications.json +23 -1
- package/dist/server/server.js +103 -0
- package/dist/server/src/config/auth-config.js +5 -0
- package/dist/server/src/config/image-extensions.js +244 -0
- package/dist/server/src/config/opencode-constants.js +69 -0
- package/dist/server/src/config/tmux-pane-config.js +100 -1
- package/dist/server/src/lib/cli-tools/base.js +33 -48
- package/dist/server/src/lib/cli-tools/opencode-config.js +12 -0
- package/dist/server/src/lib/cli-tools/opencode.js +435 -7
- package/dist/server/src/lib/cli-tools/start-availability.js +160 -0
- package/dist/server/src/lib/cmate-cli-tool-parser.js +328 -7
- package/dist/server/src/lib/cmate-parser.js +12 -0
- package/dist/server/src/lib/db/agent-instances-db.js +129 -0
- package/dist/server/src/lib/db/agent-session-cost-db.js +204 -0
- package/dist/server/src/lib/db/agent-session-cost-sampler.js +194 -0
- package/dist/server/src/lib/db/chat-db.js +33 -0
- package/dist/server/src/lib/db/db-instance.js +11 -0
- package/dist/server/src/lib/db/db.js +8 -3
- package/dist/server/src/lib/db/migrations/index.js +6 -0
- package/dist/server/src/lib/db/migrations/runner.js +1 -1
- package/dist/server/src/lib/db/migrations/v57-push-subscription-defaults-notice.js +54 -0
- package/dist/server/src/lib/db/migrations/v58-agent-session-costs.js +100 -0
- package/dist/server/src/lib/db/migrations/v59-opencode-instance-settings.js +71 -0
- package/dist/server/src/lib/db/push-subscriptions-db.js +56 -5
- package/dist/server/src/lib/detection/cli-patterns.js +17 -6
- package/dist/server/src/lib/detection/excerpt.js +48 -0
- package/dist/server/src/lib/detection/model-info-extractor.js +26 -3
- package/dist/server/src/lib/detection/opencode-modal-overlay.js +400 -0
- package/dist/server/src/lib/detection/opencode-pane-obstruction.js +181 -0
- package/dist/server/src/lib/detection/status-detector.js +7 -0
- package/dist/server/src/lib/detection/status-reason.js +20 -0
- package/dist/server/src/lib/detection/terminal-columns.js +94 -0
- package/dist/server/src/lib/detection/tools/opencode/detect.js +43 -0
- package/dist/server/src/lib/detection/tools/opencode/prompt.js +20 -0
- package/dist/server/src/lib/detection/tools/verified-against.js +14 -3
- package/dist/server/src/lib/detection/upstream-faults.js +7 -22
- package/dist/server/src/lib/hooks/agent-session-telemetry.js +324 -0
- package/dist/server/src/lib/hooks/pending-decision-kind.js +72 -0
- package/dist/server/src/lib/hooks/sources/define-source.js +88 -0
- package/dist/server/src/lib/hooks/sources/opencode/client.js +907 -2
- package/dist/server/src/lib/hooks/sources/opencode/diff.js +336 -0
- package/dist/server/src/lib/hooks/sources/opencode/history.js +480 -0
- package/dist/server/src/lib/hooks/sources/opencode/ingest.js +76 -7
- package/dist/server/src/lib/hooks/sources/opencode/launch-settings.js +222 -0
- package/dist/server/src/lib/hooks/sources/opencode/mappers.js +31 -0
- package/dist/server/src/lib/hooks/sources/opencode/payloads.js +45 -0
- package/dist/server/src/lib/hooks/sources/opencode/ports.js +16 -0
- package/dist/server/src/lib/hooks/sources/opencode/push.js +307 -0
- package/dist/server/src/lib/hooks/sources/opencode/reattach.js +284 -0
- package/dist/server/src/lib/hooks/sources/opencode/runtime.js +165 -2
- package/dist/server/src/lib/hooks/sources/opencode/source.js +46 -2
- package/dist/server/src/lib/hooks/sources/opencode/subscription.js +407 -4
- package/dist/server/src/lib/hooks/sources/opencode/transcript.js +383 -0
- package/dist/server/src/lib/hooks/structured-decision-response.js +460 -0
- package/dist/server/src/lib/job-executor.js +43 -20
- package/dist/server/src/lib/polling/response-checker.js +43 -16
- package/dist/server/src/lib/polling/structured-history-gate.js +75 -0
- package/dist/server/src/lib/prompt-answer-sender.js +153 -2
- package/dist/server/src/lib/push/delivery-health.js +237 -0
- package/dist/server/src/lib/push/failure-push-notifier.js +109 -7
- package/dist/server/src/lib/push/index.js +25 -1
- package/dist/server/src/lib/push/prompt-card-state.js +254 -14
- package/dist/server/src/lib/push/push-sender.js +63 -12
- package/dist/server/src/lib/push/resolution-push-notifier.js +15 -3
- package/dist/server/src/lib/push/vapid.js +264 -5
- package/dist/server/src/lib/push/waiting-push-notifier.js +7 -0
- package/dist/server/src/lib/server/localhost-self-check.js +333 -0
- package/dist/server/src/lib/session/agent-event-state.js +169 -4
- package/dist/server/src/lib/session/claude-executor.js +152 -15
- package/dist/server/src/lib/session/current-output-builder.js +182 -15
- package/dist/server/src/lib/session/opencode-session-api.js +214 -0
- package/dist/server/src/lib/session/opencode-session-recall.js +168 -0
- package/dist/server/src/lib/session/opencode-session-store.js +274 -0
- package/dist/server/src/lib/session/provisional-turn.js +54 -1
- package/dist/server/src/lib/session/send-user-message.js +6 -5
- package/dist/server/src/lib/session/structured-prompt.js +53 -2
- package/dist/server/src/lib/skills/compatibility-matrix.js +50 -1
- package/dist/server/src/lib/tmux/tmux.js +74 -4
- package/dist/server/src/lib/verification/gate-runner.js +71 -8
- package/dist/server/src/types/agent-session.js +63 -0
- package/dist/server/src/types/agent-transcript.js +80 -0
- package/dist/server/src/types/opencode-export.js +228 -0
- package/dist/server/src/types/opencode-instance-settings.js +140 -0
- package/dist/server/src/types/opencode-share.js +111 -0
- package/dist/server/src/types/terminal-keys.js +69 -1
- package/dist/types/cli-tool-contracts.d.ts +48 -0
- package/dist/types/cli-tool-contracts.d.ts.map +1 -1
- package/dist/types/terminal-keys.d.ts +89 -0
- package/dist/types/terminal-keys.d.ts.map +1 -0
- package/dist/types/terminal-keys.js +105 -0
- package/package.json +2 -1
- package/.next/server/chunks/1029.js +0 -1
- package/.next/server/chunks/1239.js +0 -1
- package/.next/server/chunks/1538.js +0 -7
- package/.next/server/chunks/2546.js +0 -1
- package/.next/server/chunks/2689.js +0 -13
- package/.next/server/chunks/3292.js +0 -1
- package/.next/server/chunks/3417.js +0 -1
- package/.next/server/chunks/3736.js +0 -1
- package/.next/server/chunks/4423.js +0 -1
- package/.next/server/chunks/4444.js +0 -32
- package/.next/server/chunks/4565.js +0 -3
- package/.next/server/chunks/467.js +0 -1
- package/.next/server/chunks/4905.js +0 -5
- package/.next/server/chunks/552.js +0 -19
- package/.next/server/chunks/5998.js +0 -74
- package/.next/server/chunks/6919.js +0 -1
- package/.next/server/chunks/7970.js +0 -229
- package/.next/server/chunks/8536.js +0 -1
- package/.next/server/chunks/9284.js +0 -1
- package/.next/static/9IXgWfBUtnEnRqnbmErTp/_buildManifest.js +0 -1
- package/.next/static/chunks/3361-5d6e93fba8a92bc1.js +0 -1
- package/.next/static/chunks/5229-1f5f19740a8d6c11.js +0 -1
- package/.next/static/chunks/6271.295ced91b6335f18.js +0 -1
- package/.next/static/chunks/6381-8cfe50a5ca5425b1.js +0 -1
- package/.next/static/chunks/8521-c43994fb58501d13.js +0 -1
- package/.next/static/chunks/app/api/app/update/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/app/update-check/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/assistant/conversation/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/assistant/current-output/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/assistant/messages/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/assistant/session/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/assistant/start/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/assistant/terminal/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/assistant/tools/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/auth/login/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/auth/logout/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/auth/status/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/capabilities/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/daily-summary/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/daily-summary/status/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/external-apps/[id]/health/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/external-apps/[id]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/external-apps/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/fs/browse/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/fs/recent-paths/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/hooks/agent-event/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/hooks/claude-done/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/hooks/permission-request/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/metrics/vibe/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/ollama/models/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/push/escalation/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/push/subscriptions/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/push/vapid/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/todos/[todoId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/todos/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/clone/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/excluded/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/restore/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/scan/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/sync/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/repositories/validate-path/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/sidebar/group-order/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/skills/[id]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/skills/installations/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/skills/operations/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/skills/reindex/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/skills/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/slash-commands/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/tasks/[taskId]/cancel/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/tasks/[taskId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/templates/[id]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/templates/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/todos/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/verification/runs/[runId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/verification/runs/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/capture/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/clear-composer/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/env/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/logs/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/memos/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/messages/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/resolve-target/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/respond/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/search/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/send/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update-plan/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/start-polling/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tasks/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/timers/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/todos/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tree/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/api/worktrees/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/login/page-adc51f0f7cbb7ac6.js +0 -1
- package/.next/static/chunks/app/manifest.webmanifest/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/more/page-3266dfa945972649.js +0 -1
- package/.next/static/chunks/app/proxy/[...path]/route-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/review/page-8f63aff862fee421.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/layout-6add0d88e2828c23.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-f7b3dfbe757dc6b8.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/terminal/page-a75fe180a7233b2b.js +0 -1
- package/.next/static/chunks/webpack-6a9668cf54a26eba.js +0 -1
- package/.next/static/css/928e5a8830fbf997.css +0 -1
- /package/.next/static/{9IXgWfBUtnEnRqnbmErTp → uulKcSOgyxChTo4SipUSF}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,849 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* remote Command - expose this server to a phone and pair it with a QR code
|
|
4
|
+
* Issue #1937 (R9). Design: `docs/design/remote-qr-pairing-1937.md` §5, §6.2.
|
|
5
|
+
*
|
|
6
|
+
* commandmate remote # up (default): start, publish, show the QR
|
|
7
|
+
* commandmate remote status # Provider / URL / expiry / pairing state
|
|
8
|
+
* commandmate remote stop # close the door, keeping the server running
|
|
9
|
+
*
|
|
10
|
+
* ## What lives here rather than in a Provider (§6.2)
|
|
11
|
+
*
|
|
12
|
+
* Two things, and both for the same reason — they are decisions about an
|
|
13
|
+
* IRREVERSIBLE act (putting this machine on a network it was not on), and a
|
|
14
|
+
* decision buried in a probe helper is a decision nobody reviews:
|
|
15
|
+
*
|
|
16
|
+
* 1. **Which Provider runs.** `detectRemoteProviders()` returns every Provider
|
|
17
|
+
* in preference order and picks none. "Tailscale first, and never fall
|
|
18
|
+
* through to a public tunnel on its own" is a rule about selection, so it
|
|
19
|
+
* is written here, once, as {@link selectProvider}.
|
|
20
|
+
* 2. **Whether a public tunnel may be created at all.** A prompt inside a
|
|
21
|
+
* Provider would have to re-derive interactive-vs-not per Provider, and its
|
|
22
|
+
* answer would be invisible to the caller that has to honour `--yes`.
|
|
23
|
+
*
|
|
24
|
+
* ## What this command deliberately does not have
|
|
25
|
+
*
|
|
26
|
+
* - **`--token`.** `remote` is the side that MINTS a token; one supplied from
|
|
27
|
+
* outside has no hash on the server to match (§5.1).
|
|
28
|
+
* - **`--auto-yes` in any form.** Auto-Yes state is an in-memory map that is
|
|
29
|
+
* empty at server start, so a freshly started server has it off for every
|
|
30
|
+
* worktree. Not offering a flag is what keeps it that way (§5.5); a test
|
|
31
|
+
* pins that the launch env carries no Auto-Yes key either.
|
|
32
|
+
* - **Anything that stops the server on expiry.** `--expires` closes the
|
|
33
|
+
* outside door only. A `commandmate stop` on a timer would take the user's
|
|
34
|
+
* local session down along with the remote one (§5.3).
|
|
35
|
+
*/
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.REMOTE_LAUNCH_ENV_KEYS = exports.PUBLIC_TUNNEL_PROVIDERS = exports.REMOTE_PROVIDER_ALIASES = exports.MAX_PAIRING_TTL_MS = exports.MIN_PAIRING_TTL_MS = exports.DEFAULT_PAIRING_EXPIRES = exports.DEFAULT_REMOTE_EXPIRES = void 0;
|
|
38
|
+
exports.buildRemoteLaunchEnv = buildRemoteLaunchEnv;
|
|
39
|
+
exports.applyRemoteLaunchEnv = applyRemoteLaunchEnv;
|
|
40
|
+
exports.parsePairingDuration = parsePairingDuration;
|
|
41
|
+
exports.selectProvider = selectProvider;
|
|
42
|
+
exports.runRemoteUp = runRemoteUp;
|
|
43
|
+
exports.buildPairingUrl = buildPairingUrl;
|
|
44
|
+
exports.derivePairingState = derivePairingState;
|
|
45
|
+
exports.formatRemaining = formatRemaining;
|
|
46
|
+
exports.runRemoteStatus = runRemoteStatus;
|
|
47
|
+
exports.runRemoteStop = runRemoteStop;
|
|
48
|
+
exports.remoteCommand = remoteCommand;
|
|
49
|
+
exports.createRemoteCommand = createRemoteCommand;
|
|
50
|
+
const commander_1 = require("commander");
|
|
51
|
+
const types_1 = require("../types");
|
|
52
|
+
const security_messages_1 = require("../config/security-messages");
|
|
53
|
+
const daemon_1 = require("../utils/daemon");
|
|
54
|
+
const env_setup_1 = require("../utils/env-setup");
|
|
55
|
+
const logger_1 = require("../utils/logger");
|
|
56
|
+
const prompt_1 = require("../utils/prompt");
|
|
57
|
+
const qr_terminal_1 = require("../utils/qr-terminal");
|
|
58
|
+
const remote_state_1 = require("../utils/remote-state");
|
|
59
|
+
const security_logger_1 = require("../utils/security-logger");
|
|
60
|
+
const server_ready_1 = require("../utils/server-ready");
|
|
61
|
+
const remote_1 = require("../../lib/remote");
|
|
62
|
+
const auth_1 = require("../../lib/security/auth");
|
|
63
|
+
const pairing_code_1 = require("../../lib/security/pairing-code");
|
|
64
|
+
const fs_1 = require("fs");
|
|
65
|
+
const start_1 = require("./start");
|
|
66
|
+
const logger = new logger_1.CLILogger();
|
|
67
|
+
/** Default remote-session TTL. Follows `parseDuration`'s 1h-30d range (§5.1). */
|
|
68
|
+
exports.DEFAULT_REMOTE_EXPIRES = '8h';
|
|
69
|
+
/** Default pairing-code TTL (§5.1). See {@link parsePairingDuration}. */
|
|
70
|
+
exports.DEFAULT_PAIRING_EXPIRES = '10m';
|
|
71
|
+
/** Shortest pairing window: below a minute the QR cannot be scanned in time. */
|
|
72
|
+
exports.MIN_PAIRING_TTL_MS = 60 * 1000;
|
|
73
|
+
/**
|
|
74
|
+
* Longest pairing window.
|
|
75
|
+
*
|
|
76
|
+
* The handoff file holds the plaintext session token until the code is used
|
|
77
|
+
* (§7.2), so this bound is the maximum time that plaintext sits on disk. It is
|
|
78
|
+
* deliberately far below `--expires`' 30-day ceiling.
|
|
79
|
+
*/
|
|
80
|
+
exports.MAX_PAIRING_TTL_MS = 24 * 60 * 60 * 1000;
|
|
81
|
+
/** What the user may type after `--provider`, and what it resolves to. */
|
|
82
|
+
exports.REMOTE_PROVIDER_ALIASES = {
|
|
83
|
+
tailscale: 'tailscale-serve',
|
|
84
|
+
'tailscale-serve': 'tailscale-serve',
|
|
85
|
+
cloudflare: 'cloudflare-quick',
|
|
86
|
+
'cloudflare-quick': 'cloudflare-quick',
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Providers that publish to the open internet rather than to a private network.
|
|
90
|
+
*
|
|
91
|
+
* Membership here is what triggers the explicit approval below, so this list —
|
|
92
|
+
* not a Provider's own opinion of itself — is the thing to check when a
|
|
93
|
+
* Provider is added.
|
|
94
|
+
*/
|
|
95
|
+
exports.PUBLIC_TUNNEL_PROVIDERS = ['cloudflare-quick'];
|
|
96
|
+
/**
|
|
97
|
+
* Every environment variable `remote` adds to the server it starts, and no
|
|
98
|
+
* other (§9.1).
|
|
99
|
+
*
|
|
100
|
+
* All three are already-existing keys or a path:
|
|
101
|
+
*
|
|
102
|
+
* - `CM_AUTH_TOKEN_HASH` / `CM_AUTH_EXPIRE` — what `start --auth` sets.
|
|
103
|
+
* - `CM_REMOTE_PAIRING_FILE` — a PATH, not a secret. The plaintext token and
|
|
104
|
+
* the pairing hash live in the 0600 file it names, because a pane spawned by
|
|
105
|
+
* `src/lib/tmux/**` inherits the server's environment wholesale, so anything
|
|
106
|
+
* put here would be readable by the very agents CommandMate is driving
|
|
107
|
+
* (§7.2).
|
|
108
|
+
*
|
|
109
|
+
* `tests/unit/cli/commands/remote-launch-env-1937.test.ts` holds the measured
|
|
110
|
+
* set to this declaration in BOTH directions, the way
|
|
111
|
+
* `agent-launch-plan-secrets-1933.test.ts` does for `prepareLaunch`. Adding a
|
|
112
|
+
* key without adding it here goes red; so does removing one.
|
|
113
|
+
*/
|
|
114
|
+
exports.REMOTE_LAUNCH_ENV_KEYS = [
|
|
115
|
+
'CM_AUTH_TOKEN_HASH',
|
|
116
|
+
'CM_AUTH_EXPIRE',
|
|
117
|
+
'CM_REMOTE_PAIRING_FILE',
|
|
118
|
+
];
|
|
119
|
+
/**
|
|
120
|
+
* Build the exact environment `remote` contributes to the server it starts.
|
|
121
|
+
*
|
|
122
|
+
* Returned as a plain map rather than written straight into `process.env` so
|
|
123
|
+
* the contribution is a value a test can compare against
|
|
124
|
+
* {@link REMOTE_LAUNCH_ENV_KEYS} — "what did remote add" is otherwise only
|
|
125
|
+
* observable by diffing a global.
|
|
126
|
+
*
|
|
127
|
+
* @param input - Hash, expiry and handoff path
|
|
128
|
+
* @returns The three variables, and nothing else
|
|
129
|
+
*/
|
|
130
|
+
function buildRemoteLaunchEnv(input) {
|
|
131
|
+
return {
|
|
132
|
+
CM_AUTH_TOKEN_HASH: input.authTokenHash,
|
|
133
|
+
CM_AUTH_EXPIRE: input.authExpire,
|
|
134
|
+
CM_REMOTE_PAIRING_FILE: input.pairingFilePath,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Copy the launch env into `process.env`, where `daemon.ts` reads it.
|
|
139
|
+
*
|
|
140
|
+
* `runStart` -> `DaemonManager.start()` builds the child environment from
|
|
141
|
+
* `process.env` plus `.env`, exactly as `start --auth` does, so this is the
|
|
142
|
+
* hand-off point. Note what is NOT here: `CM_BIND` is neither read nor written
|
|
143
|
+
* by `remote`, so a user already running `CM_BIND=0.0.0.0` keeps that setting
|
|
144
|
+
* and a user on the 127.0.0.1 default keeps that one (§9.1).
|
|
145
|
+
*
|
|
146
|
+
* @param env - Output of {@link buildRemoteLaunchEnv}
|
|
147
|
+
* @returns A function restoring the previous values, used on the rollback paths
|
|
148
|
+
*/
|
|
149
|
+
function applyRemoteLaunchEnv(env) {
|
|
150
|
+
const previous = new Map();
|
|
151
|
+
for (const [key, value] of Object.entries(env)) {
|
|
152
|
+
previous.set(key, process.env[key]);
|
|
153
|
+
process.env[key] = value;
|
|
154
|
+
}
|
|
155
|
+
return () => {
|
|
156
|
+
for (const [key, value] of previous) {
|
|
157
|
+
if (value === undefined)
|
|
158
|
+
delete process.env[key];
|
|
159
|
+
else
|
|
160
|
+
process.env[key] = value;
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Parse a `--pairing-expires` duration.
|
|
166
|
+
*
|
|
167
|
+
* `parseDuration()` from `auth-config` is NOT reused here even though `remote`
|
|
168
|
+
* uses it for `--expires`: its floor is 1 hour, and the pairing default is ten
|
|
169
|
+
* minutes. Raising that floor would loosen `CM_AUTH_EXPIRE` for every caller of
|
|
170
|
+
* a shared function, so the short-lived case gets its own bounds instead.
|
|
171
|
+
*
|
|
172
|
+
* @param value - Duration string (`Nm` or `Nh`)
|
|
173
|
+
* @returns Duration in milliseconds
|
|
174
|
+
* @throws Error when the format is wrong or the value is out of range
|
|
175
|
+
*/
|
|
176
|
+
function parsePairingDuration(value) {
|
|
177
|
+
const match = value.match(/^(\d+)([mh])$/);
|
|
178
|
+
if (!match) {
|
|
179
|
+
throw new Error(`Invalid duration format: "${value}". Use Nm or Nh (e.g., "10m", "1h")`);
|
|
180
|
+
}
|
|
181
|
+
const ms = parseInt(match[1], 10) * (match[2] === 'h' ? 60 * 60 * 1000 : 60 * 1000);
|
|
182
|
+
if (ms < exports.MIN_PAIRING_TTL_MS) {
|
|
183
|
+
throw new Error(`Pairing window too short: minimum is 1m. Got: "${value}"`);
|
|
184
|
+
}
|
|
185
|
+
if (ms > exports.MAX_PAIRING_TTL_MS) {
|
|
186
|
+
throw new Error(`Pairing window too long: maximum is 24h. Got: "${value}"`);
|
|
187
|
+
}
|
|
188
|
+
return ms;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Apply the Provider selection rule (§6.2).
|
|
192
|
+
*
|
|
193
|
+
* The rule, in full:
|
|
194
|
+
*
|
|
195
|
+
* - `--provider` names exactly one Provider. An unusable one is an error, not
|
|
196
|
+
* a reason to try another: the user asked for that one.
|
|
197
|
+
* - Without `--provider`, the first READY Provider in preference order wins.
|
|
198
|
+
* Preference order puts Tailscale (private tailnet) ahead of the Cloudflare
|
|
199
|
+
* Quick Tunnel (public internet).
|
|
200
|
+
* - Being chosen is never enough to be started. A Provider in
|
|
201
|
+
* {@link PUBLIC_TUNNEL_PROVIDERS} still has to clear the explicit approval
|
|
202
|
+
* in {@link approvePublicTunnel}, which is what makes "Tailscale failed, so
|
|
203
|
+
* it silently published me to the internet" impossible rather than merely
|
|
204
|
+
* unlikely.
|
|
205
|
+
* - No Provider ready is `DEPENDENCY_ERROR`, never a fallback.
|
|
206
|
+
*
|
|
207
|
+
* Pure: it neither probes nor prompts, so the rule can be tested without a
|
|
208
|
+
* Provider being installed.
|
|
209
|
+
*
|
|
210
|
+
* @param candidates - `detectRemoteProviders()` output, in preference order
|
|
211
|
+
* @param requested - The raw `--provider` value, if any
|
|
212
|
+
* @returns The chosen candidate, or the error to exit with
|
|
213
|
+
*/
|
|
214
|
+
function selectProvider(candidates, requested) {
|
|
215
|
+
const details = candidates.map(({ provider, detection }) => `${provider.id}: ${describeDetection(detection.available, detection.ready)}${detection.reason ? ` (${detection.reason})` : ''}`);
|
|
216
|
+
if (requested !== undefined) {
|
|
217
|
+
const wanted = exports.REMOTE_PROVIDER_ALIASES[requested.trim().toLowerCase()];
|
|
218
|
+
if (wanted === undefined) {
|
|
219
|
+
return {
|
|
220
|
+
error: {
|
|
221
|
+
exitCode: types_1.ExitCode.CONFIG_ERROR,
|
|
222
|
+
message: `Unknown --provider value: "${requested}". Valid values: tailscale, cloudflare.`,
|
|
223
|
+
details: [],
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
const match = candidates.find(({ provider }) => provider.id === wanted);
|
|
228
|
+
if (match === undefined || !match.detection.ready) {
|
|
229
|
+
return {
|
|
230
|
+
error: {
|
|
231
|
+
exitCode: types_1.ExitCode.DEPENDENCY_ERROR,
|
|
232
|
+
message: `Provider "${wanted}" is not usable on this machine.`,
|
|
233
|
+
details,
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
return { candidate: match };
|
|
238
|
+
}
|
|
239
|
+
const ready = candidates.find(({ detection }) => detection.ready);
|
|
240
|
+
if (ready === undefined) {
|
|
241
|
+
return {
|
|
242
|
+
error: {
|
|
243
|
+
exitCode: types_1.ExitCode.DEPENDENCY_ERROR,
|
|
244
|
+
message: 'No remote provider is usable on this machine. Install and log in to Tailscale, or install cloudflared.',
|
|
245
|
+
details,
|
|
246
|
+
},
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
return { candidate: ready };
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* @param available - Whether the executable exists
|
|
253
|
+
* @param ready - Whether it could serve right now
|
|
254
|
+
* @returns A short phrase for the `--provider` diagnosis lines
|
|
255
|
+
*/
|
|
256
|
+
function describeDetection(available, ready) {
|
|
257
|
+
if (!available)
|
|
258
|
+
return 'not installed';
|
|
259
|
+
return ready ? 'ready' : 'installed but not ready';
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Ask before anything public is created.
|
|
263
|
+
*
|
|
264
|
+
* Non-interactive without `--yes` is a refusal, not a silent yes: a scripted
|
|
265
|
+
* invocation must not be able to publish the machine because nobody was there
|
|
266
|
+
* to object (§6.4).
|
|
267
|
+
*
|
|
268
|
+
* @param options - Parsed command options (`--yes`, `--json`)
|
|
269
|
+
* @returns true when the tunnel may be created
|
|
270
|
+
*/
|
|
271
|
+
async function approvePublicTunnel(options) {
|
|
272
|
+
if (options.yes) {
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
if (!(0, prompt_1.isInteractive)()) {
|
|
276
|
+
logger.error(security_messages_1.QUICK_TUNNEL_APPROVAL_REQUIRED);
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
console.log(security_messages_1.QUICK_TUNNEL_APPROVAL_WARNING);
|
|
280
|
+
const approved = await (0, prompt_1.confirm)(security_messages_1.QUICK_TUNNEL_APPROVAL_QUESTION, { default: false });
|
|
281
|
+
(0, prompt_1.closeReadline)();
|
|
282
|
+
if (!approved) {
|
|
283
|
+
logger.info('Aborted. Nothing was exposed.');
|
|
284
|
+
}
|
|
285
|
+
return approved;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* @param url - URL as reported by `runStart`
|
|
289
|
+
* @returns The endpoint, or null when the URL is unusable
|
|
290
|
+
*/
|
|
291
|
+
function parseEndpoint(url) {
|
|
292
|
+
if (url === undefined)
|
|
293
|
+
return null;
|
|
294
|
+
try {
|
|
295
|
+
const parsed = new URL(url);
|
|
296
|
+
const port = parsed.port ? parseInt(parsed.port, 10) : parsed.protocol === 'https:' ? 443 : 80;
|
|
297
|
+
if (Number.isNaN(port))
|
|
298
|
+
return null;
|
|
299
|
+
return { host: parsed.hostname, port };
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return null;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Make sure the server this session starts is one `remote` can pair with.
|
|
307
|
+
*
|
|
308
|
+
* The awkward case is a server that is already running WITH auth: its token
|
|
309
|
+
* hash was fixed from its own environment at startup and CommandMate never kept
|
|
310
|
+
* the plaintext, so there is no cookie value a pairing could hand out, and the
|
|
311
|
+
* environment of a running process cannot be added to (§1.2 C, U-4). Restarting
|
|
312
|
+
* it uninvited would drop live sessions, so this stops and says why.
|
|
313
|
+
*
|
|
314
|
+
* @param daemonManager - Manager for the main server's PID file
|
|
315
|
+
* @param options - Parsed command options (for `--yes` / interactivity)
|
|
316
|
+
* @returns An exit code to stop on, or null to continue
|
|
317
|
+
*/
|
|
318
|
+
async function ensureNoConflictingServer(daemonManager, options) {
|
|
319
|
+
if (!(await daemonManager.isRunning())) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
const status = await daemonManager.getStatus();
|
|
323
|
+
if (status?.auth) {
|
|
324
|
+
logger.error(`A CommandMate server is already running with authentication enabled (PID: ${status.pid}).`);
|
|
325
|
+
logger.info('Its token was fixed at startup and CommandMate did not keep the plaintext, so this session cannot pair with it.');
|
|
326
|
+
logger.info('Stop it with "commandmate stop" and run "commandmate remote" again.');
|
|
327
|
+
return types_1.ExitCode.CONFIG_ERROR;
|
|
328
|
+
}
|
|
329
|
+
logger.warn(`A CommandMate server is already running without authentication (PID: ${status?.pid}).`);
|
|
330
|
+
logger.info('Exposing it remotely requires restarting it with authentication enabled.');
|
|
331
|
+
if (!options.yes) {
|
|
332
|
+
if (!(0, prompt_1.isInteractive)()) {
|
|
333
|
+
logger.error('Refusing to restart the running server without approval. Re-run with --yes, or stop it yourself first.');
|
|
334
|
+
return types_1.ExitCode.CONFIG_ERROR;
|
|
335
|
+
}
|
|
336
|
+
const approved = await (0, prompt_1.confirm)('Stop it and start a new server for this remote session?', {
|
|
337
|
+
default: false,
|
|
338
|
+
});
|
|
339
|
+
(0, prompt_1.closeReadline)();
|
|
340
|
+
if (!approved) {
|
|
341
|
+
logger.info('Aborted. The running server was left alone.');
|
|
342
|
+
return types_1.ExitCode.CONFIG_ERROR;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (!(await daemonManager.stop())) {
|
|
346
|
+
logger.error('Failed to stop the running server.');
|
|
347
|
+
// START_FAILED, not STOP_FAILED: the command the user ran is `remote up`,
|
|
348
|
+
// and what it failed to do is bring up a server it can pair with. §5.2
|
|
349
|
+
// reserves STOP_FAILED for `remote stop`'s own cleanup.
|
|
350
|
+
return types_1.ExitCode.START_FAILED;
|
|
351
|
+
}
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Run the `up` flow: start, publish, pair (§5.3, steps 1-9).
|
|
356
|
+
*
|
|
357
|
+
* @param options - Parsed command options
|
|
358
|
+
* @returns The exit code the caller should terminate with
|
|
359
|
+
*/
|
|
360
|
+
async function runRemoteUp(options) {
|
|
361
|
+
const expires = options.expires ?? exports.DEFAULT_REMOTE_EXPIRES;
|
|
362
|
+
const pairingExpires = options.pairingExpires ?? exports.DEFAULT_PAIRING_EXPIRES;
|
|
363
|
+
let expiresMs;
|
|
364
|
+
try {
|
|
365
|
+
expiresMs = (0, auth_1.parseDuration)(expires);
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
logger.error(`Invalid --expires value: ${(0, types_1.getErrorMessage)(error)}`);
|
|
369
|
+
return types_1.ExitCode.CONFIG_ERROR;
|
|
370
|
+
}
|
|
371
|
+
let pairingTtlMs;
|
|
372
|
+
try {
|
|
373
|
+
pairingTtlMs = parsePairingDuration(pairingExpires);
|
|
374
|
+
}
|
|
375
|
+
catch (error) {
|
|
376
|
+
logger.error(`Invalid --pairing-expires value: ${(0, types_1.getErrorMessage)(error)}`);
|
|
377
|
+
return types_1.ExitCode.CONFIG_ERROR;
|
|
378
|
+
}
|
|
379
|
+
// 1. Probe every Provider, then apply the selection rule here (§6.2).
|
|
380
|
+
const candidates = await (0, remote_1.detectRemoteProviders)();
|
|
381
|
+
const selection = selectProvider(candidates, options.provider);
|
|
382
|
+
if (selection.error !== undefined || selection.candidate === undefined) {
|
|
383
|
+
const failure = selection.error;
|
|
384
|
+
logger.error(failure?.message ?? 'No remote provider is usable on this machine.');
|
|
385
|
+
for (const line of failure?.details ?? []) {
|
|
386
|
+
logger.info(` ${line}`);
|
|
387
|
+
}
|
|
388
|
+
(0, security_logger_1.logSecurityEvent)({
|
|
389
|
+
timestamp: new Date().toISOString(),
|
|
390
|
+
command: 'remote',
|
|
391
|
+
action: 'failure',
|
|
392
|
+
details: `up: no provider selected (${failure?.exitCode ?? types_1.ExitCode.DEPENDENCY_ERROR})`,
|
|
393
|
+
});
|
|
394
|
+
return failure?.exitCode ?? types_1.ExitCode.DEPENDENCY_ERROR;
|
|
395
|
+
}
|
|
396
|
+
const { provider } = selection.candidate;
|
|
397
|
+
logger.success(`Provider: ${provider.id}`);
|
|
398
|
+
if (exports.PUBLIC_TUNNEL_PROVIDERS.includes(provider.id) && !(await approvePublicTunnel(options))) {
|
|
399
|
+
(0, security_logger_1.logSecurityEvent)({
|
|
400
|
+
timestamp: new Date().toISOString(),
|
|
401
|
+
command: 'remote',
|
|
402
|
+
action: 'failure',
|
|
403
|
+
details: `up: public tunnel not approved (${provider.id})`,
|
|
404
|
+
});
|
|
405
|
+
return types_1.ExitCode.CONFIG_ERROR;
|
|
406
|
+
}
|
|
407
|
+
// 2. A server already up cannot be given a pairing file after the fact.
|
|
408
|
+
const daemonManager = new daemon_1.DaemonManager((0, env_setup_1.getPidFilePath)());
|
|
409
|
+
const conflict = await ensureNoConflictingServer(daemonManager, options);
|
|
410
|
+
if (conflict !== null) {
|
|
411
|
+
return conflict;
|
|
412
|
+
}
|
|
413
|
+
// 3/4. Mint the session token and the pairing code. Neither is persisted in
|
|
414
|
+
// plaintext anywhere except the 0600 handoff file, which the server consumes
|
|
415
|
+
// and deletes on the first successful pairing.
|
|
416
|
+
const sessionToken = (0, auth_1.generateToken)();
|
|
417
|
+
const authTokenHash = (0, auth_1.hashToken)(sessionToken);
|
|
418
|
+
const pairing = (0, pairing_code_1.createPairingHandoff)({ ttlMs: pairingTtlMs, sessionToken });
|
|
419
|
+
// 5. Start the server through the existing exit-free core. Not reimplemented:
|
|
420
|
+
// `runStart` already owns .env loading, port allocation and the daemon spawn.
|
|
421
|
+
const restoreEnv = applyRemoteLaunchEnv(buildRemoteLaunchEnv({ authTokenHash, authExpire: expires, pairingFilePath: pairing.filePath }));
|
|
422
|
+
logger.info('Starting the CommandMate server...');
|
|
423
|
+
const started = await (0, start_1.runStart)({ daemon: true, port: options.port });
|
|
424
|
+
if (!started.ok) {
|
|
425
|
+
(0, pairing_code_1.consumePairingHandoff)(pairing.filePath);
|
|
426
|
+
restoreEnv();
|
|
427
|
+
return started.exitCode;
|
|
428
|
+
}
|
|
429
|
+
const endpoint = parseEndpoint(started.url);
|
|
430
|
+
if (endpoint === null) {
|
|
431
|
+
logger.error(`Could not determine the server endpoint from "${started.url}".`);
|
|
432
|
+
await rollback(daemonManager, pairing.filePath, restoreEnv);
|
|
433
|
+
return types_1.ExitCode.START_FAILED;
|
|
434
|
+
}
|
|
435
|
+
// 6. Wait for the listener. Unlike quickstart, a timeout is fatal here: the
|
|
436
|
+
// next step publishes this endpoint, and fronting a socket that never opened
|
|
437
|
+
// hands the user a public URL that answers nothing.
|
|
438
|
+
logger.info('Waiting for the server to become ready...');
|
|
439
|
+
if (!(await (0, server_ready_1.waitForServer)(endpoint.host, endpoint.port))) {
|
|
440
|
+
logger.error('The server did not start listening in time.');
|
|
441
|
+
await rollback(daemonManager, pairing.filePath, restoreEnv);
|
|
442
|
+
return types_1.ExitCode.START_FAILED;
|
|
443
|
+
}
|
|
444
|
+
logger.success(`Server: ${started.url} (pid ${started.pid})`);
|
|
445
|
+
// 7. Open the outside door. The Provider is handed 127.0.0.1 explicitly; it
|
|
446
|
+
// never reads CM_BIND (§9.1).
|
|
447
|
+
let handle;
|
|
448
|
+
try {
|
|
449
|
+
handle = await provider.start({ port: endpoint.port, signal: new AbortController().signal });
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
logger.error(`Provider ${provider.id} failed to start: ${(0, types_1.getErrorMessage)(error)}`);
|
|
453
|
+
await rollback(daemonManager, pairing.filePath, restoreEnv);
|
|
454
|
+
(0, security_logger_1.logSecurityEvent)({
|
|
455
|
+
timestamp: new Date().toISOString(),
|
|
456
|
+
command: 'remote',
|
|
457
|
+
action: 'failure',
|
|
458
|
+
details: `up: provider start failed (${provider.id})`,
|
|
459
|
+
});
|
|
460
|
+
return types_1.ExitCode.START_FAILED;
|
|
461
|
+
}
|
|
462
|
+
logger.success(`URL: ${handle.url}`);
|
|
463
|
+
// 8. Record the handle. Without it `remote stop` has no receipt, and §6.3-4
|
|
464
|
+
// forbids guessing - so a session that cannot be recorded is rolled back
|
|
465
|
+
// rather than left running with no way to prove what it created.
|
|
466
|
+
const now = Date.now();
|
|
467
|
+
const state = {
|
|
468
|
+
schemaVersion: remote_state_1.REMOTE_STATE_SCHEMA_VERSION,
|
|
469
|
+
provider: handle.provider,
|
|
470
|
+
url: handle.url,
|
|
471
|
+
startedAt: new Date(now).toISOString(),
|
|
472
|
+
expiresAt: now + expiresMs,
|
|
473
|
+
pairing: { filePath: pairing.filePath, expiresAt: pairing.expiresAt },
|
|
474
|
+
handle,
|
|
475
|
+
server: { pid: started.pid ?? null, port: endpoint.port },
|
|
476
|
+
};
|
|
477
|
+
try {
|
|
478
|
+
(0, remote_state_1.writeRemoteState)(state);
|
|
479
|
+
}
|
|
480
|
+
catch (error) {
|
|
481
|
+
logger.error(`Failed to record the remote session: ${(0, types_1.getErrorMessage)(error)}`);
|
|
482
|
+
await closeRemoteSession(state);
|
|
483
|
+
await rollback(daemonManager, pairing.filePath, restoreEnv);
|
|
484
|
+
return types_1.ExitCode.START_FAILED;
|
|
485
|
+
}
|
|
486
|
+
// 9. The one and only display of the pairing code.
|
|
487
|
+
const pairingUrl = buildPairingUrl(handle.url, pairing.code);
|
|
488
|
+
if (!options.json) {
|
|
489
|
+
announcePairing(pairingUrl);
|
|
490
|
+
}
|
|
491
|
+
(0, security_logger_1.logSecurityEvent)({
|
|
492
|
+
timestamp: new Date().toISOString(),
|
|
493
|
+
command: 'remote',
|
|
494
|
+
action: 'success',
|
|
495
|
+
// Neither the pairing code nor the token appears here (§5.2).
|
|
496
|
+
details: `up: provider=${handle.provider} port=${endpoint.port}`,
|
|
497
|
+
});
|
|
498
|
+
if (options.json) {
|
|
499
|
+
// NOT a pure-JSON stream, and saying so is better than implying otherwise:
|
|
500
|
+
// `up` runs `runStart`, whose own progress lines go to stdout and which
|
|
501
|
+
// this command does not reimplement. The object below is the LAST line of
|
|
502
|
+
// stdout, so a machine caller reads that line rather than piping the whole
|
|
503
|
+
// stream. `status` and `stop` print nothing else and pipe cleanly.
|
|
504
|
+
console.log(JSON.stringify({
|
|
505
|
+
action: 'up',
|
|
506
|
+
provider: state.provider,
|
|
507
|
+
url: state.url,
|
|
508
|
+
// The one-time display, in the form a machine caller can use. `status`
|
|
509
|
+
// never emits this field - the code is shown by `up` or not at all.
|
|
510
|
+
pairingUrl,
|
|
511
|
+
expiresAt: new Date(state.expiresAt).toISOString(),
|
|
512
|
+
pairing: { expiresAt: new Date(state.pairing.expiresAt).toISOString() },
|
|
513
|
+
server: { pid: state.server.pid, port: state.server.port, url: started.url },
|
|
514
|
+
}, null, 2));
|
|
515
|
+
}
|
|
516
|
+
return types_1.ExitCode.SUCCESS;
|
|
517
|
+
}
|
|
518
|
+
/**
|
|
519
|
+
* Undo a half-finished `up`.
|
|
520
|
+
*
|
|
521
|
+
* The handoff file goes first and unconditionally: it is the only plaintext
|
|
522
|
+
* copy of a token for a server that is about to stop existing.
|
|
523
|
+
*
|
|
524
|
+
* @param daemonManager - Manager for the server started by this invocation
|
|
525
|
+
* @param pairingFilePath - Handoff file to delete
|
|
526
|
+
* @param restoreEnv - Undo for {@link applyRemoteLaunchEnv}
|
|
527
|
+
*/
|
|
528
|
+
async function rollback(daemonManager, pairingFilePath, restoreEnv) {
|
|
529
|
+
(0, pairing_code_1.consumePairingHandoff)(pairingFilePath);
|
|
530
|
+
restoreEnv();
|
|
531
|
+
try {
|
|
532
|
+
await daemonManager.stop();
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
logger.warn(`Could not stop the server that was just started: ${(0, types_1.getErrorMessage)(error)}`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* @param url - Public URL the Provider published
|
|
540
|
+
* @param code - Plaintext pairing code
|
|
541
|
+
* @returns The `/login#code=` URL the QR encodes
|
|
542
|
+
*/
|
|
543
|
+
function buildPairingUrl(url, code) {
|
|
544
|
+
return `${url.replace(/\/+$/, '')}/login#code=${code}`;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
* Print the QR, or the URL when no QR can be shown.
|
|
548
|
+
*
|
|
549
|
+
* `renderQrToTerminal` reports `fits: false` rather than emitting a symbol it
|
|
550
|
+
* knows the terminal will soft-wrap, because a wrapped QR is unscannable. The
|
|
551
|
+
* URL is printed as text ONLY in that case: it carries the pairing code, so
|
|
552
|
+
* putting it in the scrollback of every successful run would leave a live
|
|
553
|
+
* credential in the terminal history for no benefit.
|
|
554
|
+
*
|
|
555
|
+
* @param pairingUrl - The `/login#code=` URL
|
|
556
|
+
*/
|
|
557
|
+
function announcePairing(pairingUrl) {
|
|
558
|
+
const qr = (0, qr_terminal_1.formatQrForTerminal)(pairingUrl, {
|
|
559
|
+
columns: process.stdout.columns,
|
|
560
|
+
color: process.stdout.isTTY === true,
|
|
561
|
+
});
|
|
562
|
+
logger.blank();
|
|
563
|
+
if (qr === null) {
|
|
564
|
+
logger.warn('This terminal is too narrow for a scannable QR code. Open this URL instead:');
|
|
565
|
+
logger.info(` ${pairingUrl}`);
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
console.log(qr);
|
|
569
|
+
logger.info('Scan this with your phone. The code works once, and only until it expires.');
|
|
570
|
+
}
|
|
571
|
+
logger.blank();
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Decide what to report on the `Pairing:` line (§5.4).
|
|
575
|
+
*
|
|
576
|
+
* The absence of the handoff file IS the consumed flag (§7.2) - the route
|
|
577
|
+
* unlinks it between verifying the code and setting the cookie - so absence is
|
|
578
|
+
* reported as `consumed` rather than being guessed at from the clock.
|
|
579
|
+
*
|
|
580
|
+
* @param handoffPresent - Whether the handoff file still exists
|
|
581
|
+
* @param pairingExpiresAt - Epoch ms the code dies at
|
|
582
|
+
* @param now - Epoch ms, injectable for tests
|
|
583
|
+
* @returns The state to display
|
|
584
|
+
*/
|
|
585
|
+
function derivePairingState(handoffPresent, pairingExpiresAt, now = Date.now()) {
|
|
586
|
+
if (!handoffPresent)
|
|
587
|
+
return 'consumed';
|
|
588
|
+
return now > pairingExpiresAt ? 'expired' : 'unused';
|
|
589
|
+
}
|
|
590
|
+
/**
|
|
591
|
+
* Format a millisecond delta the way `remote status` shows expiry.
|
|
592
|
+
*
|
|
593
|
+
* @param ms - Milliseconds remaining; zero or less reads as expired
|
|
594
|
+
* @returns e.g. `in 6h 12m`, or `expired`
|
|
595
|
+
*/
|
|
596
|
+
function formatRemaining(ms) {
|
|
597
|
+
if (ms <= 0)
|
|
598
|
+
return 'expired';
|
|
599
|
+
const minutes = Math.floor(ms / 60000);
|
|
600
|
+
const hours = Math.floor(minutes / 60);
|
|
601
|
+
if (hours === 0)
|
|
602
|
+
return `in ${minutes}m`;
|
|
603
|
+
return `in ${hours}h ${minutes % 60}m`;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Close the outside door for a recorded session.
|
|
607
|
+
*
|
|
608
|
+
* Everything about this routine is shaped by §6.3: the Provider is handed the
|
|
609
|
+
* recorded `RemoteHandle` and nothing else, so it can only undo what
|
|
610
|
+
* CommandMate created; anything the handle also found already in place comes
|
|
611
|
+
* back in `skipped` and is reported rather than removed. The state file is kept
|
|
612
|
+
* when the revert did not complete, so a second `remote stop` can retry.
|
|
613
|
+
*
|
|
614
|
+
* @param state - The recorded session
|
|
615
|
+
* @returns Whether the Provider reverted cleanly, plus what it reported
|
|
616
|
+
*/
|
|
617
|
+
async function closeRemoteSession(state) {
|
|
618
|
+
// The plaintext token goes first, whatever happens to the Provider (§7.4).
|
|
619
|
+
(0, pairing_code_1.consumePairingHandoff)(state.pairing.filePath);
|
|
620
|
+
const provider = (0, remote_1.createRemoteProviders)().find((entry) => entry.id === state.provider);
|
|
621
|
+
if (provider === undefined) {
|
|
622
|
+
return { ok: false, error: `Unknown provider in the state file: ${state.provider}` };
|
|
623
|
+
}
|
|
624
|
+
try {
|
|
625
|
+
const outcome = await provider.stop(state.handle);
|
|
626
|
+
if (outcome.reverted) {
|
|
627
|
+
(0, remote_state_1.removeRemoteState)();
|
|
628
|
+
}
|
|
629
|
+
return { ok: outcome.reverted, outcome };
|
|
630
|
+
}
|
|
631
|
+
catch (error) {
|
|
632
|
+
return { ok: false, error: (0, types_1.getErrorMessage)(error) };
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
/**
|
|
636
|
+
* Report what the outcome of a Provider teardown was.
|
|
637
|
+
*
|
|
638
|
+
* @param outcome - What the Provider said it did
|
|
639
|
+
*/
|
|
640
|
+
function reportStopOutcome(outcome) {
|
|
641
|
+
for (const skipped of outcome?.skipped ?? []) {
|
|
642
|
+
logger.info(` Left alone (existed before this session): ${skipped}`);
|
|
643
|
+
}
|
|
644
|
+
for (const warning of outcome?.warnings ?? []) {
|
|
645
|
+
logger.warn(` ${warning}`);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Run the `status` flow (§5.4).
|
|
650
|
+
*
|
|
651
|
+
* This is also where `--expires` is enforced in Phase 1: `up` starts the server
|
|
652
|
+
* as a daemon and returns, so no `remote` process survives to hold a timer.
|
|
653
|
+
* §5.3 allows either, and "the expiry is judged when `remote status` runs" is
|
|
654
|
+
* the half that works without a resident process. It closes the Provider only -
|
|
655
|
+
* the server keeps running, because the local user is still using it.
|
|
656
|
+
*
|
|
657
|
+
* @param options - Parsed command options
|
|
658
|
+
* @returns The exit code the caller should terminate with
|
|
659
|
+
*/
|
|
660
|
+
async function runRemoteStatus(options) {
|
|
661
|
+
const state = (0, remote_state_1.readRemoteState)();
|
|
662
|
+
const server = await new daemon_1.DaemonManager((0, env_setup_1.getPidFilePath)()).getStatus();
|
|
663
|
+
const now = Date.now();
|
|
664
|
+
if (state === null) {
|
|
665
|
+
if (options.json) {
|
|
666
|
+
console.log(JSON.stringify({ action: 'status', remote: null, server }, null, 2));
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
logger.info('Provider: (none - no remote session recorded)');
|
|
670
|
+
logger.info(`Server: ${describeServer(server)}`);
|
|
671
|
+
}
|
|
672
|
+
return types_1.ExitCode.SUCCESS;
|
|
673
|
+
}
|
|
674
|
+
// Read first: closing an expired session deletes the handoff file, and its
|
|
675
|
+
// absence is what `derivePairingState` reads as "consumed". Asking afterwards
|
|
676
|
+
// would report every expired session as having been paired.
|
|
677
|
+
const pairing = derivePairingState((0, fs_1.existsSync)(state.pairing.filePath), state.pairing.expiresAt, now);
|
|
678
|
+
const expired = now > state.expiresAt;
|
|
679
|
+
let closed = null;
|
|
680
|
+
if (expired) {
|
|
681
|
+
closed = await closeRemoteSession(state);
|
|
682
|
+
}
|
|
683
|
+
if (options.json) {
|
|
684
|
+
console.log(JSON.stringify({
|
|
685
|
+
action: 'status',
|
|
686
|
+
remote: {
|
|
687
|
+
provider: state.provider,
|
|
688
|
+
// The URL is public information; the pairing code and the token are
|
|
689
|
+
// not, and neither appears here or anywhere else in `status` (§5.4).
|
|
690
|
+
url: state.url,
|
|
691
|
+
startedAt: state.startedAt,
|
|
692
|
+
expiresAt: new Date(state.expiresAt).toISOString(),
|
|
693
|
+
expired,
|
|
694
|
+
closed: closed === null ? null : closed.ok,
|
|
695
|
+
pairing: {
|
|
696
|
+
state: pairing,
|
|
697
|
+
expiresAt: new Date(state.pairing.expiresAt).toISOString(),
|
|
698
|
+
},
|
|
699
|
+
},
|
|
700
|
+
server,
|
|
701
|
+
}, null, 2));
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
logger.info(`Provider: ${state.provider}`);
|
|
705
|
+
logger.info(`URL: ${state.url}`);
|
|
706
|
+
logger.info(`Remote expires: ${new Date(state.expiresAt).toISOString()} (${formatRemaining(state.expiresAt - now)})`);
|
|
707
|
+
logger.info(`Pairing: ${pairing}`);
|
|
708
|
+
logger.info(`Server: ${describeServer(server)}`);
|
|
709
|
+
}
|
|
710
|
+
if (closed !== null && !options.json) {
|
|
711
|
+
if (closed.ok) {
|
|
712
|
+
logger.info('The remote session expired and its provider was closed. The server is still running.');
|
|
713
|
+
}
|
|
714
|
+
else {
|
|
715
|
+
logger.warn(`The remote session expired but could not be closed: ${closed.error ?? 'see below'}`);
|
|
716
|
+
reportStopOutcome(closed.outcome);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
return types_1.ExitCode.SUCCESS;
|
|
720
|
+
}
|
|
721
|
+
/**
|
|
722
|
+
* @param server - Daemon status, or null when there is no PID file
|
|
723
|
+
* @returns The `Server:` line
|
|
724
|
+
*/
|
|
725
|
+
function describeServer(server) {
|
|
726
|
+
if (server === null || !server.running)
|
|
727
|
+
return 'stopped';
|
|
728
|
+
return `running (pid ${server.pid}, ${server.url}, auth: ${server.auth ? 'on' : 'off'})`;
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Run the `stop` flow (§6.3-4).
|
|
732
|
+
*
|
|
733
|
+
* With no readable state file this exits SUCCESS having done nothing. That is
|
|
734
|
+
* the point, not a shortcut: the alternative is inferring a Provider and tearing
|
|
735
|
+
* down whatever configuration it currently holds, and for Tailscale Serve that
|
|
736
|
+
* configuration can be the user's own, with no way to restore it. `stop.ts`
|
|
737
|
+
* treats a stale PID file with the same restraint.
|
|
738
|
+
*
|
|
739
|
+
* @param options - Parsed command options
|
|
740
|
+
* @returns The exit code the caller should terminate with
|
|
741
|
+
*/
|
|
742
|
+
async function runRemoteStop(options) {
|
|
743
|
+
const state = (0, remote_state_1.readRemoteState)();
|
|
744
|
+
if (state === null) {
|
|
745
|
+
if (options.json) {
|
|
746
|
+
console.log(JSON.stringify({ action: 'stop', cleaned: false, reason: 'no-remote-state' }, null, 2));
|
|
747
|
+
}
|
|
748
|
+
else {
|
|
749
|
+
logger.info('No remote session is recorded, so there is nothing to clean up.');
|
|
750
|
+
logger.info('Nothing was changed: CommandMate only undoes what it recorded creating.');
|
|
751
|
+
}
|
|
752
|
+
return types_1.ExitCode.SUCCESS;
|
|
753
|
+
}
|
|
754
|
+
const closed = await closeRemoteSession(state);
|
|
755
|
+
if (!options.json) {
|
|
756
|
+
reportStopOutcome(closed.outcome);
|
|
757
|
+
}
|
|
758
|
+
(0, security_logger_1.logSecurityEvent)({
|
|
759
|
+
timestamp: new Date().toISOString(),
|
|
760
|
+
command: 'remote',
|
|
761
|
+
action: closed.ok ? 'success' : 'failure',
|
|
762
|
+
details: `stop: provider=${state.provider} reverted=${closed.ok}`,
|
|
763
|
+
});
|
|
764
|
+
if (options.json) {
|
|
765
|
+
console.log(JSON.stringify({
|
|
766
|
+
action: 'stop',
|
|
767
|
+
cleaned: closed.ok,
|
|
768
|
+
provider: state.provider,
|
|
769
|
+
skipped: closed.outcome?.skipped ?? [],
|
|
770
|
+
warnings: closed.outcome?.warnings ?? [],
|
|
771
|
+
error: closed.error ?? null,
|
|
772
|
+
}, null, 2));
|
|
773
|
+
}
|
|
774
|
+
else if (closed.ok) {
|
|
775
|
+
logger.success(`Closed the ${state.provider} session. The CommandMate server is still running.`);
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
logger.error(`Failed to close the ${state.provider} session${closed.error ? `: ${closed.error}` : '.'}`);
|
|
779
|
+
logger.info('The state file was kept so "commandmate remote stop" can be retried.');
|
|
780
|
+
}
|
|
781
|
+
return closed.ok ? types_1.ExitCode.SUCCESS : types_1.ExitCode.STOP_FAILED;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* Dispatch one `remote` invocation and terminate.
|
|
785
|
+
*
|
|
786
|
+
* The exit-free `run*` functions above are what the tests drive and what a
|
|
787
|
+
* future caller (a `quickstart --remote`, say) would compose, exactly as
|
|
788
|
+
* `runStart` / `startCommand` are split (#1195).
|
|
789
|
+
*
|
|
790
|
+
* @param action - `up` (default), `status` or `stop`
|
|
791
|
+
* @param options - Parsed command options
|
|
792
|
+
*/
|
|
793
|
+
async function remoteCommand(action, options) {
|
|
794
|
+
let exitCode;
|
|
795
|
+
try {
|
|
796
|
+
switch (action ?? 'up') {
|
|
797
|
+
case 'up':
|
|
798
|
+
exitCode = await runRemoteUp(options);
|
|
799
|
+
break;
|
|
800
|
+
case 'status':
|
|
801
|
+
exitCode = await runRemoteStatus(options);
|
|
802
|
+
break;
|
|
803
|
+
case 'stop':
|
|
804
|
+
exitCode = await runRemoteStop(options);
|
|
805
|
+
break;
|
|
806
|
+
default:
|
|
807
|
+
logger.error(`Unknown action '${action}'. Valid actions: up, status, stop.`);
|
|
808
|
+
exitCode = types_1.ExitCode.CONFIG_ERROR;
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
catch (error) {
|
|
812
|
+
logger.error(`remote failed: ${(0, types_1.getErrorMessage)(error)}`);
|
|
813
|
+
(0, security_logger_1.logSecurityEvent)({
|
|
814
|
+
timestamp: new Date().toISOString(),
|
|
815
|
+
command: 'remote',
|
|
816
|
+
action: 'failure',
|
|
817
|
+
details: `unexpected: ${(0, types_1.getErrorMessage)(error)}`,
|
|
818
|
+
});
|
|
819
|
+
exitCode = types_1.ExitCode.UNEXPECTED_ERROR;
|
|
820
|
+
}
|
|
821
|
+
process.exit(exitCode);
|
|
822
|
+
}
|
|
823
|
+
/**
|
|
824
|
+
* Create the remote command.
|
|
825
|
+
* [DR1-08] Factory pattern for addCommand() registration, as `createSyncCommand()`
|
|
826
|
+
* and `createInstancesCommand()` do. `instances`' shape is followed too - a
|
|
827
|
+
* default action with the verb as an optional positional - the only difference
|
|
828
|
+
* being that the default here is `up` rather than a listing.
|
|
829
|
+
*
|
|
830
|
+
* @returns The configured commander command
|
|
831
|
+
*/
|
|
832
|
+
function createRemoteCommand() {
|
|
833
|
+
const cmd = new commander_1.Command('remote');
|
|
834
|
+
cmd
|
|
835
|
+
.description('Expose this server to your phone over a provider tunnel and pair it with a QR code')
|
|
836
|
+
.argument('[action]', 'up (default), status, or stop')
|
|
837
|
+
.option('--provider <name>', 'Force a provider instead of choosing one (tailscale or cloudflare)')
|
|
838
|
+
.option('--expires <duration>', `Remote session TTL, 1h-30d (default: ${exports.DEFAULT_REMOTE_EXPIRES})`)
|
|
839
|
+
.option('--pairing-expires <duration>', `Pairing code TTL, 1m-24h (default: ${exports.DEFAULT_PAIRING_EXPIRES})`)
|
|
840
|
+
.option('-p, --port <number>', 'Port for the server to expose', parseInt)
|
|
841
|
+
.option('--yes', 'Approve creating a public tunnel without prompting (required when non-interactive)')
|
|
842
|
+
.option('--json', 'JSON output')
|
|
843
|
+
// Deliberately absent: --token (remote mints its own; see the file header)
|
|
844
|
+
// and every --auto-yes flag (§5.5).
|
|
845
|
+
.action(async (action, options) => {
|
|
846
|
+
await remoteCommand(action, options);
|
|
847
|
+
});
|
|
848
|
+
return cmd;
|
|
849
|
+
}
|