commandmate 0.47.2 → 0.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +215 -215
- package/.next/app-path-routes-manifest.json +41 -41
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +9 -9
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route.js +3 -3
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +2 -2
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route.js +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route.js +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route.js +1 -1
- package/.next/server/app/api/relays/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route.js +1 -1
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/strict/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -103
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +12 -12
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +41 -41
- package/.next/server/chunks/1191.js +11 -4
- package/.next/server/chunks/1501.js +1 -1
- package/.next/server/chunks/1601.js +2 -2
- package/.next/server/chunks/1656.js +2 -2
- package/.next/server/chunks/1945.js +3 -3
- package/.next/server/chunks/1990.js +103 -0
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/2422.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/2534.js +1 -1
- package/.next/server/chunks/255.js +1 -1
- package/.next/server/chunks/3241.js +1 -1
- package/.next/server/chunks/3505.js +2 -2
- package/.next/server/chunks/4248.js +1 -1
- package/.next/server/chunks/4280.js +1 -0
- package/.next/server/chunks/5209.js +1 -1
- package/.next/server/chunks/6119.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6486.js +9 -8
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/720.js +103 -0
- package/.next/server/chunks/7604.js +2 -0
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8581.js +7 -7
- package/.next/server/chunks/8728.js +3 -3
- package/.next/server/chunks/8791.js +1 -1
- package/.next/server/chunks/8807.js +19 -18
- package/.next/server/chunks/8918.js +2 -104
- package/.next/server/chunks/936.js +1 -1
- package/.next/server/chunks/9390.js +1 -1
- package/.next/server/chunks/9540.js +1 -1
- package/.next/server/chunks/9627.js +3 -3
- package/.next/server/chunks/9731.js +2 -2
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/2099-c3e0ab70a1b95dd3.js +1 -0
- package/.next/static/chunks/{2407-a6533805a86d05bd.js → 2407-26139a8a2f1adbe8.js} +1 -1
- package/.next/static/chunks/{2619-04bc32f026a0d946.js → 2619-a305ad4810f1393a.js} +1 -1
- package/.next/static/chunks/{2863-6a07ec82fb52f4dd.js → 2863-f0121af1cbbedb3b.js} +1 -1
- package/.next/static/chunks/{8165-263172c17ae8e8c3.js → 8165-c68b3dc844210e6a.js} +1 -1
- package/.next/static/chunks/8407-35bbfc84793d7004.js +1 -0
- package/.next/static/chunks/9079-406b84d3cc891a87.js +1 -0
- package/.next/static/chunks/app/{layout-538d8d2746ad1588.js → layout-46b4cbf07520d9b6.js} +1 -1
- package/.next/static/chunks/app/sessions/page-fb241bed579c67aa.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-cbc7749a33450cc5.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/{page-373ea37b16d930c7.js → page-c601f3b3ece6557e.js} +1 -1
- package/.next/trace +13 -13
- package/dist/cli/commands/auto-yes.d.ts +24 -0
- package/dist/cli/commands/auto-yes.d.ts.map +1 -1
- package/dist/cli/commands/auto-yes.js +73 -3
- package/dist/cli/commands/instances.d.ts.map +1 -1
- package/dist/cli/commands/instances.js +10 -1
- package/dist/cli/commands/prompt.d.ts.map +1 -1
- package/dist/cli/commands/prompt.js +5 -3
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +15 -0
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +101 -13
- package/dist/cli/docs/agent-operations.d.ts +2 -2
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +27 -0
- package/dist/cli/types/api-responses.d.ts +116 -2
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/types/index.d.ts +4 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/utils/resource-resolvers.d.ts +0 -18
- package/dist/cli/utils/resource-resolvers.d.ts.map +1 -1
- package/dist/cli/utils/resource-resolvers.js +1 -51
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts +54 -2
- package/dist/lib/polling/auto-yes-suppression-reason.d.ts.map +1 -1
- package/dist/lib/polling/auto-yes-suppression-reason.js +33 -2
- package/dist/lib/prompt-observation/types.d.ts +13 -0
- package/dist/lib/prompt-observation/types.d.ts.map +1 -1
- package/dist/server/locales/en/worktree.json +2 -1
- package/dist/server/locales/ja/worktree.json +2 -1
- package/dist/server/src/lib/auto-yes-poller-answer-target.js +38 -0
- package/dist/server/src/lib/auto-yes-poller-keys.js +35 -0
- package/dist/server/src/lib/auto-yes-poller-session-presence.js +26 -0
- package/dist/server/src/lib/auto-yes-poller-tick.js +233 -0
- package/dist/server/src/lib/auto-yes-poller.js +337 -376
- package/dist/server/src/lib/auto-yes-state.js +50 -2
- package/dist/server/src/lib/cli-tools/submit-verified-sender.js +107 -14
- package/dist/server/src/lib/db/chat-db.js +5 -1
- package/dist/server/src/lib/db/verification-db.js +23 -2
- package/dist/server/src/lib/detection/option-recommendation.js +120 -0
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice-approval-context.js +290 -0
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +396 -350
- package/dist/server/src/lib/detection/prompt-detector.js +92 -21
- package/dist/server/src/lib/detection/prompt-screen-key.js +60 -0
- package/dist/server/src/lib/detection/tools/antigravity/dialog.js +158 -35
- package/dist/server/src/lib/detection/tools/claude/detect.js +111 -10
- package/dist/server/src/lib/detection/tools/command-code/dialog.js +67 -0
- package/dist/server/src/lib/detection/tools/dialog-block.js +16 -0
- package/dist/server/src/lib/detection/waiting-screen-reading.js +98 -0
- package/dist/server/src/lib/hooks/permission-decision-service.js +7 -0
- package/dist/server/src/lib/polling/auto-yes-confirm-page.js +2 -2
- package/dist/server/src/lib/polling/auto-yes-confirmation-ledger-types.js +3 -0
- package/dist/server/src/lib/polling/auto-yes-confirmation-ledger.js +34 -3
- package/dist/server/src/lib/polling/auto-yes-decision-state.js +195 -0
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +139 -10
- package/dist/server/src/lib/polling/auto-yes-enter-fallback.js +14 -0
- package/dist/server/src/lib/polling/auto-yes-manual-answer.js +122 -0
- package/dist/server/src/lib/polling/auto-yes-option-effect.js +157 -0
- package/dist/server/src/lib/polling/auto-yes-policy.js +11 -5
- package/dist/server/src/lib/polling/auto-yes-poller-capture.js +15 -2
- package/dist/server/src/lib/polling/auto-yes-poller-generation.js +42 -1
- package/dist/server/src/lib/polling/auto-yes-poller-receipt-log.js +42 -5
- package/dist/server/src/lib/polling/auto-yes-poller-state.js +147 -49
- package/dist/server/src/lib/polling/auto-yes-poller-steps.js +172 -2
- package/dist/server/src/lib/polling/auto-yes-prompt-suppression.js +2 -2
- package/dist/server/src/lib/polling/auto-yes-question-choice.js +57 -0
- package/dist/server/src/lib/polling/auto-yes-resolver.js +96 -21
- package/dist/server/src/lib/polling/auto-yes-suppression-reason.js +33 -2
- package/dist/server/src/lib/polling/auto-yes-suppression-state.js +25 -1
- package/dist/server/src/lib/polling/prompt-screen-reading.js +232 -0
- package/dist/server/src/lib/polling/response-checker-dialog-gate.js +39 -0
- package/dist/server/src/lib/polling/response-checker.js +133 -43
- package/dist/server/src/lib/prompt-answer-sender.js +104 -10
- package/dist/server/src/lib/push/notification-dedup.js +15 -2
- package/dist/server/src/lib/push/prompt-card-state.js +140 -19
- package/dist/server/src/lib/push/prompt-push-gate.js +158 -12
- package/dist/server/src/lib/push/push-sender.js +23 -3
- package/dist/server/src/lib/push/resolution-push-notifier.js +14 -0
- package/dist/server/src/lib/push/waiting-push-notifier.js +139 -17
- package/dist/server/src/lib/realtime/terminal-broadcast.js +16 -0
- package/dist/server/src/lib/session/agent-event-state.js +25 -5
- package/dist/server/src/lib/session/agent-event-turn.js +140 -46
- package/dist/server/src/lib/session/cli-session.js +21 -2
- package/dist/server/src/lib/session/current-output-builder.js +64 -11
- package/dist/server/src/lib/session/send-attempt-state.js +23 -7
- package/dist/server/src/lib/session/waiting-episode-binding-observation.js +289 -0
- package/dist/server/src/lib/session/waiting-episode-binding-resolve.js +38 -0
- package/dist/server/src/lib/session/waiting-episode-binding.js +276 -0
- package/dist/server/src/lib/session/waiting-episode-state.js +307 -17
- package/dist/server/src/lib/session/waiting-episode-verdict.js +174 -0
- package/dist/server/src/lib/tmux/tmux-capture-cache.js +76 -11
- package/dist/server/src/lib/tmux/tmux.js +54 -9
- package/dist/server/src/lib/verification/gate-runner.js +162 -13
- package/dist/server/src/lib/verification/machine-lock.js +5 -0
- package/dist/server/src/lib/ws-server.js +18 -3
- package/dist/server/src/types/auto-yes-answer-mode.js +38 -0
- package/dist/server/src/types/auto-yes-decision.js +61 -0
- package/dist/server/src/types/auto-yes.js +6 -0
- package/dist/server/src/types/prompt-reading.js +32 -0
- package/dist/types/auto-yes-answer-mode.d.ts +35 -0
- package/dist/types/auto-yes-answer-mode.d.ts.map +1 -0
- package/dist/types/auto-yes-answer-mode.js +38 -0
- package/docs/en/user-guide/webapp-guide.md +33 -4
- package/package.json +1 -1
- package/public/sw.js +76 -4
- package/release-notes/0.48.0.json +57 -0
- package/.next/server/chunks/1559.js +0 -2
- package/.next/server/chunks/2460.js +0 -1
- package/.next/server/chunks/5595.js +0 -1
- package/.next/server/chunks/610.js +0 -1
- package/.next/static/chunks/602-1c1488959215e140.js +0 -1
- package/.next/static/chunks/8407-155f84e5ba05f1d5.js +0 -1
- package/.next/static/chunks/9079-24f9fa549ed298f1.js +0 -1
- package/.next/static/chunks/app/sessions/page-e02f1adb1d1c1ccc.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-46aced20b2b1c010.js +0 -1
- /package/.next/static/{etorRtpxbQqqOzdUeXdw2 → PTlAswXLq8PAe2vUJ8dVP}/_buildManifest.js +0 -0
- /package/.next/static/{etorRtpxbQqqOzdUeXdw2 → PTlAswXLq8PAe2vUJ8dVP}/_ssgManifest.js +0 -0
|
@@ -6,10 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.isWithheldForWantOfReceipt = isWithheldForWantOfReceipt;
|
|
9
|
+
exports.isAntigravityGenericReadingOnScreen = isAntigravityGenericReadingOnScreen;
|
|
9
10
|
exports.isNumberedDialogVouched = isNumberedDialogVouched;
|
|
10
11
|
const logger_1 = require("../../lib/logger");
|
|
11
12
|
const logger = (0, logger_1.createLogger)('response-poller');
|
|
12
13
|
const antigravity_receipt_episodes_1 = require("./antigravity-receipt-episodes");
|
|
14
|
+
const dialog_1 = require("../../lib/detection/tools/antigravity/dialog");
|
|
15
|
+
const auto_yes_option_effect_1 = require("./auto-yes-option-effect");
|
|
13
16
|
// Issue #2457: the same rollout table, `hasDialogRules` cross-check and
|
|
14
17
|
// `detectDialog` seam Auto-Yes reads, reached through the presence helper rather
|
|
15
18
|
// than through `evaluateAutoYesDialogGate` — see `isNumberedDialogVouched`.
|
|
@@ -44,6 +47,42 @@ function isWithheldForWantOfReceipt(scope) {
|
|
|
44
47
|
});
|
|
45
48
|
return true;
|
|
46
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Does the screen itself show that the generic parser's agy reading is one
|
|
52
|
+
* CommandMate may answer? (Issue #3881, the second half: finding 8)
|
|
53
|
+
*
|
|
54
|
+
* Asked by the answering entry (`detectPromptOnCleanFrame` with a receipt
|
|
55
|
+
* scope) only for a reading agy's own reader did not take and
|
|
56
|
+
* `isAntigravityUnansweredNumberedScreen` let through — in practice a reply's
|
|
57
|
+
* plain `1. … N.` list (#1928's legacy reading). Before this, such a list was
|
|
58
|
+
* answered whenever agy's hook had recorded a tool call a moment earlier
|
|
59
|
+
* (#2849). The receipt says a tool call happened; it says nothing about
|
|
60
|
+
* whether THIS list is that call's approval UI, so on its own it is not
|
|
61
|
+
* evidence. The screen must show some:
|
|
62
|
+
*
|
|
63
|
+
* - agy's `/feedback` menu (its own footer under the options), the generic
|
|
64
|
+
* reading #2364 left in place;
|
|
65
|
+
* - option rows agy's measured permission wording reads as (`Yes`, `Yes, run
|
|
66
|
+
* command`, `Yes, and always allow …` — `auto-yes-option-effect`).
|
|
67
|
+
*
|
|
68
|
+
* The heading (`Requesting permission for:` / `Do you want to proceed?`), the
|
|
69
|
+
* `>` cursor and the `↑/↓ Navigate` footer are the other evidence, and a frame
|
|
70
|
+
* that shows them reaches no generic reading: agy's reader answers it, or
|
|
71
|
+
* `isAntigravityUnansweredNumberedScreen` declines it (#3808, #3818).
|
|
72
|
+
*
|
|
73
|
+
* A yes/no reading is not a numbered list and is left as it was.
|
|
74
|
+
*
|
|
75
|
+
* @param cleanOutput - The frame the reading came off (ANSI and box drawing stripped)
|
|
76
|
+
* @param reading - The generic parser's reading of it
|
|
77
|
+
*/
|
|
78
|
+
function isAntigravityGenericReadingOnScreen(cleanOutput, reading) {
|
|
79
|
+
const promptData = reading.promptData;
|
|
80
|
+
if (promptData?.type !== 'multiple_choice')
|
|
81
|
+
return true;
|
|
82
|
+
if ((0, dialog_1.isAntigravityFeedbackMenuScreen)(cleanOutput))
|
|
83
|
+
return true;
|
|
84
|
+
return (0, auto_yes_option_effect_1.selectAllowOnceOption)(promptData.options, 'antigravity').kind !== 'not-a-permission-dialog';
|
|
85
|
+
}
|
|
47
86
|
/**
|
|
48
87
|
* Is the generic parser's numbered-list candidate a dialog the tool vouches for?
|
|
49
88
|
* (Issue #2457)
|
|
@@ -64,7 +64,11 @@ const prompt_push_gate_1 = require("../../lib/push/prompt-push-gate");
|
|
|
64
64
|
const failure_push_notifier_1 = require("../../lib/push/failure-push-notifier");
|
|
65
65
|
const upstream_faults_1 = require("../../lib/detection/upstream-faults");
|
|
66
66
|
const waiting_push_notifier_1 = require("../../lib/push/waiting-push-notifier");
|
|
67
|
+
const waiting_episode_binding_1 = require("../../lib/session/waiting-episode-binding");
|
|
67
68
|
const waiting_episode_state_1 = require("../../lib/session/waiting-episode-state");
|
|
69
|
+
const waiting_screen_reading_1 = require("../../lib/detection/waiting-screen-reading");
|
|
70
|
+
const auto_yes_state_1 = require("../../lib/auto-yes-state");
|
|
71
|
+
const auto_yes_poller_state_1 = require("./auto-yes-poller-state");
|
|
68
72
|
const task_transition_service_1 = require("../../lib/tasks/task-transition-service");
|
|
69
73
|
const response_checker_blank_response_1 = require("./response-checker-blank-response");
|
|
70
74
|
/**
|
|
@@ -154,6 +158,7 @@ function broadcastPromptSweptToAnswered(worktreeId) {
|
|
|
154
158
|
// the one that calls `detectPrompt`, and only this file may import
|
|
155
159
|
// `@/lib/tmux/tmux-capture-cache` (.eslintrc.json `no-restricted-imports`).
|
|
156
160
|
const response_checker_extraction_result_1 = require("./response-checker-extraction-result");
|
|
161
|
+
const prompt_screen_reading_1 = require("./prompt-screen-reading");
|
|
157
162
|
var response_checker_extraction_result_2 = require("./response-checker-extraction-result");
|
|
158
163
|
Object.defineProperty(exports, "incompleteResult", { enumerable: true, get: function () { return response_checker_extraction_result_2.incompleteResult; } });
|
|
159
164
|
Object.defineProperty(exports, "buildPromptExtractionResult", { enumerable: true, get: function () { return response_checker_extraction_result_2.buildPromptExtractionResult; } });
|
|
@@ -197,8 +202,10 @@ const response_checker_extraction_steps_1 = require("./response-checker-extracti
|
|
|
197
202
|
* @param receiptScope - whose frame this is, when the caller answers it
|
|
198
203
|
* automatically (Issue #2849). For agy only: a frame that reads as a prompt is
|
|
199
204
|
* then handed back as no prompt unless agy asked CommandMate about a tool call
|
|
200
|
-
* for that instance a moment ago
|
|
201
|
-
*
|
|
205
|
+
* for that instance a moment ago — and (Issue #3881) a generic numbered
|
|
206
|
+
* reading also needs evidence on the screen itself
|
|
207
|
+
* (`isAntigravityGenericReadingOnScreen`). Omitted, the reading is not gated —
|
|
208
|
+
* which is what every caller that only DISPLAYS the frame wants.
|
|
202
209
|
* @param frame - the SAME tick's `normalizeFrame(raw, cliToolId)`, when the
|
|
203
210
|
* caller built one (Issue #3183). The Auto-Yes poller builds it once and hands
|
|
204
211
|
* the same object to the dialog gate, so the quotation veto below and the gate
|
|
@@ -235,7 +242,13 @@ function detectPromptOnCleanFrame(cleanOutput, cliToolId, precomputedLines, rawF
|
|
|
235
242
|
// reads `> 1. Google OAuth` as an answerable option. Judged without the
|
|
236
243
|
// footer, so a missing footer cannot reopen the generic path. The status
|
|
237
244
|
// verdict publishes the same frame as unclassified (`tools/antigravity/detect.ts`).
|
|
238
|
-
|
|
245
|
+
//
|
|
246
|
+
// Issue #3818: and by default — a numbered agy screen keeps the generic
|
|
247
|
+
// reading only as `/feedback` or as a reply's plain `1. … N.` list, so a
|
|
248
|
+
// run with a number missing or its `>` row off the pane is no prompt either.
|
|
249
|
+
// The status verdict keeps #3808's narrower rule: these frames still read
|
|
250
|
+
// as someone waiting there, they are only not answered from here.
|
|
251
|
+
if ((0, dialog_1.isAntigravityUnansweredNumberedScreen)(cleanOutput)) {
|
|
239
252
|
return { isPrompt: false, cleanContent: cleanOutput.trim() };
|
|
240
253
|
}
|
|
241
254
|
}
|
|
@@ -293,6 +306,14 @@ function detectPromptOnCleanFrame(cleanOutput, cliToolId, precomputedLines, rawF
|
|
|
293
306
|
if (cliToolId === 'antigravity' && result.isPrompt && (0, response_checker_dialog_gate_1.isWithheldForWantOfReceipt)(receiptScope)) {
|
|
294
307
|
return { isPrompt: false, cleanContent: cleanOutput.trim() };
|
|
295
308
|
}
|
|
309
|
+
// Issue #3881 (finding 8): and with a receipt, the receipt alone does not
|
|
310
|
+
// vouch for a generic reading — a reply's plain numbered list is answered
|
|
311
|
+
// only when the screen itself shows a known menu or agy's permission rows.
|
|
312
|
+
// Only for the caller that answers (a receipt scope); a display keeps it.
|
|
313
|
+
if (cliToolId === 'antigravity' && result.isPrompt && receiptScope !== undefined
|
|
314
|
+
&& !(0, response_checker_dialog_gate_1.isAntigravityGenericReadingOnScreen)(cleanOutput, result)) {
|
|
315
|
+
return { isPrompt: false, cleanContent: cleanOutput.trim() };
|
|
316
|
+
}
|
|
296
317
|
return result;
|
|
297
318
|
}
|
|
298
319
|
/**
|
|
@@ -615,6 +636,24 @@ function extractCompletedTurn(ctx, output, lastCapturedLine, owns) {
|
|
|
615
636
|
}
|
|
616
637
|
return { result, isFullScreenTui, lineCountIsCursor };
|
|
617
638
|
}
|
|
639
|
+
/**
|
|
640
|
+
* The episode a committed prompt observation left this wait in (Issue #3798):
|
|
641
|
+
* the one kept or rebound, the one the commit just opened or put in place, or
|
|
642
|
+
* null when the commit changed nothing.
|
|
643
|
+
*/
|
|
644
|
+
function committedEpisodeId(plan, committed) {
|
|
645
|
+
const obs = plan.observation;
|
|
646
|
+
switch (committed) {
|
|
647
|
+
case 'kept':
|
|
648
|
+
case 'rebound':
|
|
649
|
+
return plan.episodeId;
|
|
650
|
+
case 'opened':
|
|
651
|
+
case 'replaced':
|
|
652
|
+
return (0, waiting_episode_state_1.getWaitingEpisodeRecord)(obs.worktreeId, obs.cliToolId, obs.instanceId)?.episodeId ?? null;
|
|
653
|
+
default:
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
618
657
|
/**
|
|
619
658
|
* Save a live prompt as a prompt message, and raise what follows from it: the
|
|
620
659
|
* task event, the push notification and the waiting episode.
|
|
@@ -627,9 +666,11 @@ function extractCompletedTurn(ctx, output, lastCapturedLine, owns) {
|
|
|
627
666
|
* @param promptDetection - The detection that passed the #2457 gate
|
|
628
667
|
* @param result - The complete extraction this tick made
|
|
629
668
|
* @param isFullScreenTui - True for opencode and copilot, which keep polling after a prompt
|
|
669
|
+
* @param frameTime - When the frame this prompt was read on was fetched (Issue #3798)
|
|
670
|
+
* @param frame - The capture the prompt was read on, for the stored reading (Issue #3881)
|
|
630
671
|
* @returns What `checkForResponse` returns for this tick
|
|
631
672
|
*/
|
|
632
|
-
function savePromptMessage(ctx, promptDetection, result, isFullScreenTui) {
|
|
673
|
+
function savePromptMessage(ctx, promptDetection, result, isFullScreenTui, frameTime, frame) {
|
|
633
674
|
const { db, worktree, worktreeId, cliToolId, instanceId, resolvedInstanceId, pollerKey } = ctx;
|
|
634
675
|
// Issue #3701: the question #3663 / #3684 ask, for the prompt a tick retired
|
|
635
676
|
// during the capture's `await` then finds on the pane — no row, broadcast,
|
|
@@ -646,6 +687,34 @@ function savePromptMessage(ctx, promptDetection, result, isFullScreenTui) {
|
|
|
646
687
|
});
|
|
647
688
|
return false;
|
|
648
689
|
}
|
|
690
|
+
// Issue #3798 (design 規則 8): what this prompt does to the waiting episode,
|
|
691
|
+
// decided BEFORE the dedup below registers its hash. A frame fetched before
|
|
692
|
+
// the close of the very confirmation it shows — an answer and a stop landed
|
|
693
|
+
// during the capture — is not a new wait: nothing is saved, registered or
|
|
694
|
+
// pushed, and the next tick's frame decides. Planned against the state as it
|
|
695
|
+
// is now (`freshPrompt`), not as the tick found it. With the Auto-Yes
|
|
696
|
+
// poller's last answer (PR 3): another confirmation in the wait it answered
|
|
697
|
+
// is a new wait (R1-7), with a hold of its own rather than the spent one.
|
|
698
|
+
const plan = (0, waiting_episode_binding_1.planWaitingObservation)({
|
|
699
|
+
worktreeId,
|
|
700
|
+
cliToolId,
|
|
701
|
+
instanceId,
|
|
702
|
+
observer: 'response-checker',
|
|
703
|
+
start: ctx.observationStart,
|
|
704
|
+
reading: (0, waiting_screen_reading_1.promptWaitingReading)(promptDetection.promptData ?? null),
|
|
705
|
+
...frameTime,
|
|
706
|
+
freshPrompt: true,
|
|
707
|
+
lastAnswer: (0, auto_yes_poller_state_1.getAutoYesLastAnswer)((0, auto_yes_state_1.buildCompositeKey)(worktreeId, cliToolId, instanceId)),
|
|
708
|
+
});
|
|
709
|
+
if (plan.action === 'ignored') {
|
|
710
|
+
logger.info('prompt-observation-stale', {
|
|
711
|
+
worktreeId,
|
|
712
|
+
cliToolId,
|
|
713
|
+
instanceId: resolvedInstanceId,
|
|
714
|
+
because: plan.ignoredBecause,
|
|
715
|
+
});
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
649
718
|
// Issue #565: Content hash-based duplicate prompt prevention
|
|
650
719
|
const promptContent = promptDetection.rawContent || promptDetection.cleanContent;
|
|
651
720
|
const normalizedForDedup = (0, prompt_dedup_1.normalizePromptForDedup)(promptContent, cliToolId);
|
|
@@ -670,6 +739,9 @@ function savePromptMessage(ctx, promptDetection, result, isFullScreenTui) {
|
|
|
670
739
|
}
|
|
671
740
|
return false;
|
|
672
741
|
}
|
|
742
|
+
// Issue #3881 (review P2-1): whether the frame's first row is the pane's —
|
|
743
|
+
// the capture was taken with `CACHE_MAX_CAPTURE_LINES` (`checkForResponse`).
|
|
744
|
+
const captureTop = (0, prompt_screen_reading_1.captureTopOf)(frame, tmux_capture_cache_1.CACHE_MAX_CAPTURE_LINES, cliToolId);
|
|
673
745
|
// Issue #571: Clean TUI decorations from Copilot prompt content before saving
|
|
674
746
|
let promptSaveContent = promptContent;
|
|
675
747
|
if (cliToolId === 'copilot') {
|
|
@@ -683,7 +755,13 @@ function savePromptMessage(ctx, promptDetection, result, isFullScreenTui) {
|
|
|
683
755
|
role: 'assistant',
|
|
684
756
|
content: promptSaveContent,
|
|
685
757
|
messageType: 'prompt',
|
|
686
|
-
|
|
758
|
+
// Issue #3881: with what the frame was read as — the kind, the live rows,
|
|
759
|
+
// the target's completeness — so the chat transcript and every later
|
|
760
|
+
// reader take it as stated instead of deciding it again from the strings.
|
|
761
|
+
// Review P2-1: the capture window says whether the frame's top is the
|
|
762
|
+
// pane's (`captureTop`, and `top-unknown` on a target that reached a cut top),
|
|
763
|
+
// as the Auto-Yes poller reads its own frame.
|
|
764
|
+
promptData: (0, prompt_screen_reading_1.promptDataForStorage)(cliToolId, frame, (0, prompt_screen_reading_1.withCaptureTopCompleteness)(promptDetection, captureTop), captureTop),
|
|
687
765
|
timestamp: new Date(),
|
|
688
766
|
cliToolId,
|
|
689
767
|
instanceId: resolvedInstanceId,
|
|
@@ -701,19 +779,19 @@ function savePromptMessage(ctx, promptDetection, result, isFullScreenTui) {
|
|
|
701
779
|
// Fire-and-forget — push is advisory and must never block/break the poller.
|
|
702
780
|
//
|
|
703
781
|
// Issue #1790: the wait is now named by #1786's episode rather than by the
|
|
704
|
-
// prompt text.
|
|
705
|
-
//
|
|
706
|
-
//
|
|
707
|
-
//
|
|
708
|
-
//
|
|
709
|
-
//
|
|
710
|
-
//
|
|
711
|
-
//
|
|
712
|
-
//
|
|
713
|
-
//
|
|
714
|
-
//
|
|
715
|
-
|
|
716
|
-
const promptWaitingSince =
|
|
782
|
+
// prompt text. Issue #3798: and by the episode's id, which the store gives
|
|
783
|
+
// a wait only when it opens or replaces one. So the observation is committed
|
|
784
|
+
// first and the notification raised with the id the commit settled on —
|
|
785
|
+
// the kept or rebound wait's, or the one just opened — inside
|
|
786
|
+
// `fanOutAfterCommit`, which holds the edge listener's own gate back until
|
|
787
|
+
// this fan-out is done: the notification that quotes the prompt's question
|
|
788
|
+
// still records the episode in the dedup first, and the listener (and
|
|
789
|
+
// #1788's WebSocket frame) agree with it about *which* wait this is — the
|
|
790
|
+
// same id to the gate's hold and suppression record, the dedup and the
|
|
791
|
+
// card's order. A commit that changed nothing (the episode moved since the
|
|
792
|
+
// plan) names no id, and the plan's `since` decides as before.
|
|
793
|
+
// No `await` from the plan to the commit.
|
|
794
|
+
const promptWaitingSince = plan.since ?? plan.at;
|
|
717
795
|
// Issue #1999: Auto-Yes is a declaration that this session's prompts are
|
|
718
796
|
// answered without a human, so notifying for one is telling the reader the
|
|
719
797
|
// opposite of the truth. Only the notification is gated — the episode
|
|
@@ -721,30 +799,27 @@ function savePromptMessage(ctx, promptDetection, result, isFullScreenTui) {
|
|
|
721
799
|
// reminder all see the wait exactly as they did before. The gate runs
|
|
722
800
|
// before the call rather than inside it because `shouldSendWaitingPush`
|
|
723
801
|
// records the episode the moment it decides to send.
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
instanceId,
|
|
728
|
-
waitingSince: promptWaitingSince,
|
|
729
|
-
})) {
|
|
730
|
-
void (0, push_1.notifyPushSubscribers)({
|
|
802
|
+
(0, waiting_push_notifier_1.fanOutAfterCommit)({ worktreeId, cliToolId, instanceId }, () => (0, waiting_episode_binding_1.commitWaitingObservation)(plan), (committed) => {
|
|
803
|
+
const waitingEpisodeId = committedEpisodeId(plan, committed);
|
|
804
|
+
if (!(0, prompt_push_gate_1.isPromptPushSuppressed)({
|
|
731
805
|
worktreeId,
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
agentName: resolvedInstanceId,
|
|
735
|
-
instanceId: resolvedInstanceId,
|
|
736
|
-
waitingKind: 'prompt',
|
|
806
|
+
cliToolId,
|
|
807
|
+
instanceId,
|
|
737
808
|
waitingSince: promptWaitingSince,
|
|
738
|
-
|
|
739
|
-
})
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
809
|
+
waitingEpisodeId,
|
|
810
|
+
})) {
|
|
811
|
+
void (0, push_1.notifyPushSubscribers)({
|
|
812
|
+
worktreeId,
|
|
813
|
+
worktreeName: worktree.name,
|
|
814
|
+
kind: 'prompt',
|
|
815
|
+
agentName: resolvedInstanceId,
|
|
816
|
+
instanceId: resolvedInstanceId,
|
|
817
|
+
waitingKind: 'prompt',
|
|
818
|
+
waitingSince: promptWaitingSince,
|
|
819
|
+
waitingEpisodeId,
|
|
820
|
+
excerpt: promptDetection.promptData?.question ?? promptSaveContent,
|
|
821
|
+
}).catch(() => { });
|
|
822
|
+
}
|
|
748
823
|
});
|
|
749
824
|
if (!isFullScreenTui) {
|
|
750
825
|
(0, response_poller_core_1.stopPolling)(worktreeId, cliToolId, instanceId);
|
|
@@ -1203,7 +1278,18 @@ async function recordCompletedResponse(ctx, turn, claudeMetadata, cleanedRespons
|
|
|
1203
1278
|
// API, and every later prompt would be folded into that stale episode and
|
|
1204
1279
|
// silently deduped. Nothing to close is a no-op, and no notification is
|
|
1205
1280
|
// raised for a closing edge.
|
|
1206
|
-
|
|
1281
|
+
//
|
|
1282
|
+
// Issue #3798: only the episode this tick started against — one that opened
|
|
1283
|
+
// or moved while the reader and the log ran is not this reply's to end.
|
|
1284
|
+
(0, waiting_episode_binding_1.observeWaiting)({
|
|
1285
|
+
worktreeId,
|
|
1286
|
+
cliToolId,
|
|
1287
|
+
instanceId,
|
|
1288
|
+
observer: 'response-checker',
|
|
1289
|
+
start: ctx.observationStart,
|
|
1290
|
+
reading: { kind: 'not-waiting' },
|
|
1291
|
+
frameCapturedAt: 0,
|
|
1292
|
+
});
|
|
1207
1293
|
// Web Push fan-out (Issue #1125): session completed (running → idle).
|
|
1208
1294
|
// Fire-and-forget — push is advisory and must never block/break the poller.
|
|
1209
1295
|
void (0, push_1.notifyPushSubscribers)({
|
|
@@ -1256,6 +1342,8 @@ async function checkForResponse(worktreeId, cliToolId, instanceId) {
|
|
|
1256
1342
|
instanceId,
|
|
1257
1343
|
resolvedInstanceId,
|
|
1258
1344
|
pollerKey,
|
|
1345
|
+
// Issue #3798: before the tick's first `await`.
|
|
1346
|
+
observationStart: (0, waiting_episode_binding_1.startWaitingObservation)(worktreeId, cliToolId, instanceId),
|
|
1259
1347
|
};
|
|
1260
1348
|
// Check if CLI tool session is running
|
|
1261
1349
|
const running = await (0, cli_session_1.isSessionRunning)(worktreeId, cliToolId, instanceId);
|
|
@@ -1320,7 +1408,9 @@ async function checkForResponse(worktreeId, cliToolId, instanceId) {
|
|
|
1320
1408
|
// Capture current output. The requested width IS the capture window, so it is
|
|
1321
1409
|
// taken from the same constant extractResponse() measures saturation against
|
|
1322
1410
|
// (Issue #1670) — a literal here would silently decouple the two.
|
|
1323
|
-
|
|
1411
|
+
// Issue #3798: dated by where that frame came from — from the cache, it may
|
|
1412
|
+
// be older than this tick.
|
|
1413
|
+
const { frame: output, frameTime } = await (0, waiting_episode_binding_1.captureObservedFrame)(() => (0, cli_session_1.captureSessionOutput)(worktreeId, cliToolId, tmux_capture_cache_1.CACHE_MAX_CAPTURE_LINES, instanceId));
|
|
1324
1414
|
// Issue #3705: there is no `await` from here to the transcript reader
|
|
1325
1415
|
// inside the save path, so this one answer covers every write in between —
|
|
1326
1416
|
// the fault notifier, the TUI accumulator, the prompt sweep, the skip
|
|
@@ -1360,7 +1450,7 @@ async function checkForResponse(worktreeId, cliToolId, instanceId) {
|
|
|
1360
1450
|
if (owns)
|
|
1361
1451
|
(0, response_dedup_1.resetDuplicateResponseSkipStreak)(pollerKey);
|
|
1362
1452
|
// Asks for itself (#3701), before the prompt dedup.
|
|
1363
|
-
return savePromptMessage(ctx, promptDetection, result, isFullScreenTui);
|
|
1453
|
+
return savePromptMessage(ctx, promptDetection, result, isFullScreenTui, frameTime, output);
|
|
1364
1454
|
}
|
|
1365
1455
|
// Issue #3538: a finished frame without a live prompt ends the run of
|
|
1366
1456
|
// duplicate prompt ticks, as an unfinished one does in `extractCompletedTurn`.
|
|
@@ -665,7 +665,7 @@ async function recaptureAfterKeys(sessionName) {
|
|
|
665
665
|
* @throws {MultiSelectAnswerRejectedError} whenever the question was not
|
|
666
666
|
* committed; `keysSent` says whether the pane was touched.
|
|
667
667
|
*/
|
|
668
|
-
async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted, stillCurrent) {
|
|
668
|
+
async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted, stillCurrent, touch) {
|
|
669
669
|
const cursor = promptData.options.find((option) => option.isDefault === true);
|
|
670
670
|
if (cursor === undefined) {
|
|
671
671
|
throw new MultiSelectAnswerRejectedError('cursor-unknown', false, wanted);
|
|
@@ -679,7 +679,7 @@ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted,
|
|
|
679
679
|
...current.filter((n) => !wanted.includes(n)),
|
|
680
680
|
].sort((a, b) => a - b);
|
|
681
681
|
if (toggles.length > 0) {
|
|
682
|
-
await sendSpecialKeysWhileCurrent(sessionName, toggles.map(String), stillCurrent);
|
|
682
|
+
await sendSpecialKeysWhileCurrent(sessionName, toggles.map(String), stillCurrent, touch);
|
|
683
683
|
}
|
|
684
684
|
const keysSent = toggles.length > 0;
|
|
685
685
|
// 2. Read the screen back and refuse unless it is the same question with
|
|
@@ -712,7 +712,7 @@ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted,
|
|
|
712
712
|
if (cursorNow === undefined) {
|
|
713
713
|
throw new MultiSelectAnswerRejectedError('cursor-unknown', keysSent, wanted);
|
|
714
714
|
}
|
|
715
|
-
await sendSpecialKeysWhileCurrent(sessionName, [...downKeys(verified.options.length - cursorNow.number + 1), 'Enter'], stillCurrent);
|
|
715
|
+
await sendSpecialKeysWhileCurrent(sessionName, [...downKeys(verified.options.length - cursorNow.number + 1), 'Enter'], stillCurrent, touch);
|
|
716
716
|
// 4. The second stage. `Submit` opens the Review page and the answer is sent
|
|
717
717
|
// from there; `Next` advances to the following question, which IS the
|
|
718
718
|
// commit for this one (its tab turns `✔`).
|
|
@@ -728,7 +728,7 @@ async function sendCommandCodeMultiSelectAnswer(sessionName, promptData, wanted,
|
|
|
728
728
|
if (review.hasUnansweredWarning) {
|
|
729
729
|
throw new MultiSelectAnswerRejectedError('review-unanswered', true, wanted);
|
|
730
730
|
}
|
|
731
|
-
await sendSpecialKeysWhileCurrent(sessionName, ['Enter'], stillCurrent);
|
|
731
|
+
await sendSpecialKeysWhileCurrent(sessionName, ['Enter'], stillCurrent, touch);
|
|
732
732
|
return;
|
|
733
733
|
}
|
|
734
734
|
const next = (0, dialog_1.readCommandCodeQuestionDialog)(afterConfirm);
|
|
@@ -756,6 +756,50 @@ class PromptAnswerAbortedError extends Error {
|
|
|
756
756
|
}
|
|
757
757
|
}
|
|
758
758
|
exports.PromptAnswerAbortedError = PromptAnswerAbortedError;
|
|
759
|
+
/**
|
|
760
|
+
* What the tmux call that failed did (Issue #3880), when the error came from
|
|
761
|
+
* the transport (`TmuxSendError`, by name: test doubles of `./tmux/tmux` need
|
|
762
|
+
* not export the class); null for any other error.
|
|
763
|
+
*/
|
|
764
|
+
function transportDeliveryOf(error) {
|
|
765
|
+
if (!(error instanceof Error) || error.name !== 'TmuxSendError')
|
|
766
|
+
return null;
|
|
767
|
+
const delivery = error.delivery;
|
|
768
|
+
return delivery === 'not-started' || delivery === 'indeterminate' ? delivery : null;
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* A failure after a key reached the pane says so (Issue #3839): `keysSent: true`
|
|
772
|
+
* is put on it, as on {@link PromptAnswerAbortedError}, so Auto-Yes does not
|
|
773
|
+
* type the answer again over what is already there. An error that already
|
|
774
|
+
* names `keysSent` (the refusals and the stop above) keeps its own word, and a
|
|
775
|
+
* failure before any key is left as it was.
|
|
776
|
+
*
|
|
777
|
+
* Issue #3880: a transport failure also gets `answerDelivery` ({@link AnswerDelivery};
|
|
778
|
+
* the tmux error's own `delivery` is that one call's).
|
|
779
|
+
* `indeterminate` — the tmux call ended without an exit status, and its key may
|
|
780
|
+
* be on the pane — is NOT `keysSent: true` (no key is known to be there; the
|
|
781
|
+
* ledger counts it `failed`, #3820) but Auto-Yes holds it all the same. A
|
|
782
|
+
* transport refusal before any key is `keysSent: false`: known not sent, free
|
|
783
|
+
* to be sent again.
|
|
784
|
+
*/
|
|
785
|
+
function withKeysSent(error, touch) {
|
|
786
|
+
if (!(error instanceof Error))
|
|
787
|
+
return error;
|
|
788
|
+
const transport = transportDeliveryOf(error);
|
|
789
|
+
if (transport !== null) {
|
|
790
|
+
const answerDelivery = transport === 'indeterminate' ? 'indeterminate' : touch.touched ? 'delivered' : 'not-started';
|
|
791
|
+
Object.assign(error, { answerDelivery });
|
|
792
|
+
}
|
|
793
|
+
if ('keysSent' in error)
|
|
794
|
+
return error;
|
|
795
|
+
if (touch.touched) {
|
|
796
|
+
Object.assign(error, { keysSent: true });
|
|
797
|
+
}
|
|
798
|
+
else if (transport === 'not-started') {
|
|
799
|
+
Object.assign(error, { keysSent: false });
|
|
800
|
+
}
|
|
801
|
+
return error;
|
|
802
|
+
}
|
|
759
803
|
/** Stop here when the caller's `stillCurrent` says no (Issue #3706). */
|
|
760
804
|
function assertStillCurrent(stillCurrent, keysSent) {
|
|
761
805
|
if (stillCurrent && !stillCurrent())
|
|
@@ -766,13 +810,32 @@ function assertStillCurrent(stillCurrent, keysSent) {
|
|
|
766
810
|
* gave one (Issue #3706). Without it the call is exactly the old two-argument
|
|
767
811
|
* one, so manual answers and every other caller send as before.
|
|
768
812
|
*/
|
|
769
|
-
async function sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent) {
|
|
813
|
+
async function sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent, touch) {
|
|
770
814
|
if (!stillCurrent) {
|
|
771
|
-
|
|
815
|
+
try {
|
|
816
|
+
await (0, tmux_1.sendSpecialKeys)(sessionName, keys);
|
|
817
|
+
}
|
|
818
|
+
catch (error) {
|
|
819
|
+
// Issue #3880: without `shouldContinue` the count comes from the error.
|
|
820
|
+
if (touch && keysDeliveredOf(error) > 0)
|
|
821
|
+
touch.touched = true;
|
|
822
|
+
throw error;
|
|
823
|
+
}
|
|
824
|
+
if (touch && keys.length > 0)
|
|
825
|
+
touch.touched = true;
|
|
772
826
|
return;
|
|
773
827
|
}
|
|
828
|
+
// Issue #3839: `shouldContinue` is asked after each key but the last, so the
|
|
829
|
+
// times it was asked are the keys known to have reached the pane when a
|
|
830
|
+
// later one fails.
|
|
831
|
+
let delivered = 0;
|
|
774
832
|
try {
|
|
775
|
-
await (0, tmux_1.sendSpecialKeys)(sessionName, keys, {
|
|
833
|
+
await (0, tmux_1.sendSpecialKeys)(sessionName, keys, {
|
|
834
|
+
shouldContinue: () => {
|
|
835
|
+
delivered++;
|
|
836
|
+
return stillCurrent();
|
|
837
|
+
},
|
|
838
|
+
});
|
|
776
839
|
}
|
|
777
840
|
catch (error) {
|
|
778
841
|
// By name rather than `instanceof`: test doubles of `./tmux/tmux` need not
|
|
@@ -780,8 +843,22 @@ async function sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent) {
|
|
|
780
843
|
if (error instanceof Error && error.name === 'SpecialKeysAbortedError') {
|
|
781
844
|
throw new PromptAnswerAbortedError(true);
|
|
782
845
|
}
|
|
846
|
+
if (touch && Math.max(delivered, keysDeliveredOf(error)) > 0)
|
|
847
|
+
touch.touched = true;
|
|
783
848
|
throw error;
|
|
784
849
|
}
|
|
850
|
+
if (touch && keys.length > 0)
|
|
851
|
+
touch.touched = true;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* The keys a failed `sendSpecialKeys` says tmux took before the one that
|
|
855
|
+
* failed (Issue #3880, `TmuxSendError.keysDelivered`); 0 when it says none.
|
|
856
|
+
*/
|
|
857
|
+
function keysDeliveredOf(error) {
|
|
858
|
+
if (!(error instanceof Error) || error.name !== 'TmuxSendError')
|
|
859
|
+
return 0;
|
|
860
|
+
const count = error.keysDelivered;
|
|
861
|
+
return typeof count === 'number' && Number.isFinite(count) && count > 0 ? count : 0;
|
|
785
862
|
}
|
|
786
863
|
/**
|
|
787
864
|
* Send an answer to a tmux session, using cursor-key navigation for
|
|
@@ -791,8 +868,22 @@ async function sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent) {
|
|
|
791
868
|
* This function unifies the logic previously duplicated in:
|
|
792
869
|
* - src/app/api/worktrees/[id]/prompt-response/route.ts (L114-187)
|
|
793
870
|
* - src/lib/auto-yes-manager.ts (L340-399)
|
|
871
|
+
*
|
|
872
|
+
* A failure after a key of the answer reached the pane carries `keysSent: true`
|
|
873
|
+
* (Issue #3839), and a transport failure its `answerDelivery` (Issue #3880);
|
|
874
|
+
* see {@link withKeysSent}.
|
|
794
875
|
*/
|
|
795
876
|
async function sendPromptAnswer(params) {
|
|
877
|
+
const touch = { touched: false };
|
|
878
|
+
try {
|
|
879
|
+
await sendPromptAnswerKeys(params, touch);
|
|
880
|
+
}
|
|
881
|
+
catch (error) {
|
|
882
|
+
throw withKeysSent(error, touch);
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
/** {@link sendPromptAnswer}, noting in `touch` each key that reached the pane. */
|
|
886
|
+
async function sendPromptAnswerKeys(params, touch) {
|
|
796
887
|
const { sessionName, answer, cliToolId, promptData, fallbackPromptType, fallbackDefaultOptionNumber, stillCurrent } = params;
|
|
797
888
|
// Issue #2755: Command Code's checkbox question, before every guard below.
|
|
798
889
|
// Its answer is a SET (`"1,3"`), which none of them can read — `/^\d+$/` is
|
|
@@ -803,7 +894,7 @@ async function sendPromptAnswer(params) {
|
|
|
803
894
|
// a two-stage confirm, not a digit and an Enter.
|
|
804
895
|
const multiSelect = readMultiSelectRequest(params);
|
|
805
896
|
if (multiSelect !== null) {
|
|
806
|
-
await sendCommandCodeMultiSelectAnswer(sessionName, multiSelect.promptData, multiSelect.wanted, stillCurrent);
|
|
897
|
+
await sendCommandCodeMultiSelectAnswer(sessionName, multiSelect.promptData, multiSelect.wanted, stillCurrent, touch);
|
|
807
898
|
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
808
899
|
return;
|
|
809
900
|
}
|
|
@@ -874,7 +965,7 @@ async function sendPromptAnswer(params) {
|
|
|
874
965
|
keys.push(...buildNavigationKeys(downToNext));
|
|
875
966
|
// 4. Enter to submit
|
|
876
967
|
keys.push('Enter');
|
|
877
|
-
await sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent);
|
|
968
|
+
await sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent, touch);
|
|
878
969
|
}
|
|
879
970
|
else {
|
|
880
971
|
// Single-select: navigate and Enter to select
|
|
@@ -892,12 +983,15 @@ async function sendPromptAnswer(params) {
|
|
|
892
983
|
const keys = (isAskUserQuestionPicker && offset === 0)
|
|
893
984
|
? ['Down', 'Up', 'Enter']
|
|
894
985
|
: [...navigationKeys, 'Enter'];
|
|
895
|
-
await sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent);
|
|
986
|
+
await sendSpecialKeysWhileCurrent(sessionName, keys, stillCurrent, touch);
|
|
896
987
|
}
|
|
897
988
|
}
|
|
898
989
|
else {
|
|
899
990
|
// Standard CLI prompt: send text + Enter (y/n, Approve?, etc.)
|
|
900
991
|
await (0, tmux_1.sendKeys)(sessionName, answer, false);
|
|
992
|
+
// Issue #3839: the text is on the pane; a failed Enter after it says so.
|
|
993
|
+
if (answer !== '')
|
|
994
|
+
touch.touched = true;
|
|
901
995
|
// Issue #616: Resolve submitMode and determine whether to suppress Enter
|
|
902
996
|
const resolvedSubmitMode = resolveSubmitMode(params, dialog);
|
|
903
997
|
if (!shouldSuppressEnter(params, resolvedSubmitMode, dialog)) {
|
|
@@ -60,15 +60,28 @@ const waitingSent = (0, global_state_1.getOrInitGlobal)('__waitingPushDedup', ()
|
|
|
60
60
|
* - the escalation → allowed exactly once per episode;
|
|
61
61
|
* - a new episode (the wait ended and another began) → sent again, even if the
|
|
62
62
|
* prompt text and the elapsed time are identical.
|
|
63
|
+
*
|
|
64
|
+
* Issue #3798: "the same episode" is the mixed rule `prompt-push-gate` holds
|
|
65
|
+
* its hold by — both ids present and equal, or one absent and the `since`s
|
|
66
|
+
* equal. Kept inline rather than imported: this module stays a leaf.
|
|
63
67
|
*/
|
|
64
68
|
function shouldSendWaitingPush(event) {
|
|
65
69
|
const key = `${event.worktreeId}::${event.instanceId}`;
|
|
66
70
|
const escalated = event.escalated === true;
|
|
71
|
+
const episodeId = event.episodeId ?? undefined;
|
|
67
72
|
const prev = waitingSent.get(key);
|
|
68
|
-
|
|
73
|
+
const sameEpisode = prev !== undefined &&
|
|
74
|
+
(prev.episodeId !== undefined && episodeId !== undefined
|
|
75
|
+
? prev.episodeId === episodeId
|
|
76
|
+
: prev.since === event.since);
|
|
77
|
+
if (prev && sameEpisode && (prev.escalated || !escalated)) {
|
|
78
|
+
// An id-less producer recorded this wait first; it is named now.
|
|
79
|
+
if (prev.episodeId === undefined && episodeId !== undefined)
|
|
80
|
+
prev.episodeId = episodeId;
|
|
69
81
|
return false;
|
|
70
82
|
}
|
|
71
|
-
|
|
83
|
+
const recordedId = episodeId ?? (sameEpisode ? prev?.episodeId : undefined);
|
|
84
|
+
waitingSent.set(key, { since: event.since, ...(recordedId !== undefined ? { episodeId: recordedId } : {}), escalated });
|
|
72
85
|
return true;
|
|
73
86
|
}
|
|
74
87
|
/** Clear the episode-scoped state (for tests). */
|