commandmate 0.49.0 → 0.49.1
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 +238 -231
- package/.next/app-path-routes-manifest.json +19 -18
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +9 -9
- package/.next/required-server-files.json +1 -1
- package/.next/routes-manifest.json +8 -0
- 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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route.js +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/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/[relayId]/route.js +1 -0
- package/.next/server/app/api/relays/[relayId]/route.js.nft.json +1 -0
- package/.next/server/app/api/relays/[relayId]/route_client-reference-manifest.js +1 -0
- 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.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.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.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.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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route.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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +144 -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.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.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.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 +103 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_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.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.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.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.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.js.nft.json +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 +11 -11
- package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +19 -18
- package/.next/server/chunks/1656.js +2 -2
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/3773.js +1 -0
- package/.next/server/chunks/3801.js +31 -0
- package/.next/server/chunks/5209.js +1 -1
- package/.next/server/chunks/5354.js +1 -1
- package/.next/server/chunks/{9130.js → 5630.js} +1 -1
- package/.next/server/chunks/5775.js +1 -0
- package/.next/server/chunks/610.js +1 -0
- 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 +1 -1
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/6808.js +4 -0
- package/.next/server/chunks/7023.js +14 -0
- package/.next/server/chunks/7604.js +1 -1
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8581.js +15 -15
- package/.next/server/chunks/8728.js +2 -2
- package/.next/server/chunks/8782.js +1 -1
- package/.next/server/chunks/8807.js +63 -53
- package/.next/server/chunks/8918.js +103 -1
- package/.next/server/chunks/9198.js +144 -0
- package/.next/server/chunks/9390.js +1 -1
- package/.next/server/chunks/9584.js +1 -1
- package/.next/server/chunks/9627.js +1 -1
- package/.next/server/chunks/9731.js +3 -3
- 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/{2407-ab92ae9837c39dce.js → 2407-675ba6b21844dc3b.js} +1 -1
- package/.next/static/chunks/3931-1a1abab16248f14d.js +1 -0
- package/.next/static/chunks/8606-ce17ffa77f39608e.js +1 -0
- package/.next/static/chunks/app/api/agents/update/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/agents/versions/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/app/release-notes/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/app/update/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/app/update-check/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/auth/login/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/auth/logout/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/auth/status/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/capabilities/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/daily-summary/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/daily-summary/status/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/external-apps/[id]/health/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/external-apps/[id]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/external-apps/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/fs/browse/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/fs/recent-paths/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/hooks/agent-event/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/hooks/claude-done/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/hooks/permission-request/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/metrics/vibe/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/ollama/models/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/push/escalation/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/push/subscriptions/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/push/vapid/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/relays/[relayId]/cancel/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/relays/[relayId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/relays/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/remote/pair/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/clone/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/excluded/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/restore/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/scan/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/sync/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/repositories/validate-path/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/settings/default-agents/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/settings/default-surface-mode/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/sidebar/group-order/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/skills/[id]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/skills/installations/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/skills/operations/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/skills/reindex/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/skills/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/slash-commands/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/tasks/[taskId]/cancel/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/tasks/[taskId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/templates/[id]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/templates/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/verification/runs/[runId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/verification/runs/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/capture/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/clear-composer/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cli-reference/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/direct-input/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/env/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/instances/notes/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/instances/opencode/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/logs/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/memos/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/messages/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/diff/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/session/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/share/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/strict/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/resolve-target/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/respond/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/search/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/send/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update-plan/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tasks/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/timers/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/todos/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tree/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/config/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/apply-default-agents/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/api/worktrees/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/layout-8bfac4724277b47f.js +1 -0
- package/.next/static/chunks/app/manifest.webmanifest/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/proxy/[...path]/route-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/sessions/page-890fd50ec9739973.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/layout-a4f129c451de7859.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-f6d3ab8185d93aae.js +1 -0
- package/.next/static/css/c1e307d05daf93b6.css +1 -0
- package/.next/trace +13 -13
- package/.next/types/app/api/relays/[relayId]/route.ts +347 -0
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/dist/cli/commands/ask.d.ts.map +1 -1
- package/dist/cli/commands/ask.js +178 -13
- package/dist/cli/commands/message-dispatch.d.ts +25 -5
- package/dist/cli/commands/message-dispatch.d.ts.map +1 -1
- package/dist/cli/commands/message-dispatch.js +92 -6
- package/dist/cli/commands/relays.d.ts +25 -2
- package/dist/cli/commands/relays.d.ts.map +1 -1
- package/dist/cli/commands/relays.js +69 -5
- package/dist/cli/commands/respond.d.ts +12 -0
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +63 -1
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +6 -4
- package/dist/cli/commands/wait-hook-stop-settle.d.ts +66 -0
- package/dist/cli/commands/wait-hook-stop-settle.d.ts.map +1 -0
- package/dist/cli/commands/wait-hook-stop-settle.js +150 -0
- package/dist/cli/commands/wait-instance.d.ts +21 -0
- package/dist/cli/commands/wait-instance.d.ts.map +1 -0
- package/dist/cli/commands/wait-instance.js +41 -0
- package/dist/cli/commands/wait-notices.d.ts +87 -0
- package/dist/cli/commands/wait-notices.d.ts.map +1 -0
- package/dist/cli/commands/wait-notices.js +301 -0
- package/dist/cli/commands/wait-poll-bookkeeping.d.ts +15 -0
- package/dist/cli/commands/wait-poll-bookkeeping.d.ts.map +1 -0
- package/dist/cli/commands/wait-poll-bookkeeping.js +57 -0
- package/dist/cli/commands/wait-poll-state.d.ts +118 -0
- package/dist/cli/commands/wait-poll-state.d.ts.map +1 -0
- package/dist/cli/commands/wait-poll-state.js +6 -0
- package/dist/cli/commands/wait-timing.d.ts +46 -0
- package/dist/cli/commands/wait-timing.d.ts.map +1 -0
- package/dist/cli/commands/wait-timing.js +99 -0
- package/dist/cli/commands/wait-turn-boundary.d.ts +284 -0
- package/dist/cli/commands/wait-turn-boundary.d.ts.map +1 -0
- package/dist/cli/commands/wait-turn-boundary.js +427 -0
- package/dist/cli/commands/wait-verify.d.ts +50 -0
- package/dist/cli/commands/wait-verify.d.ts.map +1 -0
- package/dist/cli/commands/wait-verify.js +124 -0
- package/dist/cli/commands/wait.d.ts +6 -105
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +207 -959
- 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 +23 -1
- package/dist/cli/types/api-responses.d.ts +47 -3
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/utils/api-client.d.ts +15 -1
- package/dist/cli/utils/api-client.d.ts.map +1 -1
- package/dist/cli/utils/api-client.js +7 -1
- package/dist/cli/utils/reply-ledger.d.ts +79 -0
- package/dist/cli/utils/reply-ledger.d.ts.map +1 -1
- package/dist/cli/utils/reply-ledger.js +141 -1
- package/dist/lib/session/send-attempt-types.d.ts +23 -1
- package/dist/lib/session/send-attempt-types.d.ts.map +1 -1
- package/dist/lib/session/send-attempt-types.js +9 -1
- package/dist/server/locales/en/worktree.json +18 -3
- package/dist/server/locales/ja/worktree.json +18 -3
- package/dist/server/src/lib/auto-yes-poller.js +49 -10
- package/dist/server/src/lib/cli-tools/antigravity.js +40 -7
- package/dist/server/src/lib/cli-tools/codex.js +60 -11
- package/dist/server/src/lib/cli-tools/command-code-plan-review.js +24 -2
- package/dist/server/src/lib/cli-tools/copilot.js +120 -30
- package/dist/server/src/lib/cli-tools/gemini.js +28 -9
- package/dist/server/src/lib/cli-tools/opencode.js +55 -13
- package/dist/server/src/lib/cli-tools/submit-composer-read.js +580 -0
- package/dist/server/src/lib/cli-tools/submit-verified-sender.js +356 -621
- package/dist/server/src/lib/db/migrations/index.js +2 -0
- package/dist/server/src/lib/db/migrations/pre-migration-backup.js +266 -0
- package/dist/server/src/lib/db/migrations/runner.js +37 -4
- package/dist/server/src/lib/db/migrations/v62-session-relays-bind.js +102 -0
- package/dist/server/src/lib/db/relay-bind-db.js +437 -0
- package/dist/server/src/lib/db/relay-db.js +59 -96
- package/dist/server/src/lib/detection/upstream-faults.js +40 -6
- package/dist/server/src/lib/hooks/sources/opencode/client.js +12 -6
- package/dist/server/src/lib/polling/response-checker.js +7 -5
- package/dist/server/src/lib/prompt-answer-errors.js +288 -0
- package/dist/server/src/lib/prompt-answer-sender.js +264 -288
- package/dist/server/src/lib/push/failure-episode-state.js +4 -1
- package/dist/server/src/lib/realtime/terminal-broadcast.js +1 -4
- package/dist/server/src/lib/realtime-snippet.js +54 -0
- package/dist/server/src/lib/relay/relay-bind.js +294 -0
- package/dist/server/src/lib/relay/relay-boot.js +51 -0
- package/dist/server/src/lib/relay/relay-bound-reply.js +519 -0
- package/dist/server/src/lib/relay/relay-delivery.js +134 -220
- package/dist/server/src/lib/relay/relay-messages.js +39 -4
- package/dist/server/src/lib/relay/relay-overlap.js +92 -0
- package/dist/server/src/lib/relay/relay-system-line.js +3 -2
- package/dist/server/src/lib/relay/types.js +12 -1
- package/dist/server/src/lib/session/agent-session-lifecycle.js +18 -0
- package/dist/server/src/lib/session/claude-session.js +41 -6
- package/dist/server/src/lib/session/composer-clear.js +54 -1
- package/dist/server/src/lib/session/current-output-builder.js +21 -5
- package/dist/server/src/lib/session/instance-input-lock.js +664 -0
- package/dist/server/src/lib/session/send-attempt-state.js +17 -0
- package/dist/server/src/lib/session/send-attempt-types.js +9 -1
- package/dist/server/src/lib/session/send-user-message.js +82 -13
- package/package.json +1 -1
- package/release-notes/0.49.1.json +66 -0
- package/.next/server/chunks/1210.js +0 -1
- package/.next/server/chunks/1945.js +0 -14
- package/.next/server/chunks/1990.js +0 -103
- package/.next/server/chunks/4194.js +0 -67
- package/.next/server/chunks/4280.js +0 -1
- package/.next/server/chunks/5845.js +0 -1
- package/.next/server/chunks/720.js +0 -103
- package/.next/server/chunks/936.js +0 -1
- package/.next/server/chunks/9540.js +0 -1
- package/.next/static/chunks/8606-cf6bdbff44a764cf.js +0 -1
- package/.next/static/chunks/9079-987939d231704218.js +0 -1
- package/.next/static/chunks/app/api/agents/update/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/agents/versions/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/app/release-notes/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/app/update/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/app/update-check/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/auth/login/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/auth/logout/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/auth/status/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/capabilities/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/daily-summary/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/daily-summary/status/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/external-apps/[id]/health/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/external-apps/[id]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/external-apps/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/fs/browse/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/fs/recent-paths/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/hooks/agent-event/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/hooks/claude-done/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/hooks/permission-request/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/metrics/vibe/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/ollama/models/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/push/escalation/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/push/subscriptions/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/push/vapid/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/relays/[relayId]/cancel/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/relays/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/remote/pair/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/clone/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/excluded/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/restore/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/scan/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/sync/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/repositories/validate-path/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/settings/default-agents/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/settings/default-surface-mode/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/sidebar/group-order/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/skills/[id]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/skills/installations/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/skills/operations/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/skills/reindex/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/skills/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/slash-commands/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/tasks/[taskId]/cancel/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/tasks/[taskId]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/templates/[id]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/templates/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/verification/runs/[runId]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/verification/runs/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/capture/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/clear-composer/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cli-reference/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/direct-input/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/env/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/instances/notes/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/instances/opencode/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/logs/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/memos/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/messages/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/diff/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/session/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/opencode/share/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/strict/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/resolve-target/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/respond/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/search/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/send/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update-plan/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tasks/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/timers/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/todos/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tree/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/config/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/apply-default-agents/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/api/worktrees/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/layout-aa8e66164a4367af.js +0 -1
- package/.next/static/chunks/app/manifest.webmanifest/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/proxy/[...path]/route-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/sessions/page-cfd645305e25fd33.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/layout-c81284a9d8b35304.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-a8d7886703ffc7b4.js +0 -1
- package/.next/static/css/db8959555c3d9c96.css +0 -1
- /package/.next/static/{3_JtAZaKMJEDFIIfkHv4n → fqfSDqQMweROeHUzOt_m1}/_buildManifest.js +0 -0
- /package/.next/static/{3_JtAZaKMJEDFIIfkHv4n → fqfSDqQMweROeHUzOt_m1}/_ssgManifest.js +0 -0
|
@@ -22,21 +22,37 @@
|
|
|
22
22
|
* Infrastructure errors use ExitCode (1, 2, 99)
|
|
23
23
|
*/
|
|
24
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
|
-
exports.
|
|
26
|
-
exports.formatRestartReleaseNotice = formatRestartReleaseNotice;
|
|
25
|
+
exports.settleCurrentOutputPath = exports.HOOK_STOP_SETTLE_MAX_MS = exports.HOOK_STOP_SETTLE_INTERVAL_MS = exports.TURN_OPENING_EVENT_TYPES = exports.SELF_RESUME_PENDING_DETAIL = exports.SELF_RESUME_HOLD_MS = exports.SELF_RESUME_CAPABILITY = exports.formatRestartReleaseNotice = void 0;
|
|
27
26
|
exports.pollWorktree = pollWorktree;
|
|
28
27
|
exports.createWaitCommand = createWaitCommand;
|
|
29
28
|
const commander_1 = require("commander");
|
|
30
29
|
const types_1 = require("../types");
|
|
31
30
|
const api_client_1 = require("../utils/api-client");
|
|
32
31
|
const command_helpers_1 = require("../utils/command-helpers");
|
|
33
|
-
const verify_runner_1 = require("../utils/verify-runner");
|
|
34
32
|
const agent_target_options_1 = require("../config/agent-target-options");
|
|
35
33
|
const prompt_1 = require("./prompt");
|
|
36
34
|
const prompt_view_1 = require("../../lib/session/prompt-view");
|
|
37
35
|
const instances_1 = require("./instances");
|
|
38
|
-
|
|
39
|
-
const
|
|
36
|
+
const wait_timing_1 = require("./wait-timing");
|
|
37
|
+
const wait_notices_1 = require("./wait-notices");
|
|
38
|
+
const wait_turn_boundary_1 = require("./wait-turn-boundary");
|
|
39
|
+
const wait_hook_stop_settle_1 = require("./wait-hook-stop-settle");
|
|
40
|
+
const wait_verify_1 = require("./wait-verify");
|
|
41
|
+
const wait_instance_1 = require("./wait-instance");
|
|
42
|
+
const wait_poll_bookkeeping_1 = require("./wait-poll-bookkeeping");
|
|
43
|
+
// Issue #3964: the split-out modules' exports, re-exported so every import of
|
|
44
|
+
// `./wait` keeps working.
|
|
45
|
+
var wait_notices_2 = require("./wait-notices");
|
|
46
|
+
Object.defineProperty(exports, "formatRestartReleaseNotice", { enumerable: true, get: function () { return wait_notices_2.formatRestartReleaseNotice; } });
|
|
47
|
+
var wait_turn_boundary_2 = require("./wait-turn-boundary");
|
|
48
|
+
Object.defineProperty(exports, "SELF_RESUME_CAPABILITY", { enumerable: true, get: function () { return wait_turn_boundary_2.SELF_RESUME_CAPABILITY; } });
|
|
49
|
+
Object.defineProperty(exports, "SELF_RESUME_HOLD_MS", { enumerable: true, get: function () { return wait_turn_boundary_2.SELF_RESUME_HOLD_MS; } });
|
|
50
|
+
Object.defineProperty(exports, "SELF_RESUME_PENDING_DETAIL", { enumerable: true, get: function () { return wait_turn_boundary_2.SELF_RESUME_PENDING_DETAIL; } });
|
|
51
|
+
Object.defineProperty(exports, "TURN_OPENING_EVENT_TYPES", { enumerable: true, get: function () { return wait_turn_boundary_2.TURN_OPENING_EVENT_TYPES; } });
|
|
52
|
+
var wait_hook_stop_settle_2 = require("./wait-hook-stop-settle");
|
|
53
|
+
Object.defineProperty(exports, "HOOK_STOP_SETTLE_INTERVAL_MS", { enumerable: true, get: function () { return wait_hook_stop_settle_2.HOOK_STOP_SETTLE_INTERVAL_MS; } });
|
|
54
|
+
Object.defineProperty(exports, "HOOK_STOP_SETTLE_MAX_MS", { enumerable: true, get: function () { return wait_hook_stop_settle_2.HOOK_STOP_SETTLE_MAX_MS; } });
|
|
55
|
+
Object.defineProperty(exports, "settleCurrentOutputPath", { enumerable: true, get: function () { return wait_hook_stop_settle_2.settleCurrentOutputPath; } });
|
|
40
56
|
/**
|
|
41
57
|
* `type` reported for a blocked-on-a-human frame that carries no parsable prompt
|
|
42
58
|
* (Issue #1628). Arrow-key menus — Codex's pager and `/model`, antigravity's
|
|
@@ -74,76 +90,6 @@ function waitAnswerVia(view) {
|
|
|
74
90
|
return 'api';
|
|
75
91
|
return 'terminal';
|
|
76
92
|
}
|
|
77
|
-
/**
|
|
78
|
-
* Why `wait` decided the agent was done, printed on the completion line
|
|
79
|
-
* (Issue #1839).
|
|
80
|
-
*
|
|
81
|
-
* `Completed: <id>` used to be the whole story, which made two very different
|
|
82
|
-
* situations indistinguishable in a log: the agent's own `Stop` hook arrived, or
|
|
83
|
-
* nothing but the screen said so. The measurement behind this Issue is exactly
|
|
84
|
-
* that difference — a 529 storm returns Claude to its composer in ~3 s with the
|
|
85
|
-
* scraper reporting `ready`/`input_prompt` and no `Stop` ever sent — so the
|
|
86
|
-
* basis belongs next to the verdict rather than in a triage session afterwards.
|
|
87
|
-
*/
|
|
88
|
-
const COMPLETION_BASIS = {
|
|
89
|
-
/** The agent reported the turn ended, and the report postdates this wait's turn. */
|
|
90
|
-
HOOK_STOP: 'hook_stop',
|
|
91
|
-
/** The tmux session went away after we had seen it alive. */
|
|
92
|
-
SESSION_GONE: 'session_gone',
|
|
93
|
-
/** The terminal frame says the agent is back at its composer. Nothing corroborated it. */
|
|
94
|
-
SCRAPER_READY: 'scraper_ready',
|
|
95
|
-
};
|
|
96
|
-
/**
|
|
97
|
-
* Structured event types that mean "a turn is under way" (Issue #1839).
|
|
98
|
-
*
|
|
99
|
-
* Mirrors AGENT_EVENT_TYPES in src/lib/hooks/agent-event-types.ts; duplicated
|
|
100
|
-
* rather than imported because the CLI bundle keeps its own copy of the API
|
|
101
|
-
* shapes (see api-responses.ts).
|
|
102
|
-
*
|
|
103
|
-
* `notification` is deliberately absent, and that is the one measured deviation
|
|
104
|
-
* from the design sketched in Issue #1839. The Issue proposed accepting
|
|
105
|
-
* `stop` **or** `idle_prompt` as the end of a turn; the live capture of
|
|
106
|
-
* 2026-08-20 (see docs/design/upstream-fault-turn-boundary-1839.md) shows
|
|
107
|
-
* Claude 2.1.236 emitting `Notification(idle_prompt)` 62 s into a turn that
|
|
108
|
-
* ran nothing at all, because the composer had been idle for a minute. Reading
|
|
109
|
-
* it as a turn boundary would have re-created the false completion this gate
|
|
110
|
-
* exists to stop, one minute later. Only `Stop` ends a turn.
|
|
111
|
-
*
|
|
112
|
-
* Exported for the cross-layer pin in
|
|
113
|
-
* `tests/unit/session/status-contract-1926.test.ts`. The server opens a turn on
|
|
114
|
-
* the same three events (`src/lib/session/provisional-turn.ts`
|
|
115
|
-
* TURN_ACTIVITY_EVENTS), and since Issue #1930 `adoptTurnStart` reads that
|
|
116
|
-
* turn's `openedAt` rather than this set — so a set that drifted would change
|
|
117
|
-
* this gate silently. The set is still read here for the pre-#1930 fallback
|
|
118
|
-
* path, and the CLI cannot import the server module (`tsconfig.cli.json` sets
|
|
119
|
-
* `"paths": {}`), so the test is the only thing holding the two together.
|
|
120
|
-
*/
|
|
121
|
-
exports.TURN_OPENING_EVENT_TYPES = new Set([
|
|
122
|
-
'user_prompt_submit',
|
|
123
|
-
'pre_tool_use',
|
|
124
|
-
'post_tool_use',
|
|
125
|
-
]);
|
|
126
|
-
/**
|
|
127
|
-
* How far *before* this wait started a turn-opening event may sit and still be
|
|
128
|
-
* read as the turn this wait is about (Issue #1839).
|
|
129
|
-
*
|
|
130
|
-
* `wait` does not know when `send` ran, and the honest proxy is its own start:
|
|
131
|
-
* an orchestrator sends and then waits, so the turn's `UserPromptSubmit` lands
|
|
132
|
-
* after `wait` is already polling (measured at +0.6 s from the send). One poll
|
|
133
|
-
* interval of slack covers a `wait` that starts a moment late.
|
|
134
|
-
*
|
|
135
|
-
* The bound is what keeps this from being a new way to hang, and Issue #1930
|
|
136
|
-
* narrowed what it has to defend against. It was written when structured events
|
|
137
|
-
* were NOT fenced by generation on the way into `structuredEvents`, so a stale
|
|
138
|
-
* `user_prompt_submit` from a previous agent process could still be the last
|
|
139
|
-
* event on the wire and this window was the only thing stopping it from gating
|
|
140
|
-
* a wait for ever. The server fences the turn now and publishes null when it
|
|
141
|
-
* does, so the window's remaining job is narrower and sharper: a turn that has
|
|
142
|
-
* already CLOSED must have closed inside this wait to count, or `wait` on a
|
|
143
|
-
* session that finished an hour ago would inherit that turn's gate. An open
|
|
144
|
-
* turn is adopted whatever its age — see {@link adoptTurnStart}.
|
|
145
|
-
*/
|
|
146
|
-
const TURN_ADOPTION_GRACE_MS = POLL_INTERVAL_MS;
|
|
147
93
|
/**
|
|
148
94
|
* How long `isUnclassifiedActive` must hold before `wait` treats it as a stop
|
|
149
95
|
* reason (Issue #1708).
|
|
@@ -163,625 +109,6 @@ const TURN_ADOPTION_GRACE_MS = POLL_INTERVAL_MS;
|
|
|
163
109
|
* for working around a detector bug, and the bug is the thing to fix.
|
|
164
110
|
*/
|
|
165
111
|
const UNCLASSIFIED_DWELL_MS = 60_000;
|
|
166
|
-
/**
|
|
167
|
-
* The keystroke that closes opencode's sidebar, in opencode's own notation
|
|
168
|
-
* (Issue #2095).
|
|
169
|
-
*
|
|
170
|
-
* A local copy of `OPENCODE_SIDEBAR_RECOVERY_CHORD` from
|
|
171
|
-
* `src/lib/detection/opencode-pane-obstruction.ts` and not an import: the CLI
|
|
172
|
-
* builds with `"paths": {}` (tsconfig.cli.json) and cannot reach `@/lib` at all,
|
|
173
|
-
* which is why `api-responses.ts` mirrors payload shapes rather than importing
|
|
174
|
-
* them. Taken from opencode's own keybind table, which its `ctrl+p` palette
|
|
175
|
-
* prints as `Show sidebar ctrl+x b`.
|
|
176
|
-
*/
|
|
177
|
-
const OPENCODE_SIDEBAR_RECOVERY_CHORD = 'ctrl+x b';
|
|
178
|
-
/**
|
|
179
|
-
* The cause sentence to append when the frame carries a pane obstruction, or ''
|
|
180
|
-
* (Issue #2095).
|
|
181
|
-
*
|
|
182
|
-
* Appended rather than substituted, and no exit code moves: the frame is
|
|
183
|
-
* genuinely unclassified and `wait` was already right to stop on it. What it
|
|
184
|
-
* could not say before is WHY, which left an operator with `capture --pane` and
|
|
185
|
-
* a screenful of box drawing to work it out from.
|
|
186
|
-
*
|
|
187
|
-
* Empty for a server too old to publish the field, which is the same output
|
|
188
|
-
* `wait` produced before this Issue.
|
|
189
|
-
*/
|
|
190
|
-
function describePaneObstruction(data) {
|
|
191
|
-
const obstruction = data.paneObstruction;
|
|
192
|
-
if (!obstruction)
|
|
193
|
-
return '';
|
|
194
|
-
return (` Cause: paneObstruction=${obstruction.id} — a second column is sharing rows with the ` +
|
|
195
|
-
`transcript (it reads ${JSON.stringify(obstruction.matchedText)}), which covers the marker ` +
|
|
196
|
-
`that ends a turn. Press \`${OPENCODE_SIDEBAR_RECOVERY_CHORD}\` in the pane to close ` +
|
|
197
|
-
`opencode's sidebar.`);
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* How recent `autoYes.lastSuppression` must be to be reported as the reason this
|
|
201
|
-
* wait is blocked (Issue #1699).
|
|
202
|
-
*
|
|
203
|
-
* The record is refreshed on every poll for as long as the suppressed prompt is
|
|
204
|
-
* on screen, so a fresh timestamp means "this is happening now" while an old one
|
|
205
|
-
* is a historical suppression of some earlier prompt. The window is generous
|
|
206
|
-
* against the server's own poll interval — being a few seconds late with a true
|
|
207
|
-
* report beats staying silent, which is the failure this exists to fix.
|
|
208
|
-
*
|
|
209
|
-
* Issue #2463 reads the same window as "the policy withheld THIS prompt", which
|
|
210
|
-
* is what ends the Auto-Yes hold at once. `current-output` publishes no start
|
|
211
|
-
* time for a scraped prompt, so the push gate's `suppression.at >= waitingSince`
|
|
212
|
-
* (`src/lib/push/prompt-push-gate.ts`) cannot be computed here; a record that is
|
|
213
|
-
* still being re-stamped is the CLI's reading of it. Using one window for both
|
|
214
|
-
* keeps the hold and the payload in agreement: an exit 10 carries
|
|
215
|
-
* `autoYesSuppression` exactly when the hold judged the answer withheld. The
|
|
216
|
-
* error runs towards reporting — a withheld answer to an earlier prompt, under a
|
|
217
|
-
* minute old, still ends the hold, which is the pre-#2463 exit rather than a
|
|
218
|
-
* new failure.
|
|
219
|
-
*
|
|
220
|
-
* Issue #3798: a server that names the waiting episodes does what the push gate
|
|
221
|
-
* does — the record's `episodeId` against the payload's
|
|
222
|
-
* `autoYes.waitingEpisodeId`, which decide when both are present: another id
|
|
223
|
-
* (or no wait open) is a record of an earlier wait, however recent; the same
|
|
224
|
-
* id is this wait's. Either one missing (an older server, a record written
|
|
225
|
-
* before any wait was open), this window decides as before. Whichever
|
|
226
|
-
* decides, a record the server marks `lastSuppressionAnswered` — Auto-Yes
|
|
227
|
-
* answered the open wait after it was written — is history, not this wait's
|
|
228
|
-
* reason, as the push gate reads it: the hold goes on.
|
|
229
|
-
*/
|
|
230
|
-
const SUPPRESSION_FRESH_MS = 60_000;
|
|
231
|
-
/**
|
|
232
|
-
* The suppression currently blocking this session, or null.
|
|
233
|
-
*
|
|
234
|
-
* Issue #3863: with the Auto-Yes answer mode in effect (`autoYesAnswerMode`)
|
|
235
|
-
* when the server publishes one — what `question-left-to-human` and
|
|
236
|
-
* `recommended-option-unidentified` depend on.
|
|
237
|
-
*/
|
|
238
|
-
function activeSuppression(data, now) {
|
|
239
|
-
// No `autoYes` at all (a session that is not running, Issue #3300) reads as
|
|
240
|
-
// "nothing was withheld", the same as a null record.
|
|
241
|
-
const suppression = data.autoYes?.lastSuppression;
|
|
242
|
-
if (!suppression)
|
|
243
|
-
return null;
|
|
244
|
-
const ageMs = now - suppression.at;
|
|
245
|
-
const waitId = data.autoYes?.waitingEpisodeId;
|
|
246
|
-
if (suppression.episodeId !== undefined && waitId !== undefined) {
|
|
247
|
-
if (suppression.episodeId !== waitId)
|
|
248
|
-
return null;
|
|
249
|
-
}
|
|
250
|
-
else if (ageMs > SUPPRESSION_FRESH_MS) {
|
|
251
|
-
// A negative age is clock skew between the CLI and the server, not staleness.
|
|
252
|
-
return null;
|
|
253
|
-
}
|
|
254
|
-
if (data.autoYes?.lastSuppressionAnswered === true)
|
|
255
|
-
return null;
|
|
256
|
-
const answerMode = data.autoYesAnswerMode;
|
|
257
|
-
return {
|
|
258
|
-
suppression,
|
|
259
|
-
ageSeconds: Math.max(0, Math.round(ageMs / 1000)),
|
|
260
|
-
...(answerMode !== undefined ? { answerMode } : {}),
|
|
261
|
-
};
|
|
262
|
-
}
|
|
263
|
-
/** The wording for the four reasons a contract's `autoYes` block really authors. */
|
|
264
|
-
const CONTRACT_POLICY_CAUSE = 'by contract policy';
|
|
265
|
-
/**
|
|
266
|
-
* What withheld the answer, in the words `wait` puts on stderr (Issue #1843).
|
|
267
|
-
*
|
|
268
|
-
* A Record over the whole reason union rather than one fixed phrase: adding a
|
|
269
|
-
* reason to {@link AutoYesSuppressionReason} without deciding what `wait` should
|
|
270
|
-
* say about it is a compile error here, which is the point. Until #1843 the
|
|
271
|
-
* notice hard-coded "by contract policy" for every reason, so #1829's
|
|
272
|
-
* `agent-launch-dialog` — a product-side decision the poller makes with no
|
|
273
|
-
* contract in sight (`suppressIfNotOursToAnswer` in
|
|
274
|
-
* `src/lib/polling/auto-yes-prompt-suppression.ts`: codex's lifecycle dialogs,
|
|
275
|
-
* gemini's folder trust since #3776 and copilot's since #3790) — sent operators
|
|
276
|
-
* of contract-less worktrees hunting for a `denyPatterns` entry that did not
|
|
277
|
-
* exist.
|
|
278
|
-
*
|
|
279
|
-
* The three sites that record a suppression are covered: the poller's launch-dialog
|
|
280
|
-
* branch (`agent-launch-dialog`), the poller's policy branch and
|
|
281
|
-
* `lib/hooks/permission-decision-service.ts` (both the four `evaluatePolicyAgainstTexts`
|
|
282
|
-
* verdicts, which is why those four keep the pre-#1843 wording exactly), and
|
|
283
|
-
* the poller's stopped-answer branch (`partial-answer`, Issue #3706 / #3713),
|
|
284
|
-
* and the poller's agy trust-screen branch (`startup-trust-unhandled`, Issue #3757),
|
|
285
|
-
* and the poller's question confirm-page branch (`question-confirm-page`, Issue #3748),
|
|
286
|
-
* and the poller's question branch (`question-left-to-human`, Issue #3822),
|
|
287
|
-
* and the resolver's permission-row reading (`allow-once-unidentified`, Issue #3822),
|
|
288
|
-
* and the resolver's choice of a question's recommended option
|
|
289
|
-
* (`recommended-option-unidentified`, Issue #3863),
|
|
290
|
-
* and the poller's agy receipt-gate branch (`no-hook-receipt`, Issue #3767),
|
|
291
|
-
* and a contract lookup that failed on either of the policy paths
|
|
292
|
-
* (`policy-lookup-failed`, Issue #3822).
|
|
293
|
-
*/
|
|
294
|
-
const SUPPRESSION_CAUSE = {
|
|
295
|
-
'mode-off': CONTRACT_POLICY_CAUSE,
|
|
296
|
-
'deny-pattern': CONTRACT_POLICY_CAUSE,
|
|
297
|
-
'deny-pattern-unusable': CONTRACT_POLICY_CAUSE,
|
|
298
|
-
'type-not-allowed': CONTRACT_POLICY_CAUSE,
|
|
299
|
-
// Issue #3822. Not "by contract policy": the contract could not be read at
|
|
300
|
-
// all, so nothing it says was applied. Withheld rather than answered, since
|
|
301
|
-
// the contract may state `off`; it clears once the server reads it again.
|
|
302
|
-
'policy-lookup-failed': 'because the server could not read the execution contract (the database lookup failed), so Auto-Yes does not answer until it can; check the server log for policy-lookup-failed',
|
|
303
|
-
// Issue #3790: after the launch window the poller still leaves copilot's and
|
|
304
|
-
// gemini's trust dialogs alone when the cursor is not on the safe row, and
|
|
305
|
-
// nobody else answers them then.
|
|
306
|
-
'agent-launch-dialog': "while the agent's launch dialog was on screen; if it stays after the launch (copilot's cursor on 2. or 3., gemini's not on 1. Trust folder), answer it at the pane",
|
|
307
|
-
// Issue #1924. Deliberately not "by contract policy": no contract was
|
|
308
|
-
// consulted. The frame looked like a numbered list to the generic estimator
|
|
309
|
-
// and like prose to the tool's own detector, and an operator who reads this
|
|
310
|
-
// should go and look at the pane rather than at `denyPatterns`.
|
|
311
|
-
'unclassified-frame': 'because no tool-specific dialog detector recognised the frame',
|
|
312
|
-
// Issue #3713 (#3706's reason). Not "by contract policy" either: an earlier
|
|
313
|
-
// Auto-Yes answer was stopped with some of its keys already in the input, and
|
|
314
|
-
// typing it again would append to them, so the prompt waits for a human.
|
|
315
|
-
// Issue #3880: or a send of it (Auto-Yes's, or a person's that failed) ended
|
|
316
|
-
// without tmux confirming it, and no key may be known to be there. The #3713
|
|
317
|
-
// sentence is kept as it was and the other case follows it.
|
|
318
|
-
'partial-answer': "because an earlier answer left partial input; Auto-Yes is waiting for a human (or that answer's send could not be confirmed, so the input may hold it: check the pane, then answer; an answer that goes through releases the hold)",
|
|
319
|
-
// Issue #3757. agy's startup folder-trust screen: the launch's to confirm, not
|
|
320
|
-
// Auto-Yes's, and agy drew it after the launch window had ended.
|
|
321
|
-
'startup-trust-unhandled': "because agy's startup folder-trust confirmation is the launch's to answer, not Auto-Yes's; the next send confirms it once, or answer it at the pane",
|
|
322
|
-
// Issue #3748. The AskUserQuestion confirm page (`Submit` / `Cancel`): the
|
|
323
|
-
// tool's own reader recognised it, and `Submit` commits whatever stands as the
|
|
324
|
-
// answers, so it waits for a human. Was recorded as `unclassified-frame`,
|
|
325
|
-
// whose wording above says the opposite (nothing recognised the frame).
|
|
326
|
-
'question-confirm-page': "because the question's Submit/Cancel confirmation commits the answers as they stand, so Auto-Yes leaves it to a human",
|
|
327
|
-
// Issue #3822. A question the agent asks the operator (an AskUserQuestion
|
|
328
|
-
// picker, OpenCode V2's question form): Auto-Yes answers permissions only,
|
|
329
|
-
// and no contract setting delegates the question. Issue #3863: since the
|
|
330
|
-
// answer modes, that is the `careful` mode's rule (and OpenCode V2's form
|
|
331
|
-
// under either mode); `answerMode=` on the line says which mode was on.
|
|
332
|
-
'question-left-to-human': 'because the agent is asking a question, and Auto-Yes answers permissions only (the careful answer mode, or a question form no mode answers); answer it at the pane (prompt --json, respond), or turn Auto-Yes on with --answer-mode recommended to have it pick the recommended option',
|
|
333
|
-
// Issue #3822. A permission dialog none of whose rows allows this call only
|
|
334
|
-
// (each saves a rule, changes the mode or denies), or two of which read so.
|
|
335
|
-
// Auto-Yes never picks a row that outlives this call, so it waits for a human.
|
|
336
|
-
'allow-once-unidentified': 'because no single option of the permission dialog allows this call only (the others save a rule, change the permission mode, or deny); Auto-Yes does not pick those, so answer it at the pane (prompt --json, respond)',
|
|
337
|
-
// Issue #3863. The recommended answer mode answers a question with its one
|
|
338
|
-
// recommended option (else its default), and could not tell which that is.
|
|
339
|
-
'recommended-option-unidentified': "because the question's recommended option could not be told (two or more marked recommended, a title it could not tell from its description, a typed-text or multi-select answer); answer it at the pane (prompt --json, respond)",
|
|
340
|
-
// Issue #3767. agy's approval dialog has no matching hook question (none, too
|
|
341
|
-
// late, already on screen, or the hook stopped arriving). Not a contract verdict.
|
|
342
|
-
// Issue #3789: nor one left unused — the last was spent on keys Auto-Yes sent,
|
|
343
|
-
// and a dialog is still up past the grace — so "no unused question" covers both.
|
|
344
|
-
'no-hook-receipt': "because there is no unused agy hook permission question for this dialog (none arrived in time, or the last one was spent on keys that did not clear it); answer it yourself (auto-yes --disable, prompt --json, respond --expect-screen) or check hooks.json",
|
|
345
|
-
};
|
|
346
|
-
/**
|
|
347
|
-
* {@link SUPPRESSION_CAUSE} for a reason that arrived over the wire.
|
|
348
|
-
*
|
|
349
|
-
* `reason` is a server-supplied string, so a server newer than this CLI can name
|
|
350
|
-
* a reason the union does not have. Naming it verbatim is the only honest answer:
|
|
351
|
-
* quietly folding an unknown reason into "by contract policy" is the same
|
|
352
|
-
* misattribution #1843 exists to remove, just for a future reason instead of
|
|
353
|
-
* `agent-launch-dialog`.
|
|
354
|
-
*/
|
|
355
|
-
function suppressionCause(reason) {
|
|
356
|
-
return Object.prototype.hasOwnProperty.call(SUPPRESSION_CAUSE, reason)
|
|
357
|
-
? SUPPRESSION_CAUSE[reason]
|
|
358
|
-
: `for a reason this CLI does not recognise (${reason})`;
|
|
359
|
-
}
|
|
360
|
-
/**
|
|
361
|
-
* One stderr line naming what is holding this prompt (Issue #1699).
|
|
362
|
-
*
|
|
363
|
-
* `wait` used to print only "Waiting for human response...", which reads the
|
|
364
|
-
* same whether a human was always going to answer or whether Auto-Yes silently
|
|
365
|
-
* refused to. That ambiguity is what let a deny pattern matching a finished turn
|
|
366
|
-
* stall two workers unnoticed; the pattern and the reason code belong on screen.
|
|
367
|
-
*
|
|
368
|
-
* Issue #1843: the cause is chosen per reason rather than asserted. `reason=` is
|
|
369
|
-
* in the payload either way, so the prefix is the only part that can lie — and it
|
|
370
|
-
* did, for every non-contract suppression.
|
|
371
|
-
*/
|
|
372
|
-
function formatSuppressionNotice(suppression, ageSeconds, answerMode) {
|
|
373
|
-
const parts = [
|
|
374
|
-
`reason=${suppression.reason}`,
|
|
375
|
-
`mode=${suppression.mode ?? 'none'}`,
|
|
376
|
-
`promptType=${suppression.promptType}`,
|
|
377
|
-
];
|
|
378
|
-
if (suppression.pattern !== undefined) {
|
|
379
|
-
parts.push(`pattern=${JSON.stringify(suppression.pattern)}`);
|
|
380
|
-
}
|
|
381
|
-
// Issue #3863: the Auto-Yes answer mode in effect, when the server says.
|
|
382
|
-
if (answerMode !== undefined) {
|
|
383
|
-
parts.push(`answerMode=${answerMode}`);
|
|
384
|
-
}
|
|
385
|
-
const cause = suppressionCause(suppression.reason);
|
|
386
|
-
return ` auto-yes suppressed this prompt ${cause}: ${parts.join(' ')} (${ageSeconds}s ago)`;
|
|
387
|
-
}
|
|
388
|
-
/**
|
|
389
|
-
* One stderr line saying Auto-Yes is off on this instance because the server
|
|
390
|
-
* restarted (Issue #3730), or null.
|
|
391
|
-
*
|
|
392
|
-
* Only words: the prompt was going to be reported either way — an instance
|
|
393
|
-
* whose grant the restart released is an instance with Auto-Yes off, and exit
|
|
394
|
-
* 10 for it is exactly the hand-back it always was. What this adds is the WHY,
|
|
395
|
-
* so a delegating agent re-enables Auto-Yes instead of guessing. A server
|
|
396
|
-
* older than the reason sends none, and nothing is printed.
|
|
397
|
-
*
|
|
398
|
-
* The command it suggests names the instance this wait is about: without
|
|
399
|
-
* `--instance`, `auto-yes --enable` arms the worktree's default primary, which
|
|
400
|
-
* for an alias (or a non-default tool) is another instance — the waited-on one
|
|
401
|
-
* would stay off while a grant went somewhere nobody asked for. The instance is
|
|
402
|
-
* the resolved `--instance` when one was given, else the CLI tool the server
|
|
403
|
-
* answered for (a primary's instance ID is its tool ID).
|
|
404
|
-
*
|
|
405
|
-
* @param instanceId - The resolved `--instance` of this wait, if any
|
|
406
|
-
*/
|
|
407
|
-
function formatRestartReleaseNotice(worktreeId, data, instanceId) {
|
|
408
|
-
if (data.autoYes?.enabled !== false || data.autoYes.stopReason !== 'server-restart')
|
|
409
|
-
return null;
|
|
410
|
-
const target = instanceId ?? data.cliToolId;
|
|
411
|
-
const command = `commandmate auto-yes ${worktreeId} --enable${target ? ` --instance ${target}` : ''}`;
|
|
412
|
-
return ` auto-yes was released by a server restart on ${worktreeId} (it is not turned back on ` +
|
|
413
|
-
`automatically); re-enable it with \`${command}\` if this session should keep answering.`;
|
|
414
|
-
}
|
|
415
|
-
/**
|
|
416
|
-
* One stderr line saying Auto-Yes pressed Enter on THIS prompt (Issue #3397), or
|
|
417
|
-
* null when the record is absent or about another screen.
|
|
418
|
-
*
|
|
419
|
-
* The prompt is one CommandMate could not read (the window offers direct input
|
|
420
|
-
* for it). `sent` — Auto-Yes confirmed whatever was selected; `no-effect` — the
|
|
421
|
-
* same screen outlived the Enter, no second one was sent, and it is a human's
|
|
422
|
-
* again. An outcome this CLI does not know is named verbatim (#1843's rule).
|
|
423
|
-
* `currentPrompt` is the server's judgement that the record is about the
|
|
424
|
-
* `promptData` of the same response, so an Enter sent to an earlier screen is
|
|
425
|
-
* never reported against this one.
|
|
426
|
-
*/
|
|
427
|
-
function formatEnterFallbackNotice(data, now) {
|
|
428
|
-
const record = data.autoYes?.lastEnterFallback;
|
|
429
|
-
if (!record || record.currentPrompt !== true)
|
|
430
|
-
return null;
|
|
431
|
-
const detail = `refusal=${record.refusalReason} promptType=${record.promptType}`;
|
|
432
|
-
const ago = `(${Math.max(0, Math.round((now - record.at) / 1000))}s ago)`;
|
|
433
|
-
if (record.outcome === 'sent') {
|
|
434
|
-
return ` auto-yes sent Enter to this prompt (CommandMate could not read it): ${detail} ${ago}`;
|
|
435
|
-
}
|
|
436
|
-
if (record.outcome === 'no-effect') {
|
|
437
|
-
return ` auto-yes sent Enter to this prompt, but the same screen is still up (no-effect); ` +
|
|
438
|
-
`answer it in the terminal: ${detail} ${ago}`;
|
|
439
|
-
}
|
|
440
|
-
return ` auto-yes Enter record for this prompt: outcome=${record.outcome} ${detail} ${ago}`;
|
|
441
|
-
}
|
|
442
|
-
/**
|
|
443
|
-
* Issue #3821: the server's own word that Auto-Yes left this prompt to a human
|
|
444
|
-
* (`autoYesDecision.state === 'withheld'`) — `server-poller-inactive` when no
|
|
445
|
-
* poller runs for the instance, or a stop the suppression record does not
|
|
446
|
-
* carry. Read only when the server publishes the field; an older one leaves
|
|
447
|
-
* `wait` holding as before.
|
|
448
|
-
*/
|
|
449
|
-
function decisionWithheldReason(data) {
|
|
450
|
-
const decision = data.autoYesDecision;
|
|
451
|
-
if (decision?.state !== 'withheld')
|
|
452
|
-
return null;
|
|
453
|
-
return decision.reason ?? 'unknown';
|
|
454
|
-
}
|
|
455
|
-
/**
|
|
456
|
-
* Whether this server publishes a real turn record (Issue #1930).
|
|
457
|
-
*
|
|
458
|
-
* `dialogPendingMaxMs` landed with the turn model and is set on every payload a
|
|
459
|
-
* server of that vintage produces, so its presence is the version probe. A
|
|
460
|
-
* *value* rather than a version string, for the reason #1924 gives for the
|
|
461
|
-
* capability block: a payload that has to be interpreted by its sender's
|
|
462
|
-
* version number is a payload nobody can read forward.
|
|
463
|
-
*
|
|
464
|
-
* The probe is needed because the two readings below disagree in exactly the
|
|
465
|
-
* case that matters. On a #1930 server, `openedAt` being null while
|
|
466
|
-
* `lastEventType` is `user_prompt_submit` means the turn was fenced off by a
|
|
467
|
-
* generation or aged out — the server has *decided* it is not this instance's
|
|
468
|
-
* turn. Falling back to the event on such a payload would put back the stale
|
|
469
|
-
* adoption the turn record exists to remove.
|
|
470
|
-
*/
|
|
471
|
-
function publishesTurnRecord(data) {
|
|
472
|
-
return data.structuredEvents?.dialogPendingMaxMs != null;
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Adopt the turn this wait is about, if this poll shows one (Issue #1839,
|
|
476
|
-
* moved onto the turn record in #1930).
|
|
477
|
-
*
|
|
478
|
-
* ## What changed, and why the grace window is no longer the whole guard
|
|
479
|
-
*
|
|
480
|
-
* Before #1930 this read `lastEventType` / `lastEventAt` — the newest event of
|
|
481
|
-
* any kind — and refused anything older than {@link TURN_ADOPTION_GRACE_MS},
|
|
482
|
-
* because (in the words of that constant) structured events "are NOT fenced by
|
|
483
|
-
* generation on the way into `structuredEvents`", so a stale
|
|
484
|
-
* `user_prompt_submit` from a previous agent process could still be the last
|
|
485
|
-
* event on the wire. The bound was the only thing keeping such a record from
|
|
486
|
-
* gating a wait for ever.
|
|
487
|
-
*
|
|
488
|
-
* The server fences the turn now, and publishes null when it does. So an **open**
|
|
489
|
-
* turn is adopted whatever its age — which closes a hole the old reading had:
|
|
490
|
-
* a turn that opened ten minutes before this `wait` started, and is still
|
|
491
|
-
* running, used to be adopted only because its *newest* event was fresh. An
|
|
492
|
-
* agent that goes quiet mid-turn (thinking, a long tool call) has no fresh
|
|
493
|
-
* event, so the #1839 gate came down at exactly the moment a 529 storm would
|
|
494
|
-
* exploit it.
|
|
495
|
-
*
|
|
496
|
-
* A **closed** turn still has to have opened inside this wait's window, and the
|
|
497
|
-
* reason is the one the grace constant gives: `wait` does not know when `send`
|
|
498
|
-
* ran, so the last turn of a session that finished an hour ago must not gate a
|
|
499
|
-
* wait that has only just started. `commandmate wait` on an already-idle
|
|
500
|
-
* session therefore adopts nothing and completes on its first poll, exactly as
|
|
501
|
-
* it did before — #1975 measured that at 234/242/259 ms and it is the
|
|
502
|
-
* orchestrator's normal path.
|
|
503
|
-
*
|
|
504
|
-
* @param previous - the turn start adopted so far, or null
|
|
505
|
-
* @returns the newest adopted turn start, or `previous` when nothing qualified
|
|
506
|
-
*/
|
|
507
|
-
function adoptTurnStart(data, waitStartedAt, previous) {
|
|
508
|
-
const events = data.structuredEvents;
|
|
509
|
-
if (!events)
|
|
510
|
-
return previous;
|
|
511
|
-
if (!publishesTurnRecord(data)) {
|
|
512
|
-
// A server older than #1930. Same reading this function has had since
|
|
513
|
-
// #1839, kept so a newer CLI pointed at an older server does not silently
|
|
514
|
-
// lose the gate.
|
|
515
|
-
if (events.lastEventAt == null || events.lastEventType == null)
|
|
516
|
-
return previous;
|
|
517
|
-
if (!exports.TURN_OPENING_EVENT_TYPES.has(events.lastEventType))
|
|
518
|
-
return previous;
|
|
519
|
-
if (events.lastEventAt < waitStartedAt - TURN_ADOPTION_GRACE_MS)
|
|
520
|
-
return previous;
|
|
521
|
-
return previous === null || events.lastEventAt > previous ? events.lastEventAt : previous;
|
|
522
|
-
}
|
|
523
|
-
const openedAt = events.openedAt;
|
|
524
|
-
// Null covers every "there is no turn to adopt" case the server knows about:
|
|
525
|
-
// nothing reported, a previous generation, aged out, or a `stop` whose
|
|
526
|
-
// opening was never observed.
|
|
527
|
-
if (openedAt == null)
|
|
528
|
-
return previous;
|
|
529
|
-
if (events.closedAt != null && openedAt < waitStartedAt - TURN_ADOPTION_GRACE_MS) {
|
|
530
|
-
return previous;
|
|
531
|
-
}
|
|
532
|
-
return previous === null || openedAt > previous ? openedAt : previous;
|
|
533
|
-
}
|
|
534
|
-
/**
|
|
535
|
-
* `structuredEvents.closedBy`, phrased for a diagnostic line (Issue #1930).
|
|
536
|
-
*
|
|
537
|
-
* The server's close-reason vocabulary and {@link COMPLETION_BASIS} answer two
|
|
538
|
-
* different questions — "why did the turn end" and "what did `wait` decide on"
|
|
539
|
-
* — and are deliberately printed side by side rather than folded together.
|
|
540
|
-
* `hook_stop` is the only place they meet: it is `closedBy: 'stop'` seen from
|
|
541
|
-
* the CLI's end. Everything else (`stale`, `scraper_evidence`, `session_end`,
|
|
542
|
-
* `generation`, `resync_idle`) is a reason the turn stopped being trusted, which
|
|
543
|
-
* is precisely what `wait` must NOT read as completion.
|
|
544
|
-
*/
|
|
545
|
-
function describeTurnClose(data) {
|
|
546
|
-
const events = data.structuredEvents;
|
|
547
|
-
if (!events)
|
|
548
|
-
return 'turn=unknown';
|
|
549
|
-
const id = events.turnId ?? 'none';
|
|
550
|
-
const closedBy = events.closedBy ?? (events.openedAt != null ? 'open' : 'none');
|
|
551
|
-
return `turn=${id} closedBy=${closedBy}`;
|
|
552
|
-
}
|
|
553
|
-
/**
|
|
554
|
-
* Whether the agent has reported the end of the turn this wait adopted
|
|
555
|
-
* (Issue #1839).
|
|
556
|
-
*
|
|
557
|
-
* True when no turn was adopted at all, which is the whole of the unchanged
|
|
558
|
-
* path: a session whose agent posts no hooks never adopts one, so every caller
|
|
559
|
-
* on a machine without hook injection sees precisely the pre-#1839 behaviour.
|
|
560
|
-
*/
|
|
561
|
-
function turnSettled(data, turnStartedAt) {
|
|
562
|
-
if (turnStartedAt === null)
|
|
563
|
-
return true;
|
|
564
|
-
const stoppedAt = data.lastStopEventAt;
|
|
565
|
-
return stoppedAt != null && stoppedAt >= turnStartedAt;
|
|
566
|
-
}
|
|
567
|
-
/**
|
|
568
|
-
* The structured event that ends a turn (Issue #1975).
|
|
569
|
-
*
|
|
570
|
-
* The counterpart of {@link TURN_OPENING_EVENT_TYPES}, kept as a bare constant
|
|
571
|
-
* because the vocabulary a source declares in `capabilities.supportedEvents` is
|
|
572
|
-
* the wire's, not this build's: a tool that cannot say `stop` cannot release the
|
|
573
|
-
* hold below, so asking for the word by name is the whole of the check.
|
|
574
|
-
*/
|
|
575
|
-
const TURN_CLOSING_EVENT_TYPE = 'stop';
|
|
576
|
-
/**
|
|
577
|
-
* How long `wait` will hold a composer frame open for an agent that has been
|
|
578
|
-
* handed a prompt it has not reported the end of (Issue #1975).
|
|
579
|
-
*
|
|
580
|
-
* The hold's *reason* is exact — see {@link outstandingPrompt} — so this is not
|
|
581
|
-
* a settling window standing in for evidence. It is the bound the contract of
|
|
582
|
-
* this Issue asks for: hooks are fail-open on every path, so a `Stop` that is
|
|
583
|
-
* simply lost (the receiver was restarted, the machine-wide
|
|
584
|
-
* `~/.copilot/settings.json` was rewritten by another server mid-session, the
|
|
585
|
-
* 4-second curl in the hook timed out) must not turn `wait` into a command that
|
|
586
|
-
* never returns. After this it completes on the frame alone, exactly as it did
|
|
587
|
-
* before this Issue, and says so.
|
|
588
|
-
*
|
|
589
|
-
* 60s is the same dwell {@link UNCLASSIFIED_DWELL_MS} uses for the same job, and
|
|
590
|
-
* it is ~55x the widest send-to-turn-open window measured for this Issue
|
|
591
|
-
* (2026-08-22, copilot 1.0.80 against an isolated server: 0.04s / 0.75s / 0.88s
|
|
592
|
-
* / 1.10s over four sends, the last of them a cold session start). `--timeout`
|
|
593
|
-
* and `--stall-timeout` below 60s still win, as they do for the unclassified
|
|
594
|
-
* dwell: this pre-empts long waits, it does not extend short ones.
|
|
595
|
-
*/
|
|
596
|
-
const PENDING_PROMPT_HOLD_MS = 60_000;
|
|
597
|
-
/**
|
|
598
|
-
* Whether this tool's event source claims it can report both ends of a turn
|
|
599
|
-
* (Issue #1975).
|
|
600
|
-
*
|
|
601
|
-
* The gate that keeps the hold below off every path it has no evidence for.
|
|
602
|
-
* `structuredEvents.source.capabilities` is #1924's declaration, published to
|
|
603
|
-
* the CLI already, and the compatibility source a tool with no implementation
|
|
604
|
-
* gets (`src/lib/hooks/sources/legacy-relay.ts`) declares `supportedEvents: []`
|
|
605
|
-
* — so a tool that posts no hooks answers `false` here and takes precisely the
|
|
606
|
-
* pre-#1975 path. So does a server older than #1924, which sends no `source` at
|
|
607
|
-
* all.
|
|
608
|
-
*
|
|
609
|
-
* Both words are required. Without a turn-opening word nothing would ever open
|
|
610
|
-
* the turn this waits for; without `stop` nothing could ever close it, and the
|
|
611
|
-
* hold would only ever end at its own bound.
|
|
612
|
-
*/
|
|
613
|
-
function reportsTurnBoundaries(data) {
|
|
614
|
-
const declared = data.structuredEvents?.source?.capabilities?.supportedEvents;
|
|
615
|
-
if (!Array.isArray(declared))
|
|
616
|
-
return false;
|
|
617
|
-
return (declared.includes(TURN_CLOSING_EVENT_TYPE) &&
|
|
618
|
-
declared.some(event => exports.TURN_OPENING_EVENT_TYPES.has(event)));
|
|
619
|
-
}
|
|
620
|
-
/**
|
|
621
|
-
* The `stop` detail meaning "the agent ended its turn with its own background
|
|
622
|
-
* work still running, and resumes by itself when that work finishes"
|
|
623
|
-
* (Issue #2614).
|
|
624
|
-
*
|
|
625
|
-
* A copy of `SELF_RESUME_PENDING_DETAIL` in `src/lib/hooks/agent-event-types.ts`
|
|
626
|
-
* for the reason {@link TURN_OPENING_EVENT_TYPES} is a copy: the CLI builds with
|
|
627
|
-
* `"paths": {}`. `tests/unit/cli/commands/wait-self-resume-2614.test.ts` pins the
|
|
628
|
-
* two together.
|
|
629
|
-
*/
|
|
630
|
-
exports.SELF_RESUME_PENDING_DETAIL = 'self_resume_pending';
|
|
631
|
-
/**
|
|
632
|
-
* The capability a source declares when its `stop` can carry
|
|
633
|
-
* {@link SELF_RESUME_PENDING_DETAIL} (Issue #2614).
|
|
634
|
-
*
|
|
635
|
-
* Read by name rather than through the mirrored type in `api-responses.ts`,
|
|
636
|
-
* which predates it: `structuredEvents.source.capabilities` is published as the
|
|
637
|
-
* source's whole declaration, so a newer server sends the key and an older one
|
|
638
|
-
* simply does not.
|
|
639
|
-
*/
|
|
640
|
-
exports.SELF_RESUME_CAPABILITY = 'stopReportsSelfResume';
|
|
641
|
-
/**
|
|
642
|
-
* How long `wait` holds a `stop` whose agent said it would resume by itself
|
|
643
|
-
* (Issue #2614).
|
|
644
|
-
*
|
|
645
|
-
* Measured 2026-09-17 against antigravity 1.2.4: a `schedule` of 60 s closed the
|
|
646
|
-
* turn, the agent woke 58 s after its `Stop` and did it again three more times,
|
|
647
|
-
* and the real end came five minutes after the first `Stop` — which is where
|
|
648
|
-
* `wait` had already reported `Completed (basis=hook_stop)` and started a
|
|
649
|
-
* verification against a half-finished worktree. The wake is not something to
|
|
650
|
-
* time: it is a `post_tool_use` that opens a new turn, and #1839's gate takes
|
|
651
|
-
* over from there. What needs a bound is only the case where it never comes.
|
|
652
|
-
*
|
|
653
|
-
* A timer's own length is not on the wire (the `schedule` arguments reach the
|
|
654
|
-
* permission receiver and stop there), and a command sent to the background has
|
|
655
|
-
* no length at all, so the bound is the one the server already uses for the
|
|
656
|
-
* same question the other way round: how long an open turn is trusted with
|
|
657
|
-
* nothing heard (`TURN_STALE_AFTER_MS` in `src/lib/session/provisional-turn.ts`,
|
|
658
|
-
* pinned equal by `wait-self-resume-2614.test.ts`). Every wake starts a new
|
|
659
|
-
* `stop` and a new hold, so an agent that keeps rescheduling never reaches it.
|
|
660
|
-
*
|
|
661
|
-
* A constant, like {@link PENDING_PROMPT_HOLD_MS}: `--timeout` and
|
|
662
|
-
* `--stall-timeout` below it still win.
|
|
663
|
-
*/
|
|
664
|
-
exports.SELF_RESUME_HOLD_MS = 30 * 60 * 1000;
|
|
665
|
-
/**
|
|
666
|
-
* Whether this tool's event source can say, on its `stop`, that the agent will
|
|
667
|
-
* resume by itself (Issue #2614).
|
|
668
|
-
*
|
|
669
|
-
* The same kind of gate as {@link reportsTurnBoundaries}, and it requires that
|
|
670
|
-
* one too: the hold below is released by a turn-opening event, and a source
|
|
671
|
-
* that cannot send one could only ever end the hold at its bound. A server that
|
|
672
|
-
* predates the declaration answers `false`, and so does every source but the one
|
|
673
|
-
* that writes the detail.
|
|
674
|
-
*/
|
|
675
|
-
function reportsSelfResume(data) {
|
|
676
|
-
const declared = data.structuredEvents?.source?.capabilities;
|
|
677
|
-
return declared?.[exports.SELF_RESUME_CAPABILITY] === true && reportsTurnBoundaries(data);
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* The instant of the `stop` this agent said it would resume from, or null
|
|
681
|
-
* (Issue #2614).
|
|
682
|
-
*
|
|
683
|
-
* Non-null only while that `stop` is still the newest thing the agent has said.
|
|
684
|
-
* The wake is a `post_tool_use` (antigravity reports the timer's own tool call
|
|
685
|
-
* finishing when it fires), which replaces the displayed event and opens a new
|
|
686
|
-
* turn, so this answers null from the first poll after it — and a later `stop`
|
|
687
|
-
* is a different instant, which is how a hold knows it is about a new one.
|
|
688
|
-
*
|
|
689
|
-
* On a server that publishes a turn record the `stop` must also be what closed
|
|
690
|
-
* that turn: a turn ended by `generation` or `session_end` belongs to a process
|
|
691
|
-
* that is gone, and nothing it scheduled is going to wake anything.
|
|
692
|
-
*/
|
|
693
|
-
function pendingSelfResumeStop(data) {
|
|
694
|
-
if (!reportsSelfResume(data))
|
|
695
|
-
return null;
|
|
696
|
-
const events = data.structuredEvents;
|
|
697
|
-
if (!events || events.lastEventType !== TURN_CLOSING_EVENT_TYPE)
|
|
698
|
-
return null;
|
|
699
|
-
if (events.lastEventDetail !== exports.SELF_RESUME_PENDING_DETAIL)
|
|
700
|
-
return null;
|
|
701
|
-
// `closedBy` is the server's close-reason vocabulary; `'stop'` there is the
|
|
702
|
-
// agent's own `Stop`, the only close this hold is about.
|
|
703
|
-
if (publishesTurnRecord(data) && events.closedBy !== 'stop')
|
|
704
|
-
return null;
|
|
705
|
-
return events.lastEventAt ?? null;
|
|
706
|
-
}
|
|
707
|
-
/**
|
|
708
|
-
* When this (worktree, instance) was last handed a prompt (Issue #1975).
|
|
709
|
-
*
|
|
710
|
-
* `limit=1&unit=pairs` is "every row at or after the newest user message"
|
|
711
|
-
* (src/lib/db/chat-db.ts), which is the smallest query that is *guaranteed* to
|
|
712
|
-
* contain that message: plain `limit=1` returns the newest row of either role,
|
|
713
|
-
* and for a turn the agent has already answered that row is the assistant's.
|
|
714
|
-
*
|
|
715
|
-
* Scoped the same way the poll above is: `--instance` when the caller named one,
|
|
716
|
-
* otherwise the `cliToolId` the server resolved for that same poll. Asking
|
|
717
|
-
* unscoped would let a message sent to claude decide a wait on codex.
|
|
718
|
-
*
|
|
719
|
-
* Never throws. An unreadable ledger is not evidence that nothing was sent, so
|
|
720
|
-
* it is reported as such rather than as "nothing was sent" — the call site
|
|
721
|
-
* degrades to the pre-#1975 behaviour instead of holding on a guess.
|
|
722
|
-
*/
|
|
723
|
-
async function readNewestPromptAt(client, worktreeId, options, data) {
|
|
724
|
-
const query = new URLSearchParams({ limit: '1', unit: 'pairs' });
|
|
725
|
-
if (options.instance)
|
|
726
|
-
query.set('instance', options.instance);
|
|
727
|
-
else if (data.cliToolId)
|
|
728
|
-
query.set('cliTool', data.cliToolId);
|
|
729
|
-
try {
|
|
730
|
-
const rows = await client.get(`/api/worktrees/${worktreeId}/messages?${query.toString()}`);
|
|
731
|
-
let newest = null;
|
|
732
|
-
for (const row of rows ?? []) {
|
|
733
|
-
if (row.role !== 'user')
|
|
734
|
-
continue;
|
|
735
|
-
// ISO string on the wire (a JSON-serialized Date), so this is the only
|
|
736
|
-
// place the two clocks meet — and both sides of the comparison below are
|
|
737
|
-
// stamped by the server, so no CLI/server skew enters the verdict.
|
|
738
|
-
const at = Date.parse(row.timestamp);
|
|
739
|
-
if (Number.isNaN(at))
|
|
740
|
-
continue;
|
|
741
|
-
if (newest === null || at > newest)
|
|
742
|
-
newest = at;
|
|
743
|
-
}
|
|
744
|
-
return { readable: true, submittedAt: newest };
|
|
745
|
-
}
|
|
746
|
-
catch (error) {
|
|
747
|
-
console.error(`Note: could not read the message ledger for ${worktreeId} ` +
|
|
748
|
-
`(${error instanceof Error ? error.message : String(error)}); ` +
|
|
749
|
-
'completion will be judged from the frame alone.');
|
|
750
|
-
return { readable: false };
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* Whether the newest prompt this instance was handed is still unanswered
|
|
755
|
-
* (Issue #1975).
|
|
756
|
-
*
|
|
757
|
-
* This is the distinction the whole Issue turns on, and it is a comparison of
|
|
758
|
-
* two server-stamped facts rather than a timer:
|
|
759
|
-
*
|
|
760
|
-
* - **idle before this wait began** — the agent's `Stop` postdates the newest
|
|
761
|
-
* prompt. Nothing is outstanding; `wait` completes on the first poll exactly
|
|
762
|
-
* as it always has. An orchestrator waiting on a session that finished long
|
|
763
|
-
* ago pays nothing.
|
|
764
|
-
* - **`send` a moment ago** — the newest prompt postdates the last `Stop`
|
|
765
|
-
* (or there has never been one). The agent has been given work and has not
|
|
766
|
-
* reported finishing it, so a composer frame is "it has not started yet",
|
|
767
|
-
* not "it is done".
|
|
768
|
-
*
|
|
769
|
-
* `wait` could not tell these apart before, because from `current-output` alone
|
|
770
|
-
* they are the same payload: in both, the last thing the agent said was the
|
|
771
|
-
* previous turn's `stop`, and `adoptTurnStart` adopts nothing. Measured against
|
|
772
|
-
* copilot 1.0.80 on 2026-08-22, the window in which that is true after a send is
|
|
773
|
-
* ~1s wide, and `wait`'s first poll is immediate — which is why the false
|
|
774
|
-
* completions came back in 0.3s with `basis=scraper_ready`, 3 times in 5.
|
|
775
|
-
*
|
|
776
|
-
* The fast-turn case falls out of the same comparison rather than needing a rule
|
|
777
|
-
* of its own: a turn that opens and closes between two polls leaves
|
|
778
|
-
* `lastEventType: 'stop'` (so no turn is adopted) but a `stop` that postdates
|
|
779
|
-
* the prompt — answered, and completed on the spot.
|
|
780
|
-
*/
|
|
781
|
-
function outstandingPrompt(data, submittedAt) {
|
|
782
|
-
const stoppedAt = data.lastStopEventAt;
|
|
783
|
-
return stoppedAt == null || stoppedAt < submittedAt;
|
|
784
|
-
}
|
|
785
112
|
/**
|
|
786
113
|
* How long `--on-prompt agent` holds a prompt the target's own Auto-Yes is
|
|
787
114
|
* answering before reporting it anyway, in seconds (Issue #2463).
|
|
@@ -815,25 +142,6 @@ function parseGraceSeconds(raw) {
|
|
|
815
142
|
const trimmed = raw.trim();
|
|
816
143
|
return /^\d+$/.test(trimmed) ? Number(trimmed) : Number.NaN;
|
|
817
144
|
}
|
|
818
|
-
/**
|
|
819
|
-
* Whether one more poll interval still lands inside `--timeout` and
|
|
820
|
-
* `--stall-timeout` (Issue #2463).
|
|
821
|
-
*
|
|
822
|
-
* The Auto-Yes hold asks before it sleeps. Otherwise a caller whose deadline
|
|
823
|
-
* lapses during the hold would hear 124 about a prompt it used to hear 10 about:
|
|
824
|
-
* the hold is there to give Auto-Yes a chance to answer, not to turn an open
|
|
825
|
-
* prompt into a timeout. The same two checks the top of {@link pollWorktree}'s
|
|
826
|
-
* loop makes, one interval ahead.
|
|
827
|
-
*/
|
|
828
|
-
function nextPollWithinDeadlines(options, startTime, lastActivityTime, now) {
|
|
829
|
-
const nextPollAt = now + POLL_INTERVAL_MS;
|
|
830
|
-
if (options.timeout && nextPollAt - startTime >= options.timeout * 1000)
|
|
831
|
-
return false;
|
|
832
|
-
if (options.stallTimeout && nextPollAt - lastActivityTime >= options.stallTimeout * 1000) {
|
|
833
|
-
return false;
|
|
834
|
-
}
|
|
835
|
-
return true;
|
|
836
|
-
}
|
|
837
145
|
/**
|
|
838
146
|
* The exit-10 payload for a prompt the detection layer parsed. `suppressed` is
|
|
839
147
|
* {@link activeSuppression}'s reading of the same poll.
|
|
@@ -922,7 +230,7 @@ function describeUnclassifiedFrame(worktreeId, data, dwellMs) {
|
|
|
922
230
|
// one recovery is a keystroke in the pane. Riding the message keeps
|
|
923
231
|
// the exit-code table (10, `type: unclassified`) unchanged for every
|
|
924
232
|
// caller that already branches on it.
|
|
925
|
-
describePaneObstruction(data));
|
|
233
|
+
(0, wait_notices_1.describePaneObstruction)(data));
|
|
926
234
|
}
|
|
927
235
|
/** The exit-10 payload for a persistently unclassified frame (Issue #1708). */
|
|
928
236
|
function buildUnclassifiedOutput(worktreeId, data, question) {
|
|
@@ -1004,9 +312,9 @@ function promptStage(poll, state, data) {
|
|
|
1004
312
|
// Issue #1699: report a policy suppression on both exits — the human one
|
|
1005
313
|
// keeps polling and would otherwise say nothing about why nobody
|
|
1006
314
|
// answered, and the agent one is read by pipelines that never see stderr.
|
|
1007
|
-
const suppressed = activeSuppression(data, Date.now());
|
|
315
|
+
const suppressed = (0, wait_notices_1.activeSuppression)(data, Date.now());
|
|
1008
316
|
// Issue #3821: withheld by the server's decision, with no suppression to say so.
|
|
1009
|
-
const decisionWithheld = suppressed ? null : decisionWithheldReason(data);
|
|
317
|
+
const decisionWithheld = suppressed ? null : (0, wait_notices_1.decisionWithheldReason)(data);
|
|
1010
318
|
const decisionNotice = decisionWithheld === null
|
|
1011
319
|
? null
|
|
1012
320
|
: ` auto-yes is not answering this prompt (reason=${decisionWithheld}); it is a human's to answer.`;
|
|
@@ -1015,16 +323,16 @@ function promptStage(poll, state, data) {
|
|
|
1015
323
|
// Block and continue polling - user handles prompt manually
|
|
1016
324
|
console.error(`Prompt detected on ${worktreeId}. Waiting for human response...`);
|
|
1017
325
|
if (suppressed) {
|
|
1018
|
-
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds, suppressed.answerMode));
|
|
326
|
+
console.error((0, wait_notices_1.formatSuppressionNotice)(suppressed.suppression, suppressed.ageSeconds, suppressed.answerMode));
|
|
1019
327
|
}
|
|
1020
328
|
if (decisionNotice)
|
|
1021
329
|
console.error(decisionNotice);
|
|
1022
330
|
// Issue #3397: and whether Auto-Yes already pressed Enter on it.
|
|
1023
|
-
const enterNotice = formatEnterFallbackNotice(data, Date.now());
|
|
331
|
+
const enterNotice = (0, wait_notices_1.formatEnterFallbackNotice)(data, Date.now());
|
|
1024
332
|
if (enterNotice)
|
|
1025
333
|
console.error(enterNotice);
|
|
1026
334
|
// Issue #3730: and whether a restart is why nothing is answering it.
|
|
1027
|
-
const restartNotice = formatRestartReleaseNotice(worktreeId, data, poll.options.instance);
|
|
335
|
+
const restartNotice = (0, wait_notices_1.formatRestartReleaseNotice)(worktreeId, data, poll.options.instance);
|
|
1028
336
|
if (restartNotice)
|
|
1029
337
|
console.error(restartNotice);
|
|
1030
338
|
return { kind: 'wait' };
|
|
@@ -1047,7 +355,7 @@ function promptStage(poll, state, data) {
|
|
|
1047
355
|
}
|
|
1048
356
|
const heldMs = now - state.autoYesAnsweringSince;
|
|
1049
357
|
if (heldMs < autoYesGraceMs &&
|
|
1050
|
-
nextPollWithinDeadlines(options, startTime, state.lastActivityTime, now)) {
|
|
358
|
+
(0, wait_timing_1.nextPollWithinDeadlines)(options, startTime, state.lastActivityTime, now)) {
|
|
1051
359
|
return { kind: 'wait' };
|
|
1052
360
|
}
|
|
1053
361
|
console.error(heldMs < autoYesGraceMs
|
|
@@ -1062,16 +370,16 @@ function promptStage(poll, state, data) {
|
|
|
1062
370
|
// Default (agent mode): output prompt info and exit 10
|
|
1063
371
|
const promptOutput = buildPromptOutput(worktreeId, data, data.promptData, suppressed);
|
|
1064
372
|
if (suppressed) {
|
|
1065
|
-
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds, suppressed.answerMode));
|
|
373
|
+
console.error((0, wait_notices_1.formatSuppressionNotice)(suppressed.suppression, suppressed.ageSeconds, suppressed.answerMode));
|
|
1066
374
|
}
|
|
1067
375
|
if (decisionNotice)
|
|
1068
376
|
console.error(decisionNotice);
|
|
1069
377
|
// Issue #3397: stderr only, like the notice above; the exit-10 payload is unchanged.
|
|
1070
|
-
const enterNotice = formatEnterFallbackNotice(data, Date.now());
|
|
378
|
+
const enterNotice = (0, wait_notices_1.formatEnterFallbackNotice)(data, Date.now());
|
|
1071
379
|
if (enterNotice)
|
|
1072
380
|
console.error(enterNotice);
|
|
1073
381
|
// Issue #3730: stderr only as well.
|
|
1074
|
-
const restartNotice = formatRestartReleaseNotice(worktreeId, data, poll.options.instance);
|
|
382
|
+
const restartNotice = (0, wait_notices_1.formatRestartReleaseNotice)(worktreeId, data, poll.options.instance);
|
|
1075
383
|
if (restartNotice)
|
|
1076
384
|
console.error(restartNotice);
|
|
1077
385
|
return exitWith({ exitCode: types_1.WaitExitCode.PROMPT_DETECTED, output: promptOutput });
|
|
@@ -1091,18 +399,18 @@ function selectionListStage(poll, data) {
|
|
|
1091
399
|
'Waiting for human response...');
|
|
1092
400
|
// Issue #1699: the poller parses frames status-detector publishes as
|
|
1093
401
|
// selection lists, so a policy can be the reason this one is stuck too.
|
|
1094
|
-
const suppressed = activeSuppression(data, Date.now());
|
|
402
|
+
const suppressed = (0, wait_notices_1.activeSuppression)(data, Date.now());
|
|
1095
403
|
if (suppressed) {
|
|
1096
|
-
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds, suppressed.answerMode));
|
|
404
|
+
console.error((0, wait_notices_1.formatSuppressionNotice)(suppressed.suppression, suppressed.ageSeconds, suppressed.answerMode));
|
|
1097
405
|
}
|
|
1098
406
|
// Issue #3730
|
|
1099
|
-
const restartNotice = formatRestartReleaseNotice(worktreeId, data, poll.options.instance);
|
|
407
|
+
const restartNotice = (0, wait_notices_1.formatRestartReleaseNotice)(worktreeId, data, poll.options.instance);
|
|
1100
408
|
if (restartNotice)
|
|
1101
409
|
console.error(restartNotice);
|
|
1102
410
|
return { kind: 'wait' };
|
|
1103
411
|
}
|
|
1104
412
|
// Issue #3730: stderr only; the exit-10 payload is unchanged.
|
|
1105
|
-
const restartNotice = formatRestartReleaseNotice(worktreeId, data, poll.options.instance);
|
|
413
|
+
const restartNotice = (0, wait_notices_1.formatRestartReleaseNotice)(worktreeId, data, poll.options.instance);
|
|
1106
414
|
if (restartNotice)
|
|
1107
415
|
console.error(restartNotice);
|
|
1108
416
|
return exitWith({
|
|
@@ -1161,7 +469,7 @@ function unclassifiedStage(poll, state, data) {
|
|
|
1161
469
|
if (dwellMs >= UNCLASSIFIED_DWELL_MS) {
|
|
1162
470
|
const question = describeUnclassifiedFrame(worktreeId, data, dwellMs);
|
|
1163
471
|
// Issue #3730: why Auto-Yes is not there to answer it, if a restart is why.
|
|
1164
|
-
const restartNotice = formatRestartReleaseNotice(worktreeId, data, poll.options.instance);
|
|
472
|
+
const restartNotice = (0, wait_notices_1.formatRestartReleaseNotice)(worktreeId, data, poll.options.instance);
|
|
1165
473
|
if (options.onPrompt === 'human') {
|
|
1166
474
|
console.error(question);
|
|
1167
475
|
if (restartNotice)
|
|
@@ -1203,14 +511,25 @@ function notRunningStage(poll, state, data, selfResumeSuffix) {
|
|
|
1203
511
|
return exitWith({ exitCode: types_1.VerifyExitCode.NOT_STARTED });
|
|
1204
512
|
}
|
|
1205
513
|
if (!data.isRunning) {
|
|
1206
|
-
console.error(`Completed: ${worktreeId} (basis=${COMPLETION_BASIS.SESSION_GONE}${selfResumeSuffix()})`);
|
|
514
|
+
console.error(`Completed: ${worktreeId} (basis=${wait_turn_boundary_1.COMPLETION_BASIS.SESSION_GONE}${selfResumeSuffix()})`);
|
|
1207
515
|
return exitWith({ exitCode: types_1.WaitExitCode.SUCCESS });
|
|
1208
516
|
}
|
|
1209
517
|
return { kind: 'next' };
|
|
1210
518
|
}
|
|
519
|
+
/**
|
|
520
|
+
* The upstream fault on the frame that `--fail-on-upstream-fault` reports, or
|
|
521
|
+
* null (Issue #1839). Prints nothing, so a caller can decide which frame the
|
|
522
|
+
* verdict is on before {@link upstreamFaultStage} reports it (Issue #3956).
|
|
523
|
+
*/
|
|
524
|
+
function reportableUpstreamFault(poll, data) {
|
|
525
|
+
if (!poll.options.failOnUpstreamFault)
|
|
526
|
+
return null;
|
|
527
|
+
return data.upstreamFault ?? null;
|
|
528
|
+
}
|
|
1211
529
|
/**
|
|
1212
530
|
* Stage of a `ready` frame: an upstream fault on the frame, under
|
|
1213
|
-
* `--fail-on-upstream-fault` (Issue #1839). Exit 11
|
|
531
|
+
* `--fail-on-upstream-fault` (Issue #1839). Exit 11, with its diagnosis on
|
|
532
|
+
* stderr.
|
|
1214
533
|
*/
|
|
1215
534
|
function upstreamFaultStage(poll, data) {
|
|
1216
535
|
const { worktreeId, options } = poll;
|
|
@@ -1219,8 +538,8 @@ function upstreamFaultStage(poll, data) {
|
|
|
1219
538
|
// because it is the answer to the question that gate can only ask: the
|
|
1220
539
|
// turn did not end, and this is why. Without it the same session runs
|
|
1221
540
|
// to --timeout and reports 124, which says nothing about the cause.
|
|
1222
|
-
const fault = data
|
|
1223
|
-
if (
|
|
541
|
+
const fault = reportableUpstreamFault(poll, data);
|
|
542
|
+
if (fault) {
|
|
1224
543
|
console.error(`Upstream fault on ${worktreeId}: id=${fault.id} — the agent is back at its ` +
|
|
1225
544
|
'composer with an upstream API failure on screen, so this turn did not run. ' +
|
|
1226
545
|
`Matched: ${JSON.stringify(fault.matchedText)}`);
|
|
@@ -1237,6 +556,32 @@ function upstreamFaultStage(poll, data) {
|
|
|
1237
556
|
}
|
|
1238
557
|
return { kind: 'next' };
|
|
1239
558
|
}
|
|
559
|
+
/**
|
|
560
|
+
* The chat-ledger read of a poll, bounded by `--timeout` / `--stall-timeout`
|
|
561
|
+
* (Issue #3974).
|
|
562
|
+
*
|
|
563
|
+
* On an ordinary poll, a ledger that does not answer in time ends the wait
|
|
564
|
+
* ({@link DeadlineReached} back to {@link deadlineStage}, exit 124), not
|
|
565
|
+
* "unreadable". On the frame a settle returned (`judgingSettledFrame`) it does
|
|
566
|
+
* not: that frame was read inside the deadlines and is judged even after them
|
|
567
|
+
* (#3956), so the ledger is reported unreadable and the frame decides alone —
|
|
568
|
+
* as {@link faultFrameHasStop} treats a ledger cut by the same deadlines.
|
|
569
|
+
*/
|
|
570
|
+
async function readLedgerWithinDeadlines(poll, state, data, judgingSettledFrame) {
|
|
571
|
+
const { client, worktreeId, options, startTime } = poll;
|
|
572
|
+
try {
|
|
573
|
+
// Quiet when aborted: what the deadline leads to is said here (settled
|
|
574
|
+
// frame) or by deadlineStage (124), not "judged from the frame alone".
|
|
575
|
+
return await (0, wait_timing_1.readWithinDeadlines)(options, startTime, state.lastActivityTime, signal => (0, wait_turn_boundary_1.readNewestPromptAt)(client, worktreeId, options, data, signal, true));
|
|
576
|
+
}
|
|
577
|
+
catch (error) {
|
|
578
|
+
if (!judgingSettledFrame || !(error instanceof wait_timing_1.DeadlineReached))
|
|
579
|
+
throw error;
|
|
580
|
+
console.error(`Note: the message ledger for ${worktreeId} could not be read within --timeout/--stall-timeout; ` +
|
|
581
|
+
'judging the settled frame alone.');
|
|
582
|
+
return { readable: false };
|
|
583
|
+
}
|
|
584
|
+
}
|
|
1240
585
|
/**
|
|
1241
586
|
* How long `wait` holds an orphan turn — see {@link releaseOrphanTurn} — before
|
|
1242
587
|
* completing on the `Stop` that answered the newest prompt (Issue #3429).
|
|
@@ -1247,7 +592,7 @@ function upstreamFaultStage(poll, data) {
|
|
|
1247
592
|
* is restarted by any change to the frame, so a pane that is still drawing is
|
|
1248
593
|
* never released. `--timeout` and `--stall-timeout` below it still win.
|
|
1249
594
|
*/
|
|
1250
|
-
const ORPHAN_TURN_HOLD_MS = PENDING_PROMPT_HOLD_MS;
|
|
595
|
+
const ORPHAN_TURN_HOLD_MS = wait_turn_boundary_1.PENDING_PROMPT_HOLD_MS;
|
|
1251
596
|
/**
|
|
1252
597
|
* Whether the unsettled turn this wait adopted is an orphan the agent will never
|
|
1253
598
|
* send a `Stop` for, held for {@link ORPHAN_TURN_HOLD_MS} (Issue #3429).
|
|
@@ -1268,13 +613,13 @@ const ORPHAN_TURN_HOLD_MS = PENDING_PROMPT_HOLD_MS;
|
|
|
1268
613
|
* prompt has no `Stop` after it — that one keeps holding to `--timeout`;
|
|
1269
614
|
* - the frame has not changed for {@link ORPHAN_TURN_HOLD_MS}.
|
|
1270
615
|
*/
|
|
1271
|
-
async function releaseOrphanTurn(poll, state, data) {
|
|
1272
|
-
const {
|
|
616
|
+
async function releaseOrphanTurn(poll, state, data, judgingSettledFrame) {
|
|
617
|
+
const { worktreeId } = poll;
|
|
1273
618
|
const events = data.structuredEvents;
|
|
1274
619
|
const closedByScreen = events?.closedBy === 'scraper_evidence' || events?.closedBy === 'stale';
|
|
1275
620
|
if (!events ||
|
|
1276
|
-
!publishesTurnRecord(data) ||
|
|
1277
|
-
!reportsTurnBoundaries(data) ||
|
|
621
|
+
!(0, wait_turn_boundary_1.publishesTurnRecord)(data) ||
|
|
622
|
+
!(0, wait_turn_boundary_1.reportsTurnBoundaries)(data) ||
|
|
1278
623
|
events.closedAt == null ||
|
|
1279
624
|
events.openedAt == null ||
|
|
1280
625
|
!closedByScreen ||
|
|
@@ -1283,9 +628,10 @@ async function releaseOrphanTurn(poll, state, data) {
|
|
|
1283
628
|
state.orphanTurnHold = null;
|
|
1284
629
|
return false;
|
|
1285
630
|
}
|
|
1286
|
-
|
|
631
|
+
// Issue #3974: bounded by --timeout / --stall-timeout.
|
|
632
|
+
const ledger = await readLedgerWithinDeadlines(poll, state, data, judgingSettledFrame);
|
|
1287
633
|
state.promptLedgerReadable = ledger.readable;
|
|
1288
|
-
if (!ledger.readable || ledger.submittedAt === null || outstandingPrompt(data, ledger.submittedAt)) {
|
|
634
|
+
if (!ledger.readable || ledger.submittedAt === null || (0, wait_turn_boundary_1.outstandingPrompt)(data, ledger.submittedAt)) {
|
|
1289
635
|
state.orphanTurnHold = null;
|
|
1290
636
|
return false;
|
|
1291
637
|
}
|
|
@@ -1298,7 +644,7 @@ async function releaseOrphanTurn(poll, state, data) {
|
|
|
1298
644
|
return false;
|
|
1299
645
|
console.error(`Note: ${worktreeId} answered its newest prompt with a stop ` +
|
|
1300
646
|
`(lastStopEventAt=${data.lastStopEventAt}), and the turn opened after it ` +
|
|
1301
|
-
`(turnStartedAt=${state.turnStartedAt}, ${describeTurnClose(data)}) has had no prompt, ` +
|
|
647
|
+
`(turnStartedAt=${state.turnStartedAt}, ${(0, wait_turn_boundary_1.describeTurnClose)(data)}) has had no prompt, ` +
|
|
1302
648
|
`no stop and no new output for ${Math.round(quietMs / 1000)}s; completing on that stop.`);
|
|
1303
649
|
return true;
|
|
1304
650
|
}
|
|
@@ -1306,7 +652,7 @@ async function releaseOrphanTurn(poll, state, data) {
|
|
|
1306
652
|
* Stage of a `ready` frame: the agent has not reported the end of the turn this
|
|
1307
653
|
* wait adopted (Issue #1839). Held, except for an orphan turn (Issue #3429).
|
|
1308
654
|
*/
|
|
1309
|
-
async function unsettledTurnStage(poll, state, data) {
|
|
655
|
+
async function unsettledTurnStage(poll, state, data, judgingSettledFrame) {
|
|
1310
656
|
const { worktreeId } = poll;
|
|
1311
657
|
// Issue #1839: `ready` off the terminal frame is the agent's composer,
|
|
1312
658
|
// not the agent's verdict. Measured 2026-08-20 against a stub upstream
|
|
@@ -1315,12 +661,12 @@ async function unsettledTurnStage(poll, state, data) {
|
|
|
1315
661
|
// hooks ARE reporting — the only case in which `turnStartedAt` is
|
|
1316
662
|
// non-null — that missing `Stop` is the difference between "finished"
|
|
1317
663
|
// and "never ran", and it is the only signal that carries it.
|
|
1318
|
-
if (!turnSettled(data, state.turnStartedAt)) {
|
|
1319
|
-
if (await releaseOrphanTurn(poll, state, data))
|
|
664
|
+
if (!(0, wait_turn_boundary_1.turnSettled)(data, state.turnStartedAt)) {
|
|
665
|
+
if (await releaseOrphanTurn(poll, state, data, judgingSettledFrame))
|
|
1320
666
|
return { kind: 'next' };
|
|
1321
667
|
console.error(`Waiting: ${worktreeId} is back at its composer, but its agent has not reported ` +
|
|
1322
668
|
`the end of this turn (turnStartedAt=${state.turnStartedAt}, ` +
|
|
1323
|
-
`lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
|
|
669
|
+
`lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${(0, wait_turn_boundary_1.describeTurnClose)(data)}). ` +
|
|
1324
670
|
'Not reporting completion; inspect with ' +
|
|
1325
671
|
`\`commandmate capture ${worktreeId} --json\`.`);
|
|
1326
672
|
return { kind: 'wait' };
|
|
@@ -1352,13 +698,13 @@ function selfResumeHoldStage(poll, state, data, selfResumeStopAt) {
|
|
|
1352
698
|
state.selfResumeHold = { stopAt: selfResumeStopAt, since: now };
|
|
1353
699
|
const heldMs = now - state.selfResumeHold.since;
|
|
1354
700
|
const elapsedMs = Math.max(heldMs, now - selfResumeStopAt);
|
|
1355
|
-
if (elapsedMs <
|
|
701
|
+
if (elapsedMs < wait_turn_boundary_1.SELF_RESUME_HOLD_MS) {
|
|
1356
702
|
state.selfResumeHeld = true;
|
|
1357
703
|
console.error(`Waiting: ${worktreeId} ended its turn with background work still running ` +
|
|
1358
704
|
`(stoppedAt=${new Date(selfResumeStopAt).toISOString()}, ` +
|
|
1359
|
-
`lastEventDetail=${
|
|
705
|
+
`lastEventDetail=${wait_turn_boundary_1.SELF_RESUME_PENDING_DETAIL}, ${(0, wait_turn_boundary_1.describeTurnClose)(data)}); ` +
|
|
1360
706
|
'it resumes by itself when that work finishes. Not reporting completion ' +
|
|
1361
|
-
`(held ${Math.round(heldMs / 1000)}s, at most ${
|
|
707
|
+
`(held ${Math.round(heldMs / 1000)}s, at most ${wait_turn_boundary_1.SELF_RESUME_HOLD_MS / 1000}s ` +
|
|
1362
708
|
'after the stop).');
|
|
1363
709
|
return { kind: 'wait' };
|
|
1364
710
|
}
|
|
@@ -1374,8 +720,8 @@ function selfResumeHoldStage(poll, state, data, selfResumeStopAt) {
|
|
|
1374
720
|
* `next` carries whether the newest prompt was answered, which
|
|
1375
721
|
* {@link completionStage} needs for its basis.
|
|
1376
722
|
*/
|
|
1377
|
-
async function promptLedgerStage(poll, state, data) {
|
|
1378
|
-
const {
|
|
723
|
+
async function promptLedgerStage(poll, state, data, judgingSettledFrame) {
|
|
724
|
+
const { worktreeId, startTime } = poll;
|
|
1379
725
|
// Issue #1975: the same frame, one question further back. #1839's gate
|
|
1380
726
|
// above can only fire once a turn has been ADOPTED, and `send` leaves a
|
|
1381
727
|
// window ~1s wide in which nothing has been: the newest structured event
|
|
@@ -1393,18 +739,19 @@ async function promptLedgerStage(poll, state, data) {
|
|
|
1393
739
|
// {@link reportsTurnBoundaries} for why a tool that posts no hooks never
|
|
1394
740
|
// reaches it.
|
|
1395
741
|
let answeredNewestPrompt = false;
|
|
1396
|
-
if (state.turnStartedAt === null && state.promptLedgerReadable && reportsTurnBoundaries(data)) {
|
|
1397
|
-
|
|
742
|
+
if (state.turnStartedAt === null && state.promptLedgerReadable && (0, wait_turn_boundary_1.reportsTurnBoundaries)(data)) {
|
|
743
|
+
// Issue #3974: bounded by --timeout / --stall-timeout.
|
|
744
|
+
const ledger = await readLedgerWithinDeadlines(poll, state, data, judgingSettledFrame);
|
|
1398
745
|
// One notice, then stop asking: a ledger that failed once will fail
|
|
1399
746
|
// every poll, and the point of degrading is to stop paying for it.
|
|
1400
747
|
state.promptLedgerReadable = ledger.readable;
|
|
1401
748
|
if (ledger.readable && ledger.submittedAt !== null) {
|
|
1402
|
-
if (outstandingPrompt(data, ledger.submittedAt)) {
|
|
749
|
+
if ((0, wait_turn_boundary_1.outstandingPrompt)(data, ledger.submittedAt)) {
|
|
1403
750
|
const heldMs = Date.now() - startTime;
|
|
1404
|
-
if (heldMs < PENDING_PROMPT_HOLD_MS) {
|
|
751
|
+
if (heldMs < wait_turn_boundary_1.PENDING_PROMPT_HOLD_MS) {
|
|
1405
752
|
console.error(`Waiting: ${worktreeId} is at its composer, but the newest prompt sent to it ` +
|
|
1406
753
|
`has no reported end (sentAt=${new Date(ledger.submittedAt).toISOString()}, ` +
|
|
1407
|
-
`lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
|
|
754
|
+
`lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${(0, wait_turn_boundary_1.describeTurnClose)(data)}). ` +
|
|
1408
755
|
'Not reporting completion: the agent has not started this turn yet.');
|
|
1409
756
|
return { kind: 'wait' };
|
|
1410
757
|
}
|
|
@@ -1419,25 +766,34 @@ async function promptLedgerStage(poll, state, data) {
|
|
|
1419
766
|
}
|
|
1420
767
|
return { kind: 'next', answeredNewestPrompt };
|
|
1421
768
|
}
|
|
769
|
+
/**
|
|
770
|
+
* The basis of a completion on a `ready` frame (Issue #1839).
|
|
771
|
+
*
|
|
772
|
+
* `hook_stop` on both branches that have one, and they are the same statement
|
|
773
|
+
* made from two records: the agent reported the end of the turn this wait is
|
|
774
|
+
* about. `scraper_ready` keeps its documented meaning — "the screen said so and
|
|
775
|
+
* nothing corroborated it" — which is now exactly the set of cases that reach it.
|
|
776
|
+
*/
|
|
777
|
+
function readyCompletionBasis(state, answeredNewestPrompt) {
|
|
778
|
+
return state.turnStartedAt !== null || answeredNewestPrompt
|
|
779
|
+
? wait_turn_boundary_1.COMPLETION_BASIS.HOOK_STOP
|
|
780
|
+
: wait_turn_boundary_1.COMPLETION_BASIS.SCRAPER_READY;
|
|
781
|
+
}
|
|
1422
782
|
/** Last stage of a `ready` frame: the completion line with its basis. Exit 0. */
|
|
1423
783
|
function completionStage(poll, state, answeredNewestPrompt, selfResumeSuffix) {
|
|
1424
784
|
const { worktreeId } = poll;
|
|
1425
|
-
|
|
1426
|
-
// statement made from two records: the agent reported the end of the
|
|
1427
|
-
// turn this wait is about. `scraper_ready` keeps its documented meaning
|
|
1428
|
-
// — "the screen said so and nothing corroborated it" — which is now
|
|
1429
|
-
// exactly the set of cases that reach it.
|
|
1430
|
-
const basis = state.turnStartedAt !== null || answeredNewestPrompt
|
|
1431
|
-
? COMPLETION_BASIS.HOOK_STOP
|
|
1432
|
-
: COMPLETION_BASIS.SCRAPER_READY;
|
|
785
|
+
const basis = readyCompletionBasis(state, answeredNewestPrompt);
|
|
1433
786
|
console.error(`Completed: ${worktreeId} (basis=${basis}${selfResumeSuffix()})`);
|
|
1434
787
|
return exitWith({ exitCode: types_1.WaitExitCode.SUCCESS });
|
|
1435
788
|
}
|
|
1436
789
|
/**
|
|
1437
790
|
* Stage: the agent is back at its composer on a frame that was understood. Asks
|
|
1438
791
|
* the stages of a `ready` frame in order; the first that applies decides.
|
|
792
|
+
*
|
|
793
|
+
* `judgingSettledFrame` is true when `data` is the frame a settle returned
|
|
794
|
+
* (Issue #3956): it is judged as it stands and never settled again.
|
|
1439
795
|
*/
|
|
1440
|
-
async function readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix) {
|
|
796
|
+
async function readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix, judgingSettledFrame) {
|
|
1441
797
|
// Issue #1708 narrowed Path B: `ready` is only a completion when the frame
|
|
1442
798
|
// was actually understood. A structured `hook_stop` over an unreadable
|
|
1443
799
|
// pane is the degraded form of an overlay nobody could parse (see the note
|
|
@@ -1445,18 +801,41 @@ async function readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix)
|
|
|
1445
801
|
// merged. Path A is untouched — a session that went away really is
|
|
1446
802
|
// finished, and carries no flag anyway.
|
|
1447
803
|
if (data.sessionStatus === 'ready' && data.isUnclassifiedActive !== true) {
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
804
|
+
// Issue #3956: one bound for everything a `Stop` poll's settle waits on —
|
|
805
|
+
// the ledger read that confirms the `Stop` and the re-reads — measured
|
|
806
|
+
// from this poll, so the verdict comes at most HOOK_STOP_SETTLE_MAX_MS
|
|
807
|
+
// after it (`--timeout` is applied on top, where each wait is bounded).
|
|
808
|
+
const settleDeadline = Date.now() + wait_hook_stop_settle_1.HOOK_STOP_SETTLE_MAX_MS;
|
|
809
|
+
if (reportableUpstreamFault(poll, data) !== null) {
|
|
810
|
+
// Issue #3956: a fault on the frame of a `Stop` poll is on a pane that
|
|
811
|
+
// may still be drawing, as much as a clean one is; it is judged on the
|
|
812
|
+
// settled frame too. Without a `Stop` it is #1839's case, reported now.
|
|
813
|
+
// Nothing is printed before that is decided: the diagnosis is for the
|
|
814
|
+
// frame the verdict is on.
|
|
815
|
+
if (!judgingSettledFrame && (await (0, wait_hook_stop_settle_1.faultFrameHasStop)(poll, state, data, settleDeadline))) {
|
|
816
|
+
return { kind: 'settled', data: await (0, wait_hook_stop_settle_1.settleAfterHookStop)(poll, state, data, settleDeadline) };
|
|
817
|
+
}
|
|
818
|
+
return upstreamFaultStage(poll, data);
|
|
819
|
+
}
|
|
820
|
+
const turnOutcome = await unsettledTurnStage(poll, state, data, judgingSettledFrame);
|
|
1452
821
|
if (turnOutcome.kind !== 'next')
|
|
1453
822
|
return turnOutcome;
|
|
1454
823
|
const holdOutcome = selfResumeHoldStage(poll, state, data, selfResumeStopAt);
|
|
1455
824
|
if (holdOutcome.kind !== 'next')
|
|
1456
825
|
return holdOutcome;
|
|
1457
|
-
const ledgerOutcome = await promptLedgerStage(poll, state, data);
|
|
826
|
+
const ledgerOutcome = await promptLedgerStage(poll, state, data, judgingSettledFrame);
|
|
1458
827
|
if (ledgerOutcome.kind !== 'next')
|
|
1459
828
|
return ledgerOutcome;
|
|
829
|
+
// Issue #3956: the `Stop` can land before the end of the reply is on the
|
|
830
|
+
// pane, so a `hook_stop` completion is judged again on the settled frame —
|
|
831
|
+
// as a poll of its own, so a prompt or a new turn drawn meanwhile is not
|
|
832
|
+
// read as this completion. Only under the flag: a plain `wait` reads no
|
|
833
|
+
// fault and waits no longer.
|
|
834
|
+
if (!judgingSettledFrame &&
|
|
835
|
+
poll.options.failOnUpstreamFault &&
|
|
836
|
+
readyCompletionBasis(state, ledgerOutcome.answeredNewestPrompt) === wait_turn_boundary_1.COMPLETION_BASIS.HOOK_STOP) {
|
|
837
|
+
return { kind: 'settled', data: await (0, wait_hook_stop_settle_1.settleAfterHookStop)(poll, state, data, settleDeadline) };
|
|
838
|
+
}
|
|
1460
839
|
return completionStage(poll, state, ledgerOutcome.answeredNewestPrompt, selfResumeSuffix);
|
|
1461
840
|
}
|
|
1462
841
|
return { kind: 'next' };
|
|
@@ -1504,23 +883,34 @@ async function pollWorktree(client, worktreeId, options) {
|
|
|
1504
883
|
const total = state.selfResumeHeldMs + (state.selfResumeHold ? Date.now() - state.selfResumeHold.since : 0);
|
|
1505
884
|
return `, heldForSelfResume=${Math.round(total / 1000)}s`;
|
|
1506
885
|
};
|
|
886
|
+
/**
|
|
887
|
+
* The frame a settle returned, judged as the next poll (Issue #3956). It was
|
|
888
|
+
* read inside the deadlines the settle kept to, so that poll does not ask
|
|
889
|
+
* {@link deadlineStage} again: a turn that completed in time is not a 124.
|
|
890
|
+
*/
|
|
891
|
+
let settledFrame = null;
|
|
1507
892
|
while (true) {
|
|
1508
|
-
const
|
|
1509
|
-
if (
|
|
1510
|
-
|
|
893
|
+
const judgingSettledFrame = settledFrame !== null;
|
|
894
|
+
if (!judgingSettledFrame) {
|
|
895
|
+
const deadlineOutcome = deadlineStage(poll, state);
|
|
896
|
+
if (deadlineOutcome.kind === 'exit')
|
|
897
|
+
return deadlineOutcome.result;
|
|
898
|
+
}
|
|
1511
899
|
try {
|
|
1512
900
|
// Issue #868: scope polling to a specific agent instance when provided.
|
|
1513
901
|
// Issue #3755: `observe=1` so an exit 10 carries the observation of the
|
|
1514
902
|
// very capture it was decided on (see {@link withObservation}).
|
|
1515
|
-
const data =
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
state.
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
903
|
+
const data = settledFrame ??
|
|
904
|
+
// Issue #3974: bounded by --timeout / --stall-timeout, so a server that
|
|
905
|
+
// does not answer cannot hold the wait past them.
|
|
906
|
+
(await (0, wait_timing_1.readWithinDeadlines)(options, startTime, state.lastActivityTime, signal => {
|
|
907
|
+
const path = (0, prompt_1.observedCurrentOutputPath)(worktreeId, options.instance);
|
|
908
|
+
return signal
|
|
909
|
+
? client.get(path, { signal })
|
|
910
|
+
: client.get(path);
|
|
911
|
+
}));
|
|
912
|
+
settledFrame = null;
|
|
913
|
+
(0, wait_poll_bookkeeping_1.trackPollActivity)(state, data);
|
|
1524
914
|
// Issue #3179: the agent is still launching. Work in progress, so keep
|
|
1525
915
|
// polling: no prompt or selection list is read off the launch's frame,
|
|
1526
916
|
// the unclassified dwell does not run, and a pane that does not exist yet
|
|
@@ -1529,220 +919,78 @@ async function pollWorktree(client, worktreeId, options) {
|
|
|
1529
919
|
// completion. The server bounds the launch, so this cannot hold forever.
|
|
1530
920
|
if (typeof data.startingSince === 'number') {
|
|
1531
921
|
state.unclassifiedSince = null;
|
|
1532
|
-
await sleep(POLL_INTERVAL_MS);
|
|
922
|
+
await (0, wait_timing_1.sleep)(wait_timing_1.POLL_INTERVAL_MS);
|
|
1533
923
|
continue;
|
|
1534
924
|
}
|
|
1535
|
-
|
|
1536
|
-
// poll that ends in a prompt — the same turn is still open when the human
|
|
1537
|
-
// answers and `--on-prompt human` resumes polling.
|
|
1538
|
-
state.turnStartedAt = adoptTurnStart(data, startTime, state.turnStartedAt);
|
|
925
|
+
(0, wait_poll_bookkeeping_1.adoptAndPublishTurn)(state, data, startTime, options);
|
|
1539
926
|
// Issue #2614: a self-resume hold is about one `stop`, and ends the first
|
|
1540
927
|
// time that `stop` is no longer the newest word — the agent woke (a
|
|
1541
928
|
// turn-opening event) or stopped again. Checked on every poll, ahead of
|
|
1542
929
|
// every exit, because the wake usually lands on a `running` frame that
|
|
1543
930
|
// never reaches the hold itself.
|
|
1544
|
-
const selfResumeStopAt = pendingSelfResumeStop(data);
|
|
1545
|
-
|
|
1546
|
-
const heldMs = Date.now() - state.selfResumeHold.since;
|
|
1547
|
-
state.selfResumeHeldMs += heldMs;
|
|
1548
|
-
state.selfResumeHold = null;
|
|
1549
|
-
console.error(`Note: ${worktreeId} has moved past the stop it said it would resume from ` +
|
|
1550
|
-
`(held ${Math.round(heldMs / 1000)}s); judging its current state.`);
|
|
1551
|
-
}
|
|
931
|
+
const selfResumeStopAt = (0, wait_turn_boundary_1.pendingSelfResumeStop)(data);
|
|
932
|
+
(0, wait_poll_bookkeeping_1.releaseMovedSelfResumeHold)(worktreeId, state, selfResumeStopAt);
|
|
1552
933
|
const promptOutcome = promptStage(poll, state, data);
|
|
1553
934
|
if (promptOutcome.kind === 'exit')
|
|
1554
935
|
return withObservation(promptOutcome.result, data);
|
|
1555
936
|
if (promptOutcome.kind === 'wait') {
|
|
1556
|
-
await sleep(POLL_INTERVAL_MS);
|
|
937
|
+
await (0, wait_timing_1.sleep)(wait_timing_1.POLL_INTERVAL_MS);
|
|
1557
938
|
continue;
|
|
1558
939
|
}
|
|
1559
940
|
// Issue #2463: the prompt the hold was waiting on has gone. Who answered it
|
|
1560
941
|
// is not on the wire — Auto-Yes, or a human at the pane — so the line says
|
|
1561
942
|
// only that it cleared; what the agent does next is for the checks below.
|
|
1562
|
-
|
|
1563
|
-
console.error(`Prompt on ${worktreeId} cleared after ` +
|
|
1564
|
-
`${Math.round((Date.now() - state.autoYesAnsweringSince) / 1000)}s; judging completion as usual.`);
|
|
1565
|
-
state.autoYesAnsweringSince = null;
|
|
1566
|
-
}
|
|
943
|
+
(0, wait_poll_bookkeeping_1.noteAutoYesPromptCleared)(worktreeId, state);
|
|
1567
944
|
const selectionListOutcome = selectionListStage(poll, data);
|
|
1568
945
|
if (selectionListOutcome.kind === 'exit')
|
|
1569
946
|
return withObservation(selectionListOutcome.result, data);
|
|
1570
947
|
if (selectionListOutcome.kind === 'wait') {
|
|
1571
|
-
await sleep(POLL_INTERVAL_MS);
|
|
948
|
+
await (0, wait_timing_1.sleep)(wait_timing_1.POLL_INTERVAL_MS);
|
|
1572
949
|
continue;
|
|
1573
950
|
}
|
|
1574
951
|
const unclassifiedOutcome = unclassifiedStage(poll, state, data);
|
|
1575
952
|
if (unclassifiedOutcome.kind === 'exit')
|
|
1576
953
|
return withObservation(unclassifiedOutcome.result, data);
|
|
1577
954
|
if (unclassifiedOutcome.kind === 'wait') {
|
|
1578
|
-
await sleep(POLL_INTERVAL_MS);
|
|
955
|
+
await (0, wait_timing_1.sleep)(wait_timing_1.POLL_INTERVAL_MS);
|
|
1579
956
|
continue;
|
|
1580
957
|
}
|
|
1581
958
|
const notRunningOutcome = notRunningStage(poll, state, data, selfResumeSuffix);
|
|
1582
959
|
if (notRunningOutcome.kind === 'exit')
|
|
1583
960
|
return notRunningOutcome.result;
|
|
1584
|
-
const readyOutcome = await readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix);
|
|
961
|
+
const readyOutcome = await readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix, judgingSettledFrame);
|
|
1585
962
|
if (readyOutcome.kind === 'exit')
|
|
1586
963
|
return readyOutcome.result;
|
|
964
|
+
if (readyOutcome.kind === 'settled') {
|
|
965
|
+
settledFrame = readyOutcome.data;
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
1587
968
|
if (readyOutcome.kind === 'wait') {
|
|
1588
|
-
|
|
969
|
+
// Issue #3974: the settled frame skipped deadlineStage, and its ledger
|
|
970
|
+
// read may have been cut by the deadline; ask it now rather than one
|
|
971
|
+
// interval late. With time left, the next poll comes as before.
|
|
972
|
+
if (judgingSettledFrame) {
|
|
973
|
+
const deadlineOutcome = deadlineStage(poll, state);
|
|
974
|
+
if (deadlineOutcome.kind === 'exit')
|
|
975
|
+
return deadlineOutcome.result;
|
|
976
|
+
}
|
|
977
|
+
await (0, wait_timing_1.sleep)(wait_timing_1.POLL_INTERVAL_MS);
|
|
1589
978
|
continue;
|
|
1590
979
|
}
|
|
1591
980
|
// Progress indicator on stderr [DR1-05]
|
|
1592
981
|
console.error(`Waiting: ${worktreeId} (status=${data.sessionStatus}, running=${data.isRunning}, prompt=${data.isPromptWaiting})`);
|
|
1593
982
|
}
|
|
1594
983
|
catch (error) {
|
|
984
|
+
// Issue #3974: a read ended by --timeout / --stall-timeout. Not a failed
|
|
985
|
+
// poll: straight back to deadlineStage, which exits 124.
|
|
986
|
+
if (error instanceof wait_timing_1.DeadlineReached)
|
|
987
|
+
continue;
|
|
1595
988
|
if (error instanceof api_client_1.ApiError) {
|
|
1596
989
|
throw error;
|
|
1597
990
|
}
|
|
1598
991
|
console.error(`Poll error for ${worktreeId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1599
992
|
}
|
|
1600
|
-
await sleep(POLL_INTERVAL_MS);
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
function sleep(ms) {
|
|
1604
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1605
|
-
}
|
|
1606
|
-
/** True when the caller asked for a verdict rather than "the agent stopped". */
|
|
1607
|
-
function verifyRequested(options) {
|
|
1608
|
-
return Boolean(options.verify || options.requireWork);
|
|
1609
|
-
}
|
|
1610
|
-
/**
|
|
1611
|
-
* Whether this poll outcome should still be handed to the verification gates.
|
|
1612
|
-
*
|
|
1613
|
-
* A completion is the obvious case. NOT_STARTED joins it (Issue #1628) so the
|
|
1614
|
-
* operator gets the gate results instead of a bare "no session": work committed
|
|
1615
|
-
* by an agent whose session has since gone away is still worth reporting. The
|
|
1616
|
-
* verdict is merged rather than substituted — mergeExitCode never lets a passing
|
|
1617
|
-
* run overwrite NOT_STARTED, so "wait never saw this agent" survives to the exit
|
|
1618
|
-
* code even when the gates are green.
|
|
1619
|
-
*/
|
|
1620
|
-
function shouldVerify(exitCode, options) {
|
|
1621
|
-
if (!verifyRequested(options))
|
|
1622
|
-
return false;
|
|
1623
|
-
return exitCode === types_1.WaitExitCode.SUCCESS || exitCode === types_1.VerifyExitCode.NOT_STARTED;
|
|
1624
|
-
}
|
|
1625
|
-
/**
|
|
1626
|
-
* Task statuses that mean "this wait is about that task".
|
|
1627
|
-
*
|
|
1628
|
-
* Mirrors ACTIVE_TASK_STATUSES in src/lib/db/tasks-db.ts. Deliberately narrower
|
|
1629
|
-
* than the set the server will attach a run to: this is a guess made from a
|
|
1630
|
-
* worktree id alone, and a task that had already finished before the wait began
|
|
1631
|
-
* is a different delegation, not this one.
|
|
1632
|
-
*/
|
|
1633
|
-
const IN_FLIGHT_TASK_STATUSES = new Set([
|
|
1634
|
-
'running',
|
|
1635
|
-
'waiting_input',
|
|
1636
|
-
'verifying',
|
|
1637
|
-
]);
|
|
1638
|
-
/**
|
|
1639
|
-
* Read the task this wait is about, before waiting for it (Issue #1620).
|
|
1640
|
-
*
|
|
1641
|
-
* Timing is the whole point. Agents are asked to run the gates themselves
|
|
1642
|
-
* before reporting completion, and doing so moves their task to a terminal
|
|
1643
|
-
* status — after which a verification run started with only a worktree id has
|
|
1644
|
-
* no contract to resolve, judges no scope, and still reports `passed`. Read
|
|
1645
|
-
* while the task is still in flight, the id survives that transition and the
|
|
1646
|
-
* run that follows is judged against the contract it was supposed to judge.
|
|
1647
|
-
*
|
|
1648
|
-
* Never throws: an unreadable ledger costs the attribution, and refusing to
|
|
1649
|
-
* verify over it would cost every gate.
|
|
1650
|
-
*
|
|
1651
|
-
* @returns the task id, or undefined to leave resolution to the server
|
|
1652
|
-
*/
|
|
1653
|
-
async function resolveWaitedTaskId(client, worktreeId) {
|
|
1654
|
-
try {
|
|
1655
|
-
const data = await client.get(`/api/worktrees/${worktreeId}/tasks?limit=1`);
|
|
1656
|
-
const task = data?.tasks?.[0];
|
|
1657
|
-
if (!task || !IN_FLIGHT_TASK_STATUSES.has(task.status))
|
|
1658
|
-
return undefined;
|
|
1659
|
-
return task.id;
|
|
1660
|
-
}
|
|
1661
|
-
catch (error) {
|
|
1662
|
-
console.error(`Note: could not read the task ledger for ${worktreeId} ` +
|
|
1663
|
-
`(${error instanceof Error ? error.message : String(error)}); ` +
|
|
1664
|
-
'verification will resolve its own task.');
|
|
1665
|
-
return undefined;
|
|
1666
|
-
}
|
|
1667
|
-
}
|
|
1668
|
-
/**
|
|
1669
|
-
* Run verification for one worktree after its completion was detected.
|
|
1670
|
-
*
|
|
1671
|
-
* Swallows ApiError into an exit code: with several worktrees in flight, one
|
|
1672
|
-
* unreachable run must not abort the verdicts of the others.
|
|
1673
|
-
*/
|
|
1674
|
-
async function verifyAfterWait(client, worktreeId, options, taskId) {
|
|
1675
|
-
// --verify runs every gate, and work-evidence is always part of "every gate",
|
|
1676
|
-
// so combining it with --require-work is a superset rather than a conflict.
|
|
1677
|
-
const gateIds = options.verify ? undefined : [verify_runner_1.WORK_EVIDENCE_GATE_ID];
|
|
1678
|
-
try {
|
|
1679
|
-
const outcome = await (0, verify_runner_1.runVerification)(client, {
|
|
1680
|
-
worktreeId,
|
|
1681
|
-
trigger: 'wait',
|
|
1682
|
-
instanceId: options.instance,
|
|
1683
|
-
taskId,
|
|
1684
|
-
gateIds,
|
|
1685
|
-
// stdout stays reserved for the prompt JSON contract.
|
|
1686
|
-
resultStream: 'stderr',
|
|
1687
|
-
});
|
|
1688
|
-
return outcome.exitCode;
|
|
1689
|
-
}
|
|
1690
|
-
catch (error) {
|
|
1691
|
-
if (error instanceof api_client_1.ApiError) {
|
|
1692
|
-
console.error(`Error: ${error.message}`);
|
|
1693
|
-
return error.exitCode;
|
|
1694
|
-
}
|
|
1695
|
-
console.error(`Error: verification of ${worktreeId} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1696
|
-
return types_1.ExitCode.UNEXPECTED_ERROR;
|
|
1697
|
-
}
|
|
1698
|
-
}
|
|
1699
|
-
/**
|
|
1700
|
-
* Fold one worktree's exit code into the aggregate.
|
|
1701
|
-
*
|
|
1702
|
-
* Ranked codes (see WAIT_EXIT_CODE_PRIORITY) beat unranked infrastructure
|
|
1703
|
-
* codes, and among equals the first one observed stands.
|
|
1704
|
-
*/
|
|
1705
|
-
function mergeExitCode(current, candidate) {
|
|
1706
|
-
if (candidate === types_1.WaitExitCode.SUCCESS)
|
|
1707
|
-
return current;
|
|
1708
|
-
if (current === types_1.WaitExitCode.SUCCESS)
|
|
1709
|
-
return candidate;
|
|
1710
|
-
const rank = (code) => {
|
|
1711
|
-
const index = types_1.WAIT_EXIT_CODE_PRIORITY.indexOf(code);
|
|
1712
|
-
return index === -1 ? Number.MAX_SAFE_INTEGER : index;
|
|
1713
|
-
};
|
|
1714
|
-
return rank(candidate) < rank(current) ? candidate : current;
|
|
1715
|
-
}
|
|
1716
|
-
/**
|
|
1717
|
-
* `options` with `--instance` resolved from a selector to an instance ID
|
|
1718
|
-
* (Issue #2376).
|
|
1719
|
-
*
|
|
1720
|
-
* `wait` polls `/current-output?instance=`, which matches instance IDs and
|
|
1721
|
-
* nothing else, so an alias that reached it would filter to no session and the
|
|
1722
|
-
* wait would report on the worktree default instead — the exact silent
|
|
1723
|
-
* wrong-session failure Issue #1638 catalogued for `--agent`.
|
|
1724
|
-
*
|
|
1725
|
-
* @param client - API client
|
|
1726
|
-
* @param worktreeId - Worktree the selector is resolved against
|
|
1727
|
-
* @param options - The options as given
|
|
1728
|
-
*/
|
|
1729
|
-
async function resolveWaitInstance(client, worktreeId, options) {
|
|
1730
|
-
if (!options.instance)
|
|
1731
|
-
return options;
|
|
1732
|
-
try {
|
|
1733
|
-
const target = await (0, instances_1.resolveInstanceTarget)(client, worktreeId, options.instance, undefined);
|
|
1734
|
-
return { ...options, instance: target.instanceId ?? options.instance };
|
|
1735
|
-
}
|
|
1736
|
-
catch (error) {
|
|
1737
|
-
// Degrade to the pre-#2376 behaviour rather than failing the wait. An
|
|
1738
|
-
// instance ID needs no resolution to reach `/current-output?instance=` —
|
|
1739
|
-
// resolution exists here so that an ALIAS can — so a resolver that cannot
|
|
1740
|
-
// be reached costs alias support for this call and nothing else. Failing
|
|
1741
|
-
// instead would turn a reachable session into a non-zero exit for an
|
|
1742
|
-
// orchestrator that has been waiting on it correctly for two years.
|
|
1743
|
-
console.error(`Warning: could not resolve --instance '${options.instance}' `
|
|
1744
|
-
+ `(${(0, types_1.getErrorMessage)(error)}); using it as an instance id.`);
|
|
1745
|
-
return options;
|
|
993
|
+
await (0, wait_timing_1.sleep)(wait_timing_1.POLL_INTERVAL_MS);
|
|
1746
994
|
}
|
|
1747
995
|
}
|
|
1748
996
|
function createWaitCommand() {
|
|
@@ -1864,12 +1112,12 @@ The observation on exit 10 (Issue #3755):
|
|
|
1864
1112
|
// "Codex 2"` is one alias against two rosters, and the id behind it can
|
|
1865
1113
|
// legitimately differ — resolving once and reusing the answer would poll
|
|
1866
1114
|
// the wrong session on the second worktree.
|
|
1867
|
-
const perWorktreeOptions = await Promise.all(worktreeIds.map(id => resolveWaitInstance(client, id, options)));
|
|
1115
|
+
const perWorktreeOptions = await Promise.all(worktreeIds.map(id => (0, wait_instance_1.resolveWaitInstance)(client, id, options)));
|
|
1868
1116
|
// Issue #1620: resolved before any polling starts. Once the agent stops
|
|
1869
1117
|
// there is no reliable way left to tell which contract this wait was
|
|
1870
1118
|
// about — the agent's own verification may have closed it by then.
|
|
1871
|
-
const boundTaskIds = verifyRequested(options)
|
|
1872
|
-
? await Promise.all(worktreeIds.map(id => resolveWaitedTaskId(client, id)))
|
|
1119
|
+
const boundTaskIds = (0, wait_verify_1.verifyRequested)(options)
|
|
1120
|
+
? await Promise.all(worktreeIds.map(id => (0, wait_verify_1.resolveWaitedTaskId)(client, id)))
|
|
1873
1121
|
: worktreeIds.map(() => undefined);
|
|
1874
1122
|
if (worktreeIds.length === 1) {
|
|
1875
1123
|
// Single worktree
|
|
@@ -1880,8 +1128,8 @@ The observation on exit 10 (Issue #3755):
|
|
|
1880
1128
|
}
|
|
1881
1129
|
// Issue #1544: only a detected completion is worth verifying — a
|
|
1882
1130
|
// prompt or a timeout means the agent never claimed to be done.
|
|
1883
|
-
const exitCode = shouldVerify(result.exitCode, options)
|
|
1884
|
-
? mergeExitCode(result.exitCode, await verifyAfterWait(client, worktreeIds[0], options, boundTaskIds[0]))
|
|
1131
|
+
const exitCode = (0, wait_verify_1.shouldVerify)(result.exitCode, options)
|
|
1132
|
+
? (0, wait_verify_1.mergeExitCode)(result.exitCode, await (0, wait_verify_1.verifyAfterWait)(client, worktreeIds[0], options, boundTaskIds[0]))
|
|
1885
1133
|
: result.exitCode;
|
|
1886
1134
|
process.exit(exitCode);
|
|
1887
1135
|
return;
|
|
@@ -1897,25 +1145,25 @@ The observation on exit 10 (Issue #3755):
|
|
|
1897
1145
|
if (result.value.output) {
|
|
1898
1146
|
outputs.push(result.value.output);
|
|
1899
1147
|
}
|
|
1900
|
-
if (shouldVerify(result.value.exitCode, options)) {
|
|
1148
|
+
if ((0, wait_verify_1.shouldVerify)(result.value.exitCode, options)) {
|
|
1901
1149
|
verifyTargets.push({ id: worktreeIds[index], taskId: boundTaskIds[index] });
|
|
1902
1150
|
// Issue #1628: fold NOT_STARTED in before verification so a green
|
|
1903
1151
|
// gate run cannot promote "no session was ever running" to success.
|
|
1904
|
-
finalExitCode = mergeExitCode(finalExitCode, result.value.exitCode);
|
|
1152
|
+
finalExitCode = (0, wait_verify_1.mergeExitCode)(finalExitCode, result.value.exitCode);
|
|
1905
1153
|
return;
|
|
1906
1154
|
}
|
|
1907
|
-
finalExitCode = mergeExitCode(finalExitCode, result.value.exitCode);
|
|
1155
|
+
finalExitCode = (0, wait_verify_1.mergeExitCode)(finalExitCode, result.value.exitCode);
|
|
1908
1156
|
}
|
|
1909
1157
|
else {
|
|
1910
1158
|
const err = result.reason;
|
|
1911
|
-
finalExitCode = mergeExitCode(finalExitCode, err instanceof api_client_1.ApiError ? err.exitCode : types_1.ExitCode.UNEXPECTED_ERROR);
|
|
1159
|
+
finalExitCode = (0, wait_verify_1.mergeExitCode)(finalExitCode, err instanceof api_client_1.ApiError ? err.exitCode : types_1.ExitCode.UNEXPECTED_ERROR);
|
|
1912
1160
|
}
|
|
1913
1161
|
});
|
|
1914
1162
|
// Issue #1544: serial on purpose. The server caps concurrent runs
|
|
1915
1163
|
// process-wide, so firing them together only queues them behind each
|
|
1916
1164
|
// other while every gate competes for the same machine.
|
|
1917
1165
|
for (const target of verifyTargets) {
|
|
1918
|
-
finalExitCode = mergeExitCode(finalExitCode, await verifyAfterWait(client, target.id, options, target.taskId));
|
|
1166
|
+
finalExitCode = (0, wait_verify_1.mergeExitCode)(finalExitCode, await (0, wait_verify_1.verifyAfterWait)(client, target.id, options, target.taskId));
|
|
1919
1167
|
}
|
|
1920
1168
|
if (outputs.length > 0) {
|
|
1921
1169
|
console.log(JSON.stringify(outputs));
|