commandmate 0.11.3 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +392 -300
- package/.next/app-path-routes-manifest.json +30 -21
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +12 -12
- package/.next/react-loadable-manifest.json +8 -6
- package/.next/required-server-files.json +1 -1
- package/.next/routes-manifest.json +66 -0
- package/.next/server/app/_not-found/page.js.nft.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 +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +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_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_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_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_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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +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/skills/[id]/route.js +1 -0
- package/.next/server/app/api/skills/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/skills/route.js +1 -0
- package/.next/server/app/api/skills/route.js.nft.json +1 -0
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -0
- 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_client-reference-manifest.js +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_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_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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +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_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_client-reference-manifest.js +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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route.js +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_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_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_client-reference-manifest.js +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_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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +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_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]/install/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/route.js +23 -0
- package/.next/server/app/api/worktrees/[id]/skills/route.js.nft.json +1 -0
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +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_client-reference-manifest.js +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_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_client-reference-manifest.js +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_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_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_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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/chat/page.js +2 -2
- 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.js.nft.json +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.js.nft.json +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/skills/[skillId]/page.js +2 -0
- package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -0
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/skills/page.js +2 -0
- package/.next/server/app/skills/page.js.nft.json +1 -0
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -0
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js +2 -2
- 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 +3 -3
- 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 +30 -21
- package/.next/server/chunks/1117.js +1 -1
- package/.next/server/chunks/120.js +1 -0
- package/.next/server/chunks/1808.js +1 -0
- package/.next/server/chunks/186.js +1 -0
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/22.js +1 -0
- package/.next/server/chunks/2328.js +1 -0
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/3042.js +2 -0
- package/.next/server/chunks/3543.js +1 -1
- package/.next/server/chunks/3708.js +1 -0
- package/.next/server/chunks/3945.js +1 -1
- package/.next/server/chunks/5064.js +1 -0
- package/.next/server/chunks/5226.js +28 -0
- package/.next/server/chunks/5306.js +2 -0
- package/.next/server/chunks/5312.js +1 -0
- package/.next/server/chunks/5326.js +1 -0
- package/.next/server/chunks/5381.js +1 -1
- package/.next/server/chunks/5456.js +1 -0
- package/.next/server/chunks/5571.js +1 -1
- package/.next/server/chunks/5959.js +2 -2
- package/.next/server/chunks/6065.js +1 -0
- package/.next/server/chunks/6130.js +1 -0
- package/.next/server/chunks/6285.js +1 -1
- package/.next/server/chunks/646.js +6 -6
- package/.next/server/chunks/{9968.js → 7587.js} +1 -1
- package/.next/server/chunks/8584.js +1 -0
- package/.next/server/chunks/8681.js +1 -1
- package/.next/server/chunks/8807.js +950 -804
- package/.next/server/chunks/9123.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/D-aoE4gWfuCUN0GqEPIX3/_buildManifest.js +1 -0
- package/.next/static/chunks/1668-7484081c45a44f89.js +1 -0
- package/.next/static/chunks/3418-7e47651340d940b0.js +1 -0
- package/.next/static/chunks/4027-0c529b322be7d4d8.js +1 -0
- package/.next/static/chunks/{4560-64b1461fd996127a.js → 4560-04e5aebcab96bfa1.js} +1 -1
- package/.next/static/chunks/6007-de36119357dcd418.js +1 -0
- package/.next/static/chunks/{6488-8819e6905355caea.js → 6488-e257111ca7389d05.js} +1 -1
- package/.next/static/chunks/{8965-872d8de254196cec.js → 6497-dc26c6c6b0b15adf.js} +1 -1
- package/.next/static/chunks/790-d8e6acd26e03679c.js +1 -0
- package/.next/static/chunks/8361.4bf062be2d2962f4.js +1 -0
- package/.next/static/chunks/app/api/app/update/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/app/update-check/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/assistant/conversation/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/assistant/current-output/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/assistant/messages/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/assistant/session/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/assistant/start/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/assistant/terminal/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/assistant/tools/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/auth/login/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/auth/logout/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/auth/status/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/daily-summary/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/daily-summary/status/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/external-apps/[id]/health/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/external-apps/[id]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/external-apps/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/hooks/claude-done/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/ollama/models/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/push/subscriptions/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/push/vapid/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/todos/[todoId]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/todos/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/clone/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/excluded/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/restore/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/scan/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/repositories/sync/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/sidebar/group-order/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/skills/[id]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/skills/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/slash-commands/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/templates/[id]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/templates/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/todos/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/capture/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/logs/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/memos/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/messages/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/respond/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/search/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/send/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/start-polling/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/timers/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/todos/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tree/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/api/worktrees/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/chat/{page-9ed2ffd98eb4ae18.js → page-9cf4ba62e21d9074.js} +1 -1
- package/.next/static/chunks/app/manifest.webmanifest/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/more/{page-a496425bba427b48.js → page-082d4ae496f9a36e.js} +1 -1
- package/.next/static/chunks/app/{page-15bfd76bcf65842d.js → page-af457ca5876ed616.js} +1 -1
- package/.next/static/chunks/app/proxy/[...path]/route-56dad0523d3c4a92.js +1 -0
- package/.next/static/chunks/app/repositories/{page-d214522ab8792ce7.js → page-75f0d70452c6b6c0.js} +1 -1
- package/.next/static/chunks/app/review/{page-1dadf0b5d7129598.js → page-f431d630097c2e85.js} +1 -1
- package/.next/static/chunks/app/sessions/{page-96f007d986c5f327.js → page-20f07a99db64d2ca.js} +1 -1
- package/.next/static/chunks/app/skills/[skillId]/page-68ed5e9186efe56d.js +1 -0
- package/.next/static/chunks/app/skills/page-46242c428ee8bccf.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-bf811e793052c917.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/page-a75fe180a7233b2b.js +1 -0
- package/.next/static/chunks/webpack-0f9275e279c058eb.js +1 -0
- package/.next/static/css/b4bdb1f3457fe9a7.css +1 -0
- package/.next/trace +11 -10
- package/.next/types/app/api/skills/[id]/route.ts +347 -0
- package/.next/types/app/api/skills/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/skills/[skillId]/install/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/skills/[skillId]/plan/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.ts +347 -0
- package/.next/types/app/api/worktrees/[id]/skills/route.ts +347 -0
- package/.next/types/app/skills/[skillId]/page.ts +84 -0
- package/.next/types/app/skills/page.ts +84 -0
- package/.next/types/routes.d.ts +11 -2
- package/.next/types/validator.ts +81 -0
- package/dist/cli/commands/skill-format.d.ts +28 -0
- package/dist/cli/commands/skill-format.d.ts.map +1 -0
- package/dist/cli/commands/skill-format.js +163 -0
- package/dist/cli/commands/skill-guards.d.ts +53 -0
- package/dist/cli/commands/skill-guards.d.ts.map +1 -0
- package/dist/cli/commands/skill-guards.js +188 -0
- package/dist/cli/commands/skill.d.ts +24 -0
- package/dist/cli/commands/skill.d.ts.map +1 -0
- package/dist/cli/commands/skill.js +365 -0
- package/dist/cli/docs/agent-operations.d.ts +1 -1
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +36 -0
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/program.js +11 -0
- package/dist/cli/types/api-responses.d.ts +215 -0
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/types/index.d.ts +60 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/types/index.js +23 -1
- package/dist/cli/utils/api-client.d.ts +19 -1
- package/dist/cli/utils/api-client.d.ts.map +1 -1
- package/dist/cli/utils/api-client.js +41 -4
- package/dist/cli/utils/npx-runner.d.ts +14 -0
- package/dist/cli/utils/npx-runner.d.ts.map +1 -1
- package/dist/cli/utils/npx-runner.js +20 -0
- package/dist/server/server.js +57 -0
- package/dist/server/src/config/activity-bar-config.js +2 -0
- package/dist/server/src/config/git-status-config.js +83 -0
- package/dist/server/src/config/skill-security-config.js +139 -0
- package/dist/server/src/lib/db/migrations/index.js +8 -0
- package/dist/server/src/lib/db/migrations/runner.js +1 -1
- package/dist/server/src/lib/db/migrations/v44-skill-operations.js +81 -0
- package/dist/server/src/lib/db/migrations/v45-skill-installations.js +59 -0
- package/dist/server/src/lib/db/migrations/v46-skill-installations-cascade.js +107 -0
- package/dist/server/src/lib/db/migrations/v47-skill-installations-roots.js +70 -0
- package/dist/server/src/lib/db/worktree-db.js +9 -4
- package/dist/server/src/lib/git/git-errors.js +336 -0
- package/dist/server/src/lib/git/git-exec.js +285 -0
- package/dist/server/src/lib/skills/compatibility.js +194 -0
- package/dist/server/src/lib/skills/constants.js +252 -0
- package/dist/server/src/lib/skills/errors.js +82 -0
- package/dist/server/src/lib/skills/index.js +91 -0
- package/dist/server/src/lib/skills/install-apply.js +670 -0
- package/dist/server/src/lib/skills/install-plan.js +582 -0
- package/dist/server/src/lib/skills/installed-state.js +127 -0
- package/dist/server/src/lib/skills/integrity.js +225 -0
- package/dist/server/src/lib/skills/json-schema.js +365 -0
- package/dist/server/src/lib/skills/operation-audit.js +120 -0
- package/dist/server/src/lib/skills/operation-journal.js +286 -0
- package/dist/server/src/lib/skills/operation-lock.js +339 -0
- package/dist/server/src/lib/skills/operation-reconciler.js +107 -0
- package/dist/server/src/lib/skills/operation-store.js +153 -0
- package/dist/server/src/lib/skills/package-reader.js +495 -0
- package/dist/server/src/lib/skills/package-validator.js +451 -0
- package/dist/server/src/lib/skills/preview-diff.js +627 -0
- package/dist/server/src/lib/skills/safe-yaml.js +593 -0
- package/dist/server/src/lib/skills/schema.js +1248 -0
- package/dist/server/src/lib/skills/semver.js +193 -0
- package/dist/server/src/lib/skills/snapshot-store.js +334 -0
- package/dist/server/src/lib/skills/startup-reconcile.js +138 -0
- package/dist/server/src/lib/skills/uninstall-apply.js +495 -0
- package/dist/server/src/lib/skills/uninstall-plan.js +479 -0
- package/dist/server/src/types/skills.js +17 -0
- package/package.json +1 -1
- package/.next/server/chunks/129.js +0 -1
- package/.next/server/chunks/2478.js +0 -1
- package/.next/server/chunks/9886.js +0 -1
- package/.next/static/chunks/3165-87bf884f7f3d15cf.js +0 -1
- package/.next/static/chunks/6416.6756b7ad06dd96f7.js +0 -1
- package/.next/static/chunks/8676.57260a06f6554e7e.js +0 -1
- package/.next/static/chunks/app/api/app/update/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/app/update-check/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/assistant/conversation/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/assistant/current-output/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/assistant/messages/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/assistant/session/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/assistant/start/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/assistant/terminal/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/assistant/tools/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/auth/login/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/auth/logout/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/auth/status/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/daily-summary/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/daily-summary/status/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/external-apps/[id]/health/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/external-apps/[id]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/external-apps/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/hooks/claude-done/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/ollama/models/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/push/subscriptions/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/push/vapid/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/todos/[todoId]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/todos/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/clone/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/excluded/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/restore/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/scan/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/repositories/sync/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/sidebar/group-order/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/slash-commands/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/templates/[id]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/templates/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/todos/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/capture/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/logs/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/memos/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/messages/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/respond/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/search/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/send/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/start-polling/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/timers/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/todos/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tree/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/api/worktrees/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/manifest.webmanifest/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/proxy/[...path]/route-7536041a7a89616d.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-6105a3470b279527.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/terminal/page-ed4590b024edd8d6.js +0 -1
- package/.next/static/chunks/webpack-2e3739a831868daa.js +0 -1
- package/.next/static/css/d7e2e8d1b8d69d36.css +0 -1
- package/.next/static/i8mdUwheg9j9sU_lI_ZSf/_buildManifest.js +0 -1
- /package/.next/static/{i8mdUwheg9j9sU_lI_ZSf → D-aoE4gWfuCUN0GqEPIX3}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,670 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Atomic commit of a planned Skill install into one worktree (Issue #1235)
|
|
4
|
+
*
|
|
5
|
+
* The write half of the plan/apply pair. #1233 fixed *what* would be written —
|
|
6
|
+
* the exact payload bytes, the exact receipt bytes and the tree hash they add up
|
|
7
|
+
* to — and this module is the only place those bytes reach a repository.
|
|
8
|
+
*
|
|
9
|
+
* Four properties carry the safety argument:
|
|
10
|
+
*
|
|
11
|
+
* - **The destination is derived, never received.** The install root comes from
|
|
12
|
+
* a server-resolved worktree path plus a Skill ID re-checked against
|
|
13
|
+
* {@link SKILL_ID_PATTERN}. Re-checking the grammar rather than only the
|
|
14
|
+
* joined result is deliberate: `path.join` normalizes `..` away, so
|
|
15
|
+
* `.agents/skills/../x` and `.agents/x` compare equal and a containment check
|
|
16
|
+
* alone would accept an ID that walked out of the Skills directory.
|
|
17
|
+
* - **Every write is exclusive and does not follow links.** Files are created
|
|
18
|
+
* with `O_CREAT|O_EXCL|O_NOFOLLOW`, so a symlink or a file planted between the
|
|
19
|
+
* directory scan and the write cannot be written *through*; mode and digest
|
|
20
|
+
* are re-read afterwards, so a file that changed underneath us never reaches
|
|
21
|
+
* the receipt.
|
|
22
|
+
* - **The commit point is one rename.** Staging lives in the reserved
|
|
23
|
+
* `.agents/skills/.commandmate-staging/` namespace, on the same filesystem as
|
|
24
|
+
* the destination, so `rename(2)` is atomic. Before it lands the destination
|
|
25
|
+
* is proven absent: an existing directory — managed or hand-made — is refused,
|
|
26
|
+
* never merged into and never implicitly overwritten.
|
|
27
|
+
* - **Nothing is executed.** No script, hook, install step or archive-carried
|
|
28
|
+
* mode is ever run or honoured. Modes are assigned from the manifest's
|
|
29
|
+
* declared executable bit and nothing else.
|
|
30
|
+
*
|
|
31
|
+
* A failure *after* the rename is not a rollback. The payload exists, and the
|
|
32
|
+
* caller must report it as committed and hand the remainder to #1234
|
|
33
|
+
* reconciliation rather than claiming the worktree is unchanged.
|
|
34
|
+
*
|
|
35
|
+
* @module lib/skills/install-apply
|
|
36
|
+
*/
|
|
37
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
38
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
39
|
+
};
|
|
40
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
+
exports.SKILL_INSTALL_NEXT_ACTION_KEYS = exports.SKILL_INSTALL_RELOAD_MESSAGE_KEYS = exports.SkillInstallError = exports.SKILL_INSTALL_ERROR_STATUS = exports.SkillInstallErrorCode = exports.SKILL_INSTALL_OPERATION_ID_PATTERN = exports.SKILL_INSTALL_EXECUTABLE_MODE = exports.SKILL_INSTALL_FILE_MODE = exports.SKILL_INSTALL_DIR_MODE = void 0;
|
|
42
|
+
exports.isSkillInstallError = isSkillInstallError;
|
|
43
|
+
exports.buildSkillReloadGuidance = buildSkillReloadGuidance;
|
|
44
|
+
exports.resolveSkillInstallTarget = resolveSkillInstallTarget;
|
|
45
|
+
exports.resolveSkillInstallTargetFor = resolveSkillInstallTargetFor;
|
|
46
|
+
exports.inspectSkillDestination = inspectSkillDestination;
|
|
47
|
+
exports.hasCommittedSkillPayload = hasCommittedSkillPayload;
|
|
48
|
+
exports.writeSkillPayloadFile = writeSkillPayloadFile;
|
|
49
|
+
exports.applySkillInstall = applySkillInstall;
|
|
50
|
+
exports.completeSecondarySkillInstallRoots = completeSecondarySkillInstallRoots;
|
|
51
|
+
exports.cleanupSkillInstallStaging = cleanupSkillInstallStaging;
|
|
52
|
+
const fs_1 = require("fs");
|
|
53
|
+
const crypto_1 = require("crypto");
|
|
54
|
+
const path_1 = __importDefault(require("path"));
|
|
55
|
+
const constants_1 = require("../../lib/skills/constants");
|
|
56
|
+
const integrity_1 = require("../../lib/skills/integrity");
|
|
57
|
+
const operation_store_1 = require("../../lib/skills/operation-store");
|
|
58
|
+
const preview_diff_1 = require("../../lib/skills/preview-diff");
|
|
59
|
+
const install_plan_1 = require("../../lib/skills/install-plan");
|
|
60
|
+
// =============================================================================
|
|
61
|
+
// Modes and layout
|
|
62
|
+
// =============================================================================
|
|
63
|
+
/** Payload directories are owner-only, like the staging that produced them. */
|
|
64
|
+
exports.SKILL_INSTALL_DIR_MODE = 0o700;
|
|
65
|
+
/** Ordinary payload files. */
|
|
66
|
+
exports.SKILL_INSTALL_FILE_MODE = 0o600;
|
|
67
|
+
/** Files the manifest declared executable. Only the owner execute bit is added. */
|
|
68
|
+
exports.SKILL_INSTALL_EXECUTABLE_MODE = 0o700;
|
|
69
|
+
/**
|
|
70
|
+
* Grammar of the staging directory name.
|
|
71
|
+
*
|
|
72
|
+
* The name is a server-generated operation ID and never a client string, but it
|
|
73
|
+
* becomes a path segment, so it is checked rather than trusted.
|
|
74
|
+
*/
|
|
75
|
+
exports.SKILL_INSTALL_OPERATION_ID_PATTERN = /^[0-9a-zA-Z-]{8,64}$/;
|
|
76
|
+
/** `O_NOFOLLOW` is POSIX-only; on platforms without it the flag is a no-op. */
|
|
77
|
+
const O_NOFOLLOW = fs_1.constants.O_NOFOLLOW ?? 0;
|
|
78
|
+
// =============================================================================
|
|
79
|
+
// Errors
|
|
80
|
+
// =============================================================================
|
|
81
|
+
/** Client-safe reasons an apply refused to write or could not finish. */
|
|
82
|
+
exports.SkillInstallErrorCode = {
|
|
83
|
+
/** The install root could not be derived safely from the worktree and Skill ID. */
|
|
84
|
+
TARGET_UNSAFE: 'SKILL_INSTALL_TARGET_UNSAFE',
|
|
85
|
+
/** An ancestor of the install root is a symlink or is not a directory. */
|
|
86
|
+
ANCESTOR_UNSAFE: 'SKILL_INSTALL_ANCESTOR_UNSAFE',
|
|
87
|
+
/** A CommandMate-managed install is already present. Updating is out of scope. */
|
|
88
|
+
DESTINATION_EXISTS: 'SKILL_INSTALL_DESTINATION_EXISTS',
|
|
89
|
+
/** Something CommandMate does not manage occupies the install root. */
|
|
90
|
+
DESTINATION_UNMANAGED: 'SKILL_INSTALL_DESTINATION_UNMANAGED',
|
|
91
|
+
/** Staging and destination are on different filesystems, so rename is not atomic. */
|
|
92
|
+
CROSS_DEVICE: 'SKILL_INSTALL_CROSS_DEVICE',
|
|
93
|
+
/** Staging could not be created or written. */
|
|
94
|
+
STAGING_IO: 'SKILL_INSTALL_STAGING_IO',
|
|
95
|
+
/** What landed in staging is not what the plan fixed. */
|
|
96
|
+
PAYLOAD_MISMATCH: 'SKILL_INSTALL_PAYLOAD_MISMATCH',
|
|
97
|
+
/** The atomic rename itself failed. Nothing was published. */
|
|
98
|
+
COMMIT_FAILED: 'SKILL_INSTALL_COMMIT_FAILED',
|
|
99
|
+
};
|
|
100
|
+
/** HTTP status each reason maps to, so every caller answers alike. */
|
|
101
|
+
exports.SKILL_INSTALL_ERROR_STATUS = {
|
|
102
|
+
[exports.SkillInstallErrorCode.TARGET_UNSAFE]: 400,
|
|
103
|
+
[exports.SkillInstallErrorCode.ANCESTOR_UNSAFE]: 409,
|
|
104
|
+
[exports.SkillInstallErrorCode.DESTINATION_EXISTS]: 409,
|
|
105
|
+
[exports.SkillInstallErrorCode.DESTINATION_UNMANAGED]: 409,
|
|
106
|
+
[exports.SkillInstallErrorCode.CROSS_DEVICE]: 500,
|
|
107
|
+
[exports.SkillInstallErrorCode.STAGING_IO]: 500,
|
|
108
|
+
[exports.SkillInstallErrorCode.PAYLOAD_MISMATCH]: 500,
|
|
109
|
+
[exports.SkillInstallErrorCode.COMMIT_FAILED]: 500,
|
|
110
|
+
};
|
|
111
|
+
/** An apply rejection. The message is built from the code — never from a path. */
|
|
112
|
+
class SkillInstallError extends Error {
|
|
113
|
+
code;
|
|
114
|
+
detail;
|
|
115
|
+
constructor(code, detail) {
|
|
116
|
+
super(`Skill install rejected: ${code}`);
|
|
117
|
+
this.code = code;
|
|
118
|
+
this.detail = detail;
|
|
119
|
+
this.name = 'SkillInstallError';
|
|
120
|
+
}
|
|
121
|
+
get status() {
|
|
122
|
+
return exports.SKILL_INSTALL_ERROR_STATUS[this.code];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.SkillInstallError = SkillInstallError;
|
|
126
|
+
function isSkillInstallError(value) {
|
|
127
|
+
return value instanceof SkillInstallError;
|
|
128
|
+
}
|
|
129
|
+
function fail(code, detail) {
|
|
130
|
+
throw new SkillInstallError(code, detail);
|
|
131
|
+
}
|
|
132
|
+
// =============================================================================
|
|
133
|
+
// Reload guidance
|
|
134
|
+
// =============================================================================
|
|
135
|
+
/** i18n key per agent support level, so UI and CLI say the same thing (UX-01). */
|
|
136
|
+
exports.SKILL_INSTALL_RELOAD_MESSAGE_KEYS = {
|
|
137
|
+
native: 'skills.install.reload.native',
|
|
138
|
+
commandmate_runtime: 'skills.install.reload.commandmateRuntime',
|
|
139
|
+
unsupported: 'skills.install.reload.unsupported',
|
|
140
|
+
unknown: 'skills.install.reload.unknown',
|
|
141
|
+
};
|
|
142
|
+
/** i18n key for what the user should do next, per outcome (UX-07). */
|
|
143
|
+
exports.SKILL_INSTALL_NEXT_ACTION_KEYS = {
|
|
144
|
+
succeeded: 'skills.install.nextAction.succeeded',
|
|
145
|
+
committedReconciling: 'skills.install.nextAction.committedReconciling',
|
|
146
|
+
failed: 'skills.install.nextAction.failed',
|
|
147
|
+
};
|
|
148
|
+
/**
|
|
149
|
+
* Derive reload guidance from the receipt.
|
|
150
|
+
*
|
|
151
|
+
* The receipt is used rather than the Catalog because it is the record of what
|
|
152
|
+
* actually landed: guidance for a version other than the installed one would be
|
|
153
|
+
* worse than none.
|
|
154
|
+
*/
|
|
155
|
+
function buildSkillReloadGuidance(receipt) {
|
|
156
|
+
return {
|
|
157
|
+
skillId: receipt.skill_id,
|
|
158
|
+
version: receipt.version,
|
|
159
|
+
installRoot: receipt.install_root,
|
|
160
|
+
agents: receipt.agent_compatibility.map((entry) => ({
|
|
161
|
+
agent: entry.agent,
|
|
162
|
+
support: entry.support,
|
|
163
|
+
messageKey: exports.SKILL_INSTALL_RELOAD_MESSAGE_KEYS[entry.support],
|
|
164
|
+
})),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// =============================================================================
|
|
168
|
+
// Path safety
|
|
169
|
+
// =============================================================================
|
|
170
|
+
/**
|
|
171
|
+
* Absolute install root for a validated Skill ID inside a server-resolved worktree.
|
|
172
|
+
*
|
|
173
|
+
* Delegates to #1233's resolver so plan and apply cannot disagree about where a
|
|
174
|
+
* Skill lives, and re-checks the ID here as well: this module must be safe to
|
|
175
|
+
* call without a plan, for instance from reconciliation.
|
|
176
|
+
*/
|
|
177
|
+
function resolveSkillInstallTarget(worktreePath, skillId) {
|
|
178
|
+
return resolveSkillInstallTargetFor(worktreePath, constants_1.SKILL_INSTALL_ROOT_PREFIX, skillId);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Absolute install root for a validated Skill ID under one root prefix (#1460).
|
|
182
|
+
*
|
|
183
|
+
* The per-root generalization of {@link resolveSkillInstallTarget}: `.claude/skills`
|
|
184
|
+
* gets exactly the grammar re-check and containment rejection `.agents/skills`
|
|
185
|
+
* always had, so neither root can be walked out of by a crafted ID.
|
|
186
|
+
*/
|
|
187
|
+
function resolveSkillInstallTargetFor(worktreePath, rootPrefix, skillId) {
|
|
188
|
+
if (!constants_1.SKILL_ID_PATTERN.test(skillId) || skillId.length > constants_1.SKILL_ID_MAX_LENGTH) {
|
|
189
|
+
fail(exports.SkillInstallErrorCode.TARGET_UNSAFE, { reason: 'skill-id' });
|
|
190
|
+
}
|
|
191
|
+
try {
|
|
192
|
+
return (0, preview_diff_1.resolveSkillInstallRootFor)(worktreePath, rootPrefix, skillId);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return fail(exports.SkillInstallErrorCode.TARGET_UNSAFE, { reason: 'install-root' });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Prove no ancestor of the install root was swapped for a link.
|
|
200
|
+
*
|
|
201
|
+
* `lstat` at every level from the worktree down: a symlink anywhere on the chain
|
|
202
|
+
* would let the rename publish the payload outside the registered worktree, and
|
|
203
|
+
* `realpath` alone would silently *follow* it instead of refusing.
|
|
204
|
+
*/
|
|
205
|
+
function assertAncestorsAreRealDirectories(worktreeRealPath, worktreePath, rootPrefix = constants_1.SKILL_INSTALL_ROOT_PREFIX) {
|
|
206
|
+
let resolved;
|
|
207
|
+
try {
|
|
208
|
+
resolved = (0, fs_1.realpathSync)(worktreePath);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
return fail(exports.SkillInstallErrorCode.ANCESTOR_UNSAFE, { reason: 'worktree-unresolvable' });
|
|
212
|
+
}
|
|
213
|
+
if (resolved !== worktreeRealPath) {
|
|
214
|
+
fail(exports.SkillInstallErrorCode.ANCESTOR_UNSAFE, { reason: 'worktree-identity' });
|
|
215
|
+
}
|
|
216
|
+
let walked = worktreeRealPath;
|
|
217
|
+
for (const segment of rootPrefix.split('/')) {
|
|
218
|
+
walked = path_1.default.join(walked, segment);
|
|
219
|
+
let stats;
|
|
220
|
+
try {
|
|
221
|
+
stats = (0, fs_1.lstatSync)(walked);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// Not yet created is fine; it is created below with a plain mkdir.
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
if (stats.isSymbolicLink() || !stats.isDirectory()) {
|
|
228
|
+
fail(exports.SkillInstallErrorCode.ANCESTOR_UNSAFE, { reason: 'not-a-directory' });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Describe the install root without following anything.
|
|
234
|
+
*
|
|
235
|
+
* A non-directory at the install root (a file, a symlink) counts as present and
|
|
236
|
+
* unmanaged: it is not something an install may quietly replace.
|
|
237
|
+
*/
|
|
238
|
+
function inspectSkillDestination(installRootAbs) {
|
|
239
|
+
let stats;
|
|
240
|
+
try {
|
|
241
|
+
stats = (0, fs_1.lstatSync)(installRootAbs);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
return { present: false, managed: false, version: null };
|
|
245
|
+
}
|
|
246
|
+
if (stats.isSymbolicLink() || !stats.isDirectory()) {
|
|
247
|
+
return { present: true, managed: false, version: null };
|
|
248
|
+
}
|
|
249
|
+
try {
|
|
250
|
+
const receipt = (0, install_plan_1.parseInstalledReceipt)((0, fs_1.readFileSync)(path_1.default.join(installRootAbs, install_plan_1.SKILL_RECEIPT_FILENAME)));
|
|
251
|
+
if (receipt)
|
|
252
|
+
return { present: true, managed: true, version: receipt.version };
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// No readable receipt: the directory exists but CommandMate did not write it.
|
|
256
|
+
}
|
|
257
|
+
return { present: true, managed: false, version: null };
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Whether the payload a committed operation wrote is still on disk.
|
|
261
|
+
*
|
|
262
|
+
* The port #1234's reconciler needs: it decides between "converge forward" and
|
|
263
|
+
* "genuinely rolled back", and only the receipt digest can distinguish the
|
|
264
|
+
* install that committed from a different one that happens to share the path.
|
|
265
|
+
*/
|
|
266
|
+
function hasCommittedSkillPayload(worktreePath, skillId, receiptDigest) {
|
|
267
|
+
let installRootAbs;
|
|
268
|
+
try {
|
|
269
|
+
installRootAbs = resolveSkillInstallTarget(worktreePath, skillId);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
let bytes;
|
|
275
|
+
try {
|
|
276
|
+
bytes = (0, fs_1.readFileSync)(path_1.default.join(installRootAbs, install_plan_1.SKILL_RECEIPT_FILENAME));
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
if ((0, install_plan_1.parseInstalledReceipt)(bytes) === null)
|
|
282
|
+
return false;
|
|
283
|
+
return receiptDigest === null || (0, integrity_1.digestMatches)((0, integrity_1.computeSha256Hex)(bytes), receiptDigest);
|
|
284
|
+
}
|
|
285
|
+
// =============================================================================
|
|
286
|
+
// Staging
|
|
287
|
+
// =============================================================================
|
|
288
|
+
function makeDirectory(target, mode, recursive) {
|
|
289
|
+
try {
|
|
290
|
+
(0, fs_1.mkdirSync)(target, { mode, recursive });
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'mkdir' });
|
|
294
|
+
}
|
|
295
|
+
let stats;
|
|
296
|
+
try {
|
|
297
|
+
stats = (0, fs_1.lstatSync)(target);
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
return fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'mkdir-verify' });
|
|
301
|
+
}
|
|
302
|
+
if (stats.isSymbolicLink() || !stats.isDirectory()) {
|
|
303
|
+
fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'not-a-directory' });
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Write one file and prove afterwards that it is the file we meant to write.
|
|
308
|
+
*
|
|
309
|
+
* `O_EXCL` means an existing path is never written to, and `O_NOFOLLOW` means a
|
|
310
|
+
* symlink planted at that path is refused rather than followed — together they
|
|
311
|
+
* make "the write landed somewhere else" unrepresentable. The post-write checks
|
|
312
|
+
* are not belt-and-braces either: `nlink !== 1` would mean the path was
|
|
313
|
+
* hard-linked elsewhere, and a digest read back through the same path is the
|
|
314
|
+
* only evidence that what a later reader sees matches the plan.
|
|
315
|
+
*
|
|
316
|
+
* @internal Exported for the guard tests; callers use {@link applySkillInstall}.
|
|
317
|
+
*/
|
|
318
|
+
function writeSkillPayloadFile(target, bytes, executable) {
|
|
319
|
+
const mode = executable ? exports.SKILL_INSTALL_EXECUTABLE_MODE : exports.SKILL_INSTALL_FILE_MODE;
|
|
320
|
+
let fd;
|
|
321
|
+
try {
|
|
322
|
+
fd = (0, fs_1.openSync)(target, fs_1.constants.O_WRONLY | fs_1.constants.O_CREAT | fs_1.constants.O_EXCL | O_NOFOLLOW, mode);
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'open' });
|
|
326
|
+
}
|
|
327
|
+
try {
|
|
328
|
+
let written = 0;
|
|
329
|
+
while (written < bytes.byteLength) {
|
|
330
|
+
written += (0, fs_1.writeSync)(fd, bytes, written, bytes.byteLength - written);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
(0, fs_1.closeSync)(fd);
|
|
335
|
+
return fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'write' });
|
|
336
|
+
}
|
|
337
|
+
(0, fs_1.closeSync)(fd);
|
|
338
|
+
const stats = (0, fs_1.lstatSync)(target);
|
|
339
|
+
if (!stats.isFile() || stats.nlink !== 1 || stats.size !== bytes.byteLength) {
|
|
340
|
+
fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'verify-stat' });
|
|
341
|
+
}
|
|
342
|
+
if (((stats.mode & 0o111) !== 0) !== executable) {
|
|
343
|
+
fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'verify-mode' });
|
|
344
|
+
}
|
|
345
|
+
if (!(0, integrity_1.digestMatches)((0, integrity_1.computeSha256Hex)((0, fs_1.readFileSync)(target)), (0, integrity_1.computeSha256Hex)(bytes))) {
|
|
346
|
+
fail(exports.SkillInstallErrorCode.PAYLOAD_MISMATCH, { reason: 'readback' });
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
/** Re-read a staged tree from disk, so verification never trusts its own inputs. */
|
|
350
|
+
function readStagedTree(stagingDir) {
|
|
351
|
+
const files = [];
|
|
352
|
+
const walk = (dirAbs, relPrefix) => {
|
|
353
|
+
for (const entry of (0, fs_1.readdirSync)(dirAbs, { withFileTypes: true })) {
|
|
354
|
+
const relative = relPrefix ? `${relPrefix}/${entry.name}` : entry.name;
|
|
355
|
+
const absolute = path_1.default.join(dirAbs, entry.name);
|
|
356
|
+
const stats = (0, fs_1.lstatSync)(absolute);
|
|
357
|
+
if (stats.isDirectory()) {
|
|
358
|
+
walk(absolute, relative);
|
|
359
|
+
continue;
|
|
360
|
+
}
|
|
361
|
+
if (!stats.isFile()) {
|
|
362
|
+
fail(exports.SkillInstallErrorCode.PAYLOAD_MISMATCH, { reason: 'irregular-staged-entry' });
|
|
363
|
+
}
|
|
364
|
+
files.push({
|
|
365
|
+
path: relative,
|
|
366
|
+
sha256: (0, integrity_1.computeSha256Hex)((0, fs_1.readFileSync)(absolute)),
|
|
367
|
+
executable: (stats.mode & 0o111) !== 0,
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
walk(stagingDir, '');
|
|
372
|
+
return files;
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Stage, verify and atomically publish one Skill install.
|
|
376
|
+
*
|
|
377
|
+
* Everything before the `renameSync` is undoable and is undone on any failure:
|
|
378
|
+
* the staging directory is removed and the destination is untouched. Everything
|
|
379
|
+
* after it is not, which is why the rename is the last thing that happens and
|
|
380
|
+
* why the caller records `FS_COMMITTED` the moment this returns.
|
|
381
|
+
*
|
|
382
|
+
* @throws SkillInstallError — the destination was not modified in every case.
|
|
383
|
+
*/
|
|
384
|
+
function applySkillInstall(input) {
|
|
385
|
+
if (!exports.SKILL_INSTALL_OPERATION_ID_PATTERN.test(input.operationId)) {
|
|
386
|
+
fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'operation-id' });
|
|
387
|
+
}
|
|
388
|
+
const rootPrefixes = input.rootPrefixes && input.rootPrefixes.length > 0
|
|
389
|
+
? [...input.rootPrefixes]
|
|
390
|
+
: [constants_1.SKILL_INSTALL_ROOT_PREFIX];
|
|
391
|
+
// The payload is identical across roots: read and digest-verify it once, then
|
|
392
|
+
// stage the same bytes into each root (#1460).
|
|
393
|
+
const payload = input.snapshot.files.map((file) => {
|
|
394
|
+
const bytes = input.snapshot.readFile(file.path);
|
|
395
|
+
if (!(0, integrity_1.digestMatches)((0, integrity_1.computeSha256Hex)(bytes), file.sha256)) {
|
|
396
|
+
fail(exports.SkillInstallErrorCode.PAYLOAD_MISMATCH, { reason: 'snapshot-digest' });
|
|
397
|
+
}
|
|
398
|
+
return { relativePath: file.path, bytes, executable: file.executable };
|
|
399
|
+
});
|
|
400
|
+
const directories = directoriesFor(input.snapshot.files.map((f) => f.path), input.snapshot.directories);
|
|
401
|
+
// Every destination is proven safe and absent *before* the primary commits, so
|
|
402
|
+
// a secondary that is already blocked cannot leave a committed primary behind.
|
|
403
|
+
for (const prefix of rootPrefixes) {
|
|
404
|
+
const abs = resolveSkillInstallTargetFor(input.worktreePath, prefix, input.skillId);
|
|
405
|
+
assertAncestorsAreRealDirectories(input.worktreeRealPath, input.worktreePath, prefix);
|
|
406
|
+
const destination = inspectSkillDestination(abs);
|
|
407
|
+
if (destination.present) {
|
|
408
|
+
fail(destination.managed
|
|
409
|
+
? exports.SkillInstallErrorCode.DESTINATION_EXISTS
|
|
410
|
+
: exports.SkillInstallErrorCode.DESTINATION_UNMANAGED, destination.version ? { version: destination.version } : undefined);
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
const committedRoots = [];
|
|
414
|
+
const pendingRoots = [];
|
|
415
|
+
for (let index = 0; index < rootPrefixes.length; index += 1) {
|
|
416
|
+
const prefix = rootPrefixes[index];
|
|
417
|
+
try {
|
|
418
|
+
stageAndCommitSkillRoot({
|
|
419
|
+
worktreePath: input.worktreePath,
|
|
420
|
+
worktreeRealPath: input.worktreeRealPath,
|
|
421
|
+
rootPrefix: prefix,
|
|
422
|
+
skillId: input.skillId,
|
|
423
|
+
operationId: input.operationId,
|
|
424
|
+
payload,
|
|
425
|
+
directories,
|
|
426
|
+
receiptBytes: input.receiptBytes,
|
|
427
|
+
plannedTreeHash: input.plannedTreeHash,
|
|
428
|
+
});
|
|
429
|
+
committedRoots.push((0, preview_diff_1.skillInstallRootFor)(prefix, input.skillId));
|
|
430
|
+
}
|
|
431
|
+
catch (error) {
|
|
432
|
+
// The primary rename is the commit point. A failure there published
|
|
433
|
+
// nothing, so it rolls back cleanly and is rethrown. A failure at a
|
|
434
|
+
// secondary root leaves the primary committed: the operation is
|
|
435
|
+
// *committed, reconciling*, and the remaining roots are handed to #1234.
|
|
436
|
+
if (index === 0)
|
|
437
|
+
throw error;
|
|
438
|
+
for (let rest = index; rest < rootPrefixes.length; rest += 1) {
|
|
439
|
+
pendingRoots.push((0, preview_diff_1.skillInstallRootFor)(rootPrefixes[rest], input.skillId));
|
|
440
|
+
}
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
const installRoots = rootPrefixes.map((prefix) => (0, preview_diff_1.skillInstallRootFor)(prefix, input.skillId));
|
|
445
|
+
const installRootRel = installRoots[0];
|
|
446
|
+
const receiptSha256 = (0, integrity_1.computeSha256Hex)(input.receiptBytes);
|
|
447
|
+
return {
|
|
448
|
+
installRoot: installRootRel,
|
|
449
|
+
installRoots,
|
|
450
|
+
committedRoots,
|
|
451
|
+
pendingRoots,
|
|
452
|
+
reconciling: pendingRoots.length > 0,
|
|
453
|
+
receiptPath: `${installRootRel}/${install_plan_1.SKILL_RECEIPT_FILENAME}`,
|
|
454
|
+
receiptSha256,
|
|
455
|
+
receiptSize: input.receiptBytes.byteLength,
|
|
456
|
+
files: input.snapshot.files.map((file) => ({
|
|
457
|
+
path: file.path,
|
|
458
|
+
sha256: file.sha256,
|
|
459
|
+
size: file.size,
|
|
460
|
+
executable: file.executable,
|
|
461
|
+
})),
|
|
462
|
+
treeHash: input.plannedTreeHash,
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
/** Sorted set of directories a payload implies, plus any the package declared. */
|
|
466
|
+
function directoriesFor(filePaths, declared = []) {
|
|
467
|
+
const directories = new Set(declared);
|
|
468
|
+
for (const filePath of filePaths) {
|
|
469
|
+
const parents = filePath.split('/').slice(0, -1);
|
|
470
|
+
let walked = '';
|
|
471
|
+
for (const segment of parents) {
|
|
472
|
+
walked = walked === '' ? segment : `${walked}/${segment}`;
|
|
473
|
+
directories.add(walked);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
return [...directories].sort();
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Stage the verified payload into one root and atomically publish it (#1460).
|
|
480
|
+
*
|
|
481
|
+
* The single-root commit #1235 built, lifted to take the root prefix as a
|
|
482
|
+
* parameter: staging lives under *that* root's reserved namespace so the rename
|
|
483
|
+
* stays on one filesystem, and every check — ancestor lstat walk, exclusive
|
|
484
|
+
* no-follow writes, tree-hash gate, destination-absent, same-filesystem — is
|
|
485
|
+
* applied per root. Throws {@link SkillInstallError} on any failure, having
|
|
486
|
+
* removed its own staging; the destination is untouched unless the rename ran.
|
|
487
|
+
*/
|
|
488
|
+
function stageAndCommitSkillRoot(input) {
|
|
489
|
+
const installRootAbs = resolveSkillInstallTargetFor(input.worktreePath, input.rootPrefix, input.skillId);
|
|
490
|
+
assertAncestorsAreRealDirectories(input.worktreeRealPath, input.worktreePath, input.rootPrefix);
|
|
491
|
+
const destinationBefore = inspectSkillDestination(installRootAbs);
|
|
492
|
+
if (destinationBefore.present) {
|
|
493
|
+
fail(destinationBefore.managed
|
|
494
|
+
? exports.SkillInstallErrorCode.DESTINATION_EXISTS
|
|
495
|
+
: exports.SkillInstallErrorCode.DESTINATION_UNMANAGED, destinationBefore.version ? { version: destinationBefore.version } : undefined);
|
|
496
|
+
}
|
|
497
|
+
const stagingRoot = (0, operation_store_1.getSkillInstallStagingRoot)(input.worktreePath, input.rootPrefix);
|
|
498
|
+
makeDirectory(path_1.default.dirname(stagingRoot), 0o755, true);
|
|
499
|
+
makeDirectory(stagingRoot, exports.SKILL_INSTALL_DIR_MODE, true);
|
|
500
|
+
// Not recursive: a staging directory that already exists means another
|
|
501
|
+
// operation is using this ID, and silently adopting it would merge two writes.
|
|
502
|
+
const stagingDir = path_1.default.join(stagingRoot, input.operationId);
|
|
503
|
+
makeDirectory(stagingDir, exports.SKILL_INSTALL_DIR_MODE, false);
|
|
504
|
+
try {
|
|
505
|
+
for (const directory of input.directories) {
|
|
506
|
+
makeDirectory(path_1.default.join(stagingDir, directory), exports.SKILL_INSTALL_DIR_MODE, false);
|
|
507
|
+
}
|
|
508
|
+
for (const file of input.payload) {
|
|
509
|
+
// The execute bit comes from the reconciled inventory, which is also what
|
|
510
|
+
// the plan hashed — never from the archive header, which is attacker data.
|
|
511
|
+
writeSkillPayloadFile(path_1.default.join(stagingDir, file.relativePath), file.bytes, file.executable);
|
|
512
|
+
}
|
|
513
|
+
// The receipt is written last and from the plan's own bytes: rebuilding it
|
|
514
|
+
// here would make the file the user previewed and the file on disk two
|
|
515
|
+
// different artifacts that merely ought to agree.
|
|
516
|
+
writeSkillPayloadFile(path_1.default.join(stagingDir, install_plan_1.SKILL_RECEIPT_FILENAME), input.receiptBytes, false);
|
|
517
|
+
const staged = readStagedTree(stagingDir);
|
|
518
|
+
const treeHash = (0, preview_diff_1.computeSkillTreeHash)(staged);
|
|
519
|
+
if (treeHash !== input.plannedTreeHash) {
|
|
520
|
+
fail(exports.SkillInstallErrorCode.PAYLOAD_MISMATCH, { reason: 'tree-hash' });
|
|
521
|
+
}
|
|
522
|
+
assertSameFilesystem(stagingDir, path_1.default.dirname(installRootAbs));
|
|
523
|
+
// Re-checked immediately before the rename rather than only at entry: the
|
|
524
|
+
// exclusive lock keeps CommandMate out, but nothing keeps the user's own
|
|
525
|
+
// editor from creating this directory while the payload was being staged.
|
|
526
|
+
assertAncestorsAreRealDirectories(input.worktreeRealPath, input.worktreePath, input.rootPrefix);
|
|
527
|
+
const destinationNow = inspectSkillDestination(installRootAbs);
|
|
528
|
+
if (destinationNow.present) {
|
|
529
|
+
fail(destinationNow.managed
|
|
530
|
+
? exports.SkillInstallErrorCode.DESTINATION_EXISTS
|
|
531
|
+
: exports.SkillInstallErrorCode.DESTINATION_UNMANAGED);
|
|
532
|
+
}
|
|
533
|
+
try {
|
|
534
|
+
(0, fs_1.renameSync)(stagingDir, installRootAbs);
|
|
535
|
+
}
|
|
536
|
+
catch {
|
|
537
|
+
fail(exports.SkillInstallErrorCode.COMMIT_FAILED, { reason: 'rename' });
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
(0, fs_1.rmSync)(stagingDir, { recursive: true, force: true });
|
|
542
|
+
pruneStagingRoot(stagingRoot);
|
|
543
|
+
throw error;
|
|
544
|
+
}
|
|
545
|
+
pruneStagingRoot(stagingRoot);
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Converge a committed install's secondary roots forward from the primary (#1460).
|
|
549
|
+
*
|
|
550
|
+
* The reconciliation primitive for a partial multi-root install: when the
|
|
551
|
+
* primary `.agents/skills` root committed but a secondary rename did not, this
|
|
552
|
+
* reads the primary's own on-disk payload — proven byte-for-byte against the
|
|
553
|
+
* receipt inventory — and atomically writes it into every declared root that is
|
|
554
|
+
* still absent. A root already present (the correct managed copy, or a user's
|
|
555
|
+
* conflict) is left untouched, so convergence is forward-only and never
|
|
556
|
+
* overwrites. Idempotent: a second call after a partial pass completes the rest.
|
|
557
|
+
*
|
|
558
|
+
* @returns repository-relative roots this call wrote
|
|
559
|
+
*/
|
|
560
|
+
function completeSecondarySkillInstallRoots(worktreePath, worktreeRealPath, skillId) {
|
|
561
|
+
const primaryAbs = resolveSkillInstallTarget(worktreePath, skillId);
|
|
562
|
+
const receiptBytes = (0, fs_1.readFileSync)(path_1.default.join(primaryAbs, install_plan_1.SKILL_RECEIPT_FILENAME));
|
|
563
|
+
const receipt = (0, install_plan_1.parseInstalledReceipt)(receiptBytes);
|
|
564
|
+
if (receipt === null) {
|
|
565
|
+
fail(exports.SkillInstallErrorCode.PAYLOAD_MISMATCH, { reason: 'primary-receipt-unreadable' });
|
|
566
|
+
}
|
|
567
|
+
// Read the primary payload from disk and prove it against the receipt before
|
|
568
|
+
// it is copied anywhere: a copy of a tampered primary must not propagate.
|
|
569
|
+
const payload = receipt.files.map((file) => {
|
|
570
|
+
const bytes = (0, fs_1.readFileSync)(path_1.default.join(primaryAbs, file.path));
|
|
571
|
+
if (!(0, integrity_1.digestMatches)((0, integrity_1.computeSha256Hex)(bytes), file.sha256)) {
|
|
572
|
+
fail(exports.SkillInstallErrorCode.PAYLOAD_MISMATCH, { reason: 'primary-file-digest' });
|
|
573
|
+
}
|
|
574
|
+
return { relativePath: file.path, bytes, executable: file.executable };
|
|
575
|
+
});
|
|
576
|
+
const directories = directoriesFor(receipt.files.map((file) => file.path));
|
|
577
|
+
const plannedTreeHash = (0, preview_diff_1.computeSkillTreeHash)([
|
|
578
|
+
...receipt.files.map((file) => ({
|
|
579
|
+
path: file.path,
|
|
580
|
+
sha256: file.sha256,
|
|
581
|
+
executable: file.executable,
|
|
582
|
+
})),
|
|
583
|
+
{ path: install_plan_1.SKILL_RECEIPT_FILENAME, sha256: (0, integrity_1.computeSha256Hex)(receiptBytes), executable: false },
|
|
584
|
+
]);
|
|
585
|
+
const operationId = (0, crypto_1.randomBytes)(16).toString('hex');
|
|
586
|
+
const completed = [];
|
|
587
|
+
for (const rootRel of (0, install_plan_1.receiptInstallRoots)(receipt)) {
|
|
588
|
+
const prefix = rootRel.slice(0, Math.max(0, rootRel.length - skillId.length - 1));
|
|
589
|
+
const abs = resolveSkillInstallTargetFor(worktreePath, prefix, skillId);
|
|
590
|
+
// Present already: either the correct managed copy or a user conflict. Both
|
|
591
|
+
// are left alone — convergence only fills absent roots.
|
|
592
|
+
if (inspectSkillDestination(abs).present)
|
|
593
|
+
continue;
|
|
594
|
+
stageAndCommitSkillRoot({
|
|
595
|
+
worktreePath,
|
|
596
|
+
worktreeRealPath,
|
|
597
|
+
rootPrefix: prefix,
|
|
598
|
+
skillId,
|
|
599
|
+
operationId,
|
|
600
|
+
payload,
|
|
601
|
+
directories,
|
|
602
|
+
receiptBytes,
|
|
603
|
+
plannedTreeHash,
|
|
604
|
+
});
|
|
605
|
+
completed.push(rootRel);
|
|
606
|
+
}
|
|
607
|
+
return { completed };
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Refuse to commit across a filesystem boundary.
|
|
611
|
+
*
|
|
612
|
+
* `rename(2)` is only atomic within one filesystem; across one it fails with
|
|
613
|
+
* EXDEV, and a caller that "helpfully" fell back to copy+delete would give up
|
|
614
|
+
* the single property the whole design rests on. Staging is placed inside the
|
|
615
|
+
* destination's own parent so this holds by construction — the check is here so
|
|
616
|
+
* a future change that moves staging elsewhere fails loudly.
|
|
617
|
+
*/
|
|
618
|
+
function assertSameFilesystem(stagingDir, destinationParent) {
|
|
619
|
+
let stagingDev;
|
|
620
|
+
let destinationDev;
|
|
621
|
+
try {
|
|
622
|
+
stagingDev = (0, fs_1.lstatSync)(stagingDir).dev;
|
|
623
|
+
destinationDev = (0, fs_1.lstatSync)(destinationParent).dev;
|
|
624
|
+
}
|
|
625
|
+
catch {
|
|
626
|
+
return fail(exports.SkillInstallErrorCode.STAGING_IO, { reason: 'stat-device' });
|
|
627
|
+
}
|
|
628
|
+
if (stagingDev !== destinationDev) {
|
|
629
|
+
fail(exports.SkillInstallErrorCode.CROSS_DEVICE);
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
/** Remove the staging root once it is empty, so it does not linger in a worktree. */
|
|
633
|
+
function pruneStagingRoot(stagingRoot) {
|
|
634
|
+
try {
|
|
635
|
+
(0, fs_1.rmdirSync)(stagingRoot);
|
|
636
|
+
}
|
|
637
|
+
catch {
|
|
638
|
+
// Still in use by a concurrent operation, or already gone.
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Drop staging directories left behind by a crashed process.
|
|
643
|
+
*
|
|
644
|
+
* Only entries whose name matches the operation-ID grammar are removed, so
|
|
645
|
+
* pointing this at a directory holding anything else cannot destroy content.
|
|
646
|
+
*
|
|
647
|
+
* @returns Number of staging directories removed
|
|
648
|
+
*/
|
|
649
|
+
function cleanupSkillInstallStaging(worktreePath) {
|
|
650
|
+
let removed = 0;
|
|
651
|
+
// Each install root has its own staging namespace (#1460); clean all of them.
|
|
652
|
+
for (const rootPrefix of constants_1.SKILL_INSTALL_ROOT_PREFIXES) {
|
|
653
|
+
const stagingRoot = (0, operation_store_1.getSkillInstallStagingRoot)(worktreePath, rootPrefix);
|
|
654
|
+
let entries;
|
|
655
|
+
try {
|
|
656
|
+
entries = (0, fs_1.readdirSync)(stagingRoot);
|
|
657
|
+
}
|
|
658
|
+
catch {
|
|
659
|
+
continue;
|
|
660
|
+
}
|
|
661
|
+
for (const entry of entries) {
|
|
662
|
+
if (!exports.SKILL_INSTALL_OPERATION_ID_PATTERN.test(entry))
|
|
663
|
+
continue;
|
|
664
|
+
(0, fs_1.rmSync)(path_1.default.join(stagingRoot, entry), { recursive: true, force: true });
|
|
665
|
+
removed += 1;
|
|
666
|
+
}
|
|
667
|
+
pruneStagingRoot(stagingRoot);
|
|
668
|
+
}
|
|
669
|
+
return removed;
|
|
670
|
+
}
|