commandmate 0.47.0 → 0.47.2
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 +501 -501
- package/.next/app-path-routes-manifest.json +36 -36
- package/.next/build-manifest.json +8 -8
- package/.next/diagnostics/framework.json +1 -1
- package/.next/next-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +15 -15
- package/.next/react-loadable-manifest.json +1 -1
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page.js +2 -2
- 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/agents/update/route.js +2 -2
- package/.next/server/app/api/agents/update/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route.js +1 -1
- package/.next/server/app/api/agents/versions/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/release-notes/route.js +1 -1
- package/.next/server/app/api/app/release-notes/route.js.nft.json +1 -1
- package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route.js +5 -5
- package/.next/server/app/api/app/update/route.js.nft.json +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route.js.nft.json +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route.js +1 -1
- package/.next/server/app/api/auth/login/route.js.nft.json +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route.js +1 -1
- package/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route.js +1 -1
- package/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route.js.nft.json +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route.js +1 -1
- package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route.js +1 -1
- package/.next/server/app/api/external-apps/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route.js +1 -1
- package/.next/server/app/api/fs/browse/route.js.nft.json +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route.js.nft.json +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +2 -2
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route.js +2 -2
- 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.js +1 -1
- package/.next/server/app/api/ollama/models/route.js.nft.json +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route.js +1 -1
- package/.next/server/app/api/push/escalation/route.js.nft.json +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route.js +1 -1
- package/.next/server/app/api/push/subscriptions/route.js.nft.json +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route.js +1 -1
- package/.next/server/app/api/push/vapid/route.js.nft.json +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route.js +1 -1
- package/.next/server/app/api/relays/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route.js +2 -2
- package/.next/server/app/api/remote/pair/route.js.nft.json +1 -1
- package/.next/server/app/api/remote/pair/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/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/settings/default-agents/route.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route.js.nft.json +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route.js +1 -1
- package/.next/server/app/api/skills/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route.js +1 -1
- package/.next/server/app/api/skills/installations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route.js +2 -2
- package/.next/server/app/api/skills/operations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route.js +1 -1
- package/.next/server/app/api/skills/reindex/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route.js +1 -1
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route.js +1 -1
- package/.next/server/app/api/slash-commands/route.js.nft.json +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route.js +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/verification/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route.js.nft.json +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route.js +1 -1
- package/.next/server/app/api/verification/runs/route.js.nft.json +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +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 +7 -7
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/env/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +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]/opencode/diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +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 +5 -5
- 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]/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 +2 -2
- 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/config/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/verify/config/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +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/apply-default-agents/route.js +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/apple-icon.png/route.js +1 -1
- package/.next/server/app/apple-icon.png/route.js.nft.json +1 -1
- package/.next/server/app/apple-icon.png.meta +1 -1
- package/.next/server/app/icon.png/route.js +1 -1
- package/.next/server/app/icon.png/route.js.nft.json +1 -1
- package/.next/server/app/icon.png.meta +1 -1
- package/.next/server/app/icon1.png/route.js +1 -1
- package/.next/server/app/icon1.png/route.js.nft.json +1 -1
- package/.next/server/app/icon1.png.meta +1 -1
- package/.next/server/app/icon2.png/route.js +1 -1
- package/.next/server/app/icon2.png/route.js.nft.json +1 -1
- package/.next/server/app/icon2.png.meta +1 -1
- package/.next/server/app/login/page.js +2 -2
- 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.js +2 -2
- package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest.meta +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 +2 -2
- 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 +2 -2
- 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.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.js +2 -2
- 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 +2 -2
- 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 +2 -2
- 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 -2
- package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page.js +2 -2
- package/.next/server/app/skills/installed/page.js.nft.json +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page.js +2 -2
- package/.next/server/app/skills/page.js.nft.json +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- 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 +4 -4
- 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 +36 -36
- package/.next/server/chunks/{5048.js → 1185.js} +1 -1
- package/.next/server/chunks/1656.js +19 -0
- package/.next/server/chunks/2460.js +1 -1
- package/.next/server/chunks/255.js +1 -0
- package/.next/server/chunks/3241.js +1 -1
- package/.next/server/chunks/3505.js +7 -0
- package/.next/server/chunks/3897.js +22 -0
- package/.next/server/chunks/4072.js +5 -5
- package/.next/server/chunks/463.js +1 -0
- package/.next/server/chunks/5209.js +1 -1
- package/.next/server/chunks/5595.js +1 -1
- package/.next/server/chunks/5611.js +1 -1
- package/.next/server/chunks/610.js +1 -0
- package/.next/server/chunks/6119.js +1 -0
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6345.js +1 -1
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/6784.js +1 -0
- package/.next/server/chunks/8581.js +1 -1
- package/.next/server/chunks/8728.js +2 -2
- package/.next/server/chunks/8918.js +1 -1
- package/.next/server/chunks/9130.js +1 -1
- package/.next/server/chunks/936.js +1 -1
- package/.next/server/chunks/9390.js +1 -1
- package/.next/server/chunks/9540.js +1 -1
- package/.next/server/chunks/9627.js +1 -1
- package/.next/server/chunks/9731.js +3 -3
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages/_document.js.nft.json +1 -1
- package/.next/server/pages/_error.js +3 -3
- package/.next/server/pages/_error.js.nft.json +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/server/src/middleware.js.map +1 -1
- package/.next/static/chunks/{1111.5ab4f0ffb0d944e5.js → 1111.1b653d4a9816a0a7.js} +8 -8
- package/.next/static/chunks/{1255-7e5873f06b25e129.js → 1255-a85690d352f4f8fd.js} +1 -1
- package/.next/static/chunks/{2407-b2f524f99f7fc353.js → 2407-a6533805a86d05bd.js} +1 -1
- package/.next/static/chunks/9465-b59bb255b376c813.js +1 -0
- package/.next/static/chunks/app/{layout-419eaf7de340f4ab.js → layout-538d8d2746ad1588.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/page-46aced20b2b1c010.js +1 -0
- package/.next/static/chunks/main-37ca13e38030fe8b.js +1 -0
- package/.next/static/chunks/{webpack-468b7b33030234b3.js → webpack-838df0273b03af19.js} +1 -1
- package/.next/trace +13 -13
- package/dist/cli/commands/prompt.d.ts.map +1 -1
- package/dist/cli/commands/prompt.js +23 -11
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +7 -1
- package/dist/cli/types/api-responses.d.ts +15 -2
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts +11 -0
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts.map +1 -1
- package/dist/lib/polling/auto-yes-suppression-reason.js +4 -1
- package/dist/server/src/lib/auto-yes-poller.js +269 -554
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +88 -6
- package/dist/server/src/lib/detection/prompt-detector.js +1 -1
- package/dist/server/src/lib/detection/tools/antigravity/dialog.js +1 -1
- package/dist/server/src/lib/hooks/permission-adjudication.js +26 -0
- package/dist/server/src/lib/hooks/permission-decision-service.js +42 -4
- package/dist/server/src/lib/hooks/permission-request-payload.js +20 -0
- package/dist/server/src/lib/hooks/sources/antigravity/source.js +21 -0
- package/dist/server/src/lib/hooks/sources/claude/source.js +3 -0
- package/dist/server/src/lib/hooks/sources/codex/source.js +2 -0
- package/dist/server/src/lib/hooks/sources/command-code/source.js +2 -0
- package/dist/server/src/lib/hooks/sources/copilot/source.js +2 -0
- package/dist/server/src/lib/hooks/sources/gemini/source.js +2 -0
- package/dist/server/src/lib/hooks/sources/legacy-relay.js +2 -0
- package/dist/server/src/lib/hooks/sources/opencode/ingest.js +6 -0
- package/dist/server/src/lib/hooks/sources/opencode/source.js +2 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/ingest.js +6 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/source.js +2 -0
- package/dist/server/src/lib/hooks/sources/pending-decisions.js +14 -2
- package/dist/server/src/lib/polling/antigravity-permission-receipts.js +14 -3
- package/dist/server/src/lib/polling/antigravity-receipt-episodes.js +21 -1
- package/dist/server/src/lib/polling/auto-yes-confirmation-ledger-types.js +114 -0
- package/dist/server/src/lib/polling/auto-yes-confirmation-ledger.js +1060 -0
- package/dist/server/src/lib/polling/auto-yes-ledger-records.js +143 -0
- package/dist/server/src/lib/polling/auto-yes-policy.js +36 -7
- package/dist/server/src/lib/polling/auto-yes-poller-capture.js +50 -0
- package/dist/server/src/lib/polling/auto-yes-poller-enter-fallback.js +37 -0
- package/dist/server/src/lib/polling/auto-yes-poller-generation.js +151 -0
- package/dist/server/src/lib/polling/auto-yes-poller-receipt-log.js +287 -0
- package/dist/server/src/lib/polling/auto-yes-poller-state.js +75 -6
- package/dist/server/src/lib/polling/auto-yes-poller-steps.js +109 -0
- package/dist/server/src/lib/polling/auto-yes-prompt-suppression.js +11 -0
- package/dist/server/src/lib/polling/auto-yes-resolver.js +21 -1
- package/dist/server/src/lib/polling/auto-yes-suppression-reason.js +4 -1
- package/dist/server/src/lib/polling/response-checker-blank-response.js +30 -0
- package/dist/server/src/lib/polling/response-checker.js +5 -10
- package/dist/server/src/lib/prompt-observation/appearance.js +165 -0
- package/package.json +2 -2
- package/release-notes/0.47.1.json +20 -0
- package/release-notes/0.47.2.json +20 -0
- package/scripts/hooks/cmate-agent-event.sh +22 -0
- package/.next/server/chunks/1331.js +0 -22
- package/.next/server/chunks/1836.js +0 -1
- package/.next/server/chunks/1944.js +0 -1
- package/.next/server/chunks/2328.js +0 -1
- package/.next/server/chunks/5292.js +0 -7
- package/.next/server/chunks/7166.js +0 -19
- package/.next/server/chunks/9051.js +0 -1
- package/.next/server/chunks/9199.js +0 -1
- package/.next/static/chunks/9465-e5a351baa941f31b.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-45294052ee3032f1.js +0 -1
- package/.next/static/chunks/main-ac91ed6e71380841.js +0 -1
- /package/.next/static/{b5BiQC9F6r_XFPdA9cuSj → etorRtpxbQqqOzdUeXdw2}/_buildManifest.js +0 -0
- /package/.next/static/{b5BiQC9F6r_XFPdA9cuSj → etorRtpxbQqqOzdUeXdw2}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,1060 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The Auto-Yes confirmation ledger (Issue #3820): one record per confirmation —
|
|
4
|
+
* what Auto-Yes decided about it, each send and how it came back, how it went
|
|
5
|
+
* away — and the intervals Auto-Yes left it alone, written as structured log
|
|
6
|
+
* lines for agent-health's daily count (design
|
|
7
|
+
* `docs/design/auto-yes-measurement-3820.md`; PR 1: the screen path, PR 2: the
|
|
8
|
+
* hook route, the API adjudication and `/prompt-response`, PR 3: agy's call).
|
|
9
|
+
*
|
|
10
|
+
* ## Records, never decides
|
|
11
|
+
*
|
|
12
|
+
* Nothing in the poller reads this to choose what to do: every entry point is
|
|
13
|
+
* called after the poller decided, and none of them can throw. A failure here —
|
|
14
|
+
* the ledger's own or its logger's — is counted (`ledgerErrors` on the hourly
|
|
15
|
+
* `alive` line) and swallowed; the `catch` calls nothing that can throw in turn
|
|
16
|
+
* (design §8.1). What is promised is "an exception in the ledger never fails an
|
|
17
|
+
* answer", not that writing a line costs nothing: the logger writes to the
|
|
18
|
+
* console synchronously.
|
|
19
|
+
*
|
|
20
|
+
* ## Two axes (design §2.2)
|
|
21
|
+
*
|
|
22
|
+
* A confirmation is `present` or `unobservable` (the poller stopped: Auto-Yes
|
|
23
|
+
* off, expired, …) while it is open; it closes when a tick that read the screen
|
|
24
|
+
* did not see it (`gone`), or when the session it was on ended (`abandoned`).
|
|
25
|
+
* Whether Auto-Yes may answer it is the other axis: a withheld interval opens
|
|
26
|
+
* at the first withholding and runs, through reason changes, until an `ok`
|
|
27
|
+
* send, the confirmation going away, or the poller stopping. agy's receipt
|
|
28
|
+
* window flips the gated reading to `isPrompt: false` while the dialog stays
|
|
29
|
+
* up; the poller observes it from the ungated reading instead, so it stays one
|
|
30
|
+
* confirmation and one interval.
|
|
31
|
+
*
|
|
32
|
+
* ## The hook, the API and `/prompt-response` (design §2.3, §2.4, PR 2)
|
|
33
|
+
*
|
|
34
|
+
* A hook request is its own record, opened by the hook route only (the API
|
|
35
|
+
* adjudication never makes one) and closed when the reply is written; it holds
|
|
36
|
+
* no waiting time. An `allow` on a source whose allow draws no dialog is also
|
|
37
|
+
* the confirmation, opened and closed with the request. A screen confirmation
|
|
38
|
+
* opened soon after a request on the same instance carries that fact
|
|
39
|
+
* (`afterHookAllow` / `afterHookAbstain`), never the claim that it is the same
|
|
40
|
+
* call. An opencode approval is a confirmation keyed by its decision id, open
|
|
41
|
+
* until the reply settles it. A `/prompt-response` answer is a confirmation of
|
|
42
|
+
* its own, opened and closed with the request.
|
|
43
|
+
*
|
|
44
|
+
* ## agy's call (design §2.4, PR 3)
|
|
45
|
+
*
|
|
46
|
+
* agy's `PreToolUse` names its call (`callId`, `<conversationId>:<stepIdx>`).
|
|
47
|
+
* Its allow still draws the dialog, so the request opens no confirmation; the
|
|
48
|
+
* screen's confirmation is tied to the call when the receipt that let it
|
|
49
|
+
* through named one, and carries the request's id. It closes on whichever comes
|
|
50
|
+
* first: gone from the screen, or the call's `PostToolUse`. A call that ends
|
|
51
|
+
* with no confirmation ever tied to it gets a `dialogUnobserved` line on its
|
|
52
|
+
* request — not observed, never "no dialog". A "No" sends no `PostToolUse`, so
|
|
53
|
+
* that confirmation closes only by going from the screen.
|
|
54
|
+
*
|
|
55
|
+
* ## State
|
|
56
|
+
*
|
|
57
|
+
* One `globalThis` object (`bootId`, the entries, the counters, the clock), so
|
|
58
|
+
* a second bundle or a hot reload continues the same `bootId` and the same
|
|
59
|
+
* sequence; only a new process starts another (design §3.3, recommendation 7).
|
|
60
|
+
* The hourly clock (`alive` and `checkpoint` lines on the UTC hour grid) is
|
|
61
|
+
* armed the first time the ledger is used — `server.ts` is not touched — and is
|
|
62
|
+
* `unref`ed so it never holds the process open.
|
|
63
|
+
*
|
|
64
|
+
* Server only (logger, `node:crypto`). Must not import `auto-yes-poller.ts`.
|
|
65
|
+
*
|
|
66
|
+
* @module lib/polling/auto-yes-confirmation-ledger
|
|
67
|
+
*/
|
|
68
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
69
|
+
exports.AUTO_YES_LEDGER_UNOBSERVABLE_TIMEOUT_MS = exports.AUTO_YES_LEDGER_RECORDED_PATHS = exports.AUTO_YES_LEDGER_MAX_OPEN_TOTAL = exports.AUTO_YES_LEDGER_MAX_OPEN_PER_INSTANCE = exports.AUTO_YES_LEDGER_HOOK_LINK_WINDOW_MS = exports.AUTO_YES_LEDGER_CLOCK_MS = void 0;
|
|
70
|
+
exports.beginLedgerTick = beginLedgerTick;
|
|
71
|
+
exports.endLedgerTick = endLedgerTick;
|
|
72
|
+
exports.observeLedgerScreen = observeLedgerScreen;
|
|
73
|
+
exports.withholdLedgerConfirmation = withholdLedgerConfirmation;
|
|
74
|
+
exports.beginLedgerAttempt = beginLedgerAttempt;
|
|
75
|
+
exports.settleLedgerAttempt = settleLedgerAttempt;
|
|
76
|
+
exports.noteLedgerPollerStopped = noteLedgerPollerStopped;
|
|
77
|
+
exports.noteLedgerWorktreeStopped = noteLedgerWorktreeStopped;
|
|
78
|
+
exports.beginLedgerHookRequest = beginLedgerHookRequest;
|
|
79
|
+
exports.decideLedgerHookRequest = decideLedgerHookRequest;
|
|
80
|
+
exports.closeLedgerHookRequest = closeLedgerHookRequest;
|
|
81
|
+
exports.noteLedgerToolCallEnded = noteLedgerToolCallEnded;
|
|
82
|
+
exports.observeLedgerCliMode = observeLedgerCliMode;
|
|
83
|
+
exports.recordLedgerApiAdjudication = recordLedgerApiAdjudication;
|
|
84
|
+
exports.beginLedgerApiAdjudication = beginLedgerApiAdjudication;
|
|
85
|
+
exports.settleLedgerApiAdjudication = settleLedgerApiAdjudication;
|
|
86
|
+
exports.noteLedgerApiDecisionReplied = noteLedgerApiDecisionReplied;
|
|
87
|
+
exports.recordLedgerPromptResponse = recordLedgerPromptResponse;
|
|
88
|
+
exports.runAutoYesLedgerHourForTests = runAutoYesLedgerHourForTests;
|
|
89
|
+
exports.resetAutoYesConfirmationLedgerForTests = resetAutoYesConfirmationLedgerForTests;
|
|
90
|
+
exports.setAutoYesLedgerFaultForTests = setAutoYesLedgerFaultForTests;
|
|
91
|
+
exports.setAutoYesLedgerClockTimersForTests = setAutoYesLedgerClockTimersForTests;
|
|
92
|
+
exports.getAutoYesLedgerErrorCountForTests = getAutoYesLedgerErrorCountForTests;
|
|
93
|
+
const node_crypto_1 = require("node:crypto");
|
|
94
|
+
const auto_yes_state_1 = require("../auto-yes-state");
|
|
95
|
+
const global_state_1 = require("../global-state");
|
|
96
|
+
const auto_yes_enter_fallback_state_1 = require("./auto-yes-enter-fallback-state");
|
|
97
|
+
const auto_yes_confirmation_ledger_types_1 = require("./auto-yes-confirmation-ledger-types");
|
|
98
|
+
const auto_yes_ledger_records_1 = require("./auto-yes-ledger-records");
|
|
99
|
+
Object.defineProperty(exports, "AUTO_YES_LEDGER_CLOCK_MS", { enumerable: true, get: function () { return auto_yes_ledger_records_1.AUTO_YES_LEDGER_CLOCK_MS; } });
|
|
100
|
+
Object.defineProperty(exports, "AUTO_YES_LEDGER_HOOK_LINK_WINDOW_MS", { enumerable: true, get: function () { return auto_yes_ledger_records_1.AUTO_YES_LEDGER_HOOK_LINK_WINDOW_MS; } });
|
|
101
|
+
Object.defineProperty(exports, "AUTO_YES_LEDGER_MAX_OPEN_PER_INSTANCE", { enumerable: true, get: function () { return auto_yes_ledger_records_1.AUTO_YES_LEDGER_MAX_OPEN_PER_INSTANCE; } });
|
|
102
|
+
Object.defineProperty(exports, "AUTO_YES_LEDGER_MAX_OPEN_TOTAL", { enumerable: true, get: function () { return auto_yes_ledger_records_1.AUTO_YES_LEDGER_MAX_OPEN_TOTAL; } });
|
|
103
|
+
Object.defineProperty(exports, "AUTO_YES_LEDGER_RECORDED_PATHS", { enumerable: true, get: function () { return auto_yes_ledger_records_1.AUTO_YES_LEDGER_RECORDED_PATHS; } });
|
|
104
|
+
Object.defineProperty(exports, "AUTO_YES_LEDGER_UNOBSERVABLE_TIMEOUT_MS", { enumerable: true, get: function () { return auto_yes_ledger_records_1.AUTO_YES_LEDGER_UNOBSERVABLE_TIMEOUT_MS; } });
|
|
105
|
+
/**
|
|
106
|
+
* The clock's timers, taken when the module loads. The hourly clock is not one
|
|
107
|
+
* of the poller's timers, so a test that fakes timers around the poller (and
|
|
108
|
+
* counts them) neither sees nor runs it. Tests of the clock itself replace them
|
|
109
|
+
* with {@link setAutoYesLedgerClockTimersForTests}.
|
|
110
|
+
*/
|
|
111
|
+
const loadedClockTimers = {
|
|
112
|
+
setTimeout: globalThis.setTimeout.bind(globalThis),
|
|
113
|
+
clearTimeout: globalThis.clearTimeout.bind(globalThis),
|
|
114
|
+
};
|
|
115
|
+
let clockTimers = loadedClockTimers;
|
|
116
|
+
/** Test seam: when set, every entry point fails as if its body had thrown. */
|
|
117
|
+
let injectedFault = null;
|
|
118
|
+
function ledgerState() {
|
|
119
|
+
const existing = globalThis.__autoYesConfirmationLedger;
|
|
120
|
+
if (existing !== undefined)
|
|
121
|
+
return existing;
|
|
122
|
+
const state = (0, global_state_1.getOrInitGlobal)('__autoYesConfirmationLedger', () => {
|
|
123
|
+
const startedAt = Date.now();
|
|
124
|
+
return {
|
|
125
|
+
bootId: (0, node_crypto_1.randomUUID)().slice(0, 8),
|
|
126
|
+
startedAt,
|
|
127
|
+
nextConfirmation: 0,
|
|
128
|
+
entries: new Map(),
|
|
129
|
+
apiDecisions: new Map(),
|
|
130
|
+
nextHookRequest: 0,
|
|
131
|
+
hookRequests: new Map(),
|
|
132
|
+
lastHookRequest: new Map(),
|
|
133
|
+
cliModes: new Map(),
|
|
134
|
+
current: new Map(),
|
|
135
|
+
ticks: new Map(),
|
|
136
|
+
nextTick: 0,
|
|
137
|
+
pending: new Map(),
|
|
138
|
+
calls: new Map(),
|
|
139
|
+
endedCalls: new Map(),
|
|
140
|
+
errors: 0,
|
|
141
|
+
lastAliveAt: null,
|
|
142
|
+
clock: null,
|
|
143
|
+
};
|
|
144
|
+
});
|
|
145
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.started, {
|
|
146
|
+
atMs: state.startedAt,
|
|
147
|
+
logLevel: (0, auto_yes_ledger_records_1.currentLogLevel)(),
|
|
148
|
+
paths: [...auto_yes_ledger_records_1.AUTO_YES_LEDGER_RECORDED_PATHS],
|
|
149
|
+
});
|
|
150
|
+
return state;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Run `body` on the ledger's state, arming the clock first. Whatever throws —
|
|
154
|
+
* the body, the state, the clock — is counted and `fallback` returned; the
|
|
155
|
+
* counting itself cannot throw.
|
|
156
|
+
*/
|
|
157
|
+
function guarded(fallback, body) {
|
|
158
|
+
try {
|
|
159
|
+
if (injectedFault !== null)
|
|
160
|
+
throw injectedFault;
|
|
161
|
+
const state = ledgerState();
|
|
162
|
+
ensureClock(state);
|
|
163
|
+
return body(state, Date.now());
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
const state = globalThis.__autoYesConfirmationLedger;
|
|
167
|
+
if (state !== undefined)
|
|
168
|
+
state.errors += 1;
|
|
169
|
+
return fallback;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
// =============================================================================
|
|
173
|
+
// The clock: `alive` and `checkpoint` lines on the UTC hour grid (design §4.3, §4.4)
|
|
174
|
+
// =============================================================================
|
|
175
|
+
function ensureClock(state) {
|
|
176
|
+
if (state.clock !== null)
|
|
177
|
+
return;
|
|
178
|
+
scheduleClock(state, Date.now());
|
|
179
|
+
}
|
|
180
|
+
function scheduleClock(state, now) {
|
|
181
|
+
const dueAt = (Math.floor(now / auto_yes_ledger_records_1.AUTO_YES_LEDGER_CLOCK_MS) + 1) * auto_yes_ledger_records_1.AUTO_YES_LEDGER_CLOCK_MS;
|
|
182
|
+
const clock = { timer: null, dueAt };
|
|
183
|
+
state.clock = clock;
|
|
184
|
+
const timer = clockTimers.setTimeout(() => onClock(clock), Math.max(0, dueAt - now));
|
|
185
|
+
timer.unref?.();
|
|
186
|
+
clock.timer = timer;
|
|
187
|
+
}
|
|
188
|
+
function onClock(clock) {
|
|
189
|
+
const state = globalThis.__autoYesConfirmationLedger;
|
|
190
|
+
// A reset (tests) or a newer clock replaced this one.
|
|
191
|
+
if (state === undefined || state.clock !== clock)
|
|
192
|
+
return;
|
|
193
|
+
state.clock = null;
|
|
194
|
+
try {
|
|
195
|
+
if (injectedFault !== null)
|
|
196
|
+
throw injectedFault;
|
|
197
|
+
runHour(state, clock.dueAt);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
state.errors += 1;
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
scheduleClock(state, Date.now());
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
state.errors += 1;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* One hour boundary: let go of confirmations unobservable for too long, then
|
|
211
|
+
* the `alive` line and a `checkpoint` per open confirmation, all stamped `at`.
|
|
212
|
+
*/
|
|
213
|
+
function runHour(state, at) {
|
|
214
|
+
for (const entry of [...state.entries.values()]) {
|
|
215
|
+
if (entry.presence === 'unobservable' &&
|
|
216
|
+
entry.unobservableSince !== null &&
|
|
217
|
+
at - entry.unobservableSince >= auto_yes_ledger_records_1.AUTO_YES_LEDGER_UNOBSERVABLE_TIMEOUT_MS) {
|
|
218
|
+
closeEntry(state, entry, at, { kind: 'abandoned', reason: 'unobservable-timeout' });
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const segmentStart = state.lastAliveAt ?? state.startedAt;
|
|
222
|
+
state.lastAliveAt = at;
|
|
223
|
+
let openIntervals = 0;
|
|
224
|
+
for (const entry of state.entries.values())
|
|
225
|
+
if (entry.interval !== null)
|
|
226
|
+
openIntervals += 1;
|
|
227
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.alive, {
|
|
228
|
+
atMs: at,
|
|
229
|
+
logLevel: (0, auto_yes_ledger_records_1.currentLogLevel)(),
|
|
230
|
+
segments: auto_yes_ledger_records_1.AUTO_YES_LEDGER_RECORDED_PATHS.map((path) => ({ path, startMs: segmentStart, endMs: at })),
|
|
231
|
+
openConfirmations: state.entries.size,
|
|
232
|
+
openIntervals,
|
|
233
|
+
ledgerErrors: state.errors,
|
|
234
|
+
});
|
|
235
|
+
for (const entry of state.entries.values()) {
|
|
236
|
+
const interval = entry.interval;
|
|
237
|
+
const intervalMs = interval === null ? 0 : Math.max(0, at - interval.startedAt);
|
|
238
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.checkpoint, {
|
|
239
|
+
atMs: at,
|
|
240
|
+
confirmationId: entry.id,
|
|
241
|
+
cliToolId: entry.cliToolId,
|
|
242
|
+
source: entry.source,
|
|
243
|
+
presence: entry.presence,
|
|
244
|
+
answerability: interval === null ? 'answerable' : 'withheld',
|
|
245
|
+
withheldMsTotal: entry.withheldMsClosed + intervalMs,
|
|
246
|
+
...(interval !== null
|
|
247
|
+
? { intervalId: interval.id, reason: interval.reason, intervalStartedAtMs: interval.startedAt, intervalMs }
|
|
248
|
+
: {}),
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// =============================================================================
|
|
253
|
+
// Intervals and closing
|
|
254
|
+
// =============================================================================
|
|
255
|
+
function withhold(state, entry, reason, now) {
|
|
256
|
+
const interval = entry.interval;
|
|
257
|
+
if (interval === null) {
|
|
258
|
+
entry.intervals += 1;
|
|
259
|
+
const opened = { id: `${entry.id}#${entry.intervals}`, startedAt: now, reason };
|
|
260
|
+
entry.interval = opened;
|
|
261
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.withholdStarted, {
|
|
262
|
+
atMs: now,
|
|
263
|
+
confirmationId: entry.id,
|
|
264
|
+
intervalId: opened.id,
|
|
265
|
+
cliToolId: entry.cliToolId,
|
|
266
|
+
source: entry.source,
|
|
267
|
+
reason,
|
|
268
|
+
startedAtMs: now,
|
|
269
|
+
});
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (interval.reason === reason)
|
|
273
|
+
return;
|
|
274
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.withholdReasonChanged, {
|
|
275
|
+
atMs: now,
|
|
276
|
+
confirmationId: entry.id,
|
|
277
|
+
intervalId: interval.id,
|
|
278
|
+
cliToolId: entry.cliToolId,
|
|
279
|
+
source: entry.source,
|
|
280
|
+
from: interval.reason,
|
|
281
|
+
to: reason,
|
|
282
|
+
});
|
|
283
|
+
interval.reason = reason;
|
|
284
|
+
}
|
|
285
|
+
function endInterval(state, entry, end, now) {
|
|
286
|
+
const interval = entry.interval;
|
|
287
|
+
if (interval === null)
|
|
288
|
+
return;
|
|
289
|
+
entry.interval = null;
|
|
290
|
+
const withheldMs = Math.max(0, now - interval.startedAt);
|
|
291
|
+
entry.withheldMsClosed += withheldMs;
|
|
292
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.withholdEnded, {
|
|
293
|
+
atMs: now,
|
|
294
|
+
confirmationId: entry.id,
|
|
295
|
+
intervalId: interval.id,
|
|
296
|
+
cliToolId: entry.cliToolId,
|
|
297
|
+
source: entry.source,
|
|
298
|
+
startedAtMs: interval.startedAt,
|
|
299
|
+
endedAtMs: now,
|
|
300
|
+
withheldMs,
|
|
301
|
+
end,
|
|
302
|
+
lastReason: interval.reason,
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
function closeEntry(state, entry, now, how) {
|
|
306
|
+
const wasUnobservable = entry.presence === 'unobservable';
|
|
307
|
+
if (wasUnobservable && entry.unobservableSince !== null) {
|
|
308
|
+
entry.unobservableMs += Math.max(0, now - entry.unobservableSince);
|
|
309
|
+
}
|
|
310
|
+
// Withheld only by the duplicate guard after an `ok`: the answer was landing.
|
|
311
|
+
const waitingForAnswer = entry.answered && entry.interval?.reason === 'answered-recently';
|
|
312
|
+
const withheldAtClose = entry.interval !== null && !waitingForAnswer;
|
|
313
|
+
endInterval(state, entry, how.kind === 'abandoned' ? 'abandoned' : 'gone', now);
|
|
314
|
+
let attemptsPending = 0;
|
|
315
|
+
for (const pending of state.pending.values())
|
|
316
|
+
if (pending.confirmationId === entry.id)
|
|
317
|
+
attemptsPending += 1;
|
|
318
|
+
const sent = entry.nextAttempt > 0;
|
|
319
|
+
let resolution;
|
|
320
|
+
if (how.kind === 'abandoned') {
|
|
321
|
+
resolution = sent ? 'unresolved-after-send' : 'abandoned';
|
|
322
|
+
}
|
|
323
|
+
else if (how.kind === 'reply') {
|
|
324
|
+
resolution = 'resolved-by-reply';
|
|
325
|
+
}
|
|
326
|
+
else if (wasUnobservable) {
|
|
327
|
+
resolution = 'gone-while-unobservable';
|
|
328
|
+
}
|
|
329
|
+
else if (withheldAtClose) {
|
|
330
|
+
resolution = 'resolved-while-withheld';
|
|
331
|
+
}
|
|
332
|
+
else if (entry.answered) {
|
|
333
|
+
resolution = 'resolved-after-answer';
|
|
334
|
+
}
|
|
335
|
+
else if (entry.intervals > 0) {
|
|
336
|
+
// Answered never, withheld once and since answerable again.
|
|
337
|
+
resolution = 'resolved-while-withheld';
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
resolution = 'resolved-before-decision';
|
|
341
|
+
}
|
|
342
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.closed, {
|
|
343
|
+
atMs: now,
|
|
344
|
+
confirmationId: entry.id,
|
|
345
|
+
worktreeId: entry.worktreeId,
|
|
346
|
+
cliToolId: entry.cliToolId,
|
|
347
|
+
instanceId: entry.instanceId,
|
|
348
|
+
source: entry.source,
|
|
349
|
+
promptType: entry.promptType,
|
|
350
|
+
decision: entry.decision,
|
|
351
|
+
basis: entry.basis,
|
|
352
|
+
attempts: { ...entry.attempts },
|
|
353
|
+
attemptsPending,
|
|
354
|
+
answeredAtClose: entry.answered,
|
|
355
|
+
resolution,
|
|
356
|
+
// The screen path cannot tell Auto-Yes's keys from a human's; only a
|
|
357
|
+
// delivered reply that released it is known to be Auto-Yes's (design §2.6).
|
|
358
|
+
resolvedBy: how.kind === 'reply' ? 'auto' : how.kind === 'gone' ? (how.resolvedBy ?? 'unknown') : 'unknown',
|
|
359
|
+
openMs: Math.max(0, now - entry.openedAt),
|
|
360
|
+
withheldMsTotal: entry.withheldMsClosed,
|
|
361
|
+
unobservableMs: entry.unobservableMs,
|
|
362
|
+
intervals: entry.intervals,
|
|
363
|
+
...(how.kind === 'abandoned' ? { abandonReason: how.reason } : {}),
|
|
364
|
+
});
|
|
365
|
+
state.entries.delete(entry.id);
|
|
366
|
+
if (state.current.get(entry.compositeKey) === entry.id)
|
|
367
|
+
state.current.delete(entry.compositeKey);
|
|
368
|
+
if (entry.decisionKey !== undefined)
|
|
369
|
+
state.apiDecisions.delete(entry.decisionKey);
|
|
370
|
+
}
|
|
371
|
+
/** Open a confirmation and write its `opened` line; the caller indexes it. */
|
|
372
|
+
function openEntry(state, scope, compositeKey, fields, now, link = {}) {
|
|
373
|
+
makeRoom(state, compositeKey, now);
|
|
374
|
+
state.nextConfirmation += 1;
|
|
375
|
+
const opened = {
|
|
376
|
+
id: `${state.bootId}-${state.nextConfirmation}`,
|
|
377
|
+
compositeKey,
|
|
378
|
+
worktreeId: scope.worktreeId,
|
|
379
|
+
cliToolId: scope.cliToolId,
|
|
380
|
+
instanceId: scope.instanceId ?? scope.cliToolId,
|
|
381
|
+
source: fields.source,
|
|
382
|
+
screenKey: fields.screenKey,
|
|
383
|
+
...(fields.decisionKey !== undefined ? { decisionKey: fields.decisionKey } : {}),
|
|
384
|
+
...(link.callId !== undefined ? { callId: link.callId } : {}),
|
|
385
|
+
epoch: (0, auto_yes_enter_fallback_state_1.getEnterFallbackSessionEpoch)(compositeKey),
|
|
386
|
+
promptType: fields.promptType,
|
|
387
|
+
openedAt: now,
|
|
388
|
+
presence: 'present',
|
|
389
|
+
unobservableSince: null,
|
|
390
|
+
unobservableMs: 0,
|
|
391
|
+
decision: 'none',
|
|
392
|
+
basis: null,
|
|
393
|
+
interval: null,
|
|
394
|
+
intervals: 0,
|
|
395
|
+
withheldMsClosed: 0,
|
|
396
|
+
attempts: { ok: 0, partial: 0, noKeysSent: 0, failed: 0 },
|
|
397
|
+
nextAttempt: 0,
|
|
398
|
+
answered: false,
|
|
399
|
+
autoYesStopped: false,
|
|
400
|
+
observedTick: state.ticks.get(compositeKey) ?? 0,
|
|
401
|
+
};
|
|
402
|
+
state.entries.set(opened.id, opened);
|
|
403
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.opened, {
|
|
404
|
+
atMs: now,
|
|
405
|
+
confirmationId: opened.id,
|
|
406
|
+
worktreeId: opened.worktreeId,
|
|
407
|
+
cliToolId: opened.cliToolId,
|
|
408
|
+
instanceId: opened.instanceId,
|
|
409
|
+
source: opened.source,
|
|
410
|
+
promptType: opened.promptType,
|
|
411
|
+
...link,
|
|
412
|
+
});
|
|
413
|
+
return opened;
|
|
414
|
+
}
|
|
415
|
+
function makeRoom(state, compositeKey, now) {
|
|
416
|
+
const ofInstance = [...state.entries.values()].filter((entry) => entry.compositeKey === compositeKey);
|
|
417
|
+
if (ofInstance.length >= auto_yes_ledger_records_1.AUTO_YES_LEDGER_MAX_OPEN_PER_INSTANCE) {
|
|
418
|
+
closeEntry(state, ofInstance[0], now, { kind: 'abandoned', reason: 'capacity' });
|
|
419
|
+
}
|
|
420
|
+
if (state.entries.size >= auto_yes_ledger_records_1.AUTO_YES_LEDGER_MAX_OPEN_TOTAL) {
|
|
421
|
+
const oldest = state.entries.values().next().value;
|
|
422
|
+
if (oldest !== undefined)
|
|
423
|
+
closeEntry(state, oldest, now, { kind: 'abandoned', reason: 'capacity' });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
// =============================================================================
|
|
427
|
+
// The screen path (the poller)
|
|
428
|
+
// =============================================================================
|
|
429
|
+
/**
|
|
430
|
+
* A poller tick that has read the screen begins. A confirmation from another
|
|
431
|
+
* session of this instance (a relaunch the poller outlived) is abandoned.
|
|
432
|
+
*
|
|
433
|
+
* @returns The tick's token, for {@link endLedgerTick}
|
|
434
|
+
*/
|
|
435
|
+
function beginLedgerTick(scope) {
|
|
436
|
+
return guarded(0, (state, now) => {
|
|
437
|
+
const compositeKey = (0, auto_yes_ledger_records_1.keyOf)(scope);
|
|
438
|
+
state.nextTick += 1;
|
|
439
|
+
const tick = state.nextTick;
|
|
440
|
+
state.ticks.set(compositeKey, tick);
|
|
441
|
+
const entry = (0, auto_yes_ledger_records_1.currentEntry)(state, compositeKey);
|
|
442
|
+
if (entry !== undefined && entry.epoch !== (0, auto_yes_enter_fallback_state_1.getEnterFallbackSessionEpoch)(compositeKey)) {
|
|
443
|
+
closeEntry(state, entry, now, { kind: 'abandoned', reason: 'session-epoch-changed' });
|
|
444
|
+
}
|
|
445
|
+
return tick;
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* The tick is over: when it read the screen and saw no confirmation there —
|
|
450
|
+
* neither the gated reading nor the ungated one — the open one is `gone`. A
|
|
451
|
+
* newer tick for the same instance (a poller restarted meanwhile) decides
|
|
452
|
+
* instead.
|
|
453
|
+
*/
|
|
454
|
+
function endLedgerTick(scope, tick) {
|
|
455
|
+
guarded(undefined, (state, now) => {
|
|
456
|
+
const compositeKey = (0, auto_yes_ledger_records_1.keyOf)(scope);
|
|
457
|
+
if (tick === 0 || state.ticks.get(compositeKey) !== tick)
|
|
458
|
+
return;
|
|
459
|
+
state.ticks.delete(compositeKey);
|
|
460
|
+
const entry = (0, auto_yes_ledger_records_1.currentEntry)(state, compositeKey);
|
|
461
|
+
if (entry !== undefined && entry.observedTick !== tick)
|
|
462
|
+
closeEntry(state, entry, now, { kind: 'gone' });
|
|
463
|
+
// A tick that read the screen and did not see the dialog of a call that
|
|
464
|
+
// ended: it is off the screen now, and the next sighting is a new one.
|
|
465
|
+
const ended = (0, auto_yes_ledger_records_1.endedCallsOf)(state).get(compositeKey);
|
|
466
|
+
if (ended !== undefined && ended.seenTick !== tick)
|
|
467
|
+
(0, auto_yes_ledger_records_1.endedCallsOf)(state).delete(compositeKey);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* The tick sees a confirmation on screen. The same screen key in the same
|
|
472
|
+
* session continues the open one (back to `present` if it was unobservable);
|
|
473
|
+
* anything else closes it as gone and opens a new one.
|
|
474
|
+
*
|
|
475
|
+
* agy (PR 3, design §2.1・§2.4): `options.callId` is the call the receipt that
|
|
476
|
+
* let the dialog through asked about. The hook's identity comes before the
|
|
477
|
+
* screen's: a different call is another confirmation even under the same
|
|
478
|
+
* screen key (the same command asked twice, no clear read between). A
|
|
479
|
+
* confirmation with no call yet takes this one. The dialog of a call whose
|
|
480
|
+
* `PostToolUse` already closed it is not reopened while it is still read.
|
|
481
|
+
*
|
|
482
|
+
* @param screenKey - `partialAnswerScreenKey` of the prompt (kept in memory, never logged)
|
|
483
|
+
*/
|
|
484
|
+
function observeLedgerScreen(scope, screenKey, promptType, options = {}) {
|
|
485
|
+
guarded(undefined, (state, now) => {
|
|
486
|
+
const compositeKey = (0, auto_yes_ledger_records_1.keyOf)(scope);
|
|
487
|
+
const epoch = (0, auto_yes_enter_fallback_state_1.getEnterFallbackSessionEpoch)(compositeKey);
|
|
488
|
+
const tick = state.ticks.get(compositeKey) ?? 0;
|
|
489
|
+
const callId = options.callId;
|
|
490
|
+
let entry = (0, auto_yes_ledger_records_1.currentEntry)(state, compositeKey);
|
|
491
|
+
const otherCall = entry !== undefined && callId !== undefined && entry.callId !== undefined && entry.callId !== callId;
|
|
492
|
+
if (entry !== undefined && (entry.screenKey !== screenKey || entry.epoch !== epoch || otherCall)) {
|
|
493
|
+
closeEntry(state, entry, now, entry.epoch !== epoch ? { kind: 'abandoned', reason: 'session-epoch-changed' } : { kind: 'gone' });
|
|
494
|
+
entry = undefined;
|
|
495
|
+
}
|
|
496
|
+
if (entry === undefined) {
|
|
497
|
+
const ended = (0, auto_yes_ledger_records_1.endedCallsOf)(state).get(compositeKey);
|
|
498
|
+
if (ended !== undefined &&
|
|
499
|
+
ended.epoch === epoch &&
|
|
500
|
+
ended.screenKey === screenKey &&
|
|
501
|
+
(callId === undefined || callId === ended.callId)) {
|
|
502
|
+
ended.seenTick = tick;
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
(0, auto_yes_ledger_records_1.endedCallsOf)(state).delete(compositeKey);
|
|
506
|
+
const opened = openEntry(state, scope, compositeKey, { source: 'screen', screenKey, promptType }, now, { ...hookLink(state, compositeKey, now), ...callLink(state, compositeKey, callId) });
|
|
507
|
+
state.current.set(compositeKey, opened.id);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
if (callId !== undefined && entry.callId === undefined) {
|
|
511
|
+
// Seen before the receipt was judged for it; tied now, so its call's
|
|
512
|
+
// `PostToolUse` closes it and the request is not "unobserved".
|
|
513
|
+
entry.callId = callId;
|
|
514
|
+
callLink(state, compositeKey, callId);
|
|
515
|
+
}
|
|
516
|
+
if (entry.presence === 'unobservable') {
|
|
517
|
+
if (entry.unobservableSince !== null)
|
|
518
|
+
entry.unobservableMs += Math.max(0, now - entry.unobservableSince);
|
|
519
|
+
entry.presence = 'present';
|
|
520
|
+
entry.unobservableSince = null;
|
|
521
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.presenceChanged, {
|
|
522
|
+
atMs: now,
|
|
523
|
+
confirmationId: entry.id,
|
|
524
|
+
from: 'unobservable',
|
|
525
|
+
to: 'present',
|
|
526
|
+
cause: 'observed',
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
entry.observedTick = tick;
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Tie a screen confirmation to agy's call: marks the call observed and gives
|
|
534
|
+
* the `opened` line its `callId` and the request's id (PR 3).
|
|
535
|
+
*/
|
|
536
|
+
function callLink(state, compositeKey, callId) {
|
|
537
|
+
if (callId === undefined)
|
|
538
|
+
return {};
|
|
539
|
+
const call = (0, auto_yes_ledger_records_1.callsOf)(state).get((0, auto_yes_ledger_records_1.callKey)(compositeKey, callId));
|
|
540
|
+
if (call === undefined)
|
|
541
|
+
return { callId };
|
|
542
|
+
call.observed = true;
|
|
543
|
+
return { callId, hookRequestId: call.hookRequestId };
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Auto-Yes leaves the instance's current confirmation alone for `reason`:
|
|
547
|
+
* opens a withheld interval, or records the reason changing inside one.
|
|
548
|
+
*/
|
|
549
|
+
function withholdLedgerConfirmation(scope, reason) {
|
|
550
|
+
guarded(undefined, (state, now) => {
|
|
551
|
+
const entry = (0, auto_yes_ledger_records_1.currentEntry)(state, (0, auto_yes_ledger_records_1.keyOf)(scope));
|
|
552
|
+
if (entry === undefined || entry.presence !== 'present')
|
|
553
|
+
return;
|
|
554
|
+
entry.decision = 'withhold';
|
|
555
|
+
withhold(state, entry, reason, now);
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* A send to the instance's current confirmation is about to begin. Called
|
|
560
|
+
* before its first await; the handle goes with the send.
|
|
561
|
+
*
|
|
562
|
+
* @returns The handle, or null when there is no confirmation (or the ledger failed)
|
|
563
|
+
*/
|
|
564
|
+
function beginLedgerAttempt(scope, basis, options = {}) {
|
|
565
|
+
return guarded(null, (state) => {
|
|
566
|
+
const entry = (0, auto_yes_ledger_records_1.currentEntry)(state, (0, auto_yes_ledger_records_1.keyOf)(scope));
|
|
567
|
+
if (entry === undefined)
|
|
568
|
+
return null;
|
|
569
|
+
return beginAttempt(state, entry, basis, options.receiptAccepted === true);
|
|
570
|
+
});
|
|
571
|
+
}
|
|
572
|
+
function beginAttempt(state, entry, basis, receiptAccepted) {
|
|
573
|
+
entry.nextAttempt += 1;
|
|
574
|
+
entry.decision = 'answer';
|
|
575
|
+
entry.basis = basis;
|
|
576
|
+
const handle = { confirmationId: entry.id, attemptId: `${entry.id}.${entry.nextAttempt}` };
|
|
577
|
+
if (state.pending.size >= auto_yes_ledger_records_1.MAX_PENDING_ATTEMPTS) {
|
|
578
|
+
const oldest = state.pending.keys().next().value;
|
|
579
|
+
if (oldest !== undefined)
|
|
580
|
+
state.pending.delete(oldest);
|
|
581
|
+
}
|
|
582
|
+
state.pending.set(handle.attemptId, { confirmationId: entry.id, cliToolId: entry.cliToolId, basis, receiptAccepted });
|
|
583
|
+
return handle;
|
|
584
|
+
}
|
|
585
|
+
const WITHHOLD_REASON_OF_RESULT = {
|
|
586
|
+
partial: 'partial-answer',
|
|
587
|
+
'no-keys-sent': 'send-no-keys',
|
|
588
|
+
failed: 'send-failed',
|
|
589
|
+
};
|
|
590
|
+
/**
|
|
591
|
+
* A send came back. Its line belongs to the confirmation it was begun for,
|
|
592
|
+
* open or not: one that closed meanwhile gets a `late` line and nothing else —
|
|
593
|
+
* it is not reopened, and its resolution and intervals stay as they were
|
|
594
|
+
* (design §2.5, N1). A second call for the same send does nothing.
|
|
595
|
+
*
|
|
596
|
+
* @param options.expired - The poller's send record had expired (#3713)
|
|
597
|
+
*/
|
|
598
|
+
function settleLedgerAttempt(handle, result, options = {}) {
|
|
599
|
+
if (handle === null || handle === undefined)
|
|
600
|
+
return;
|
|
601
|
+
guarded(undefined, (state, now) => settleAttempt(state, handle, result, options.expired === true, now));
|
|
602
|
+
}
|
|
603
|
+
function settleAttempt(state, handle, result, expired, now, options = {}) {
|
|
604
|
+
const pending = state.pending.get(handle.attemptId);
|
|
605
|
+
if (pending === undefined)
|
|
606
|
+
return;
|
|
607
|
+
state.pending.delete(handle.attemptId);
|
|
608
|
+
const entry = state.entries.get(handle.confirmationId);
|
|
609
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.attemptSettled, {
|
|
610
|
+
atMs: now,
|
|
611
|
+
confirmationId: handle.confirmationId,
|
|
612
|
+
attemptId: handle.attemptId,
|
|
613
|
+
cliToolId: pending.cliToolId,
|
|
614
|
+
basis: pending.basis,
|
|
615
|
+
result,
|
|
616
|
+
late: entry === undefined,
|
|
617
|
+
expired,
|
|
618
|
+
...(pending.receiptAccepted ? { receiptAccepted: true } : {}),
|
|
619
|
+
});
|
|
620
|
+
if (entry === undefined)
|
|
621
|
+
return;
|
|
622
|
+
if (result === 'ok') {
|
|
623
|
+
entry.attempts.ok += 1;
|
|
624
|
+
entry.answered = true;
|
|
625
|
+
endInterval(state, entry, 'answered', now);
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
if (result === 'partial')
|
|
629
|
+
entry.attempts.partial += 1;
|
|
630
|
+
else if (result === 'no-keys-sent')
|
|
631
|
+
entry.attempts.noKeysSent += 1;
|
|
632
|
+
else
|
|
633
|
+
entry.attempts.failed += 1;
|
|
634
|
+
if (entry.presence === 'present' && !entry.autoYesStopped && options.withholdOnFailure !== false) {
|
|
635
|
+
withhold(state, entry, WITHHOLD_REASON_OF_RESULT[result], now);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* The instance's poller stopped (design §4.2). A stop that ends the session or
|
|
640
|
+
* hands the key over abandons its confirmations; any other (off, expired, the
|
|
641
|
+
* stop pattern, errors, a shutdown) only stops looking — they turn
|
|
642
|
+
* `unobservable`, their withheld interval ends, and the same confirmation is
|
|
643
|
+
* continued if the next poller sees it again.
|
|
644
|
+
*/
|
|
645
|
+
function noteLedgerPollerStopped(compositeKey, reason) {
|
|
646
|
+
guarded(undefined, (state, now) => {
|
|
647
|
+
state.ticks.delete(compositeKey);
|
|
648
|
+
// The session is over: no frame of it is read again, the next sighting is new.
|
|
649
|
+
if (auto_yes_ledger_records_1.SESSION_ENDING_STOP_REASONS.has(reason))
|
|
650
|
+
(0, auto_yes_ledger_records_1.endedCallsOf)(state).delete(compositeKey);
|
|
651
|
+
for (const entry of [...state.entries.values()]) {
|
|
652
|
+
if (entry.compositeKey === compositeKey)
|
|
653
|
+
noteEntryStopped(state, entry, reason, now);
|
|
654
|
+
}
|
|
655
|
+
});
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Every poller of a worktree stopped, or the worktree went: the same as
|
|
659
|
+
* {@link noteLedgerPollerStopped} for each confirmation the worktree holds,
|
|
660
|
+
* whether or not a poller was running for its instance (design §4.2). An API
|
|
661
|
+
* approval is opened with Auto-Yes off too, so the keys of the running pollers
|
|
662
|
+
* do not name every instance with an open confirmation.
|
|
663
|
+
*/
|
|
664
|
+
function noteLedgerWorktreeStopped(worktreeId, reason) {
|
|
665
|
+
guarded(undefined, (state, now) => {
|
|
666
|
+
if (auto_yes_ledger_records_1.SESSION_ENDING_STOP_REASONS.has(reason)) {
|
|
667
|
+
const endedCalls = (0, auto_yes_ledger_records_1.endedCallsOf)(state);
|
|
668
|
+
for (const [compositeKey, ended] of [...endedCalls]) {
|
|
669
|
+
if (ended.worktreeId === worktreeId)
|
|
670
|
+
endedCalls.delete(compositeKey);
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
for (const entry of [...state.entries.values()]) {
|
|
674
|
+
if (entry.worktreeId !== worktreeId)
|
|
675
|
+
continue;
|
|
676
|
+
state.ticks.delete(entry.compositeKey);
|
|
677
|
+
noteEntryStopped(state, entry, reason, now);
|
|
678
|
+
}
|
|
679
|
+
});
|
|
680
|
+
}
|
|
681
|
+
function noteEntryStopped(state, entry, reason, now) {
|
|
682
|
+
if (auto_yes_ledger_records_1.ABANDONING_STOP_REASONS.has(reason)) {
|
|
683
|
+
closeEntry(state, entry, now, { kind: 'abandoned', reason });
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
if (entry.source !== 'screen') {
|
|
687
|
+
// An API approval is not read off the screen: the poller stopping does not
|
|
688
|
+
// stop it being seen (its reply still settles it), so it stays open and
|
|
689
|
+
// `present`. Auto-Yes stopped answering it, though, so a withheld interval
|
|
690
|
+
// ends here: the time it is off is nobody's withheld time.
|
|
691
|
+
endInterval(state, entry, 'stopped', now);
|
|
692
|
+
entry.autoYesStopped = true;
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
if (entry.presence === 'unobservable')
|
|
696
|
+
return;
|
|
697
|
+
endInterval(state, entry, 'unobservable', now);
|
|
698
|
+
entry.presence = 'unobservable';
|
|
699
|
+
entry.unobservableSince = now;
|
|
700
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.presenceChanged, {
|
|
701
|
+
atMs: now,
|
|
702
|
+
confirmationId: entry.id,
|
|
703
|
+
from: 'present',
|
|
704
|
+
to: 'unobservable',
|
|
705
|
+
cause: reason,
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
/** `afterHookAllow` / `afterHookAbstain` for a screen confirmation opened `now` (design §2.3). */
|
|
709
|
+
function hookLink(state, compositeKey, now) {
|
|
710
|
+
const recent = state.lastHookRequest.get(compositeKey);
|
|
711
|
+
if (recent === undefined || now - recent.at > auto_yes_ledger_records_1.AUTO_YES_LEDGER_HOOK_LINK_WINDOW_MS)
|
|
712
|
+
return {};
|
|
713
|
+
return recent.outcome === 'allow' ? { afterHookAllow: true } : { afterHookAbstain: recent.abstainReason ?? 'unknown' };
|
|
714
|
+
}
|
|
715
|
+
// =============================================================================
|
|
716
|
+
// The hook path (the hook route and the adjudication it calls, PR 2)
|
|
717
|
+
// =============================================================================
|
|
718
|
+
/**
|
|
719
|
+
* A hook request arrived. **Only the hook route calls this** (design §2.3,
|
|
720
|
+
* N2): the API adjudication shares the adjudicator but makes no hook request.
|
|
721
|
+
*
|
|
722
|
+
* @returns The request's id, for {@link decideLedgerHookRequest} and
|
|
723
|
+
* {@link closeLedgerHookRequest}; null when the ledger failed
|
|
724
|
+
*/
|
|
725
|
+
function beginLedgerHookRequest(scope, receivedAtMs) {
|
|
726
|
+
return guarded(null, (state) => {
|
|
727
|
+
state.nextHookRequest += 1;
|
|
728
|
+
const id = `${state.bootId}-h${state.nextHookRequest}`;
|
|
729
|
+
const instanceId = scope.instanceId ?? scope.cliToolId;
|
|
730
|
+
(0, auto_yes_ledger_records_1.rememberBounded)(state.hookRequests, id, {
|
|
731
|
+
id,
|
|
732
|
+
compositeKey: scope.worktreeId === null ? null : (0, auto_yes_state_1.buildCompositeKey)(scope.worktreeId, scope.cliToolId, instanceId),
|
|
733
|
+
worktreeId: scope.worktreeId,
|
|
734
|
+
cliToolId: scope.cliToolId,
|
|
735
|
+
instanceId,
|
|
736
|
+
receivedAt: receivedAtMs,
|
|
737
|
+
decision: null,
|
|
738
|
+
confirmation: null,
|
|
739
|
+
}, auto_yes_ledger_records_1.MAX_OPEN_HOOK_REQUESTS);
|
|
740
|
+
return id;
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
/**
|
|
744
|
+
* The adjudicator decided about a hook request. An `allow` on a source whose
|
|
745
|
+
* allow draws no dialog makes the request the confirmation (design §2.3): it
|
|
746
|
+
* is opened here and closed with the request. Any other outcome opens nothing —
|
|
747
|
+
* a dialog that follows is the screen's confirmation, which alone holds the
|
|
748
|
+
* waiting time (the rule against counting it twice).
|
|
749
|
+
*/
|
|
750
|
+
function decideLedgerHookRequest(hookRequestId, decision) {
|
|
751
|
+
if (hookRequestId === null || hookRequestId === undefined)
|
|
752
|
+
return;
|
|
753
|
+
guarded(undefined, (state, now) => {
|
|
754
|
+
const request = state.hookRequests.get(hookRequestId);
|
|
755
|
+
if (request === undefined)
|
|
756
|
+
return;
|
|
757
|
+
request.decision = { ...decision };
|
|
758
|
+
if (decision.outcome !== 'allow' || !decision.allowSuppressesDialog || request.worktreeId === null)
|
|
759
|
+
return;
|
|
760
|
+
if (request.confirmation !== null)
|
|
761
|
+
return;
|
|
762
|
+
state.nextConfirmation += 1;
|
|
763
|
+
const confirmation = { id: `${state.bootId}-${state.nextConfirmation}`, openedAt: now, promptType: decision.promptType };
|
|
764
|
+
request.confirmation = confirmation;
|
|
765
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.opened, {
|
|
766
|
+
atMs: now,
|
|
767
|
+
confirmationId: confirmation.id,
|
|
768
|
+
worktreeId: request.worktreeId,
|
|
769
|
+
cliToolId: request.cliToolId,
|
|
770
|
+
instanceId: request.instanceId,
|
|
771
|
+
source: 'hook',
|
|
772
|
+
promptType: confirmation.promptType,
|
|
773
|
+
hookRequestId,
|
|
774
|
+
});
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
/**
|
|
778
|
+
* The confirmation a hook request was closes with the request: its one send
|
|
779
|
+
* settles and it closes answered, or unanswered when the reply did not leave.
|
|
780
|
+
*/
|
|
781
|
+
function settleHookConfirmation(state, now, request, worktreeId, confirmation, ok, failure) {
|
|
782
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.attemptSettled, {
|
|
783
|
+
atMs: now,
|
|
784
|
+
confirmationId: confirmation.id,
|
|
785
|
+
attemptId: `${confirmation.id}.1`,
|
|
786
|
+
cliToolId: request.cliToolId,
|
|
787
|
+
basis: 'L1',
|
|
788
|
+
result: ok ? 'ok' : 'failed',
|
|
789
|
+
late: false,
|
|
790
|
+
expired: false,
|
|
791
|
+
});
|
|
792
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.closed, {
|
|
793
|
+
atMs: now,
|
|
794
|
+
confirmationId: confirmation.id,
|
|
795
|
+
worktreeId,
|
|
796
|
+
cliToolId: request.cliToolId,
|
|
797
|
+
instanceId: request.instanceId,
|
|
798
|
+
source: 'hook',
|
|
799
|
+
promptType: confirmation.promptType,
|
|
800
|
+
decision: 'answer',
|
|
801
|
+
basis: 'L1',
|
|
802
|
+
attempts: { ok: ok ? 1 : 0, partial: 0, noKeysSent: 0, failed: ok ? 0 : 1 },
|
|
803
|
+
attemptsPending: 0,
|
|
804
|
+
answeredAtClose: ok,
|
|
805
|
+
resolution: ok ? 'resolved-by-reply' : 'unresolved-after-send',
|
|
806
|
+
resolvedBy: ok ? 'auto' : 'unknown',
|
|
807
|
+
openMs: Math.max(0, now - confirmation.openedAt),
|
|
808
|
+
withheldMsTotal: 0,
|
|
809
|
+
unobservableMs: 0,
|
|
810
|
+
intervals: 0,
|
|
811
|
+
...(ok ? {} : { abandonReason: failure }),
|
|
812
|
+
});
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* The hook route wrote its reply. `delivered: false` is a verdict that did not
|
|
816
|
+
* leave — the route's catch-all, or a delivery whose receipt said so: whatever
|
|
817
|
+
* had been decided, the agent got an abstention, so the request is closed
|
|
818
|
+
* `abstained` (`failure`, `error` when omitted) and a confirmation it was is
|
|
819
|
+
* closed unanswered, its send `failed`.
|
|
820
|
+
*/
|
|
821
|
+
function closeLedgerHookRequest(hookRequestId, reply) {
|
|
822
|
+
if (hookRequestId === null || hookRequestId === undefined)
|
|
823
|
+
return;
|
|
824
|
+
guarded(undefined, (state, now) => {
|
|
825
|
+
const request = state.hookRequests.get(hookRequestId);
|
|
826
|
+
if (request === undefined)
|
|
827
|
+
return;
|
|
828
|
+
state.hookRequests.delete(hookRequestId);
|
|
829
|
+
const decision = request.decision;
|
|
830
|
+
const outcome = reply.delivered && decision !== null ? decision.outcome : 'abstained';
|
|
831
|
+
const failure = reply.failure ?? 'error';
|
|
832
|
+
const abstainReason = !reply.delivered ? failure : decision === null ? 'undecided' : decision.abstainReason;
|
|
833
|
+
const confirmation = request.confirmation;
|
|
834
|
+
if (confirmation !== null && request.worktreeId !== null) {
|
|
835
|
+
settleHookConfirmation(state, now, request, request.worktreeId, confirmation, reply.delivered, failure);
|
|
836
|
+
}
|
|
837
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.hookRequestClosed, {
|
|
838
|
+
atMs: now,
|
|
839
|
+
hookRequestId,
|
|
840
|
+
cliToolId: request.cliToolId,
|
|
841
|
+
outcome,
|
|
842
|
+
...(outcome === 'abstained' && abstainReason !== undefined ? { abstainReason } : {}),
|
|
843
|
+
allowSuppressesDialog: decision?.allowSuppressesDialog ?? false,
|
|
844
|
+
replyMs: Math.max(0, now - request.receivedAt),
|
|
845
|
+
...(decision?.callId !== undefined ? { callId: decision.callId } : {}),
|
|
846
|
+
});
|
|
847
|
+
// PR 3: a call the request opened no confirmation for waits for the
|
|
848
|
+
// screen's confirmation to be tied to it, or for its `PostToolUse`.
|
|
849
|
+
if (request.compositeKey !== null && decision?.callId !== undefined && confirmation === null) {
|
|
850
|
+
(0, auto_yes_ledger_records_1.rememberBounded)((0, auto_yes_ledger_records_1.callsOf)(state), (0, auto_yes_ledger_records_1.callKey)(request.compositeKey, decision.callId), { hookRequestId, cliToolId: request.cliToolId, observed: false }, auto_yes_ledger_records_1.MAX_REMEMBERED_CALLS);
|
|
851
|
+
}
|
|
852
|
+
if (request.compositeKey !== null) {
|
|
853
|
+
(0, auto_yes_ledger_records_1.rememberBounded)(state.lastHookRequest, request.compositeKey, { at: now, outcome, ...(outcome === 'abstained' && abstainReason !== undefined ? { abstainReason } : {}) }, auto_yes_ledger_records_1.MAX_REMEMBERED_INSTANCES);
|
|
854
|
+
}
|
|
855
|
+
});
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* agy's call `callId` ended: its `PostToolUse` came (design §2.4, §2.6, PR 3).
|
|
859
|
+
* The screen confirmation tied to it closes as gone, if it had not gone from
|
|
860
|
+
* the screen first (who answered is not known: `unknown`). A call no
|
|
861
|
+
* confirmation was ever tied to writes `dialogUnobserved` on its hook request
|
|
862
|
+
* — and opens nothing. A call this ledger never heard asked about (a restart
|
|
863
|
+
* in between, a body without `stepIdx`) writes nothing; so does a second
|
|
864
|
+
* `PostToolUse` for the same call.
|
|
865
|
+
*/
|
|
866
|
+
function noteLedgerToolCallEnded(scope, callId) {
|
|
867
|
+
if (callId === null || callId === undefined)
|
|
868
|
+
return;
|
|
869
|
+
guarded(undefined, (state, now) => {
|
|
870
|
+
const compositeKey = (0, auto_yes_ledger_records_1.keyOf)(scope);
|
|
871
|
+
for (const entry of [...state.entries.values()]) {
|
|
872
|
+
if (entry.compositeKey !== compositeKey || entry.callId !== callId)
|
|
873
|
+
continue;
|
|
874
|
+
const wasCurrent = state.current.get(compositeKey) === entry.id;
|
|
875
|
+
closeEntry(state, entry, now, { kind: 'gone' });
|
|
876
|
+
if (wasCurrent) {
|
|
877
|
+
(0, auto_yes_ledger_records_1.rememberBounded)((0, auto_yes_ledger_records_1.endedCallsOf)(state), compositeKey, {
|
|
878
|
+
callId,
|
|
879
|
+
screenKey: entry.screenKey,
|
|
880
|
+
worktreeId: entry.worktreeId,
|
|
881
|
+
epoch: entry.epoch,
|
|
882
|
+
seenTick: state.ticks.get(compositeKey) ?? 0,
|
|
883
|
+
}, auto_yes_ledger_records_1.MAX_REMEMBERED_INSTANCES);
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
const key = (0, auto_yes_ledger_records_1.callKey)(compositeKey, callId);
|
|
887
|
+
const call = (0, auto_yes_ledger_records_1.callsOf)(state).get(key);
|
|
888
|
+
if (call === undefined)
|
|
889
|
+
return;
|
|
890
|
+
(0, auto_yes_ledger_records_1.callsOf)(state).delete(key);
|
|
891
|
+
if (call.observed)
|
|
892
|
+
return;
|
|
893
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.hookRequestDialogUnobserved, {
|
|
894
|
+
atMs: now,
|
|
895
|
+
hookRequestId: call.hookRequestId,
|
|
896
|
+
cliToolId: call.cliToolId,
|
|
897
|
+
callId,
|
|
898
|
+
dialogUnobserved: true,
|
|
899
|
+
});
|
|
900
|
+
});
|
|
901
|
+
}
|
|
902
|
+
/**
|
|
903
|
+
* The CLI's own permission mode, as a `PermissionRequest` stated it (design
|
|
904
|
+
* §3.4). A line the first time an instance's session shows one and whenever it
|
|
905
|
+
* changes; a new session forgets it. Instances that never show one write
|
|
906
|
+
* nothing — the count reads them as unknown, never as zero.
|
|
907
|
+
*/
|
|
908
|
+
function observeLedgerCliMode(scope, mode) {
|
|
909
|
+
guarded(undefined, (state, now) => {
|
|
910
|
+
const compositeKey = (0, auto_yes_ledger_records_1.keyOf)(scope);
|
|
911
|
+
const epoch = (0, auto_yes_enter_fallback_state_1.getEnterFallbackSessionEpoch)(compositeKey);
|
|
912
|
+
const word = auto_yes_ledger_records_1.CLI_MODE_WORD.test(mode) ? mode : '(other)';
|
|
913
|
+
const seen = state.cliModes.get(compositeKey);
|
|
914
|
+
const sameSession = seen !== undefined && seen.epoch === epoch;
|
|
915
|
+
if (sameSession && seen.mode === word)
|
|
916
|
+
return;
|
|
917
|
+
(0, auto_yes_ledger_records_1.rememberBounded)(state.cliModes, compositeKey, { epoch, mode: word }, auto_yes_ledger_records_1.MAX_REMEMBERED_INSTANCES);
|
|
918
|
+
(0, auto_yes_ledger_records_1.emit)(state, auto_yes_confirmation_ledger_types_1.AUTO_YES_LEDGER_EVENTS.cliModeObserved, {
|
|
919
|
+
atMs: now,
|
|
920
|
+
worktreeId: scope.worktreeId,
|
|
921
|
+
cliToolId: scope.cliToolId,
|
|
922
|
+
instanceId: scope.instanceId ?? scope.cliToolId,
|
|
923
|
+
sessionEpoch: epoch,
|
|
924
|
+
mode: word,
|
|
925
|
+
change: sameSession ? 'changed' : 'first',
|
|
926
|
+
});
|
|
927
|
+
});
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* One adjudication of the approval `decisionId` (design §2.4), in one call.
|
|
931
|
+
* The same as {@link beginLedgerApiAdjudication} followed at once by
|
|
932
|
+
* {@link settleLedgerApiAdjudication}; a caller that awaits the delivery in
|
|
933
|
+
* between uses the two.
|
|
934
|
+
*/
|
|
935
|
+
function recordLedgerApiAdjudication(scope, decisionId, adjudication) {
|
|
936
|
+
settleLedgerApiAdjudication(beginLedgerApiAdjudication(scope, decisionId, adjudication), adjudication);
|
|
937
|
+
}
|
|
938
|
+
/**
|
|
939
|
+
* An adjudication of the approval `decisionId` decided, and its verdict is
|
|
940
|
+
* about to be delivered (design §2.4). Called before the delivery's first
|
|
941
|
+
* await, as the screen path takes its handle (§2.5): the first adjudication
|
|
942
|
+
* opens the confirmation, a re-adjudication (re-connect, Auto-Yes switched on)
|
|
943
|
+
* continues it, a policy's abstention withholds it. An `allow` is a send,
|
|
944
|
+
* begun here.
|
|
945
|
+
*
|
|
946
|
+
* @returns The send's handle, for {@link settleLedgerApiAdjudication}; null for
|
|
947
|
+
* an abstention (or when the ledger failed)
|
|
948
|
+
*/
|
|
949
|
+
function beginLedgerApiAdjudication(scope, decisionId, verdict) {
|
|
950
|
+
return guarded(null, (state, now) => {
|
|
951
|
+
const compositeKey = (0, auto_yes_ledger_records_1.keyOf)(scope);
|
|
952
|
+
const decisionKey = `${compositeKey}\u0000${decisionId}`;
|
|
953
|
+
const knownId = state.apiDecisions.get(decisionKey);
|
|
954
|
+
let entry = knownId === undefined ? undefined : state.entries.get(knownId);
|
|
955
|
+
if (entry === undefined) {
|
|
956
|
+
entry = openEntry(state, scope, compositeKey, {
|
|
957
|
+
source: 'api',
|
|
958
|
+
screenKey: '',
|
|
959
|
+
promptType: verdict.promptType,
|
|
960
|
+
decisionKey,
|
|
961
|
+
}, now);
|
|
962
|
+
state.apiDecisions.set(decisionKey, entry.id);
|
|
963
|
+
}
|
|
964
|
+
// Adjudicated again with Auto-Yes on (an allow, or a policy's withholding):
|
|
965
|
+
// its intervals are this period's.
|
|
966
|
+
if (verdict.outcome === 'allow' || verdict.withholdReason !== undefined)
|
|
967
|
+
entry.autoYesStopped = false;
|
|
968
|
+
if (verdict.outcome === 'allow')
|
|
969
|
+
return beginAttempt(state, entry, 'L1', false);
|
|
970
|
+
if (verdict.withholdReason !== undefined) {
|
|
971
|
+
entry.decision = 'withhold';
|
|
972
|
+
withhold(state, entry, verdict.withholdReason, now);
|
|
973
|
+
}
|
|
974
|
+
return null;
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
/**
|
|
978
|
+
* The delivery of an `allow` came back: `delivered` is the send's result, and
|
|
979
|
+
* a settled reply closes the confirmation, answered by Auto-Yes. The result
|
|
980
|
+
* belongs to the confirmation the send was begun for — one that closed
|
|
981
|
+
* meanwhile (a session killed during the delivery) gets a `late` line and is
|
|
982
|
+
* neither reopened nor closed again (design §2.5, N1).
|
|
983
|
+
*/
|
|
984
|
+
function settleLedgerApiAdjudication(handle, delivery) {
|
|
985
|
+
if (handle === null || handle === undefined)
|
|
986
|
+
return;
|
|
987
|
+
guarded(undefined, (state, now) => {
|
|
988
|
+
settleAttempt(state, handle, delivery.delivered ? 'ok' : 'failed', false, now);
|
|
989
|
+
const entry = state.entries.get(handle.confirmationId);
|
|
990
|
+
if (entry !== undefined && delivery.delivered && delivery.settled)
|
|
991
|
+
closeEntry(state, entry, now, { kind: 'reply' });
|
|
992
|
+
});
|
|
993
|
+
}
|
|
994
|
+
/**
|
|
995
|
+
* The agent said the approval `decisionId` was answered (opencode's
|
|
996
|
+
* `permission.replied`) — by this server, another client or a human at the
|
|
997
|
+
* terminal. An open confirmation closes as gone; who answered is not known.
|
|
998
|
+
*/
|
|
999
|
+
function noteLedgerApiDecisionReplied(scope, decisionId) {
|
|
1000
|
+
guarded(undefined, (state, now) => {
|
|
1001
|
+
const knownId = state.apiDecisions.get(`${(0, auto_yes_ledger_records_1.keyOf)(scope)}\u0000${decisionId}`);
|
|
1002
|
+
const entry = knownId === undefined ? undefined : state.entries.get(knownId);
|
|
1003
|
+
if (entry !== undefined)
|
|
1004
|
+
closeEntry(state, entry, now, { kind: 'gone' });
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
/**
|
|
1008
|
+
* A `/prompt-response` answer: a confirmation of its own, opened and closed
|
|
1009
|
+
* with the request, with its one send. A failure is never an answer. Only a
|
|
1010
|
+
* human's successful answer names who resolved it (`human-ui`, design §2.6).
|
|
1011
|
+
*/
|
|
1012
|
+
function recordLedgerPromptResponse(scope, response) {
|
|
1013
|
+
guarded(undefined, (state, now) => {
|
|
1014
|
+
const entry = openEntry(state, scope, (0, auto_yes_ledger_records_1.keyOf)(scope), {
|
|
1015
|
+
source: 'prompt-response',
|
|
1016
|
+
screenKey: '',
|
|
1017
|
+
promptType: response.promptType,
|
|
1018
|
+
}, now);
|
|
1019
|
+
const handle = beginAttempt(state, entry, response.basis, false);
|
|
1020
|
+
if (response.basis === 'human')
|
|
1021
|
+
entry.decision = 'none';
|
|
1022
|
+
// Closed in the same call, so a failure opens no withheld interval.
|
|
1023
|
+
settleAttempt(state, handle, response.result, false, now, { withholdOnFailure: false });
|
|
1024
|
+
if (response.result === 'ok') {
|
|
1025
|
+
closeEntry(state, entry, now, { kind: 'gone', resolvedBy: response.basis === 'human' ? 'human-ui' : 'unknown' });
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
closeEntry(state, entry, now, { kind: 'abandoned', reason: 'send-failed' });
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
// =============================================================================
|
|
1032
|
+
// Test seams
|
|
1033
|
+
// =============================================================================
|
|
1034
|
+
/**
|
|
1035
|
+
* One hour boundary's lines, stamped `atMs`, as the clock writes them.
|
|
1036
|
+
* @internal Exported for tests.
|
|
1037
|
+
*/
|
|
1038
|
+
function runAutoYesLedgerHourForTests(atMs) {
|
|
1039
|
+
guarded(undefined, (state) => runHour(state, atMs));
|
|
1040
|
+
}
|
|
1041
|
+
/** Drop the state (and its clock). @internal Exported for tests. */
|
|
1042
|
+
function resetAutoYesConfirmationLedgerForTests() {
|
|
1043
|
+
const state = globalThis.__autoYesConfirmationLedger;
|
|
1044
|
+
if (state?.clock?.timer)
|
|
1045
|
+
clockTimers.clearTimeout(state.clock.timer);
|
|
1046
|
+
globalThis.__autoYesConfirmationLedger = undefined;
|
|
1047
|
+
injectedFault = null;
|
|
1048
|
+
}
|
|
1049
|
+
/** Make every entry point fail as if it had thrown; null restores. @internal Exported for tests. */
|
|
1050
|
+
function setAutoYesLedgerFaultForTests(fault) {
|
|
1051
|
+
injectedFault = fault;
|
|
1052
|
+
}
|
|
1053
|
+
/** Replace the clock's timers; null restores the ones taken at load. @internal Exported for tests. */
|
|
1054
|
+
function setAutoYesLedgerClockTimersForTests(timers) {
|
|
1055
|
+
clockTimers = timers ?? loadedClockTimers;
|
|
1056
|
+
}
|
|
1057
|
+
/** The swallowed-exception count of this process (`ledgerErrors`). @internal Exported for tests. */
|
|
1058
|
+
function getAutoYesLedgerErrorCountForTests() {
|
|
1059
|
+
return globalThis.__autoYesConfirmationLedger?.errors ?? 0;
|
|
1060
|
+
}
|