commandmate 0.44.1 → 0.44.3
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 +169 -169
- package/.next/app-path-routes-manifest.json +35 -35
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +3 -3
- package/.next/react-loadable-manifest.json +0 -6
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route.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.js +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route.js +2 -2
- 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.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.js +1 -1
- package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +2 -2
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route.js +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route.js +2 -2
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route.js +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route.js +1 -1
- package/.next/server/app/api/relays/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.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.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.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.js +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route.js +2 -2
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route.js +2 -2
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.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 +3 -3
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_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_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_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_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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route.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_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.js +1 -2
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -2
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.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 +2 -2
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page.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 +35 -35
- package/.next/server/chunks/1191.js +2 -2
- package/.next/server/chunks/1210.js +1 -1
- package/.next/server/chunks/1559.js +2 -0
- package/.next/server/chunks/1789.js +1 -0
- 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/2460.js +1 -0
- package/.next/server/chunks/2710.js +1 -1
- package/.next/server/chunks/2908.js +1 -0
- package/.next/server/chunks/2980.js +1 -1
- package/.next/server/chunks/3241.js +1 -1
- package/.next/server/chunks/3480.js +1 -1
- package/.next/server/chunks/3718.js +1 -1
- package/.next/server/chunks/4207.js +2 -2
- package/.next/server/chunks/450.js +1 -1
- package/.next/server/chunks/4672.js +5 -0
- package/.next/server/chunks/{9353.js → 4718.js} +2 -2
- package/.next/server/chunks/4837.js +14 -0
- package/.next/server/chunks/5048.js +1 -1
- package/.next/server/chunks/5209.js +1 -0
- package/.next/server/chunks/5595.js +1 -0
- package/.next/server/chunks/5625.js +25 -0
- package/.next/server/chunks/5845.js +1 -0
- package/.next/server/chunks/611.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/6793.js +3 -3
- package/.next/server/chunks/7491.js +2 -2
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/850.js +1 -0
- package/.next/server/chunks/8543.js +1 -1
- package/.next/server/chunks/8728.js +3 -3
- package/.next/server/chunks/8791.js +1 -1
- package/.next/server/chunks/8800.js +1 -1
- package/.next/server/chunks/8918.js +7 -7
- package/.next/server/chunks/9130.js +1 -5
- package/.next/server/chunks/9390.js +2 -3
- package/.next/server/chunks/9584.js +1 -1
- package/.next/server/chunks/9627.js +6 -6
- package/.next/server/chunks/9731.js +3 -3
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{1642-fb2e176aaadbd137.js → 1642-767aed8e7c61ef7f.js} +1 -1
- package/.next/static/chunks/{2407-f1f258d4a1d92620.js → 2407-06d35bb1aa02de80.js} +1 -1
- package/.next/static/chunks/{2619-04bc32f026a0d946.js → 2619-a305ad4810f1393a.js} +1 -1
- package/.next/static/chunks/4727-5d695d71e3fdf97b.js +1 -0
- package/.next/static/chunks/{8165-3853772f6ae1299b.js → 8165-3525fb42f1b4976e.js} +1 -1
- package/.next/static/chunks/app/{layout-da66300cc20244ed.js → layout-0d1750b833f5cc3e.js} +1 -1
- package/.next/static/chunks/app/sessions/page-2af68c63211c751f.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-e36898c3a80e7302.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/{page-373ea37b16d930c7.js → page-c601f3b3ece6557e.js} +1 -1
- package/.next/static/css/057f64a65726c439.css +1 -0
- package/.next/trace +13 -13
- package/dist/cli/commands/ask.d.ts.map +1 -1
- package/dist/cli/commands/ask.js +120 -119
- package/dist/cli/commands/attach.d.ts +94 -0
- package/dist/cli/commands/attach.d.ts.map +1 -1
- package/dist/cli/commands/attach.js +145 -7
- package/dist/cli/commands/auto-yes.js +1 -1
- package/dist/cli/commands/capture.d.ts.map +1 -1
- package/dist/cli/commands/capture.js +10 -13
- package/dist/cli/commands/command-target.d.ts +23 -0
- package/dist/cli/commands/command-target.d.ts.map +1 -0
- package/dist/cli/commands/command-target.js +25 -0
- package/dist/cli/commands/instances.d.ts.map +1 -1
- package/dist/cli/commands/instances.js +41 -2
- package/dist/cli/commands/message-dispatch.d.ts +36 -0
- package/dist/cli/commands/message-dispatch.d.ts.map +1 -0
- package/dist/cli/commands/message-dispatch.js +63 -0
- package/dist/cli/commands/reply.d.ts.map +1 -1
- package/dist/cli/commands/reply.js +2 -5
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +3 -6
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +149 -146
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +608 -416
- package/dist/cli/types/api-responses.d.ts +174 -27
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/types/api-responses.js +4 -2
- package/dist/cli/utils/api-client.d.ts +25 -5
- package/dist/cli/utils/api-client.d.ts.map +1 -1
- package/dist/cli/utils/api-client.js +87 -55
- package/dist/cli/utils/server-url.d.ts +1 -0
- package/dist/cli/utils/server-url.d.ts.map +1 -1
- package/dist/cli/utils/server-url.js +7 -0
- package/dist/config/uat-isolation.d.ts +140 -0
- package/dist/config/uat-isolation.d.ts.map +1 -0
- package/dist/config/uat-isolation.js +246 -0
- package/dist/lib/global-state.d.ts +12 -0
- package/dist/lib/global-state.d.ts.map +1 -0
- package/dist/lib/global-state.js +16 -0
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts +33 -0
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts.map +1 -0
- package/dist/lib/polling/auto-yes-suppression-reason.js +2 -0
- package/dist/lib/session/prompt-view.d.ts +228 -0
- package/dist/lib/session/prompt-view.d.ts.map +1 -0
- package/dist/lib/session/prompt-view.js +290 -0
- package/dist/lib/session/status-evidence-type.d.ts +16 -0
- package/dist/lib/session/status-evidence-type.d.ts.map +1 -0
- package/dist/lib/session/status-evidence-type.js +2 -0
- package/dist/lib/tmux/legacy-session-alias.d.ts.map +1 -1
- package/dist/lib/tmux/legacy-session-alias.js +2 -1
- package/dist/server/locales/en/worktree.json +3 -1
- package/dist/server/locales/ja/worktree.json +3 -1
- package/dist/server/server.js +5 -3
- package/dist/server/src/cli/types/api-responses.js +4 -2
- package/dist/server/src/config/cli-tool-timing-config.js +1 -6
- package/dist/server/src/config/uat-isolation.js +246 -0
- package/dist/server/src/lib/assistant-response-saver.js +62 -3
- package/dist/server/src/lib/auto-yes-lifecycle.js +139 -0
- package/dist/server/src/lib/auto-yes-poller.js +465 -160
- package/dist/server/src/lib/auto-yes-state.js +2 -2
- package/dist/server/src/lib/cli-tools/antigravity.js +39 -80
- package/dist/server/src/lib/cli-tools/base.js +151 -0
- package/dist/server/src/lib/cli-tools/codex.js +44 -80
- package/dist/server/src/lib/cli-tools/command-code.js +24 -56
- package/dist/server/src/lib/cli-tools/copilot.js +25 -67
- package/dist/server/src/lib/cli-tools/direct-input.js +8 -0
- package/dist/server/src/lib/cli-tools/gemini.js +23 -73
- package/dist/server/src/lib/cli-tools/opencode-pane-width.js +53 -0
- package/dist/server/src/lib/cli-tools/opencode-v2.js +9 -7
- package/dist/server/src/lib/cli-tools/opencode.js +21 -85
- package/dist/server/src/lib/cli-tools/submit-verified-sender.js +127 -4
- package/dist/server/src/lib/cli-tools/vibe-local.js +21 -66
- package/dist/server/src/lib/detection/cli-patterns.js +374 -3047
- package/dist/server/src/lib/detection/idle-evidence-observation.js +2 -2
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +7 -32
- package/dist/server/src/lib/detection/prompt-detector.js +2 -35
- package/dist/server/src/lib/detection/selection-shape-patterns.js +69 -0
- package/dist/server/src/lib/detection/selection-shape.js +32 -520
- package/dist/server/src/lib/detection/shared/pasted-text.js +41 -0
- package/dist/server/src/lib/detection/shared/shell-pane-command.js +16 -0
- package/dist/server/src/lib/detection/shared/strip-box-drawing.js +25 -0
- package/dist/server/src/lib/detection/status-detector.js +1 -1
- package/dist/server/src/lib/detection/tools/antigravity/detect.js +12 -60
- package/dist/server/src/lib/detection/tools/antigravity/dialog.js +2 -15
- package/dist/server/src/lib/detection/tools/antigravity/live-region.js +39 -0
- package/dist/server/src/lib/detection/tools/antigravity/patterns.js +286 -0
- package/dist/server/src/lib/detection/tools/claude/detect.js +11 -17
- package/dist/server/src/lib/detection/tools/claude/live-region.js +26 -0
- package/dist/server/src/lib/detection/tools/claude/patterns.js +264 -4
- package/dist/server/src/lib/detection/tools/claude/prompt.js +2 -10
- package/dist/server/src/lib/detection/tools/codex/cli-patterns.js +1 -1
- package/dist/server/src/lib/detection/tools/codex/detect.js +71 -130
- package/dist/server/src/lib/detection/tools/codex/live-region.js +104 -0
- package/dist/server/src/lib/detection/tools/codex/patterns.js +855 -0
- package/dist/server/src/lib/detection/tools/codex/prompt.js +2 -10
- package/dist/server/src/lib/detection/tools/command-code/detect.js +19 -50
- package/dist/server/src/lib/detection/tools/command-code/dialog.js +2 -18
- package/dist/server/src/lib/detection/tools/command-code/live-region.js +36 -0
- package/dist/server/src/lib/detection/tools/command-code/patterns.js +234 -0
- package/dist/server/src/lib/detection/tools/command-code/selection-shape.js +461 -0
- package/dist/server/src/lib/detection/tools/context-above.js +20 -0
- package/dist/server/src/lib/detection/tools/copilot/detect.js +13 -35
- package/dist/server/src/lib/detection/tools/copilot/live-region.js +52 -0
- package/dist/server/src/lib/detection/tools/copilot/patterns.js +640 -0
- package/dist/server/src/lib/detection/tools/copilot/prompt.js +2 -10
- package/dist/server/src/lib/detection/tools/frame.js +36 -2
- package/dist/server/src/lib/detection/tools/gemini/patterns.js +29 -0
- package/dist/server/src/lib/detection/tools/live-region-specs.js +31 -0
- package/dist/server/src/lib/detection/tools/live-region.js +204 -0
- package/dist/server/src/lib/detection/tools/opencode/detect.js +11 -49
- package/dist/server/src/lib/detection/tools/opencode/live-region.js +24 -0
- package/dist/server/src/lib/detection/tools/opencode/patterns.js +508 -0
- package/dist/server/src/lib/detection/tools/opencode-gutter-live-region.js +72 -0
- package/dist/server/src/lib/detection/tools/opencode-v2/detect.js +10 -42
- package/dist/server/src/lib/detection/tools/opencode-v2/live-region.js +24 -0
- package/dist/server/src/lib/detection/tools/opencode-v2/patterns.js +63 -0
- package/dist/server/src/lib/detection/tools/run-detection.js +31 -50
- package/dist/server/src/lib/detection/tools/verdicts.js +59 -0
- package/dist/server/src/lib/detection/tools/vibe-local/patterns.js +20 -0
- package/dist/server/src/lib/detection/truncate-raw-content.js +38 -0
- package/dist/server/src/lib/detection/turn-abandoned.js +66 -0
- package/dist/server/src/lib/detection/unclassified-frame-tracker.js +2 -2
- package/dist/server/src/lib/global-state.js +16 -0
- package/dist/server/src/lib/hooks/agent-session-telemetry.js +4 -6
- package/dist/server/src/lib/hooks/permission-decision-state.js +2 -2
- package/dist/server/src/lib/hooks/sources/antigravity/history.js +11 -76
- package/dist/server/src/lib/hooks/sources/antigravity/hooks-config.js +63 -1
- package/dist/server/src/lib/hooks/sources/antigravity/source.js +16 -0
- package/dist/server/src/lib/hooks/sources/antigravity/transcript.js +3 -12
- package/dist/server/src/lib/hooks/sources/claude/history.js +17 -156
- package/dist/server/src/lib/hooks/sources/claude/queued-notice.js +53 -0
- package/dist/server/src/lib/hooks/sources/claude/source.js +33 -3
- package/dist/server/src/lib/hooks/sources/claude/transcript.js +3 -13
- package/dist/server/src/lib/hooks/sources/codex/history.js +11 -74
- package/dist/server/src/lib/hooks/sources/codex/hooks-config.js +147 -11
- package/dist/server/src/lib/hooks/sources/codex/relay-install.js +64 -21
- package/dist/server/src/lib/hooks/sources/codex/transcript.js +5 -15
- package/dist/server/src/lib/hooks/sources/command-code/history.js +20 -121
- package/dist/server/src/lib/hooks/sources/command-code/transcript.js +3 -13
- package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +161 -31
- package/dist/server/src/lib/hooks/sources/define-source.js +40 -55
- package/dist/server/src/lib/hooks/sources/event-mapper.js +2 -1
- package/dist/server/src/lib/hooks/sources/opencode/diff.js +3 -4
- package/dist/server/src/lib/hooks/sources/opencode/history.js +2 -1
- package/dist/server/src/lib/hooks/sources/opencode/launch-settings.js +2 -1
- package/dist/server/src/lib/hooks/sources/opencode/payloads.js +2 -1
- package/dist/server/src/lib/hooks/sources/opencode/ports.js +2 -1
- package/dist/server/src/lib/hooks/sources/opencode/subscription.js +4 -3
- package/dist/server/src/lib/hooks/sources/opencode/transcript.js +3 -16
- package/dist/server/src/lib/hooks/sources/opencode-v2/history.js +2 -1
- package/dist/server/src/lib/hooks/sources/opencode-v2/mappers.js +5 -4
- package/dist/server/src/lib/hooks/sources/opencode-v2/ports.js +2 -1
- package/dist/server/src/lib/hooks/sources/opencode-v2/subscription.js +3 -7
- package/dist/server/src/lib/hooks/sources/opencode-v2/usage.js +2 -1
- package/dist/server/src/lib/hooks/sources/pending-decisions.js +2 -1
- package/dist/server/src/lib/hooks/sources/registry.js +3 -2
- package/dist/server/src/lib/hooks/sources/transcript-history.js +262 -0
- package/dist/server/src/lib/hooks/sources/turn-body.js +31 -0
- package/dist/server/src/lib/hooks/tool-input-normalization-state.js +2 -2
- package/dist/server/src/lib/polling/antigravity-permission-receipts.js +2 -2
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +16 -4
- package/dist/server/src/lib/polling/auto-yes-enter-fallback-state.js +142 -0
- package/dist/server/src/lib/polling/auto-yes-enter-fallback.js +187 -0
- package/dist/server/src/lib/polling/auto-yes-resolver.js +9 -3
- package/dist/server/src/lib/polling/auto-yes-suppression-reason.js +2 -0
- package/dist/server/src/lib/polling/auto-yes-suppression-state.js +2 -2
- package/dist/server/src/lib/polling/pending-scraped-response.js +190 -0
- package/dist/server/src/lib/polling/prompt-dedup-state.js +2 -2
- package/dist/server/src/lib/polling/prompt-dedup.js +2 -2
- package/dist/server/src/lib/polling/response-checker-dialog-gate.js +95 -0
- package/dist/server/src/lib/polling/response-checker-extraction-result.js +50 -0
- package/dist/server/src/lib/polling/response-checker-extraction-steps.js +670 -0
- package/dist/server/src/lib/polling/response-checker.js +666 -1162
- package/dist/server/src/lib/polling/response-dedup.js +3 -4
- package/dist/server/src/lib/polling/response-poller-constants.js +17 -0
- package/dist/server/src/lib/polling/response-poller-core.js +54 -20
- package/dist/server/src/lib/polling/startup-screen.js +142 -0
- package/dist/server/src/lib/polling/structured-history-gate.js +3 -2
- package/dist/server/src/lib/prompt-answer-semantic.js +178 -0
- package/dist/server/src/lib/prompt-answer-sender.js +6 -5
- package/dist/server/src/lib/push/failure-episode-state.js +2 -2
- package/dist/server/src/lib/push/notification-dedup.js +3 -4
- package/dist/server/src/lib/push/prompt-card-state.js +2 -2
- package/dist/server/src/lib/push/waiting-push-notifier.js +3 -4
- package/dist/server/src/lib/realtime/publisher-registry.js +3 -2
- package/dist/server/src/lib/realtime/terminal-broadcast.js +38 -2
- package/dist/server/src/lib/realtime/terminal-session-ownership.js +45 -0
- package/dist/server/src/lib/relay/relay-delivery.js +6 -2
- package/dist/server/src/lib/relay/relay-readiness.js +38 -1
- package/dist/server/src/lib/relay/relay-triggers.js +9 -0
- package/dist/server/src/lib/resource-cleanup.js +6 -4
- package/dist/server/src/lib/response-cleaner.js +24 -1
- package/dist/server/src/lib/response-extractor.js +16 -0
- package/dist/server/src/lib/schedule-manager.js +8 -10
- package/dist/server/src/lib/session/agent-event-ask-user-question.js +168 -0
- package/dist/server/src/lib/session/agent-event-awaiting-instruction.js +104 -0
- package/dist/server/src/lib/session/agent-event-dedup.js +539 -0
- package/dist/server/src/lib/session/agent-event-model.js +562 -0
- package/dist/server/src/lib/session/agent-event-record.js +10 -0
- package/dist/server/src/lib/session/agent-event-state.js +106 -1854
- package/dist/server/src/lib/session/agent-event-structured-state.js +109 -0
- package/dist/server/src/lib/session/agent-event-turn.js +811 -0
- package/dist/server/src/lib/session/agent-session-lifecycle.js +11 -2
- package/dist/server/src/lib/session/chat-turn-progress.js +322 -0
- package/dist/server/src/lib/session/claude-executor.js +45 -5
- package/dist/server/src/lib/session/claude-session.js +21 -65
- package/dist/server/src/lib/session/cli-session.js +17 -0
- package/dist/server/src/lib/session/current-output-builder.js +454 -1103
- package/dist/server/src/lib/session/current-output-history-writers.js +255 -0
- package/dist/server/src/lib/session/current-output-types.js +9 -0
- package/dist/server/src/lib/session/detection-divergence.js +55 -0
- package/dist/server/src/lib/session/global-session-constants.js +2 -13
- package/dist/server/src/lib/session/hook-turn-hold.js +102 -0
- package/dist/server/src/lib/session/layer-disagreement.js +2 -2
- package/dist/server/src/lib/session/opencode-session-store.js +2 -1
- package/dist/server/src/lib/session/prompt-view.js +290 -0
- package/dist/server/src/lib/session/prompt-waiting-composition.js +35 -0
- package/dist/server/src/lib/session/provisional-turn.js +3 -1
- package/dist/server/src/lib/session/send-user-message.js +1 -1
- package/dist/server/src/lib/session/session-starting-state.js +4 -6
- package/dist/server/src/lib/session/status-evidence-type.js +2 -0
- package/dist/server/src/lib/session/status-evidence.js +2 -2
- package/dist/server/src/lib/session/structured-status-merge.js +335 -0
- package/dist/server/src/lib/session/waiting-episode-state.js +3 -4
- package/dist/server/src/lib/session/waiting-kind.js +3 -0
- package/dist/server/src/lib/session-cleanup.js +6 -8
- package/dist/server/src/lib/skills/install-plan.js +2 -1
- package/dist/server/src/lib/skills/snapshot-store.js +2 -2
- package/dist/server/src/lib/skills/uninstall-plan.js +2 -2
- package/dist/server/src/lib/timer-manager.js +6 -8
- package/dist/server/src/lib/tmux/geometry-delegation.js +3 -4
- package/dist/server/src/lib/tmux/legacy-session-alias.js +2 -1
- package/dist/server/src/lib/tmux/session-hooks.js +2 -1
- package/dist/server/src/lib/tmux/session-status-options.js +3 -3
- package/dist/server/src/lib/tmux/tmux-capture-cache.js +3 -2
- package/dist/server/src/lib/tmux/tmux.js +33 -59
- package/dist/server/src/lib/tui-accumulator.js +2 -2
- package/dist/server/src/lib/version-checker.js +6 -6
- package/dist/server/src/lib/ws-server.js +47 -11
- package/docs/en/user-guide/webapp-guide.md +27 -3
- package/package.json +1 -1
- package/release-notes/0.44.2.json +33 -0
- package/release-notes/0.44.3.json +82 -0
- package/scripts/hooks/cmate-agent-event.sh +18 -0
- package/.next/server/chunks/1068.js +0 -1
- package/.next/server/chunks/434.js +0 -1
- package/.next/server/chunks/5775.js +0 -1
- package/.next/server/chunks/6474.js +0 -14
- package/.next/server/chunks/650.js +0 -1
- package/.next/server/chunks/6661.js +0 -1
- package/.next/server/chunks/8583.js +0 -1
- package/.next/server/chunks/964.js +0 -1
- package/.next/server/chunks/967.js +0 -1
- package/.next/server/chunks/9882.js +0 -25
- package/.next/static/chunks/591-308072f285c34787.js +0 -1
- package/.next/static/chunks/app/sessions/page-049e06335187aa91.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-040c5f0f585e6812.js +0 -1
- package/.next/static/css/38070d879efa1371.css +0 -1
- package/dist/server/src/lib/cli-tools/index.js +0 -41
- package/dist/server/src/lib/polling/global-session-poller.js +0 -140
- /package/.next/static/{57lOiz8zSEHdw97XIm0af → tWwHQzmvc-rv9KKUtDWfQ}/_buildManifest.js +0 -0
- /package/.next/static/{57lOiz8zSEHdw97XIm0af → tWwHQzmvc-rv9KKUtDWfQ}/_ssgManifest.js +0 -0
|
@@ -31,6 +31,7 @@ const api_client_1 = require("../utils/api-client");
|
|
|
31
31
|
const command_helpers_1 = require("../utils/command-helpers");
|
|
32
32
|
const verify_runner_1 = require("../utils/verify-runner");
|
|
33
33
|
const agent_target_options_1 = require("../config/agent-target-options");
|
|
34
|
+
const prompt_view_1 = require("../../lib/session/prompt-view");
|
|
34
35
|
const instances_1 = require("./instances");
|
|
35
36
|
/** [IA3-02] Polling interval 5 seconds (matches tmux-capture-cache TTL=2s) */
|
|
36
37
|
const POLL_INTERVAL_MS = 5000;
|
|
@@ -53,7 +54,24 @@ const SELECTION_LIST_PROMPT_TYPE = 'selection_list';
|
|
|
53
54
|
* among them) keeps working and simply meets a kind it does not recognise,
|
|
54
55
|
* whereas a new exit code reads as an infrastructure error to all of them.
|
|
55
56
|
*/
|
|
56
|
-
|
|
57
|
+
//
|
|
58
|
+
// Issue #3184: the value comes from `lib/session/prompt-view` rather than a copy
|
|
59
|
+
// here — that module has no imports, so the CLI build compiles it.
|
|
60
|
+
const UNCLASSIFIED_PROMPT_TYPE = prompt_view_1.UNCLASSIFIED_PROMPT_VIEW_TYPE;
|
|
61
|
+
/**
|
|
62
|
+
* How the prompt reported on exit 10 is answered (Issue #3184): `screen` = the
|
|
63
|
+
* option number or y/n typed at the pane (`respond`), `api` = a decision
|
|
64
|
+
* delivered over the agent's own API (`respond <id> <number>`, no keys sent),
|
|
65
|
+
* `terminal` = nothing to offer, a human answers at the pane. Read off the
|
|
66
|
+
* shared view so `wait` and the browser cannot reach different conclusions.
|
|
67
|
+
*/
|
|
68
|
+
function waitAnswerVia(view) {
|
|
69
|
+
if (view?.kind === 'screen-choices')
|
|
70
|
+
return 'screen';
|
|
71
|
+
if (view?.kind === 'api-choices')
|
|
72
|
+
return 'api';
|
|
73
|
+
return 'terminal';
|
|
74
|
+
}
|
|
57
75
|
/**
|
|
58
76
|
* Why `wait` decided the agent was done, printed on the completion line
|
|
59
77
|
* (Issue #1839).
|
|
@@ -200,6 +218,8 @@ function describePaneObstruction(data) {
|
|
|
200
218
|
const SUPPRESSION_FRESH_MS = 60_000;
|
|
201
219
|
/** The suppression currently blocking this session, or null. */
|
|
202
220
|
function activeSuppression(data, now) {
|
|
221
|
+
// No `autoYes` at all (a session that is not running, Issue #3300) reads as
|
|
222
|
+
// "nothing was withheld", the same as a null record.
|
|
203
223
|
const suppression = data.autoYes?.lastSuppression;
|
|
204
224
|
if (!suppression)
|
|
205
225
|
return null;
|
|
@@ -278,6 +298,33 @@ function formatSuppressionNotice(suppression, ageSeconds) {
|
|
|
278
298
|
const cause = suppressionCause(suppression.reason);
|
|
279
299
|
return ` auto-yes suppressed this prompt ${cause}: ${parts.join(' ')} (${ageSeconds}s ago)`;
|
|
280
300
|
}
|
|
301
|
+
/**
|
|
302
|
+
* One stderr line saying Auto-Yes pressed Enter on THIS prompt (Issue #3397), or
|
|
303
|
+
* null when the record is absent or about another screen.
|
|
304
|
+
*
|
|
305
|
+
* The prompt is one CommandMate could not read (the window offers direct input
|
|
306
|
+
* for it). `sent` — Auto-Yes confirmed whatever was selected; `no-effect` — the
|
|
307
|
+
* same screen outlived the Enter, no second one was sent, and it is a human's
|
|
308
|
+
* again. An outcome this CLI does not know is named verbatim (#1843's rule).
|
|
309
|
+
* `currentPrompt` is the server's judgement that the record is about the
|
|
310
|
+
* `promptData` of the same response, so an Enter sent to an earlier screen is
|
|
311
|
+
* never reported against this one.
|
|
312
|
+
*/
|
|
313
|
+
function formatEnterFallbackNotice(data, now) {
|
|
314
|
+
const record = data.autoYes?.lastEnterFallback;
|
|
315
|
+
if (!record || record.currentPrompt !== true)
|
|
316
|
+
return null;
|
|
317
|
+
const detail = `refusal=${record.refusalReason} promptType=${record.promptType}`;
|
|
318
|
+
const ago = `(${Math.max(0, Math.round((now - record.at) / 1000))}s ago)`;
|
|
319
|
+
if (record.outcome === 'sent') {
|
|
320
|
+
return ` auto-yes sent Enter to this prompt (CommandMate could not read it): ${detail} ${ago}`;
|
|
321
|
+
}
|
|
322
|
+
if (record.outcome === 'no-effect') {
|
|
323
|
+
return ` auto-yes sent Enter to this prompt, but the same screen is still up (no-effect); ` +
|
|
324
|
+
`answer it in the terminal: ${detail} ${ago}`;
|
|
325
|
+
}
|
|
326
|
+
return ` auto-yes Enter record for this prompt: outcome=${record.outcome} ${detail} ${ago}`;
|
|
327
|
+
}
|
|
281
328
|
/**
|
|
282
329
|
* Whether this server publishes a real turn record (Issue #1930).
|
|
283
330
|
*
|
|
@@ -660,6 +707,508 @@ function nextPollWithinDeadlines(options, startTime, lastActivityTime, now) {
|
|
|
660
707
|
}
|
|
661
708
|
return true;
|
|
662
709
|
}
|
|
710
|
+
/**
|
|
711
|
+
* The exit-10 payload for a prompt the detection layer parsed. `suppressed` is
|
|
712
|
+
* {@link activeSuppression}'s reading of the same poll.
|
|
713
|
+
*/
|
|
714
|
+
function buildPromptOutput(worktreeId, data, promptData, suppressed) {
|
|
715
|
+
// Issue #1898: the degraded `unclassified` payload carries no `options`
|
|
716
|
+
// — by construction, because nothing parsed the screen — but for a
|
|
717
|
+
// source whose approvals are answered by decision id it does carry
|
|
718
|
+
// `decisionOptions`, which ARE answerable (`respond <id> 1`). Reporting
|
|
719
|
+
// an empty list there told the caller a dialog was open and gave it
|
|
720
|
+
// nothing to do about it, which is the whole of #1898-3 seen from the
|
|
721
|
+
// pipeline's side.
|
|
722
|
+
//
|
|
723
|
+
// Issue #3184: and a QUESTION answered by decision id (OpenCode V2,
|
|
724
|
+
// #2100) carries neither — its choices are `askUserQuestion.labels`,
|
|
725
|
+
// numbered by position. The panel offered them as buttons while this
|
|
726
|
+
// reported `[]`. Which of these applies is the shared view's call
|
|
727
|
+
// (`readPromptView`), not a third reading of the raw fields here.
|
|
728
|
+
const promptView = (0, prompt_view_1.readPromptView)(data);
|
|
729
|
+
const promptOptions = promptData.options?.length
|
|
730
|
+
? promptData.options
|
|
731
|
+
: promptData.decisionOptions?.length
|
|
732
|
+
? promptData.decisionOptions
|
|
733
|
+
: promptView?.apiTarget === 'question'
|
|
734
|
+
? promptView.choices.map((choice) => ({
|
|
735
|
+
number: Number(choice.answer),
|
|
736
|
+
label: choice.label,
|
|
737
|
+
}))
|
|
738
|
+
: [];
|
|
739
|
+
const promptOutput = {
|
|
740
|
+
worktreeId,
|
|
741
|
+
cliToolId: data.cliToolId || 'claude',
|
|
742
|
+
type: promptData.type || 'unknown',
|
|
743
|
+
question: promptData.question || '',
|
|
744
|
+
options: promptOptions,
|
|
745
|
+
status: promptData.status || 'pending',
|
|
746
|
+
answerVia: waitAnswerVia(promptView),
|
|
747
|
+
...(promptData.approvalTarget !== undefined && {
|
|
748
|
+
approvalTarget: promptData.approvalTarget,
|
|
749
|
+
}),
|
|
750
|
+
...(suppressed && {
|
|
751
|
+
autoYesSuppression: {
|
|
752
|
+
reason: suppressed.suppression.reason,
|
|
753
|
+
mode: suppressed.suppression.mode,
|
|
754
|
+
promptType: suppressed.suppression.promptType,
|
|
755
|
+
...(suppressed.suppression.pattern !== undefined && {
|
|
756
|
+
pattern: suppressed.suppression.pattern,
|
|
757
|
+
}),
|
|
758
|
+
ageSeconds: suppressed.ageSeconds,
|
|
759
|
+
},
|
|
760
|
+
}),
|
|
761
|
+
};
|
|
762
|
+
return promptOutput;
|
|
763
|
+
}
|
|
764
|
+
/** The exit-10 payload for an arrow-key selection list (Issue #1628). */
|
|
765
|
+
function buildSelectionListOutput(worktreeId, data) {
|
|
766
|
+
return {
|
|
767
|
+
worktreeId,
|
|
768
|
+
cliToolId: data.cliToolId || 'claude',
|
|
769
|
+
type: SELECTION_LIST_PROMPT_TYPE,
|
|
770
|
+
question: data.sessionStatusReason ?? SELECTION_LIST_PROMPT_TYPE,
|
|
771
|
+
options: [],
|
|
772
|
+
status: 'pending',
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* What `wait` says about a frame that stayed unclassified for the whole dwell
|
|
777
|
+
* (Issue #1708): the stderr line, and the `question` of its exit-10 payload.
|
|
778
|
+
*/
|
|
779
|
+
function describeUnclassifiedFrame(worktreeId, data, dwellMs) {
|
|
780
|
+
const dwellSeconds = Math.round(dwellMs / 1000);
|
|
781
|
+
return (`Unclassified interactive frame on ${worktreeId} for ${dwellSeconds}s ` +
|
|
782
|
+
`(status=${data.sessionStatus ?? 'unknown'}/${data.sessionStatusReason ?? 'unknown'}). ` +
|
|
783
|
+
`The detection layer could not parse it; inspect the raw pane with ` +
|
|
784
|
+
`\`commandmate capture ${worktreeId} --pane\`.` +
|
|
785
|
+
// Issue #2095: the sidebar is exactly this frame's reason, and the
|
|
786
|
+
// one recovery is a keystroke in the pane. Riding the message keeps
|
|
787
|
+
// the exit-code table (10, `type: unclassified`) unchanged for every
|
|
788
|
+
// caller that already branches on it.
|
|
789
|
+
describePaneObstruction(data));
|
|
790
|
+
}
|
|
791
|
+
/** The exit-10 payload for a persistently unclassified frame (Issue #1708). */
|
|
792
|
+
function buildUnclassifiedOutput(worktreeId, data, question) {
|
|
793
|
+
return {
|
|
794
|
+
worktreeId,
|
|
795
|
+
cliToolId: data.cliToolId || 'claude',
|
|
796
|
+
type: UNCLASSIFIED_PROMPT_TYPE,
|
|
797
|
+
question,
|
|
798
|
+
options: [],
|
|
799
|
+
status: 'pending',
|
|
800
|
+
answerVia: 'terminal',
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
/** The stderr line for a session this wait never saw running (Issue #1628). */
|
|
804
|
+
function describeNotStarted(worktreeId, data, options) {
|
|
805
|
+
return (`Not started: ${worktreeId} has no running ${data.cliToolId ?? 'agent'} session` +
|
|
806
|
+
`${options.instance ? ` for instance ${options.instance}` : ''}` +
|
|
807
|
+
// Issue #1884: name the stage that chose the agent above. `wait` has
|
|
808
|
+
// no --agent to correct a mis-resolution with, so "no running claude
|
|
809
|
+
// session for instance opencode" was the entire evidence an operator
|
|
810
|
+
// got for a live agent reported as absent. `worktree-default` here
|
|
811
|
+
// means the instance is neither in the roster nor named after a
|
|
812
|
+
// tool; `client-fallback`, that the server is too old to resolve.
|
|
813
|
+
`${data.resolvedBy ? ` (resolvedBy=${data.resolvedBy})` : ''}.`);
|
|
814
|
+
}
|
|
815
|
+
/** The outcome that ends the wait with `result`. */
|
|
816
|
+
function exitWith(result) {
|
|
817
|
+
return { kind: 'exit', result };
|
|
818
|
+
}
|
|
819
|
+
/**
|
|
820
|
+
* Stage: `--timeout` and `--stall-timeout`, asked at the top of every poll,
|
|
821
|
+
* before its request. Exit 124.
|
|
822
|
+
*/
|
|
823
|
+
function deadlineStage(poll, state) {
|
|
824
|
+
const { worktreeId, options, startTime } = poll;
|
|
825
|
+
// Check timeout
|
|
826
|
+
if (options.timeout) {
|
|
827
|
+
const elapsed = (Date.now() - startTime) / 1000;
|
|
828
|
+
if (elapsed >= options.timeout) {
|
|
829
|
+
console.error(`Timeout: ${worktreeId} exceeded ${options.timeout}s`);
|
|
830
|
+
return exitWith({ exitCode: types_1.WaitExitCode.TIMEOUT });
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
// Check stall-timeout
|
|
834
|
+
if (options.stallTimeout) {
|
|
835
|
+
const stallElapsed = (Date.now() - state.lastActivityTime) / 1000;
|
|
836
|
+
if (stallElapsed >= options.stallTimeout) {
|
|
837
|
+
console.error(`Stall timeout: ${worktreeId} no output for ${options.stallTimeout}s`);
|
|
838
|
+
return exitWith({ exitCode: types_1.WaitExitCode.TIMEOUT });
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
return { kind: 'next' };
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Stage: a prompt the detection layer parsed. Exit 10, unless it is held for a
|
|
845
|
+
* human (`--on-prompt human`) or for the target's Auto-Yes (Issue #2463).
|
|
846
|
+
*/
|
|
847
|
+
function promptStage(poll, state, data) {
|
|
848
|
+
const { worktreeId, options, startTime, autoYesGraceSeconds, autoYesGraceMs } = poll;
|
|
849
|
+
// Prompt detected
|
|
850
|
+
if (data.isPromptWaiting && data.promptData) {
|
|
851
|
+
// Issue #1699: report a policy suppression on both exits — the human one
|
|
852
|
+
// keeps polling and would otherwise say nothing about why nobody
|
|
853
|
+
// answered, and the agent one is read by pipelines that never see stderr.
|
|
854
|
+
const suppressed = activeSuppression(data, Date.now());
|
|
855
|
+
// [DR1-03] Prompt detection exit code
|
|
856
|
+
if (options.onPrompt === 'human') {
|
|
857
|
+
// Block and continue polling - user handles prompt manually
|
|
858
|
+
console.error(`Prompt detected on ${worktreeId}. Waiting for human response...`);
|
|
859
|
+
if (suppressed) {
|
|
860
|
+
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
|
|
861
|
+
}
|
|
862
|
+
// Issue #3397: and whether Auto-Yes already pressed Enter on it.
|
|
863
|
+
const enterNotice = formatEnterFallbackNotice(data, Date.now());
|
|
864
|
+
if (enterNotice)
|
|
865
|
+
console.error(enterNotice);
|
|
866
|
+
return { kind: 'wait' };
|
|
867
|
+
}
|
|
868
|
+
// Issue #2463: the one case `decidePromptPush()` stays quiet about —
|
|
869
|
+
// Auto-Yes is on and has not withheld this answer — is a prompt Auto-Yes
|
|
870
|
+
// is about to answer, and exit 10 there hands a delegation back to a
|
|
871
|
+
// human for a dialog nobody had to see. Hold it for the grace window; a
|
|
872
|
+
// poll that shows no prompt ends the hold below and completion is judged
|
|
873
|
+
// as usual. A withheld answer (`suppressed`) and Auto-Yes being off are
|
|
874
|
+
// the gate's other two branches and still exit 10 at once.
|
|
875
|
+
if (!suppressed && data.autoYes?.enabled === true && autoYesGraceMs > 0) {
|
|
876
|
+
const now = Date.now();
|
|
877
|
+
if (state.autoYesAnsweringSince === null) {
|
|
878
|
+
state.autoYesAnsweringSince = now;
|
|
879
|
+
// stderr only: stdout is the exit-10 payload and nothing else.
|
|
880
|
+
console.error("Prompt detected; the target's Auto-Yes is answering, waiting up to " +
|
|
881
|
+
`${autoYesGraceSeconds}s… (${worktreeId})`);
|
|
882
|
+
}
|
|
883
|
+
const heldMs = now - state.autoYesAnsweringSince;
|
|
884
|
+
if (heldMs < autoYesGraceMs &&
|
|
885
|
+
nextPollWithinDeadlines(options, startTime, state.lastActivityTime, now)) {
|
|
886
|
+
return { kind: 'wait' };
|
|
887
|
+
}
|
|
888
|
+
console.error(heldMs < autoYesGraceMs
|
|
889
|
+
? `Note: the prompt on ${worktreeId} is still open after ${Math.round(heldMs / 1000)}s ` +
|
|
890
|
+
'under Auto-Yes, and the next poll would pass --timeout/--stall-timeout; reporting it now.'
|
|
891
|
+
: `Note: the target's Auto-Yes did not answer the prompt on ${worktreeId} within ` +
|
|
892
|
+
`${autoYesGraceSeconds}s; reporting it.`);
|
|
893
|
+
}
|
|
894
|
+
else if (state.autoYesAnsweringSince !== null && !suppressed) {
|
|
895
|
+
console.error(`Note: Auto-Yes is no longer enabled on ${worktreeId}; reporting the prompt.`);
|
|
896
|
+
}
|
|
897
|
+
// Default (agent mode): output prompt info and exit 10
|
|
898
|
+
const promptOutput = buildPromptOutput(worktreeId, data, data.promptData, suppressed);
|
|
899
|
+
if (suppressed) {
|
|
900
|
+
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
|
|
901
|
+
}
|
|
902
|
+
// Issue #3397: stderr only, like the notice above; the exit-10 payload is unchanged.
|
|
903
|
+
const enterNotice = formatEnterFallbackNotice(data, Date.now());
|
|
904
|
+
if (enterNotice)
|
|
905
|
+
console.error(enterNotice);
|
|
906
|
+
return exitWith({ exitCode: types_1.WaitExitCode.PROMPT_DETECTED, output: promptOutput });
|
|
907
|
+
}
|
|
908
|
+
return { kind: 'next' };
|
|
909
|
+
}
|
|
910
|
+
/** Stage: an arrow-key selection list (Issue #1628). Exit 10, or held under `--on-prompt human`. */
|
|
911
|
+
function selectionListStage(poll, data) {
|
|
912
|
+
const { worktreeId, options } = poll;
|
|
913
|
+
// Issue #1628: an arrow-key menu is the agent blocked on a human just as much
|
|
914
|
+
// as a numbered prompt is, but it is published with isPromptWaiting=false so
|
|
915
|
+
// the UI can render NavigationButtons instead of PromptPanel. Treat it as a
|
|
916
|
+
// prompt here — otherwise `wait` polls a stopped agent until --timeout.
|
|
917
|
+
if (data.isSelectionListActive) {
|
|
918
|
+
if (options.onPrompt === 'human') {
|
|
919
|
+
console.error(`Selection list active on ${worktreeId} (${data.sessionStatusReason ?? 'selection_list'}). ` +
|
|
920
|
+
'Waiting for human response...');
|
|
921
|
+
// Issue #1699: the poller parses frames status-detector publishes as
|
|
922
|
+
// selection lists, so a policy can be the reason this one is stuck too.
|
|
923
|
+
const suppressed = activeSuppression(data, Date.now());
|
|
924
|
+
if (suppressed) {
|
|
925
|
+
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
|
|
926
|
+
}
|
|
927
|
+
return { kind: 'wait' };
|
|
928
|
+
}
|
|
929
|
+
return exitWith({
|
|
930
|
+
exitCode: types_1.WaitExitCode.PROMPT_DETECTED,
|
|
931
|
+
output: buildSelectionListOutput(worktreeId, data),
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
return { kind: 'next' };
|
|
935
|
+
}
|
|
936
|
+
/**
|
|
937
|
+
* Stage: an interactive frame nothing could parse, once it has stayed up for the
|
|
938
|
+
* whole dwell (Issue #1708). Exit 10, or held under `--on-prompt human`.
|
|
939
|
+
*/
|
|
940
|
+
function unclassifiedStage(poll, state, data) {
|
|
941
|
+
const { worktreeId, options } = poll;
|
|
942
|
+
// Issue #1708: the frame is interactive but nothing could parse it. The
|
|
943
|
+
// detection layer is the single entry point every downstream safeguard
|
|
944
|
+
// hangs off, so a frame that slips past it disables Auto-Yes, the exit-10
|
|
945
|
+
// handoff and the contract's autoYes policy all at once — and `wait` used
|
|
946
|
+
// to burn its whole --timeout without ever mentioning it. Treat a
|
|
947
|
+
// PERSISTENT unclassified frame as a stop reason of its own.
|
|
948
|
+
//
|
|
949
|
+
// The dwell deliberately spans ALL THREE states that raise this flag, and
|
|
950
|
+
// the completion check below is suppressed while it is up. That is the
|
|
951
|
+
// whole point, and it is worth spelling out because the obvious reading is
|
|
952
|
+
// the wrong one. The server's definition (`isUnclassifiedFrame` in
|
|
953
|
+
// `src/lib/session/status-evidence.ts`, restated there by Issue #2011):
|
|
954
|
+
//
|
|
955
|
+
// isUnclassifiedActive =
|
|
956
|
+
// running && (default | unknown_frame | no_recent_output)
|
|
957
|
+
//
|
|
958
|
+
// `no_recent_output` is there because a static unrecognised overlay
|
|
959
|
+
// DEGRADES into it — once the Auto-Yes poller stamps
|
|
960
|
+
// lastServerResponseTimestamp, a frame that stopped changing flips from
|
|
961
|
+
// `running`/`default` after STALE_OUTPUT_THRESHOLD_MS (5s). `unknown_frame`
|
|
962
|
+
// is the same floor for a tool that opts out of the generic composer check
|
|
963
|
+
// (copilot, opencode), and says "this tool's own rules looked and read
|
|
964
|
+
// nothing". Both arrive about twelve times faster than this dwell. Letting
|
|
965
|
+
// the completion check claim one turned a stalled worker into `Completed`,
|
|
966
|
+
// which is worse than the timeout Issue #1708 complained about: exit 124
|
|
967
|
+
// stops a pipeline, exit 0 lets it merge. Measured before this guard: two
|
|
968
|
+
// unclassified polls followed by the degraded state returned SUCCESS.
|
|
969
|
+
//
|
|
970
|
+
// What is deliberately NOT in the set is `ready`/`input_prompt` with
|
|
971
|
+
// `statusEvidence: 'none'` — the agent back at its composer on a frame no
|
|
972
|
+
// tool-specific idle rule could vouch for. That frame WAS classified; what
|
|
973
|
+
// is missing is positive proof, which is a different question and §4 D1's
|
|
974
|
+
// to answer. Issue #1927 folded the two together and every idle Claude pane
|
|
975
|
+
// stopped completing (#2011). Whether `wait` should hold for evidence as
|
|
976
|
+
// well as classification is open, and any answer belongs in the same place
|
|
977
|
+
// as the rollout that produces the evidence — not here.
|
|
978
|
+
if (data.isUnclassifiedActive === true) {
|
|
979
|
+
if (state.unclassifiedSince === null)
|
|
980
|
+
state.unclassifiedSince = Date.now();
|
|
981
|
+
const dwellMs = Date.now() - state.unclassifiedSince;
|
|
982
|
+
if (dwellMs >= UNCLASSIFIED_DWELL_MS) {
|
|
983
|
+
const question = describeUnclassifiedFrame(worktreeId, data, dwellMs);
|
|
984
|
+
if (options.onPrompt === 'human') {
|
|
985
|
+
console.error(question);
|
|
986
|
+
console.error('Waiting for human response...');
|
|
987
|
+
return { kind: 'wait' };
|
|
988
|
+
}
|
|
989
|
+
console.error(question);
|
|
990
|
+
return exitWith({
|
|
991
|
+
exitCode: types_1.WaitExitCode.PROMPT_DETECTED,
|
|
992
|
+
output: buildUnclassifiedOutput(worktreeId, data, question),
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
state.unclassifiedSince = null;
|
|
998
|
+
}
|
|
999
|
+
return { kind: 'next' };
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* Stage: the session is not running (Path A). Exit 21 when this wait never saw
|
|
1003
|
+
* it alive (Issue #1628), exit 0 when it went away after it had been seen.
|
|
1004
|
+
*/
|
|
1005
|
+
function notRunningStage(poll, state, data, selfResumeSuffix) {
|
|
1006
|
+
const { worktreeId, options } = poll;
|
|
1007
|
+
// Completion check [DR1-04]:
|
|
1008
|
+
// Path A: the tmux session went away after we had seen it alive — the agent
|
|
1009
|
+
// finished and its session was stopped.
|
|
1010
|
+
// Path B: agent completed task (sessionStatus === 'ready', input prompt detected)
|
|
1011
|
+
// Both indicate "no more work in progress" from wait command's perspective.
|
|
1012
|
+
// (This stage handles Path A only; Path B is checked in `readyStage`.)
|
|
1013
|
+
//
|
|
1014
|
+
// Issue #1628 narrowed Path A: a session that was NEVER seen running is
|
|
1015
|
+
// "nothing to wait for" (NOT_STARTED), not a completion. See `everRunning`.
|
|
1016
|
+
if (!data.isRunning && !state.everRunning) {
|
|
1017
|
+
console.error(describeNotStarted(worktreeId, data, options));
|
|
1018
|
+
return exitWith({ exitCode: types_1.VerifyExitCode.NOT_STARTED });
|
|
1019
|
+
}
|
|
1020
|
+
if (!data.isRunning) {
|
|
1021
|
+
console.error(`Completed: ${worktreeId} (basis=${COMPLETION_BASIS.SESSION_GONE}${selfResumeSuffix()})`);
|
|
1022
|
+
return exitWith({ exitCode: types_1.WaitExitCode.SUCCESS });
|
|
1023
|
+
}
|
|
1024
|
+
return { kind: 'next' };
|
|
1025
|
+
}
|
|
1026
|
+
/**
|
|
1027
|
+
* Stage of a `ready` frame: an upstream fault on the frame, under
|
|
1028
|
+
* `--fail-on-upstream-fault` (Issue #1839). Exit 11.
|
|
1029
|
+
*/
|
|
1030
|
+
function upstreamFaultStage(poll, data) {
|
|
1031
|
+
const { worktreeId, options } = poll;
|
|
1032
|
+
// Issue #1839: the agent is back at its composer with an upstream
|
|
1033
|
+
// failure on the frame. Checked BEFORE the turn-boundary gate below,
|
|
1034
|
+
// because it is the answer to the question that gate can only ask: the
|
|
1035
|
+
// turn did not end, and this is why. Without it the same session runs
|
|
1036
|
+
// to --timeout and reports 124, which says nothing about the cause.
|
|
1037
|
+
const fault = data.upstreamFault ?? null;
|
|
1038
|
+
if (options.failOnUpstreamFault && fault) {
|
|
1039
|
+
console.error(`Upstream fault on ${worktreeId}: id=${fault.id} — the agent is back at its ` +
|
|
1040
|
+
'composer with an upstream API failure on screen, so this turn did not run. ' +
|
|
1041
|
+
`Matched: ${JSON.stringify(fault.matchedText)}`);
|
|
1042
|
+
if (fault.id === 'context-limit') {
|
|
1043
|
+
// A retry into the same session hits the same wall (Issue #3011).
|
|
1044
|
+
console.error('The session\'s conversation is over the model\'s context limit. Start a fresh ' +
|
|
1045
|
+
`session and send again: commandmate instances ${worktreeId} kill ` +
|
|
1046
|
+
`${options.instance ?? '<instance>'}`);
|
|
1047
|
+
}
|
|
1048
|
+
return exitWith({
|
|
1049
|
+
exitCode: types_1.WaitExitCode.UPSTREAM_FAULT,
|
|
1050
|
+
upstreamFault: { id: fault.id, matchedText: fault.matchedText },
|
|
1051
|
+
});
|
|
1052
|
+
}
|
|
1053
|
+
return { kind: 'next' };
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Stage of a `ready` frame: the agent has not reported the end of the turn this
|
|
1057
|
+
* wait adopted (Issue #1839). Held.
|
|
1058
|
+
*/
|
|
1059
|
+
function unsettledTurnStage(poll, state, data) {
|
|
1060
|
+
const { worktreeId } = poll;
|
|
1061
|
+
// Issue #1839: `ready` off the terminal frame is the agent's composer,
|
|
1062
|
+
// not the agent's verdict. Measured 2026-08-20 against a stub upstream
|
|
1063
|
+
// answering 529: Claude returns to the composer ~3 s after the send
|
|
1064
|
+
// having executed nothing, and never sends `Stop`. When this instance's
|
|
1065
|
+
// hooks ARE reporting — the only case in which `turnStartedAt` is
|
|
1066
|
+
// non-null — that missing `Stop` is the difference between "finished"
|
|
1067
|
+
// and "never ran", and it is the only signal that carries it.
|
|
1068
|
+
if (!turnSettled(data, state.turnStartedAt)) {
|
|
1069
|
+
console.error(`Waiting: ${worktreeId} is back at its composer, but its agent has not reported ` +
|
|
1070
|
+
`the end of this turn (turnStartedAt=${state.turnStartedAt}, ` +
|
|
1071
|
+
`lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
|
|
1072
|
+
'Not reporting completion; inspect with ' +
|
|
1073
|
+
`\`commandmate capture ${worktreeId} --json\`.`);
|
|
1074
|
+
return { kind: 'wait' };
|
|
1075
|
+
}
|
|
1076
|
+
return { kind: 'next' };
|
|
1077
|
+
}
|
|
1078
|
+
/**
|
|
1079
|
+
* Stage of a `ready` frame: the turn ended on a `stop` that said the agent will
|
|
1080
|
+
* resume by itself (Issue #2614). Held, up to {@link SELF_RESUME_HOLD_MS}.
|
|
1081
|
+
*/
|
|
1082
|
+
function selfResumeHoldStage(poll, state, data, selfResumeStopAt) {
|
|
1083
|
+
const { worktreeId } = poll;
|
|
1084
|
+
// Issue #2614: the turn did end — the agent said so — but it also said
|
|
1085
|
+
// that work of its own is still running in the background (a `schedule`
|
|
1086
|
+
// timer, a backgrounded command), and that work wakes it with nobody
|
|
1087
|
+
// typing anything. Measured 2026-09-17 on antigravity 1.2.4: four such
|
|
1088
|
+
// stops ~58 s before each self-wake, and the first one was reported as
|
|
1089
|
+
// `Completed (basis=hook_stop)` and verified five minutes before the
|
|
1090
|
+
// work was done. So this `stop` is held until it is no longer the newest
|
|
1091
|
+
// word (see `selfResumeStopAt` above), or until the bound.
|
|
1092
|
+
//
|
|
1093
|
+
// The bound is measured from whichever is further along: the `stop`
|
|
1094
|
+
// itself (server clock — a negative age is skew, and the max discards
|
|
1095
|
+
// it) or this wait's first sight of it. A session that said so hours ago
|
|
1096
|
+
// and never woke is not held again.
|
|
1097
|
+
if (selfResumeStopAt !== null) {
|
|
1098
|
+
const now = Date.now();
|
|
1099
|
+
if (state.selfResumeHold === null)
|
|
1100
|
+
state.selfResumeHold = { stopAt: selfResumeStopAt, since: now };
|
|
1101
|
+
const heldMs = now - state.selfResumeHold.since;
|
|
1102
|
+
const elapsedMs = Math.max(heldMs, now - selfResumeStopAt);
|
|
1103
|
+
if (elapsedMs < exports.SELF_RESUME_HOLD_MS) {
|
|
1104
|
+
state.selfResumeHeld = true;
|
|
1105
|
+
console.error(`Waiting: ${worktreeId} ended its turn with background work still running ` +
|
|
1106
|
+
`(stoppedAt=${new Date(selfResumeStopAt).toISOString()}, ` +
|
|
1107
|
+
`lastEventDetail=${exports.SELF_RESUME_PENDING_DETAIL}, ${describeTurnClose(data)}); ` +
|
|
1108
|
+
'it resumes by itself when that work finishes. Not reporting completion ' +
|
|
1109
|
+
`(held ${Math.round(heldMs / 1000)}s, at most ${exports.SELF_RESUME_HOLD_MS / 1000}s ` +
|
|
1110
|
+
'after the stop).');
|
|
1111
|
+
return { kind: 'wait' };
|
|
1112
|
+
}
|
|
1113
|
+
console.error(`Note: ${worktreeId} said at its stop ${Math.round(elapsedMs / 1000)}s ` +
|
|
1114
|
+
'ago that background work was still running, and has not resumed since; ' +
|
|
1115
|
+
'completing on that stop.');
|
|
1116
|
+
}
|
|
1117
|
+
return { kind: 'next' };
|
|
1118
|
+
}
|
|
1119
|
+
/**
|
|
1120
|
+
* Stage of a `ready` frame: the chat ledger shows a prompt the agent has not
|
|
1121
|
+
* reported the end of (Issue #1975). Held, up to {@link PENDING_PROMPT_HOLD_MS}.
|
|
1122
|
+
* `next` carries whether the newest prompt was answered, which
|
|
1123
|
+
* {@link completionStage} needs for its basis.
|
|
1124
|
+
*/
|
|
1125
|
+
async function promptLedgerStage(poll, state, data) {
|
|
1126
|
+
const { client, worktreeId, options, startTime } = poll;
|
|
1127
|
+
// Issue #1975: the same frame, one question further back. #1839's gate
|
|
1128
|
+
// above can only fire once a turn has been ADOPTED, and `send` leaves a
|
|
1129
|
+
// window ~1s wide in which nothing has been: the newest structured event
|
|
1130
|
+
// is still the previous turn's `stop`, so `adoptTurnStart` takes nothing,
|
|
1131
|
+
// `turnSettled` reads null as "settled", and the composer the agent has
|
|
1132
|
+
// not touched yet is read as the composer it came back to. Measured
|
|
1133
|
+
// 2026-08-22 against copilot 1.0.80 on an isolated server: 3 of 5
|
|
1134
|
+
// send-then-wait runs came back in ~0.3s with `basis=scraper_ready` and
|
|
1135
|
+
// no artefact on disk.
|
|
1136
|
+
//
|
|
1137
|
+
// So ask the ledger instead of the clock: has this instance been handed
|
|
1138
|
+
// a prompt that the agent has not reported the end of? See
|
|
1139
|
+
// {@link outstandingPrompt} for why that comparison is the one that
|
|
1140
|
+
// separates "not started" from "finished", and
|
|
1141
|
+
// {@link reportsTurnBoundaries} for why a tool that posts no hooks never
|
|
1142
|
+
// reaches it.
|
|
1143
|
+
let answeredNewestPrompt = false;
|
|
1144
|
+
if (state.turnStartedAt === null && state.promptLedgerReadable && reportsTurnBoundaries(data)) {
|
|
1145
|
+
const ledger = await readNewestPromptAt(client, worktreeId, options, data);
|
|
1146
|
+
// One notice, then stop asking: a ledger that failed once will fail
|
|
1147
|
+
// every poll, and the point of degrading is to stop paying for it.
|
|
1148
|
+
state.promptLedgerReadable = ledger.readable;
|
|
1149
|
+
if (ledger.readable && ledger.submittedAt !== null) {
|
|
1150
|
+
if (outstandingPrompt(data, ledger.submittedAt)) {
|
|
1151
|
+
const heldMs = Date.now() - startTime;
|
|
1152
|
+
if (heldMs < PENDING_PROMPT_HOLD_MS) {
|
|
1153
|
+
console.error(`Waiting: ${worktreeId} is at its composer, but the newest prompt sent to it ` +
|
|
1154
|
+
`has no reported end (sentAt=${new Date(ledger.submittedAt).toISOString()}, ` +
|
|
1155
|
+
`lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
|
|
1156
|
+
'Not reporting completion: the agent has not started this turn yet.');
|
|
1157
|
+
return { kind: 'wait' };
|
|
1158
|
+
}
|
|
1159
|
+
console.error(`Note: ${worktreeId} has been at its composer for ` +
|
|
1160
|
+
`${Math.round(heldMs / 1000)}s with the newest prompt still unreported by its ` +
|
|
1161
|
+
'agent. Its hooks are not answering; completing on the frame alone.');
|
|
1162
|
+
}
|
|
1163
|
+
else {
|
|
1164
|
+
answeredNewestPrompt = true;
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
return { kind: 'next', answeredNewestPrompt };
|
|
1169
|
+
}
|
|
1170
|
+
/** Last stage of a `ready` frame: the completion line with its basis. Exit 0. */
|
|
1171
|
+
function completionStage(poll, state, answeredNewestPrompt, selfResumeSuffix) {
|
|
1172
|
+
const { worktreeId } = poll;
|
|
1173
|
+
// `hook_stop` on both branches that have one, and they are the same
|
|
1174
|
+
// statement made from two records: the agent reported the end of the
|
|
1175
|
+
// turn this wait is about. `scraper_ready` keeps its documented meaning
|
|
1176
|
+
// — "the screen said so and nothing corroborated it" — which is now
|
|
1177
|
+
// exactly the set of cases that reach it.
|
|
1178
|
+
const basis = state.turnStartedAt !== null || answeredNewestPrompt
|
|
1179
|
+
? COMPLETION_BASIS.HOOK_STOP
|
|
1180
|
+
: COMPLETION_BASIS.SCRAPER_READY;
|
|
1181
|
+
console.error(`Completed: ${worktreeId} (basis=${basis}${selfResumeSuffix()})`);
|
|
1182
|
+
return exitWith({ exitCode: types_1.WaitExitCode.SUCCESS });
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* Stage: the agent is back at its composer on a frame that was understood. Asks
|
|
1186
|
+
* the stages of a `ready` frame in order; the first that applies decides.
|
|
1187
|
+
*/
|
|
1188
|
+
async function readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix) {
|
|
1189
|
+
// Issue #1708 narrowed Path B: `ready` is only a completion when the frame
|
|
1190
|
+
// was actually understood. A structured `hook_stop` over an unreadable
|
|
1191
|
+
// pane is the degraded form of an overlay nobody could parse (see the note
|
|
1192
|
+
// above), and reporting it as `Completed` is how a stalled worker gets
|
|
1193
|
+
// merged. Path A is untouched — a session that went away really is
|
|
1194
|
+
// finished, and carries no flag anyway.
|
|
1195
|
+
if (data.sessionStatus === 'ready' && data.isUnclassifiedActive !== true) {
|
|
1196
|
+
const faultOutcome = upstreamFaultStage(poll, data);
|
|
1197
|
+
if (faultOutcome.kind !== 'next')
|
|
1198
|
+
return faultOutcome;
|
|
1199
|
+
const turnOutcome = unsettledTurnStage(poll, state, data);
|
|
1200
|
+
if (turnOutcome.kind !== 'next')
|
|
1201
|
+
return turnOutcome;
|
|
1202
|
+
const holdOutcome = selfResumeHoldStage(poll, state, data, selfResumeStopAt);
|
|
1203
|
+
if (holdOutcome.kind !== 'next')
|
|
1204
|
+
return holdOutcome;
|
|
1205
|
+
const ledgerOutcome = await promptLedgerStage(poll, state, data);
|
|
1206
|
+
if (ledgerOutcome.kind !== 'next')
|
|
1207
|
+
return ledgerOutcome;
|
|
1208
|
+
return completionStage(poll, state, ledgerOutcome.answeredNewestPrompt, selfResumeSuffix);
|
|
1209
|
+
}
|
|
1210
|
+
return { kind: 'next' };
|
|
1211
|
+
}
|
|
663
1212
|
/**
|
|
664
1213
|
* Poll a single worktree until completion, prompt, or timeout.
|
|
665
1214
|
*
|
|
@@ -676,81 +1225,36 @@ function nextPollWithinDeadlines(options, startTime, lastActivityTime, now) {
|
|
|
676
1225
|
*/
|
|
677
1226
|
async function pollWorktree(client, worktreeId, options) {
|
|
678
1227
|
const startTime = Date.now();
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
* `isUnclassifiedActive === true`, or null when the last poll cleared it
|
|
692
|
-
* (Issue #1708).
|
|
693
|
-
*/
|
|
694
|
-
let unclassifiedSince = null;
|
|
695
|
-
/**
|
|
696
|
-
* Epoch ms of the `user_prompt_submit` / `pre_tool_use` / `post_tool_use` this
|
|
697
|
-
* wait adopted as "the turn I am waiting on", or null when the agent has
|
|
698
|
-
* reported none (Issue #1839). See {@link adoptTurnStart}.
|
|
699
|
-
*/
|
|
700
|
-
let turnStartedAt = null;
|
|
701
|
-
/**
|
|
702
|
-
* Whether the chat ledger is still worth asking (Issue #1975). Cleared by the
|
|
703
|
-
* first read that fails, after which this wait judges completion from the
|
|
704
|
-
* frame alone — the pre-#1975 behaviour — rather than re-reporting the same
|
|
705
|
-
* unreachable endpoint on every poll.
|
|
706
|
-
*/
|
|
707
|
-
let promptLedgerReadable = true;
|
|
708
|
-
/**
|
|
709
|
-
* Epoch ms of the first poll in the current unbroken run of an agent-mode
|
|
710
|
-
* prompt the target's Auto-Yes is expected to answer, or null (Issue #2463).
|
|
711
|
-
* Cleared by the first poll that shows no prompt, so every prompt Auto-Yes
|
|
712
|
-
* answers gets a window of its own.
|
|
713
|
-
*/
|
|
714
|
-
let autoYesAnsweringSince = null;
|
|
1228
|
+
const state = {
|
|
1229
|
+
lastActivityTime: Date.now(),
|
|
1230
|
+
lastContent: '',
|
|
1231
|
+
everRunning: false,
|
|
1232
|
+
unclassifiedSince: null,
|
|
1233
|
+
turnStartedAt: null,
|
|
1234
|
+
promptLedgerReadable: true,
|
|
1235
|
+
autoYesAnsweringSince: null,
|
|
1236
|
+
selfResumeHold: null,
|
|
1237
|
+
selfResumeHeldMs: 0,
|
|
1238
|
+
selfResumeHeld: false,
|
|
1239
|
+
};
|
|
715
1240
|
const autoYesGraceSeconds = options.autoYesGrace ?? AUTO_YES_GRACE_DEFAULT_SECONDS;
|
|
716
1241
|
const autoYesGraceMs = autoYesGraceSeconds * 1000;
|
|
717
|
-
|
|
718
|
-
* The self-resume hold in progress: the `stop` it is about, and when this wait
|
|
719
|
-
* first held on it (CLI clock). Null when none is (Issue #2614).
|
|
720
|
-
*/
|
|
721
|
-
let selfResumeHold = null;
|
|
722
|
-
/** Milliseconds spent in self-resume holds that have already ended (Issue #2614). */
|
|
723
|
-
let selfResumeHeldMs = 0;
|
|
724
|
-
/** Whether any poll of this wait was held for a self-resume (Issue #2614). */
|
|
725
|
-
let selfResumeHeld = false;
|
|
1242
|
+
const poll = { client, worktreeId, options, startTime, autoYesGraceSeconds, autoYesGraceMs };
|
|
726
1243
|
/**
|
|
727
1244
|
* What the completion line adds when this wait held for a self-resume, or ''
|
|
728
1245
|
* (Issue #2614). `basis=` keeps its word: the verdict is still the agent's own
|
|
729
1246
|
* `Stop`, the hold only decided which one.
|
|
730
1247
|
*/
|
|
731
1248
|
const selfResumeSuffix = () => {
|
|
732
|
-
if (!selfResumeHeld)
|
|
1249
|
+
if (!state.selfResumeHeld)
|
|
733
1250
|
return '';
|
|
734
|
-
const total = selfResumeHeldMs + (selfResumeHold ? Date.now() - selfResumeHold.since : 0);
|
|
1251
|
+
const total = state.selfResumeHeldMs + (state.selfResumeHold ? Date.now() - state.selfResumeHold.since : 0);
|
|
735
1252
|
return `, heldForSelfResume=${Math.round(total / 1000)}s`;
|
|
736
1253
|
};
|
|
737
1254
|
while (true) {
|
|
738
|
-
|
|
739
|
-
if (
|
|
740
|
-
|
|
741
|
-
if (elapsed >= options.timeout) {
|
|
742
|
-
console.error(`Timeout: ${worktreeId} exceeded ${options.timeout}s`);
|
|
743
|
-
return { exitCode: types_1.WaitExitCode.TIMEOUT };
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
// Check stall-timeout
|
|
747
|
-
if (options.stallTimeout) {
|
|
748
|
-
const stallElapsed = (Date.now() - lastActivityTime) / 1000;
|
|
749
|
-
if (stallElapsed >= options.stallTimeout) {
|
|
750
|
-
console.error(`Stall timeout: ${worktreeId} no output for ${options.stallTimeout}s`);
|
|
751
|
-
return { exitCode: types_1.WaitExitCode.TIMEOUT };
|
|
752
|
-
}
|
|
753
|
-
}
|
|
1255
|
+
const deadlineOutcome = deadlineStage(poll, state);
|
|
1256
|
+
if (deadlineOutcome.kind === 'exit')
|
|
1257
|
+
return deadlineOutcome.result;
|
|
754
1258
|
try {
|
|
755
1259
|
// Issue #868: scope polling to a specific agent instance when provided.
|
|
756
1260
|
const path = options.instance
|
|
@@ -758,12 +1262,12 @@ async function pollWorktree(client, worktreeId, options) {
|
|
|
758
1262
|
: `/api/worktrees/${worktreeId}/current-output`;
|
|
759
1263
|
const data = await client.get(path);
|
|
760
1264
|
// Track content changes for stall detection
|
|
761
|
-
if (data.content !== lastContent) {
|
|
762
|
-
lastContent = data.content;
|
|
763
|
-
lastActivityTime = Date.now();
|
|
1265
|
+
if (data.content !== state.lastContent) {
|
|
1266
|
+
state.lastContent = data.content;
|
|
1267
|
+
state.lastActivityTime = Date.now();
|
|
764
1268
|
}
|
|
765
1269
|
if (data.isRunning) {
|
|
766
|
-
everRunning = true;
|
|
1270
|
+
state.everRunning = true;
|
|
767
1271
|
}
|
|
768
1272
|
// Issue #3179: the agent is still launching. Work in progress, so keep
|
|
769
1273
|
// polling: no prompt or selection list is read off the launch's frame,
|
|
@@ -772,377 +1276,65 @@ async function pollWorktree(client, worktreeId, options) {
|
|
|
772
1276
|
// launch that then fails leaves no session, which is NOT_STARTED, not a
|
|
773
1277
|
// completion. The server bounds the launch, so this cannot hold forever.
|
|
774
1278
|
if (typeof data.startingSince === 'number') {
|
|
775
|
-
unclassifiedSince = null;
|
|
1279
|
+
state.unclassifiedSince = null;
|
|
776
1280
|
await sleep(POLL_INTERVAL_MS);
|
|
777
1281
|
continue;
|
|
778
1282
|
}
|
|
779
1283
|
// Issue #1839: done before any exit path so the turn is adopted even on a
|
|
780
1284
|
// poll that ends in a prompt — the same turn is still open when the human
|
|
781
1285
|
// answers and `--on-prompt human` resumes polling.
|
|
782
|
-
turnStartedAt = adoptTurnStart(data, startTime, turnStartedAt);
|
|
1286
|
+
state.turnStartedAt = adoptTurnStart(data, startTime, state.turnStartedAt);
|
|
783
1287
|
// Issue #2614: a self-resume hold is about one `stop`, and ends the first
|
|
784
1288
|
// time that `stop` is no longer the newest word — the agent woke (a
|
|
785
1289
|
// turn-opening event) or stopped again. Checked on every poll, ahead of
|
|
786
1290
|
// every exit, because the wake usually lands on a `running` frame that
|
|
787
1291
|
// never reaches the hold itself.
|
|
788
1292
|
const selfResumeStopAt = pendingSelfResumeStop(data);
|
|
789
|
-
if (selfResumeHold !== null && selfResumeHold.stopAt !== selfResumeStopAt) {
|
|
790
|
-
const heldMs = Date.now() - selfResumeHold.since;
|
|
791
|
-
selfResumeHeldMs += heldMs;
|
|
792
|
-
selfResumeHold = null;
|
|
1293
|
+
if (state.selfResumeHold !== null && state.selfResumeHold.stopAt !== selfResumeStopAt) {
|
|
1294
|
+
const heldMs = Date.now() - state.selfResumeHold.since;
|
|
1295
|
+
state.selfResumeHeldMs += heldMs;
|
|
1296
|
+
state.selfResumeHold = null;
|
|
793
1297
|
console.error(`Note: ${worktreeId} has moved past the stop it said it would resume from ` +
|
|
794
1298
|
`(held ${Math.round(heldMs / 1000)}s); judging its current state.`);
|
|
795
1299
|
}
|
|
796
|
-
|
|
797
|
-
if (
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
// [DR1-03] Prompt detection exit code
|
|
803
|
-
if (options.onPrompt === 'human') {
|
|
804
|
-
// Block and continue polling - user handles prompt manually
|
|
805
|
-
console.error(`Prompt detected on ${worktreeId}. Waiting for human response...`);
|
|
806
|
-
if (suppressed) {
|
|
807
|
-
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
|
|
808
|
-
}
|
|
809
|
-
await sleep(POLL_INTERVAL_MS);
|
|
810
|
-
continue;
|
|
811
|
-
}
|
|
812
|
-
// Issue #2463: the one case `decidePromptPush()` stays quiet about —
|
|
813
|
-
// Auto-Yes is on and has not withheld this answer — is a prompt Auto-Yes
|
|
814
|
-
// is about to answer, and exit 10 there hands a delegation back to a
|
|
815
|
-
// human for a dialog nobody had to see. Hold it for the grace window; a
|
|
816
|
-
// poll that shows no prompt ends the hold below and completion is judged
|
|
817
|
-
// as usual. A withheld answer (`suppressed`) and Auto-Yes being off are
|
|
818
|
-
// the gate's other two branches and still exit 10 at once.
|
|
819
|
-
if (!suppressed && data.autoYes?.enabled === true && autoYesGraceMs > 0) {
|
|
820
|
-
const now = Date.now();
|
|
821
|
-
if (autoYesAnsweringSince === null) {
|
|
822
|
-
autoYesAnsweringSince = now;
|
|
823
|
-
// stderr only: stdout is the exit-10 payload and nothing else.
|
|
824
|
-
console.error("Prompt detected; the target's Auto-Yes is answering, waiting up to " +
|
|
825
|
-
`${autoYesGraceSeconds}s… (${worktreeId})`);
|
|
826
|
-
}
|
|
827
|
-
const heldMs = now - autoYesAnsweringSince;
|
|
828
|
-
if (heldMs < autoYesGraceMs &&
|
|
829
|
-
nextPollWithinDeadlines(options, startTime, lastActivityTime, now)) {
|
|
830
|
-
await sleep(POLL_INTERVAL_MS);
|
|
831
|
-
continue;
|
|
832
|
-
}
|
|
833
|
-
console.error(heldMs < autoYesGraceMs
|
|
834
|
-
? `Note: the prompt on ${worktreeId} is still open after ${Math.round(heldMs / 1000)}s ` +
|
|
835
|
-
'under Auto-Yes, and the next poll would pass --timeout/--stall-timeout; reporting it now.'
|
|
836
|
-
: `Note: the target's Auto-Yes did not answer the prompt on ${worktreeId} within ` +
|
|
837
|
-
`${autoYesGraceSeconds}s; reporting it.`);
|
|
838
|
-
}
|
|
839
|
-
else if (autoYesAnsweringSince !== null && !suppressed) {
|
|
840
|
-
console.error(`Note: Auto-Yes is no longer enabled on ${worktreeId}; reporting the prompt.`);
|
|
841
|
-
}
|
|
842
|
-
// Default (agent mode): output prompt info and exit 10
|
|
843
|
-
//
|
|
844
|
-
// Issue #1898: the degraded `unclassified` payload carries no `options`
|
|
845
|
-
// — by construction, because nothing parsed the screen — but for a
|
|
846
|
-
// source whose approvals are answered by decision id it does carry
|
|
847
|
-
// `decisionOptions`, which ARE answerable (`respond <id> 1`). Reporting
|
|
848
|
-
// an empty list there told the caller a dialog was open and gave it
|
|
849
|
-
// nothing to do about it, which is the whole of #1898-3 seen from the
|
|
850
|
-
// pipeline's side.
|
|
851
|
-
const promptOptions = data.promptData.options?.length
|
|
852
|
-
? data.promptData.options
|
|
853
|
-
: (data.promptData.decisionOptions ?? []);
|
|
854
|
-
const promptOutput = {
|
|
855
|
-
worktreeId,
|
|
856
|
-
cliToolId: data.cliToolId || 'claude',
|
|
857
|
-
type: data.promptData.type || 'unknown',
|
|
858
|
-
question: data.promptData.question || '',
|
|
859
|
-
options: promptOptions,
|
|
860
|
-
status: data.promptData.status || 'pending',
|
|
861
|
-
...(data.promptData.approvalTarget !== undefined && {
|
|
862
|
-
approvalTarget: data.promptData.approvalTarget,
|
|
863
|
-
}),
|
|
864
|
-
...(suppressed && {
|
|
865
|
-
autoYesSuppression: {
|
|
866
|
-
reason: suppressed.suppression.reason,
|
|
867
|
-
mode: suppressed.suppression.mode,
|
|
868
|
-
promptType: suppressed.suppression.promptType,
|
|
869
|
-
...(suppressed.suppression.pattern !== undefined && {
|
|
870
|
-
pattern: suppressed.suppression.pattern,
|
|
871
|
-
}),
|
|
872
|
-
ageSeconds: suppressed.ageSeconds,
|
|
873
|
-
},
|
|
874
|
-
}),
|
|
875
|
-
};
|
|
876
|
-
if (suppressed) {
|
|
877
|
-
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
|
|
878
|
-
}
|
|
879
|
-
return { exitCode: types_1.WaitExitCode.PROMPT_DETECTED, output: promptOutput };
|
|
1300
|
+
const promptOutcome = promptStage(poll, state, data);
|
|
1301
|
+
if (promptOutcome.kind === 'exit')
|
|
1302
|
+
return promptOutcome.result;
|
|
1303
|
+
if (promptOutcome.kind === 'wait') {
|
|
1304
|
+
await sleep(POLL_INTERVAL_MS);
|
|
1305
|
+
continue;
|
|
880
1306
|
}
|
|
881
1307
|
// Issue #2463: the prompt the hold was waiting on has gone. Who answered it
|
|
882
1308
|
// is not on the wire — Auto-Yes, or a human at the pane — so the line says
|
|
883
1309
|
// only that it cleared; what the agent does next is for the checks below.
|
|
884
|
-
if (autoYesAnsweringSince !== null) {
|
|
1310
|
+
if (state.autoYesAnsweringSince !== null) {
|
|
885
1311
|
console.error(`Prompt on ${worktreeId} cleared after ` +
|
|
886
|
-
`${Math.round((Date.now() - autoYesAnsweringSince) / 1000)}s; judging completion as usual.`);
|
|
887
|
-
autoYesAnsweringSince = null;
|
|
888
|
-
}
|
|
889
|
-
// Issue #1628: an arrow-key menu is the agent blocked on a human just as much
|
|
890
|
-
// as a numbered prompt is, but it is published with isPromptWaiting=false so
|
|
891
|
-
// the UI can render NavigationButtons instead of PromptPanel. Treat it as a
|
|
892
|
-
// prompt here — otherwise `wait` polls a stopped agent until --timeout.
|
|
893
|
-
if (data.isSelectionListActive) {
|
|
894
|
-
if (options.onPrompt === 'human') {
|
|
895
|
-
console.error(`Selection list active on ${worktreeId} (${data.sessionStatusReason ?? 'selection_list'}). ` +
|
|
896
|
-
'Waiting for human response...');
|
|
897
|
-
// Issue #1699: the poller parses frames status-detector publishes as
|
|
898
|
-
// selection lists, so a policy can be the reason this one is stuck too.
|
|
899
|
-
const suppressed = activeSuppression(data, Date.now());
|
|
900
|
-
if (suppressed) {
|
|
901
|
-
console.error(formatSuppressionNotice(suppressed.suppression, suppressed.ageSeconds));
|
|
902
|
-
}
|
|
903
|
-
await sleep(POLL_INTERVAL_MS);
|
|
904
|
-
continue;
|
|
905
|
-
}
|
|
906
|
-
return {
|
|
907
|
-
exitCode: types_1.WaitExitCode.PROMPT_DETECTED,
|
|
908
|
-
output: {
|
|
909
|
-
worktreeId,
|
|
910
|
-
cliToolId: data.cliToolId || 'claude',
|
|
911
|
-
type: SELECTION_LIST_PROMPT_TYPE,
|
|
912
|
-
question: data.sessionStatusReason ?? SELECTION_LIST_PROMPT_TYPE,
|
|
913
|
-
options: [],
|
|
914
|
-
status: 'pending',
|
|
915
|
-
},
|
|
916
|
-
};
|
|
917
|
-
}
|
|
918
|
-
// Issue #1708: the frame is interactive but nothing could parse it. The
|
|
919
|
-
// detection layer is the single entry point every downstream safeguard
|
|
920
|
-
// hangs off, so a frame that slips past it disables Auto-Yes, the exit-10
|
|
921
|
-
// handoff and the contract's autoYes policy all at once — and `wait` used
|
|
922
|
-
// to burn its whole --timeout without ever mentioning it. Treat a
|
|
923
|
-
// PERSISTENT unclassified frame as a stop reason of its own.
|
|
924
|
-
//
|
|
925
|
-
// The dwell deliberately spans ALL THREE states that raise this flag, and
|
|
926
|
-
// the completion check below is suppressed while it is up. That is the
|
|
927
|
-
// whole point, and it is worth spelling out because the obvious reading is
|
|
928
|
-
// the wrong one. The server's definition (`isUnclassifiedFrame` in
|
|
929
|
-
// `src/lib/session/status-evidence.ts`, restated there by Issue #2011):
|
|
930
|
-
//
|
|
931
|
-
// isUnclassifiedActive =
|
|
932
|
-
// running && (default | unknown_frame | no_recent_output)
|
|
933
|
-
//
|
|
934
|
-
// `no_recent_output` is there because a static unrecognised overlay
|
|
935
|
-
// DEGRADES into it — once the Auto-Yes poller stamps
|
|
936
|
-
// lastServerResponseTimestamp, a frame that stopped changing flips from
|
|
937
|
-
// `running`/`default` after STALE_OUTPUT_THRESHOLD_MS (5s). `unknown_frame`
|
|
938
|
-
// is the same floor for a tool that opts out of the generic composer check
|
|
939
|
-
// (copilot, opencode), and says "this tool's own rules looked and read
|
|
940
|
-
// nothing". Both arrive about twelve times faster than this dwell. Letting
|
|
941
|
-
// the completion check claim one turned a stalled worker into `Completed`,
|
|
942
|
-
// which is worse than the timeout Issue #1708 complained about: exit 124
|
|
943
|
-
// stops a pipeline, exit 0 lets it merge. Measured before this guard: two
|
|
944
|
-
// unclassified polls followed by the degraded state returned SUCCESS.
|
|
945
|
-
//
|
|
946
|
-
// What is deliberately NOT in the set is `ready`/`input_prompt` with
|
|
947
|
-
// `statusEvidence: 'none'` — the agent back at its composer on a frame no
|
|
948
|
-
// tool-specific idle rule could vouch for. That frame WAS classified; what
|
|
949
|
-
// is missing is positive proof, which is a different question and §4 D1's
|
|
950
|
-
// to answer. Issue #1927 folded the two together and every idle Claude pane
|
|
951
|
-
// stopped completing (#2011). Whether `wait` should hold for evidence as
|
|
952
|
-
// well as classification is open, and any answer belongs in the same place
|
|
953
|
-
// as the rollout that produces the evidence — not here.
|
|
954
|
-
if (data.isUnclassifiedActive === true) {
|
|
955
|
-
if (unclassifiedSince === null)
|
|
956
|
-
unclassifiedSince = Date.now();
|
|
957
|
-
const dwellMs = Date.now() - unclassifiedSince;
|
|
958
|
-
if (dwellMs >= UNCLASSIFIED_DWELL_MS) {
|
|
959
|
-
const dwellSeconds = Math.round(dwellMs / 1000);
|
|
960
|
-
const question = `Unclassified interactive frame on ${worktreeId} for ${dwellSeconds}s ` +
|
|
961
|
-
`(status=${data.sessionStatus ?? 'unknown'}/${data.sessionStatusReason ?? 'unknown'}). ` +
|
|
962
|
-
`The detection layer could not parse it; inspect the raw pane with ` +
|
|
963
|
-
`\`commandmate capture ${worktreeId} --pane\`.` +
|
|
964
|
-
// Issue #2095: the sidebar is exactly this frame's reason, and the
|
|
965
|
-
// one recovery is a keystroke in the pane. Riding the message keeps
|
|
966
|
-
// the exit-code table (10, `type: unclassified`) unchanged for every
|
|
967
|
-
// caller that already branches on it.
|
|
968
|
-
describePaneObstruction(data);
|
|
969
|
-
if (options.onPrompt === 'human') {
|
|
970
|
-
console.error(question);
|
|
971
|
-
console.error('Waiting for human response...');
|
|
972
|
-
await sleep(POLL_INTERVAL_MS);
|
|
973
|
-
continue;
|
|
974
|
-
}
|
|
975
|
-
console.error(question);
|
|
976
|
-
return {
|
|
977
|
-
exitCode: types_1.WaitExitCode.PROMPT_DETECTED,
|
|
978
|
-
output: {
|
|
979
|
-
worktreeId,
|
|
980
|
-
cliToolId: data.cliToolId || 'claude',
|
|
981
|
-
type: UNCLASSIFIED_PROMPT_TYPE,
|
|
982
|
-
question,
|
|
983
|
-
options: [],
|
|
984
|
-
status: 'pending',
|
|
985
|
-
},
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
}
|
|
989
|
-
else {
|
|
990
|
-
unclassifiedSince = null;
|
|
1312
|
+
`${Math.round((Date.now() - state.autoYesAnsweringSince) / 1000)}s; judging completion as usual.`);
|
|
1313
|
+
state.autoYesAnsweringSince = null;
|
|
991
1314
|
}
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
// Issue #1628 narrowed Path A: a session that was NEVER seen running is
|
|
999
|
-
// "nothing to wait for" (NOT_STARTED), not a completion. See `everRunning`.
|
|
1000
|
-
if (!data.isRunning && !everRunning) {
|
|
1001
|
-
console.error(`Not started: ${worktreeId} has no running ${data.cliToolId ?? 'agent'} session` +
|
|
1002
|
-
`${options.instance ? ` for instance ${options.instance}` : ''}` +
|
|
1003
|
-
// Issue #1884: name the stage that chose the agent above. `wait` has
|
|
1004
|
-
// no --agent to correct a mis-resolution with, so "no running claude
|
|
1005
|
-
// session for instance opencode" was the entire evidence an operator
|
|
1006
|
-
// got for a live agent reported as absent. `worktree-default` here
|
|
1007
|
-
// means the instance is neither in the roster nor named after a
|
|
1008
|
-
// tool; `client-fallback`, that the server is too old to resolve.
|
|
1009
|
-
`${data.resolvedBy ? ` (resolvedBy=${data.resolvedBy})` : ''}.`);
|
|
1010
|
-
return { exitCode: types_1.VerifyExitCode.NOT_STARTED };
|
|
1315
|
+
const selectionListOutcome = selectionListStage(poll, data);
|
|
1316
|
+
if (selectionListOutcome.kind === 'exit')
|
|
1317
|
+
return selectionListOutcome.result;
|
|
1318
|
+
if (selectionListOutcome.kind === 'wait') {
|
|
1319
|
+
await sleep(POLL_INTERVAL_MS);
|
|
1320
|
+
continue;
|
|
1011
1321
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
if (!data.isRunning) {
|
|
1019
|
-
console.error(`Completed: ${worktreeId} (basis=${COMPLETION_BASIS.SESSION_GONE}${selfResumeSuffix()})`);
|
|
1020
|
-
return { exitCode: types_1.WaitExitCode.SUCCESS };
|
|
1322
|
+
const unclassifiedOutcome = unclassifiedStage(poll, state, data);
|
|
1323
|
+
if (unclassifiedOutcome.kind === 'exit')
|
|
1324
|
+
return unclassifiedOutcome.result;
|
|
1325
|
+
if (unclassifiedOutcome.kind === 'wait') {
|
|
1326
|
+
await sleep(POLL_INTERVAL_MS);
|
|
1327
|
+
continue;
|
|
1021
1328
|
}
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
'composer with an upstream API failure on screen, so this turn did not run. ' +
|
|
1032
|
-
`Matched: ${JSON.stringify(fault.matchedText)}`);
|
|
1033
|
-
if (fault.id === 'context-limit') {
|
|
1034
|
-
// A retry into the same session hits the same wall (Issue #3011).
|
|
1035
|
-
console.error('The session\'s conversation is over the model\'s context limit. Start a fresh ' +
|
|
1036
|
-
`session and send again: commandmate instances ${worktreeId} kill ` +
|
|
1037
|
-
`${options.instance ?? '<instance>'}`);
|
|
1038
|
-
}
|
|
1039
|
-
return {
|
|
1040
|
-
exitCode: types_1.WaitExitCode.UPSTREAM_FAULT,
|
|
1041
|
-
upstreamFault: { id: fault.id, matchedText: fault.matchedText },
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
// Issue #1839: `ready` off the terminal frame is the agent's composer,
|
|
1045
|
-
// not the agent's verdict. Measured 2026-08-20 against a stub upstream
|
|
1046
|
-
// answering 529: Claude returns to the composer ~3 s after the send
|
|
1047
|
-
// having executed nothing, and never sends `Stop`. When this instance's
|
|
1048
|
-
// hooks ARE reporting — the only case in which `turnStartedAt` is
|
|
1049
|
-
// non-null — that missing `Stop` is the difference between "finished"
|
|
1050
|
-
// and "never ran", and it is the only signal that carries it.
|
|
1051
|
-
if (!turnSettled(data, turnStartedAt)) {
|
|
1052
|
-
console.error(`Waiting: ${worktreeId} is back at its composer, but its agent has not reported ` +
|
|
1053
|
-
`the end of this turn (turnStartedAt=${turnStartedAt}, ` +
|
|
1054
|
-
`lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
|
|
1055
|
-
'Not reporting completion; inspect with ' +
|
|
1056
|
-
`\`commandmate capture ${worktreeId} --json\`.`);
|
|
1057
|
-
await sleep(POLL_INTERVAL_MS);
|
|
1058
|
-
continue;
|
|
1059
|
-
}
|
|
1060
|
-
// Issue #2614: the turn did end — the agent said so — but it also said
|
|
1061
|
-
// that work of its own is still running in the background (a `schedule`
|
|
1062
|
-
// timer, a backgrounded command), and that work wakes it with nobody
|
|
1063
|
-
// typing anything. Measured 2026-09-17 on antigravity 1.2.4: four such
|
|
1064
|
-
// stops ~58 s before each self-wake, and the first one was reported as
|
|
1065
|
-
// `Completed (basis=hook_stop)` and verified five minutes before the
|
|
1066
|
-
// work was done. So this `stop` is held until it is no longer the newest
|
|
1067
|
-
// word (see `selfResumeStopAt` above), or until the bound.
|
|
1068
|
-
//
|
|
1069
|
-
// The bound is measured from whichever is further along: the `stop`
|
|
1070
|
-
// itself (server clock — a negative age is skew, and the max discards
|
|
1071
|
-
// it) or this wait's first sight of it. A session that said so hours ago
|
|
1072
|
-
// and never woke is not held again.
|
|
1073
|
-
if (selfResumeStopAt !== null) {
|
|
1074
|
-
const now = Date.now();
|
|
1075
|
-
if (selfResumeHold === null)
|
|
1076
|
-
selfResumeHold = { stopAt: selfResumeStopAt, since: now };
|
|
1077
|
-
const heldMs = now - selfResumeHold.since;
|
|
1078
|
-
const elapsedMs = Math.max(heldMs, now - selfResumeStopAt);
|
|
1079
|
-
if (elapsedMs < exports.SELF_RESUME_HOLD_MS) {
|
|
1080
|
-
selfResumeHeld = true;
|
|
1081
|
-
console.error(`Waiting: ${worktreeId} ended its turn with background work still running ` +
|
|
1082
|
-
`(stoppedAt=${new Date(selfResumeStopAt).toISOString()}, ` +
|
|
1083
|
-
`lastEventDetail=${exports.SELF_RESUME_PENDING_DETAIL}, ${describeTurnClose(data)}); ` +
|
|
1084
|
-
'it resumes by itself when that work finishes. Not reporting completion ' +
|
|
1085
|
-
`(held ${Math.round(heldMs / 1000)}s, at most ${exports.SELF_RESUME_HOLD_MS / 1000}s ` +
|
|
1086
|
-
'after the stop).');
|
|
1087
|
-
await sleep(POLL_INTERVAL_MS);
|
|
1088
|
-
continue;
|
|
1089
|
-
}
|
|
1090
|
-
console.error(`Note: ${worktreeId} said at its stop ${Math.round(elapsedMs / 1000)}s ` +
|
|
1091
|
-
'ago that background work was still running, and has not resumed since; ' +
|
|
1092
|
-
'completing on that stop.');
|
|
1093
|
-
}
|
|
1094
|
-
// Issue #1975: the same frame, one question further back. #1839's gate
|
|
1095
|
-
// above can only fire once a turn has been ADOPTED, and `send` leaves a
|
|
1096
|
-
// window ~1s wide in which nothing has been: the newest structured event
|
|
1097
|
-
// is still the previous turn's `stop`, so `adoptTurnStart` takes nothing,
|
|
1098
|
-
// `turnSettled` reads null as "settled", and the composer the agent has
|
|
1099
|
-
// not touched yet is read as the composer it came back to. Measured
|
|
1100
|
-
// 2026-08-22 against copilot 1.0.80 on an isolated server: 3 of 5
|
|
1101
|
-
// send-then-wait runs came back in ~0.3s with `basis=scraper_ready` and
|
|
1102
|
-
// no artefact on disk.
|
|
1103
|
-
//
|
|
1104
|
-
// So ask the ledger instead of the clock: has this instance been handed
|
|
1105
|
-
// a prompt that the agent has not reported the end of? See
|
|
1106
|
-
// {@link outstandingPrompt} for why that comparison is the one that
|
|
1107
|
-
// separates "not started" from "finished", and
|
|
1108
|
-
// {@link reportsTurnBoundaries} for why a tool that posts no hooks never
|
|
1109
|
-
// reaches it.
|
|
1110
|
-
let answeredNewestPrompt = false;
|
|
1111
|
-
if (turnStartedAt === null && promptLedgerReadable && reportsTurnBoundaries(data)) {
|
|
1112
|
-
const ledger = await readNewestPromptAt(client, worktreeId, options, data);
|
|
1113
|
-
// One notice, then stop asking: a ledger that failed once will fail
|
|
1114
|
-
// every poll, and the point of degrading is to stop paying for it.
|
|
1115
|
-
promptLedgerReadable = ledger.readable;
|
|
1116
|
-
if (ledger.readable && ledger.submittedAt !== null) {
|
|
1117
|
-
if (outstandingPrompt(data, ledger.submittedAt)) {
|
|
1118
|
-
const heldMs = Date.now() - startTime;
|
|
1119
|
-
if (heldMs < PENDING_PROMPT_HOLD_MS) {
|
|
1120
|
-
console.error(`Waiting: ${worktreeId} is at its composer, but the newest prompt sent to it ` +
|
|
1121
|
-
`has no reported end (sentAt=${new Date(ledger.submittedAt).toISOString()}, ` +
|
|
1122
|
-
`lastStopEventAt=${data.lastStopEventAt ?? 'none'}, ${describeTurnClose(data)}). ` +
|
|
1123
|
-
'Not reporting completion: the agent has not started this turn yet.');
|
|
1124
|
-
await sleep(POLL_INTERVAL_MS);
|
|
1125
|
-
continue;
|
|
1126
|
-
}
|
|
1127
|
-
console.error(`Note: ${worktreeId} has been at its composer for ` +
|
|
1128
|
-
`${Math.round(heldMs / 1000)}s with the newest prompt still unreported by its ` +
|
|
1129
|
-
'agent. Its hooks are not answering; completing on the frame alone.');
|
|
1130
|
-
}
|
|
1131
|
-
else {
|
|
1132
|
-
answeredNewestPrompt = true;
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
}
|
|
1136
|
-
// `hook_stop` on both branches that have one, and they are the same
|
|
1137
|
-
// statement made from two records: the agent reported the end of the
|
|
1138
|
-
// turn this wait is about. `scraper_ready` keeps its documented meaning
|
|
1139
|
-
// — "the screen said so and nothing corroborated it" — which is now
|
|
1140
|
-
// exactly the set of cases that reach it.
|
|
1141
|
-
const basis = turnStartedAt !== null || answeredNewestPrompt
|
|
1142
|
-
? COMPLETION_BASIS.HOOK_STOP
|
|
1143
|
-
: COMPLETION_BASIS.SCRAPER_READY;
|
|
1144
|
-
console.error(`Completed: ${worktreeId} (basis=${basis}${selfResumeSuffix()})`);
|
|
1145
|
-
return { exitCode: types_1.WaitExitCode.SUCCESS };
|
|
1329
|
+
const notRunningOutcome = notRunningStage(poll, state, data, selfResumeSuffix);
|
|
1330
|
+
if (notRunningOutcome.kind === 'exit')
|
|
1331
|
+
return notRunningOutcome.result;
|
|
1332
|
+
const readyOutcome = await readyStage(poll, state, data, selfResumeStopAt, selfResumeSuffix);
|
|
1333
|
+
if (readyOutcome.kind === 'exit')
|
|
1334
|
+
return readyOutcome.result;
|
|
1335
|
+
if (readyOutcome.kind === 'wait') {
|
|
1336
|
+
await sleep(POLL_INTERVAL_MS);
|
|
1337
|
+
continue;
|
|
1146
1338
|
}
|
|
1147
1339
|
// Progress indicator on stderr [DR1-05]
|
|
1148
1340
|
console.error(`Waiting: ${worktreeId} (status=${data.sessionStatus}, running=${data.isRunning}, prompt=${data.isPromptWaiting})`);
|