commandmate 0.47.0 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +501 -501
- package/.next/app-path-routes-manifest.json +34 -34
- 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 +12 -12
- 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 +1 -103
- 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 +12 -12
- 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 +34 -34
- package/.next/server/chunks/{5048.js → 1185.js} +1 -1
- package/.next/server/chunks/1191.js +11 -4
- package/.next/server/chunks/1501.js +1 -1
- package/.next/server/chunks/1601.js +2 -2
- package/.next/server/chunks/1656.js +19 -0
- package/.next/server/chunks/1945.js +3 -3
- package/.next/server/chunks/1990.js +103 -0
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/2422.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/2534.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/4248.js +1 -1
- package/.next/server/chunks/4280.js +1 -0
- package/.next/server/chunks/463.js +1 -0
- package/.next/server/chunks/5209.js +1 -1
- package/.next/server/chunks/5611.js +1 -1
- 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/6486.js +9 -8
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/6784.js +1 -0
- package/.next/server/chunks/720.js +103 -0
- package/.next/server/chunks/7604.js +2 -0
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8581.js +7 -7
- package/.next/server/chunks/8728.js +3 -3
- package/.next/server/chunks/8791.js +1 -1
- package/.next/server/chunks/8807.js +19 -18
- package/.next/server/chunks/8918.js +2 -104
- 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 +4 -4
- 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/2099-c3e0ab70a1b95dd3.js +1 -0
- package/.next/static/chunks/{2407-b2f524f99f7fc353.js → 2407-26139a8a2f1adbe8.js} +1 -1
- package/.next/static/chunks/{2619-04bc32f026a0d946.js → 2619-a305ad4810f1393a.js} +1 -1
- package/.next/static/chunks/{2863-6a07ec82fb52f4dd.js → 2863-f0121af1cbbedb3b.js} +1 -1
- package/.next/static/chunks/{8165-263172c17ae8e8c3.js → 8165-c68b3dc844210e6a.js} +1 -1
- package/.next/static/chunks/8407-35bbfc84793d7004.js +1 -0
- package/.next/static/chunks/9079-406b84d3cc891a87.js +1 -0
- package/.next/static/chunks/9465-b59bb255b376c813.js +1 -0
- package/.next/static/chunks/app/{layout-419eaf7de340f4ab.js → layout-46b4cbf07520d9b6.js} +1 -1
- package/.next/static/chunks/app/sessions/page-fb241bed579c67aa.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-cbc7749a33450cc5.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/{page-373ea37b16d930c7.js → page-c601f3b3ece6557e.js} +1 -1
- 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/auto-yes.d.ts +24 -0
- package/dist/cli/commands/auto-yes.d.ts.map +1 -1
- package/dist/cli/commands/auto-yes.js +73 -3
- package/dist/cli/commands/instances.d.ts.map +1 -1
- package/dist/cli/commands/instances.js +10 -1
- package/dist/cli/commands/prompt.d.ts.map +1 -1
- package/dist/cli/commands/prompt.js +28 -14
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +15 -0
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +108 -14
- package/dist/cli/docs/agent-operations.d.ts +2 -2
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +27 -0
- package/dist/cli/types/api-responses.d.ts +131 -4
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/types/index.d.ts +4 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/utils/resource-resolvers.d.ts +0 -18
- package/dist/cli/utils/resource-resolvers.d.ts.map +1 -1
- package/dist/cli/utils/resource-resolvers.js +1 -51
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts +65 -2
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts.map +1 -1
- package/dist/lib/polling/auto-yes-suppression-reason.js +36 -2
- package/dist/lib/prompt-observation/types.d.ts +13 -0
- package/dist/lib/prompt-observation/types.d.ts.map +1 -1
- package/dist/server/locales/en/worktree.json +2 -1
- package/dist/server/locales/ja/worktree.json +2 -1
- package/dist/server/src/lib/auto-yes-poller-answer-target.js +38 -0
- package/dist/server/src/lib/auto-yes-poller-keys.js +35 -0
- package/dist/server/src/lib/auto-yes-poller-session-presence.js +26 -0
- package/dist/server/src/lib/auto-yes-poller-tick.js +233 -0
- package/dist/server/src/lib/auto-yes-poller.js +468 -792
- package/dist/server/src/lib/auto-yes-state.js +50 -2
- package/dist/server/src/lib/cli-tools/submit-verified-sender.js +107 -14
- package/dist/server/src/lib/db/chat-db.js +5 -1
- package/dist/server/src/lib/db/verification-db.js +23 -2
- package/dist/server/src/lib/detection/option-recommendation.js +120 -0
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice-approval-context.js +290 -0
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +396 -268
- package/dist/server/src/lib/detection/prompt-detector.js +92 -21
- package/dist/server/src/lib/detection/prompt-screen-key.js +60 -0
- package/dist/server/src/lib/detection/tools/antigravity/dialog.js +158 -35
- package/dist/server/src/lib/detection/tools/claude/detect.js +111 -10
- package/dist/server/src/lib/detection/tools/command-code/dialog.js +67 -0
- package/dist/server/src/lib/detection/tools/dialog-block.js +16 -0
- package/dist/server/src/lib/detection/waiting-screen-reading.js +98 -0
- package/dist/server/src/lib/hooks/permission-adjudication.js +26 -0
- package/dist/server/src/lib/hooks/permission-decision-service.js +49 -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-confirm-page.js +2 -2
- package/dist/server/src/lib/polling/auto-yes-confirmation-ledger-types.js +117 -0
- package/dist/server/src/lib/polling/auto-yes-confirmation-ledger.js +1091 -0
- package/dist/server/src/lib/polling/auto-yes-decision-state.js +195 -0
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +139 -10
- package/dist/server/src/lib/polling/auto-yes-enter-fallback.js +14 -0
- package/dist/server/src/lib/polling/auto-yes-ledger-records.js +143 -0
- package/dist/server/src/lib/polling/auto-yes-manual-answer.js +122 -0
- package/dist/server/src/lib/polling/auto-yes-option-effect.js +157 -0
- package/dist/server/src/lib/polling/auto-yes-policy.js +46 -11
- package/dist/server/src/lib/polling/auto-yes-poller-capture.js +63 -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 +192 -0
- package/dist/server/src/lib/polling/auto-yes-poller-receipt-log.js +324 -0
- package/dist/server/src/lib/polling/auto-yes-poller-state.js +193 -26
- package/dist/server/src/lib/polling/auto-yes-poller-steps.js +279 -0
- package/dist/server/src/lib/polling/auto-yes-prompt-suppression.js +13 -2
- package/dist/server/src/lib/polling/auto-yes-question-choice.js +57 -0
- package/dist/server/src/lib/polling/auto-yes-resolver.js +117 -22
- package/dist/server/src/lib/polling/auto-yes-suppression-reason.js +36 -2
- package/dist/server/src/lib/polling/auto-yes-suppression-state.js +25 -1
- package/dist/server/src/lib/polling/prompt-screen-reading.js +232 -0
- package/dist/server/src/lib/polling/response-checker-blank-response.js +30 -0
- package/dist/server/src/lib/polling/response-checker-dialog-gate.js +39 -0
- package/dist/server/src/lib/polling/response-checker.js +138 -53
- package/dist/server/src/lib/prompt-answer-sender.js +104 -10
- package/dist/server/src/lib/prompt-observation/appearance.js +165 -0
- package/dist/server/src/lib/push/notification-dedup.js +15 -2
- package/dist/server/src/lib/push/prompt-card-state.js +140 -19
- package/dist/server/src/lib/push/prompt-push-gate.js +158 -12
- package/dist/server/src/lib/push/push-sender.js +23 -3
- package/dist/server/src/lib/push/resolution-push-notifier.js +14 -0
- package/dist/server/src/lib/push/waiting-push-notifier.js +139 -17
- package/dist/server/src/lib/realtime/terminal-broadcast.js +16 -0
- package/dist/server/src/lib/session/agent-event-state.js +25 -5
- package/dist/server/src/lib/session/agent-event-turn.js +140 -46
- package/dist/server/src/lib/session/cli-session.js +21 -2
- package/dist/server/src/lib/session/current-output-builder.js +64 -11
- package/dist/server/src/lib/session/send-attempt-state.js +23 -7
- package/dist/server/src/lib/session/waiting-episode-binding-observation.js +289 -0
- package/dist/server/src/lib/session/waiting-episode-binding-resolve.js +38 -0
- package/dist/server/src/lib/session/waiting-episode-binding.js +276 -0
- package/dist/server/src/lib/session/waiting-episode-state.js +307 -17
- package/dist/server/src/lib/session/waiting-episode-verdict.js +174 -0
- package/dist/server/src/lib/tmux/tmux-capture-cache.js +76 -11
- package/dist/server/src/lib/tmux/tmux.js +54 -9
- package/dist/server/src/lib/verification/gate-runner.js +162 -13
- package/dist/server/src/lib/verification/machine-lock.js +5 -0
- package/dist/server/src/lib/ws-server.js +18 -3
- package/dist/server/src/types/auto-yes-answer-mode.js +38 -0
- package/dist/server/src/types/auto-yes-decision.js +61 -0
- package/dist/server/src/types/auto-yes.js +6 -0
- package/dist/server/src/types/prompt-reading.js +32 -0
- package/dist/types/auto-yes-answer-mode.d.ts +35 -0
- package/dist/types/auto-yes-answer-mode.d.ts.map +1 -0
- package/dist/types/auto-yes-answer-mode.js +38 -0
- package/docs/en/user-guide/webapp-guide.md +33 -4
- package/package.json +2 -2
- package/public/sw.js +76 -4
- package/release-notes/0.47.1.json +20 -0
- package/release-notes/0.47.2.json +20 -0
- package/release-notes/0.48.0.json +57 -0
- package/scripts/hooks/cmate-agent-event.sh +22 -0
- package/.next/server/chunks/1331.js +0 -22
- package/.next/server/chunks/1559.js +0 -2
- 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/2460.js +0 -1
- package/.next/server/chunks/5292.js +0 -7
- package/.next/server/chunks/5595.js +0 -1
- 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/602-1c1488959215e140.js +0 -1
- package/.next/static/chunks/8407-155f84e5ba05f1d5.js +0 -1
- package/.next/static/chunks/9079-24f9fa549ed298f1.js +0 -1
- package/.next/static/chunks/9465-e5a351baa941f31b.js +0 -1
- package/.next/static/chunks/app/sessions/page-e02f1adb1d1c1ccc.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 → PTlAswXLq8PAe2vUJ8dVP}/_buildManifest.js +0 -0
- /package/.next/static/{b5BiQC9F6r_XFPdA9cuSj → PTlAswXLq8PAe2vUJ8dVP}/_ssgManifest.js +0 -0
|
@@ -8,8 +8,14 @@
|
|
|
8
8
|
* Issue #525: Composite key migration (worktreeId:cliToolId) for per-agent auto-yes.
|
|
9
9
|
*
|
|
10
10
|
* Dependencies: auto-yes-state.ts (composite keys / state), polling/* (prompt
|
|
11
|
-
* detection, resolver, policy, dialog gate,
|
|
12
|
-
* cli-tools/*, session/cli-session.ts, tmux/*, detection/*,
|
|
11
|
+
* detection, resolver, policy, dialog gate, session epoch, poller state,
|
|
12
|
+
* decision record), cli-tools/*, session/cli-session.ts, tmux/*, detection/*,
|
|
13
|
+
* db/*, tasks/*.
|
|
14
|
+
*
|
|
15
|
+
* Issue #3821: this poller (with the hook / API adjudication) is what answers
|
|
16
|
+
* automatically. The browser no longer answers, and the Enter sent to a choice
|
|
17
|
+
* screen CommandMate could not read (#3397) is gone: such a screen is left to a
|
|
18
|
+
* human, recorded as `unclassified-frame`.
|
|
13
19
|
*/
|
|
14
20
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
21
|
if (k2 === undefined) k2 = k;
|
|
@@ -45,46 +51,38 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
45
51
|
};
|
|
46
52
|
})();
|
|
47
53
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.AUTO_YES_ENTER_FALLBACK_ANSWER = void 0;
|
|
49
|
-
exports.getActivePollerCount = getActivePollerCount;
|
|
54
|
+
exports.capturePollerFrame = exports.captureAndCleanOutput = exports.AUTO_YES_ENTER_FALLBACK_ANSWER = exports.isAnyPollerActiveForWorktree = exports.getAutoYesPollerCompositeKeys = exports.noHookReceiptHint = exports.isPollerActive = exports.getLastServerResponseTimestamp = exports.getActivePollerCount = void 0;
|
|
50
55
|
exports.clearAllPollerStates = clearAllPollerStates;
|
|
51
|
-
exports.getLastServerResponseTimestamp = getLastServerResponseTimestamp;
|
|
52
|
-
exports.isPollerActive = isPollerActive;
|
|
53
56
|
exports.validatePollingContext = validatePollingContext;
|
|
54
|
-
exports.capturePollerFrame = capturePollerFrame;
|
|
55
|
-
exports.captureAndCleanOutput = captureAndCleanOutput;
|
|
56
57
|
exports.processStopConditionDelta = processStopConditionDelta;
|
|
57
|
-
exports.noHookReceiptHint = noHookReceiptHint;
|
|
58
58
|
exports.detectAndRespondToPrompt = detectAndRespondToPrompt;
|
|
59
59
|
exports.startAutoYesPolling = startAutoYesPolling;
|
|
60
60
|
exports.stopAutoYesPolling = stopAutoYesPolling;
|
|
61
61
|
exports.stopAllAutoYesPolling = stopAllAutoYesPolling;
|
|
62
|
-
exports.getAutoYesPollerCompositeKeys = getAutoYesPollerCompositeKeys;
|
|
63
62
|
exports.stopAutoYesPollingByWorktree = stopAutoYesPollingByWorktree;
|
|
64
|
-
exports.isAnyPollerActiveForWorktree = isAnyPollerActiveForWorktree;
|
|
65
|
-
const cli_session_1 = require("./session/cli-session");
|
|
66
63
|
const response_checker_1 = require("./polling/response-checker");
|
|
67
|
-
const antigravity_receipt_episodes_1 = require("./polling/antigravity-receipt-episodes");
|
|
68
|
-
const antigravity_permission_receipts_1 = require("./polling/antigravity-permission-receipts");
|
|
69
|
-
const auto_yes_resolver_1 = require("./polling/auto-yes-resolver");
|
|
70
64
|
const auto_yes_policy_1 = require("./polling/auto-yes-policy");
|
|
71
|
-
const detect_1 = require("./detection/tools/codex/detect");
|
|
72
|
-
const frame_1 = require("./detection/tools/frame");
|
|
73
|
-
const auto_yes_dialog_gate_1 = require("./polling/auto-yes-dialog-gate");
|
|
74
65
|
const auto_yes_enter_fallback_1 = require("./polling/auto-yes-enter-fallback");
|
|
66
|
+
const auto_yes_decision_state_1 = require("./polling/auto-yes-decision-state");
|
|
67
|
+
const auto_yes_manual_answer_1 = require("./polling/auto-yes-manual-answer");
|
|
68
|
+
const auto_yes_decision_1 = require("../types/auto-yes-decision");
|
|
75
69
|
const task_transition_service_1 = require("./tasks/task-transition-service");
|
|
76
70
|
const db_instance_1 = require("./db/db-instance");
|
|
77
71
|
const chat_db_1 = require("./db/chat-db");
|
|
78
72
|
const worktree_session_ownership_1 = require("./cli-tools/worktree-session-ownership");
|
|
79
73
|
const prompt_answer_sender_1 = require("./prompt-answer-sender");
|
|
80
|
-
const prompt_answer_semantic_1 = require("./prompt-answer-semantic");
|
|
81
|
-
const tmux_1 = require("./tmux/tmux");
|
|
82
74
|
const session_created_signal_1 = require("./tmux/session-created-signal");
|
|
83
75
|
const manager_1 = require("./cli-tools/manager");
|
|
84
76
|
const cli_patterns_1 = require("./detection/cli-patterns");
|
|
85
77
|
const prompt_key_1 = require("./detection/prompt-key");
|
|
86
78
|
const errors_1 = require("./errors");
|
|
87
79
|
const tmux_capture_cache_1 = require("./tmux/tmux-capture-cache");
|
|
80
|
+
const waiting_screen_reading_1 = require("./detection/waiting-screen-reading");
|
|
81
|
+
const status_detector_1 = require("./detection/status-detector");
|
|
82
|
+
const prompt_waiting_composition_1 = require("./session/prompt-waiting-composition");
|
|
83
|
+
const registry_1 = require("./hooks/sources/registry");
|
|
84
|
+
const waiting_episode_binding_1 = require("./session/waiting-episode-binding");
|
|
85
|
+
const waiting_episode_state_1 = require("./session/waiting-episode-state");
|
|
88
86
|
const auto_yes_config_1 = require("../config/auto-yes-config");
|
|
89
87
|
const auto_yes_poller_stop_reason_1 = require("./polling/auto-yes-poller-stop-reason");
|
|
90
88
|
const logger_1 = require("../lib/logger");
|
|
@@ -92,42 +90,34 @@ const logger = (0, logger_1.createLogger)('auto-yes-poller');
|
|
|
92
90
|
const path_validator_1 = require("./security/path-validator");
|
|
93
91
|
const auto_yes_state_1 = require("./auto-yes-state");
|
|
94
92
|
const global_state_1 = require("./global-state");
|
|
95
|
-
const auto_yes_suppression_reason_1 = require("./polling/auto-yes-suppression-reason");
|
|
96
|
-
const auto_yes_suppression_state_1 = require("./polling/auto-yes-suppression-state");
|
|
97
93
|
const auto_yes_poller_state_1 = require("./polling/auto-yes-poller-state");
|
|
98
94
|
const auto_yes_prompt_suppression_1 = require("./polling/auto-yes-prompt-suppression");
|
|
99
|
-
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Get the number of active pollers.
|
|
127
|
-
*/
|
|
128
|
-
function getActivePollerCount() {
|
|
129
|
-
return autoYesPollerStates.size;
|
|
130
|
-
}
|
|
95
|
+
const auto_yes_poller_generation_1 = require("./polling/auto-yes-poller-generation");
|
|
96
|
+
const auto_yes_poller_receipt_log_1 = require("./polling/auto-yes-poller-receipt-log");
|
|
97
|
+
const auto_yes_poller_enter_fallback_1 = require("./polling/auto-yes-poller-enter-fallback");
|
|
98
|
+
const auto_yes_poller_capture_1 = require("./polling/auto-yes-poller-capture");
|
|
99
|
+
const prompt_screen_reading_1 = require("./polling/prompt-screen-reading");
|
|
100
|
+
const auto_yes_confirmation_ledger_1 = require("./polling/auto-yes-confirmation-ledger");
|
|
101
|
+
const auto_yes_poller_tick_1 = require("./auto-yes-poller-tick");
|
|
102
|
+
const auto_yes_poller_answer_target_1 = require("./auto-yes-poller-answer-target");
|
|
103
|
+
const auto_yes_poller_session_presence_1 = require("./auto-yes-poller-session-presence");
|
|
104
|
+
const auto_yes_poller_steps_1 = require("./polling/auto-yes-poller-steps");
|
|
105
|
+
// Issue #3783: split out; re-exported so existing importers are unchanged.
|
|
106
|
+
var auto_yes_poller_generation_2 = require("./polling/auto-yes-poller-generation");
|
|
107
|
+
Object.defineProperty(exports, "getActivePollerCount", { enumerable: true, get: function () { return auto_yes_poller_generation_2.getActivePollerCount; } });
|
|
108
|
+
Object.defineProperty(exports, "getLastServerResponseTimestamp", { enumerable: true, get: function () { return auto_yes_poller_generation_2.getLastServerResponseTimestamp; } });
|
|
109
|
+
Object.defineProperty(exports, "isPollerActive", { enumerable: true, get: function () { return auto_yes_poller_generation_2.isPollerActive; } });
|
|
110
|
+
var auto_yes_poller_receipt_log_2 = require("./polling/auto-yes-poller-receipt-log");
|
|
111
|
+
Object.defineProperty(exports, "noHookReceiptHint", { enumerable: true, get: function () { return auto_yes_poller_receipt_log_2.noHookReceiptHint; } });
|
|
112
|
+
// Issue #3893: split out; re-exported so existing importers are unchanged.
|
|
113
|
+
var auto_yes_poller_keys_1 = require("./auto-yes-poller-keys");
|
|
114
|
+
Object.defineProperty(exports, "getAutoYesPollerCompositeKeys", { enumerable: true, get: function () { return auto_yes_poller_keys_1.getAutoYesPollerCompositeKeys; } });
|
|
115
|
+
Object.defineProperty(exports, "isAnyPollerActiveForWorktree", { enumerable: true, get: function () { return auto_yes_poller_keys_1.isAnyPollerActiveForWorktree; } });
|
|
116
|
+
var auto_yes_poller_enter_fallback_2 = require("./polling/auto-yes-poller-enter-fallback");
|
|
117
|
+
Object.defineProperty(exports, "AUTO_YES_ENTER_FALLBACK_ANSWER", { enumerable: true, get: function () { return auto_yes_poller_enter_fallback_2.AUTO_YES_ENTER_FALLBACK_ANSWER; } });
|
|
118
|
+
var auto_yes_poller_capture_2 = require("./polling/auto-yes-poller-capture");
|
|
119
|
+
Object.defineProperty(exports, "captureAndCleanOutput", { enumerable: true, get: function () { return auto_yes_poller_capture_2.captureAndCleanOutput; } });
|
|
120
|
+
Object.defineProperty(exports, "capturePollerFrame", { enumerable: true, get: function () { return auto_yes_poller_capture_2.capturePollerFrame; } });
|
|
131
121
|
/**
|
|
132
122
|
* Clear all poller states.
|
|
133
123
|
* Stops all active pollers before clearing state.
|
|
@@ -136,58 +126,8 @@ function getActivePollerCount() {
|
|
|
136
126
|
function clearAllPollerStates() {
|
|
137
127
|
// Issue #3730: a test seam, not a shutdown — logged as such.
|
|
138
128
|
(0, auto_yes_poller_stop_reason_1.withPollerStopReason)('reset', () => stopAllAutoYesPolling());
|
|
139
|
-
autoYesPollerStates.clear();
|
|
140
|
-
withheldNoReceiptLoggedAt.clear();
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Get the last server response timestamp for a composite key.
|
|
144
|
-
*
|
|
145
|
-
* Issue #525: Changed from (worktreeId) to (compositeKey).
|
|
146
|
-
*
|
|
147
|
-
* @param compositeKey - Composite key (worktreeId:cliToolId)
|
|
148
|
-
* @returns Timestamp (Date.now()) of the last server response, or null if none
|
|
149
|
-
*/
|
|
150
|
-
function getLastServerResponseTimestamp(compositeKey) {
|
|
151
|
-
const pollerState = getPollerState(compositeKey);
|
|
152
|
-
return pollerState?.lastServerResponseTimestamp ?? null;
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Check if a server-side auto-yes poller is active for a composite key.
|
|
156
|
-
*
|
|
157
|
-
* Issue #525: Changed from (worktreeId) to (compositeKey).
|
|
158
|
-
*
|
|
159
|
-
* @param compositeKey - Composite key (worktreeId:cliToolId)
|
|
160
|
-
* @returns true if a poller is actively running
|
|
161
|
-
*/
|
|
162
|
-
function isPollerActive(compositeKey) {
|
|
163
|
-
return autoYesPollerStates.has(compositeKey);
|
|
164
|
-
}
|
|
165
|
-
/**
|
|
166
|
-
* Update the last server response timestamp.
|
|
167
|
-
*
|
|
168
|
-
* @param compositeKey - Composite key
|
|
169
|
-
* @param timestamp - Timestamp value (Date.now())
|
|
170
|
-
*/
|
|
171
|
-
function updateLastServerResponseTimestamp(compositeKey, timestamp, owner) {
|
|
172
|
-
const pollerState = ownedPollerState(compositeKey, owner);
|
|
173
|
-
if (pollerState) {
|
|
174
|
-
pollerState.lastServerResponseTimestamp = timestamp;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
/**
|
|
178
|
-
* Reset error count for a poller and restore the default polling interval.
|
|
179
|
-
* Called after every poll that ran to the end without an error (Issue #3329)
|
|
180
|
-
* and after an answer is sent.
|
|
181
|
-
*
|
|
182
|
-
* @param compositeKey - Composite key
|
|
183
|
-
* @param owner - The tick's own poller state (Issue #3706); see {@link ownedPollerState}
|
|
184
|
-
*/
|
|
185
|
-
function resetErrorCount(compositeKey, owner) {
|
|
186
|
-
const pollerState = ownedPollerState(compositeKey, owner);
|
|
187
|
-
if (pollerState) {
|
|
188
|
-
pollerState.consecutiveErrors = 0;
|
|
189
|
-
pollerState.currentInterval = auto_yes_state_1.POLLING_INTERVAL_MS;
|
|
190
|
-
}
|
|
129
|
+
auto_yes_poller_generation_1.autoYesPollerStates.clear();
|
|
130
|
+
auto_yes_poller_receipt_log_1.withheldNoReceiptLoggedAt.clear();
|
|
191
131
|
}
|
|
192
132
|
/**
|
|
193
133
|
* Increment error count and apply backoff if the threshold is exceeded.
|
|
@@ -197,10 +137,12 @@ function resetErrorCount(compositeKey, owner) {
|
|
|
197
137
|
* @param owner - The tick's own poller state (Issue #3706); see {@link ownedPollerState}
|
|
198
138
|
*/
|
|
199
139
|
function incrementErrorCount(compositeKey, owner) {
|
|
200
|
-
const pollerState = ownedPollerState(compositeKey, owner);
|
|
140
|
+
const pollerState = (0, auto_yes_poller_generation_1.ownedPollerState)(compositeKey, owner);
|
|
201
141
|
if (pollerState) {
|
|
202
142
|
pollerState.consecutiveErrors++;
|
|
203
143
|
pollerState.currentInterval = (0, auto_yes_state_1.calculateBackoffInterval)(pollerState.consecutiveErrors);
|
|
144
|
+
// Issue #3791 (review N1): a failed tick held nothing back with the duplicate guard.
|
|
145
|
+
(0, auto_yes_poller_generation_1.releaseDuplicateRetry)(pollerState);
|
|
204
146
|
// Issue #499 Item 5: Auto-stop after consecutive error threshold.
|
|
205
147
|
//
|
|
206
148
|
// Issue #3184: this is the `consecutive-errors` row of AUTO_YES_LIFECYCLE
|
|
@@ -221,46 +163,6 @@ function incrementErrorCount(compositeKey, owner) {
|
|
|
221
163
|
}
|
|
222
164
|
}
|
|
223
165
|
}
|
|
224
|
-
/**
|
|
225
|
-
* The poller state under `compositeKey`, but only when it is `owner` — the
|
|
226
|
-
* tick's own (Issue #3706). Without `owner` (callers outside a tick, and tests
|
|
227
|
-
* driving `detectAndRespondToPrompt` with a hand-built state) it is the plain
|
|
228
|
-
* by-key read this always was.
|
|
229
|
-
*/
|
|
230
|
-
function ownedPollerState(compositeKey, owner) {
|
|
231
|
-
const pollerState = getPollerState(compositeKey);
|
|
232
|
-
if (owner !== undefined && pollerState !== owner)
|
|
233
|
-
return undefined;
|
|
234
|
-
return pollerState;
|
|
235
|
-
}
|
|
236
|
-
/** Is the tick's poller still the one under its key (not stopped, not replaced)? */
|
|
237
|
-
function isPollerCurrent(generation) {
|
|
238
|
-
return getPollerState(generation.compositeKey) === generation.pollerState;
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* May the tick still act: its poller, its grant (the same enable, not expired)
|
|
242
|
-
* and its session (no relaunch since) are all still the ones it started under.
|
|
243
|
-
* Checked after capture, after each wait before a key, and inside the send.
|
|
244
|
-
*/
|
|
245
|
-
function isTickCurrent(generation) {
|
|
246
|
-
if (!isPollerCurrent(generation))
|
|
247
|
-
return false;
|
|
248
|
-
// `getAutoYesState` returns the stored object until it expires, when it
|
|
249
|
-
// stores (and returns) a disabled one — so an expiry fails identity too.
|
|
250
|
-
const grant = (0, auto_yes_state_1.getAutoYesState)(generation.worktreeId, generation.cliToolId, generation.instanceId);
|
|
251
|
-
if (grant !== generation.grant || !grant.enabled)
|
|
252
|
-
return false;
|
|
253
|
-
return isSameSession(generation);
|
|
254
|
-
}
|
|
255
|
-
/**
|
|
256
|
-
* Is the session the tick answered still the one it started on (Issue #3706)?
|
|
257
|
-
* What the follow-ups of an answer already sent — the response poller restart,
|
|
258
|
-
* the terminal push — are judged by: a disable after the keys landed does not
|
|
259
|
-
* un-send them, a relaunch does make them about another process.
|
|
260
|
-
*/
|
|
261
|
-
function isSameSession(generation) {
|
|
262
|
-
return (0, auto_yes_enter_fallback_1.getEnterFallbackSessionEpoch)(generation.compositeKey) === generation.sessionEpoch;
|
|
263
|
-
}
|
|
264
166
|
/**
|
|
265
167
|
* End a tick that found its generation gone (Issue #3706). It changes nothing;
|
|
266
168
|
* it re-arms its timer only when its own poller is still the current one — a
|
|
@@ -272,25 +174,11 @@ function endStaleTick(generation) {
|
|
|
272
174
|
worktreeId: generation.worktreeId,
|
|
273
175
|
cliToolId: generation.cliToolId,
|
|
274
176
|
instanceId: generation.instanceId,
|
|
275
|
-
pollerCurrent: isPollerCurrent(generation),
|
|
177
|
+
pollerCurrent: (0, auto_yes_poller_generation_1.isPollerCurrent)(generation),
|
|
276
178
|
});
|
|
277
|
-
if (isPollerCurrent(generation))
|
|
179
|
+
if ((0, auto_yes_poller_generation_1.isPollerCurrent)(generation))
|
|
278
180
|
scheduleNextPoll(generation);
|
|
279
181
|
}
|
|
280
|
-
/**
|
|
281
|
-
* Check if the given prompt has already been answered recently.
|
|
282
|
-
*
|
|
283
|
-
* @param pollerState - Current poller state
|
|
284
|
-
* @param promptKey - Composite key of the current prompt
|
|
285
|
-
* @returns true if the prompt key matches and is within the retry expiry window
|
|
286
|
-
*/
|
|
287
|
-
function isDuplicatePrompt(pollerState, promptKey) {
|
|
288
|
-
if (pollerState.lastAnsweredPromptKey !== promptKey)
|
|
289
|
-
return false;
|
|
290
|
-
if (pollerState.lastAnsweredAt === null)
|
|
291
|
-
return false;
|
|
292
|
-
return (Date.now() - pollerState.lastAnsweredAt) < auto_yes_state_1.DUPLICATE_RETRY_EXPIRY_MS;
|
|
293
|
-
}
|
|
294
182
|
// =============================================================================
|
|
295
183
|
// Extracted Functions for pollAutoYes (Issue #323: SRP decomposition)
|
|
296
184
|
// =============================================================================
|
|
@@ -327,38 +215,6 @@ function validatePollingContext(compositeKey, pollerState) {
|
|
|
327
215
|
}
|
|
328
216
|
return 'valid';
|
|
329
217
|
}
|
|
330
|
-
/**
|
|
331
|
-
* Capture tmux session output once, keeping both spellings (Issue #2522).
|
|
332
|
-
*
|
|
333
|
-
* @internal Exported for testing purposes only.
|
|
334
|
-
* @param worktreeId - Worktree identifier
|
|
335
|
-
* @param cliToolId - CLI tool type being polled
|
|
336
|
-
* @param captureLines - Optional number of lines to capture
|
|
337
|
-
* @param instanceId - Optional agent instance ID (Issue #896; defaults to primary session)
|
|
338
|
-
* @returns The tick's raw capture and its cleaned form
|
|
339
|
-
*/
|
|
340
|
-
async function capturePollerFrame(worktreeId, cliToolId, captureLines, instanceId) {
|
|
341
|
-
const lines = captureLines ?? auto_yes_config_1.FULL_CAPTURE_LINES;
|
|
342
|
-
const output = await (0, cli_session_1.captureSessionOutput)(worktreeId, cliToolId, lines, instanceId);
|
|
343
|
-
return { raw: output, clean: (0, cli_patterns_1.stripBoxDrawing)((0, cli_patterns_1.stripAnsi)(output)) };
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Capture tmux session output and strip ANSI escape codes.
|
|
347
|
-
*
|
|
348
|
-
* Kept as the cleaned half of {@link capturePollerFrame} so the many callers and
|
|
349
|
-
* tests that only ever wanted that string are untouched; `pollAutoYes` takes the
|
|
350
|
-
* pair. `stripBoxDrawing` still runs exactly once per capture either way.
|
|
351
|
-
*
|
|
352
|
-
* @internal Exported for testing purposes only.
|
|
353
|
-
* @param worktreeId - Worktree identifier
|
|
354
|
-
* @param cliToolId - CLI tool type being polled
|
|
355
|
-
* @param captureLines - Optional number of lines to capture
|
|
356
|
-
* @param instanceId - Optional agent instance ID (Issue #896; defaults to primary session)
|
|
357
|
-
* @returns Cleaned output string (ANSI stripped)
|
|
358
|
-
*/
|
|
359
|
-
async function captureAndCleanOutput(worktreeId, cliToolId, captureLines, instanceId) {
|
|
360
|
-
return (await capturePollerFrame(worktreeId, cliToolId, captureLines, instanceId)).clean;
|
|
361
|
-
}
|
|
362
218
|
/**
|
|
363
219
|
* Process stop condition check using delta-based approach.
|
|
364
220
|
*
|
|
@@ -386,422 +242,6 @@ function processStopConditionDelta(compositeKey, pollerState, cleanOutput) {
|
|
|
386
242
|
}
|
|
387
243
|
return false;
|
|
388
244
|
}
|
|
389
|
-
/**
|
|
390
|
-
* Say, once a minute, that Auto-Yes left an agy dialog alone for want of a hook
|
|
391
|
-
* receipt (Issue #2857).
|
|
392
|
-
*
|
|
393
|
-
* `detectPromptOnCleanFrame` hands a frame the receipt gate (#2849) withholds
|
|
394
|
-
* back as an ordinary `isPrompt: false`, so the poller cannot tell "no dialog on
|
|
395
|
-
* the pane" from "a dialog agy never asked us about" by looking at the result.
|
|
396
|
-
* The gate is the ONLY thing `receiptScope` changes, so the same frame read
|
|
397
|
-
* without it answering a prompt is exactly the withheld case. That second
|
|
398
|
-
* reading is taken only after the cheap tests: no receipt for this instance in
|
|
399
|
-
* the window (with one, the gate let the frame through and a no-prompt result is
|
|
400
|
-
* a real one) and no line for it in the last minute.
|
|
401
|
-
*
|
|
402
|
-
* Why it is worth a line: a machine whose `~/.gemini/config/hooks.json` points at
|
|
403
|
-
* another server (#2622) never sends us the question, and every real dialog then
|
|
404
|
-
* waits for a human with no sign of why. The line names the file to look at.
|
|
405
|
-
*
|
|
406
|
-
* A stale receipt does not always mean that, though (Issue #3724): a dialog the
|
|
407
|
-
* contract's autoYes withheld got its receipt, the server answered `ask`, and
|
|
408
|
-
* the dialog outlived the window. When `resolveAutoAnswerWithPolicy` on the
|
|
409
|
-
* ungated reading suppresses the answer by contract (the base rules would have
|
|
410
|
-
* answered it), the line is `antigravity-autoyes-withheld-by-policy` instead,
|
|
411
|
-
* naming the reason, the mode and the task. Both share the limit.
|
|
412
|
-
* The response-checker's own `antigravity-dialog-no-recent-receipt` stays at
|
|
413
|
-
* debug — it prints on every tick the same pane is read again.
|
|
414
|
-
*
|
|
415
|
-
* @param compositeKey - The instance's key, for the once-a-minute limit
|
|
416
|
-
* @param readWithoutGate - The same frame read without `receiptScope`
|
|
417
|
-
*/
|
|
418
|
-
function logIfWithheldForWantOfReceipt(worktreeId, instanceId, compositeKey, readWithoutGate) {
|
|
419
|
-
// Issue #3767: the gate's own verdict for this tick's candidate. Null means it
|
|
420
|
-
// never saw one (no dialog), `ok` that it let the frame through.
|
|
421
|
-
let verdict = (0, antigravity_receipt_episodes_1.getAntigravityReceiptVerdict)(worktreeId, instanceId);
|
|
422
|
-
if (verdict?.ok)
|
|
423
|
-
return;
|
|
424
|
-
const now = Date.now();
|
|
425
|
-
const ungated = readWithoutGate();
|
|
426
|
-
if (!ungated.isPrompt || !ungated.promptData)
|
|
427
|
-
return;
|
|
428
|
-
// The gate was not consulted (the gated reading declined the frame on screen
|
|
429
|
-
// grounds alone) yet the frame reads as a prompt: judge it here.
|
|
430
|
-
verdict ??= (0, antigravity_receipt_episodes_1.judgeAntigravityPermissionReceipt)(worktreeId, instanceId, now);
|
|
431
|
-
if (verdict.ok)
|
|
432
|
-
return;
|
|
433
|
-
// Issue #3724: a contract that withholds the answer makes the server reply
|
|
434
|
-
// `ask`, so the dialog stays up past the receipt window. The cause is then the
|
|
435
|
-
// contract, not a hooks.json that points elsewhere. Judged exactly as the tick
|
|
436
|
-
// judges a prompt it can read — the base rules first, then the contract — so
|
|
437
|
-
// a prompt the base rules never answer (a checkbox, a typed option) is not
|
|
438
|
-
// blamed on the contract. Policy and task id come from one lookup.
|
|
439
|
-
const { policy, taskId } = (0, auto_yes_policy_1.getSessionAutoYesPolicyEntry)(worktreeId, 'antigravity', instanceId);
|
|
440
|
-
const resolution = (0, auto_yes_resolver_1.resolveAutoAnswerWithPolicy)(ungated.promptData, policy);
|
|
441
|
-
// Issue #3767: `answered` is the dialog the gate already let through on this
|
|
442
|
-
// receipt, still up past the window. Unless the contract withheld it, that is
|
|
443
|
-
// not a missing receipt: neither recorded nor logged, nor counted for the limit.
|
|
444
|
-
// Issue #3789: `answered` is also a dialog accepted but never sent to (the
|
|
445
|
-
// tick recorded its own reason, if any, and that record is kept). One the
|
|
446
|
-
// poller DID send keys to and still up past the grace is `outlived`, which is
|
|
447
|
-
// recorded and logged like the others, so the stop is not a silent one.
|
|
448
|
-
// Issue #3796: the reason the poller recorded for this dialog (partial-answer,
|
|
449
|
-
// the contract, …) while it could still read it inside the window was not
|
|
450
|
-
// re-stamped once the window closed — the gated reading stopped seeing the
|
|
451
|
-
// prompt — so `cmate wait` dropped it as stale a minute later with the dialog
|
|
452
|
-
// still up. Re-stamped here on every tick the dialog stays — only while it
|
|
453
|
-
// still holds under this tick's evaluation — and kept over a `no-hook-receipt`
|
|
454
|
-
// for it: it is the more exact reason.
|
|
455
|
-
const keptPartialAnswer = refreshEpisodeSuppression(worktreeId, instanceId, verdict, resolution);
|
|
456
|
-
// Issue #3796 review D: a contract that withholds the prompt now is published
|
|
457
|
-
// whatever was recorded before — none at all (the window closed before the
|
|
458
|
-
// tick could read it, or an ended contract's record was dropped and a new one
|
|
459
|
-
// withholds it again) or another reason. Without it `cmate wait` read no
|
|
460
|
-
// reason and held the prompt as one Auto-Yes was answering. Only a partial
|
|
461
|
-
// answer still on screen comes first, as it does on the tick (step 2.5).
|
|
462
|
-
if (resolution.suppressedBy && !keptPartialAnswer) {
|
|
463
|
-
(0, auto_yes_suppression_state_1.recordPolicySuppression)(worktreeId, 'antigravity', instanceId, {
|
|
464
|
-
reason: resolution.suppressedBy,
|
|
465
|
-
mode: policy?.mode ?? null,
|
|
466
|
-
promptType: ungated.promptData.type,
|
|
467
|
-
...(resolution.pattern !== undefined ? { pattern: resolution.pattern } : {}),
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
if (!resolution.suppressedBy && (verdict.cause === 'answered' || keptPartialAnswer))
|
|
471
|
-
return;
|
|
472
|
-
const lastLoggedAt = withheldNoReceiptLoggedAt.get(compositeKey);
|
|
473
|
-
const logDue = lastLoggedAt === undefined || now - lastLoggedAt >= WITHHELD_NO_RECEIPT_LOG_INTERVAL_MS;
|
|
474
|
-
if (logDue) {
|
|
475
|
-
for (const [key, loggedAt] of withheldNoReceiptLoggedAt) {
|
|
476
|
-
if (now - loggedAt >= WITHHELD_NO_RECEIPT_LOG_INTERVAL_MS)
|
|
477
|
-
withheldNoReceiptLoggedAt.delete(key);
|
|
478
|
-
}
|
|
479
|
-
withheldNoReceiptLoggedAt.set(compositeKey, now);
|
|
480
|
-
}
|
|
481
|
-
if (resolution.suppressedBy) {
|
|
482
|
-
if (!logDue)
|
|
483
|
-
return;
|
|
484
|
-
logger.info('antigravity-autoyes-withheld-by-policy', {
|
|
485
|
-
worktreeId,
|
|
486
|
-
instanceId: instanceId ?? 'antigravity',
|
|
487
|
-
reason: resolution.suppressedBy,
|
|
488
|
-
mode: policy?.mode ?? null,
|
|
489
|
-
taskId,
|
|
490
|
-
hint: '契約の autoYes が答えを止めている。契約の autoYes を確認',
|
|
491
|
-
});
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
// Issue #3767: recorded on every tick (the record's `at` follows the prompt
|
|
495
|
-
// while it stays up), logged once a minute.
|
|
496
|
-
(0, auto_yes_suppression_state_1.recordPolicySuppression)(worktreeId, 'antigravity', instanceId, {
|
|
497
|
-
reason: auto_yes_suppression_reason_1.NO_HOOK_RECEIPT_SUPPRESSION_REASON,
|
|
498
|
-
mode: null,
|
|
499
|
-
promptType: ungated.promptData.type,
|
|
500
|
-
});
|
|
501
|
-
if (!logDue)
|
|
502
|
-
return;
|
|
503
|
-
logger.info('antigravity-autoyes-withheld-no-hook-receipt', {
|
|
504
|
-
worktreeId,
|
|
505
|
-
instanceId: instanceId ?? 'antigravity',
|
|
506
|
-
windowMs: antigravity_permission_receipts_1.ANTIGRAVITY_PERMISSION_RECEIPT_WINDOW_MS,
|
|
507
|
-
hint: noHookReceiptHint(verdict, now),
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Issue #3796: keep the suppression the poller recorded during this dialog's
|
|
512
|
-
* episode current while the dialog it accepted (`answered` / `outlived`) is
|
|
513
|
-
* still up. Only a record made since the dialog was first read, and never the
|
|
514
|
-
* receipt gate's own `no-hook-receipt` (the caller records that itself). A
|
|
515
|
-
* record is kept only while its reason still holds NOW:
|
|
516
|
-
*
|
|
517
|
-
* - `partial-answer` remembers an event: it holds for as long as the dialog
|
|
518
|
-
* the keys went to stays up (this episode), and is re-stamped here;
|
|
519
|
-
* - a contract reason is the contract's verdict on the prompt, re-evaluated on
|
|
520
|
-
* every tick (`resolution`): no verdict (the contract ended, or now answers
|
|
521
|
-
* it) drops the record — the dialog is then `answered` / `outlived` like any
|
|
522
|
-
* other. A verdict is recorded by the caller (review D), whatever was here;
|
|
523
|
-
* - any other reason is left as it was recorded.
|
|
524
|
-
*
|
|
525
|
-
* @returns true when a `partial-answer` that still holds was re-stamped
|
|
526
|
-
*/
|
|
527
|
-
function refreshEpisodeSuppression(worktreeId, instanceId, verdict, resolution) {
|
|
528
|
-
if (verdict.cause !== 'answered' && verdict.cause !== 'outlived')
|
|
529
|
-
return false;
|
|
530
|
-
const own = (0, auto_yes_suppression_state_1.getLastPolicySuppression)(worktreeId, 'antigravity', instanceId);
|
|
531
|
-
if (own === null || own.reason === auto_yes_suppression_reason_1.NO_HOOK_RECEIPT_SUPPRESSION_REASON || !(own.at >= verdict.firstSeenAt)) {
|
|
532
|
-
return false;
|
|
533
|
-
}
|
|
534
|
-
if (own.reason === auto_yes_suppression_reason_1.PARTIAL_ANSWER_SUPPRESSION_REASON) {
|
|
535
|
-
// The memory is the episode's: the dialog the keys went to is still the one
|
|
536
|
-
// up (same episode, accepted on the same receipt). Not `getPartialAnswer`:
|
|
537
|
-
// the tick forgets it as soon as the gated reading stops seeing the prompt,
|
|
538
|
-
// which past the window is every tick.
|
|
539
|
-
const { at: _recordedAt, ...suppression } = own;
|
|
540
|
-
(0, auto_yes_suppression_state_1.recordPolicySuppression)(worktreeId, 'antigravity', instanceId, suppression);
|
|
541
|
-
return true;
|
|
542
|
-
}
|
|
543
|
-
if (auto_yes_suppression_reason_1.CONTRACT_SUPPRESSION_REASONS.has(own.reason) && !resolution.suppressedBy) {
|
|
544
|
-
(0, auto_yes_suppression_state_1.forgetPolicySuppression)(worktreeId, 'antigravity', instanceId);
|
|
545
|
-
}
|
|
546
|
-
return false;
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* Issue #3789: keys for an agy dialog the receipt gate accepted reached tmux.
|
|
550
|
-
* Only here does the gate start the grace after which a dialog still up is
|
|
551
|
-
* reported as `outlived`; the tick's `no_answer` exits (another server's session,
|
|
552
|
-
* a partial answer, the base rules or the contract not answering) never get
|
|
553
|
-
* here, so their own records are not overwritten by `no-hook-receipt`.
|
|
554
|
-
*
|
|
555
|
-
* Issue #3796: `interrupted` — the send began and was cut short (stopped
|
|
556
|
-
* part-way, or failed). Its keys may be on the pane and the receipt is spent,
|
|
557
|
-
* so the grace starts here too; without it the dialog stayed `answered`, and
|
|
558
|
-
* silent, for as long as it stayed up.
|
|
559
|
-
*/
|
|
560
|
-
function noteAnswerSent(cliToolId, worktreeId, instanceId, interrupted = false, forReceiptAt) {
|
|
561
|
-
if (cliToolId !== 'antigravity')
|
|
562
|
-
return;
|
|
563
|
-
(0, antigravity_receipt_episodes_1.markAntigravityAnswerSent)(worktreeId, instanceId, Date.now(), {
|
|
564
|
-
interrupted,
|
|
565
|
-
...(forReceiptAt !== undefined ? { forReceiptAt } : {}),
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
/**
|
|
569
|
-
* Issue #3796 review: the agy episode a send is about to go to, read before
|
|
570
|
-
* its first await; null for other tools. Given back to {@link noteAnswerSent}
|
|
571
|
-
* however the send came back — whole, failed or cut short (review E) — so that
|
|
572
|
-
* only that episode is marked — the same
|
|
573
|
-
* idea as the Enter record's generation check in `tryEnterFallback`.
|
|
574
|
-
*/
|
|
575
|
-
function receiptEpisodeOfSend(cliToolId, worktreeId, instanceId) {
|
|
576
|
-
return cliToolId === 'antigravity' ? (0, antigravity_receipt_episodes_1.getAntigravityAcceptedReceiptAt)(worktreeId, instanceId) : null;
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* The hint for `antigravity-autoyes-withheld-no-hook-receipt` (Issue #3767):
|
|
580
|
-
* which of the withheld cases it was decides where to look.
|
|
581
|
-
*/
|
|
582
|
-
function noHookReceiptHint(verdict, now = Date.now()) {
|
|
583
|
-
const seconds = verdict.ageMs === null ? null : Math.round(verdict.ageMs / 1000);
|
|
584
|
-
// `lapsed` says how long ago, so from now: the line repeats once a minute.
|
|
585
|
-
const secondsAgo = verdict.lastReceiptAt === null ? null : Math.round((now - verdict.lastReceiptAt) / 1000);
|
|
586
|
-
switch (verdict.cause) {
|
|
587
|
-
case 'never':
|
|
588
|
-
return 'hook の受信が一度も無いため Auto-Yes は答えなかった。~/.gemini/config/hooks.json の向き先(#2622)を確認';
|
|
589
|
-
case 'late':
|
|
590
|
-
return `最後の受信から ${seconds} 秒後に確認が出た(窓 ${antigravity_permission_receipts_1.ANTIGRAVITY_PERMISSION_RECEIPT_WINDOW_MS / 1000} 秒の外)ため答えなかった。人が答える(auto-yes --disable → prompt --json → respond --expect-screen)。続くなら ~/.gemini/config/hooks.json の向き先(#2622)も確認`;
|
|
591
|
-
case 'lapsed':
|
|
592
|
-
return `最後の受信は ${secondsAgo} 秒前で途絶えている(hook が届かなくなった)。hooks.json の向き先(#2622)と agy の再起動を確認`;
|
|
593
|
-
case 'predates':
|
|
594
|
-
return '確認は最後の受信より前から画面に出ていた(引用か別の確認)ため答えなかった。人が答える';
|
|
595
|
-
case 'used':
|
|
596
|
-
return '最後の受信は直前の確認に使い済み。この確認に対する受信は無いため答えなかった。人が答える';
|
|
597
|
-
case 'outlived':
|
|
598
|
-
if (verdict.answerInterrupted === true) {
|
|
599
|
-
return `Auto-Yes が最後の受信の確認へ答えを送る途中で送信が止まり(キーの一部が入力に残っている可能性がある)、${antigravity_receipt_episodes_1.ANTIGRAVITY_ANSWERED_DIALOG_GRACE_MS / 1000} 秒を過ぎても確認が画面に残っている。未使用の受信が無いため、もう一度は答えない。人が答える(auto-yes --disable → prompt --json → respond --expect-screen)`;
|
|
600
|
-
}
|
|
601
|
-
return `Auto-Yes が最後の受信の確認へキーを送ってから ${antigravity_receipt_episodes_1.ANTIGRAVITY_ANSWERED_DIALOG_GRACE_MS / 1000} 秒を過ぎても、確認が画面に残っている。キーで確認が閉じなかったか、新しい受信の無い別の確認と入れ替わった(画面からは区別できない)。未使用の受信が無いため、もう一度は答えない。人が答える(auto-yes --disable → prompt --json → respond --expect-screen)`;
|
|
602
|
-
default:
|
|
603
|
-
return 'hook の受信記録が直近に無いため Auto-Yes は答えなかった。~/.gemini/config/hooks.json の向き先(#2622)を確認';
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
/**
|
|
607
|
-
* The audit row's `answer` for the Enter (Issue #3397): not a digit, so the
|
|
608
|
-
* History reads as "Auto-Yes pressed Enter" rather than as a chosen option.
|
|
609
|
-
*/
|
|
610
|
-
exports.AUTO_YES_ENTER_FALLBACK_ANSWER = '[Enter]';
|
|
611
|
-
/**
|
|
612
|
-
* Issue #3397: is the fresh capture still the screen the Enter was decided for?
|
|
613
|
-
* Re-reads it the way one tick does — prompt reading, the same `promptFrameKey`,
|
|
614
|
-
* codex's launch dialogs and `/model` picker, the dialog gate refusing with no
|
|
615
|
-
* dialog vouched for, and `judgeEnterFallback` (input box off screen, tool
|
|
616
|
-
* alive, not thinking). The policy and the checkbox rule read `promptData`,
|
|
617
|
-
* which the equal `promptFrameKey` already pins (type, question, options).
|
|
618
|
-
*/
|
|
619
|
-
function isStillEnterFallbackScreen(prompt, fresh) {
|
|
620
|
-
const { worktreeId, cliToolId, instanceId, frameKey } = prompt;
|
|
621
|
-
const clean = (0, cli_patterns_1.stripBoxDrawing)((0, cli_patterns_1.stripAnsi)(fresh));
|
|
622
|
-
const frame = (0, frame_1.normalizeFrame)(fresh, cliToolId);
|
|
623
|
-
const detection = (0, response_checker_1.detectPromptOnCleanFrame)(clean, cliToolId, clean.split('\n'), fresh, { worktreeId, instanceId }, frame);
|
|
624
|
-
if (!detection.isPrompt || !detection.promptData)
|
|
625
|
-
return false;
|
|
626
|
-
if ((0, auto_yes_poller_state_1.promptFrameKey)(detection.promptData) !== frameKey)
|
|
627
|
-
return false;
|
|
628
|
-
if (cliToolId === 'codex' && ((0, cli_patterns_1.getCodexLifecycleDialog)(frame) || (0, detect_1.isCodexModelPickerFrame)(frame))) {
|
|
629
|
-
return false;
|
|
630
|
-
}
|
|
631
|
-
const gate = (0, auto_yes_dialog_gate_1.evaluateAutoYesDialogGate)(cliToolId, detection.promptData.type, frame);
|
|
632
|
-
if (gate.allowed || gate.dialog !== null)
|
|
633
|
-
return false;
|
|
634
|
-
return (0, auto_yes_enter_fallback_1.judgeEnterFallback)(cliToolId, fresh).eligible;
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* Issue #3397: a frame the dialog gate refused may still be a choice screen
|
|
638
|
-
* CommandMate cannot read — the one the prompt window offers direct input for.
|
|
639
|
-
* Send ONE Enter there (confirm whatever is selected), under every condition
|
|
640
|
-
* `judgeEnterFallback` and this function check; otherwise record the refusal as
|
|
641
|
-
* step 3.5 always did.
|
|
642
|
-
*
|
|
643
|
-
* Order, each one able to stop the Enter:
|
|
644
|
-
* 1. `judgeEnterFallback` (rollout table, refusal, composer off screen, tool
|
|
645
|
-
* alive, not thinking) — and the gate must not have vouched for a dialog it
|
|
646
|
-
* refused to type into (opencode's `keys` strip, #1893);
|
|
647
|
-
* 2. the screen already had its Enter: record `no-effect`, send nothing;
|
|
648
|
-
* 3. the contract policy, exactly as step 4 applies it (mode, allow-listed
|
|
649
|
-
* types, deny patterns over the question, options and `approvalTarget`);
|
|
650
|
-
* a prompt the base rules would not answer (multi-select, typed text) gets
|
|
651
|
-
* nothing either;
|
|
652
|
-
* 4. the screen must have been eligible on the previous tick as well;
|
|
653
|
-
* 5. the session must be this server's (#2865);
|
|
654
|
-
* 6. a capture taken now, past the capture cache, must still be that screen
|
|
655
|
-
* ({@link isStillEnterFallbackScreen}).
|
|
656
|
-
*
|
|
657
|
-
* Issue #3706: with a `generation` (a tick of `pollAutoYes`), the waits of
|
|
658
|
-
* steps 5 and 6 are each followed by {@link isTickCurrent}; a tick that lost
|
|
659
|
-
* its generation sends nothing and changes nothing.
|
|
660
|
-
*
|
|
661
|
-
* @returns true when the Enter was sent; the caller returns `responded`
|
|
662
|
-
*/
|
|
663
|
-
async function tryEnterFallback(prompt, promptDetection, dialogGate, rawOutput, generation) {
|
|
664
|
-
const { worktreeId, cliToolId, instanceId, pollerState, promptData, frameKey } = prompt;
|
|
665
|
-
const judgement = dialogGate.dialog === null ? (0, auto_yes_enter_fallback_1.judgeEnterFallback)(cliToolId, rawOutput) : null;
|
|
666
|
-
if (judgement === null || !judgement.eligible) {
|
|
667
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
668
|
-
(0, auto_yes_prompt_suppression_1.suppressUnclassifiedFrame)(prompt, dialogGate);
|
|
669
|
-
return false;
|
|
670
|
-
}
|
|
671
|
-
const screenKey = (0, auto_yes_enter_fallback_1.enterFallbackScreenKey)(promptData);
|
|
672
|
-
// 2. The Enter did not move the screen on. Another one would be a guess.
|
|
673
|
-
if (pollerState.enterFallbackSentKey === frameKey) {
|
|
674
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
675
|
-
(0, auto_yes_enter_fallback_1.recordEnterFallbackNoEffect)(worktreeId, cliToolId, instanceId, screenKey);
|
|
676
|
-
(0, auto_yes_prompt_suppression_1.suppressUnclassifiedFrame)(prompt, dialogGate);
|
|
677
|
-
(0, auto_yes_poller_state_1.warnOncePerFrame)(pollerState, `${frameKey}\u0000enter-fallback-no-effect`, 'poller:auto-yes-enter-fallback-no-effect', {
|
|
678
|
-
worktreeId,
|
|
679
|
-
cliToolId,
|
|
680
|
-
instanceId,
|
|
681
|
-
promptType: promptData.type,
|
|
682
|
-
refusalReason: judgement.refusalReason,
|
|
683
|
-
});
|
|
684
|
-
return false;
|
|
685
|
-
}
|
|
686
|
-
// 3. The contract policy, as step 4 reads it.
|
|
687
|
-
const policy = (0, auto_yes_policy_1.getSessionAutoYesPolicy)(worktreeId, cliToolId, instanceId);
|
|
688
|
-
const resolution = (0, auto_yes_resolver_1.resolveAutoAnswerWithPolicy)(promptData, policy);
|
|
689
|
-
if (resolution.suppressedBy) {
|
|
690
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
691
|
-
(0, auto_yes_prompt_suppression_1.suppressAndWarnOnce)(prompt, {
|
|
692
|
-
reason: resolution.suppressedBy,
|
|
693
|
-
mode: policy?.mode ?? null,
|
|
694
|
-
promptType: promptData.type,
|
|
695
|
-
pattern: resolution.pattern,
|
|
696
|
-
}, `${frameKey}\u0000${resolution.suppressedBy}\u0000${policy?.mode ?? ''}\u0000${resolution.pattern ?? ''}`, 'poller:auto-yes-suppressed-by-policy', {
|
|
697
|
-
reason: resolution.suppressedBy,
|
|
698
|
-
mode: policy?.mode ?? null,
|
|
699
|
-
pattern: resolution.pattern,
|
|
700
|
-
promptType: promptData.type,
|
|
701
|
-
enterFallback: true,
|
|
702
|
-
});
|
|
703
|
-
return false;
|
|
704
|
-
}
|
|
705
|
-
// A checkbox list is out of scope whatever the parser's flag says: the
|
|
706
|
-
// labels' boxes (`[ ]` / `[x]` / `[X]` / `[✔]`, the one reading in
|
|
707
|
-
// `prompt-answer-semantic` the sender shares) count too, so an Enter never
|
|
708
|
-
// submits a half-ticked list (Issue #3397; the base rules' #2755 reading
|
|
709
|
-
// covers `multiSelect` only).
|
|
710
|
-
if (resolution.answer === null ||
|
|
711
|
-
(promptData.type === 'multiple_choice' && (0, prompt_answer_semantic_1.isMultiSelectPrompt)(promptData))) {
|
|
712
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
713
|
-
(0, auto_yes_prompt_suppression_1.suppressUnclassifiedFrame)(prompt, dialogGate);
|
|
714
|
-
return false;
|
|
715
|
-
}
|
|
716
|
-
// 4. Seen once: wait for the next tick to see the same screen again.
|
|
717
|
-
// Nothing is recorded as withheld here: Auto-Yes is about to answer, and a
|
|
718
|
-
// fresh `lastSuppression` would make `cmate wait` report the prompt to a
|
|
719
|
-
// human at once instead of holding for Auto-Yes (#2463).
|
|
720
|
-
if (pollerState.enterFallbackCandidateKey !== frameKey) {
|
|
721
|
-
pollerState.enterFallbackCandidateKey = frameKey;
|
|
722
|
-
logger.debug('poller:auto-yes-enter-fallback-candidate', {
|
|
723
|
-
worktreeId,
|
|
724
|
-
cliToolId,
|
|
725
|
-
instanceId,
|
|
726
|
-
promptType: promptData.type,
|
|
727
|
-
});
|
|
728
|
-
return false;
|
|
729
|
-
}
|
|
730
|
-
// 5. Never another server's session (Issue #2865).
|
|
731
|
-
const sessionName = manager_1.CLIToolManager.getInstance().getTool(cliToolId).getSessionName(worktreeId, instanceId);
|
|
732
|
-
const ownership = await (0, worktree_session_ownership_1.checkWorktreeSessionOwnership)(worktreeId, sessionName);
|
|
733
|
-
if (generation !== undefined && !isTickCurrent(generation))
|
|
734
|
-
return false;
|
|
735
|
-
if (ownership === null || ownership.verdict === 'foreign') {
|
|
736
|
-
(0, auto_yes_poller_state_1.warnOncePerFrame)(pollerState, `${frameKey}\u0000${sessionName}\u0000${ownership ? 'foreign' : 'worktree_not_found'}`, 'poller:auto-yes-skipped-foreign-session', {
|
|
737
|
-
worktreeId,
|
|
738
|
-
cliToolId,
|
|
739
|
-
instanceId,
|
|
740
|
-
sessionName,
|
|
741
|
-
sessionPath: ownership?.sessionPath ?? null,
|
|
742
|
-
reason: ownership ? 'foreign' : 'worktree_not_found',
|
|
743
|
-
enterFallback: true,
|
|
744
|
-
});
|
|
745
|
-
return false;
|
|
746
|
-
}
|
|
747
|
-
// 6. The last look before the key, at a capture taken NOW. The two ticks of
|
|
748
|
-
// step 4 read through the capture cache, whose TTL is longer than the poll
|
|
749
|
-
// interval, so "seen twice" can be one stale frame read twice: a redraw caught
|
|
750
|
-
// with its input box missing (#2457's repaint) while the real pane already
|
|
751
|
-
// has the box back. Everything that decided the Enter is judged again on the
|
|
752
|
-
// fresh frame; any difference sends nothing, and the next tick starts over.
|
|
753
|
-
const fresh = await (0, cli_session_1.captureSessionOutputFresh)(worktreeId, cliToolId, (rawOutput ?? '').split('\n').length, instanceId);
|
|
754
|
-
if (generation !== undefined && !isTickCurrent(generation))
|
|
755
|
-
return false;
|
|
756
|
-
if (!isStillEnterFallbackScreen(prompt, fresh)) {
|
|
757
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
758
|
-
logger.debug('poller:auto-yes-enter-fallback-fresh-frame-differs', {
|
|
759
|
-
worktreeId,
|
|
760
|
-
cliToolId,
|
|
761
|
-
instanceId,
|
|
762
|
-
promptType: promptData.type,
|
|
763
|
-
});
|
|
764
|
-
return false;
|
|
765
|
-
}
|
|
766
|
-
const receiptEpisode = receiptEpisodeOfSend(cliToolId, worktreeId, instanceId);
|
|
767
|
-
try {
|
|
768
|
-
await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
|
|
769
|
-
}
|
|
770
|
-
catch (error) {
|
|
771
|
-
// Issue #3796: the Enter may or may not have reached the pane.
|
|
772
|
-
noteAnswerSent(cliToolId, worktreeId, instanceId, true, receiptEpisode);
|
|
773
|
-
throw error;
|
|
774
|
-
}
|
|
775
|
-
finally {
|
|
776
|
-
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
777
|
-
}
|
|
778
|
-
// Issue #3796 review E: the Enter is out — for the episode it began for only.
|
|
779
|
-
noteAnswerSent(cliToolId, worktreeId, instanceId, false, receiptEpisode);
|
|
780
|
-
// Issue #3706: the Enter is out, but the per-screen record is the CURRENT
|
|
781
|
-
// session's: when the poller was stopped (the record was forgotten with it)
|
|
782
|
-
// or a new session began while `send-keys` was awaited, the return of this
|
|
783
|
-
// send must not put the record back. The audit row below is kept either way.
|
|
784
|
-
if (generation === undefined || (isPollerCurrent(generation) && isSameSession(generation))) {
|
|
785
|
-
pollerState.enterFallbackSentKey = frameKey;
|
|
786
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
787
|
-
(0, auto_yes_enter_fallback_1.recordEnterFallbackSent)(worktreeId, cliToolId, instanceId, {
|
|
788
|
-
promptType: promptData.type,
|
|
789
|
-
refusalReason: judgement.refusalReason,
|
|
790
|
-
screenKey,
|
|
791
|
-
...(generation !== undefined ? { epoch: generation.sessionEpoch } : {}),
|
|
792
|
-
});
|
|
793
|
-
}
|
|
794
|
-
logger.info('poller:auto-yes-enter-fallback-sent', {
|
|
795
|
-
worktreeId,
|
|
796
|
-
cliToolId,
|
|
797
|
-
instanceId,
|
|
798
|
-
promptType: promptData.type,
|
|
799
|
-
refusalReason: judgement.refusalReason,
|
|
800
|
-
composerState: judgement.composerState,
|
|
801
|
-
});
|
|
802
|
-
await finishAnsweredPrompt(prompt, promptDetection, exports.AUTO_YES_ENTER_FALLBACK_ANSWER, generation);
|
|
803
|
-
return true;
|
|
804
|
-
}
|
|
805
245
|
/**
|
|
806
246
|
* Issue #3214: steps 6 and 7 of `detectAndRespondToPrompt` and everything after
|
|
807
247
|
* them -- what is done once the answer has reached tmux, in the order it always
|
|
@@ -817,8 +257,11 @@ async function tryEnterFallback(prompt, promptDetection, dialogGate, rawOutput,
|
|
|
817
257
|
* tick's own poller state only, never to a successor under the same key, and
|
|
818
258
|
* the response poller restart and the terminal push are skipped when the
|
|
819
259
|
* session was relaunched meanwhile.
|
|
260
|
+
* @param capture - Issue #3881 (review P2-2): the tick's frame and its capture
|
|
261
|
+
* window, so an audit row this answer creates carries the same reading the
|
|
262
|
+
* response poller's save gives a row (`promptDataForStorage`)
|
|
820
263
|
*/
|
|
821
|
-
async function finishAnsweredPrompt(prompt, promptDetection, answer, generation) {
|
|
264
|
+
async function finishAnsweredPrompt(prompt, promptDetection, answer, generation, capture) {
|
|
822
265
|
const { worktreeId, cliToolId, instanceId, compositeKey, pollerState, promptData, promptKey } = prompt;
|
|
823
266
|
// Issue #3706: the keys went to the session the tick started on. When a new
|
|
824
267
|
// one was begun while they were being sent, the new process never received
|
|
@@ -827,11 +270,11 @@ async function finishAnsweredPrompt(prompt, promptDetection, answer, generation)
|
|
|
827
270
|
// process's identical question), not the poller's response time, not the
|
|
828
271
|
// task event (the task looked up now may be the new session's). Only the
|
|
829
272
|
// audit row is, and it may not adopt a pending row saved after the tick began.
|
|
830
|
-
const sameSession = generation === undefined || isSameSession(generation);
|
|
273
|
+
const sameSession = generation === undefined || (0, auto_yes_poller_generation_1.isSameSession)(generation);
|
|
831
274
|
if (sameSession) {
|
|
832
275
|
// 6. Update timestamp and reset error count
|
|
833
|
-
updateLastServerResponseTimestamp(compositeKey, Date.now(), generation?.pollerState);
|
|
834
|
-
resetErrorCount(compositeKey, generation?.pollerState);
|
|
276
|
+
(0, auto_yes_poller_generation_1.updateLastServerResponseTimestamp)(compositeKey, Date.now(), generation?.pollerState);
|
|
277
|
+
(0, auto_yes_poller_generation_1.resetErrorCount)(compositeKey, generation?.pollerState);
|
|
835
278
|
// 7. Record answered prompt key and timestamp
|
|
836
279
|
pollerState.lastAnsweredPromptKey = promptKey;
|
|
837
280
|
pollerState.lastAnsweredAt = Date.now();
|
|
@@ -839,7 +282,7 @@ async function finishAnsweredPrompt(prompt, promptDetection, answer, generation)
|
|
|
839
282
|
}
|
|
840
283
|
// Issue #3748: what was answered and with what — the question (cut to
|
|
841
284
|
// MAX_LOGGED_QUESTION_LENGTH, never the full text) and the answer sent (the
|
|
842
|
-
// option number
|
|
285
|
+
// option number or `y`) — so an answer that should not have been
|
|
843
286
|
// given can be told from the log alone.
|
|
844
287
|
logger.info('poller:response-sent', {
|
|
845
288
|
worktreeId,
|
|
@@ -869,7 +312,10 @@ async function finishAnsweredPrompt(prompt, promptDetection, answer, generation)
|
|
|
869
312
|
worktreeId,
|
|
870
313
|
cliToolId,
|
|
871
314
|
instanceId: instanceId ?? cliToolId,
|
|
872
|
-
|
|
315
|
+
// Issue #3881 (review P2-2): with the reading of the frame it answered,
|
|
316
|
+
// so a row this creates is classified as the response poller's row for
|
|
317
|
+
// the same screen would be — not by whichever of the two wrote first.
|
|
318
|
+
promptData: auditPromptData(cliToolId, promptDetection, promptData, capture),
|
|
873
319
|
answer,
|
|
874
320
|
answeredBy: 'auto',
|
|
875
321
|
content: promptDetection.rawContent || promptDetection.cleanContent,
|
|
@@ -906,11 +352,67 @@ async function finishAnsweredPrompt(prompt, promptDetection, answer, generation)
|
|
|
906
352
|
]);
|
|
907
353
|
// Re-read after the await, not the `sameSession` taken before the audit: a
|
|
908
354
|
// relaunch while the modules loaded makes the restart about the new process.
|
|
909
|
-
if (!sameSession || (generation !== undefined && !isSameSession(generation)))
|
|
355
|
+
if (!sameSession || (generation !== undefined && !(0, auto_yes_poller_generation_1.isSameSession)(generation)))
|
|
910
356
|
return;
|
|
911
357
|
startResponsePolling(worktreeId, cliToolId, instanceId);
|
|
912
358
|
void broadcastTerminalSnapshotAfterInteraction(worktreeId, cliToolId, instanceId);
|
|
913
359
|
}
|
|
360
|
+
/**
|
|
361
|
+
* The `promptData` an Auto-Yes audit row is recorded with (Issue #3881 review
|
|
362
|
+
* P2-2): the answered prompt with `promptDataForStorage`'s reading of the
|
|
363
|
+
* tick's frame. A pending row the response poller saved keeps its own reading
|
|
364
|
+
* (`recordAnsweredPrompt` spreads it); this is what a row created here, or one
|
|
365
|
+
* saved without a reading, gets.
|
|
366
|
+
*/
|
|
367
|
+
function auditPromptData(cliToolId, promptDetection, promptData, capture) {
|
|
368
|
+
return ((0, prompt_screen_reading_1.promptDataForStorage)(cliToolId, capture?.frame ?? null, { ...promptDetection, promptData }, capture?.captureTop)
|
|
369
|
+
?? promptData);
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* The `catch` of `detectAndRespondToPrompt`: settles the send in flight and
|
|
373
|
+
* tells an abandoned tick from a failed one.
|
|
374
|
+
*/
|
|
375
|
+
function settleFailedTick(error, tick) {
|
|
376
|
+
const { worktreeId, cliToolId, instanceId, compositeKey, generation, attempt, sendInFlight, receiptEpisode } = tick;
|
|
377
|
+
const keysSent = error instanceof Error && 'keysSent' in error ? Boolean(error.keysSent) : null;
|
|
378
|
+
// Issue #3880: a tmux call that ended without an exit status may have left
|
|
379
|
+
// the answer on the pane though no key is known to be there (`keysSent` is
|
|
380
|
+
// not true, and the ledger counts it `failed`). Held as a partial answer is:
|
|
381
|
+
// the next tick does not send it again at the same confirmation (step 2.5).
|
|
382
|
+
// Read off the error like `keysSent` (`AnswerDelivery` in prompt-answer-sender).
|
|
383
|
+
const delivery = error instanceof Error && 'answerDelivery' in error ? error.answerDelivery : null;
|
|
384
|
+
const mayBeOnPane = keysSent === true || delivery === 'indeterminate';
|
|
385
|
+
// Issue #3820: the send that was cut short, in the ledger — before the send
|
|
386
|
+
// record below is settled, whose state says whether it had expired.
|
|
387
|
+
if (attempt !== null && sendInFlight) {
|
|
388
|
+
(0, auto_yes_confirmation_ledger_1.settleLedgerAttempt)(attempt.ledger, (0, auto_yes_poller_tick_1.attemptResultOfThrow)(keysSent), { expired: attempt.state === 'expired' });
|
|
389
|
+
}
|
|
390
|
+
// Issue #3706: a tick that lost its generation — the send stopped part-way
|
|
391
|
+
// (`PromptAnswerAbortedError`), or failed after the grant went — is not a
|
|
392
|
+
// failure of the poller that now holds the key, and not an answer either.
|
|
393
|
+
if (generation !== undefined && !(0, auto_yes_poller_generation_1.isTickCurrent)(generation)) {
|
|
394
|
+
// A stop with keys already on the pane: the next tick must not type the
|
|
395
|
+
// answer again over them (step 2.5). Recorded under the attempt's key as
|
|
396
|
+
// it is now — the new one when a worktree ID move carried it (#3713).
|
|
397
|
+
if (attempt !== null)
|
|
398
|
+
(0, auto_yes_poller_state_1.settleSendAttempt)(attempt, mayBeOnPane);
|
|
399
|
+
if (sendInFlight)
|
|
400
|
+
(0, auto_yes_poller_receipt_log_1.noteAnswerSent)(cliToolId, worktreeId, instanceId, true, receiptEpisode);
|
|
401
|
+
logger.info('poller:auto-yes-answer-abandoned', { worktreeId, cliToolId, instanceId, keysSent, delivery });
|
|
402
|
+
return 'no_answer';
|
|
403
|
+
}
|
|
404
|
+
// Issue #3839: a failure with keys already on the pane is held the same way —
|
|
405
|
+
// the next tick must not type the answer again over them (step 2.5); the
|
|
406
|
+
// screen leaving or changing forgets it (`forgetPartialAnswer`). Issue #3880:
|
|
407
|
+
// so is a send whose outcome is not known (`mayBeOnPane` above).
|
|
408
|
+
if (attempt !== null)
|
|
409
|
+
(0, auto_yes_poller_state_1.settleSendAttempt)(attempt, mayBeOnPane);
|
|
410
|
+
if (sendInFlight)
|
|
411
|
+
(0, auto_yes_poller_receipt_log_1.noteAnswerSent)(cliToolId, worktreeId, instanceId, true, receiptEpisode);
|
|
412
|
+
incrementErrorCount(compositeKey, generation?.pollerState);
|
|
413
|
+
logger.warn('poller:detect-respond-error', { worktreeId, cliToolId, instanceId, delivery });
|
|
414
|
+
return 'error';
|
|
415
|
+
}
|
|
914
416
|
/**
|
|
915
417
|
* Detect prompt in terminal output, resolve auto-answer, and send response.
|
|
916
418
|
*
|
|
@@ -925,14 +427,33 @@ async function finishAnsweredPrompt(prompt, promptDetection, answer, generation)
|
|
|
925
427
|
* (Issue #2522). Omitting it costs Command Code's `AskUserQuestion` and
|
|
926
428
|
* nothing else; see {@link capturePollerFrame}.
|
|
927
429
|
* @param generation - The calling tick's generation (Issue #3706). Given, every
|
|
928
|
-
* wait before a key — the ownership check
|
|
929
|
-
*
|
|
430
|
+
* wait before a key — the ownership check and each wait inside the send — is
|
|
431
|
+
* followed by {@link isTickCurrent}, and a tick
|
|
930
432
|
* that lost it types nothing more and returns `no_answer`. Omitted (direct
|
|
931
433
|
* callers, tests), nothing is checked, as before.
|
|
434
|
+
* @param observation - Issue #3798: the tick's waiting-episode start, fixed
|
|
435
|
+
* before its capture, and when that capture's frame was fetched. The answer
|
|
436
|
+
* is observed against them ({@link observeAnsweredPrompt}). Omitted (direct
|
|
437
|
+
* callers, tests), the start is fixed here and the frame dated 0.
|
|
438
|
+
* @param captureWindowLines - Issue #3881 (review P2-1): the window the
|
|
439
|
+
* capture was taken with. Given, a capture that filled it is read as
|
|
440
|
+
* possibly cut at its top: an approval target that reached that top is
|
|
441
|
+
* `top-unknown`, and a deny miss on it is not a pass. Omitted (direct
|
|
442
|
+
* callers, tests), nothing is known about the capture's extent, as before.
|
|
443
|
+
* The same window says where the audit row's frame begins (`captureTop`).
|
|
444
|
+
* @param captureHeadCut - Issue #3881 (third review N4): whether that window
|
|
445
|
+
* dropped rows from the top of what tmux returned, as the capture layer said
|
|
446
|
+
* ({@link capturePollerFrame}'s `headCut`). At a window of the pane's height
|
|
447
|
+
* the row count cannot tell. Omitted, judged from the row count as before.
|
|
932
448
|
* @returns 'responded' | 'no_prompt' | 'duplicate' | 'no_answer' | 'error'
|
|
933
449
|
*/
|
|
934
|
-
async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, cleanOutput, precomputedLines, instanceId, rawOutput, generation) {
|
|
450
|
+
async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, cleanOutput, precomputedLines, instanceId, rawOutput, generation, observation, captureWindowLines, captureHeadCut) {
|
|
935
451
|
const compositeKey = (0, auto_yes_state_1.buildCompositeKey)(worktreeId, cliToolId, instanceId);
|
|
452
|
+
const captureExtent = captureWindowLines === undefined ? undefined : { windowLines: captureWindowLines, headCut: captureHeadCut };
|
|
453
|
+
const tickObservation = observation ?? {
|
|
454
|
+
start: (0, waiting_episode_binding_1.startWaitingObservation)(worktreeId, cliToolId, instanceId),
|
|
455
|
+
frameTime: { frameCapturedAt: 0, frameFetchedAfterStart: false },
|
|
456
|
+
};
|
|
936
457
|
// Issue #3706 / #3713: the send in flight, settled without an await once it
|
|
937
458
|
// comes back — as a partial answer when it was stopped with keys on the pane.
|
|
938
459
|
let attempt = null;
|
|
@@ -940,6 +461,21 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
940
461
|
// the send short, and the agy receipt gate is told so (`noteAnswerSent`).
|
|
941
462
|
let sendInFlight = false;
|
|
942
463
|
let receiptEpisode = null;
|
|
464
|
+
// Issue #3820: the ledger's tick. A tick that read the screen and saw no
|
|
465
|
+
// confirmation closes the open one as gone when it ends (`endLedgerTick`).
|
|
466
|
+
// Issue #3863: the answer mode this tick acts under, recorded on its ledger lines.
|
|
467
|
+
const answerMode = (0, auto_yes_poller_steps_1.answerModeOfTick)(worktreeId, cliToolId, instanceId, generation?.grant);
|
|
468
|
+
const ledgerScope = { compositeKey, worktreeId, cliToolId, instanceId, answerMode };
|
|
469
|
+
const ledgerTick = (0, auto_yes_confirmation_ledger_1.beginLedgerTick)(ledgerScope);
|
|
470
|
+
// Issue #3821: when this tick began, for the decision's reason (see `tickDecisionRecorder`).
|
|
471
|
+
const tickStartedAt = Date.now();
|
|
472
|
+
// Issue #3791 (review N1 / N3): the duplicate guard's reservation outlives
|
|
473
|
+
// this tick only when the guard holds the prompt back again. It stays up
|
|
474
|
+
// while the tick goes on to send the retry of the reserved prompt (an answer
|
|
475
|
+
// still on its way), and is released before any await for another screen,
|
|
476
|
+
// and in `finally` for everything else — withheld, failed, stopped, or
|
|
477
|
+
// answered (the new answer restarts the hold).
|
|
478
|
+
let keepDuplicateRetry = false;
|
|
943
479
|
try {
|
|
944
480
|
// 1. Detect prompt.
|
|
945
481
|
//
|
|
@@ -980,54 +516,85 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
980
516
|
// machine whose hook does not reach us. The price is that Auto-Yes leaves
|
|
981
517
|
// such a machine's dialogs alone, which is why `logIfWithheldForWantOfReceipt`
|
|
982
518
|
// says so.
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
const epoch = (0, auto_yes_enter_fallback_1.getEnterFallbackSessionEpoch)(compositeKey);
|
|
986
|
-
if ((pollerState.enterFallbackEpoch ?? 0) !== epoch) {
|
|
987
|
-
pollerState.enterFallbackSentKey = null;
|
|
988
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
989
|
-
pollerState.enterFallbackEpoch = epoch;
|
|
990
|
-
}
|
|
991
|
-
const receiptScope = { worktreeId, instanceId };
|
|
992
|
-
// Issue #3183: the ONE frame every judgement below reads — normalised once,
|
|
993
|
-
// from the capture as captured (the input-box markers are rule rows the
|
|
994
|
-
// cleaned spelling has blanked), and handed as the same object to the
|
|
995
|
-
// prompt reading, the codex launch guards and the dialog gate. That is what
|
|
996
|
-
// makes "the status chain and Auto-Yes read the same live region" a fact
|
|
997
|
-
// rather than a hope: there is no second normalisation to disagree with.
|
|
998
|
-
const frame = (0, frame_1.normalizeFrame)(rawOutput ?? cleanOutput, cliToolId);
|
|
999
|
-
// Issue #3767: bracket the read so the receipt gate can tell when an agy
|
|
1000
|
-
// dialog first appeared, not only what time this tick is.
|
|
1001
|
-
if (cliToolId === 'antigravity')
|
|
1002
|
-
(0, antigravity_receipt_episodes_1.beginAntigravityFrameRead)(worktreeId, instanceId);
|
|
1003
|
-
const promptDetection = (0, response_checker_1.detectPromptOnCleanFrame)(cleanOutput, cliToolId, precomputedLines, rawOutput, receiptScope, frame);
|
|
1004
|
-
if (cliToolId === 'antigravity')
|
|
1005
|
-
(0, antigravity_receipt_episodes_1.endAntigravityFrameRead)(worktreeId, instanceId);
|
|
519
|
+
const epoch = (0, auto_yes_poller_enter_fallback_1.syncEnterFallbackEpoch)(compositeKey, pollerState);
|
|
520
|
+
const { frame, promptDetection } = (0, auto_yes_poller_tick_1.readPromptFrame)(worktreeId, cliToolId, cleanOutput, precomputedLines, instanceId, rawOutput, captureExtent, response_checker_1.detectPromptOnCleanFrame);
|
|
1006
521
|
if (!promptDetection.isPrompt || !promptDetection.promptData) {
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
522
|
+
// Issue #3821: no prompt, no decision — except agy's dialog the receipt
|
|
523
|
+
// gate keeps from this reading while the status API still shows it.
|
|
524
|
+
(0, auto_yes_decision_state_1.forgetAutoYesDecision)(compositeKey);
|
|
525
|
+
const withheldPastGate = (0, auto_yes_poller_tick_1.noteNoPromptOnScreen)({
|
|
526
|
+
worktreeId,
|
|
527
|
+
cliToolId,
|
|
528
|
+
instanceId,
|
|
529
|
+
compositeKey,
|
|
530
|
+
epoch,
|
|
531
|
+
pollerState,
|
|
532
|
+
frame,
|
|
533
|
+
promptDetection,
|
|
534
|
+
cleanOutput,
|
|
535
|
+
precomputedLines,
|
|
536
|
+
rawOutput,
|
|
537
|
+
captureExtent,
|
|
538
|
+
detectPromptOnCleanFrame: response_checker_1.detectPromptOnCleanFrame,
|
|
539
|
+
});
|
|
540
|
+
if (withheldPastGate !== null && withheldPastGate.reason !== null) {
|
|
541
|
+
(0, auto_yes_poller_tick_1.tickDecisionRecorder)({
|
|
542
|
+
worktreeId,
|
|
543
|
+
cliToolId,
|
|
544
|
+
instanceId,
|
|
545
|
+
compositeKey,
|
|
546
|
+
promptData: withheldPastGate.promptData,
|
|
547
|
+
epoch,
|
|
548
|
+
generation,
|
|
549
|
+
startedAt: tickStartedAt,
|
|
550
|
+
}).withheld(withheldPastGate.reason);
|
|
1022
551
|
}
|
|
1023
552
|
return 'no_prompt';
|
|
1024
553
|
}
|
|
554
|
+
// Issue #3820: computed here, before the duplicate check, so the ledger
|
|
555
|
+
// sees the confirmation on every tick it is on screen (step 2.5 below
|
|
556
|
+
// reads the same key).
|
|
557
|
+
// The ledger's own key keeps the body (`ledgerScreenKey`): two commands
|
|
558
|
+
// that differ by a `>` or an indent are two confirmations to count.
|
|
559
|
+
const screenKey = (0, auto_yes_poller_state_1.partialAnswerScreenKey)(promptDetection.promptData);
|
|
560
|
+
// agy (PR 3): tied to the call the receipt that let it through asked about.
|
|
561
|
+
(0, auto_yes_confirmation_ledger_1.observeLedgerScreen)(ledgerScope, (0, auto_yes_poller_state_1.ledgerScreenKey)(promptDetection.promptData), promptDetection.promptData.type, (0, auto_yes_poller_tick_1.ledgerCallOf)(cliToolId, worktreeId, instanceId));
|
|
562
|
+
// Issue #3821: what this tick decides about the prompt, for `current-output`.
|
|
563
|
+
const decision = (0, auto_yes_poller_tick_1.tickDecisionRecorder)({
|
|
564
|
+
worktreeId,
|
|
565
|
+
cliToolId,
|
|
566
|
+
instanceId,
|
|
567
|
+
compositeKey,
|
|
568
|
+
promptData: promptDetection.promptData,
|
|
569
|
+
epoch,
|
|
570
|
+
generation,
|
|
571
|
+
startedAt: tickStartedAt,
|
|
572
|
+
});
|
|
573
|
+
// 1.5. Issue #3821 (review 2): a person began answering on this instance
|
|
574
|
+
// moments ago. What is on screen may be the very confirmation they are
|
|
575
|
+
// answering, so it is theirs until the hold passes; Auto-Yes stays on.
|
|
576
|
+
if ((0, auto_yes_manual_answer_1.isManualAnswerHolding)(compositeKey)) {
|
|
577
|
+
decision.withheld(auto_yes_manual_answer_1.ANSWERED_BY_HUMAN_DECISION_REASON);
|
|
578
|
+
return 'no_answer';
|
|
579
|
+
}
|
|
1025
580
|
// 2. Check for duplicate prompt (Issue #306)
|
|
1026
581
|
const promptKey = (0, prompt_key_1.generatePromptKey)(promptDetection.promptData);
|
|
1027
582
|
const frameKey = (0, auto_yes_poller_state_1.promptFrameKey)(promptDetection.promptData);
|
|
1028
|
-
if (isDuplicatePrompt(pollerState, promptKey)) {
|
|
583
|
+
if ((0, auto_yes_poller_generation_1.isDuplicatePrompt)(pollerState, promptKey)) {
|
|
584
|
+
// Issue #3791 (review N1): the push gate holds this wait until the retry.
|
|
585
|
+
(0, auto_yes_poller_generation_1.reserveDuplicateRetry)(pollerState, promptKey, tickStartedAt);
|
|
586
|
+
keepDuplicateRetry = true;
|
|
587
|
+
// Issue #3820: not answered on this tick either — an interval of its own
|
|
588
|
+
// reason, so the count can tell the wait for an answer to land apart.
|
|
589
|
+
(0, auto_yes_confirmation_ledger_1.withholdLedgerConfirmation)(ledgerScope, 'answered-recently');
|
|
590
|
+
// Issue #3821: still `answering` only if this is the confirmation the send was for.
|
|
591
|
+
decision.reaffirmAnswering();
|
|
1029
592
|
return 'duplicate';
|
|
1030
593
|
}
|
|
594
|
+
// Issue #3791 (review N3): another screen than the reserved one — released
|
|
595
|
+
// now, before the awaits below, so the gate never reads it for this screen.
|
|
596
|
+
if (!(0, auto_yes_poller_generation_1.isDuplicateRetryOf)(pollerState, promptKey))
|
|
597
|
+
(0, auto_yes_poller_generation_1.releaseDuplicateRetry)(pollerState);
|
|
1031
598
|
const judged = {
|
|
1032
599
|
worktreeId,
|
|
1033
600
|
cliToolId,
|
|
@@ -1037,6 +604,11 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
1037
604
|
promptData: promptDetection.promptData,
|
|
1038
605
|
promptKey,
|
|
1039
606
|
frameKey,
|
|
607
|
+
// Issue #3863: for the `recommended` answer mode's choice among a question's options.
|
|
608
|
+
...(promptDetection.optionRecommendations !== undefined
|
|
609
|
+
? { optionRecommendations: promptDetection.optionRecommendations }
|
|
610
|
+
: {}),
|
|
611
|
+
answerMode,
|
|
1040
612
|
};
|
|
1041
613
|
// 2.5. Issue #3706: an earlier answer to this prompt was stopped after some
|
|
1042
614
|
// of its keys reached the pane (a `y` whose Enter was withheld). Typing the
|
|
@@ -1046,72 +618,45 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
1046
618
|
// (`partialAnswerScreenKey`: options and approvalTarget count, the cursor
|
|
1047
619
|
// does not), or the session is relaunched. Recorded as a suppression, so
|
|
1048
620
|
// the prompt Push and `cmate wait` see "withheld", not "answering".
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
if (partial !== null) {
|
|
1052
|
-
if (partial.screenKey === screenKey) {
|
|
1053
|
-
(0, auto_yes_prompt_suppression_1.suppressAndWarnOnce)(judged, {
|
|
1054
|
-
reason: auto_yes_suppression_reason_1.PARTIAL_ANSWER_SUPPRESSION_REASON,
|
|
1055
|
-
mode: null,
|
|
1056
|
-
promptType: promptDetection.promptData.type,
|
|
1057
|
-
}, `${frameKey}\u0000partial-answer`, 'poller:auto-yes-skipped-partial-answer', { promptType: promptDetection.promptData.type, stoppedAt: partial.at });
|
|
1058
|
-
return 'no_answer';
|
|
1059
|
-
}
|
|
1060
|
-
// Another prompt is on screen: only the sends at the forgotten one's
|
|
1061
|
-
// screen go with it (#3713) — one in flight at this screen keeps its hold.
|
|
1062
|
-
(0, auto_yes_poller_state_1.forgetPartialAnswer)(compositeKey, partial.screenKey);
|
|
1063
|
-
}
|
|
1064
|
-
// Issue #3713: a worktree ID move carried an answer still being sent to
|
|
1065
|
-
// this session's key. Its keys may already be on the pane, and how its send
|
|
1066
|
-
// ends is not known yet — so this screen gets no keys until it comes back
|
|
1067
|
-
// (recorded as a partial answer above, or gone).
|
|
1068
|
-
if ((0, auto_yes_poller_state_1.hasMovedSendInFlight)(compositeKey, epoch, screenKey)) {
|
|
1069
|
-
(0, auto_yes_poller_state_1.warnOncePerFrame)(pollerState, `${frameKey}\u0000moved-send-in-flight`, 'poller:auto-yes-skipped-moved-send-in-flight', { worktreeId, cliToolId, instanceId, promptType: promptDetection.promptData.type });
|
|
621
|
+
if ((0, auto_yes_poller_steps_1.withheldForEarlierSend)(judged, screenKey, epoch)) {
|
|
622
|
+
decision.withheld('moved-send-in-flight');
|
|
1070
623
|
return 'no_answer';
|
|
1071
624
|
}
|
|
1072
625
|
// 3., 3.2., 3.5. Frames that are not Auto-Yes's to answer: see
|
|
1073
626
|
// `suppressIfNotOursToAnswer`.
|
|
1074
627
|
const notOurs = (0, auto_yes_prompt_suppression_1.suppressIfNotOursToAnswer)(judged, frame);
|
|
1075
|
-
if (notOurs.kind !== 'dialog-gate-refused') {
|
|
1076
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
1077
|
-
}
|
|
1078
628
|
if (notOurs.kind === 'left-alone') {
|
|
629
|
+
decision.withheld('unclassified-frame');
|
|
1079
630
|
return 'no_answer';
|
|
1080
631
|
}
|
|
1081
|
-
// 3.6.
|
|
1082
|
-
//
|
|
632
|
+
// 3.6. A frame the dialog gate refused is left to a human, whatever it is.
|
|
633
|
+
// Issue #3821: including a choice screen CommandMate cannot read, which got
|
|
634
|
+
// one bare Enter (#3397) until this Issue retired it — an Enter confirms
|
|
635
|
+
// whatever happens to be selected, and nothing here can say what that is.
|
|
1083
636
|
if (notOurs.kind === 'dialog-gate-refused') {
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
637
|
+
(0, auto_yes_prompt_suppression_1.suppressUnclassifiedFrame)(judged, notOurs.dialogGate);
|
|
638
|
+
decision.withheld('unclassified-frame');
|
|
639
|
+
return 'no_answer';
|
|
640
|
+
}
|
|
641
|
+
// 3.7. Issue #3822: a question to the operator is the human's to answer —
|
|
642
|
+
// under the `careful` answer mode (Issue #3863); under `recommended` a
|
|
643
|
+
// question reader's picker goes on to step 4. See `withheldAsQuestion`.
|
|
644
|
+
if ((0, auto_yes_poller_steps_1.withheldAsQuestion)(judged)) {
|
|
645
|
+
decision.withheld('question-left-to-human');
|
|
646
|
+
return 'no_answer';
|
|
1088
647
|
}
|
|
1089
648
|
// 4. Resolve auto answer under the execution contract's policy (Issue #1547).
|
|
649
|
+
// Issue #3863: a question the `recommended` mode answers takes its
|
|
650
|
+
// recommended option, else its default; one whose recommendation cannot
|
|
651
|
+
// be told is withheld (`recommended-option-unidentified`).
|
|
1090
652
|
// Auto-Yes reads the frame itself instead of going through status-detector
|
|
1091
653
|
// (it shares the reader, not the verdict), so this is the only place the policy can gate an
|
|
1092
654
|
// auto-answer: a prompt the policy withholds is left for a human, and the
|
|
1093
655
|
// response poller's prompt path (WS broadcast + Web Push, see
|
|
1094
656
|
// polling/response-checker.ts) is what tells them it is waiting.
|
|
1095
|
-
const
|
|
1096
|
-
const resolution = (0, auto_yes_resolver_1.resolveAutoAnswerWithPolicy)(promptDetection.promptData, policy);
|
|
1097
|
-
if (resolution.suppressedBy) {
|
|
1098
|
-
// Issue #1684: the log line alone leaves a CLI-driven pipeline blind to
|
|
1099
|
-
// why its worker stalled. Record the suppression so buildCurrentOutput
|
|
1100
|
-
// can publish it (`autoYes.lastSuppression` in capture --json).
|
|
1101
|
-
(0, auto_yes_prompt_suppression_1.suppressAndWarnOnce)(judged, {
|
|
1102
|
-
reason: resolution.suppressedBy,
|
|
1103
|
-
mode: policy?.mode ?? null,
|
|
1104
|
-
promptType: promptDetection.promptData.type,
|
|
1105
|
-
pattern: resolution.pattern,
|
|
1106
|
-
}, `${frameKey}\u0000${resolution.suppressedBy}\u0000${policy?.mode ?? ''}\u0000${resolution.pattern ?? ''}`, 'poller:auto-yes-suppressed-by-policy', {
|
|
1107
|
-
reason: resolution.suppressedBy,
|
|
1108
|
-
mode: policy?.mode ?? null,
|
|
1109
|
-
pattern: resolution.pattern,
|
|
1110
|
-
promptType: promptDetection.promptData.type,
|
|
1111
|
-
});
|
|
1112
|
-
}
|
|
1113
|
-
const answer = resolution.answer;
|
|
657
|
+
const answer = (0, auto_yes_poller_steps_1.resolveAnswerUnderPolicy)(judged);
|
|
1114
658
|
if (answer === null) {
|
|
659
|
+
decision.withheld(auto_yes_decision_1.NO_AUTO_ANSWER_DECISION_REASON);
|
|
1115
660
|
return 'no_answer';
|
|
1116
661
|
}
|
|
1117
662
|
// 5. Send answer to tmux (Issue #896: resolve the instance-specific session)
|
|
@@ -1121,21 +666,29 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
1121
666
|
// Issue #2865: never auto-answer a same-named session another CommandMate
|
|
1122
667
|
// server created. The poller keeps running; it just does not type.
|
|
1123
668
|
const ownership = await (0, worktree_session_ownership_1.checkWorktreeSessionOwnership)(worktreeId, sessionName);
|
|
1124
|
-
if (generation !== undefined && !isTickCurrent(generation))
|
|
669
|
+
if (generation !== undefined && !(0, auto_yes_poller_generation_1.isTickCurrent)(generation))
|
|
1125
670
|
return 'no_answer';
|
|
1126
|
-
if (
|
|
1127
|
-
|
|
1128
|
-
worktreeId,
|
|
1129
|
-
cliToolId,
|
|
1130
|
-
instanceId,
|
|
1131
|
-
sessionName,
|
|
1132
|
-
sessionPath: ownership?.sessionPath ?? null,
|
|
1133
|
-
reason: ownership ? 'foreign' : 'worktree_not_found',
|
|
1134
|
-
});
|
|
671
|
+
if ((0, auto_yes_poller_steps_1.skippedForUnownedSession)(judged, sessionName, ownership)) {
|
|
672
|
+
decision.withheld('foreign-session');
|
|
1135
673
|
return 'no_answer';
|
|
1136
674
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
675
|
+
// 5.5. Issue #3822: the last look before the first key — Auto-Yes still on
|
|
676
|
+
// and inside its window, and the contract, read past its cache, still
|
|
677
|
+
// allowing this answer. No wait between here and the send.
|
|
678
|
+
if ((0, auto_yes_poller_steps_1.withheldAtSend)(judged, generation !== undefined)) {
|
|
679
|
+
decision.withheld(auto_yes_decision_1.NO_AUTO_ANSWER_DECISION_REASON);
|
|
680
|
+
return 'no_answer';
|
|
681
|
+
}
|
|
682
|
+
// Issue #3821: from here until the screen is redrawn, Auto-Yes is answering.
|
|
683
|
+
decision.answering();
|
|
684
|
+
attempt = (0, auto_yes_poller_state_1.beginSendAttempt)(compositeKey, screenKey, generation?.sessionEpoch ?? epoch,
|
|
685
|
+
// Issue #3820: an agy prompt read past the gate is one a hook receipt let through.
|
|
686
|
+
(0, auto_yes_confirmation_ledger_1.beginLedgerAttempt)(ledgerScope, (0, auto_yes_poller_tick_1.answerBasisOf)(judged, cleanOutput), {
|
|
687
|
+
receiptAccepted: cliToolId === 'antigravity',
|
|
688
|
+
}));
|
|
689
|
+
receiptEpisode = (0, auto_yes_poller_receipt_log_1.receiptEpisodeOfSend)(cliToolId, worktreeId, instanceId);
|
|
690
|
+
// Issue #3798: the wait this answer goes to, fixed as the send begins.
|
|
691
|
+
const answerTarget = (0, auto_yes_poller_answer_target_1.fixAnswerTarget)(worktreeId, cliToolId, instanceId);
|
|
1139
692
|
sendInFlight = true;
|
|
1140
693
|
try {
|
|
1141
694
|
await (0, prompt_answer_sender_1.sendPromptAnswer)({
|
|
@@ -1144,43 +697,53 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
1144
697
|
cliToolId,
|
|
1145
698
|
promptData: promptDetection.promptData,
|
|
1146
699
|
// Issue #3706: asked after each wait inside the send.
|
|
1147
|
-
...(generation !== undefined ? { stillCurrent: () => isTickCurrent(generation) } : {}),
|
|
700
|
+
...(generation !== undefined ? { stillCurrent: () => (0, auto_yes_poller_generation_1.isTickCurrent)(generation) } : {}),
|
|
1148
701
|
});
|
|
1149
702
|
}
|
|
1150
703
|
finally {
|
|
1151
704
|
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
1152
705
|
}
|
|
1153
706
|
sendInFlight = false;
|
|
707
|
+
(0, auto_yes_confirmation_ledger_1.settleLedgerAttempt)(attempt.ledger, 'ok', { expired: attempt.state === 'expired' });
|
|
1154
708
|
(0, auto_yes_poller_state_1.settleSendAttempt)(attempt, false);
|
|
1155
709
|
// Issue #3796 review E: the episode the send began for, as on the failure side.
|
|
1156
|
-
noteAnswerSent(cliToolId, worktreeId, instanceId, false, receiptEpisode);
|
|
710
|
+
(0, auto_yes_poller_receipt_log_1.noteAnswerSent)(cliToolId, worktreeId, instanceId, false, receiptEpisode);
|
|
711
|
+
// Issue #3798: the wait this answer went to — opened if none is open — so
|
|
712
|
+
// the frame that shows the confirmation gone closes it. Once the keys are
|
|
713
|
+
// out, only by a tick that still acts for this instance (#3706: one that
|
|
714
|
+
// lost its grant or session writes nothing that says "answered"), and only
|
|
715
|
+
// for the wait fixed as the send began.
|
|
716
|
+
if (generation === undefined || (0, auto_yes_poller_generation_1.isTickCurrent)(generation)) {
|
|
717
|
+
observeAnsweredPrompt(judged, screenKey, tickObservation, answerTarget);
|
|
718
|
+
}
|
|
1157
719
|
// 6., 7. The answer reached tmux: see `finishAnsweredPrompt`.
|
|
1158
|
-
await finishAnsweredPrompt(judged, promptDetection, answer, generation
|
|
720
|
+
await finishAnsweredPrompt(judged, promptDetection, answer, generation, {
|
|
721
|
+
// The tick's one normalised frame (#3183), not the capture again.
|
|
722
|
+
frame,
|
|
723
|
+
captureTop: (0, auto_yes_poller_tick_1.captureTopOf)(rawOutput ?? cleanOutput, captureExtent, cliToolId),
|
|
724
|
+
});
|
|
1159
725
|
return 'responded';
|
|
1160
726
|
}
|
|
1161
727
|
catch (error) {
|
|
1162
|
-
// Issue #
|
|
1163
|
-
//
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
if (
|
|
1180
|
-
|
|
1181
|
-
incrementErrorCount(compositeKey, generation?.pollerState);
|
|
1182
|
-
logger.warn('poller:detect-respond-error', { worktreeId, cliToolId, instanceId });
|
|
1183
|
-
return 'error';
|
|
728
|
+
// Issue #3821: a tick that failed has decided nothing the next one will not
|
|
729
|
+
// decide again; until then the prompt is not "being answered".
|
|
730
|
+
if (generation === undefined || (0, auto_yes_poller_generation_1.isTickCurrent)(generation))
|
|
731
|
+
(0, auto_yes_decision_state_1.forgetAutoYesDecision)(compositeKey);
|
|
732
|
+
return settleFailedTick(error, {
|
|
733
|
+
worktreeId,
|
|
734
|
+
cliToolId,
|
|
735
|
+
instanceId,
|
|
736
|
+
compositeKey,
|
|
737
|
+
generation,
|
|
738
|
+
attempt,
|
|
739
|
+
sendInFlight,
|
|
740
|
+
receiptEpisode,
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
finally {
|
|
744
|
+
(0, auto_yes_confirmation_ledger_1.endLedgerTick)(ledgerScope, ledgerTick);
|
|
745
|
+
if (!keepDuplicateRetry)
|
|
746
|
+
(0, auto_yes_poller_generation_1.releaseDuplicateRetry)(pollerState);
|
|
1184
747
|
}
|
|
1185
748
|
}
|
|
1186
749
|
/**
|
|
@@ -1195,7 +758,7 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
1195
758
|
async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
1196
759
|
const compositeKey = (0, auto_yes_state_1.buildCompositeKey)(worktreeId, cliToolId, instanceId);
|
|
1197
760
|
// 1. Validate context
|
|
1198
|
-
const pollerState = getPollerState(compositeKey);
|
|
761
|
+
const pollerState = (0, auto_yes_poller_generation_1.getPollerState)(compositeKey);
|
|
1199
762
|
if (owner !== undefined && pollerState !== owner)
|
|
1200
763
|
return;
|
|
1201
764
|
const contextResult = validatePollingContext(compositeKey, pollerState);
|
|
@@ -1215,11 +778,15 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
1215
778
|
grant,
|
|
1216
779
|
sessionEpoch: (0, auto_yes_enter_fallback_1.getEnterFallbackSessionEpoch)(compositeKey),
|
|
1217
780
|
startedAt: Date.now(),
|
|
781
|
+
// Issue #3821: a person's answer begun after this is read stops the tick.
|
|
782
|
+
manualAnswerSeq: (0, auto_yes_manual_answer_1.getManualAnswerSeq)(compositeKey),
|
|
1218
783
|
};
|
|
1219
784
|
// Issue #3796: this is the session wait's tick (it was scheduled as one) —
|
|
1220
785
|
// recorded before anything can fail, for the push gate.
|
|
1221
786
|
if (pollerState.sessionWaitTickAt !== undefined)
|
|
1222
787
|
pollerState.sessionWaitTickRanAt = generation.startedAt;
|
|
788
|
+
// Issue #3798: the waiting episode as this tick found it, before its first wait.
|
|
789
|
+
const observationStart = (0, waiting_episode_binding_1.startWaitingObservation)(worktreeId, cliToolId, instanceId);
|
|
1223
790
|
try {
|
|
1224
791
|
// 2. Capture and clean output
|
|
1225
792
|
const captureLines = grant.stopPattern
|
|
@@ -1229,8 +796,11 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
1229
796
|
// step below exactly as it did; the raw one is carried to the prompt reading
|
|
1230
797
|
// so a dialog anchored on box drawing is not invisible to the one path that
|
|
1231
798
|
// can answer it without a human.
|
|
1232
|
-
|
|
1233
|
-
|
|
799
|
+
//
|
|
800
|
+
// Issue #3798: dated by where that frame came from — the capture goes
|
|
801
|
+
// through the 5 s cache, so it may predate this tick.
|
|
802
|
+
const { frame: { raw: rawOutput, clean: cleanOutput, headCut }, frameTime, } = await (0, waiting_episode_binding_1.captureObservedFrame)(() => (0, auto_yes_poller_capture_1.capturePollerFrame)(worktreeId, cliToolId, captureLines, instanceId));
|
|
803
|
+
if (!(0, auto_yes_poller_generation_1.isTickCurrent)(generation)) {
|
|
1234
804
|
endStaleTick(generation);
|
|
1235
805
|
return;
|
|
1236
806
|
}
|
|
@@ -1246,8 +816,11 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
1246
816
|
return;
|
|
1247
817
|
}
|
|
1248
818
|
// 4. Detect and respond to prompt
|
|
1249
|
-
const result = await detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, cleanOutput, lines, instanceId, rawOutput, generation
|
|
1250
|
-
|
|
819
|
+
const result = await detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, cleanOutput, lines, instanceId, rawOutput, generation, { start: observationStart, frameTime },
|
|
820
|
+
// Issue #3881 (review P2-1): the window this capture was taken with,
|
|
821
|
+
// and (third review N4) whether it cut the pane's top.
|
|
822
|
+
captureLines, headCut);
|
|
823
|
+
if (!(0, auto_yes_poller_generation_1.isTickCurrent)(generation)) {
|
|
1251
824
|
endStaleTick(generation);
|
|
1252
825
|
return;
|
|
1253
826
|
}
|
|
@@ -1256,7 +829,7 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
1256
829
|
// over hours. Not on 'error': a capture that works followed by an answer
|
|
1257
830
|
// that fails every time must still back off and stop.
|
|
1258
831
|
if (result !== 'error') {
|
|
1259
|
-
resetErrorCount(compositeKey, generation.pollerState);
|
|
832
|
+
(0, auto_yes_poller_generation_1.resetErrorCount)(compositeKey, generation.pollerState);
|
|
1260
833
|
}
|
|
1261
834
|
if (result === 'responded') {
|
|
1262
835
|
scheduleNextPoll(generation, auto_yes_state_1.COOLDOWN_INTERVAL_MS);
|
|
@@ -1264,6 +837,15 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
1264
837
|
}
|
|
1265
838
|
// 5. Thinking check
|
|
1266
839
|
if (result === 'no_prompt') {
|
|
840
|
+
observeWaitingFromTick({
|
|
841
|
+
worktreeId,
|
|
842
|
+
cliToolId,
|
|
843
|
+
instanceId,
|
|
844
|
+
start: observationStart,
|
|
845
|
+
frameTime,
|
|
846
|
+
pollerState: generation.pollerState,
|
|
847
|
+
rawOutput,
|
|
848
|
+
});
|
|
1267
849
|
const recentLines = lines.slice(-auto_yes_state_1.THINKING_CHECK_LINE_COUNT).join('\n');
|
|
1268
850
|
if ((0, cli_patterns_1.detectThinking)(cliToolId, recentLines)) {
|
|
1269
851
|
scheduleNextPoll(generation, auto_yes_config_1.THINKING_POLLING_INTERVAL_MS);
|
|
@@ -1276,12 +858,24 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
1276
858
|
// the session it answers for (`auto-yes-lifecycle`), and `send --auto-yes`
|
|
1277
859
|
// enables it before the session starts — so wait until `expiresAt`, at the
|
|
1278
860
|
// backoff cap, instead of counting toward `consecutive_errors`.
|
|
1279
|
-
const sessionMissing = await isSessionMissing(worktreeId, cliToolId, instanceId);
|
|
1280
|
-
if (!isTickCurrent(generation)) {
|
|
861
|
+
const sessionMissing = await (0, auto_yes_poller_session_presence_1.isSessionMissing)(worktreeId, cliToolId, instanceId);
|
|
862
|
+
if (!(0, auto_yes_poller_generation_1.isTickCurrent)(generation)) {
|
|
1281
863
|
endStaleTick(generation);
|
|
1282
864
|
return;
|
|
1283
865
|
}
|
|
1284
866
|
if (sessionMissing) {
|
|
867
|
+
// Issue #3791 (review N1): no screen for the duplicate guard to hold back.
|
|
868
|
+
(0, auto_yes_poller_generation_1.releaseDuplicateRetry)(generation.pollerState);
|
|
869
|
+
// Issue #3798: a session that is gone is waiting for nobody.
|
|
870
|
+
observeWaitingFromTick({
|
|
871
|
+
worktreeId,
|
|
872
|
+
cliToolId,
|
|
873
|
+
instanceId,
|
|
874
|
+
start: observationStart,
|
|
875
|
+
frameTime: { frameCapturedAt: 0, frameFetchedAfterStart: false },
|
|
876
|
+
pollerState: generation.pollerState,
|
|
877
|
+
rawOutput: null,
|
|
878
|
+
});
|
|
1285
879
|
if (!pollerState.waitingForSession) {
|
|
1286
880
|
pollerState.waitingForSession = true;
|
|
1287
881
|
logger.info('poller:waiting-for-session', { worktreeId, cliToolId, instanceId });
|
|
@@ -1295,17 +889,108 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
1295
889
|
scheduleNextPoll(generation);
|
|
1296
890
|
}
|
|
1297
891
|
/**
|
|
1298
|
-
*
|
|
1299
|
-
* (Issue #
|
|
1300
|
-
*
|
|
1301
|
-
*
|
|
892
|
+
* The answer the poller just sent, as an observation of the waiting episodes
|
|
893
|
+
* (Issue #3798, design §2.5 "Auto-Yes poller", PR 3). Called in the
|
|
894
|
+
* synchronous step the send returns to, before anything else is awaited: the
|
|
895
|
+
* confirmation answered is a fresh prompt (planned against the episode as it
|
|
896
|
+
* is now, I5 (d)), so a wait opens if none is open, and a second confirmation
|
|
897
|
+
* of the same turn after an answer (another screen key) replaces the answered
|
|
898
|
+
* wait (R1-7) — a new hold, not the old wait's spent one. The episode the plan
|
|
899
|
+
* leaves open is recorded as `lastAnswer`; a plan refused (another generation,
|
|
900
|
+
* or a frame fetched before the close of this very confirmation — a stop that
|
|
901
|
+
* landed during the send) records none, so nothing is closed on the strength
|
|
902
|
+
* of it. Nor does a send whose wait moved under it (`target`, fixed as the
|
|
903
|
+
* send began): another wait opened during the send — a hook, another
|
|
904
|
+
* observer — is not the one these keys answered, and nothing is planned or
|
|
905
|
+
* recorded for it; `lastAnswer` stays as it was — and so for the same wait
|
|
906
|
+
* rebound during the send to a person's `screen`. Advisory, like
|
|
907
|
+
* {@link observeWaitingFromTick}.
|
|
908
|
+
*/
|
|
909
|
+
function observeAnsweredPrompt(prompt, screenKey, observation, target) {
|
|
910
|
+
const { worktreeId, cliToolId, instanceId, pollerState, promptData } = prompt;
|
|
911
|
+
try {
|
|
912
|
+
if (!(0, auto_yes_poller_answer_target_1.answerTargetHolds)(target, worktreeId, cliToolId, instanceId)) {
|
|
913
|
+
logger.debug('poller:answer-target-moved', { worktreeId, cliToolId, instanceId, target: target.episodeId });
|
|
914
|
+
return;
|
|
915
|
+
}
|
|
916
|
+
const plan = (0, waiting_episode_binding_1.observeWaiting)({
|
|
917
|
+
worktreeId,
|
|
918
|
+
cliToolId,
|
|
919
|
+
instanceId,
|
|
920
|
+
observer: 'auto-yes-poller',
|
|
921
|
+
start: observation.start,
|
|
922
|
+
reading: (0, waiting_screen_reading_1.promptWaitingReading)(promptData),
|
|
923
|
+
...observation.frameTime,
|
|
924
|
+
freshPrompt: true,
|
|
925
|
+
lastAnswer: pollerState.lastAnswer ?? null,
|
|
926
|
+
});
|
|
927
|
+
const episode = plan.action === 'ignored' ? null : (0, waiting_episode_state_1.getWaitingEpisodeRecord)(worktreeId, cliToolId, instanceId);
|
|
928
|
+
pollerState.lastAnswer = episode === null ? null : { episodeId: episode.episodeId, screenKey, at: plan.at };
|
|
929
|
+
}
|
|
930
|
+
catch (error) {
|
|
931
|
+
pollerState.lastAnswer = null;
|
|
932
|
+
logger.debug('poller:waiting-observation-failed', {
|
|
933
|
+
worktreeId,
|
|
934
|
+
cliToolId,
|
|
935
|
+
instanceId,
|
|
936
|
+
error: (0, errors_1.getErrorMessage)(error),
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
/**
|
|
941
|
+
* Tell the waiting episodes what this tick saw (Issue #3798, design §2.5,
|
|
942
|
+
* PR 1b): a frame with nothing for Auto-Yes to answer, read the way the status
|
|
943
|
+
* probe reads it — without the agy receipt window — or a session that is gone.
|
|
944
|
+
*
|
|
945
|
+
* What it can do is table O-1 for a waiting frame (a survey or a picker after
|
|
946
|
+
* an answer opens, or turns the wait into, a person's `screen`), and on the
|
|
947
|
+
* closing side a `screen` this tick saw cleared on a frame fetched after it
|
|
948
|
+
* became one, the wait the poller answered (`lastAnswer`, PR 3), or any wait
|
|
949
|
+
* of a session that is gone. A wait the poller did not answer — or answered
|
|
950
|
+
* before it was replaced — is not its to close. Advisory: a failure is logged
|
|
951
|
+
* and the tick goes on.
|
|
1302
952
|
*/
|
|
1303
|
-
|
|
953
|
+
function observeWaitingFromTick(tick) {
|
|
954
|
+
const { worktreeId, cliToolId, instanceId } = tick;
|
|
1304
955
|
try {
|
|
1305
|
-
|
|
956
|
+
let reading = { kind: 'gone' };
|
|
957
|
+
if (tick.rawOutput !== null) {
|
|
958
|
+
const lastResponseAt = tick.pollerState.lastServerResponseTimestamp;
|
|
959
|
+
const lastOutputTimestamp = lastResponseAt ? new Date(lastResponseAt) : undefined;
|
|
960
|
+
// Without the receipt scope (design I9), and with the structured wait
|
|
961
|
+
// read the way the status probe reads it — the API-answerable one
|
|
962
|
+
// (#3184) a `prompt` here too, or the two observers would flip the
|
|
963
|
+
// episode's kind between `prompt` and `menu` on every tick.
|
|
964
|
+
const verdict = (0, status_detector_1.detectSessionStatus)(tick.rawOutput, cliToolId, lastOutputTimestamp);
|
|
965
|
+
const { structured } = (0, prompt_waiting_composition_1.peekPromptWaiting)({ worktreeId, cliToolId, instanceId, scraper: verdict });
|
|
966
|
+
reading = (0, waiting_screen_reading_1.readWaitingScreen)({
|
|
967
|
+
cliToolId,
|
|
968
|
+
output: tick.rawOutput,
|
|
969
|
+
lastOutputTimestamp,
|
|
970
|
+
structuredWaiting: structured !== null,
|
|
971
|
+
structuredSince: structured?.at ?? null,
|
|
972
|
+
apiAnswerable: (0, prompt_waiting_composition_1.isApiAnswerableStructuredWait)(structured, (0, registry_1.getAgentEventSource)(cliToolId).capabilities.eventIdentity),
|
|
973
|
+
verdict,
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
(0, waiting_episode_binding_1.observeWaiting)({
|
|
977
|
+
worktreeId,
|
|
978
|
+
cliToolId,
|
|
979
|
+
instanceId,
|
|
980
|
+
observer: 'auto-yes-poller',
|
|
981
|
+
start: tick.start,
|
|
982
|
+
reading,
|
|
983
|
+
...tick.frameTime,
|
|
984
|
+
lastAnswer: tick.pollerState.lastAnswer ?? null,
|
|
985
|
+
});
|
|
1306
986
|
}
|
|
1307
|
-
catch {
|
|
1308
|
-
|
|
987
|
+
catch (error) {
|
|
988
|
+
logger.debug('poller:waiting-observation-failed', {
|
|
989
|
+
worktreeId,
|
|
990
|
+
cliToolId,
|
|
991
|
+
instanceId,
|
|
992
|
+
error: (0, errors_1.getErrorMessage)(error),
|
|
993
|
+
});
|
|
1309
994
|
}
|
|
1310
995
|
}
|
|
1311
996
|
/**
|
|
@@ -1320,7 +1005,7 @@ async function isSessionMissing(worktreeId, cliToolId, instanceId) {
|
|
|
1320
1005
|
* @param options.sessionWait - The tick waits for a session to appear (Issue #3791)
|
|
1321
1006
|
*/
|
|
1322
1007
|
function scheduleNextPoll(generation, overrideInterval, options = {}) {
|
|
1323
|
-
if (!isPollerCurrent(generation))
|
|
1008
|
+
if (!(0, auto_yes_poller_generation_1.isPollerCurrent)(generation))
|
|
1324
1009
|
return;
|
|
1325
1010
|
const { worktreeId, cliToolId, instanceId, pollerState } = generation;
|
|
1326
1011
|
const interval = Math.max(overrideInterval ?? pollerState.currentInterval, auto_yes_state_1.POLLING_INTERVAL_MS);
|
|
@@ -1373,7 +1058,7 @@ function armSessionWaitWake(generation, timerId) {
|
|
|
1373
1058
|
if (wake === undefined || wake.timerId !== timerId)
|
|
1374
1059
|
return;
|
|
1375
1060
|
sessionWaitWakes.delete(compositeKey);
|
|
1376
|
-
if (!isPollerCurrent(generation) || pollerState.timerId !== timerId)
|
|
1061
|
+
if (!(0, auto_yes_poller_generation_1.isPollerCurrent)(generation) || pollerState.timerId !== timerId)
|
|
1377
1062
|
return;
|
|
1378
1063
|
clearTimeout(timerId);
|
|
1379
1064
|
logger.info('poller:session-created-wake', { worktreeId, cliToolId, instanceId });
|
|
@@ -1416,8 +1101,8 @@ function startAutoYesPolling(worktreeId, cliToolId, instanceId) {
|
|
|
1416
1101
|
}
|
|
1417
1102
|
const compositeKey = (0, auto_yes_state_1.buildCompositeKey)(worktreeId, cliToolId, effectiveInstanceId);
|
|
1418
1103
|
// Check concurrent poller limit (DoS protection)
|
|
1419
|
-
const existingPollerState = getPollerState(compositeKey);
|
|
1420
|
-
if (!existingPollerState && autoYesPollerStates.size >= auto_yes_state_1.MAX_CONCURRENT_POLLERS) {
|
|
1104
|
+
const existingPollerState = (0, auto_yes_poller_generation_1.getPollerState)(compositeKey);
|
|
1105
|
+
if (!existingPollerState && auto_yes_poller_generation_1.autoYesPollerStates.size >= auto_yes_state_1.MAX_CONCURRENT_POLLERS) {
|
|
1421
1106
|
return { started: false, reason: 'max concurrent pollers reached' };
|
|
1422
1107
|
}
|
|
1423
1108
|
// Issue #501: Idempotency check (key already encodes the instance, so a matching
|
|
@@ -1442,7 +1127,7 @@ function startAutoYesPolling(worktreeId, cliToolId, instanceId) {
|
|
|
1442
1127
|
stopCheckBaselineLength: -1,
|
|
1443
1128
|
lastSkipWarnKey: null,
|
|
1444
1129
|
};
|
|
1445
|
-
autoYesPollerStates.set(compositeKey, pollerState);
|
|
1130
|
+
auto_yes_poller_generation_1.autoYesPollerStates.set(compositeKey, pollerState);
|
|
1446
1131
|
// A task may have been recorded moments ago; start from a fresh policy read.
|
|
1447
1132
|
(0, auto_yes_policy_1.invalidateSessionAutoYesPolicy)(compositeKey);
|
|
1448
1133
|
// Start polling immediately
|
|
@@ -1471,14 +1156,19 @@ function stopAutoYesPolling(compositeKey, reason) {
|
|
|
1471
1156
|
// cleanup call this for an instance whose poller may already be gone, and the
|
|
1472
1157
|
// Enter record must not outlive the grant or the session either way.
|
|
1473
1158
|
(0, auto_yes_enter_fallback_1.forgetEnterFallback)(compositeKey);
|
|
1474
|
-
|
|
1159
|
+
// Issue #3821: and the decision, for the same reason.
|
|
1160
|
+
(0, auto_yes_decision_state_1.forgetAutoYesDecision)(compositeKey);
|
|
1161
|
+
// Issue #3820: before the early return too — a session ended after its
|
|
1162
|
+
// poller had already stopped still abandons the confirmation left on it.
|
|
1163
|
+
(0, auto_yes_confirmation_ledger_1.noteLedgerPollerStopped)(compositeKey, (0, auto_yes_poller_stop_reason_1.resolvePollerStopReason)(reason, 'unspecified'));
|
|
1164
|
+
const pollerState = (0, auto_yes_poller_generation_1.getPollerState)(compositeKey);
|
|
1475
1165
|
if (!pollerState)
|
|
1476
1166
|
return;
|
|
1477
1167
|
if (pollerState.timerId) {
|
|
1478
1168
|
clearTimeout(pollerState.timerId);
|
|
1479
1169
|
}
|
|
1480
1170
|
dropSessionWaitWake(compositeKey);
|
|
1481
|
-
autoYesPollerStates.delete(compositeKey);
|
|
1171
|
+
auto_yes_poller_generation_1.autoYesPollerStates.delete(compositeKey);
|
|
1482
1172
|
(0, auto_yes_policy_1.invalidateSessionAutoYesPolicy)(compositeKey);
|
|
1483
1173
|
logger.info('poller:stopped', { compositeKey, reason: (0, auto_yes_poller_stop_reason_1.resolvePollerStopReason)(reason, 'unspecified') });
|
|
1484
1174
|
}
|
|
@@ -1492,28 +1182,20 @@ function stopAutoYesPolling(compositeKey, reason) {
|
|
|
1492
1182
|
*/
|
|
1493
1183
|
function stopAllAutoYesPolling() {
|
|
1494
1184
|
const reason = (0, auto_yes_poller_stop_reason_1.resolvePollerStopReason)(undefined, 'shutdown');
|
|
1495
|
-
for (const [key, pollerState] of autoYesPollerStates.entries()) {
|
|
1185
|
+
for (const [key, pollerState] of auto_yes_poller_generation_1.autoYesPollerStates.entries()) {
|
|
1496
1186
|
if (pollerState.timerId) {
|
|
1497
1187
|
clearTimeout(pollerState.timerId);
|
|
1498
1188
|
}
|
|
1499
1189
|
dropSessionWaitWake(key);
|
|
1500
1190
|
(0, auto_yes_policy_1.invalidateSessionAutoYesPolicy)(key);
|
|
1191
|
+
(0, auto_yes_confirmation_ledger_1.noteLedgerPollerStopped)(key, reason);
|
|
1501
1192
|
logger.info('poller:stopped', { compositeKey: key, reason });
|
|
1502
1193
|
}
|
|
1503
|
-
autoYesPollerStates.clear();
|
|
1194
|
+
auto_yes_poller_generation_1.autoYesPollerStates.clear();
|
|
1504
1195
|
(0, auto_yes_enter_fallback_1.clearEnterFallbacks)();
|
|
1196
|
+
(0, auto_yes_decision_state_1.clearAutoYesDecisions)();
|
|
1505
1197
|
(0, auto_yes_poller_state_1.clearPartialAnswers)();
|
|
1506
1198
|
}
|
|
1507
|
-
/**
|
|
1508
|
-
* Get all composite keys that have active auto-yes poller entries.
|
|
1509
|
-
*
|
|
1510
|
-
* Issue #525: Returns composite keys (worktreeId:cliToolId).
|
|
1511
|
-
*
|
|
1512
|
-
* @returns Array of composite keys present in the autoYesPollerStates Map
|
|
1513
|
-
*/
|
|
1514
|
-
function getAutoYesPollerCompositeKeys() {
|
|
1515
|
-
return Array.from(autoYesPollerStates.keys());
|
|
1516
|
-
}
|
|
1517
1199
|
// =============================================================================
|
|
1518
1200
|
// byWorktree Helpers (Issue #525)
|
|
1519
1201
|
// =============================================================================
|
|
@@ -1531,21 +1213,15 @@ function getAutoYesPollerCompositeKeys() {
|
|
|
1531
1213
|
* `auto-yes-lifecycle`), both are dropped and a late send records nothing.
|
|
1532
1214
|
*/
|
|
1533
1215
|
function stopAutoYesPollingByWorktree(worktreeId, options) {
|
|
1534
|
-
const pollerKeys = (0, auto_yes_state_1.filterCompositeKeysByWorktree)(Array.from(autoYesPollerStates.keys()), worktreeId);
|
|
1216
|
+
const pollerKeys = (0, auto_yes_state_1.filterCompositeKeysByWorktree)(Array.from(auto_yes_poller_generation_1.autoYesPollerStates.keys()), worktreeId);
|
|
1535
1217
|
// Issue #3730: `options.reason`, else the enclosing scope's (the lifecycle table).
|
|
1536
1218
|
pollerKeys.forEach(key => stopAutoYesPolling(key, options?.reason));
|
|
1537
1219
|
// Issue #3397: and the records of instances whose poller had already stopped.
|
|
1538
1220
|
(0, auto_yes_enter_fallback_1.forgetEnterFallbacksByWorktree)(worktreeId);
|
|
1221
|
+
(0, auto_yes_decision_state_1.forgetAutoYesDecisionsByWorktree)(worktreeId);
|
|
1222
|
+
// Issue #3820: and the ledger's confirmations on them — an API approval is
|
|
1223
|
+
// opened with Auto-Yes off too, so the running pollers do not name them all.
|
|
1224
|
+
(0, auto_yes_confirmation_ledger_1.noteLedgerWorktreeStopped)(worktreeId, (0, auto_yes_poller_stop_reason_1.resolvePollerStopReason)(options?.reason, 'unspecified'));
|
|
1539
1225
|
if (!options?.keepPartialAnswers)
|
|
1540
1226
|
(0, auto_yes_poller_state_1.forgetPartialAnswersByWorktree)(worktreeId);
|
|
1541
1227
|
}
|
|
1542
|
-
/**
|
|
1543
|
-
* Check if any auto-yes poller is active for a given worktreeId.
|
|
1544
|
-
* Uses shared filterCompositeKeysByWorktree (DRY).
|
|
1545
|
-
*
|
|
1546
|
-
* @param worktreeId - Worktree identifier
|
|
1547
|
-
* @returns true if any poller is active for this worktree
|
|
1548
|
-
*/
|
|
1549
|
-
function isAnyPollerActiveForWorktree(worktreeId) {
|
|
1550
|
-
return (0, auto_yes_state_1.filterCompositeKeysByWorktree)(Array.from(autoYesPollerStates.keys()), worktreeId).length > 0;
|
|
1551
|
-
}
|