commandmate 0.33.2 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +160 -160
- package/.next/app-path-routes-manifest.json +28 -28
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +12 -12
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route.js.nft.json +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/session/route.js +1 -1
- package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/start/route.js +2 -2
- package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/terminal/route.js +3 -3
- package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route.js.nft.json +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route.js +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route.js +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route.js +1 -1
- package/.next/server/app/api/relays/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route.js +1 -1
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route.js +1 -1
- package/.next/server/app/api/skills/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route.js +1 -1
- package/.next/server/app/api/skills/installations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route_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.js.nft.json +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +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 +2 -2
- 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.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_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.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/tasks/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route.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.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_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/chat/page_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.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +10 -10
- 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 +28 -28
- package/.next/server/chunks/1049.js +1 -0
- package/.next/server/chunks/1501.js +6 -2
- package/.next/server/chunks/1886.js +3 -3
- 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/3123.js +1 -1
- package/.next/server/chunks/3241.js +1 -1
- package/.next/server/chunks/3323.js +1 -1
- package/.next/server/chunks/3480.js +2 -2
- package/.next/server/chunks/4443.js +1 -1
- package/.next/server/chunks/4802.js +1 -1
- package/.next/server/chunks/5164.js +1 -1
- package/.next/server/chunks/5571.js +1 -1
- package/.next/server/chunks/595.js +2 -2
- package/.next/server/chunks/6130.js +1 -0
- package/.next/server/chunks/6285.js +1 -1
- package/.next/server/chunks/6286.js +7 -7
- package/.next/server/chunks/6337.js +1 -1
- package/.next/server/chunks/650.js +1 -1
- package/.next/server/chunks/663.js +1 -1
- package/.next/server/chunks/6661.js +1 -1
- package/.next/server/chunks/6677.js +25 -0
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/7075.js +1 -0
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8583.js +1 -0
- package/.next/server/chunks/8918.js +7 -5
- package/.next/server/chunks/9080.js +1 -0
- package/.next/server/chunks/9627.js +1 -1
- package/.next/server/chunks/964.js +1 -0
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/2053-9ac860ab4e92ac89.js +1 -0
- package/.next/static/chunks/2652-18b8fea64413467e.js +1 -0
- package/.next/static/chunks/{4718-441a2af91f0374e9.js → 4718-2d9f0397a8f931c4.js} +1 -1
- package/.next/static/chunks/6022-7a7d1760fc9814c7.js +1 -0
- package/.next/static/chunks/{8361-9bb887203c456edb.js → 8361-0142beb59be2abf3.js} +1 -1
- package/.next/static/chunks/app/{page-022090bf6f932818.js → page-26a42881c8648cd3.js} +1 -1
- package/.next/static/chunks/app/sessions/page-a3ab6f122ec60d5a.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-a39ec2a0732d11a6.js +1 -0
- package/.next/static/css/b09bede85744e1cf.css +1 -0
- package/.next/trace +13 -13
- package/dist/cli/commands/ask.d.ts.map +1 -1
- package/dist/cli/commands/ask.js +11 -2
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +8 -4
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +18 -0
- package/dist/cli/commands/wait.d.ts +18 -3
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +137 -2
- package/dist/cli/docs/agent-operations.d.ts +2 -2
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +41 -1
- package/dist/cli/utils/session-target.d.ts +23 -6
- package/dist/cli/utils/session-target.d.ts.map +1 -1
- package/dist/cli/utils/session-target.js +33 -5
- package/dist/server/locales/en/worktree.json +30 -4
- package/dist/server/locales/ja/worktree.json +30 -4
- package/dist/server/src/config/schedule-config.js +45 -3
- package/dist/server/src/lib/cli-tools/antigravity.js +95 -10
- package/dist/server/src/lib/cli-tools/submit-verified-sender.js +377 -16
- package/dist/server/src/lib/cli-tools/vibe-local.js +10 -0
- package/dist/server/src/lib/cmate-parser.js +8 -1
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +140 -19
- package/dist/server/src/lib/detection/tools/claude/detect.js +13 -2
- package/dist/server/src/lib/detection/tools/claude/picker-chrome.js +239 -0
- package/dist/server/src/lib/detection/tools/claude/prompt.js +74 -6
- package/dist/server/src/lib/hooks/hook-settings-generator.js +61 -1
- package/dist/server/src/lib/hooks/sources/antigravity/history.js +302 -27
- package/dist/server/src/lib/hooks/sources/antigravity/transcript.js +103 -0
- package/dist/server/src/lib/hooks/sources/claude/history.js +391 -34
- package/dist/server/src/lib/hooks/sources/claude/transcript.js +91 -0
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +114 -11
- package/dist/server/src/lib/polling/response-checker.js +82 -3
- package/dist/server/src/lib/polling/structured-history-gate.js +68 -4
- package/dist/server/src/lib/schedule-manager.js +178 -19
- package/dist/server/src/lib/session/agent-session-lifecycle.js +31 -1
- package/dist/server/src/lib/session/ask-user-question-prompt.js +4 -2
- package/dist/server/src/lib/session/claude-executor.js +33 -2
- package/dist/server/src/lib/session/resolve-session-target.js +37 -9
- package/dist/server/src/lib/session/session-generation-archive.js +194 -0
- package/dist/server/src/lib/tasks/contract-message.js +83 -9
- package/dist/server/src/lib/tasks/contract-parser.js +2 -0
- package/dist/server/src/lib/verification/env-clean-gate.js +81 -4
- package/dist/server/src/types/agent-transcript.js +143 -1
- package/package.json +1 -1
- package/.next/server/chunks/1068.js +0 -1
- package/.next/server/chunks/153.js +0 -1
- package/.next/server/chunks/4299.js +0 -1
- package/.next/server/chunks/6808.js +0 -1
- package/.next/server/chunks/6838.js +0 -1
- package/.next/server/chunks/7366.js +0 -5
- package/.next/server/chunks/7875.js +0 -25
- package/.next/static/chunks/2053-3f299a7a2c7d6767.js +0 -1
- package/.next/static/chunks/6022-2fa0b5a82d4ce7b6.js +0 -1
- package/.next/static/chunks/8772-9be53a530950d804.js +0 -1
- package/.next/static/chunks/app/sessions/page-584adf11ae51df10.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-38edcd53e51f53b0.js +0 -1
- package/.next/static/css/acd46e25427a2080.css +0 -1
- /package/.next/static/{0a4qrU8WdUwQrlO4mfLMu → gniPBCKoXtbIOQey8kNcx}/_buildManifest.js +0 -0
- /package/.next/static/{0a4qrU8WdUwQrlO4mfLMu → gniPBCKoXtbIOQey8kNcx}/_ssgManifest.js +0 -0
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
* @module lib/hooks/hook-settings-generator
|
|
44
44
|
*/
|
|
45
45
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.PERMISSION_DENY_RULES = exports.TOOL_USE_MATCHER = exports.NOTIFICATION_MATCHER = exports.AUTH_TOKEN_ENV_VAR = exports.PERMISSION_REQUEST_TIMEOUT_SECONDS = exports.HOOK_TIMEOUT_SECONDS = exports.PERMISSION_REQUEST_PATH = exports.AGENT_EVENT_PATH = void 0;
|
|
46
|
+
exports.PERMISSION_DENY_RULES = exports.TMUX_UNPINNED_DENY_RULES = exports.TOOL_USE_MATCHER = exports.NOTIFICATION_MATCHER = exports.AUTH_TOKEN_ENV_VAR = exports.PERMISSION_REQUEST_TIMEOUT_SECONDS = exports.HOOK_TIMEOUT_SECONDS = exports.PERMISSION_REQUEST_PATH = exports.AGENT_EVENT_PATH = void 0;
|
|
47
47
|
exports.isHookInjectionEnabled = isHookInjectionEnabled;
|
|
48
48
|
exports.isAuthTokenExpected = isAuthTokenExpected;
|
|
49
49
|
exports.getHookSettingsDirectory = getHookSettingsDirectory;
|
|
@@ -127,6 +127,62 @@ exports.NOTIFICATION_MATCHER = 'permission_prompt|idle_prompt';
|
|
|
127
127
|
* receiver takes.
|
|
128
128
|
*/
|
|
129
129
|
exports.TOOL_USE_MATCHER = permission_request_payload_1.ASK_USER_QUESTION_TOOL;
|
|
130
|
+
/**
|
|
131
|
+
* tmux spellings that reach whichever server the ambient environment points at
|
|
132
|
+
* (Issue #2442).
|
|
133
|
+
*
|
|
134
|
+
* On 2026-09-08 22:53 JST all 42 `mcbd-*` sessions on the default tmux server
|
|
135
|
+
* were destroyed by a socket-less `tmux kill-server` run from an ad-hoc Bash
|
|
136
|
+
* block — the second such wipe after 2026-08-02 (#1624). The block had set
|
|
137
|
+
* `TMUX_TMPDIR` first, which reads as isolation and is not: tmux consults it
|
|
138
|
+
* only while `$TMUX` is unset, and every CommandMate agent runs inside a pane.
|
|
139
|
+
*
|
|
140
|
+
* A tmux invocation carries its target as a *global option before the
|
|
141
|
+
* subcommand* — `-L <name>` (socket name) or `-S <path>` (socket path) — and
|
|
142
|
+
* both outrank `$TMUX`. So "which server does this hit" is decidable from the
|
|
143
|
+
* argv shape alone, and that is what these rules read: a command whose first
|
|
144
|
+
* word is `tmux` and whose second is a destroying or server-global subcommand
|
|
145
|
+
* names no socket and therefore hits the shared one.
|
|
146
|
+
*
|
|
147
|
+
* The pinned spelling of every rule below is deliberately *not* covered, which
|
|
148
|
+
* is what keeps the isolated-probe recipes in `docs/design/` working. "Not
|
|
149
|
+
* covered" means "no new deny rule matches it", not "pre-approved": such a
|
|
150
|
+
* command still goes through the session's normal permission handling.
|
|
151
|
+
*
|
|
152
|
+
* Aliases get their own entry because Claude's prefix matching is **token-exact
|
|
153
|
+
* and adjacency-sensitive**, measured on 2.1.266 in
|
|
154
|
+
* `docs/design/agent-hooks-permission-deny-verification.md` §6: a rule naming
|
|
155
|
+
* `tmux list-p` left `tmux list-panes` untouched, and one naming
|
|
156
|
+
* `tmux show-options -g` left both `tmux show-options -gv …` and
|
|
157
|
+
* `tmux show-options -t 0 -g` untouched. A single truncated rule covering a
|
|
158
|
+
* family is therefore not available — it would load without error and match
|
|
159
|
+
* nothing. `bind` / `unbind` / `set` are tmux's own documented aliases for
|
|
160
|
+
* `bind-key` / `unbind-key` / `set-option`; `kill-server` and `kill-session`
|
|
161
|
+
* have none.
|
|
162
|
+
*
|
|
163
|
+
* Shapes that escape these rules (absolute path, `bash -c`, another global
|
|
164
|
+
* option before the subcommand, tmux's unambiguous-prefix abbreviations,
|
|
165
|
+
* combined global flags) are measured and listed in §6.4 of the same document
|
|
166
|
+
* rather than guessed at here. This layer narrows the accident, it does not
|
|
167
|
+
* close the class — `env-clean` (#1740) is the after-the-fact detector.
|
|
168
|
+
*/
|
|
169
|
+
exports.TMUX_UNPINNED_DENY_RULES = [
|
|
170
|
+
// Destroys every session on the server it reaches. The 2026-08-02 and
|
|
171
|
+
// 2026-09-08 wipes were both this word.
|
|
172
|
+
'Bash(tmux kill-server:*)',
|
|
173
|
+
// `-t` included on purpose: an exact-match `kill-session -t '=name:'` is safe
|
|
174
|
+
// only about *what* it names, never about *where* — and the static guard's
|
|
175
|
+
// exemption for that spelling is why agent recipes must pin the socket.
|
|
176
|
+
'Bash(tmux kill-session:*)',
|
|
177
|
+
// Server-global mutations outlive the caller and are shared with every session
|
|
178
|
+
// on that server.
|
|
179
|
+
'Bash(tmux set-option -g:*)',
|
|
180
|
+
'Bash(tmux set -g:*)',
|
|
181
|
+
'Bash(tmux bind-key:*)',
|
|
182
|
+
'Bash(tmux bind:*)',
|
|
183
|
+
'Bash(tmux unbind-key:*)',
|
|
184
|
+
'Bash(tmux unbind:*)',
|
|
185
|
+
];
|
|
130
186
|
/**
|
|
131
187
|
* Bash spellings this server refuses to let an agent run (Issue #1739).
|
|
132
188
|
*
|
|
@@ -162,11 +218,15 @@ exports.TOOL_USE_MATCHER = permission_request_payload_1.ASK_USER_QUESTION_TOOL;
|
|
|
162
218
|
* signals every process the user owns and `kill -9 -<pgid>` a whole group; the
|
|
163
219
|
* default `kill` (SIGTERM) is untouched, so the graceful spelling of the same
|
|
164
220
|
* intent is the one that survives.
|
|
221
|
+
*
|
|
222
|
+
* Issue #2442 adds the tmux half of the same story: see
|
|
223
|
+
* {@link TMUX_UNPINNED_DENY_RULES}.
|
|
165
224
|
*/
|
|
166
225
|
exports.PERMISSION_DENY_RULES = [
|
|
167
226
|
'Bash(pkill:*)',
|
|
168
227
|
'Bash(killall:*)',
|
|
169
228
|
'Bash(kill -9:*)',
|
|
229
|
+
...exports.TMUX_UNPINNED_DENY_RULES,
|
|
170
230
|
];
|
|
171
231
|
/** Relay script shipped with the package (`files: ["scripts/hooks/"]`). */
|
|
172
232
|
const RELAY_SCRIPT_RELATIVE_PATH = (0, path_1.join)('scripts', 'hooks', 'cmate-agent-event.sh');
|
|
@@ -47,6 +47,25 @@
|
|
|
47
47
|
* module reads only the former — see {@link ANTIGRAVITY_CLI_HOME_SEGMENTS} — and
|
|
48
48
|
* the conversation ids are uuids in any case.
|
|
49
49
|
*
|
|
50
|
+
* ## Saving and finishing are two questions (Issue #2443)
|
|
51
|
+
*
|
|
52
|
+
* agy writes no record that closes a turn, so "may this be saved" has to be
|
|
53
|
+
* answered from the shape of its last words — and an interim report has the
|
|
54
|
+
* same shape as a conclusion. #2438 made the row that follows repairable. #2443
|
|
55
|
+
* separates the *second* consequence of the same evidence: whether the body may
|
|
56
|
+
* be handed onward as the answer. Two states, and the reader reports which one
|
|
57
|
+
* the newest turn is in:
|
|
58
|
+
*
|
|
59
|
+
* - **provisional** — History holds the turn, the scraper stands down, the row
|
|
60
|
+
* keeps being re-read and grown, and `broadcastMessage('message_updated', …)`
|
|
61
|
+
* refreshes what a browser is showing. Nothing leaves the server.
|
|
62
|
+
* - **settled** — agy's own `Stop` arrived at or after the turn's newest
|
|
63
|
+
* record, so the body is the one it finished on. The gate announces the
|
|
64
|
+
* completion edge exactly once for that body.
|
|
65
|
+
*
|
|
66
|
+
* `docs/design/antigravity-turn-completion-2443.md` is the argument, including
|
|
67
|
+
* what happens when the evidence never arrives.
|
|
68
|
+
*
|
|
50
69
|
* ## Nothing here throws
|
|
51
70
|
*
|
|
52
71
|
* Same contract as the other three readers, for the same reason: this runs
|
|
@@ -91,8 +110,9 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
91
110
|
};
|
|
92
111
|
})();
|
|
93
112
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
94
|
-
exports.ANTIGRAVITY_TURN_RECHECK_LIMIT = exports.ANTIGRAVITY_CLI_HOME_SEGMENTS = exports.ANTIGRAVITY_TRANSCRIPT_TAIL_BYTES = void 0;
|
|
113
|
+
exports.ANTIGRAVITY_TURN_RECHECK_LIMIT = exports.ANTIGRAVITY_UNSETTLED_TURN_LIMIT = exports.ANTIGRAVITY_CLI_HOME_SEGMENTS = exports.ANTIGRAVITY_TRANSCRIPT_TAIL_BYTES = void 0;
|
|
95
114
|
exports.resetAntigravityTranscriptConversations = resetAntigravityTranscriptConversations;
|
|
115
|
+
exports.resetAntigravityUnsettledTurns = resetAntigravityUnsettledTurns;
|
|
96
116
|
exports.resolveAntigravityConversationId = resolveAntigravityConversationId;
|
|
97
117
|
exports.resolveAntigravityHome = resolveAntigravityHome;
|
|
98
118
|
exports.antigravityBrainRoot = antigravityBrainRoot;
|
|
@@ -159,12 +179,153 @@ const ANTIGRAVITY_CONVERSATION_ID_PATTERN = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9
|
|
|
159
179
|
* did not would otherwise blank the pointer mid-session.
|
|
160
180
|
*/
|
|
161
181
|
const conversationPointers = (globalThis.__antigravityTranscriptConversations ??= new Map());
|
|
182
|
+
/**
|
|
183
|
+
* How many written-but-unconfirmed turns one instance may be following (#2443).
|
|
184
|
+
*
|
|
185
|
+
* The bound on the answer to "a saved row must be able to catch up with its
|
|
186
|
+
* conclusion even once three later turns have been written". Sixteen and not
|
|
187
|
+
* "however many are in the window", because the list is walked on **every**
|
|
188
|
+
* poll: each entry costs one indexed `findMessageByRequestId` and, only when
|
|
189
|
+
* that finds a row, one render of a turn that is already parsed. Sixteen turns
|
|
190
|
+
* is more than a working session accumulates without a single `Stop` arriving,
|
|
191
|
+
* and it is a fixed ceiling on a per-instance map rather than a function of a
|
|
192
|
+
* file somebody else appends to.
|
|
193
|
+
*
|
|
194
|
+
* Eviction is oldest-first and is a real loss of coverage, which is why it is
|
|
195
|
+
* logged (`antigravity-transcript-unsettled-evicted`) rather than silent. What
|
|
196
|
+
* is left is #2438's behaviour for that row: the newest
|
|
197
|
+
* {@link ANTIGRAVITY_TURN_RECHECK_LIMIT} turns are re-read regardless of this
|
|
198
|
+
* list, so an evicted entry loses the *extra* reach and not the ordinary one.
|
|
199
|
+
*/
|
|
200
|
+
exports.ANTIGRAVITY_UNSETTLED_TURN_LIMIT = 16;
|
|
201
|
+
/**
|
|
202
|
+
* Which written turns are still waiting for agy to vouch for them (#2443).
|
|
203
|
+
*
|
|
204
|
+
* On `globalThis` for the reason {@link conversationPointers} is: under `next
|
|
205
|
+
* dev` the poller's bundle and the hook receiver's bundle each get their own
|
|
206
|
+
* copy of a module-scoped map, and a list only one of the two writers can see is
|
|
207
|
+
* not a list.
|
|
208
|
+
*
|
|
209
|
+
* In memory and not in SQLite, deliberately. The entry describes a turn this
|
|
210
|
+
* *process* wrote provisionally and has not seen confirmed; a restart loses it,
|
|
211
|
+
* and what remains is exactly {@link ANTIGRAVITY_TURN_RECHECK_LIMIT} — the same
|
|
212
|
+
* coverage #2438 shipped. Persisting it would make a row's repair depend on a
|
|
213
|
+
* table that outlives the transcript window it can only be repaired from.
|
|
214
|
+
*/
|
|
215
|
+
const unsettledTurns = (globalThis.__antigravityUnsettledTurns ??= new Map());
|
|
162
216
|
function keyOf(target) {
|
|
163
217
|
return (0, auto_yes_state_1.buildCompositeKey)(target.worktreeId, target.cliToolId, target.instanceId);
|
|
164
218
|
}
|
|
165
|
-
/**
|
|
219
|
+
/**
|
|
220
|
+
* Forget every instance's pointer and every unconfirmed row it was following.
|
|
221
|
+
*
|
|
222
|
+
* Test seam. Both maps, because they are two halves of one per-instance state:
|
|
223
|
+
* a suite that reset the pointer and kept the follow list would carry one test's
|
|
224
|
+
* `step_index` values into the next one's conversation.
|
|
225
|
+
*/
|
|
166
226
|
function resetAntigravityTranscriptConversations() {
|
|
167
227
|
conversationPointers.clear();
|
|
228
|
+
unsettledTurns.clear();
|
|
229
|
+
}
|
|
230
|
+
/** Forget the unconfirmed rows alone. Test seam. */
|
|
231
|
+
function resetAntigravityUnsettledTurns() {
|
|
232
|
+
unsettledTurns.clear();
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* The steps this instance is following in `conversationId`, oldest first.
|
|
236
|
+
*
|
|
237
|
+
* A conversation that is not the one the list was built for answers empty and
|
|
238
|
+
* drops the list: `/clear` mints a new conversation id, and following the old
|
|
239
|
+
* one's `step_index` values into it would re-check turns that are not the same
|
|
240
|
+
* turns. This is the leak test #2443 asks for, expressed as the read path
|
|
241
|
+
* rather than as a promise.
|
|
242
|
+
*/
|
|
243
|
+
function unsettledStepsFor(key, conversationId) {
|
|
244
|
+
const entry = unsettledTurns.get(key);
|
|
245
|
+
if (!entry)
|
|
246
|
+
return [];
|
|
247
|
+
if (entry.conversationId !== conversationId) {
|
|
248
|
+
unsettledTurns.delete(key);
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
return entry.steps;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Start, or stop, following one written turn (Issue #2443).
|
|
255
|
+
*
|
|
256
|
+
* `confirmed` is {@link AntigravityTurnCompletion.confirmed}: a turn agy has
|
|
257
|
+
* vouched for cannot grow again without a later record, and a later record takes
|
|
258
|
+
* the confirmation away and re-adds it here on the very next pass. So the list
|
|
259
|
+
* holds exactly the rows whose body is still provisional.
|
|
260
|
+
*
|
|
261
|
+
* @returns The step that was evicted to make room, or null
|
|
262
|
+
*/
|
|
263
|
+
function noteAntigravityTurnCompletion(key, conversationId, stepIndex, confirmed) {
|
|
264
|
+
const entry = unsettledTurns.get(key);
|
|
265
|
+
if (entry && entry.conversationId !== conversationId)
|
|
266
|
+
unsettledTurns.delete(key);
|
|
267
|
+
if (confirmed) {
|
|
268
|
+
const current = unsettledTurns.get(key);
|
|
269
|
+
if (!current)
|
|
270
|
+
return null;
|
|
271
|
+
current.steps = current.steps.filter((step) => step !== stepIndex);
|
|
272
|
+
if (current.steps.length === 0)
|
|
273
|
+
unsettledTurns.delete(key);
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
const current = unsettledTurns.get(key) ?? { conversationId, steps: [] };
|
|
277
|
+
unsettledTurns.set(key, current);
|
|
278
|
+
if (current.steps.includes(stepIndex))
|
|
279
|
+
return null;
|
|
280
|
+
current.steps.push(stepIndex);
|
|
281
|
+
if (current.steps.length <= exports.ANTIGRAVITY_UNSETTLED_TURN_LIMIT)
|
|
282
|
+
return null;
|
|
283
|
+
return current.steps.shift() ?? null;
|
|
284
|
+
}
|
|
285
|
+
/** Stop following steps the current read window no longer contains. */
|
|
286
|
+
function forgetAntigravityTurnsOutsideWindow(key, conversationId, present) {
|
|
287
|
+
const entry = unsettledTurns.get(key);
|
|
288
|
+
if (!entry || entry.conversationId !== conversationId)
|
|
289
|
+
return [];
|
|
290
|
+
const dropped = entry.steps.filter((step) => !present.has(step));
|
|
291
|
+
if (dropped.length === 0)
|
|
292
|
+
return [];
|
|
293
|
+
entry.steps = entry.steps.filter((step) => present.has(step));
|
|
294
|
+
if (entry.steps.length === 0)
|
|
295
|
+
unsettledTurns.delete(key);
|
|
296
|
+
return dropped;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* When this instance last reported that its loop stopped, or null (#2443).
|
|
300
|
+
*
|
|
301
|
+
* The one piece of evidence {@link resolveAntigravityTurnCompletion} is asked to
|
|
302
|
+
* judge against, read the way {@link resolveAntigravityConversationId} reads its
|
|
303
|
+
* own: dynamically, so `agent-event-state`'s module graph is not a static
|
|
304
|
+
* dependency of the poller, and defensively, so a state module that cannot be
|
|
305
|
+
* reached — or a build in which this reader is newer than its neighbour — is one
|
|
306
|
+
* that knows of no stop rather than one that throws inside the save path.
|
|
307
|
+
*
|
|
308
|
+
* `recordAgentStopEvent` runs **before** the Stop receiver asks for a capture
|
|
309
|
+
* (`lib/hooks/agent-event-service`), so the value is already there on the read
|
|
310
|
+
* that stop itself triggers. That ordering is what lets one seam serve both
|
|
311
|
+
* triggers instead of the receiver having to hand a flag down through the gate.
|
|
312
|
+
*/
|
|
313
|
+
async function resolveAntigravityStopAt(target) {
|
|
314
|
+
try {
|
|
315
|
+
const state = await Promise.resolve().then(() => __importStar(require('../../../../lib/session/agent-event-state')));
|
|
316
|
+
const read = state.getLastStopEventAt;
|
|
317
|
+
if (typeof read !== 'function')
|
|
318
|
+
return null;
|
|
319
|
+
return read(target.worktreeId, target.cliToolId, target.instanceId) ?? null;
|
|
320
|
+
}
|
|
321
|
+
catch (error) {
|
|
322
|
+
logger.debug('antigravity-transcript-stop-lookup-failed', {
|
|
323
|
+
worktreeId: target.worktreeId,
|
|
324
|
+
instanceId: target.instanceId ?? target.cliToolId,
|
|
325
|
+
error: error instanceof Error ? error.message : String(error),
|
|
326
|
+
});
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
168
329
|
}
|
|
169
330
|
/**
|
|
170
331
|
* The conversation id this instance's transcript is under, or null.
|
|
@@ -306,6 +467,20 @@ function acceptAntigravityTranscriptPath(agyHome, candidate) {
|
|
|
306
467
|
* is worth holding rather than saving. Every other false leaves it unset, which
|
|
307
468
|
* the gate reads as `'unavailable'`.
|
|
308
469
|
*
|
|
470
|
+
* **A saved turn is not a finished turn (Issue #2443).** #2438 made the frozen
|
|
471
|
+
* row repairable and left the other half of the damage in place: the same
|
|
472
|
+
* `true` that tells the poller to drop its scrape also told the relay that the
|
|
473
|
+
* turn was over, so an interim report was **delivered** to whoever had asked
|
|
474
|
+
* agy a question, and no later `message_updated` could take that back. So the
|
|
475
|
+
* `true` now carries a second word. `report.completion` is `'settled'` only
|
|
476
|
+
* when {@link resolveAntigravityTurnCompletion} can show, from agy's own `Stop`
|
|
477
|
+
* event, that the body in hand is the one it finished on; otherwise it is
|
|
478
|
+
* `'provisional'` — History still holds the row, the repair still runs on every
|
|
479
|
+
* later read, and nothing is announced to a relay. Rows written provisionally
|
|
480
|
+
* are followed by `step_index` (see {@link ANTIGRAVITY_UNSETTLED_TURN_LIMIT}),
|
|
481
|
+
* so the conclusion is still picked up once the turn has fallen out of
|
|
482
|
+
* {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}'s window.
|
|
483
|
+
*
|
|
309
484
|
* @param target - The instance whose turn just ended
|
|
310
485
|
* @param capture - See {@link AntigravityTranscriptCapture}
|
|
311
486
|
* @param report - Optional out-parameter; see `StructuredHistoryCaptureReport`
|
|
@@ -366,7 +541,36 @@ async function captureAntigravityTranscriptTurn(target, capture = {}, report) {
|
|
|
366
541
|
preludeRecords: built.preludeRecords,
|
|
367
542
|
});
|
|
368
543
|
}
|
|
544
|
+
// Issue #2443: one read of the evidence, applied to every turn in the
|
|
545
|
+
// window. `stopAt` is agy's own account of when its loop ended; see
|
|
546
|
+
// {@link resolveAntigravityTurnCompletion} for why an ordering against the
|
|
547
|
+
// turn's newest record — rather than a word, a silence or a `status` — is
|
|
548
|
+
// what the promotion to "final" rests on.
|
|
549
|
+
const instanceKey = keyOf(target);
|
|
550
|
+
const stopAt = await resolveAntigravityStopAt(target);
|
|
551
|
+
const completions = new Map();
|
|
552
|
+
for (const turn of built.turns) {
|
|
553
|
+
completions.set(turn.stepIndex, (0, transcript_1.resolveAntigravityTurnCompletion)(turn, stopAt));
|
|
554
|
+
}
|
|
555
|
+
const newestTurn = built.turns[built.turns.length - 1];
|
|
556
|
+
const newestCompletion = completions.get(newestTurn.stepIndex) ??
|
|
557
|
+
(0, transcript_1.resolveAntigravityTurnCompletion)(newestTurn, stopAt);
|
|
558
|
+
// A step this read can no longer see is a step no later read can repair:
|
|
559
|
+
// the 4 MiB tail slid past it, its `USER_INPUT` is outside the window, or
|
|
560
|
+
// the file was replaced. Logged rather than dropped in silence, because it
|
|
561
|
+
// is the boundary of what #2443 promises.
|
|
562
|
+
const forgotten = forgetAntigravityTurnsOutsideWindow(instanceKey, conversationId, new Set(built.turns.map((turn) => turn.stepIndex)));
|
|
563
|
+
if (forgotten.length > 0) {
|
|
564
|
+
logger.info('antigravity-transcript-unsettled-out-of-window', {
|
|
565
|
+
worktreeId: target.worktreeId,
|
|
566
|
+
instanceId,
|
|
567
|
+
conversationId,
|
|
568
|
+
steps: forgotten,
|
|
569
|
+
turnsInWindow: built.turns.length,
|
|
570
|
+
});
|
|
571
|
+
}
|
|
369
572
|
const pending = await selectUnwrittenAntigravityTurns(target, built.turns);
|
|
573
|
+
const writtenTurns = built.turns.slice(0, built.turns.length - pending.turns.length);
|
|
370
574
|
// Before anything is written: the rows that are already there (#2438). This
|
|
371
575
|
// is deliberately ahead of the early return below, because "the newest turn
|
|
372
576
|
// is already a row" is exactly the state the frozen row the Issue measured
|
|
@@ -375,9 +579,7 @@ async function captureAntigravityTranscriptTurn(target, capture = {}, report) {
|
|
|
375
579
|
// sat in the transcript beside it. Written turns are re-checked whether or
|
|
376
580
|
// not anything is pending, so an old turn can be repaired in the same pass
|
|
377
581
|
// that writes a new one.
|
|
378
|
-
await refreshAntigravityTurnRows(target,
|
|
379
|
-
.slice(0, built.turns.length - pending.turns.length)
|
|
380
|
-
.slice(-exports.ANTIGRAVITY_TURN_RECHECK_LIMIT), path);
|
|
582
|
+
await refreshAntigravityTurnRows(target, selectAntigravityRecheckCandidates(writtenTurns, unsettledStepsFor(instanceKey, conversationId)), path, { instanceKey, conversationId, completions });
|
|
381
583
|
if (pending.turns.length === 0) {
|
|
382
584
|
logger.debug('antigravity-transcript-turns-already-saved', {
|
|
383
585
|
worktreeId: target.worktreeId,
|
|
@@ -387,6 +589,7 @@ async function captureAntigravityTranscriptTurn(target, capture = {}, report) {
|
|
|
387
589
|
// Issue #2437: this turn is already History's Markdown, so the pane rows
|
|
388
590
|
// behind it must stop being "unsaved output" the pre-send flush can pick up.
|
|
389
591
|
await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
|
|
592
|
+
reportAntigravityCompletion(report, newestTurn, newestCompletion);
|
|
390
593
|
return true;
|
|
391
594
|
}
|
|
392
595
|
if (pending.turns.length > 1) {
|
|
@@ -413,7 +616,14 @@ async function captureAntigravityTranscriptTurn(target, capture = {}, report) {
|
|
|
413
616
|
let captured = false;
|
|
414
617
|
for (let index = 0; index < pending.turns.length; index += 1) {
|
|
415
618
|
const turn = pending.turns[index];
|
|
416
|
-
captured = await writeAntigravityTurn(target, turn, (0, transcript_1.renderAntigravityTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index],
|
|
619
|
+
captured = await writeAntigravityTurn(target, turn, (0, transcript_1.renderAntigravityTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], (0, transcript_1.antigravityTurnLastRecordAt)(turn), nextTurnOpensAt(pending.turns, userRows, index)), path, report);
|
|
620
|
+
// Issue #2443: a row now exists for this turn, and whether it is the body
|
|
621
|
+
// agy finished on is a separate question from whether it could be saved.
|
|
622
|
+
// An unconfirmed one joins the follow list so that its conclusion is still
|
|
623
|
+
// picked up once three later turns have pushed it out of #2438's window.
|
|
624
|
+
if (captured) {
|
|
625
|
+
noteUnsettledAntigravityTurn(target, instanceKey, turn, completions.get(turn.stepIndex) ?? (0, transcript_1.resolveAntigravityTurnCompletion)(turn, stopAt));
|
|
626
|
+
}
|
|
417
627
|
}
|
|
418
628
|
if (captured) {
|
|
419
629
|
// Issue #2437: History now holds this turn as the agent's own Markdown.
|
|
@@ -421,6 +631,7 @@ async function captureAntigravityTranscriptTurn(target, capture = {}, report) {
|
|
|
421
631
|
// `/send` arriving before the next poll tick saves the whole finished turn
|
|
422
632
|
// a second time.
|
|
423
633
|
await (0, assistant_response_saver_1.advanceCapturedLineForTranscriptTurn)(target);
|
|
634
|
+
reportAntigravityCompletion(report, newestTurn, newestCompletion);
|
|
424
635
|
}
|
|
425
636
|
return captured;
|
|
426
637
|
}
|
|
@@ -585,23 +796,6 @@ function resolveAssistantTimestampMs(turn, userRow, lastRecordAt = 0, nextTurnOp
|
|
|
585
796
|
const latest = nextTurnOpensAt === null ? Number.POSITIVE_INFINITY : nextTurnOpensAt - 1;
|
|
586
797
|
return Math.max(earliest, Math.min(lastRecordAt, latest));
|
|
587
798
|
}
|
|
588
|
-
/**
|
|
589
|
-
* When the last record agy wrote for this turn was made (Issue #2273).
|
|
590
|
-
*
|
|
591
|
-
* The maximum rather than `records.at(-1)`: `created_at` is agy's own field and
|
|
592
|
-
* a record that carries none reads as null, so the last record in file order is
|
|
593
|
-
* not always the last one with a clock on it.
|
|
594
|
-
*
|
|
595
|
-
* @returns Epoch ms, or 0 when the turn has no timestamped record
|
|
596
|
-
*/
|
|
597
|
-
function lastAntigravityRecordAt(turn) {
|
|
598
|
-
let at = 0;
|
|
599
|
-
for (const record of turn.records) {
|
|
600
|
-
if (record.timestampMs !== null && record.timestampMs > at)
|
|
601
|
-
at = record.timestampMs;
|
|
602
|
-
}
|
|
603
|
-
return at;
|
|
604
|
-
}
|
|
605
799
|
/**
|
|
606
800
|
* The instant the next pending turn's prompt row carries, or null (Issue #2273).
|
|
607
801
|
*
|
|
@@ -727,7 +921,7 @@ async function growAntigravityTurnRow(target, existing, rendered, path) {
|
|
|
727
921
|
* {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}
|
|
728
922
|
* @returns How many rows were replaced
|
|
729
923
|
*/
|
|
730
|
-
async function refreshAntigravityTurnRows(target, candidates, path) {
|
|
924
|
+
async function refreshAntigravityTurnRows(target, candidates, path, follow) {
|
|
731
925
|
if (candidates.length === 0)
|
|
732
926
|
return 0;
|
|
733
927
|
const [{ getDbInstance }, { findMessageByRequestId }] = await Promise.all([
|
|
@@ -737,10 +931,18 @@ async function refreshAntigravityTurnRows(target, candidates, path) {
|
|
|
737
931
|
const db = getDbInstance();
|
|
738
932
|
let updated = 0;
|
|
739
933
|
for (const turn of candidates) {
|
|
740
|
-
|
|
741
|
-
|
|
934
|
+
// Issue #2443: the row lookup moved ahead of the writable check, because
|
|
935
|
+
// the follow list is a statement about ROWS. A turn that is open again has a
|
|
936
|
+
// row whose body is provisional by definition and must stay followed, and a
|
|
937
|
+
// candidate whose row has gone — History cleared, the key rewritten — is one
|
|
938
|
+
// nothing can repair and is dropped here rather than re-queried forever.
|
|
742
939
|
const existing = findMessageByRequestId(db, target.worktreeId, (0, agent_transcript_1.antigravityTurnRequestId)(turn.conversationId, turn.stepIndex));
|
|
743
|
-
if (!existing)
|
|
940
|
+
if (!existing) {
|
|
941
|
+
noteAntigravityTurnCompletion(follow.instanceKey, follow.conversationId, turn.stepIndex, true);
|
|
942
|
+
continue;
|
|
943
|
+
}
|
|
944
|
+
noteUnsettledAntigravityTurn(target, follow.instanceKey, turn, follow.completions.get(turn.stepIndex) ?? (0, transcript_1.resolveAntigravityTurnCompletion)(turn, null));
|
|
945
|
+
if (!(0, transcript_1.isAntigravityTurnWritable)(turn))
|
|
744
946
|
continue;
|
|
745
947
|
if (await growAntigravityTurnRow(target, existing, (0, transcript_1.renderAntigravityTurn)(turn), path)) {
|
|
746
948
|
updated += 1;
|
|
@@ -748,6 +950,79 @@ async function refreshAntigravityTurnRows(target, candidates, path) {
|
|
|
748
950
|
}
|
|
749
951
|
return updated;
|
|
750
952
|
}
|
|
953
|
+
/**
|
|
954
|
+
* The written turns to re-read on this pass (Issue #2443).
|
|
955
|
+
*
|
|
956
|
+
* Two sources, concatenated oldest-first and de-duplicated:
|
|
957
|
+
*
|
|
958
|
+
* - **the newest {@link ANTIGRAVITY_TURN_RECHECK_LIMIT}**, which is #2438's
|
|
959
|
+
* window exactly and is what covers the ordinary case — a row saved at an
|
|
960
|
+
* interim report and concluded seconds later, while the session has not moved
|
|
961
|
+
* on. It is kept as a floor rather than replaced, so a cold process (one that
|
|
962
|
+
* restarted, or one whose follow list was evicted) still has #2438's reach.
|
|
963
|
+
* - **the followed steps**, which are the rows this process wrote from a body
|
|
964
|
+
* agy had not vouched for. They are the ones the limit above loses: four
|
|
965
|
+
* prompts queued back to back push the first turn out of the window in
|
|
966
|
+
* seconds, and nothing else in the system ever revisits it.
|
|
967
|
+
*
|
|
968
|
+
* The result is bounded by `ANTIGRAVITY_TURN_RECHECK_LIMIT +
|
|
969
|
+
* {@link ANTIGRAVITY_UNSETTLED_TURN_LIMIT}` — a fixed 19 — whatever the window
|
|
970
|
+
* holds, so a long transcript cannot make a poll's cost grow with it.
|
|
971
|
+
*
|
|
972
|
+
* @param writtenTurns - Turns in the window that already have rows, oldest first
|
|
973
|
+
* @param followed - `step_index` values from the follow list
|
|
974
|
+
*/
|
|
975
|
+
function selectAntigravityRecheckCandidates(writtenTurns, followed) {
|
|
976
|
+
const recent = writtenTurns.slice(-exports.ANTIGRAVITY_TURN_RECHECK_LIMIT);
|
|
977
|
+
if (followed.length === 0)
|
|
978
|
+
return recent;
|
|
979
|
+
const inRecent = new Set(recent.map((turn) => turn.stepIndex));
|
|
980
|
+
const followedSteps = new Set(followed);
|
|
981
|
+
const older = writtenTurns.filter((turn) => followedSteps.has(turn.stepIndex) && !inRecent.has(turn.stepIndex));
|
|
982
|
+
return older.length === 0 ? recent : [...older, ...recent];
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Follow this row, or stop following it, and say so once (Issue #2443).
|
|
986
|
+
*
|
|
987
|
+
* The log line is the only place an operator can see why a repair did or did not
|
|
988
|
+
* keep happening, so it carries the reason word rather than the boolean:
|
|
989
|
+
* `no-stop-event` and `stop-before-last-record` are very different sessions.
|
|
990
|
+
*/
|
|
991
|
+
function noteUnsettledAntigravityTurn(target, instanceKey, turn, completion) {
|
|
992
|
+
const evicted = noteAntigravityTurnCompletion(instanceKey, turn.conversationId, turn.stepIndex, completion.confirmed);
|
|
993
|
+
if (evicted === null)
|
|
994
|
+
return;
|
|
995
|
+
logger.info('antigravity-transcript-unsettled-evicted', {
|
|
996
|
+
worktreeId: target.worktreeId,
|
|
997
|
+
instanceId: target.instanceId ?? target.cliToolId,
|
|
998
|
+
conversationId: turn.conversationId,
|
|
999
|
+
step: evicted,
|
|
1000
|
+
limit: exports.ANTIGRAVITY_UNSETTLED_TURN_LIMIT,
|
|
1001
|
+
});
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* Tell the caller whether the turn it was handed is final (Issue #2443).
|
|
1005
|
+
*
|
|
1006
|
+
* `completion` is what the gate reads to decide whether a relay may be told the
|
|
1007
|
+
* turn ended; `completionKey` is what stops it being told twice about one body.
|
|
1008
|
+
* The key names the turn **and** the instant of its newest record, so a turn
|
|
1009
|
+
* that grows after being confirmed is a new state and is announced again once
|
|
1010
|
+
* the new state is itself confirmed — which is exactly the `Stop`-then-`continue`
|
|
1011
|
+
* case `./source` warns about, handled without a second rule.
|
|
1012
|
+
*
|
|
1013
|
+
* Left entirely alone when the body is not confirmed, apart from the word
|
|
1014
|
+
* `provisional`: the gate defaults an absent `completion` to `settled`, so this
|
|
1015
|
+
* is the one place antigravity opts out of the pre-#2443 announcement.
|
|
1016
|
+
*/
|
|
1017
|
+
function reportAntigravityCompletion(report, turn, completion) {
|
|
1018
|
+
if (!report)
|
|
1019
|
+
return;
|
|
1020
|
+
report.completion = completion.confirmed ? 'settled' : 'provisional';
|
|
1021
|
+
report.completionKey = completion.confirmed
|
|
1022
|
+
? `${(0, agent_transcript_1.antigravityTurnRequestId)(turn.conversationId, turn.stepIndex)}@${completion.lastRecordAt}`
|
|
1023
|
+
: undefined;
|
|
1024
|
+
report.completionReason = completion.reason;
|
|
1025
|
+
}
|
|
751
1026
|
/**
|
|
752
1027
|
* Write one rendered turn, unless it is already there.
|
|
753
1028
|
*
|
|
@@ -76,6 +76,8 @@ exports.isAntigravityTurnClosingRecord = isAntigravityTurnClosingRecord;
|
|
|
76
76
|
exports.isAntigravityTurnWritable = isAntigravityTurnWritable;
|
|
77
77
|
exports.isAntigravityPromptRecord = isAntigravityPromptRecord;
|
|
78
78
|
exports.renderAntigravityTurn = renderAntigravityTurn;
|
|
79
|
+
exports.antigravityTurnLastRecordAt = antigravityTurnLastRecordAt;
|
|
80
|
+
exports.resolveAntigravityTurnCompletion = resolveAntigravityTurnCompletion;
|
|
79
81
|
const event_mapper_1 = require("../event-mapper");
|
|
80
82
|
const turn_body_1 = require("../turn-body");
|
|
81
83
|
/**
|
|
@@ -444,3 +446,104 @@ function renderAntigravityTurn(turn) {
|
|
|
444
446
|
unknownRecordTypes: [...unknown],
|
|
445
447
|
};
|
|
446
448
|
}
|
|
449
|
+
/**
|
|
450
|
+
* Epoch ms of the newest record agy wrote inside this turn, or 0 (Issue #2443).
|
|
451
|
+
*
|
|
452
|
+
* The maximum rather than `records.at(-1)`: `created_at` is agy's own field and
|
|
453
|
+
* a record that carries none reads as null, so the last record in file order is
|
|
454
|
+
* not always the last one with a clock on it. The prompt record is deliberately
|
|
455
|
+
* outside the walk — `records` holds everything *after* the `USER_INPUT` — which
|
|
456
|
+
* is why {@link resolveAntigravityTurnCompletion} floors the comparison at
|
|
457
|
+
* {@link AntigravityTurnAccumulator.startedAt} as well.
|
|
458
|
+
*
|
|
459
|
+
* @returns Epoch ms, or 0 when the turn has no timestamped record
|
|
460
|
+
*/
|
|
461
|
+
function antigravityTurnLastRecordAt(turn) {
|
|
462
|
+
let at = 0;
|
|
463
|
+
for (const record of turn.records) {
|
|
464
|
+
if (record.timestampMs !== null && record.timestampMs > at)
|
|
465
|
+
at = record.timestampMs;
|
|
466
|
+
}
|
|
467
|
+
return at;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Whether agy has vouched for this turn's body (Issue #2443).
|
|
471
|
+
*
|
|
472
|
+
* ## What this is separate from, and why the separation is the Issue
|
|
473
|
+
*
|
|
474
|
+
* {@link isAntigravityTurnWritable} answers "may a row be written from this
|
|
475
|
+
* turn". It has to be generous — agy writes **no record that closes a turn**, so
|
|
476
|
+
* the shape of the last thing it wrote is all there is, and an interim report
|
|
477
|
+
* ("waiting for the worker") is prose with no `tool_calls` exactly like a
|
|
478
|
+
* conclusion is. #2438 made the row that follows from that repairable. What it
|
|
479
|
+
* could not make repairable is everything a save *triggers*: a relay delivering
|
|
480
|
+
* the interim body to the session that asked for the answer cannot be taken
|
|
481
|
+
* back, and `broadcastMessage('message_updated', …)` does not rewind it.
|
|
482
|
+
*
|
|
483
|
+
* So this is the second question — "is this body final" — and it is answered
|
|
484
|
+
* from a different kind of evidence, deliberately:
|
|
485
|
+
*
|
|
486
|
+
* - **not the wording.** "waiting", "Waiting for" and their translations are a
|
|
487
|
+
* model's prose, and a rule keyed on them is wrong the first time the model
|
|
488
|
+
* is asked to answer in another language or writes a conclusion that mentions
|
|
489
|
+
* waiting.
|
|
490
|
+
* - **not a fixed quiet period.** The gaps measured on the reporting machine
|
|
491
|
+
* were 3 / 58 / 156 s from an interim candidate to the next record and 9 /
|
|
492
|
+
* 113 / 118 s from the final one, which overlap: no constant separates them.
|
|
493
|
+
* - **not `status: DONE`** (all 15 measured candidates carry it, early and
|
|
494
|
+
* final alike) **and not `truncated_fields`**, which is agy saying it
|
|
495
|
+
* shortened a field.
|
|
496
|
+
*
|
|
497
|
+
* ## The evidence that is used
|
|
498
|
+
*
|
|
499
|
+
* agy's own `Stop` hook, correlated by instant. `Stop` is agy reporting that its
|
|
500
|
+
* loop ended, and CommandMate already records when one arrived
|
|
501
|
+
* (`session/agent-event-state`'s `getLastStopEventAt`). What makes it usable
|
|
502
|
+
* despite `source.ts`'s warning that a `Stop` can be answered with
|
|
503
|
+
* `{"decision":"continue"}` is that the correlation is an ordering rather than a
|
|
504
|
+
* flag: a stop is evidence about the file **as it was when the stop arrived**.
|
|
505
|
+
*
|
|
506
|
+
* - A resumed loop appends records *after* the stop, which pushes
|
|
507
|
+
* `lastRecordAt` past `stopAt` and takes the confirmation away again. The
|
|
508
|
+
* evidence therefore withdraws itself in exactly the case the warning is
|
|
509
|
+
* about, with no `continue`-detection of its own.
|
|
510
|
+
* - A stop belonging to the *previous* turn is older than this turn's records
|
|
511
|
+
* and confirms nothing.
|
|
512
|
+
* - No stop at all — hooks not wired up, agy killed, CommandMate restarted
|
|
513
|
+
* since — is `no-stop-event`, and the caller keeps the body provisional
|
|
514
|
+
* rather than promoting it.
|
|
515
|
+
*
|
|
516
|
+
* The residual is agy's clock resolution: `created_at` is written to the second,
|
|
517
|
+
* so a record appended in the same second as the stop compares equal to it.
|
|
518
|
+
* That is a sub-second window, it is bounded by one `created_at` tick, and the
|
|
519
|
+
* direction of the error is a body confirmed one record early rather than a turn
|
|
520
|
+
* confirmed that never ended.
|
|
521
|
+
*
|
|
522
|
+
* Pure: the stop instant is a parameter, so this file keeps its no-filesystem,
|
|
523
|
+
* no-database, no-`globalThis` contract and the rule is a property a test states
|
|
524
|
+
* against values rather than against a running server.
|
|
525
|
+
*
|
|
526
|
+
* @param turn - The turn to judge
|
|
527
|
+
* @param stopAt - Epoch ms of this instance's last `Stop`, or null when none has
|
|
528
|
+
* been received
|
|
529
|
+
*/
|
|
530
|
+
function resolveAntigravityTurnCompletion(turn, stopAt) {
|
|
531
|
+
const lastRecordAt = antigravityTurnLastRecordAt(turn);
|
|
532
|
+
const base = { confirmed: false, lastRecordAt, stopAt };
|
|
533
|
+
// A turn agy is still working through has no final body to vouch for. Asked
|
|
534
|
+
// before the clock questions so that "it is still running" never reads as
|
|
535
|
+
// "its records are unstamped".
|
|
536
|
+
if (!isAntigravityTurnWritable(turn))
|
|
537
|
+
return { ...base, reason: 'turn-open' };
|
|
538
|
+
if (lastRecordAt <= 0)
|
|
539
|
+
return { ...base, reason: 'no-timestamped-record' };
|
|
540
|
+
if (stopAt === null)
|
|
541
|
+
return { ...base, reason: 'no-stop-event' };
|
|
542
|
+
// `startedAt` as well as the newest record: a turn whose records all predate
|
|
543
|
+
// its own prompt is a shape this reader has not seen, and taking the later of
|
|
544
|
+
// the two cannot make the test easier to pass.
|
|
545
|
+
if (stopAt < Math.max(lastRecordAt, turn.startedAt)) {
|
|
546
|
+
return { ...base, reason: 'stop-before-last-record' };
|
|
547
|
+
}
|
|
548
|
+
return { confirmed: true, reason: 'stop-after-last-record', lastRecordAt, stopAt };
|
|
549
|
+
}
|