commandmate 0.47.2 → 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 +215 -215
- package/.next/app-path-routes-manifest.json +41 -41
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +9 -9
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route.js +3 -3
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route.js +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/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_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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +3 -3
- 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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.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_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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/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_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_client-reference-manifest.js +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_client-reference-manifest.js +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_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/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +12 -12
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +41 -41
- 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 +2 -2
- 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 -1
- package/.next/server/chunks/3241.js +1 -1
- package/.next/server/chunks/3505.js +2 -2
- package/.next/server/chunks/4248.js +1 -1
- package/.next/server/chunks/4280.js +1 -0
- package/.next/server/chunks/5209.js +1 -1
- package/.next/server/chunks/6119.js +1 -1
- package/.next/server/chunks/6130.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/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/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 +3 -3
- package/.next/server/chunks/9731.js +2 -2
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/2099-c3e0ab70a1b95dd3.js +1 -0
- package/.next/static/chunks/{2407-a6533805a86d05bd.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/app/{layout-538d8d2746ad1588.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/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 +5 -3
- 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 +101 -13
- 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 +116 -2
- 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 +54 -2
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts.map +1 -1
- package/dist/lib/polling/auto-yes-suppression-reason.js +33 -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 +337 -376
- 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 -350
- 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-decision-service.js +7 -0
- 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 +3 -0
- package/dist/server/src/lib/polling/auto-yes-confirmation-ledger.js +34 -3
- 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-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 +11 -5
- package/dist/server/src/lib/polling/auto-yes-poller-capture.js +15 -2
- package/dist/server/src/lib/polling/auto-yes-poller-generation.js +42 -1
- package/dist/server/src/lib/polling/auto-yes-poller-receipt-log.js +42 -5
- package/dist/server/src/lib/polling/auto-yes-poller-state.js +147 -49
- package/dist/server/src/lib/polling/auto-yes-poller-steps.js +172 -2
- package/dist/server/src/lib/polling/auto-yes-prompt-suppression.js +2 -2
- package/dist/server/src/lib/polling/auto-yes-question-choice.js +57 -0
- package/dist/server/src/lib/polling/auto-yes-resolver.js +96 -21
- package/dist/server/src/lib/polling/auto-yes-suppression-reason.js +33 -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-dialog-gate.js +39 -0
- package/dist/server/src/lib/polling/response-checker.js +133 -43
- package/dist/server/src/lib/prompt-answer-sender.js +104 -10
- 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 +1 -1
- package/public/sw.js +76 -4
- package/release-notes/0.48.0.json +57 -0
- package/.next/server/chunks/1559.js +0 -2
- package/.next/server/chunks/2460.js +0 -1
- package/.next/server/chunks/5595.js +0 -1
- package/.next/server/chunks/610.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/app/sessions/page-e02f1adb1d1c1ccc.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-46aced20b2b1c010.js +0 -1
- /package/.next/static/{etorRtpxbQqqOzdUeXdw2 → PTlAswXLq8PAe2vUJ8dVP}/_buildManifest.js +0 -0
- /package/.next/static/{etorRtpxbQqqOzdUeXdw2 → 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,7 +51,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
45
51
|
};
|
|
46
52
|
})();
|
|
47
53
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
-
exports.capturePollerFrame = exports.captureAndCleanOutput = exports.AUTO_YES_ENTER_FALLBACK_ANSWER = exports.noHookReceiptHint = exports.isPollerActive = exports.getLastServerResponseTimestamp = exports.getActivePollerCount = void 0;
|
|
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;
|
|
49
55
|
exports.clearAllPollerStates = clearAllPollerStates;
|
|
50
56
|
exports.validatePollingContext = validatePollingContext;
|
|
51
57
|
exports.processStopConditionDelta = processStopConditionDelta;
|
|
@@ -53,32 +59,30 @@ exports.detectAndRespondToPrompt = detectAndRespondToPrompt;
|
|
|
53
59
|
exports.startAutoYesPolling = startAutoYesPolling;
|
|
54
60
|
exports.stopAutoYesPolling = stopAutoYesPolling;
|
|
55
61
|
exports.stopAllAutoYesPolling = stopAllAutoYesPolling;
|
|
56
|
-
exports.getAutoYesPollerCompositeKeys = getAutoYesPollerCompositeKeys;
|
|
57
62
|
exports.stopAutoYesPollingByWorktree = stopAutoYesPollingByWorktree;
|
|
58
|
-
exports.isAnyPollerActiveForWorktree = isAnyPollerActiveForWorktree;
|
|
59
|
-
const cli_session_1 = require("./session/cli-session");
|
|
60
63
|
const response_checker_1 = require("./polling/response-checker");
|
|
61
|
-
const antigravity_receipt_episodes_1 = require("./polling/antigravity-receipt-episodes");
|
|
62
|
-
const auto_yes_resolver_1 = require("./polling/auto-yes-resolver");
|
|
63
64
|
const auto_yes_policy_1 = require("./polling/auto-yes-policy");
|
|
64
|
-
const detect_1 = require("./detection/tools/codex/detect");
|
|
65
|
-
const frame_1 = require("./detection/tools/frame");
|
|
66
|
-
const dialog_1 = require("./detection/tools/antigravity/dialog");
|
|
67
|
-
const auto_yes_dialog_gate_1 = require("./polling/auto-yes-dialog-gate");
|
|
68
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");
|
|
69
69
|
const task_transition_service_1 = require("./tasks/task-transition-service");
|
|
70
70
|
const db_instance_1 = require("./db/db-instance");
|
|
71
71
|
const chat_db_1 = require("./db/chat-db");
|
|
72
72
|
const worktree_session_ownership_1 = require("./cli-tools/worktree-session-ownership");
|
|
73
73
|
const prompt_answer_sender_1 = require("./prompt-answer-sender");
|
|
74
|
-
const prompt_answer_semantic_1 = require("./prompt-answer-semantic");
|
|
75
|
-
const tmux_1 = require("./tmux/tmux");
|
|
76
74
|
const session_created_signal_1 = require("./tmux/session-created-signal");
|
|
77
75
|
const manager_1 = require("./cli-tools/manager");
|
|
78
76
|
const cli_patterns_1 = require("./detection/cli-patterns");
|
|
79
77
|
const prompt_key_1 = require("./detection/prompt-key");
|
|
80
78
|
const errors_1 = require("./errors");
|
|
81
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");
|
|
82
86
|
const auto_yes_config_1 = require("../config/auto-yes-config");
|
|
83
87
|
const auto_yes_poller_stop_reason_1 = require("./polling/auto-yes-poller-stop-reason");
|
|
84
88
|
const logger_1 = require("../lib/logger");
|
|
@@ -92,7 +96,11 @@ const auto_yes_poller_generation_1 = require("./polling/auto-yes-poller-generati
|
|
|
92
96
|
const auto_yes_poller_receipt_log_1 = require("./polling/auto-yes-poller-receipt-log");
|
|
93
97
|
const auto_yes_poller_enter_fallback_1 = require("./polling/auto-yes-poller-enter-fallback");
|
|
94
98
|
const auto_yes_poller_capture_1 = require("./polling/auto-yes-poller-capture");
|
|
99
|
+
const prompt_screen_reading_1 = require("./polling/prompt-screen-reading");
|
|
95
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");
|
|
96
104
|
const auto_yes_poller_steps_1 = require("./polling/auto-yes-poller-steps");
|
|
97
105
|
// Issue #3783: split out; re-exported so existing importers are unchanged.
|
|
98
106
|
var auto_yes_poller_generation_2 = require("./polling/auto-yes-poller-generation");
|
|
@@ -101,6 +109,10 @@ Object.defineProperty(exports, "getLastServerResponseTimestamp", { enumerable: t
|
|
|
101
109
|
Object.defineProperty(exports, "isPollerActive", { enumerable: true, get: function () { return auto_yes_poller_generation_2.isPollerActive; } });
|
|
102
110
|
var auto_yes_poller_receipt_log_2 = require("./polling/auto-yes-poller-receipt-log");
|
|
103
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; } });
|
|
104
116
|
var auto_yes_poller_enter_fallback_2 = require("./polling/auto-yes-poller-enter-fallback");
|
|
105
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; } });
|
|
106
118
|
var auto_yes_poller_capture_2 = require("./polling/auto-yes-poller-capture");
|
|
@@ -129,6 +141,8 @@ function incrementErrorCount(compositeKey, owner) {
|
|
|
129
141
|
if (pollerState) {
|
|
130
142
|
pollerState.consecutiveErrors++;
|
|
131
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);
|
|
132
146
|
// Issue #499 Item 5: Auto-stop after consecutive error threshold.
|
|
133
147
|
//
|
|
134
148
|
// Issue #3184: this is the `consecutive-errors` row of AUTO_YES_LIFECYCLE
|
|
@@ -228,207 +242,6 @@ function processStopConditionDelta(compositeKey, pollerState, cleanOutput) {
|
|
|
228
242
|
}
|
|
229
243
|
return false;
|
|
230
244
|
}
|
|
231
|
-
/**
|
|
232
|
-
* Issue #3397: is the fresh capture still the screen the Enter was decided for?
|
|
233
|
-
* Re-reads it the way one tick does — prompt reading, the same `promptFrameKey`,
|
|
234
|
-
* codex's launch dialogs and `/model` picker, the dialog gate refusing with no
|
|
235
|
-
* dialog vouched for, and `judgeEnterFallback` (input box off screen, tool
|
|
236
|
-
* alive, not thinking). The policy and the checkbox rule read `promptData`,
|
|
237
|
-
* which the equal `promptFrameKey` already pins (type, question, options).
|
|
238
|
-
*/
|
|
239
|
-
function isStillEnterFallbackScreen(prompt, fresh) {
|
|
240
|
-
const { worktreeId, cliToolId, instanceId, frameKey } = prompt;
|
|
241
|
-
const clean = (0, cli_patterns_1.stripBoxDrawing)((0, cli_patterns_1.stripAnsi)(fresh));
|
|
242
|
-
const frame = (0, frame_1.normalizeFrame)(fresh, cliToolId);
|
|
243
|
-
const detection = (0, response_checker_1.detectPromptOnCleanFrame)(clean, cliToolId, clean.split('\n'), fresh, { worktreeId, instanceId }, frame);
|
|
244
|
-
if (!detection.isPrompt || !detection.promptData)
|
|
245
|
-
return false;
|
|
246
|
-
if ((0, auto_yes_poller_state_1.promptFrameKey)(detection.promptData) !== frameKey)
|
|
247
|
-
return false;
|
|
248
|
-
if (cliToolId === 'codex' && ((0, cli_patterns_1.getCodexLifecycleDialog)(frame) || (0, detect_1.isCodexModelPickerFrame)(frame))) {
|
|
249
|
-
return false;
|
|
250
|
-
}
|
|
251
|
-
const gate = (0, auto_yes_dialog_gate_1.evaluateAutoYesDialogGate)(cliToolId, detection.promptData.type, frame);
|
|
252
|
-
if (gate.allowed || gate.dialog !== null)
|
|
253
|
-
return false;
|
|
254
|
-
return (0, auto_yes_enter_fallback_1.judgeEnterFallback)(cliToolId, fresh).eligible;
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Issue #3397: a frame the dialog gate refused may still be a choice screen
|
|
258
|
-
* CommandMate cannot read — the one the prompt window offers direct input for.
|
|
259
|
-
* Send ONE Enter there (confirm whatever is selected), under every condition
|
|
260
|
-
* `judgeEnterFallback` and this function check; otherwise record the refusal as
|
|
261
|
-
* step 3.5 always did.
|
|
262
|
-
*
|
|
263
|
-
* Order, each one able to stop the Enter:
|
|
264
|
-
* 1. `judgeEnterFallback` (rollout table, refusal, composer off screen, tool
|
|
265
|
-
* alive, not thinking) — and the gate must not have vouched for a dialog it
|
|
266
|
-
* refused to type into (opencode's `keys` strip, #1893);
|
|
267
|
-
* 2. the screen already had its Enter: record `no-effect`, send nothing;
|
|
268
|
-
* 3. the contract policy, exactly as step 4 applies it (mode, allow-listed
|
|
269
|
-
* types, deny patterns over the question, options and `approvalTarget`);
|
|
270
|
-
* a prompt the base rules would not answer (multi-select, typed text) gets
|
|
271
|
-
* nothing either;
|
|
272
|
-
* 4. the screen must have been eligible on the previous tick as well;
|
|
273
|
-
* 5. the session must be this server's (#2865);
|
|
274
|
-
* 6. a capture taken now, past the capture cache, must still be that screen
|
|
275
|
-
* ({@link isStillEnterFallbackScreen}).
|
|
276
|
-
*
|
|
277
|
-
* Issue #3706: with a `generation` (a tick of `pollAutoYes`), the waits of
|
|
278
|
-
* steps 5 and 6 are each followed by {@link isTickCurrent}; a tick that lost
|
|
279
|
-
* its generation sends nothing and changes nothing.
|
|
280
|
-
*
|
|
281
|
-
* @returns true when the Enter was sent; the caller returns `responded`
|
|
282
|
-
*/
|
|
283
|
-
async function tryEnterFallback(prompt, promptDetection, dialogGate, rawOutput, generation) {
|
|
284
|
-
const { worktreeId, cliToolId, instanceId, pollerState, promptData, frameKey } = prompt;
|
|
285
|
-
const judgement = dialogGate.dialog === null ? (0, auto_yes_enter_fallback_1.judgeEnterFallback)(cliToolId, rawOutput) : null;
|
|
286
|
-
if (judgement === null || !judgement.eligible) {
|
|
287
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
288
|
-
(0, auto_yes_prompt_suppression_1.suppressUnclassifiedFrame)(prompt, dialogGate);
|
|
289
|
-
return false;
|
|
290
|
-
}
|
|
291
|
-
const screenKey = (0, auto_yes_enter_fallback_1.enterFallbackScreenKey)(promptData);
|
|
292
|
-
// 2. The Enter did not move the screen on. Another one would be a guess.
|
|
293
|
-
if (pollerState.enterFallbackSentKey === frameKey) {
|
|
294
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
295
|
-
(0, auto_yes_enter_fallback_1.recordEnterFallbackNoEffect)(worktreeId, cliToolId, instanceId, screenKey);
|
|
296
|
-
(0, auto_yes_prompt_suppression_1.suppressUnclassifiedFrame)(prompt, dialogGate);
|
|
297
|
-
(0, auto_yes_poller_state_1.warnOncePerFrame)(pollerState, `${frameKey}\u0000enter-fallback-no-effect`, 'poller:auto-yes-enter-fallback-no-effect', {
|
|
298
|
-
worktreeId,
|
|
299
|
-
cliToolId,
|
|
300
|
-
instanceId,
|
|
301
|
-
promptType: promptData.type,
|
|
302
|
-
refusalReason: judgement.refusalReason,
|
|
303
|
-
});
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
|
-
// 3. The contract policy, as step 4 reads it (Issue #3822: a failed lookup withholds).
|
|
307
|
-
const policy = (0, auto_yes_policy_1.getSessionAutoYesPolicy)(worktreeId, cliToolId, instanceId);
|
|
308
|
-
const resolution = (0, auto_yes_resolver_1.resolveAutoAnswerWithPolicy)(promptData, policy);
|
|
309
|
-
if (resolution.suppressedBy) {
|
|
310
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
311
|
-
const mode = (0, auto_yes_resolver_1.policyLookupMode)(policy);
|
|
312
|
-
(0, auto_yes_prompt_suppression_1.suppressAndWarnOnce)(prompt, {
|
|
313
|
-
reason: resolution.suppressedBy,
|
|
314
|
-
mode,
|
|
315
|
-
promptType: promptData.type,
|
|
316
|
-
pattern: resolution.pattern,
|
|
317
|
-
}, `${frameKey}\u0000${resolution.suppressedBy}\u0000${mode ?? ''}\u0000${resolution.pattern ?? ''}`, 'poller:auto-yes-suppressed-by-policy', {
|
|
318
|
-
reason: resolution.suppressedBy,
|
|
319
|
-
mode,
|
|
320
|
-
pattern: resolution.pattern,
|
|
321
|
-
promptType: promptData.type,
|
|
322
|
-
enterFallback: true,
|
|
323
|
-
});
|
|
324
|
-
return false;
|
|
325
|
-
}
|
|
326
|
-
// A checkbox list is out of scope whatever the parser's flag says: the
|
|
327
|
-
// labels' boxes (`[ ]` / `[x]` / `[X]` / `[✔]`, the one reading in
|
|
328
|
-
// `prompt-answer-semantic` the sender shares) count too, so an Enter never
|
|
329
|
-
// submits a half-ticked list (Issue #3397; the base rules' #2755 reading
|
|
330
|
-
// covers `multiSelect` only).
|
|
331
|
-
if (resolution.answer === null ||
|
|
332
|
-
(promptData.type === 'multiple_choice' && (0, prompt_answer_semantic_1.isMultiSelectPrompt)(promptData))) {
|
|
333
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
334
|
-
(0, auto_yes_prompt_suppression_1.suppressUnclassifiedFrame)(prompt, dialogGate);
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
337
|
-
// 4. Seen once: wait for the next tick to see the same screen again.
|
|
338
|
-
// Nothing is recorded as withheld here: Auto-Yes is about to answer, and a
|
|
339
|
-
// fresh `lastSuppression` would make `cmate wait` report the prompt to a
|
|
340
|
-
// human at once instead of holding for Auto-Yes (#2463).
|
|
341
|
-
if (pollerState.enterFallbackCandidateKey !== frameKey) {
|
|
342
|
-
pollerState.enterFallbackCandidateKey = frameKey;
|
|
343
|
-
logger.debug('poller:auto-yes-enter-fallback-candidate', {
|
|
344
|
-
worktreeId,
|
|
345
|
-
cliToolId,
|
|
346
|
-
instanceId,
|
|
347
|
-
promptType: promptData.type,
|
|
348
|
-
});
|
|
349
|
-
return false;
|
|
350
|
-
}
|
|
351
|
-
// 5. Never another server's session (Issue #2865).
|
|
352
|
-
const sessionName = manager_1.CLIToolManager.getInstance().getTool(cliToolId).getSessionName(worktreeId, instanceId);
|
|
353
|
-
const ownership = await (0, worktree_session_ownership_1.checkWorktreeSessionOwnership)(worktreeId, sessionName);
|
|
354
|
-
if (generation !== undefined && !(0, auto_yes_poller_generation_1.isTickCurrent)(generation))
|
|
355
|
-
return false;
|
|
356
|
-
if (ownership === null || ownership.verdict === 'foreign') {
|
|
357
|
-
// Issue #3820: the ledger's own reason, as `skippedForUnownedSession` records it.
|
|
358
|
-
(0, auto_yes_confirmation_ledger_1.withholdLedgerConfirmation)(prompt, 'foreign-session');
|
|
359
|
-
(0, auto_yes_poller_state_1.warnOncePerFrame)(pollerState, `${frameKey}\u0000${sessionName}\u0000${ownership ? 'foreign' : 'worktree_not_found'}`, 'poller:auto-yes-skipped-foreign-session', {
|
|
360
|
-
worktreeId,
|
|
361
|
-
cliToolId,
|
|
362
|
-
instanceId,
|
|
363
|
-
sessionName,
|
|
364
|
-
sessionPath: ownership?.sessionPath ?? null,
|
|
365
|
-
reason: ownership ? 'foreign' : 'worktree_not_found',
|
|
366
|
-
enterFallback: true,
|
|
367
|
-
});
|
|
368
|
-
return false;
|
|
369
|
-
}
|
|
370
|
-
// 6. The last look before the key, at a capture taken NOW. The two ticks of
|
|
371
|
-
// step 4 read through the capture cache, whose TTL is longer than the poll
|
|
372
|
-
// interval, so "seen twice" can be one stale frame read twice: a redraw caught
|
|
373
|
-
// with its input box missing (#2457's repaint) while the real pane already
|
|
374
|
-
// has the box back. Everything that decided the Enter is judged again on the
|
|
375
|
-
// fresh frame; any difference sends nothing, and the next tick starts over.
|
|
376
|
-
const fresh = await (0, cli_session_1.captureSessionOutputFresh)(worktreeId, cliToolId, (rawOutput ?? '').split('\n').length, instanceId);
|
|
377
|
-
if (generation !== undefined && !(0, auto_yes_poller_generation_1.isTickCurrent)(generation))
|
|
378
|
-
return false;
|
|
379
|
-
if (!isStillEnterFallbackScreen(prompt, fresh)) {
|
|
380
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
381
|
-
logger.debug('poller:auto-yes-enter-fallback-fresh-frame-differs', {
|
|
382
|
-
worktreeId,
|
|
383
|
-
cliToolId,
|
|
384
|
-
instanceId,
|
|
385
|
-
promptType: promptData.type,
|
|
386
|
-
});
|
|
387
|
-
return false;
|
|
388
|
-
}
|
|
389
|
-
const receiptEpisode = (0, auto_yes_poller_receipt_log_1.receiptEpisodeOfSend)(cliToolId, worktreeId, instanceId);
|
|
390
|
-
// Issue #3820: taken before the await, so the result goes to this confirmation.
|
|
391
|
-
const ledgerAttempt = (0, auto_yes_confirmation_ledger_1.beginLedgerAttempt)(prompt, 'enter-fallback');
|
|
392
|
-
try {
|
|
393
|
-
await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
|
|
394
|
-
}
|
|
395
|
-
catch (error) {
|
|
396
|
-
// Issue #3796: the Enter may or may not have reached the pane.
|
|
397
|
-
(0, auto_yes_poller_receipt_log_1.noteAnswerSent)(cliToolId, worktreeId, instanceId, true, receiptEpisode);
|
|
398
|
-
(0, auto_yes_confirmation_ledger_1.settleLedgerAttempt)(ledgerAttempt, 'failed');
|
|
399
|
-
throw error;
|
|
400
|
-
}
|
|
401
|
-
finally {
|
|
402
|
-
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
403
|
-
}
|
|
404
|
-
// Issue #3796 review E: the Enter is out — for the episode it began for only.
|
|
405
|
-
(0, auto_yes_poller_receipt_log_1.noteAnswerSent)(cliToolId, worktreeId, instanceId, false, receiptEpisode);
|
|
406
|
-
(0, auto_yes_confirmation_ledger_1.settleLedgerAttempt)(ledgerAttempt, 'ok');
|
|
407
|
-
// Issue #3706: the Enter is out, but the per-screen record is the CURRENT
|
|
408
|
-
// session's: when the poller was stopped (the record was forgotten with it)
|
|
409
|
-
// or a new session began while `send-keys` was awaited, the return of this
|
|
410
|
-
// send must not put the record back. The audit row below is kept either way.
|
|
411
|
-
if (generation === undefined || ((0, auto_yes_poller_generation_1.isPollerCurrent)(generation) && (0, auto_yes_poller_generation_1.isSameSession)(generation))) {
|
|
412
|
-
pollerState.enterFallbackSentKey = frameKey;
|
|
413
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
414
|
-
(0, auto_yes_enter_fallback_1.recordEnterFallbackSent)(worktreeId, cliToolId, instanceId, {
|
|
415
|
-
promptType: promptData.type,
|
|
416
|
-
refusalReason: judgement.refusalReason,
|
|
417
|
-
screenKey,
|
|
418
|
-
...(generation !== undefined ? { epoch: generation.sessionEpoch } : {}),
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
logger.info('poller:auto-yes-enter-fallback-sent', {
|
|
422
|
-
worktreeId,
|
|
423
|
-
cliToolId,
|
|
424
|
-
instanceId,
|
|
425
|
-
promptType: promptData.type,
|
|
426
|
-
refusalReason: judgement.refusalReason,
|
|
427
|
-
composerState: judgement.composerState,
|
|
428
|
-
});
|
|
429
|
-
await finishAnsweredPrompt(prompt, promptDetection, auto_yes_poller_enter_fallback_1.AUTO_YES_ENTER_FALLBACK_ANSWER, generation);
|
|
430
|
-
return true;
|
|
431
|
-
}
|
|
432
245
|
/**
|
|
433
246
|
* Issue #3214: steps 6 and 7 of `detectAndRespondToPrompt` and everything after
|
|
434
247
|
* them -- what is done once the answer has reached tmux, in the order it always
|
|
@@ -444,8 +257,11 @@ async function tryEnterFallback(prompt, promptDetection, dialogGate, rawOutput,
|
|
|
444
257
|
* tick's own poller state only, never to a successor under the same key, and
|
|
445
258
|
* the response poller restart and the terminal push are skipped when the
|
|
446
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`)
|
|
447
263
|
*/
|
|
448
|
-
async function finishAnsweredPrompt(prompt, promptDetection, answer, generation) {
|
|
264
|
+
async function finishAnsweredPrompt(prompt, promptDetection, answer, generation, capture) {
|
|
449
265
|
const { worktreeId, cliToolId, instanceId, compositeKey, pollerState, promptData, promptKey } = prompt;
|
|
450
266
|
// Issue #3706: the keys went to the session the tick started on. When a new
|
|
451
267
|
// one was begun while they were being sent, the new process never received
|
|
@@ -466,7 +282,7 @@ async function finishAnsweredPrompt(prompt, promptDetection, answer, generation)
|
|
|
466
282
|
}
|
|
467
283
|
// Issue #3748: what was answered and with what — the question (cut to
|
|
468
284
|
// MAX_LOGGED_QUESTION_LENGTH, never the full text) and the answer sent (the
|
|
469
|
-
// option number
|
|
285
|
+
// option number or `y`) — so an answer that should not have been
|
|
470
286
|
// given can be told from the log alone.
|
|
471
287
|
logger.info('poller:response-sent', {
|
|
472
288
|
worktreeId,
|
|
@@ -496,7 +312,10 @@ async function finishAnsweredPrompt(prompt, promptDetection, answer, generation)
|
|
|
496
312
|
worktreeId,
|
|
497
313
|
cliToolId,
|
|
498
314
|
instanceId: instanceId ?? cliToolId,
|
|
499
|
-
|
|
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),
|
|
500
319
|
answer,
|
|
501
320
|
answeredBy: 'auto',
|
|
502
321
|
content: promptDetection.rawContent || promptDetection.cleanContent,
|
|
@@ -539,111 +358,15 @@ async function finishAnsweredPrompt(prompt, promptDetection, answer, generation)
|
|
|
539
358
|
void broadcastTerminalSnapshotAfterInteraction(worktreeId, cliToolId, instanceId);
|
|
540
359
|
}
|
|
541
360
|
/**
|
|
542
|
-
*
|
|
543
|
-
*
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
// Issue #3183: the ONE frame every judgement below reads — normalised once,
|
|
548
|
-
// from the capture as captured (the input-box markers are rule rows the
|
|
549
|
-
// cleaned spelling has blanked), and handed as the same object to the
|
|
550
|
-
// prompt reading, the codex launch guards and the dialog gate. That is what
|
|
551
|
-
// makes "the status chain and Auto-Yes read the same live region" a fact
|
|
552
|
-
// rather than a hope: there is no second normalisation to disagree with.
|
|
553
|
-
const frame = (0, frame_1.normalizeFrame)(rawOutput ?? cleanOutput, cliToolId);
|
|
554
|
-
// Issue #3767: bracket the read so the receipt gate can tell when an agy
|
|
555
|
-
// dialog first appeared, not only what time this tick is.
|
|
556
|
-
if (cliToolId === 'antigravity')
|
|
557
|
-
(0, antigravity_receipt_episodes_1.beginAntigravityFrameRead)(worktreeId, instanceId);
|
|
558
|
-
const promptDetection = (0, response_checker_1.detectPromptOnCleanFrame)(cleanOutput, cliToolId, precomputedLines, rawOutput, receiptScope, frame);
|
|
559
|
-
if (cliToolId === 'antigravity')
|
|
560
|
-
(0, antigravity_receipt_episodes_1.endAntigravityFrameRead)(worktreeId, instanceId);
|
|
561
|
-
return { frame, promptDetection };
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* What `detectAndRespondToPrompt` does to the poller state on a frame with no
|
|
565
|
-
* prompt to answer, before it returns `no_prompt`.
|
|
566
|
-
*/
|
|
567
|
-
function noteNoPromptOnScreen(tick) {
|
|
568
|
-
const { worktreeId, cliToolId, instanceId, compositeKey, pollerState, frame, promptDetection, cleanOutput, precomputedLines, rawOutput, } = tick;
|
|
569
|
-
(0, auto_yes_poller_state_1.forgetPartialAnswer)(compositeKey);
|
|
570
|
-
pollerState.lastAnsweredPromptKey = null;
|
|
571
|
-
pollerState.lastAnsweredAt = null;
|
|
572
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
573
|
-
// Issue #3757: agy's trust screen reads as no prompt (unnumbered: neither
|
|
574
|
-
// reader takes it), but it is one nobody here answers — record why, still
|
|
575
|
-
// as `no_prompt`. Before the warn key is cleared, so the WARN stays once
|
|
576
|
-
// per screen.
|
|
577
|
-
// Issue #3820: the trust screen records itself in the ledger when it records
|
|
578
|
-
// its reason (`suppressAntigravityTrustScreen`).
|
|
579
|
-
if (cliToolId === 'antigravity' &&
|
|
580
|
-
(0, auto_yes_prompt_suppression_1.suppressAntigravityTrustScreen)(worktreeId, instanceId, pollerState, frame, manager_1.CLIToolManager.getInstance().getTool(cliToolId).getSessionName(worktreeId, instanceId))) {
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
pollerState.lastSkipWarnKey = null;
|
|
584
|
-
if (cliToolId === 'antigravity' && !promptDetection.isPrompt) {
|
|
585
|
-
const seen = (0, auto_yes_poller_receipt_log_1.logIfWithheldForWantOfReceipt)(worktreeId, instanceId, compositeKey, () => (0, response_checker_1.detectPromptOnCleanFrame)(cleanOutput, cliToolId, precomputedLines, rawOutput));
|
|
586
|
-
// Issue #3820: past the receipt window the gated reading says "no prompt"
|
|
587
|
-
// while the dialog is still up. The ungated reading says it is, so the
|
|
588
|
-
// ledger keeps the same confirmation (and the same withheld interval)
|
|
589
|
-
// rather than closing it on every tick outside the window.
|
|
590
|
-
if (seen !== null) {
|
|
591
|
-
const scope = { compositeKey, worktreeId, cliToolId, instanceId };
|
|
592
|
-
(0, auto_yes_confirmation_ledger_1.observeLedgerScreen)(scope, (0, auto_yes_poller_state_1.ledgerScreenKey)(seen.promptData), seen.promptData.type, ledgerCallOf(cliToolId, worktreeId, instanceId));
|
|
593
|
-
if (seen.reason !== null)
|
|
594
|
-
(0, auto_yes_confirmation_ledger_1.withholdLedgerConfirmation)(scope, seen.reason);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
/**
|
|
599
|
-
* Issue #3820 (design §2.4, PR 3): the agy call the receipt episode on screen
|
|
600
|
-
* was accepted for, for the ledger to tie the confirmation to. Asked after the
|
|
601
|
-
* frame was judged; read only to record, and never throws.
|
|
602
|
-
*/
|
|
603
|
-
function ledgerCallOf(cliToolId, worktreeId, instanceId) {
|
|
604
|
-
if (cliToolId !== 'antigravity')
|
|
605
|
-
return {};
|
|
606
|
-
try {
|
|
607
|
-
const callId = (0, antigravity_receipt_episodes_1.getAntigravityAcceptedReceiptCallId)(worktreeId, instanceId);
|
|
608
|
-
return callId === null ? {} : { callId };
|
|
609
|
-
}
|
|
610
|
-
catch {
|
|
611
|
-
// Recording only: a failure here ties nothing and changes nothing else.
|
|
612
|
-
return {};
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
/**
|
|
616
|
-
* Issue #3820: the result of a send that threw, as the ledger counts it.
|
|
617
|
-
* `keysSent` is what the sender said (#3706); a throw that says nothing is a
|
|
618
|
-
* failure whose keys may or may not be on the pane.
|
|
619
|
-
*/
|
|
620
|
-
function attemptResultOfThrow(keysSent) {
|
|
621
|
-
if (keysSent === true)
|
|
622
|
-
return 'partial';
|
|
623
|
-
if (keysSent === false)
|
|
624
|
-
return 'no-keys-sent';
|
|
625
|
-
return 'failed';
|
|
626
|
-
}
|
|
627
|
-
/**
|
|
628
|
-
* Issue #3820: the evidence an answer on the screen path is given on (design
|
|
629
|
-
* §7 PR 1). A tool's own dialog detector vouched for the frame: `L3`. The
|
|
630
|
-
* gate did not judge it (a `legacy` tool, a non-multiple-choice prompt): the
|
|
631
|
-
* generic reading alone, `L4`.
|
|
632
|
-
*
|
|
633
|
-
* agy's gate is `legacy` (`gated: false`), yet its prompts are read by its own
|
|
634
|
-
* reader first (`detectPromptOnCleanFrame` returns that reader's result
|
|
635
|
-
* whenever it reads the frame). Which reader it was is not on the detection
|
|
636
|
-
* result, so it is asked of the same reader on the same text here — for the
|
|
637
|
-
* label only; the answer was decided before this is called. Read by agy's own
|
|
638
|
-
* reader, and through the receipt gate (the tick's reading carried the
|
|
639
|
-
* receipt scope): `L3`, with `receiptAccepted` on the attempt.
|
|
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.
|
|
640
366
|
*/
|
|
641
|
-
function
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
645
|
-
const gate = prompt.dialogGate;
|
|
646
|
-
return gate !== undefined && gate.gated && gate.allowed && gate.dialog !== null ? 'L3' : 'L4';
|
|
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);
|
|
647
370
|
}
|
|
648
371
|
/**
|
|
649
372
|
* The `catch` of `detectAndRespondToPrompt`: settles the send in flight and
|
|
@@ -652,10 +375,17 @@ function answerBasisOf(prompt, cleanOutput) {
|
|
|
652
375
|
function settleFailedTick(error, tick) {
|
|
653
376
|
const { worktreeId, cliToolId, instanceId, compositeKey, generation, attempt, sendInFlight, receiptEpisode } = tick;
|
|
654
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';
|
|
655
385
|
// Issue #3820: the send that was cut short, in the ledger — before the send
|
|
656
386
|
// record below is settled, whose state says whether it had expired.
|
|
657
387
|
if (attempt !== null && sendInFlight) {
|
|
658
|
-
(0, auto_yes_confirmation_ledger_1.settleLedgerAttempt)(attempt.ledger, attemptResultOfThrow(keysSent), { expired: attempt.state === 'expired' });
|
|
388
|
+
(0, auto_yes_confirmation_ledger_1.settleLedgerAttempt)(attempt.ledger, (0, auto_yes_poller_tick_1.attemptResultOfThrow)(keysSent), { expired: attempt.state === 'expired' });
|
|
659
389
|
}
|
|
660
390
|
// Issue #3706: a tick that lost its generation — the send stopped part-way
|
|
661
391
|
// (`PromptAnswerAbortedError`), or failed after the grant went — is not a
|
|
@@ -665,18 +395,22 @@ function settleFailedTick(error, tick) {
|
|
|
665
395
|
// answer again over them (step 2.5). Recorded under the attempt's key as
|
|
666
396
|
// it is now — the new one when a worktree ID move carried it (#3713).
|
|
667
397
|
if (attempt !== null)
|
|
668
|
-
(0, auto_yes_poller_state_1.settleSendAttempt)(attempt,
|
|
398
|
+
(0, auto_yes_poller_state_1.settleSendAttempt)(attempt, mayBeOnPane);
|
|
669
399
|
if (sendInFlight)
|
|
670
400
|
(0, auto_yes_poller_receipt_log_1.noteAnswerSent)(cliToolId, worktreeId, instanceId, true, receiptEpisode);
|
|
671
|
-
logger.info('poller:auto-yes-answer-abandoned', { worktreeId, cliToolId, instanceId, keysSent });
|
|
401
|
+
logger.info('poller:auto-yes-answer-abandoned', { worktreeId, cliToolId, instanceId, keysSent, delivery });
|
|
672
402
|
return 'no_answer';
|
|
673
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).
|
|
674
408
|
if (attempt !== null)
|
|
675
|
-
(0, auto_yes_poller_state_1.settleSendAttempt)(attempt,
|
|
409
|
+
(0, auto_yes_poller_state_1.settleSendAttempt)(attempt, mayBeOnPane);
|
|
676
410
|
if (sendInFlight)
|
|
677
411
|
(0, auto_yes_poller_receipt_log_1.noteAnswerSent)(cliToolId, worktreeId, instanceId, true, receiptEpisode);
|
|
678
412
|
incrementErrorCount(compositeKey, generation?.pollerState);
|
|
679
|
-
logger.warn('poller:detect-respond-error', { worktreeId, cliToolId, instanceId });
|
|
413
|
+
logger.warn('poller:detect-respond-error', { worktreeId, cliToolId, instanceId, delivery });
|
|
680
414
|
return 'error';
|
|
681
415
|
}
|
|
682
416
|
/**
|
|
@@ -693,14 +427,33 @@ function settleFailedTick(error, tick) {
|
|
|
693
427
|
* (Issue #2522). Omitting it costs Command Code's `AskUserQuestion` and
|
|
694
428
|
* nothing else; see {@link capturePollerFrame}.
|
|
695
429
|
* @param generation - The calling tick's generation (Issue #3706). Given, every
|
|
696
|
-
* wait before a key — the ownership check
|
|
697
|
-
*
|
|
430
|
+
* wait before a key — the ownership check and each wait inside the send — is
|
|
431
|
+
* followed by {@link isTickCurrent}, and a tick
|
|
698
432
|
* that lost it types nothing more and returns `no_answer`. Omitted (direct
|
|
699
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.
|
|
700
448
|
* @returns 'responded' | 'no_prompt' | 'duplicate' | 'no_answer' | 'error'
|
|
701
449
|
*/
|
|
702
|
-
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) {
|
|
703
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
|
+
};
|
|
704
457
|
// Issue #3706 / #3713: the send in flight, settled without an await once it
|
|
705
458
|
// comes back — as a partial answer when it was stopped with keys on the pane.
|
|
706
459
|
let attempt = null;
|
|
@@ -710,8 +463,19 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
710
463
|
let receiptEpisode = null;
|
|
711
464
|
// Issue #3820: the ledger's tick. A tick that read the screen and saw no
|
|
712
465
|
// confirmation closes the open one as gone when it ends (`endLedgerTick`).
|
|
713
|
-
|
|
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 };
|
|
714
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;
|
|
715
479
|
try {
|
|
716
480
|
// 1. Detect prompt.
|
|
717
481
|
//
|
|
@@ -753,20 +517,38 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
753
517
|
// such a machine's dialogs alone, which is why `logIfWithheldForWantOfReceipt`
|
|
754
518
|
// says so.
|
|
755
519
|
const epoch = (0, auto_yes_poller_enter_fallback_1.syncEnterFallbackEpoch)(compositeKey, pollerState);
|
|
756
|
-
const { frame, promptDetection } = readPromptFrame(worktreeId, cliToolId, cleanOutput, precomputedLines, instanceId, rawOutput);
|
|
520
|
+
const { frame, promptDetection } = (0, auto_yes_poller_tick_1.readPromptFrame)(worktreeId, cliToolId, cleanOutput, precomputedLines, instanceId, rawOutput, captureExtent, response_checker_1.detectPromptOnCleanFrame);
|
|
757
521
|
if (!promptDetection.isPrompt || !promptDetection.promptData) {
|
|
758
|
-
|
|
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)({
|
|
759
526
|
worktreeId,
|
|
760
527
|
cliToolId,
|
|
761
528
|
instanceId,
|
|
762
529
|
compositeKey,
|
|
530
|
+
epoch,
|
|
763
531
|
pollerState,
|
|
764
532
|
frame,
|
|
765
533
|
promptDetection,
|
|
766
534
|
cleanOutput,
|
|
767
535
|
precomputedLines,
|
|
768
536
|
rawOutput,
|
|
537
|
+
captureExtent,
|
|
538
|
+
detectPromptOnCleanFrame: response_checker_1.detectPromptOnCleanFrame,
|
|
769
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);
|
|
551
|
+
}
|
|
770
552
|
return 'no_prompt';
|
|
771
553
|
}
|
|
772
554
|
// Issue #3820: computed here, before the duplicate check, so the ledger
|
|
@@ -776,16 +558,43 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
776
558
|
// that differ by a `>` or an indent are two confirmations to count.
|
|
777
559
|
const screenKey = (0, auto_yes_poller_state_1.partialAnswerScreenKey)(promptDetection.promptData);
|
|
778
560
|
// agy (PR 3): tied to the call the receipt that let it through asked about.
|
|
779
|
-
(0, auto_yes_confirmation_ledger_1.observeLedgerScreen)(ledgerScope, (0, auto_yes_poller_state_1.ledgerScreenKey)(promptDetection.promptData), promptDetection.promptData.type, ledgerCallOf(cliToolId, worktreeId, instanceId));
|
|
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
|
+
}
|
|
780
580
|
// 2. Check for duplicate prompt (Issue #306)
|
|
781
581
|
const promptKey = (0, prompt_key_1.generatePromptKey)(promptDetection.promptData);
|
|
782
582
|
const frameKey = (0, auto_yes_poller_state_1.promptFrameKey)(promptDetection.promptData);
|
|
783
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;
|
|
784
587
|
// Issue #3820: not answered on this tick either — an interval of its own
|
|
785
588
|
// reason, so the count can tell the wait for an answer to land apart.
|
|
786
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();
|
|
787
592
|
return 'duplicate';
|
|
788
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);
|
|
789
598
|
const judged = {
|
|
790
599
|
worktreeId,
|
|
791
600
|
cliToolId,
|
|
@@ -795,6 +604,11 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
795
604
|
promptData: promptDetection.promptData,
|
|
796
605
|
promptKey,
|
|
797
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,
|
|
798
612
|
};
|
|
799
613
|
// 2.5. Issue #3706: an earlier answer to this prompt was stopped after some
|
|
800
614
|
// of its keys reached the pane (a `y` whose Enter was withheld). Typing the
|
|
@@ -805,26 +619,36 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
805
619
|
// does not), or the session is relaunched. Recorded as a suppression, so
|
|
806
620
|
// the prompt Push and `cmate wait` see "withheld", not "answering".
|
|
807
621
|
if ((0, auto_yes_poller_steps_1.withheldForEarlierSend)(judged, screenKey, epoch)) {
|
|
622
|
+
decision.withheld('moved-send-in-flight');
|
|
808
623
|
return 'no_answer';
|
|
809
624
|
}
|
|
810
625
|
// 3., 3.2., 3.5. Frames that are not Auto-Yes's to answer: see
|
|
811
626
|
// `suppressIfNotOursToAnswer`.
|
|
812
627
|
const notOurs = (0, auto_yes_prompt_suppression_1.suppressIfNotOursToAnswer)(judged, frame);
|
|
813
|
-
if (notOurs.kind !== 'dialog-gate-refused') {
|
|
814
|
-
pollerState.enterFallbackCandidateKey = null;
|
|
815
|
-
}
|
|
816
628
|
if (notOurs.kind === 'left-alone') {
|
|
629
|
+
decision.withheld('unclassified-frame');
|
|
817
630
|
return 'no_answer';
|
|
818
631
|
}
|
|
819
|
-
// 3.6.
|
|
820
|
-
//
|
|
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.
|
|
821
636
|
if (notOurs.kind === 'dialog-gate-refused') {
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
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';
|
|
826
647
|
}
|
|
827
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`).
|
|
828
652
|
// Auto-Yes reads the frame itself instead of going through status-detector
|
|
829
653
|
// (it shares the reader, not the verdict), so this is the only place the policy can gate an
|
|
830
654
|
// auto-answer: a prompt the policy withholds is left for a human, and the
|
|
@@ -832,6 +656,7 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
832
656
|
// polling/response-checker.ts) is what tells them it is waiting.
|
|
833
657
|
const answer = (0, auto_yes_poller_steps_1.resolveAnswerUnderPolicy)(judged);
|
|
834
658
|
if (answer === null) {
|
|
659
|
+
decision.withheld(auto_yes_decision_1.NO_AUTO_ANSWER_DECISION_REASON);
|
|
835
660
|
return 'no_answer';
|
|
836
661
|
}
|
|
837
662
|
// 5. Send answer to tmux (Issue #896: resolve the instance-specific session)
|
|
@@ -844,14 +669,26 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
844
669
|
if (generation !== undefined && !(0, auto_yes_poller_generation_1.isTickCurrent)(generation))
|
|
845
670
|
return 'no_answer';
|
|
846
671
|
if ((0, auto_yes_poller_steps_1.skippedForUnownedSession)(judged, sessionName, ownership)) {
|
|
672
|
+
decision.withheld('foreign-session');
|
|
673
|
+
return 'no_answer';
|
|
674
|
+
}
|
|
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);
|
|
847
680
|
return 'no_answer';
|
|
848
681
|
}
|
|
682
|
+
// Issue #3821: from here until the screen is redrawn, Auto-Yes is answering.
|
|
683
|
+
decision.answering();
|
|
849
684
|
attempt = (0, auto_yes_poller_state_1.beginSendAttempt)(compositeKey, screenKey, generation?.sessionEpoch ?? epoch,
|
|
850
685
|
// Issue #3820: an agy prompt read past the gate is one a hook receipt let through.
|
|
851
|
-
(0, auto_yes_confirmation_ledger_1.beginLedgerAttempt)(ledgerScope, answerBasisOf(judged, cleanOutput), {
|
|
686
|
+
(0, auto_yes_confirmation_ledger_1.beginLedgerAttempt)(ledgerScope, (0, auto_yes_poller_tick_1.answerBasisOf)(judged, cleanOutput), {
|
|
852
687
|
receiptAccepted: cliToolId === 'antigravity',
|
|
853
688
|
}));
|
|
854
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);
|
|
855
692
|
sendInFlight = true;
|
|
856
693
|
try {
|
|
857
694
|
await (0, prompt_answer_sender_1.sendPromptAnswer)({
|
|
@@ -871,11 +708,27 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
871
708
|
(0, auto_yes_poller_state_1.settleSendAttempt)(attempt, false);
|
|
872
709
|
// Issue #3796 review E: the episode the send began for, as on the failure side.
|
|
873
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
|
+
}
|
|
874
719
|
// 6., 7. The answer reached tmux: see `finishAnsweredPrompt`.
|
|
875
|
-
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
|
+
});
|
|
876
725
|
return 'responded';
|
|
877
726
|
}
|
|
878
727
|
catch (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);
|
|
879
732
|
return settleFailedTick(error, {
|
|
880
733
|
worktreeId,
|
|
881
734
|
cliToolId,
|
|
@@ -889,6 +742,8 @@ async function detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, clea
|
|
|
889
742
|
}
|
|
890
743
|
finally {
|
|
891
744
|
(0, auto_yes_confirmation_ledger_1.endLedgerTick)(ledgerScope, ledgerTick);
|
|
745
|
+
if (!keepDuplicateRetry)
|
|
746
|
+
(0, auto_yes_poller_generation_1.releaseDuplicateRetry)(pollerState);
|
|
892
747
|
}
|
|
893
748
|
}
|
|
894
749
|
/**
|
|
@@ -923,11 +778,15 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
923
778
|
grant,
|
|
924
779
|
sessionEpoch: (0, auto_yes_enter_fallback_1.getEnterFallbackSessionEpoch)(compositeKey),
|
|
925
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),
|
|
926
783
|
};
|
|
927
784
|
// Issue #3796: this is the session wait's tick (it was scheduled as one) —
|
|
928
785
|
// recorded before anything can fail, for the push gate.
|
|
929
786
|
if (pollerState.sessionWaitTickAt !== undefined)
|
|
930
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);
|
|
931
790
|
try {
|
|
932
791
|
// 2. Capture and clean output
|
|
933
792
|
const captureLines = grant.stopPattern
|
|
@@ -937,7 +796,10 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
937
796
|
// step below exactly as it did; the raw one is carried to the prompt reading
|
|
938
797
|
// so a dialog anchored on box drawing is not invisible to the one path that
|
|
939
798
|
// can answer it without a human.
|
|
940
|
-
|
|
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));
|
|
941
803
|
if (!(0, auto_yes_poller_generation_1.isTickCurrent)(generation)) {
|
|
942
804
|
endStaleTick(generation);
|
|
943
805
|
return;
|
|
@@ -954,7 +816,10 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
954
816
|
return;
|
|
955
817
|
}
|
|
956
818
|
// 4. Detect and respond to prompt
|
|
957
|
-
const result = await detectAndRespondToPrompt(worktreeId, pollerState, cliToolId, cleanOutput, lines, instanceId, rawOutput, generation
|
|
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);
|
|
958
823
|
if (!(0, auto_yes_poller_generation_1.isTickCurrent)(generation)) {
|
|
959
824
|
endStaleTick(generation);
|
|
960
825
|
return;
|
|
@@ -972,6 +837,15 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
972
837
|
}
|
|
973
838
|
// 5. Thinking check
|
|
974
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
|
+
});
|
|
975
849
|
const recentLines = lines.slice(-auto_yes_state_1.THINKING_CHECK_LINE_COUNT).join('\n');
|
|
976
850
|
if ((0, cli_patterns_1.detectThinking)(cliToolId, recentLines)) {
|
|
977
851
|
scheduleNextPoll(generation, auto_yes_config_1.THINKING_POLLING_INTERVAL_MS);
|
|
@@ -984,12 +858,24 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
984
858
|
// the session it answers for (`auto-yes-lifecycle`), and `send --auto-yes`
|
|
985
859
|
// enables it before the session starts — so wait until `expiresAt`, at the
|
|
986
860
|
// backoff cap, instead of counting toward `consecutive_errors`.
|
|
987
|
-
const sessionMissing = await isSessionMissing(worktreeId, cliToolId, instanceId);
|
|
861
|
+
const sessionMissing = await (0, auto_yes_poller_session_presence_1.isSessionMissing)(worktreeId, cliToolId, instanceId);
|
|
988
862
|
if (!(0, auto_yes_poller_generation_1.isTickCurrent)(generation)) {
|
|
989
863
|
endStaleTick(generation);
|
|
990
864
|
return;
|
|
991
865
|
}
|
|
992
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
|
+
});
|
|
993
879
|
if (!pollerState.waitingForSession) {
|
|
994
880
|
pollerState.waitingForSession = true;
|
|
995
881
|
logger.info('poller:waiting-for-session', { worktreeId, cliToolId, instanceId });
|
|
@@ -1003,17 +889,108 @@ async function pollAutoYes(worktreeId, cliToolId, instanceId, owner) {
|
|
|
1003
889
|
scheduleNextPoll(generation);
|
|
1004
890
|
}
|
|
1005
891
|
/**
|
|
1006
|
-
*
|
|
1007
|
-
* (Issue #
|
|
1008
|
-
*
|
|
1009
|
-
*
|
|
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.
|
|
1010
952
|
*/
|
|
1011
|
-
|
|
953
|
+
function observeWaitingFromTick(tick) {
|
|
954
|
+
const { worktreeId, cliToolId, instanceId } = tick;
|
|
1012
955
|
try {
|
|
1013
|
-
|
|
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
|
+
});
|
|
1014
986
|
}
|
|
1015
|
-
catch {
|
|
1016
|
-
|
|
987
|
+
catch (error) {
|
|
988
|
+
logger.debug('poller:waiting-observation-failed', {
|
|
989
|
+
worktreeId,
|
|
990
|
+
cliToolId,
|
|
991
|
+
instanceId,
|
|
992
|
+
error: (0, errors_1.getErrorMessage)(error),
|
|
993
|
+
});
|
|
1017
994
|
}
|
|
1018
995
|
}
|
|
1019
996
|
/**
|
|
@@ -1179,6 +1156,8 @@ function stopAutoYesPolling(compositeKey, reason) {
|
|
|
1179
1156
|
// cleanup call this for an instance whose poller may already be gone, and the
|
|
1180
1157
|
// Enter record must not outlive the grant or the session either way.
|
|
1181
1158
|
(0, auto_yes_enter_fallback_1.forgetEnterFallback)(compositeKey);
|
|
1159
|
+
// Issue #3821: and the decision, for the same reason.
|
|
1160
|
+
(0, auto_yes_decision_state_1.forgetAutoYesDecision)(compositeKey);
|
|
1182
1161
|
// Issue #3820: before the early return too — a session ended after its
|
|
1183
1162
|
// poller had already stopped still abandons the confirmation left on it.
|
|
1184
1163
|
(0, auto_yes_confirmation_ledger_1.noteLedgerPollerStopped)(compositeKey, (0, auto_yes_poller_stop_reason_1.resolvePollerStopReason)(reason, 'unspecified'));
|
|
@@ -1214,18 +1193,9 @@ function stopAllAutoYesPolling() {
|
|
|
1214
1193
|
}
|
|
1215
1194
|
auto_yes_poller_generation_1.autoYesPollerStates.clear();
|
|
1216
1195
|
(0, auto_yes_enter_fallback_1.clearEnterFallbacks)();
|
|
1196
|
+
(0, auto_yes_decision_state_1.clearAutoYesDecisions)();
|
|
1217
1197
|
(0, auto_yes_poller_state_1.clearPartialAnswers)();
|
|
1218
1198
|
}
|
|
1219
|
-
/**
|
|
1220
|
-
* Get all composite keys that have active auto-yes poller entries.
|
|
1221
|
-
*
|
|
1222
|
-
* Issue #525: Returns composite keys (worktreeId:cliToolId).
|
|
1223
|
-
*
|
|
1224
|
-
* @returns Array of composite keys present in the autoYesPollerStates Map
|
|
1225
|
-
*/
|
|
1226
|
-
function getAutoYesPollerCompositeKeys() {
|
|
1227
|
-
return Array.from(auto_yes_poller_generation_1.autoYesPollerStates.keys());
|
|
1228
|
-
}
|
|
1229
1199
|
// =============================================================================
|
|
1230
1200
|
// byWorktree Helpers (Issue #525)
|
|
1231
1201
|
// =============================================================================
|
|
@@ -1248,19 +1218,10 @@ function stopAutoYesPollingByWorktree(worktreeId, options) {
|
|
|
1248
1218
|
pollerKeys.forEach(key => stopAutoYesPolling(key, options?.reason));
|
|
1249
1219
|
// Issue #3397: and the records of instances whose poller had already stopped.
|
|
1250
1220
|
(0, auto_yes_enter_fallback_1.forgetEnterFallbacksByWorktree)(worktreeId);
|
|
1221
|
+
(0, auto_yes_decision_state_1.forgetAutoYesDecisionsByWorktree)(worktreeId);
|
|
1251
1222
|
// Issue #3820: and the ledger's confirmations on them — an API approval is
|
|
1252
1223
|
// opened with Auto-Yes off too, so the running pollers do not name them all.
|
|
1253
1224
|
(0, auto_yes_confirmation_ledger_1.noteLedgerWorktreeStopped)(worktreeId, (0, auto_yes_poller_stop_reason_1.resolvePollerStopReason)(options?.reason, 'unspecified'));
|
|
1254
1225
|
if (!options?.keepPartialAnswers)
|
|
1255
1226
|
(0, auto_yes_poller_state_1.forgetPartialAnswersByWorktree)(worktreeId);
|
|
1256
1227
|
}
|
|
1257
|
-
/**
|
|
1258
|
-
* Check if any auto-yes poller is active for a given worktreeId.
|
|
1259
|
-
* Uses shared filterCompositeKeysByWorktree (DRY).
|
|
1260
|
-
*
|
|
1261
|
-
* @param worktreeId - Worktree identifier
|
|
1262
|
-
* @returns true if any poller is active for this worktree
|
|
1263
|
-
*/
|
|
1264
|
-
function isAnyPollerActiveForWorktree(worktreeId) {
|
|
1265
|
-
return (0, auto_yes_state_1.filterCompositeKeysByWorktree)(Array.from(auto_yes_poller_generation_1.autoYesPollerStates.keys()), worktreeId).length > 0;
|
|
1266
|
-
}
|