commandmate 0.22.1 → 0.23.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 +86 -86
- package/.next/app-path-routes-manifest.json +17 -17
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +9 -9
- 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_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 -3
- package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_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.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route.js +1 -1
- package/.next/server/app/api/external-apps/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route.js +1 -1
- package/.next/server/app/api/fs/browse/route.js.nft.json +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route.js.nft.json +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +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/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route.js +1 -1
- package/.next/server/app/api/metrics/vibe/route.js.nft.json +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/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.js +1 -1
- package/.next/server/app/api/push/vapid/route.js.nft.json +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route.js +1 -1
- package/.next/server/app/api/repositories/excluded/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route.js +1 -1
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route.js.nft.json +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route.js +1 -1
- package/.next/server/app/api/skills/installations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route.js +1 -1
- package/.next/server/app/api/skills/operations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route.js +1 -1
- package/.next/server/app/api/skills/reindex/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route_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/tasks/[taskId]/cancel/route.js +1 -4
- package/.next/server/app/api/tasks/[taskId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route.js +1 -4
- package/.next/server/app/api/tasks/[taskId]/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route.js +1 -1
- package/.next/server/app/api/templates/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route.js +1 -1
- package/.next/server/app/api/templates/route.js.nft.json +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/todos/route.js +1 -1
- package/.next/server/app/api/todos/route.js.nft.json +1 -1
- package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route.js.nft.json +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route.js +1 -1
- package/.next/server/app/api/verification/runs/route.js.nft.json +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +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 +3 -3
- 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 +2 -2
- 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 +3 -3
- package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/tasks/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -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]/verify/route.js +1 -4
- package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route.js +1 -1
- package/.next/server/app/proxy/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +2 -2
- package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +17 -17
- package/.next/server/chunks/1029.js +1 -1
- package/.next/server/chunks/1068.js +1 -1
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/2546.js +1 -1
- package/.next/server/chunks/3241.js +1 -0
- package/.next/server/chunks/3417.js +1 -1
- package/.next/server/chunks/406.js +10 -6
- package/.next/server/chunks/4444.js +1 -1
- package/.next/server/chunks/5959.js +4 -5
- package/.next/server/chunks/5998.js +1 -12
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6274.js +3 -3
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6781.js +1 -0
- package/.next/server/chunks/7458.js +6 -0
- package/.next/server/chunks/{3753.js → 7970.js} +57 -32
- package/.next/server/chunks/8536.js +1 -1
- package/.next/server/chunks/8807.js +180 -127
- package/.next/server/chunks/9058.js +1 -1
- package/.next/server/chunks/9067.js +1 -1
- package/.next/server/chunks/9360.js +1 -1
- package/.next/server/chunks/9687.js +2 -2
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/server/src/middleware.js.map +1 -1
- package/.next/static/chunks/{6488-63dacfbab082ca8d.js → 6488-95ba9d24a76f0cc5.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/{page-c1be93f2595d0803.js → page-966a451ae7b0903a.js} +1 -1
- package/.next/trace +12 -12
- 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 +5 -1
- package/dist/cli/utils/api-client.d.ts.map +1 -1
- package/dist/cli/utils/api-client.js +9 -2
- package/dist/cli/utils/server-url.d.ts +23 -0
- package/dist/cli/utils/server-url.d.ts.map +1 -1
- package/dist/cli/utils/server-url.js +33 -0
- package/dist/server/src/config/log-config.js +10 -1
- package/dist/server/src/config/safe-directory.js +103 -0
- package/dist/server/src/config/system-directories.js +74 -9
- package/dist/server/src/lib/cli-tools/antigravity.js +19 -2
- package/dist/server/src/lib/cli-tools/codex.js +95 -1
- package/dist/server/src/lib/cli-tools/copilot.js +30 -1
- package/dist/server/src/lib/cli-tools/gemini.js +28 -2
- package/dist/server/src/lib/cli-tools/opencode.js +51 -2
- package/dist/server/src/lib/git/git-default-branch.js +59 -0
- package/dist/server/src/lib/hooks/agent-event-service.js +205 -0
- package/dist/server/src/lib/hooks/agent-event-types.js +7 -86
- package/dist/server/src/lib/hooks/hook-settings-generator.js +26 -11
- package/dist/server/src/lib/hooks/permission-decision-service.js +269 -0
- package/dist/server/src/lib/hooks/sources/abstain.js +78 -0
- package/dist/server/src/lib/hooks/sources/antigravity/hooks-config.js +372 -0
- package/dist/server/src/lib/hooks/sources/antigravity/source.js +225 -0
- package/dist/server/src/lib/hooks/sources/antigravity/tool-id.js +16 -0
- package/dist/server/src/lib/hooks/sources/claude/source.js +143 -0
- package/dist/server/src/lib/hooks/sources/claude/tool-id.js +18 -0
- package/dist/server/src/lib/hooks/sources/codex/hooks-config.js +465 -0
- package/dist/server/src/lib/hooks/sources/codex/source.js +138 -0
- package/dist/server/src/lib/hooks/sources/codex/tool-id.js +15 -0
- package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +473 -0
- package/dist/server/src/lib/hooks/sources/copilot/source.js +210 -0
- package/dist/server/src/lib/hooks/sources/copilot/tool-id.js +15 -0
- package/dist/server/src/lib/hooks/sources/define-source.js +169 -0
- package/dist/server/src/lib/hooks/sources/event-mapper.js +157 -0
- package/dist/server/src/lib/hooks/sources/gemini/event-vocabulary.js +102 -0
- package/dist/server/src/lib/hooks/sources/gemini/settings-generator.js +315 -0
- package/dist/server/src/lib/hooks/sources/gemini/shared-config-tree.js +103 -0
- package/dist/server/src/lib/hooks/sources/gemini/source.js +151 -0
- package/dist/server/src/lib/hooks/sources/gemini/tool-id.js +17 -0
- package/dist/server/src/lib/hooks/sources/hook-event-vocabulary.js +111 -0
- package/dist/server/src/lib/hooks/sources/index.js +62 -0
- package/dist/server/src/lib/hooks/sources/legacy-relay.js +84 -0
- package/dist/server/src/lib/hooks/sources/opencode/client.js +299 -0
- package/dist/server/src/lib/hooks/sources/opencode/ingest.js +261 -0
- package/dist/server/src/lib/hooks/sources/opencode/mappers.js +154 -0
- package/dist/server/src/lib/hooks/sources/opencode/payloads.js +189 -0
- package/dist/server/src/lib/hooks/sources/opencode/ports.js +295 -0
- package/dist/server/src/lib/hooks/sources/opencode/runtime.js +159 -0
- package/dist/server/src/lib/hooks/sources/opencode/source.js +250 -0
- package/dist/server/src/lib/hooks/sources/opencode/subscription.js +422 -0
- package/dist/server/src/lib/hooks/sources/opencode/tool-id.js +14 -0
- package/dist/server/src/lib/hooks/sources/opencode/turn-gate.js +193 -0
- package/dist/server/src/lib/hooks/sources/pending-decisions.js +127 -0
- package/dist/server/src/lib/hooks/sources/registry.js +111 -0
- package/dist/server/src/lib/hooks/sources/types.js +46 -0
- package/dist/server/src/lib/session/agent-session-lifecycle.js +82 -0
- package/dist/server/src/lib/session/claude-session.js +10 -3
- package/dist/server/src/lib/tasks/contract-message.js +175 -0
- package/dist/server/src/lib/verification/env-clean-gate.js +320 -0
- package/dist/server/src/lib/verification/env-snapshot.js +474 -0
- package/dist/server/src/lib/verification/gate-runner.js +802 -0
- package/dist/server/src/lib/verification/scope-gate.js +402 -0
- package/dist/server/src/lib/verification/verify-config.js +281 -0
- package/package.json +1 -1
- package/scripts/hooks/cmate-agent-event.sh +73 -3
- package/.next/server/chunks/8856.js +0 -4
- /package/.next/static/{d4vh4O18WEhXs4WbdShIs → wH6K6QNPHSdATFkVoIcy3}/_buildManifest.js +0 -0
- /package/.next/static/{d4vh4O18WEhXs4WbdShIs → wH6K6QNPHSdATFkVoIcy3}/_ssgManifest.js +0 -0
|
@@ -9,19 +9,18 @@
|
|
|
9
9
|
* runner. `agent-event-service` re-exports everything here, so existing
|
|
10
10
|
* importers are unaffected.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* **Nothing here names a tool.** It used to: `CLAUDE_HOOK_EVENT_NAMES` and
|
|
13
|
+
* `extractClaudeEventDetail` lived beside the words until Issue #1759 moved
|
|
14
|
+
* them to `lib/hooks/sources/hook-event-vocabulary`, where a source *selects*
|
|
15
|
+
* them. One tool's spellings sitting in the module every tool-agnostic consumer
|
|
16
|
+
* imports is how the next tool ends up appended to the same table instead of
|
|
17
|
+
* bringing its own — the copy-paste Epic #1720 exists to stop.
|
|
17
18
|
*
|
|
18
19
|
* @module lib/hooks/agent-event-types
|
|
19
20
|
*/
|
|
20
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.MAX_EVENT_DETAIL_LENGTH = exports.
|
|
22
|
+
exports.MAX_EVENT_DETAIL_LENGTH = exports.AGENT_EVENT_TYPES = void 0;
|
|
22
23
|
exports.isAgentEventType = isAgentEventType;
|
|
23
|
-
exports.mapClaudeHookEventName = mapClaudeHookEventName;
|
|
24
|
-
exports.extractClaudeEventDetail = extractClaudeEventDetail;
|
|
25
24
|
/**
|
|
26
25
|
* Event kinds accepted by `POST /api/hooks/agent-event`.
|
|
27
26
|
*
|
|
@@ -49,83 +48,5 @@ exports.AGENT_EVENT_TYPES = [
|
|
|
49
48
|
function isAgentEventType(value) {
|
|
50
49
|
return typeof value === 'string' && exports.AGENT_EVENT_TYPES.includes(value);
|
|
51
50
|
}
|
|
52
|
-
/**
|
|
53
|
-
* Claude Code's own `hook_event_name` values, mapped onto the vocabulary above.
|
|
54
|
-
*
|
|
55
|
-
* An injected `type: "http"` hook posts Claude's payload verbatim — there is no
|
|
56
|
-
* way to shape the body — so the receiver has to read Claude's spelling. Only
|
|
57
|
-
* the events CommandMate injects are listed, and an unmapped name is refused
|
|
58
|
-
* rather than silently filed under something else.
|
|
59
|
-
*
|
|
60
|
-
* `PermissionRequest` is absent because it has its own receiver: its response
|
|
61
|
-
* body is a decision the agent obeys, which is the opposite contract to this
|
|
62
|
-
* fire-and-forget route (#1724).
|
|
63
|
-
*
|
|
64
|
-
* `PostToolUse` **is** mapped, on the strength of a measurement taken for Issue
|
|
65
|
-
* #1726 rather than of the #1721 spike, which recorded it as unobserved. Driving
|
|
66
|
-
* a live v2.1.223 session on 2026-08-06 with a `PostToolUse` hook registered:
|
|
67
|
-
*
|
|
68
|
-
* ```
|
|
69
|
-
* 15:36:04.112 PreToolUse AskUserQuestion (picker drawn)
|
|
70
|
-
* 15:36:10.127 Notification permission_prompt (picker still up)
|
|
71
|
-
* 15:36:28.643 PostToolUse AskUserQuestion (the human answered)
|
|
72
|
-
* 15:36:29.992 Stop
|
|
73
|
-
* ```
|
|
74
|
-
*
|
|
75
|
-
* It fires, and it is the precise signal — "this tool call is over" — where
|
|
76
|
-
* `Stop` is "the turn is over" and can be minutes later if the agent keeps
|
|
77
|
-
* working after the answer. Both are wired up; see `agent-event-state`.
|
|
78
|
-
*/
|
|
79
|
-
exports.CLAUDE_HOOK_EVENT_NAMES = {
|
|
80
|
-
Stop: 'stop',
|
|
81
|
-
SubagentStop: 'stop',
|
|
82
|
-
Notification: 'notification',
|
|
83
|
-
SessionStart: 'session_start',
|
|
84
|
-
SessionEnd: 'session_end',
|
|
85
|
-
UserPromptSubmit: 'user_prompt_submit',
|
|
86
|
-
// Issue #1726. Injected with matcher `AskUserQuestion`, so in practice these
|
|
87
|
-
// only ever arrive for that tool — but the receiver re-reads `tool_name`
|
|
88
|
-
// rather than trusting the matcher, because a user's own settings.json is
|
|
89
|
-
// concatenated with the injected one and may register a wider matcher.
|
|
90
|
-
PreToolUse: 'pre_tool_use',
|
|
91
|
-
PostToolUse: 'post_tool_use',
|
|
92
|
-
};
|
|
93
|
-
/** @returns The event this `hook_event_name` maps to, or null when unmapped. */
|
|
94
|
-
function mapClaudeHookEventName(value) {
|
|
95
|
-
if (typeof value !== 'string')
|
|
96
|
-
return null;
|
|
97
|
-
return exports.CLAUDE_HOOK_EVENT_NAMES[value] ?? null;
|
|
98
|
-
}
|
|
99
51
|
/** Bound on the stored `detail`; every observed value is a short enum-ish word. */
|
|
100
52
|
exports.MAX_EVENT_DETAIL_LENGTH = 128;
|
|
101
|
-
/**
|
|
102
|
-
* The event's subtype, as a single short string, or null when it has none.
|
|
103
|
-
*
|
|
104
|
-
* Each event spells this differently and none of them share a field:
|
|
105
|
-
*
|
|
106
|
-
* - `Notification` → `notification_type` (`permission_prompt` / `idle_prompt`).
|
|
107
|
-
* This is also what a `Notification` matcher is tested against — **not**
|
|
108
|
-
* `message`, which is English prose for a human (D3).
|
|
109
|
-
* - `SessionEnd` → `reason` (`clear` / `prompt_input_exit` / …)
|
|
110
|
-
* - `SessionStart` → `source` (`startup` / `clear` / …)
|
|
111
|
-
* - `PreToolUse` / `PostToolUse` → `tool_name` (`AskUserQuestion`), Issue #1726
|
|
112
|
-
*
|
|
113
|
-
* `Stop` and `UserPromptSubmit` have no subtype, so they answer null.
|
|
114
|
-
*/
|
|
115
|
-
function extractClaudeEventDetail(event, payload) {
|
|
116
|
-
const field = event === 'notification'
|
|
117
|
-
? 'notification_type'
|
|
118
|
-
: event === 'session_end'
|
|
119
|
-
? 'reason'
|
|
120
|
-
: event === 'session_start'
|
|
121
|
-
? 'source'
|
|
122
|
-
: event === 'pre_tool_use' || event === 'post_tool_use'
|
|
123
|
-
? 'tool_name'
|
|
124
|
-
: null;
|
|
125
|
-
if (field === null)
|
|
126
|
-
return null;
|
|
127
|
-
const value = payload[field];
|
|
128
|
-
if (typeof value !== 'string' || value === '')
|
|
129
|
-
return null;
|
|
130
|
-
return value.slice(0, exports.MAX_EVENT_DETAIL_LENGTH);
|
|
131
|
-
}
|
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
* - **Every hook failure is fail-open.** A refused connection or a timeout
|
|
29
29
|
* costs the event, never the session.
|
|
30
30
|
*
|
|
31
|
+
* Issue #1759 made this module *Claude's* config serialiser rather than *the*
|
|
32
|
+
* config serialiser: it is reached through `claudeAgentEventSource.prepareLaunch`
|
|
33
|
+
* (seams S3/S4/S5), and the four other hook tools each bring their own — their
|
|
34
|
+
* files live in different places, nest differently, and cannot use `type:"http"`
|
|
35
|
+
* at all. Nothing here changed; only who calls it did.
|
|
36
|
+
*
|
|
31
37
|
* The generated file is written rather than passed inline. `--settings` does
|
|
32
38
|
* accept a JSON string (D2), but the launch command travels to the CLI through
|
|
33
39
|
* `tmux send-keys` as a single line, and a ~1 KB argument of braces, quotes and
|
|
@@ -55,8 +61,10 @@ const crypto_1 = require("crypto");
|
|
|
55
61
|
const fs_1 = require("fs");
|
|
56
62
|
const os_1 = require("os");
|
|
57
63
|
const path_1 = require("path");
|
|
64
|
+
const safe_directory_1 = require("../../config/safe-directory");
|
|
58
65
|
const env_1 = require("../../lib/env");
|
|
59
66
|
const types_1 = require("../../lib/cli-tools/types");
|
|
67
|
+
const tool_id_1 = require("../../lib/hooks/sources/claude/tool-id");
|
|
60
68
|
const permission_request_payload_1 = require("../../lib/hooks/permission-request-payload");
|
|
61
69
|
const logger_1 = require("../../lib/logger");
|
|
62
70
|
const logger = (0, logger_1.createLogger)('lib/hooks/hook-settings-generator');
|
|
@@ -178,18 +186,25 @@ function isHookInjectionEnabled() {
|
|
|
178
186
|
function isAuthTokenExpected() {
|
|
179
187
|
return Boolean(process.env[exports.AUTH_TOKEN_ENV_VAR] || process.env.CM_AUTH_TOKEN_HASH);
|
|
180
188
|
}
|
|
181
|
-
/**
|
|
189
|
+
/**
|
|
190
|
+
* Directory the generated settings files live in.
|
|
191
|
+
*
|
|
192
|
+
* Issue #1774: `writeAgentHookSettings` calls `mkdirSync(…, {recursive:true})`
|
|
193
|
+
* on the result, so a value inside `/proc`, `/sys` or `/dev` would spin the
|
|
194
|
+
* event loop forever rather than throw — the fail-open `try/catch` below is
|
|
195
|
+
* never reached, because the call never returns. Such a value is refused here
|
|
196
|
+
* and the default is used.
|
|
197
|
+
*/
|
|
182
198
|
function getHookSettingsDirectory(options = {}) {
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
return (0, path_1.join)((0, os_1.homedir)(), '.commandmate', 'hooks');
|
|
199
|
+
const fallback = (0, path_1.join)((0, os_1.homedir)(), '.commandmate', 'hooks');
|
|
200
|
+
if (options.directory) {
|
|
201
|
+
return (0, safe_directory_1.resolveSafeDirectory)(options.directory, fallback, 'HookSettingsOptions.directory');
|
|
202
|
+
}
|
|
203
|
+
return (0, safe_directory_1.resolveSafeDirectory)(process.env.CM_AGENT_HOOKS_DIR, fallback, 'CM_AGENT_HOOKS_DIR');
|
|
189
204
|
}
|
|
190
205
|
/** The instance this settings file speaks for; primary when unspecified. */
|
|
191
206
|
function resolveTargetInstanceId(target) {
|
|
192
|
-
const cliToolId = target.cliToolId ??
|
|
207
|
+
const cliToolId = target.cliToolId ?? tool_id_1.CLAUDE_CLI_TOOL_ID;
|
|
193
208
|
const instanceId = target.instanceId ?? cliToolId;
|
|
194
209
|
return instanceId;
|
|
195
210
|
}
|
|
@@ -202,7 +217,7 @@ function resolveTargetInstanceId(target) {
|
|
|
202
217
|
* restart overwrites rather than accumulates.
|
|
203
218
|
*/
|
|
204
219
|
function getHookSettingsPath(target, options = {}) {
|
|
205
|
-
const cliToolId = target.cliToolId ??
|
|
220
|
+
const cliToolId = target.cliToolId ?? tool_id_1.CLAUDE_CLI_TOOL_ID;
|
|
206
221
|
const instanceId = resolveTargetInstanceId(target);
|
|
207
222
|
const slug = `${cliToolId}-${target.worktreeId}-${instanceId}`.replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
208
223
|
const digest = (0, crypto_1.createHash)('sha256')
|
|
@@ -236,7 +251,7 @@ function buildPermissionRequestUrl(target, options = {}) {
|
|
|
236
251
|
return buildReceiverUrl(exports.PERMISSION_REQUEST_PATH, target, options);
|
|
237
252
|
}
|
|
238
253
|
function buildReceiverUrl(path, target, options) {
|
|
239
|
-
const cliToolId = target.cliToolId ??
|
|
254
|
+
const cliToolId = target.cliToolId ?? tool_id_1.CLAUDE_CLI_TOOL_ID;
|
|
240
255
|
const port = options.port ?? (0, env_1.getServerPort)();
|
|
241
256
|
const params = new URLSearchParams({
|
|
242
257
|
tool: cliToolId,
|
|
@@ -285,7 +300,7 @@ function buildSessionStartCommand(target, options = {}) {
|
|
|
285
300
|
return [
|
|
286
301
|
shellQuote(relay),
|
|
287
302
|
'--tool',
|
|
288
|
-
shellQuote(target.cliToolId ??
|
|
303
|
+
shellQuote(target.cliToolId ?? tool_id_1.CLAUDE_CLI_TOOL_ID),
|
|
289
304
|
'--event',
|
|
290
305
|
'session_start',
|
|
291
306
|
'--worktree-id',
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auto-Yes v2: adjudicating Claude's `PermissionRequest` hook (Issue #1724).
|
|
4
|
+
*
|
|
5
|
+
* Auto-Yes has always worked by reading the pane with a regex and injecting a
|
|
6
|
+
* keystroke. This module is the structured replacement: Claude asks *before*
|
|
7
|
+
* drawing the dialog, over HTTP, with the tool call attached, and the answer is
|
|
8
|
+
* a verdict rather than a key. Three bug families stop being possible rather
|
|
9
|
+
* than being fixed — a dialog the detectors cannot read (#1708) never has to be
|
|
10
|
+
* read, deny patterns cannot be poisoned by scrollback (#1699) because there is
|
|
11
|
+
* no scrollback in the input, and an overlay cannot be mistaken for a prompt
|
|
12
|
+
* (#1495) because nothing is typed anywhere.
|
|
13
|
+
*
|
|
14
|
+
* ## The safety rule
|
|
15
|
+
*
|
|
16
|
+
* **A wrong `allow` executes a command; a wrong no-decision costs a dialog.**
|
|
17
|
+
* Every branch that is not certain therefore returns no-decision, which the
|
|
18
|
+
* Issue #1721 spike measured (D5) as landing back in the ordinary TUI approval
|
|
19
|
+
* flow — the behaviour of a machine where this feature does not exist. Timeouts
|
|
20
|
+
* and refused connections are fail-open for the same reason (§1.1).
|
|
21
|
+
*
|
|
22
|
+
* `deny` is never returned. Today's Auto-Yes suppression means *"do not answer
|
|
23
|
+
* this"*, not *"refuse this"*, and a contract's `denyPatterns` is a rule about
|
|
24
|
+
* what may be auto-answered — not a rule about what the human may approve.
|
|
25
|
+
* Turning suppression into a `Denied by PermissionRequest hook` would change the
|
|
26
|
+
* meaning of every existing contract in the field.
|
|
27
|
+
*
|
|
28
|
+
* ## Why the verdict is computed as a `multiple_choice`
|
|
29
|
+
*
|
|
30
|
+
* The dialog this hook pre-empts is detected on screen as a `multiple_choice`
|
|
31
|
+
* prompt ("Do you want to proceed? / 1. Yes / 2. Yes, and … / 3. No"). Feeding
|
|
32
|
+
* that same type into the shared policy evaluator is what stops the hook from
|
|
33
|
+
* being *more permissive* than the poller it front-runs: under `mode: safe` the
|
|
34
|
+
* screen path suppresses a permission dialog, so this one must too.
|
|
35
|
+
*
|
|
36
|
+
* @module lib/hooks/permission-decision-service
|
|
37
|
+
*/
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.PERMISSION_DECISION_SLOW_MS = exports.PERMISSION_REQUEST_PROMPT_TYPE = void 0;
|
|
40
|
+
exports.decidePermissionRequest = decidePermissionRequest;
|
|
41
|
+
exports.resolvePermissionRequest = resolvePermissionRequest;
|
|
42
|
+
const auto_yes_state_1 = require("../../lib/auto-yes-state");
|
|
43
|
+
const db_instance_1 = require("../../lib/db/db-instance");
|
|
44
|
+
const chat_db_1 = require("../../lib/db/chat-db");
|
|
45
|
+
const auto_yes_policy_1 = require("../../lib/polling/auto-yes-policy");
|
|
46
|
+
const auto_yes_resolver_1 = require("../../lib/polling/auto-yes-resolver");
|
|
47
|
+
const auto_yes_suppression_state_1 = require("../../lib/polling/auto-yes-suppression-state");
|
|
48
|
+
const agent_event_state_1 = require("../../lib/session/agent-event-state");
|
|
49
|
+
const logger_1 = require("../../lib/logger");
|
|
50
|
+
const ask_user_question_payload_1 = require("./ask-user-question-payload");
|
|
51
|
+
const permission_request_payload_1 = require("./permission-request-payload");
|
|
52
|
+
const logger = (0, logger_1.createLogger)('lib/hooks/permission-decision-service');
|
|
53
|
+
/**
|
|
54
|
+
* How the pre-empted dialog would have been classified on screen.
|
|
55
|
+
*
|
|
56
|
+
* Not cosmetic: it is what `mode: safe` (yes_no only) and `mode: allow-listed`
|
|
57
|
+
* are evaluated against, so the hook and the poller agree.
|
|
58
|
+
*/
|
|
59
|
+
exports.PERMISSION_REQUEST_PROMPT_TYPE = 'multiple_choice';
|
|
60
|
+
/** Response time past which the hook is holding the agent up noticeably. */
|
|
61
|
+
exports.PERMISSION_DECISION_SLOW_MS = 500;
|
|
62
|
+
const NO_DECISION = (reason) => ({
|
|
63
|
+
behavior: null,
|
|
64
|
+
reason,
|
|
65
|
+
});
|
|
66
|
+
/**
|
|
67
|
+
* The verdict for one permission request. Pure apart from reading Auto-Yes
|
|
68
|
+
* state and the (TTL-cached) contract policy; the recording side effects live
|
|
69
|
+
* in {@link resolvePermissionRequest}.
|
|
70
|
+
*
|
|
71
|
+
* Order matters and mirrors the table in Issue #1724:
|
|
72
|
+
*
|
|
73
|
+
* | condition | verdict |
|
|
74
|
+
* |---|---|
|
|
75
|
+
* | payload unreadable | no-decision |
|
|
76
|
+
* | `AskUserQuestion` | no-decision |
|
|
77
|
+
* | Auto-Yes off / expired | no-decision |
|
|
78
|
+
* | policy suppresses (mode off, deny pattern, type) | no-decision + suppression |
|
|
79
|
+
* | otherwise | allow |
|
|
80
|
+
*
|
|
81
|
+
* @param session - Worktree / tool / instance the request came from
|
|
82
|
+
* @param payload - Parsed payload, or null when it could not be parsed
|
|
83
|
+
*/
|
|
84
|
+
function decidePermissionRequest(session, payload) {
|
|
85
|
+
if (!payload) {
|
|
86
|
+
return NO_DECISION('unknown-payload');
|
|
87
|
+
}
|
|
88
|
+
// Before the Auto-Yes check on purpose: this verdict must not depend on
|
|
89
|
+
// whether Auto-Yes happens to be on, so that turning Auto-Yes on can never
|
|
90
|
+
// start approving questions.
|
|
91
|
+
if (payload.toolName === permission_request_payload_1.ASK_USER_QUESTION_TOOL) {
|
|
92
|
+
return NO_DECISION('ask-user-question');
|
|
93
|
+
}
|
|
94
|
+
const { worktreeId, cliToolId, instanceId } = session;
|
|
95
|
+
// Returns null for "never enabled" and for expired (it disables on read), so
|
|
96
|
+
// the expiry boundary is the same one the poller sees.
|
|
97
|
+
const state = (0, auto_yes_state_1.getAutoYesState)(worktreeId, cliToolId, instanceId);
|
|
98
|
+
if (!state?.enabled) {
|
|
99
|
+
return NO_DECISION('auto-yes-disabled');
|
|
100
|
+
}
|
|
101
|
+
const policy = (0, auto_yes_policy_1.getSessionAutoYesPolicy)(worktreeId, cliToolId, instanceId);
|
|
102
|
+
const denial = (0, auto_yes_resolver_1.evaluatePolicyAgainstTexts)(exports.PERMISSION_REQUEST_PROMPT_TYPE, (0, permission_request_payload_1.collectToolInputMatchTexts)(payload.toolName, payload.toolInput), policy);
|
|
103
|
+
if (denial) {
|
|
104
|
+
return {
|
|
105
|
+
behavior: null,
|
|
106
|
+
reason: 'policy-suppressed',
|
|
107
|
+
suppressedBy: denial.reason,
|
|
108
|
+
pattern: denial.pattern,
|
|
109
|
+
mode: policy?.mode ?? null,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return { behavior: 'allow', reason: 'auto-yes', mode: policy?.mode ?? null };
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Persist an `allow` to the prompt history `capture --prompts` reads
|
|
116
|
+
* (Issue #1685's layer).
|
|
117
|
+
*
|
|
118
|
+
* Only `allow` is written here, and that asymmetry is deliberate. An allowed
|
|
119
|
+
* request never draws a dialog, so this row is the *only* record that anything
|
|
120
|
+
* happened — without it, Auto-Yes v2 approves commands invisibly. Every other
|
|
121
|
+
* verdict ends in the dialog being drawn, where the existing response poller
|
|
122
|
+
* records the prompt exactly as it does today; a second row would double-count
|
|
123
|
+
* the audit trail, and writing it as `pending` would be worse still, because
|
|
124
|
+
* `recordAnsweredPrompt` stamps the newest pending row when the real answer
|
|
125
|
+
* arrives and would attach the human's answer to this synthetic one.
|
|
126
|
+
*
|
|
127
|
+
* A new row is always created rather than reusing `recordAnsweredPrompt`, which
|
|
128
|
+
* looks for a pending row to stamp: on this path there is no dialog, so any
|
|
129
|
+
* pending row it found would belong to a *different*, still-unanswered prompt.
|
|
130
|
+
*
|
|
131
|
+
* Never throws — the verdict has already been decided and the agent is waiting.
|
|
132
|
+
*/
|
|
133
|
+
function recordAllowedPermission(session, payload) {
|
|
134
|
+
const texts = (0, permission_request_payload_1.collectToolInputMatchTexts)(payload.toolName, payload.toolInput);
|
|
135
|
+
const target = texts.join('\n').slice(0, auto_yes_resolver_1.MAX_DENY_MATCH_TEXT_LENGTH);
|
|
136
|
+
const now = new Date();
|
|
137
|
+
try {
|
|
138
|
+
(0, chat_db_1.createMessage)((0, db_instance_1.getDbInstance)(), {
|
|
139
|
+
worktreeId: session.worktreeId,
|
|
140
|
+
role: 'assistant',
|
|
141
|
+
content: `${payload.toolName}: ${target}`.slice(0, auto_yes_resolver_1.MAX_DENY_MATCH_TEXT_LENGTH),
|
|
142
|
+
// D2: there is no tool_use_id. `prompt_id` + `tool_name` is the
|
|
143
|
+
// correlation key that actually exists in the payload.
|
|
144
|
+
summary: `PermissionRequest allow · tool=${payload.toolName} · prompt_id=${payload.promptId ?? 'unknown'}`,
|
|
145
|
+
messageType: 'prompt',
|
|
146
|
+
promptData: {
|
|
147
|
+
type: 'multiple_choice',
|
|
148
|
+
question: `Approve ${payload.toolName}?`,
|
|
149
|
+
// Empty on purpose: the hook fires before the dialog exists, so the
|
|
150
|
+
// options Claude would have offered were never rendered. Inventing
|
|
151
|
+
// them would put text in the audit trail that nobody ever saw.
|
|
152
|
+
options: [],
|
|
153
|
+
status: 'answered',
|
|
154
|
+
answer: 'allow',
|
|
155
|
+
answeredAt: now.toISOString(),
|
|
156
|
+
answeredBy: 'auto',
|
|
157
|
+
// Exactly what the deny patterns were judged against (#1699).
|
|
158
|
+
approvalTarget: target,
|
|
159
|
+
},
|
|
160
|
+
timestamp: now,
|
|
161
|
+
cliToolId: session.cliToolId,
|
|
162
|
+
instanceId: session.instanceId,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
logger.warn('permission-request:audit-record-failed', {
|
|
167
|
+
worktreeId: session.worktreeId,
|
|
168
|
+
instanceId: session.instanceId,
|
|
169
|
+
toolName: payload.toolName,
|
|
170
|
+
error: error instanceof Error ? error.message : String(error),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Permission modes in which declining to decide does NOT produce a dialog.
|
|
176
|
+
*
|
|
177
|
+
* `bypassPermissions` is Claude's "do not ask me" mode. If the hook fires at
|
|
178
|
+
* all there, a no-decision is answered by the agent itself and no human is ever
|
|
179
|
+
* blocked — so reporting a dialog would make `wait --on-prompt agent` exit 10
|
|
180
|
+
* on a session that is running perfectly well. Whether the hook fires in that
|
|
181
|
+
* mode was NOT measured by the #1721 spike; this guard costs nothing and
|
|
182
|
+
* removes the question.
|
|
183
|
+
*/
|
|
184
|
+
const NON_BLOCKING_PERMISSION_MODES = new Set(['bypassPermissions']);
|
|
185
|
+
/**
|
|
186
|
+
* Tell the detection layer that a dialog is about to be drawn (Issue #1725).
|
|
187
|
+
*
|
|
188
|
+
* A no-decision means precisely this: D5 measured `{}` landing back in the
|
|
189
|
+
* ordinary TUI approval flow, i.e. the dialog appears. That is ~6 seconds
|
|
190
|
+
* before `Notification(permission_prompt)` announces the same dialog (§5.5), so
|
|
191
|
+
* it is the earliest moment anything in this system can know a human is needed.
|
|
192
|
+
*
|
|
193
|
+
* It is a prediction rather than an observation, and it is recorded as one:
|
|
194
|
+
* `agent-event-state` expires a `permission-request` record that nothing
|
|
195
|
+
* corroborates within 20 s. See STRUCTURED_PROMPT_PROVISIONAL_MAX_AGE_MS for
|
|
196
|
+
* why the asymmetry with the notification source is deliberate.
|
|
197
|
+
*
|
|
198
|
+
* `AskUserQuestion` is included even though this Issue does not claim to detect
|
|
199
|
+
* its screens: it also raises a `PermissionRequest`, and allowing it does not
|
|
200
|
+
* dismiss the picker (§5.6), so a no-decision there is followed by a screen a
|
|
201
|
+
* human must act on just the same. What is NOT claimed is that the state
|
|
202
|
+
* survives — nothing about that screen produces events, so unless the scraper
|
|
203
|
+
* corroborates it the record expires, which is the honest outcome for a screen
|
|
204
|
+
* this layer cannot see. That screen belongs to #1708 / #1726.
|
|
205
|
+
*/
|
|
206
|
+
function reportPendingDialog(session, payload) {
|
|
207
|
+
if (payload?.permissionMode && NON_BLOCKING_PERMISSION_MODES.has(payload.permissionMode)) {
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
(0, agent_event_state_1.reportPermissionRequestPending)(session.worktreeId, session.cliToolId, session.instanceId, payload?.toolName ?? null);
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Adjudicate a permission request and record the outcome.
|
|
214
|
+
*
|
|
215
|
+
* @param session - Worktree / tool / instance the request came from
|
|
216
|
+
* @param payload - Parsed payload, or null when it could not be parsed
|
|
217
|
+
* @returns The verdict the route serialises
|
|
218
|
+
*/
|
|
219
|
+
function resolvePermissionRequest(session, payload) {
|
|
220
|
+
const decision = decidePermissionRequest(session, payload);
|
|
221
|
+
// Issue #1726: `AskUserQuestion` raises a `PermissionRequest` carrying the
|
|
222
|
+
// same `tool_input` its `PreToolUse` does (§5.6), so the questions are
|
|
223
|
+
// recorded from here too. Redundant on a session this server started — both
|
|
224
|
+
// hooks are injected — and the only source on a session started before the
|
|
225
|
+
// upgrade, whose settings file has no `PreToolUse` entry at all. The two
|
|
226
|
+
// deliveries carry identical content, so the second is a harmless overwrite.
|
|
227
|
+
//
|
|
228
|
+
// This does NOT adjudicate anything: `decidePermissionRequest` still answers
|
|
229
|
+
// no-decision for `AskUserQuestion`, unchanged from #1724, because allowing it
|
|
230
|
+
// does not dismiss the picker.
|
|
231
|
+
if (payload?.toolName === permission_request_payload_1.ASK_USER_QUESTION_TOOL) {
|
|
232
|
+
const spec = (0, ask_user_question_payload_1.parseAskUserQuestionPayload)({
|
|
233
|
+
tool_name: payload.toolName,
|
|
234
|
+
tool_input: payload.toolInput,
|
|
235
|
+
prompt_id: payload.promptId,
|
|
236
|
+
});
|
|
237
|
+
if (spec) {
|
|
238
|
+
(0, agent_event_state_1.recordAskUserQuestion)(session.worktreeId, session.cliToolId, session.instanceId, spec);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (decision.behavior !== 'allow') {
|
|
242
|
+
reportPendingDialog(session, payload);
|
|
243
|
+
}
|
|
244
|
+
if (decision.reason === 'policy-suppressed' && decision.suppressedBy) {
|
|
245
|
+
// Issue #1684's record, so `capture --json` can say why the worker is
|
|
246
|
+
// waiting on a dialog it never asked for. Recording it — and NOT denying —
|
|
247
|
+
// is what keeps the meaning of `denyPatterns` unchanged.
|
|
248
|
+
(0, auto_yes_suppression_state_1.recordPolicySuppression)(session.worktreeId, session.cliToolId, session.instanceId, {
|
|
249
|
+
reason: decision.suppressedBy,
|
|
250
|
+
mode: decision.mode ?? null,
|
|
251
|
+
promptType: exports.PERMISSION_REQUEST_PROMPT_TYPE,
|
|
252
|
+
pattern: decision.pattern,
|
|
253
|
+
});
|
|
254
|
+
logger.warn('permission-request:suppressed-by-policy', {
|
|
255
|
+
worktreeId: session.worktreeId,
|
|
256
|
+
cliToolId: session.cliToolId,
|
|
257
|
+
instanceId: session.instanceId,
|
|
258
|
+
toolName: payload?.toolName,
|
|
259
|
+
promptId: payload?.promptId,
|
|
260
|
+
reason: decision.suppressedBy,
|
|
261
|
+
mode: decision.mode ?? null,
|
|
262
|
+
pattern: decision.pattern,
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
if (decision.behavior === 'allow' && payload) {
|
|
266
|
+
recordAllowedPermission(session, payload);
|
|
267
|
+
}
|
|
268
|
+
return decision;
|
|
269
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* What it costs to not decide (Issue #1759, constraint C3).
|
|
4
|
+
*
|
|
5
|
+
* Auto-Yes v2 abstains constantly — it is off, the worktree has no policy, the
|
|
6
|
+
* payload did not parse, the tool is `AskUserQuestion`. On Claude that is free:
|
|
7
|
+
* #1721 D5 measured an empty reply as indistinguishable from having no hook, so
|
|
8
|
+
* the dialog appears and a human answers it. The rule the codebase learned from
|
|
9
|
+
* that measurement is "when in doubt, say nothing", and it is written into
|
|
10
|
+
* comments in several files.
|
|
11
|
+
*
|
|
12
|
+
* **That rule is false on two of the six tools.**
|
|
13
|
+
*
|
|
14
|
+
* - opencode waits, with no timeout at all. #1758 §5.5.3 left a permission
|
|
15
|
+
* unanswered for 10 minutes 19 seconds and it was still pending; the session
|
|
16
|
+
* does not fall through to a TUI prompt, because the TUI prompt and the API
|
|
17
|
+
* request are the same pending object. Abstaining stops the agent silently.
|
|
18
|
+
* - antigravity reads an empty `{}` as a *denial* and refuses the tool call
|
|
19
|
+
* (#1757 P10, confirmed against a hooks-free control run). Its `PreToolUse`
|
|
20
|
+
* `decision` field is required, and "required" turns out to mean fail-closed.
|
|
21
|
+
*
|
|
22
|
+
* Neither failure produces an error anywhere. The session just stops, which is
|
|
23
|
+
* the same thing a thinking agent looks like. So abstention has to be a
|
|
24
|
+
* decision the caller makes knowingly, and this module is the thing that makes
|
|
25
|
+
* it knowing: it reads {@link AgentEventSource.noDecision} and says, in one
|
|
26
|
+
* struct, whether silence is safe and what to tell the operator when it is not.
|
|
27
|
+
*
|
|
28
|
+
* @module lib/hooks/sources/abstain
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.describeNoDecision = describeNoDecision;
|
|
32
|
+
exports.describeAbstain = describeAbstain;
|
|
33
|
+
exports.isAbstainSafe = isAbstainSafe;
|
|
34
|
+
/**
|
|
35
|
+
* Judge one {@link NoDecisionBehavior}.
|
|
36
|
+
*
|
|
37
|
+
* Split from {@link describeAbstain} so a source can be judged before it exists
|
|
38
|
+
* — Phase 4-2…4-5 tests a spec's declared value without constructing anything.
|
|
39
|
+
*/
|
|
40
|
+
function describeNoDecision(behavior) {
|
|
41
|
+
switch (behavior.kind) {
|
|
42
|
+
case 'proceeds':
|
|
43
|
+
return {
|
|
44
|
+
safe: true,
|
|
45
|
+
blocksForMs: 0,
|
|
46
|
+
summary: 'the agent continues with its own approval flow',
|
|
47
|
+
};
|
|
48
|
+
case 'blocks':
|
|
49
|
+
return {
|
|
50
|
+
safe: false,
|
|
51
|
+
blocksForMs: null,
|
|
52
|
+
summary: 'the agent waits indefinitely; nothing else will unblock it',
|
|
53
|
+
};
|
|
54
|
+
case 'blocksUntil':
|
|
55
|
+
return {
|
|
56
|
+
safe: false,
|
|
57
|
+
blocksForMs: behavior.timeoutMs,
|
|
58
|
+
summary: `the agent waits up to ${behavior.timeoutMs}ms before continuing`,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* What happens if this source is given no verdict.
|
|
64
|
+
*
|
|
65
|
+
* @param source - The source about to be abstained on
|
|
66
|
+
* @returns Whether silence is safe, and the sentence to log when it is not
|
|
67
|
+
*/
|
|
68
|
+
function describeAbstain(source) {
|
|
69
|
+
return describeNoDecision(source.noDecision);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Shorthand for the common guard.
|
|
73
|
+
*
|
|
74
|
+
* @returns Whether abstaining leaves the agent able to make progress
|
|
75
|
+
*/
|
|
76
|
+
function isAbstainSafe(source) {
|
|
77
|
+
return describeAbstain(source).safe;
|
|
78
|
+
}
|