commandmate 0.43.0 → 0.44.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +357 -361
- package/.next/app-path-routes-manifest.json +33 -33
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +3 -3
- package/.next/react-loadable-manifest.json +3 -3
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route.js +2 -2
- 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.js.nft.json +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.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_client-reference-manifest.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.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.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.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.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.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.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.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 +2 -2
- 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.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.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/relays/[relayId]/cancel/route.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route.js +1 -1
- package/.next/server/app/api/relays/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route.js +2 -2
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.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/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.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.nft.json +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.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 +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 +2 -2
- 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 +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.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.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.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.nft.json +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.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.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-reference/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.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.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 +1 -1
- 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]/direct-input/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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/notes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- 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.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.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 +7 -7
- 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.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.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.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.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- 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.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.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.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.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 +1 -1
- 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 +3 -3
- 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.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]/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 +103 -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.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 -1
- 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.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.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.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.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.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/config/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/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]/cancel/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.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.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.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/apply-default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/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/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_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.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_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page.js.nft.json +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page.js +1 -1
- package/.next/server/app/skills/[skillId]/page.js.nft.json +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 +9 -9
- 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 +1 -1
- 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 +33 -33
- package/.next/server/chunks/1068.js +1 -1
- package/.next/server/chunks/1501.js +3 -3
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2283.js +15 -0
- package/.next/server/chunks/2328.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/2816.js +1 -1
- package/.next/server/chunks/4207.js +1 -1
- package/.next/server/chunks/4802.js +1 -1
- package/.next/server/chunks/488.js +1 -0
- package/.next/server/chunks/5326.js +1 -1
- package/.next/server/chunks/5456.js +1 -1
- package/.next/server/chunks/611.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6474.js +14 -0
- package/.next/server/chunks/650.js +1 -0
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/{5742.js → 6927.js} +1 -1
- package/.next/server/chunks/7506.js +1 -1
- package/.next/server/chunks/7685.js +1 -1
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8543.js +1 -1
- package/.next/server/chunks/8581.js +2 -2
- package/.next/server/chunks/8728.js +2 -2
- package/.next/server/chunks/8782.js +1 -0
- package/.next/server/chunks/8791.js +1 -1
- package/.next/server/chunks/8918.js +105 -3
- package/.next/server/chunks/9130.js +1 -1
- package/.next/server/chunks/9390.js +1 -1
- package/.next/server/chunks/967.js +1 -1
- package/.next/server/chunks/9731.js +3 -3
- package/.next/server/chunks/9882.js +3 -3
- 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 +2 -2
- package/.next/server/src/middleware.js.map +1 -1
- package/.next/static/chunks/{1642-767aed8e7c61ef7f.js → 1642-fb2e176aaadbd137.js} +1 -1
- package/.next/static/chunks/2053-85a974ddfe7498fe.js +1 -0
- package/.next/static/chunks/{2407-940df9b11fadafc6.js → 2407-f1f258d4a1d92620.js} +1 -1
- package/.next/static/chunks/{2619-a305ad4810f1393a.js → 2619-04bc32f026a0d946.js} +1 -1
- package/.next/static/chunks/344-e1cefd00787060e4.js +1 -0
- package/.next/static/chunks/3922.f45dcfc1e7da552a.js +1 -0
- package/.next/static/chunks/5521-c358c31f60e5e689.js +1 -0
- package/.next/static/chunks/591-308072f285c34787.js +1 -0
- package/.next/static/chunks/6654-ac431270fac1a283.js +1 -0
- package/.next/static/chunks/{8165-3525fb42f1b4976e.js → 8165-3853772f6ae1299b.js} +1 -1
- package/.next/static/chunks/{8566-a6a7c70558927410.js → 8566-aeda747542072ace.js} +1 -1
- package/.next/static/chunks/8811-29eaa24237f48558.js +1 -0
- package/.next/static/chunks/{9619-22adf5367c4b7080.js → 9619-6c17a271f7f98fbb.js} +1 -1
- package/.next/static/chunks/998-2eb5883186abd0bd.js +1 -0
- package/.next/static/chunks/app/layout-da66300cc20244ed.js +1 -0
- package/.next/static/chunks/app/more/{page-30057cf1e0762ad2.js → page-87c84987b2765213.js} +1 -1
- package/.next/static/chunks/app/{page-8483ba400af011f5.js → page-1b820c421db48c2c.js} +1 -1
- package/.next/static/chunks/app/review/page-95f749caae382f46.js +1 -0
- package/.next/static/chunks/app/sessions/page-049e06335187aa91.js +1 -0
- package/.next/static/chunks/app/skills/[skillId]/{page-74aac15286504ef4.js → page-9ee7a381636e60cb.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/page-040c5f0f585e6812.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/{page-c601f3b3ece6557e.js → page-373ea37b16d930c7.js} +1 -1
- package/.next/static/chunks/{webpack-49ade0526854dd4e.js → webpack-021f0741f22dd16a.js} +1 -1
- package/.next/static/css/38070d879efa1371.css +1 -0
- package/.next/trace +13 -13
- package/README.md +90 -605
- package/dist/cli/commands/capture.d.ts.map +1 -1
- package/dist/cli/commands/capture.js +11 -1
- package/dist/cli/commands/docs.d.ts.map +1 -1
- package/dist/cli/commands/docs.js +5 -0
- package/dist/cli/commands/remote.d.ts +34 -1
- package/dist/cli/commands/remote.d.ts.map +1 -1
- package/dist/cli/commands/remote.js +171 -6
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +255 -112
- package/dist/cli/commands/stop.d.ts.map +1 -1
- package/dist/cli/commands/stop.js +53 -1
- package/dist/cli/commands/sync.js +3 -3
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +11 -0
- package/dist/cli/docs/setup-guide.d.ts +14 -0
- package/dist/cli/docs/setup-guide.d.ts.map +1 -0
- package/dist/cli/docs/setup-guide.js +368 -0
- package/dist/cli/types/api-responses.d.ts +21 -0
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/types/index.d.ts +2 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/utils/daemon.d.ts +42 -2
- package/dist/cli/utils/daemon.d.ts.map +1 -1
- package/dist/cli/utils/daemon.js +222 -40
- package/dist/cli/utils/docs-reader.d.ts +6 -0
- package/dist/cli/utils/docs-reader.d.ts.map +1 -1
- package/dist/cli/utils/docs-reader.js +14 -13
- package/dist/cli/utils/npm-runner.d.ts +12 -0
- package/dist/cli/utils/npm-runner.d.ts.map +1 -1
- package/dist/cli/utils/npm-runner.js +36 -0
- package/dist/cli/utils/process-inspect.d.ts +55 -0
- package/dist/cli/utils/process-inspect.d.ts.map +1 -0
- package/dist/cli/utils/process-inspect.js +214 -0
- package/dist/cli/utils/remote-pairing.d.ts +68 -0
- package/dist/cli/utils/remote-pairing.d.ts.map +1 -0
- package/dist/cli/utils/remote-pairing.js +117 -0
- package/dist/cli/utils/server-identity.d.ts +50 -0
- package/dist/cli/utils/server-identity.d.ts.map +1 -0
- package/dist/cli/utils/server-identity.js +118 -0
- package/dist/cli/utils/server-ready.d.ts +13 -0
- package/dist/cli/utils/server-ready.d.ts.map +1 -1
- package/dist/cli/utils/server-ready.js +16 -0
- package/dist/lib/detection/status-reason.d.ts +17 -0
- package/dist/lib/detection/status-reason.d.ts.map +1 -1
- package/dist/lib/detection/status-reason.js +17 -0
- package/dist/lib/security/pairing-code.d.ts +2 -1
- package/dist/lib/security/pairing-code.d.ts.map +1 -1
- package/dist/server/locales/en/worktree.json +41 -7
- package/dist/server/locales/ja/worktree.json +41 -7
- package/dist/server/src/config/image-extensions.js +1 -0
- package/dist/server/src/config/session-starting-config.js +75 -0
- package/dist/server/src/lib/auto-yes-poller.js +22 -0
- package/dist/server/src/lib/cli-tools/antigravity.js +2 -1
- package/dist/server/src/lib/cli-tools/base.js +15 -1
- package/dist/server/src/lib/cli-tools/codex.js +3 -2
- package/dist/server/src/lib/cli-tools/command-code-plan-review.js +175 -0
- package/dist/server/src/lib/cli-tools/command-code.js +30 -4
- package/dist/server/src/lib/cli-tools/copilot.js +2 -1
- package/dist/server/src/lib/cli-tools/gemini.js +2 -1
- package/dist/server/src/lib/cli-tools/liveness-spec.js +27 -9
- package/dist/server/src/lib/cli-tools/opencode-v2.js +2 -1
- package/dist/server/src/lib/cli-tools/opencode.js +2 -1
- package/dist/server/src/lib/cli-tools/vibe-local.js +2 -1
- package/dist/server/src/lib/detection/cli-patterns.js +94 -1
- package/dist/server/src/lib/detection/status-reason.js +17 -0
- package/dist/server/src/lib/detection/tool-liveness.js +3 -1
- package/dist/server/src/lib/detection/tools/codex/detect.js +26 -0
- package/dist/server/src/lib/detection/tools/command-code/plan-review-state.js +75 -0
- package/dist/server/src/lib/hooks/sources/claude/transcript.js +33 -1
- package/dist/server/src/lib/realtime/terminal-broadcast.js +5 -0
- package/dist/server/src/lib/session/agent-session-lifecycle.js +11 -0
- package/dist/server/src/lib/session/claude-executor.js +2 -2
- package/dist/server/src/lib/session/claude-session.js +138 -16
- package/dist/server/src/lib/session/current-output-builder.js +49 -21
- package/dist/server/src/lib/session/launch-screen.js +57 -0
- package/dist/server/src/lib/session/session-start-error.js +20 -0
- package/dist/server/src/lib/session/session-starting-state.js +236 -0
- package/dist/server/src/lib/skills/agent-state-paths.js +39 -0
- package/dist/server/src/lib/skills/receipt-owned-paths.js +118 -0
- package/dist/server/src/lib/tmux/tmux.js +25 -0
- package/dist/server/src/lib/verification/env-clean-gate.js +195 -6
- package/dist/server/src/lib/verification/gate-runner.js +29 -2
- package/dist/server/src/lib/verification/scope-gate.js +58 -4
- package/docs/en/architecture.md +722 -0
- package/docs/en/user-guide/agents-guide.md +306 -0
- package/docs/en/user-guide/cli-setup-guide.md +676 -0
- package/docs/en/user-guide/cmate-schedules-guide.md +388 -0
- package/docs/en/user-guide/commands-guide.md +467 -0
- package/docs/en/user-guide/quick-start.md +231 -0
- package/docs/en/user-guide/webapp-guide.md +1020 -0
- package/docs/en/user-guide/workflow-examples.md +463 -0
- package/package.json +18 -7
- package/release-notes/0.44.0.json +82 -0
- package/release-notes/0.44.1.json +54 -0
- package/.next/server/chunks/1990.js +0 -103
- package/.next/server/chunks/3707.js +0 -15
- package/.next/server/chunks/6491.js +0 -103
- package/.next/server/chunks/7004.js +0 -1
- package/.next/server/chunks/8673.js +0 -14
- package/.next/static/chunks/2039-117a361f795ddc4b.js +0 -1
- package/.next/static/chunks/2053-611dd27d42721b79.js +0 -1
- package/.next/static/chunks/344-6f9fc1f38f01a839.js +0 -1
- package/.next/static/chunks/3778-56f41fc2cecb8c43.js +0 -1
- package/.next/static/chunks/3922.8e79fc89f593280b.js +0 -1
- package/.next/static/chunks/5449-6cb80bab2bd06b79.js +0 -1
- package/.next/static/chunks/6966-bb854d1145783a64.js +0 -1
- package/.next/static/chunks/7705-1f58d4c03d991fcf.js +0 -1
- package/.next/static/chunks/app/layout-057c850cd0df978e.js +0 -1
- package/.next/static/chunks/app/review/page-ff9efae3f86eb840.js +0 -1
- package/.next/static/chunks/app/sessions/page-1a8ba152bbcb9efb.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-eab0bf7564d3f9e2.js +0 -1
- package/.next/static/css/b3f433d52b8ed5c8.css +0 -1
- /package/.next/static/{BVkBYdceLRvMROqQIqeBx → 57lOiz8zSEHdw97XIm0af}/_buildManifest.js +0 -0
- /package/.next/static/{BVkBYdceLRvMROqQIqeBx → 57lOiz8zSEHdw97XIm0af}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Best-effort process inspection for stop/start (Issue #3087)
|
|
4
|
+
*
|
|
5
|
+
* - Zombies: `kill(pid, 0)` succeeds for a zombie, so without an init process
|
|
6
|
+
* (a container whose PID 1 never reaps) a stopped server's group looked alive
|
|
7
|
+
* forever. On Linux, /proc tells a zombie apart; elsewhere nothing is known
|
|
8
|
+
* and callers keep their signal-based answer.
|
|
9
|
+
* - Listeners: when something answers on the configured port but is not the
|
|
10
|
+
* server the PID file describes, the user is told which PID holds it.
|
|
11
|
+
*
|
|
12
|
+
* Every function here is read-only and never throws.
|
|
13
|
+
*
|
|
14
|
+
* @module process-inspect
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.parseProcStat = parseProcStat;
|
|
18
|
+
exports.isZombieProcess = isZombieProcess;
|
|
19
|
+
exports.listProcessGroupStates = listProcessGroupStates;
|
|
20
|
+
exports.isExitedState = isExitedState;
|
|
21
|
+
exports.findListeningPids = findListeningPids;
|
|
22
|
+
exports.describeProcess = describeProcess;
|
|
23
|
+
exports.describeListeners = describeListeners;
|
|
24
|
+
const child_process_1 = require("child_process");
|
|
25
|
+
const fs_1 = require("fs");
|
|
26
|
+
/** Process states that are no longer running code: zombie and dead. */
|
|
27
|
+
const EXITED_STATES = new Set(['Z', 'X', 'x']);
|
|
28
|
+
/**
|
|
29
|
+
* Parse `/proc/<pid>/stat`. The command name is parenthesised and may itself
|
|
30
|
+
* contain spaces or parentheses, so fields are read after the LAST `)`.
|
|
31
|
+
*/
|
|
32
|
+
function parseProcStat(content) {
|
|
33
|
+
const end = content.lastIndexOf(')');
|
|
34
|
+
if (end === -1)
|
|
35
|
+
return null;
|
|
36
|
+
const fields = content.slice(end + 1).trim().split(/\s+/);
|
|
37
|
+
// fields[0] = state, fields[1] = ppid, fields[2] = pgrp
|
|
38
|
+
const pgrp = parseInt(fields[2] ?? '', 10);
|
|
39
|
+
if (!fields[0] || Number.isNaN(pgrp))
|
|
40
|
+
return null;
|
|
41
|
+
return { state: fields[0], pgrp };
|
|
42
|
+
}
|
|
43
|
+
function readProcStat(pid) {
|
|
44
|
+
try {
|
|
45
|
+
return parseProcStat((0, fs_1.readFileSync)(`/proc/${pid}/stat`, 'utf-8'));
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* @returns true when /proc reports the process as a zombie (or dead); false when it is
|
|
53
|
+
* running, absent, or the platform has no /proc
|
|
54
|
+
*/
|
|
55
|
+
function isZombieProcess(pid) {
|
|
56
|
+
if (process.platform !== 'linux')
|
|
57
|
+
return false;
|
|
58
|
+
const stat = readProcStat(pid);
|
|
59
|
+
return stat !== null && EXITED_STATES.has(stat.state);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* States of every process whose process group is `pgid`.
|
|
63
|
+
*
|
|
64
|
+
* @returns the state letters (possibly empty), or null when /proc cannot be read
|
|
65
|
+
* (non-Linux), in which case nothing is known
|
|
66
|
+
*/
|
|
67
|
+
function listProcessGroupStates(pgid) {
|
|
68
|
+
if (process.platform !== 'linux')
|
|
69
|
+
return null;
|
|
70
|
+
let entries;
|
|
71
|
+
try {
|
|
72
|
+
entries = (0, fs_1.readdirSync)('/proc');
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
if (!Array.isArray(entries))
|
|
78
|
+
return null;
|
|
79
|
+
const states = [];
|
|
80
|
+
for (const entry of entries) {
|
|
81
|
+
if (!/^\d+$/.test(entry))
|
|
82
|
+
continue;
|
|
83
|
+
const stat = readProcStat(parseInt(entry, 10));
|
|
84
|
+
if (stat !== null && stat.pgrp === pgid) {
|
|
85
|
+
states.push(stat.state);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return states;
|
|
89
|
+
}
|
|
90
|
+
/** @returns true when a /proc state letter means the process no longer runs */
|
|
91
|
+
function isExitedState(state) {
|
|
92
|
+
return EXITED_STATES.has(state);
|
|
93
|
+
}
|
|
94
|
+
/** Socket inodes listening on `port` per /proc/net/tcp{,6} (state 0A = LISTEN). */
|
|
95
|
+
function listeningInodes(port) {
|
|
96
|
+
const inodes = new Set();
|
|
97
|
+
const hexPort = port.toString(16).toUpperCase().padStart(4, '0');
|
|
98
|
+
for (const table of ['/proc/net/tcp', '/proc/net/tcp6']) {
|
|
99
|
+
let content;
|
|
100
|
+
try {
|
|
101
|
+
content = (0, fs_1.readFileSync)(table, 'utf-8');
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
for (const line of String(content).split('\n').slice(1)) {
|
|
107
|
+
const fields = line.trim().split(/\s+/);
|
|
108
|
+
// sl local_address rem_address st tx:rx tr:when retrnsmt uid timeout inode
|
|
109
|
+
if (fields.length < 10)
|
|
110
|
+
continue;
|
|
111
|
+
const localPort = fields[1].split(':')[1];
|
|
112
|
+
if (localPort === hexPort && fields[3] === '0A') {
|
|
113
|
+
inodes.add(fields[9]);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return inodes;
|
|
118
|
+
}
|
|
119
|
+
function findListeningPidsLinux(port) {
|
|
120
|
+
const inodes = listeningInodes(port);
|
|
121
|
+
if (inodes.size === 0)
|
|
122
|
+
return [];
|
|
123
|
+
const pids = [];
|
|
124
|
+
let entries;
|
|
125
|
+
try {
|
|
126
|
+
entries = (0, fs_1.readdirSync)('/proc');
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
for (const entry of entries) {
|
|
132
|
+
if (!/^\d+$/.test(entry))
|
|
133
|
+
continue;
|
|
134
|
+
let fds;
|
|
135
|
+
try {
|
|
136
|
+
fds = (0, fs_1.readdirSync)(`/proc/${entry}/fd`);
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
continue; // not ours to read, or gone
|
|
140
|
+
}
|
|
141
|
+
for (const fd of fds) {
|
|
142
|
+
let target;
|
|
143
|
+
try {
|
|
144
|
+
target = (0, fs_1.readlinkSync)(`/proc/${entry}/fd/${fd}`);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const match = /^socket:\[(\d+)\]$/.exec(target);
|
|
150
|
+
if (match && inodes.has(match[1])) {
|
|
151
|
+
pids.push(parseInt(entry, 10));
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return pids;
|
|
157
|
+
}
|
|
158
|
+
function findListeningPidsLsof(port) {
|
|
159
|
+
try {
|
|
160
|
+
const out = (0, child_process_1.execFileSync)('lsof', ['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-t'], {
|
|
161
|
+
encoding: 'utf-8',
|
|
162
|
+
timeout: 3000,
|
|
163
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
164
|
+
});
|
|
165
|
+
return [...new Set(String(out).split('\n').map((l) => parseInt(l, 10)).filter((n) => !Number.isNaN(n)))];
|
|
166
|
+
}
|
|
167
|
+
catch {
|
|
168
|
+
return []; // lsof exits 1 when nothing matches, or is not installed
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* PIDs listening on a TCP port: /proc on Linux, `lsof` elsewhere.
|
|
173
|
+
*
|
|
174
|
+
* @returns the PIDs found; empty when none are visible (another user's process, or no tool)
|
|
175
|
+
*/
|
|
176
|
+
function findListeningPids(port) {
|
|
177
|
+
return process.platform === 'linux' ? findListeningPidsLinux(port) : findListeningPidsLsof(port);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* One-line description of a process for an error message.
|
|
181
|
+
*
|
|
182
|
+
* @returns the command line, or null when it cannot be read
|
|
183
|
+
*/
|
|
184
|
+
function describeProcess(pid) {
|
|
185
|
+
try {
|
|
186
|
+
if (process.platform === 'linux') {
|
|
187
|
+
const cmdline = (0, fs_1.readFileSync)(`/proc/${pid}/cmdline`, 'utf-8').split('\0').filter(Boolean).join(' ');
|
|
188
|
+
return cmdline || null;
|
|
189
|
+
}
|
|
190
|
+
const out = (0, child_process_1.execFileSync)('ps', ['-o', 'command=', '-p', String(pid)], {
|
|
191
|
+
encoding: 'utf-8',
|
|
192
|
+
timeout: 3000,
|
|
193
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
194
|
+
}).trim();
|
|
195
|
+
return out || null;
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* "PID 875 (node dist/server/server.js), PID 876" — or null when no PID is visible.
|
|
203
|
+
*/
|
|
204
|
+
function describeListeners(port) {
|
|
205
|
+
const pids = findListeningPids(port);
|
|
206
|
+
if (pids.length === 0)
|
|
207
|
+
return null;
|
|
208
|
+
return pids
|
|
209
|
+
.map((pid) => {
|
|
210
|
+
const command = describeProcess(pid);
|
|
211
|
+
return command ? `PID ${pid} (${command.slice(0, 120)})` : `PID ${pid}`;
|
|
212
|
+
})
|
|
213
|
+
.join(', ');
|
|
214
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-issue the pairing code of a live `commandmate remote` session (Issue #3127).
|
|
3
|
+
*
|
|
4
|
+
* `remote up` shows the pairing link once, as a QR code, and keeps only the
|
|
5
|
+
* code's HASH on disk (`pairing-code.ts`). When that QR is lost — an agent's
|
|
6
|
+
* chat pane folds the output and cuts the QR off — the link cannot be shown
|
|
7
|
+
* again, because the plaintext code no longer exists anywhere. Before this
|
|
8
|
+
* module the only way back was `remote stop` + `remote`, which tears the
|
|
9
|
+
* Provider down and publishes a NEW URL.
|
|
10
|
+
*
|
|
11
|
+
* What this does instead: mint a fresh code and swap its hash into the
|
|
12
|
+
* existing handoff file, keeping the session token and the expiry. Nothing
|
|
13
|
+
* else changes — the server, the Provider and the public URL are untouched,
|
|
14
|
+
* and no new way in is created. The previous code stops working, because its
|
|
15
|
+
* hash is gone.
|
|
16
|
+
*
|
|
17
|
+
* ## Why the file is renamed away first
|
|
18
|
+
*
|
|
19
|
+
* The consumed flag is the ABSENCE of the handoff file: the server unlinks it
|
|
20
|
+
* on a successful pairing. A plain read-modify-write races with that — a
|
|
21
|
+
* pairing landing between our read and our write would see the file deleted,
|
|
22
|
+
* then recreated by us, and the already-paired session token would become
|
|
23
|
+
* pairable a second time. Renaming the file to a private name first is an
|
|
24
|
+
* atomic claim: if the rename fails with ENOENT the code was spent and we stop;
|
|
25
|
+
* if it succeeds the server can no longer consume it (it sees "absent", which
|
|
26
|
+
* answers 410 for the old code — the code we are about to replace anyway).
|
|
27
|
+
*
|
|
28
|
+
* ## Fail-closed
|
|
29
|
+
*
|
|
30
|
+
* Anything unreadable, malformed or already expired yields no code. A failure
|
|
31
|
+
* after the claim deletes the claimed file rather than guessing, so the worst
|
|
32
|
+
* case is "pairing is gone, run `remote stop` and `remote` again", never "a
|
|
33
|
+
* spent token is pairable again".
|
|
34
|
+
*/
|
|
35
|
+
/** Why no new code was issued. */
|
|
36
|
+
export type PairingReissueFailure =
|
|
37
|
+
/** The handoff file is absent: the code was used (or never written). */
|
|
38
|
+
'consumed'
|
|
39
|
+
/** The code's window has closed. */
|
|
40
|
+
| 'expired'
|
|
41
|
+
/** The file exists but could not be claimed or parsed. */
|
|
42
|
+
| 'unreadable'
|
|
43
|
+
/** Claimed, but the new code could not be written. The pairing is gone. */
|
|
44
|
+
| 'write-failed';
|
|
45
|
+
export type PairingReissueResult = {
|
|
46
|
+
ok: true;
|
|
47
|
+
/** Plaintext pairing code. Never persisted; the caller shows it and drops it. */
|
|
48
|
+
code: string;
|
|
49
|
+
/** Epoch ms, unchanged from the original code. */
|
|
50
|
+
expiresAt: number;
|
|
51
|
+
} | {
|
|
52
|
+
ok: false;
|
|
53
|
+
reason: PairingReissueFailure;
|
|
54
|
+
};
|
|
55
|
+
/**
|
|
56
|
+
* @param filePath - Handoff file
|
|
57
|
+
* @returns The private name the file is claimed under while it is rewritten
|
|
58
|
+
*/
|
|
59
|
+
export declare function getReissueClaimPath(filePath: string): string;
|
|
60
|
+
/**
|
|
61
|
+
* Replace the pairing code of an unused handoff file with a fresh one.
|
|
62
|
+
*
|
|
63
|
+
* @param filePath - Absolute path of the handoff file (`state.pairing.filePath`)
|
|
64
|
+
* @param now - Epoch ms, injectable for tests
|
|
65
|
+
* @returns The new code and its (unchanged) expiry, or why there is none
|
|
66
|
+
*/
|
|
67
|
+
export declare function reissuePairingCode(filePath: string, now?: number): PairingReissueResult;
|
|
68
|
+
//# sourceMappingURL=remote-pairing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-pairing.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/remote-pairing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAYH,kCAAkC;AAClC,MAAM,MAAM,qBAAqB;AAC/B,wEAAwE;AACtE,UAAU;AACZ,oCAAoC;GAClC,SAAS;AACX,0DAA0D;GACxD,YAAY;AACd,2EAA2E;GACzE,cAAc,CAAC;AAEnB,MAAM,MAAM,oBAAoB,GAC5B;IACE,EAAE,EAAE,IAAI,CAAC;IACT,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;IACb,kDAAkD;IAClD,SAAS,EAAE,MAAM,CAAC;CACnB,GACD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,qBAAqB,CAAA;CAAE,CAAC;AAEjD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AA+BD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,oBAAoB,CAmCnG"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Re-issue the pairing code of a live `commandmate remote` session (Issue #3127).
|
|
4
|
+
*
|
|
5
|
+
* `remote up` shows the pairing link once, as a QR code, and keeps only the
|
|
6
|
+
* code's HASH on disk (`pairing-code.ts`). When that QR is lost — an agent's
|
|
7
|
+
* chat pane folds the output and cuts the QR off — the link cannot be shown
|
|
8
|
+
* again, because the plaintext code no longer exists anywhere. Before this
|
|
9
|
+
* module the only way back was `remote stop` + `remote`, which tears the
|
|
10
|
+
* Provider down and publishes a NEW URL.
|
|
11
|
+
*
|
|
12
|
+
* What this does instead: mint a fresh code and swap its hash into the
|
|
13
|
+
* existing handoff file, keeping the session token and the expiry. Nothing
|
|
14
|
+
* else changes — the server, the Provider and the public URL are untouched,
|
|
15
|
+
* and no new way in is created. The previous code stops working, because its
|
|
16
|
+
* hash is gone.
|
|
17
|
+
*
|
|
18
|
+
* ## Why the file is renamed away first
|
|
19
|
+
*
|
|
20
|
+
* The consumed flag is the ABSENCE of the handoff file: the server unlinks it
|
|
21
|
+
* on a successful pairing. A plain read-modify-write races with that — a
|
|
22
|
+
* pairing landing between our read and our write would see the file deleted,
|
|
23
|
+
* then recreated by us, and the already-paired session token would become
|
|
24
|
+
* pairable a second time. Renaming the file to a private name first is an
|
|
25
|
+
* atomic claim: if the rename fails with ENOENT the code was spent and we stop;
|
|
26
|
+
* if it succeeds the server can no longer consume it (it sees "absent", which
|
|
27
|
+
* answers 410 for the old code — the code we are about to replace anyway).
|
|
28
|
+
*
|
|
29
|
+
* ## Fail-closed
|
|
30
|
+
*
|
|
31
|
+
* Anything unreadable, malformed or already expired yields no code. A failure
|
|
32
|
+
* after the claim deletes the claimed file rather than guessing, so the worst
|
|
33
|
+
* case is "pairing is gone, run `remote stop` and `remote` again", never "a
|
|
34
|
+
* spent token is pairable again".
|
|
35
|
+
*/
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.getReissueClaimPath = getReissueClaimPath;
|
|
38
|
+
exports.reissuePairingCode = reissuePairingCode;
|
|
39
|
+
const fs_1 = require("fs");
|
|
40
|
+
const auth_1 = require("../../lib/security/auth");
|
|
41
|
+
const pairing_code_1 = require("../../lib/security/pairing-code");
|
|
42
|
+
/**
|
|
43
|
+
* @param filePath - Handoff file
|
|
44
|
+
* @returns The private name the file is claimed under while it is rewritten
|
|
45
|
+
*/
|
|
46
|
+
function getReissueClaimPath(filePath) {
|
|
47
|
+
return `${filePath}.reissue-${process.pid}`;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Best-effort unlink. A missing file is the state we wanted.
|
|
51
|
+
*
|
|
52
|
+
* @param filePath - File to remove
|
|
53
|
+
*/
|
|
54
|
+
function removeQuietly(filePath) {
|
|
55
|
+
try {
|
|
56
|
+
(0, fs_1.unlinkSync)(filePath);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Already gone.
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Put a claimed file back where the server reads it. When that fails the
|
|
64
|
+
* claimed copy is deleted: an orphan holding the plaintext token is worse than
|
|
65
|
+
* a pairing that has to be started again.
|
|
66
|
+
*
|
|
67
|
+
* @param claimPath - Where the file was claimed to
|
|
68
|
+
* @param filePath - Where the server expects it
|
|
69
|
+
*/
|
|
70
|
+
function restoreClaim(claimPath, filePath) {
|
|
71
|
+
try {
|
|
72
|
+
(0, fs_1.renameSync)(claimPath, filePath);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
removeQuietly(claimPath);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Replace the pairing code of an unused handoff file with a fresh one.
|
|
80
|
+
*
|
|
81
|
+
* @param filePath - Absolute path of the handoff file (`state.pairing.filePath`)
|
|
82
|
+
* @param now - Epoch ms, injectable for tests
|
|
83
|
+
* @returns The new code and its (unchanged) expiry, or why there is none
|
|
84
|
+
*/
|
|
85
|
+
function reissuePairingCode(filePath, now = Date.now()) {
|
|
86
|
+
const claimPath = getReissueClaimPath(filePath);
|
|
87
|
+
try {
|
|
88
|
+
(0, fs_1.renameSync)(filePath, claimPath);
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
const code = error?.code;
|
|
92
|
+
return { ok: false, reason: code === 'ENOENT' ? 'consumed' : 'unreadable' };
|
|
93
|
+
}
|
|
94
|
+
const handoff = (0, pairing_code_1.readPairingHandoff)(claimPath);
|
|
95
|
+
if (handoff === null) {
|
|
96
|
+
restoreClaim(claimPath, filePath);
|
|
97
|
+
return { ok: false, reason: 'unreadable' };
|
|
98
|
+
}
|
|
99
|
+
if ((0, pairing_code_1.isPairingExpired)(handoff, now)) {
|
|
100
|
+
restoreClaim(claimPath, filePath);
|
|
101
|
+
return { ok: false, reason: 'expired' };
|
|
102
|
+
}
|
|
103
|
+
const code = (0, pairing_code_1.generatePairingCode)();
|
|
104
|
+
try {
|
|
105
|
+
(0, pairing_code_1.writePairingHandoff)(claimPath, {
|
|
106
|
+
pairingHash: (0, auth_1.hashToken)(code),
|
|
107
|
+
expiresAt: handoff.expiresAt,
|
|
108
|
+
sessionToken: handoff.sessionToken,
|
|
109
|
+
});
|
|
110
|
+
(0, fs_1.renameSync)(claimPath, filePath);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
removeQuietly(claimPath);
|
|
114
|
+
return { ok: false, reason: 'write-failed' };
|
|
115
|
+
}
|
|
116
|
+
return { ok: true, code, expiresAt: handoff.expiresAt };
|
|
117
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Launched-server identity check
|
|
3
|
+
* Issue #3087: `remote` published whatever answered on the port
|
|
4
|
+
*
|
|
5
|
+
* A TCP connect only proves that SOMETHING listens. In #3087 an orphaned server from an
|
|
6
|
+
* earlier `start --daemon` (no authentication) kept the port, the server `remote` launched
|
|
7
|
+
* died on EADDRINUSE, and `remote` put the orphan behind a public tunnel.
|
|
8
|
+
*
|
|
9
|
+
* Before anything is published, this asks the endpoint two questions over plain HTTP(S):
|
|
10
|
+
*
|
|
11
|
+
* 1. A request carrying a token nobody holds must be refused with 401. Anything else means
|
|
12
|
+
* authentication is off (or the answer is not CommandMate's middleware), so the server
|
|
13
|
+
* would be reachable without pairing.
|
|
14
|
+
* 2. A request carrying the session token `remote` minted moments ago must succeed. Only
|
|
15
|
+
* the server launched with that token's hash can accept it, so this proves the listener
|
|
16
|
+
* is the one this invocation started — no new API route or nonce is needed.
|
|
17
|
+
*
|
|
18
|
+
* Question 1 is asked first so the session token is never sent to a server already shown to
|
|
19
|
+
* be the wrong one. Every outcome that is not a clear "yes" to both is a refusal (fail-closed);
|
|
20
|
+
* only connection errors and 5xx (a server still warming up) are retried until the deadline.
|
|
21
|
+
*
|
|
22
|
+
* @module server-identity
|
|
23
|
+
*/
|
|
24
|
+
/** Path probed: authenticated like every API route, and it reads nothing (Issue #1925). */
|
|
25
|
+
export declare const IDENTITY_PROBE_PATH = "/api/capabilities";
|
|
26
|
+
export declare const DEFAULT_IDENTITY_TIMEOUT_MS = 30000;
|
|
27
|
+
export declare const DEFAULT_IDENTITY_INTERVAL_MS = 300;
|
|
28
|
+
export interface VerifyLaunchedServerOptions {
|
|
29
|
+
protocol: 'http' | 'https';
|
|
30
|
+
host: string;
|
|
31
|
+
port: number;
|
|
32
|
+
/** Plaintext session token whose hash the launched server was given */
|
|
33
|
+
sessionToken: string;
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
intervalMs?: number;
|
|
36
|
+
}
|
|
37
|
+
export type LaunchedServerVerdict = {
|
|
38
|
+
ok: true;
|
|
39
|
+
} | {
|
|
40
|
+
ok: false;
|
|
41
|
+
reason: string;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Verify that the endpoint is the authenticated server this invocation launched.
|
|
45
|
+
*
|
|
46
|
+
* @returns `{ ok: true }` only when an unknown token is refused with 401 AND the session
|
|
47
|
+
* token is accepted; otherwise `{ ok: false, reason }`. Never throws.
|
|
48
|
+
*/
|
|
49
|
+
export declare function verifyLaunchedServer(options: VerifyLaunchedServerOptions): Promise<LaunchedServerVerdict>;
|
|
50
|
+
//# sourceMappingURL=server-identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-identity.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/server-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAMH,2FAA2F;AAC3F,eAAO,MAAM,mBAAmB,sBAAsB,CAAC;AAEvD,eAAO,MAAM,2BAA2B,QAAQ,CAAC;AACjD,eAAO,MAAM,4BAA4B,MAAM,CAAC;AAGhD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,uEAAuE;IACvE,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,qBAAqB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAqDjF;;;;;GAKG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,2BAA2B,GACnC,OAAO,CAAC,qBAAqB,CAAC,CA0ChC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Launched-server identity check
|
|
4
|
+
* Issue #3087: `remote` published whatever answered on the port
|
|
5
|
+
*
|
|
6
|
+
* A TCP connect only proves that SOMETHING listens. In #3087 an orphaned server from an
|
|
7
|
+
* earlier `start --daemon` (no authentication) kept the port, the server `remote` launched
|
|
8
|
+
* died on EADDRINUSE, and `remote` put the orphan behind a public tunnel.
|
|
9
|
+
*
|
|
10
|
+
* Before anything is published, this asks the endpoint two questions over plain HTTP(S):
|
|
11
|
+
*
|
|
12
|
+
* 1. A request carrying a token nobody holds must be refused with 401. Anything else means
|
|
13
|
+
* authentication is off (or the answer is not CommandMate's middleware), so the server
|
|
14
|
+
* would be reachable without pairing.
|
|
15
|
+
* 2. A request carrying the session token `remote` minted moments ago must succeed. Only
|
|
16
|
+
* the server launched with that token's hash can accept it, so this proves the listener
|
|
17
|
+
* is the one this invocation started — no new API route or nonce is needed.
|
|
18
|
+
*
|
|
19
|
+
* Question 1 is asked first so the session token is never sent to a server already shown to
|
|
20
|
+
* be the wrong one. Every outcome that is not a clear "yes" to both is a refusal (fail-closed);
|
|
21
|
+
* only connection errors and 5xx (a server still warming up) are retried until the deadline.
|
|
22
|
+
*
|
|
23
|
+
* @module server-identity
|
|
24
|
+
*/
|
|
25
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
+
exports.DEFAULT_IDENTITY_INTERVAL_MS = exports.DEFAULT_IDENTITY_TIMEOUT_MS = exports.IDENTITY_PROBE_PATH = void 0;
|
|
27
|
+
exports.verifyLaunchedServer = verifyLaunchedServer;
|
|
28
|
+
const http_1 = require("http");
|
|
29
|
+
const https_1 = require("https");
|
|
30
|
+
const crypto_1 = require("crypto");
|
|
31
|
+
/** Path probed: authenticated like every API route, and it reads nothing (Issue #1925). */
|
|
32
|
+
exports.IDENTITY_PROBE_PATH = '/api/capabilities';
|
|
33
|
+
exports.DEFAULT_IDENTITY_TIMEOUT_MS = 30000;
|
|
34
|
+
exports.DEFAULT_IDENTITY_INTERVAL_MS = 300;
|
|
35
|
+
const REQUEST_TIMEOUT_MS = 10000;
|
|
36
|
+
function probe(options, bearer, timeoutMs) {
|
|
37
|
+
return new Promise((resolve) => {
|
|
38
|
+
const send = options.protocol === 'https' ? https_1.request : http_1.request;
|
|
39
|
+
let settled = false;
|
|
40
|
+
const finish = (status) => {
|
|
41
|
+
if (settled)
|
|
42
|
+
return;
|
|
43
|
+
settled = true;
|
|
44
|
+
resolve(status);
|
|
45
|
+
};
|
|
46
|
+
try {
|
|
47
|
+
const req = send({
|
|
48
|
+
host: options.host,
|
|
49
|
+
port: options.port,
|
|
50
|
+
path: exports.IDENTITY_PROBE_PATH,
|
|
51
|
+
method: 'GET',
|
|
52
|
+
headers: { Authorization: `Bearer ${bearer}` },
|
|
53
|
+
timeout: timeoutMs,
|
|
54
|
+
// Loopback only, and identity is proven by the token, not the certificate: a
|
|
55
|
+
// self-signed CM_HTTPS_CERT must not make the check impossible.
|
|
56
|
+
rejectUnauthorized: false,
|
|
57
|
+
}, (res) => {
|
|
58
|
+
res.resume();
|
|
59
|
+
finish(res.statusCode ?? null);
|
|
60
|
+
});
|
|
61
|
+
req.on('timeout', () => {
|
|
62
|
+
req.destroy();
|
|
63
|
+
finish(null);
|
|
64
|
+
});
|
|
65
|
+
req.on('error', () => finish(null));
|
|
66
|
+
req.end();
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
finish(null);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
function isTransient(status) {
|
|
74
|
+
return status === null || status >= 500;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Verify that the endpoint is the authenticated server this invocation launched.
|
|
78
|
+
*
|
|
79
|
+
* @returns `{ ok: true }` only when an unknown token is refused with 401 AND the session
|
|
80
|
+
* token is accepted; otherwise `{ ok: false, reason }`. Never throws.
|
|
81
|
+
*/
|
|
82
|
+
async function verifyLaunchedServer(options) {
|
|
83
|
+
const timeoutMs = options.timeoutMs ?? exports.DEFAULT_IDENTITY_TIMEOUT_MS;
|
|
84
|
+
const intervalMs = options.intervalMs ?? exports.DEFAULT_IDENTITY_INTERVAL_MS;
|
|
85
|
+
const deadline = Date.now() + timeoutMs;
|
|
86
|
+
// A token that cannot be anyone's: fresh random bytes, never hashed or stored anywhere.
|
|
87
|
+
const decoy = (0, crypto_1.randomBytes)(32).toString('hex');
|
|
88
|
+
const where = `${options.host}:${options.port}`;
|
|
89
|
+
const ask = async (bearer) => {
|
|
90
|
+
for (;;) {
|
|
91
|
+
const remaining = deadline - Date.now();
|
|
92
|
+
const status = await probe(options, bearer, Math.max(Math.min(REQUEST_TIMEOUT_MS, remaining), 1));
|
|
93
|
+
if (!isTransient(status) || deadline - Date.now() <= 0) {
|
|
94
|
+
return status;
|
|
95
|
+
}
|
|
96
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(intervalMs, Math.max(deadline - Date.now(), 1))));
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
const unauthenticated = await ask(decoy);
|
|
100
|
+
if (unauthenticated !== 401) {
|
|
101
|
+
return {
|
|
102
|
+
ok: false,
|
|
103
|
+
reason: unauthenticated === null
|
|
104
|
+
? `nothing answered on ${where}`
|
|
105
|
+
: `the server on ${where} did not require authentication (HTTP ${unauthenticated} for an unknown token, expected 401)`,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
const authenticated = await ask(options.sessionToken);
|
|
109
|
+
if (authenticated === null || authenticated < 200 || authenticated >= 300) {
|
|
110
|
+
return {
|
|
111
|
+
ok: false,
|
|
112
|
+
reason: authenticated === null
|
|
113
|
+
? `nothing answered on ${where}`
|
|
114
|
+
: `the server on ${where} is not the one this command started (HTTP ${authenticated} for this session's token)`,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
return { ok: true };
|
|
118
|
+
}
|
|
@@ -25,4 +25,17 @@ export declare const DEFAULT_INTERVAL_MS = 300;
|
|
|
25
25
|
* @returns true if the server accepted a connection, false on timeout
|
|
26
26
|
*/
|
|
27
27
|
export declare function waitForServer(host: string, port: number, options?: WaitForServerOptions): Promise<boolean>;
|
|
28
|
+
/**
|
|
29
|
+
* Whether something is accepting TCP connections on host:port right now.
|
|
30
|
+
*
|
|
31
|
+
* Issue #3087: a single attempt, used where "the port is free" has to be proven
|
|
32
|
+
* (before `start` spawns a server, after `stop` claims to have stopped one)
|
|
33
|
+
* rather than waited for.
|
|
34
|
+
*
|
|
35
|
+
* @param host - Host to connect to
|
|
36
|
+
* @param port - Port to connect to
|
|
37
|
+
* @param timeoutMs - How long one connection attempt may take
|
|
38
|
+
* @returns true if a connection was accepted
|
|
39
|
+
*/
|
|
40
|
+
export declare function isPortInUse(host: string, port: number, timeoutMs?: number): Promise<boolean>;
|
|
28
41
|
//# sourceMappingURL=server-ready.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server-ready.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/server-ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,OAAO,CAAC,CAmBlB"}
|
|
1
|
+
{"version":3,"file":"server-ready.d.ts","sourceRoot":"","sources":["../../../src/cli/utils/server-ready.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,oBAAoB;IACnC,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,OAAO,CAAC,CAmBlB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE,MAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAElG"}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
13
|
exports.DEFAULT_INTERVAL_MS = exports.DEFAULT_TIMEOUT_MS = void 0;
|
|
14
14
|
exports.waitForServer = waitForServer;
|
|
15
|
+
exports.isPortInUse = isPortInUse;
|
|
15
16
|
const net_1 = require("net");
|
|
16
17
|
exports.DEFAULT_TIMEOUT_MS = 30000;
|
|
17
18
|
exports.DEFAULT_INTERVAL_MS = 300;
|
|
@@ -39,6 +40,21 @@ async function waitForServer(host, port, options = {}) {
|
|
|
39
40
|
await delay(Math.min(intervalMs, remaining));
|
|
40
41
|
}
|
|
41
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Whether something is accepting TCP connections on host:port right now.
|
|
45
|
+
*
|
|
46
|
+
* Issue #3087: a single attempt, used where "the port is free" has to be proven
|
|
47
|
+
* (before `start` spawns a server, after `stop` claims to have stopped one)
|
|
48
|
+
* rather than waited for.
|
|
49
|
+
*
|
|
50
|
+
* @param host - Host to connect to
|
|
51
|
+
* @param port - Port to connect to
|
|
52
|
+
* @param timeoutMs - How long one connection attempt may take
|
|
53
|
+
* @returns true if a connection was accepted
|
|
54
|
+
*/
|
|
55
|
+
function isPortInUse(host, port, timeoutMs = 1000) {
|
|
56
|
+
return tryConnect(host, port, timeoutMs);
|
|
57
|
+
}
|
|
42
58
|
/**
|
|
43
59
|
* Attempt a single TCP connection.
|
|
44
60
|
*
|
|
@@ -112,6 +112,23 @@ export declare const STATUS_REASON: {
|
|
|
112
112
|
readonly OPENCODE_RESPONSE_COMPLETE: "opencode_response_complete";
|
|
113
113
|
readonly INPUT_PROMPT: "input_prompt";
|
|
114
114
|
readonly NO_RECENT_OUTPUT: "no_recent_output";
|
|
115
|
+
/**
|
|
116
|
+
* Issue #3179: the agent's launch is still in progress.
|
|
117
|
+
*
|
|
118
|
+
* Published by `current-output-builder` and `worktree-status-helper` while
|
|
119
|
+
* `lib/session/session-starting-state` holds a record for the instance — from
|
|
120
|
+
* `beginAgentSession` until `startSession` returns or throws, bounded by the
|
|
121
|
+
* tool's readiness wait and released early by a dialog the launch does not
|
|
122
|
+
* answer. The frame underneath (a shell prompt and the launch line, or a trust
|
|
123
|
+
* dialog the launch is about to answer) is not read while it is up: the status
|
|
124
|
+
* is `running`, and `isUnclassifiedActive` / `isSelectionListActive` /
|
|
125
|
+
* `isPromptWaiting` are all false, so no pad, no answer sheet and no `wait`
|
|
126
|
+
* exit 10 is raised for a screen nobody has to drive.
|
|
127
|
+
*
|
|
128
|
+
* ADDITIVE in the sense {@link STATUS_REASON.EXITED} is: a reader that does not
|
|
129
|
+
* know the token sees a `running` session.
|
|
130
|
+
*/
|
|
131
|
+
readonly STARTING: "starting";
|
|
115
132
|
/**
|
|
116
133
|
* Issue #2070: the tmux session is there, and the TOOL is not.
|
|
117
134
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status-reason.d.ts","sourceRoot":"","sources":["../../../src/lib/detection/status-reason.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;IAKxB;;;;;;;;;;;;;;;;;;OAkBG;;IAEH,6EAA6E;;;IAG7E;;;;;;;;;;;;;;;;OAgBG;;IAEH;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;;IAEH;;;;;;;;;;;OAWG;;;;IAIH,kEAAkE;;IAElE,6EAA6E;;;;;;IAM7E;;;;;;;;;;;;;;;OAeG;;IAEH;;;;;;;;;;;;;;;OAeG;;;CAGK,CAAC"}
|
|
1
|
+
{"version":3,"file":"status-reason.d.ts","sourceRoot":"","sources":["../../../src/lib/detection/status-reason.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;IAKxB;;;;;;;;;;;;;;;;;;OAkBG;;IAEH,6EAA6E;;;IAG7E;;;;;;;;;;;;;;;;OAgBG;;IAEH;;;;;;;;;;;;;;;;;;;;;;;;;;OA0BG;;IAEH;;;;;;;;;;;OAWG;;;;IAIH,kEAAkE;;IAElE,6EAA6E;;;;;;IAM7E;;;;;;;;;;;;;;;OAeG;;IAEH;;;;;;;;;;;;;;;OAeG;;IAEH;;;;;;;;;;;;;;;OAeG;;;CAGK,CAAC"}
|