commandmate 0.10.3 → 0.10.4
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 +135 -135
- package/.next/app-path-routes-manifest.json +28 -28
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +15 -15
- 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/app/update/route.js +3 -3
- 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 +1 -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 +3 -2
- 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_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/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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +1 -1
- 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/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route.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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.js +1 -47
- 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 -47
- 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/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +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/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]/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 +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]/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]/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 +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 +2 -2
- 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]/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]/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 +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 +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 +2 -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 +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]/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]/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 -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 +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]/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.js +1 -1
- package/.next/server/app/chat/page.js.nft.json +1 -1
- package/.next/server/app/chat/page_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.js +2 -2
- package/.next/server/app/more/page.js.nft.json +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.js +1 -1
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page.js +1 -1
- package/.next/server/app/repositories/page.js.nft.json +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.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/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +8 -8
- 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_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +28 -28
- package/.next/server/chunks/1068.js +1 -1
- package/.next/server/chunks/1117.js +1 -0
- package/.next/server/chunks/233.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/3270.js +1 -1
- package/.next/server/chunks/3480.js +2 -2
- package/.next/server/chunks/3543.js +1 -1
- package/.next/server/chunks/3945.js +1 -1
- package/.next/server/chunks/406.js +47 -0
- package/.next/server/chunks/4444.js +1 -1
- package/.next/server/chunks/5381.js +1 -47
- package/.next/server/chunks/5959.js +2 -2
- package/.next/server/chunks/646.js +33 -0
- package/.next/server/chunks/8681.js +1 -0
- package/.next/server/chunks/8807.js +305 -300
- package/.next/server/chunks/9355.js +1 -1
- package/.next/server/chunks/9687.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/4560-2bf9cb6504cc4425.js +1 -0
- package/.next/static/chunks/7347-a013a163a75030ec.js +1 -0
- package/.next/static/chunks/app/chat/page-5d20240f98c07cee.js +1 -0
- package/.next/static/chunks/app/layout-fe5857360dfba2b9.js +1 -0
- package/.next/static/chunks/app/more/page-af1d2af13ea901d2.js +1 -0
- package/.next/static/chunks/app/page-3bbe737ec910d1fb.js +1 -0
- package/.next/static/chunks/app/repositories/page-ace9134ac165a6de.js +1 -0
- package/.next/static/chunks/app/review/page-331b80f4f58582bc.js +1 -0
- package/.next/static/chunks/app/sessions/page-d694149a7e8649b6.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-932a52f8d11971f7.js +1 -0
- package/.next/static/css/d7e2e8d1b8d69d36.css +1 -0
- package/.next/trace +10 -10
- package/dist/cli/commands/quickstart.d.ts.map +1 -1
- package/dist/cli/commands/quickstart.js +27 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +19 -0
- package/dist/cli/types/index.d.ts +6 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/utils/agent-instances.d.ts +1 -1
- package/dist/cli/utils/agent-instances.d.ts.map +1 -1
- package/dist/cli/utils/agent-instances.js +8 -1
- package/dist/cli/utils/api-client.d.ts +36 -0
- package/dist/cli/utils/api-client.d.ts.map +1 -1
- package/dist/cli/utils/api-client.js +82 -0
- package/dist/cli/utils/daemon.d.ts.map +1 -1
- package/dist/cli/utils/daemon.js +44 -9
- package/dist/cli/utils/package-info.d.ts +17 -0
- package/dist/cli/utils/package-info.d.ts.map +1 -0
- package/dist/cli/utils/package-info.js +31 -0
- package/dist/cli/utils/pid-manager.d.ts +65 -9
- package/dist/cli/utils/pid-manager.d.ts.map +1 -1
- package/dist/cli/utils/pid-manager.js +81 -21
- package/dist/cli/utils/process-inspector.d.ts +27 -0
- package/dist/cli/utils/process-inspector.d.ts.map +1 -0
- package/dist/cli/utils/process-inspector.js +37 -0
- package/dist/server/src/config/github-links.js +22 -0
- package/dist/server/src/lib/db/db-instance.js +22 -3
- package/dist/server/src/lib/db/db-repository.js +107 -19
- package/dist/server/src/lib/db/db.js +3 -2
- package/dist/server/src/lib/db/memo-db.js +32 -1
- package/dist/server/src/lib/db/migrations/index.js +2 -0
- package/dist/server/src/lib/db/migrations/runner.js +11 -1
- package/dist/server/src/lib/db/migrations/v43-remove-cm-root-dir-ghost-repository.js +126 -0
- package/dist/server/src/lib/git/worktrees.js +90 -0
- package/dist/server/src/lib/job-executor.js +8 -2
- package/dist/server/src/lib/realtime/types.js +76 -0
- package/dist/server/src/lib/schedule-manager.js +9 -1
- package/dist/server/src/lib/version-checker.js +297 -0
- package/dist/server/src/lib/ws-server.js +37 -0
- package/package.json +1 -1
- package/.next/server/chunks/2464.js +0 -33
- package/.next/server/chunks/6791.js +0 -47
- package/.next/static/chunks/7347-4a031aecf4664a6d.js +0 -1
- package/.next/static/chunks/8954-ce15ee4d0423f1b1.js +0 -1
- package/.next/static/chunks/app/chat/page-dee86bdf87516e40.js +0 -1
- package/.next/static/chunks/app/layout-d02f4691a4eff86b.js +0 -1
- package/.next/static/chunks/app/more/page-39ec8b5f27cf52e7.js +0 -1
- package/.next/static/chunks/app/page-ebf1db9826b4065d.js +0 -1
- package/.next/static/chunks/app/repositories/page-2be54cae5fcc1f7a.js +0 -1
- package/.next/static/chunks/app/review/page-ac4efe6857a0f3bf.js +0 -1
- package/.next/static/chunks/app/sessions/page-dc545a3d45374187.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-9eb2f37809919531.js +0 -1
- package/.next/static/css/eabd34bf2ab147a4.css +0 -1
- /package/.next/static/{Ndx_NzkoP54cD0UCmjUlu → uBCIYS1Hth7V4unroKqGu}/_buildManifest.js +0 -0
- /package/.next/static/{Ndx_NzkoP54cD0UCmjUlu → uBCIYS1Hth7V4unroKqGu}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Migration v43: delete the CM_ROOT_DIR ghost repository row (Issue #1339).
|
|
4
|
+
*
|
|
5
|
+
* Before #1328, `getRepositoryPaths()` returned CM_ROOT_DIR as if it were a
|
|
6
|
+
* single repository path, and the sync route handed it to
|
|
7
|
+
* `ensureEnvRepositoriesRegistered()`, which wrote it to `repositories` with
|
|
8
|
+
* `is_env_managed = 1`. But CM_ROOT_DIR is the *container* of repositories, not
|
|
9
|
+
* a repository: `git worktree list` run there returns nothing, so no `worktrees`
|
|
10
|
+
* row was ever created for it. The result is a repository row with no worktrees
|
|
11
|
+
* under it — visible in the repository management screen, absent from the
|
|
12
|
+
* sidebar (which is driven by `worktrees`), and impossible for the user to tell
|
|
13
|
+
* apart from a real entry.
|
|
14
|
+
*
|
|
15
|
+
* #1328 removed the discovery that created these rows but deliberately left the
|
|
16
|
+
* existing rows alone. This migration is that clean-up.
|
|
17
|
+
*
|
|
18
|
+
* SCOPE: only the `is_env_managed = 1` row whose path is exactly CM_ROOT_DIR.
|
|
19
|
+
* The `is_env_managed = 0` ghosts written by `disableRepository()` are a
|
|
20
|
+
* different defect (#1346) and are not touched here.
|
|
21
|
+
*
|
|
22
|
+
* The three guards below exist because deleting a *legitimate* env-managed row
|
|
23
|
+
* is not a harmless mistake: `ensureEnvRepositoriesRegistered()` recreates a
|
|
24
|
+
* missing row with `enabled: true` (db-repository.ts:469), so a wrong delete
|
|
25
|
+
* silently re-enables a repository the user had switched off, and drops their
|
|
26
|
+
* `visible` / `display_name` alongside it. Every guard fails toward keeping the
|
|
27
|
+
* row.
|
|
28
|
+
*
|
|
29
|
+
* Backward compatibility: a DB with no ghost row (the normal case for anyone who
|
|
30
|
+
* never ran a pre-#1328 build) matches nothing and the migration is a no-op.
|
|
31
|
+
*/
|
|
32
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
33
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
34
|
+
};
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.v43_migrations = void 0;
|
|
37
|
+
const path_1 = __importDefault(require("path"));
|
|
38
|
+
/**
|
|
39
|
+
* The configured CM_ROOT_DIR, resolved the same way the ghost row's path was
|
|
40
|
+
* written: `path.resolve()` over the raw env value (`resolveRepositoryPath()`).
|
|
41
|
+
*
|
|
42
|
+
* Deliberately NOT `getEnv()`: that falls back to `process.cwd()` when
|
|
43
|
+
* CM_ROOT_DIR is unset (env.ts:218), which would aim this DELETE at whatever
|
|
44
|
+
* directory the server happened to start in — quite plausibly a real repository.
|
|
45
|
+
* An unset CM_ROOT_DIR must mean "skip", never "target cwd".
|
|
46
|
+
*
|
|
47
|
+
* Read straight from process.env rather than through env.ts so the migration
|
|
48
|
+
* stays frozen: it must keep deleting exactly what the pre-#1328 code wrote,
|
|
49
|
+
* whatever env.ts grows into later.
|
|
50
|
+
*
|
|
51
|
+
* @returns Resolved CM_ROOT_DIR, or null when it is not configured
|
|
52
|
+
*/
|
|
53
|
+
function getConfiguredRootDir() {
|
|
54
|
+
// MCBD_ROOT_DIR is the pre-#76 name and still supported (env.ts ENV_MAPPING).
|
|
55
|
+
const raw = process.env.CM_ROOT_DIR ?? process.env.MCBD_ROOT_DIR;
|
|
56
|
+
if (!raw || !raw.trim()) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return path_1.default.resolve(raw.trim());
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* WORKTREE_REPOS entries, resolved. These are the *legitimate* `is_env_managed`
|
|
63
|
+
* rows: post-#1328 `getRepositoryPaths()` returns this list and nothing else.
|
|
64
|
+
*
|
|
65
|
+
* Parsed inline, mirroring `getRepositoryPaths()` (git/worktrees.ts:144), rather
|
|
66
|
+
* than imported: worktrees.ts pulls in `@/lib/db`, whose barrel re-exports this
|
|
67
|
+
* very migration list.
|
|
68
|
+
*
|
|
69
|
+
* @returns Resolved WORKTREE_REPOS paths (empty when unset)
|
|
70
|
+
*/
|
|
71
|
+
function getWorktreeRepoPaths() {
|
|
72
|
+
const raw = process.env.WORKTREE_REPOS;
|
|
73
|
+
if (!raw || !raw.trim()) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
return raw
|
|
77
|
+
.split(',')
|
|
78
|
+
.map((p) => p.trim())
|
|
79
|
+
.filter((p) => p.length > 0)
|
|
80
|
+
.map((p) => path_1.default.resolve(p));
|
|
81
|
+
}
|
|
82
|
+
exports.v43_migrations = [
|
|
83
|
+
{
|
|
84
|
+
version: 43,
|
|
85
|
+
name: 'remove-cm-root-dir-ghost-repository',
|
|
86
|
+
up: (db) => {
|
|
87
|
+
// Guard 1: no CM_ROOT_DIR, no target. See getConfiguredRootDir().
|
|
88
|
+
const rootDir = getConfiguredRootDir();
|
|
89
|
+
if (!rootDir) {
|
|
90
|
+
console.log('Migration 43: CM_ROOT_DIR is not set; no ghost row to remove');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// Guard 2: CM_ROOT_DIR may legitimately also be listed in WORKTREE_REPOS,
|
|
94
|
+
// which makes its is_env_managed row real and its absence self-healing at
|
|
95
|
+
// enabled=true. Never delete a row the env still asks for.
|
|
96
|
+
if (getWorktreeRepoPaths().includes(rootDir)) {
|
|
97
|
+
console.log(`Migration 43: ${rootDir} is a WORKTREE_REPOS entry; keeping its repository row`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
// Guard 3 (the NOT EXISTS): a row with worktrees under it is not a ghost,
|
|
101
|
+
// whatever the env says. This is the condition the issue names, and it is
|
|
102
|
+
// what makes the delete provably lossless — nothing references the row.
|
|
103
|
+
const result = db
|
|
104
|
+
.prepare(`DELETE FROM repositories
|
|
105
|
+
WHERE path = ?
|
|
106
|
+
AND is_env_managed = 1
|
|
107
|
+
AND NOT EXISTS (
|
|
108
|
+
SELECT 1 FROM worktrees WHERE worktrees.repository_path = ?
|
|
109
|
+
)`)
|
|
110
|
+
.run(rootDir, rootDir);
|
|
111
|
+
if (result.changes > 0) {
|
|
112
|
+
console.log(`Migration 43: removed CM_ROOT_DIR ghost repository row (${rootDir})`);
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
console.log(`Migration 43: no ghost repository row at ${rootDir}`);
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
down: () => {
|
|
119
|
+
// The deleted row carried no user data — an env-managed ghost with no
|
|
120
|
+
// worktrees, no clone URL, and default flags — and re-inserting it would
|
|
121
|
+
// restore the very defect this migration fixes. No-op rollback (mirrors
|
|
122
|
+
// v35/v40).
|
|
123
|
+
console.log('No rollback for the CM_ROOT_DIR ghost row removal');
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
];
|
|
@@ -13,8 +13,11 @@ exports.getRepositoryPaths = getRepositoryPaths;
|
|
|
13
13
|
exports.scanWorktrees = scanWorktrees;
|
|
14
14
|
exports.scanMultipleRepositories = scanMultipleRepositories;
|
|
15
15
|
exports.syncWorktreesToDB = syncWorktreesToDB;
|
|
16
|
+
exports.repositoryExistsOnDisk = repositoryExistsOnDisk;
|
|
17
|
+
exports.pruneStaleRepositoryWorktrees = pruneStaleRepositoryWorktrees;
|
|
16
18
|
const child_process_1 = require("child_process");
|
|
17
19
|
const util_1 = require("util");
|
|
20
|
+
const fs_1 = __importDefault(require("fs"));
|
|
18
21
|
const path_1 = __importDefault(require("path"));
|
|
19
22
|
const db_1 = require("../../lib/db");
|
|
20
23
|
const logger_1 = require("../../lib/logger");
|
|
@@ -293,3 +296,90 @@ function syncWorktreesToDB(db, worktrees) {
|
|
|
293
296
|
}
|
|
294
297
|
return { deletedIds: allDeletedIds, upsertedCount };
|
|
295
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* Whether a repository still exists on disk as a git working tree.
|
|
301
|
+
*
|
|
302
|
+
* Returns `false` only when the directory itself is gone OR its `.git` entry is
|
|
303
|
+
* missing (a de-gitified directory). Every other state — including a present
|
|
304
|
+
* directory whose `.git` is intact — is reported as "still there", so a
|
|
305
|
+
* transient git failure (a locked index, a momentarily-unavailable network
|
|
306
|
+
* drive whose mount point is still present, …) never satisfies the prune
|
|
307
|
+
* condition. Issue #1349: fall on the side of NOT pruning whenever the on-disk
|
|
308
|
+
* state is inconclusive.
|
|
309
|
+
*
|
|
310
|
+
* @param repoPath - Canonical repository path (as stored in
|
|
311
|
+
* `worktrees.repository_path`, i.e. already `path.resolve()`d by
|
|
312
|
+
* {@link scanWorktrees}; see #1347)
|
|
313
|
+
* @returns `true` if the repository still looks present on disk
|
|
314
|
+
*/
|
|
315
|
+
function repositoryExistsOnDisk(repoPath) {
|
|
316
|
+
if (!repoPath)
|
|
317
|
+
return false;
|
|
318
|
+
try {
|
|
319
|
+
return fs_1.default.existsSync(repoPath) && fs_1.default.existsSync(path_1.default.join(repoPath, '.git'));
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
// Inconclusive filesystem read (e.g. EACCES): be conservative and keep rows.
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Prune DB worktree rows for repositories that have vanished from disk.
|
|
328
|
+
*
|
|
329
|
+
* Issue #1349: when a repository directory is deleted or de-gitified,
|
|
330
|
+
* {@link scanWorktrees} returns `[]` (git exit 128), so the repository silently
|
|
331
|
+
* drops out of the scan and {@link syncWorktreesToDB} never reaches its per-repo
|
|
332
|
+
* prune for it — the rows linger as ghost entries in the sidebar. The global
|
|
333
|
+
* early-return in `syncWorktreesToDB` only fires when *every* repository is
|
|
334
|
+
* empty, so a single vanished repository among healthy ones is never cleaned up.
|
|
335
|
+
*
|
|
336
|
+
* This runs as the global-sync reconciliation step: it enumerates every
|
|
337
|
+
* `repository_path` that still owns worktree rows and, for those that produced
|
|
338
|
+
* no worktrees in the current scan, deletes the rows **only when the repository
|
|
339
|
+
* directory (or its `.git`) is genuinely gone** (see
|
|
340
|
+
* {@link repositoryExistsOnDisk}). A repository that still exists but merely
|
|
341
|
+
* errored in git is left untouched, so a transient failure — a network drive
|
|
342
|
+
* blip, a locked repo — never destroys history.
|
|
343
|
+
*
|
|
344
|
+
* Intended for the full-scan endpoint (`POST /api/repositories/sync`) only.
|
|
345
|
+
* Single-repository callers (scan/restore) must NOT run this: they hold no
|
|
346
|
+
* authority over repositories outside their own scan, and running it there would
|
|
347
|
+
* prune repositories that merely weren't part of that request.
|
|
348
|
+
*
|
|
349
|
+
* Row keys stay consistent with #1347: {@link getRepositories} returns the
|
|
350
|
+
* stored (already `path.resolve()`d) `repository_path`, and every subsequent DB
|
|
351
|
+
* and filesystem lookup uses that same canonical value.
|
|
352
|
+
*
|
|
353
|
+
* @param db - Database instance
|
|
354
|
+
* @param liveWorktrees - Worktrees produced by the current scan; their
|
|
355
|
+
* repositories are known-present and therefore skipped
|
|
356
|
+
* @returns IDs of worktrees deleted for vanished repositories
|
|
357
|
+
*/
|
|
358
|
+
function pruneStaleRepositoryWorktrees(db, liveWorktrees) {
|
|
359
|
+
// Repositories that produced at least one worktree this scan are alive by
|
|
360
|
+
// definition (git listed them), so they are never candidates for pruning.
|
|
361
|
+
const liveRepoPaths = new Set(liveWorktrees
|
|
362
|
+
.map(wt => wt.repositoryPath)
|
|
363
|
+
.filter((p) => !!p));
|
|
364
|
+
const deletedIds = [];
|
|
365
|
+
for (const repo of (0, db_1.getRepositories)(db)) {
|
|
366
|
+
const repoPath = repo.path;
|
|
367
|
+
if (!repoPath)
|
|
368
|
+
continue;
|
|
369
|
+
if (liveRepoPaths.has(repoPath))
|
|
370
|
+
continue;
|
|
371
|
+
// Conservative guard: keep rows unless the directory/.git is truly gone.
|
|
372
|
+
if (repositoryExistsOnDisk(repoPath))
|
|
373
|
+
continue;
|
|
374
|
+
const ids = (0, db_1.getWorktreesByRepository)(db, repoPath).map(row => row.id);
|
|
375
|
+
if (ids.length === 0)
|
|
376
|
+
continue;
|
|
377
|
+
const result = (0, db_1.deleteWorktreesByIds)(db, ids);
|
|
378
|
+
deletedIds.push(...ids);
|
|
379
|
+
logger.info('worktree:stale-repo-pruned', {
|
|
380
|
+
repoPath,
|
|
381
|
+
deletedCount: result.deletedCount,
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
return deletedIds;
|
|
385
|
+
}
|
|
@@ -136,8 +136,12 @@ async function executeSchedule(state) {
|
|
|
136
136
|
return;
|
|
137
137
|
}
|
|
138
138
|
state.isExecuting = true;
|
|
139
|
-
|
|
139
|
+
// Issue #1343: createExecutionLog() must stay inside the try so that a DB
|
|
140
|
+
// failure still reaches the finally that resets isExecuting. Otherwise the
|
|
141
|
+
// schedule is skipped by the guard above until the server restarts.
|
|
142
|
+
let logId;
|
|
140
143
|
try {
|
|
144
|
+
logId = createExecutionLog(state.scheduleId, state.worktreeId, state.entry.message);
|
|
141
145
|
const db = getLazyDbInstance();
|
|
142
146
|
const worktree = db.prepare('SELECT path, vibe_local_model FROM worktrees WHERE id = ?').get(state.worktreeId);
|
|
143
147
|
if (!worktree) {
|
|
@@ -153,7 +157,9 @@ async function executeSchedule(state) {
|
|
|
153
157
|
}
|
|
154
158
|
catch (error) {
|
|
155
159
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
156
|
-
|
|
160
|
+
if (logId !== undefined) {
|
|
161
|
+
updateExecutionLog(logId, 'failed', errorMessage, null);
|
|
162
|
+
}
|
|
157
163
|
logger.error('execution:failed', { name: state.entry.name, error: errorMessage });
|
|
158
164
|
}
|
|
159
165
|
finally {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Realtime (WebSocket) message contracts shared by the server broadcasters and
|
|
4
|
+
* the client consumers. Issue #1120.
|
|
5
|
+
*
|
|
6
|
+
* Server broadcasts are double-wrapped by `handleBroadcast` into an envelope:
|
|
7
|
+
* { type: 'broadcast', worktreeId, data: { type: '<realType>', ...payload } }
|
|
8
|
+
* `parseRealtimeEvent` unwraps that envelope and returns the inner payload as
|
|
9
|
+
* the canonical {@link RealtimeEvent}.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.VERSION_MISMATCH_EVENT_TYPE = exports.CLIENT_VERSION_MESSAGE_TYPE = void 0;
|
|
13
|
+
exports.isVersionMismatch = isVersionMismatch;
|
|
14
|
+
exports.parseRealtimeEvent = parseRealtimeEvent;
|
|
15
|
+
/**
|
|
16
|
+
* Client → server hello carrying the client bundle version, sent on every
|
|
17
|
+
* (re)connect so the server can detect a version drift (#1356). Kept as a shared
|
|
18
|
+
* constant so the client sender and the server handler cannot drift apart.
|
|
19
|
+
*/
|
|
20
|
+
exports.CLIENT_VERSION_MESSAGE_TYPE = 'client_version';
|
|
21
|
+
/**
|
|
22
|
+
* Server → client notice that the running server version differs from this
|
|
23
|
+
* tab's bundle version (#1338/#1356). Drives the reload banner.
|
|
24
|
+
*/
|
|
25
|
+
exports.VERSION_MISMATCH_EVENT_TYPE = 'version_mismatch';
|
|
26
|
+
/**
|
|
27
|
+
* Whether the running server version and this tab's bundle version have drifted
|
|
28
|
+
* apart and the user should be nudged to reload (#1338/#1356).
|
|
29
|
+
*
|
|
30
|
+
* Conservative on purpose (受入条件: 版が一致している間は誤検知しない): an empty or
|
|
31
|
+
* `'0.0.0'` fallback on either side means "version unknown" and is never treated
|
|
32
|
+
* as a mismatch, so a server that cannot resolve its own version stays silent.
|
|
33
|
+
*/
|
|
34
|
+
function isVersionMismatch(serverVersion, clientVersion) {
|
|
35
|
+
if (!serverVersion || !clientVersion)
|
|
36
|
+
return false;
|
|
37
|
+
if (serverVersion === '0.0.0' || clientVersion === '0.0.0')
|
|
38
|
+
return false;
|
|
39
|
+
return serverVersion !== clientVersion;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Parse a raw WebSocket frame into the inner realtime event.
|
|
43
|
+
*
|
|
44
|
+
* Handles both the room broadcast envelope ({ type:'broadcast', data:{...} })
|
|
45
|
+
* and (defensively) already-unwrapped frames. Returns null on malformed input
|
|
46
|
+
* or frames without a usable inner `type`.
|
|
47
|
+
*/
|
|
48
|
+
function parseRealtimeEvent(raw) {
|
|
49
|
+
let parsed;
|
|
50
|
+
try {
|
|
51
|
+
parsed = JSON.parse(raw);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
if (!parsed || typeof parsed !== 'object')
|
|
57
|
+
return null;
|
|
58
|
+
const env = parsed;
|
|
59
|
+
if (env.type === 'broadcast') {
|
|
60
|
+
const inner = env.data;
|
|
61
|
+
if (!inner || typeof inner !== 'object')
|
|
62
|
+
return null;
|
|
63
|
+
const innerObj = inner;
|
|
64
|
+
if (typeof innerObj.type !== 'string')
|
|
65
|
+
return null;
|
|
66
|
+
// Ensure worktreeId is present even if the payload omitted it.
|
|
67
|
+
if (innerObj.worktreeId === undefined && typeof env.worktreeId === 'string') {
|
|
68
|
+
innerObj.worktreeId = env.worktreeId;
|
|
69
|
+
}
|
|
70
|
+
return innerObj;
|
|
71
|
+
}
|
|
72
|
+
if (typeof env.type === 'string') {
|
|
73
|
+
return env;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
@@ -71,7 +71,15 @@ function createScheduleState(worktreeId, scheduleId, entry) {
|
|
|
71
71
|
entry,
|
|
72
72
|
};
|
|
73
73
|
cronJob.schedule(() => {
|
|
74
|
-
|
|
74
|
+
// Issue #1343: executeSchedule() rejects if its own error handling fails
|
|
75
|
+
// (e.g. the DB is still down when writing the 'failed' log). Without this
|
|
76
|
+
// catch the rejection is silently unhandled.
|
|
77
|
+
void (0, job_executor_1.executeSchedule)(state).catch((error) => {
|
|
78
|
+
logger.error('execution:unhandled', {
|
|
79
|
+
name: entry.name,
|
|
80
|
+
error: error instanceof Error ? error.message : String(error),
|
|
81
|
+
});
|
|
82
|
+
});
|
|
75
83
|
});
|
|
76
84
|
return state;
|
|
77
85
|
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Version Checker Module
|
|
4
|
+
* Issue #257: Version update notification feature
|
|
5
|
+
*
|
|
6
|
+
* Checks GitHub Releases API for newer versions of CommandMate.
|
|
7
|
+
* Uses globalThis cache pattern (auto-yes-manager.ts reference) for
|
|
8
|
+
* hot-reload persistence.
|
|
9
|
+
*
|
|
10
|
+
* Security:
|
|
11
|
+
* - [SEC-001] GITHUB_API_URL is hardcoded (SSRF prevention, OWASP A10:2021)
|
|
12
|
+
* - [SEC-SF-001] Response validation (validateReleaseUrl, sanitizeReleaseName)
|
|
13
|
+
* - [SEC-SF-002] User-Agent header for GitHub API compliance (OWASP A07:2021)
|
|
14
|
+
*
|
|
15
|
+
* @module version-checker
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.GITHUB_RELEASE_URL_PREFIX = exports.GITHUB_API_URL = void 0;
|
|
19
|
+
exports.isNewerVersion = isNewerVersion;
|
|
20
|
+
exports.getClientVersion = getClientVersion;
|
|
21
|
+
exports.getServerVersion = getServerVersion;
|
|
22
|
+
exports.getCurrentVersion = getCurrentVersion;
|
|
23
|
+
exports.validateReleaseUrl = validateReleaseUrl;
|
|
24
|
+
exports.sanitizeReleaseName = sanitizeReleaseName;
|
|
25
|
+
exports.checkForUpdate = checkForUpdate;
|
|
26
|
+
exports.resetCacheForTesting = resetCacheForTesting;
|
|
27
|
+
const fs_1 = require("fs");
|
|
28
|
+
const path_1 = require("path");
|
|
29
|
+
// =============================================================================
|
|
30
|
+
// Constants
|
|
31
|
+
// =============================================================================
|
|
32
|
+
/**
|
|
33
|
+
* [SEC-001] SSRF Prevention: GitHub API URL is a hardcoded constant.
|
|
34
|
+
* This value MUST NOT be derived from environment variables, config files,
|
|
35
|
+
* or user input. Changing this value requires security review.
|
|
36
|
+
* OWASP A10:2021 - Server-Side Request Forgery
|
|
37
|
+
*/
|
|
38
|
+
exports.GITHUB_API_URL = 'https://api.github.com/repos/Kewton/CommandMate/releases/latest';
|
|
39
|
+
/**
|
|
40
|
+
* [SEC-SF-001] GitHub Releases URL allowed prefix for validation.
|
|
41
|
+
* Used to verify html_url from API responses.
|
|
42
|
+
* Imported from github-links.ts (Issue #264 DRY) and re-exported for backward compatibility.
|
|
43
|
+
*/
|
|
44
|
+
const github_links_1 = require("../config/github-links");
|
|
45
|
+
Object.defineProperty(exports, "GITHUB_RELEASE_URL_PREFIX", { enumerable: true, get: function () { return github_links_1.GITHUB_RELEASE_URL_PREFIX; } });
|
|
46
|
+
/** Semver pattern: optional v-prefix followed by major.minor.patch */
|
|
47
|
+
const SEMVER_PATTERN = /^v?\d+\.\d+\.\d+$/;
|
|
48
|
+
/** [SEC-SF-001] Release name allowed characters pattern */
|
|
49
|
+
const RELEASE_NAME_PATTERN = /^[a-zA-Z0-9.\-\s_v]+$/;
|
|
50
|
+
/** Maximum allowed release name length */
|
|
51
|
+
const RELEASE_NAME_MAX_LENGTH = 128;
|
|
52
|
+
/** Cache TTL: 1 hour (matches GitHub API unauthenticated rate limit of 60 req/h) */
|
|
53
|
+
const CACHE_TTL_MS = 60 * 60 * 1000;
|
|
54
|
+
/** Fetch timeout: 5 seconds */
|
|
55
|
+
const FETCH_TIMEOUT_MS = 5000;
|
|
56
|
+
/**
|
|
57
|
+
* npm package name. [Issue #1359] Used to verify that a package.json resolved at
|
|
58
|
+
* runtime is CommandMate's own manifest and not an unrelated project's — a guard
|
|
59
|
+
* against an unexpected process.cwd() (e.g. a dev run started from a user's
|
|
60
|
+
* project directory) leaking a foreign version.
|
|
61
|
+
*/
|
|
62
|
+
const PACKAGE_NAME = 'commandmate';
|
|
63
|
+
const cache = globalThis.__versionCheckCache ??
|
|
64
|
+
(globalThis.__versionCheckCache = {
|
|
65
|
+
result: null,
|
|
66
|
+
fetchedAt: 0,
|
|
67
|
+
rateLimitResetAt: null,
|
|
68
|
+
});
|
|
69
|
+
// =============================================================================
|
|
70
|
+
// Public Functions
|
|
71
|
+
// =============================================================================
|
|
72
|
+
/**
|
|
73
|
+
* Compare two semver version strings.
|
|
74
|
+
* [SF-003] Includes built-in validation - returns false for invalid formats.
|
|
75
|
+
*
|
|
76
|
+
* @param current - Current version (e.g., "0.2.3", "v0.2.3")
|
|
77
|
+
* @param latest - Latest version (e.g., "0.3.0", "v0.3.0")
|
|
78
|
+
* @returns true if latest is newer than current, false for invalid formats
|
|
79
|
+
*/
|
|
80
|
+
function isNewerVersion(current, latest) {
|
|
81
|
+
// [SF-003] Defensive validation: reject invalid formats immediately
|
|
82
|
+
if (!SEMVER_PATTERN.test(current) || !SEMVER_PATTERN.test(latest)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
const parse = (v) => v.replace(/^v/, '').split('.').map(Number);
|
|
86
|
+
const [cMajor, cMinor, cPatch] = parse(current);
|
|
87
|
+
const [lMajor, lMinor, lPatch] = parse(latest);
|
|
88
|
+
if (lMajor !== cMajor)
|
|
89
|
+
return lMajor > cMajor;
|
|
90
|
+
if (lMinor !== cMinor)
|
|
91
|
+
return lMinor > cMinor;
|
|
92
|
+
return lPatch > cPatch;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Read CommandMate's version from the installed package.json at runtime.
|
|
96
|
+
*
|
|
97
|
+
* [Issue #1359] `NEXT_PUBLIC_APP_VERSION` is baked into the bundle at
|
|
98
|
+
* `next build` time, so it reflects "the version present when the client bundle
|
|
99
|
+
* was last built", not the version of the server code actually running. Reading
|
|
100
|
+
* package.json on each call reflects the real installed version, which is what
|
|
101
|
+
* the update-check API must report as `currentVersion`.
|
|
102
|
+
*
|
|
103
|
+
* The server is spawned with cwd = package root (start.ts), so
|
|
104
|
+
* `process.cwd()/package.json` is the installed manifest. We verify
|
|
105
|
+
* `name === 'commandmate'` so an unexpected cwd can never leak an unrelated
|
|
106
|
+
* project's version; on any mismatch or read failure the caller falls back to
|
|
107
|
+
* the baked value.
|
|
108
|
+
*
|
|
109
|
+
* @returns Runtime version string, or null when unreadable / not CommandMate's package.json
|
|
110
|
+
*/
|
|
111
|
+
function readRuntimeServerVersion() {
|
|
112
|
+
try {
|
|
113
|
+
const raw = (0, fs_1.readFileSync)((0, path_1.join)(process.cwd(), 'package.json'), 'utf-8');
|
|
114
|
+
const parsed = JSON.parse(raw);
|
|
115
|
+
if (parsed.name === PACKAGE_NAME &&
|
|
116
|
+
typeof parsed.version === 'string' &&
|
|
117
|
+
parsed.version.length > 0) {
|
|
118
|
+
return parsed.version;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Unreadable / malformed package.json: fall back to the baked value.
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the client bundle version (baked at build time).
|
|
129
|
+
* [CONS-002] `NEXT_PUBLIC_APP_VERSION` is injected by next.config.js from
|
|
130
|
+
* package.json at `next build` time. This is the correct value to describe
|
|
131
|
+
* "the version of the bundle this page was served from" and is intentionally
|
|
132
|
+
* left build-time baked (Issue #1359).
|
|
133
|
+
*
|
|
134
|
+
* @returns Client bundle version string (e.g., "0.2.3"), or "0.0.0" as fallback
|
|
135
|
+
*/
|
|
136
|
+
function getClientVersion() {
|
|
137
|
+
return process.env.NEXT_PUBLIC_APP_VERSION ?? '0.0.0';
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get the server's actually-running version, resolved at runtime.
|
|
141
|
+
* [Issue #1359] Prefers the installed package.json (runtime truth) over the
|
|
142
|
+
* build-time baked `NEXT_PUBLIC_APP_VERSION`, so update-check reports the version
|
|
143
|
+
* of the server code that is really running. Separating this from
|
|
144
|
+
* getClientVersion() is the basis for version-mismatch detection (#1338/#1356).
|
|
145
|
+
*
|
|
146
|
+
* Resolution order:
|
|
147
|
+
* 1. Runtime package.json (name === "commandmate")
|
|
148
|
+
* 2. Baked NEXT_PUBLIC_APP_VERSION
|
|
149
|
+
* 3. "0.0.0"
|
|
150
|
+
*
|
|
151
|
+
* @returns Server runtime version string (e.g., "0.2.3"), or "0.0.0" as fallback
|
|
152
|
+
*/
|
|
153
|
+
function getServerVersion() {
|
|
154
|
+
return readRuntimeServerVersion() ?? getClientVersion();
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get the current application version (server runtime version).
|
|
158
|
+
* Retained for backward compatibility; delegates to getServerVersion().
|
|
159
|
+
*
|
|
160
|
+
* @returns Current version string (e.g., "0.2.3"), or "0.0.0" as fallback
|
|
161
|
+
*/
|
|
162
|
+
function getCurrentVersion() {
|
|
163
|
+
return getServerVersion();
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Validate that a URL is a legitimate GitHub Releases URL.
|
|
167
|
+
* [SEC-SF-001] OWASP A03:2021 - Prevents injection via DNS pollution/MITM.
|
|
168
|
+
*
|
|
169
|
+
* @param url - URL to validate
|
|
170
|
+
* @returns Validated URL, or null if invalid
|
|
171
|
+
*/
|
|
172
|
+
function validateReleaseUrl(url) {
|
|
173
|
+
if (!url.startsWith(github_links_1.GITHUB_RELEASE_URL_PREFIX)) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
return url;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Sanitize a release name to safe character set.
|
|
180
|
+
* [SEC-SF-001] Restricts to alphanumeric, dots, hyphens, spaces, underscores, v-prefix.
|
|
181
|
+
*
|
|
182
|
+
* @param name - Release name to sanitize
|
|
183
|
+
* @param tagName - Fallback value (semver-validated tag_name)
|
|
184
|
+
* @returns Sanitized name, or tagName if the name is invalid
|
|
185
|
+
*/
|
|
186
|
+
function sanitizeReleaseName(name, tagName) {
|
|
187
|
+
if (RELEASE_NAME_PATTERN.test(name) && name.length <= RELEASE_NAME_MAX_LENGTH) {
|
|
188
|
+
return name;
|
|
189
|
+
}
|
|
190
|
+
// Fallback to tag_name (already validated by SEMVER_PATTERN)
|
|
191
|
+
return tagName;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Check GitHub Releases for newer versions.
|
|
195
|
+
* Uses in-memory cache (globalThis.__versionCheckCache) with 1-hour TTL.
|
|
196
|
+
* Silently fails on network errors, timeouts, or API issues.
|
|
197
|
+
*
|
|
198
|
+
* [SF-002] Multiple calls within the same process are safe: the globalThis cache
|
|
199
|
+
* (1-hour TTL) ensures that only the first call triggers a network request.
|
|
200
|
+
* Subsequent calls within the TTL window return the cached result without
|
|
201
|
+
* network overhead. The cache is stored in globalThis.__versionCheckCache
|
|
202
|
+
* and automatically invalidated after CACHE_TTL_MS (1 hour).
|
|
203
|
+
*
|
|
204
|
+
* @returns Update check result, or null on failure
|
|
205
|
+
*/
|
|
206
|
+
async function checkForUpdate() {
|
|
207
|
+
try {
|
|
208
|
+
// Check cache validity
|
|
209
|
+
if (isCacheValid()) {
|
|
210
|
+
return cache.result;
|
|
211
|
+
}
|
|
212
|
+
// Check rate limit
|
|
213
|
+
if (isRateLimited()) {
|
|
214
|
+
return cache.result;
|
|
215
|
+
}
|
|
216
|
+
const response = await fetch(exports.GITHUB_API_URL, {
|
|
217
|
+
headers: {
|
|
218
|
+
'Accept': 'application/vnd.github+json',
|
|
219
|
+
'User-Agent': `CommandMate/${getCurrentVersion()}`, // [SEC-SF-002]
|
|
220
|
+
},
|
|
221
|
+
cache: 'no-store', // Issue #278: Prevent Next.js Data Cache from caching GitHub API responses
|
|
222
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
223
|
+
});
|
|
224
|
+
// Handle rate limit (403)
|
|
225
|
+
if (response.status === 403) {
|
|
226
|
+
handleRateLimit(response);
|
|
227
|
+
return cache.result;
|
|
228
|
+
}
|
|
229
|
+
if (!response.ok) {
|
|
230
|
+
return cache.result;
|
|
231
|
+
}
|
|
232
|
+
const data = (await response.json());
|
|
233
|
+
const currentVersion = getCurrentVersion();
|
|
234
|
+
const latestVersion = data.tag_name.replace(/^v/, '');
|
|
235
|
+
const hasUpdate = isNewerVersion(currentVersion, data.tag_name);
|
|
236
|
+
const result = {
|
|
237
|
+
hasUpdate,
|
|
238
|
+
currentVersion,
|
|
239
|
+
latestVersion,
|
|
240
|
+
releaseUrl: validateReleaseUrl(data.html_url),
|
|
241
|
+
releaseName: sanitizeReleaseName(data.name, data.tag_name),
|
|
242
|
+
publishedAt: data.published_at,
|
|
243
|
+
};
|
|
244
|
+
// Update cache
|
|
245
|
+
cache.result = result;
|
|
246
|
+
cache.fetchedAt = Date.now();
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
// Silent failure: network errors, timeouts, parse errors
|
|
251
|
+
return cache.result;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Reset cache for testing purposes only.
|
|
256
|
+
* @internal
|
|
257
|
+
*/
|
|
258
|
+
function resetCacheForTesting() {
|
|
259
|
+
cache.result = null;
|
|
260
|
+
cache.fetchedAt = 0;
|
|
261
|
+
cache.rateLimitResetAt = null;
|
|
262
|
+
}
|
|
263
|
+
// =============================================================================
|
|
264
|
+
// Internal Functions
|
|
265
|
+
// =============================================================================
|
|
266
|
+
/** Check if cache is valid (within TTL) */
|
|
267
|
+
function isCacheValid() {
|
|
268
|
+
return cache.result !== null && (Date.now() - cache.fetchedAt) < CACHE_TTL_MS;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Check if currently rate-limited.
|
|
272
|
+
* [C-001] Simplified rate limit handling: uses rateLimitResetAt from 403 response.
|
|
273
|
+
*/
|
|
274
|
+
function isRateLimited() {
|
|
275
|
+
if (!cache.rateLimitResetAt)
|
|
276
|
+
return false;
|
|
277
|
+
if (Date.now() >= cache.rateLimitResetAt) {
|
|
278
|
+
cache.rateLimitResetAt = null;
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
return true;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Handle 403 rate limit response.
|
|
285
|
+
* Extracts X-RateLimit-Reset header for precise retry timing,
|
|
286
|
+
* or falls back to CACHE_TTL_MS extension.
|
|
287
|
+
*/
|
|
288
|
+
function handleRateLimit(response) {
|
|
289
|
+
const resetTimestamp = response.headers.get('X-RateLimit-Reset');
|
|
290
|
+
if (resetTimestamp) {
|
|
291
|
+
cache.rateLimitResetAt = parseInt(resetTimestamp, 10) * 1000;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
// Reset time unknown: retry after 1 hour
|
|
295
|
+
cache.rateLimitResetAt = Date.now() + CACHE_TTL_MS;
|
|
296
|
+
}
|
|
297
|
+
}
|