commandmate 0.49.1 → 0.49.2
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 +128 -132
- package/.next/app-path-routes-manifest.json +22 -22
- 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/release-notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +2 -2
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route.js +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/route_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.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js +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 +2 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/logs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page.js +1 -1
- package/.next/server/app/review/page_client-reference-manifest.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 +2 -2
- 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 +22 -22
- package/.next/server/chunks/1062.js +1 -0
- package/.next/server/chunks/110.js +1 -0
- package/.next/server/chunks/1501.js +5 -4
- package/.next/server/chunks/1656.js +2 -2
- package/.next/server/chunks/1957.js +2 -0
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/2897.js +1 -0
- package/.next/server/chunks/3417.js +1 -0
- package/.next/server/chunks/3505.js +1 -1
- package/.next/server/chunks/3756.js +1 -0
- package/.next/server/chunks/3801.js +3 -3
- package/.next/server/chunks/4911.js +1 -0
- package/.next/server/chunks/4936.js +1 -0
- package/.next/server/chunks/5209.js +2 -1
- package/.next/server/chunks/5354.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/7023.js +2 -2
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8581.js +15 -15
- package/.next/server/chunks/8728.js +2 -2
- package/.next/server/chunks/8782.js +1 -1
- package/.next/server/chunks/9390.js +1 -1
- package/.next/server/chunks/9584.js +1 -1
- 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/{2407-675ba6b21844dc3b.js → 2407-07a237575e1ceb9e.js} +1 -1
- package/.next/static/chunks/3931-61ad1a4fc0208d0e.js +1 -0
- package/.next/static/chunks/5794-7975b8e51e731b19.js +1 -0
- package/.next/static/chunks/6966-d8dc6032410ffaba.js +1 -0
- package/.next/static/chunks/7197-ed3b3d99ac3bd450.js +1 -0
- package/.next/static/chunks/7636-a48cf0f7110250c5.js +1 -0
- package/.next/static/chunks/app/layout-4f64316957b0a8e5.js +1 -0
- package/.next/static/chunks/app/more/page-ff5af5ca48774c89.js +1 -0
- package/.next/static/chunks/app/page-b4863bfe0452e09d.js +1 -0
- package/.next/static/chunks/app/review/page-ff3efb96fdf9bb4b.js +1 -0
- package/.next/static/chunks/app/sessions/{page-890fd50ec9739973.js → page-c6eb7c02db2f4c80.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/{page-f6d3ab8185d93aae.js → page-33afc6aa96289fb0.js} +1 -1
- package/.next/trace +13 -13
- package/dist/cli/commands/ask.d.ts.map +1 -1
- package/dist/cli/commands/ask.js +56 -5
- package/dist/cli/commands/attach.d.ts +4 -1
- package/dist/cli/commands/attach.d.ts.map +1 -1
- package/dist/cli/commands/attach.js +19 -7
- package/dist/cli/commands/command-target.d.ts +7 -0
- package/dist/cli/commands/command-target.d.ts.map +1 -1
- package/dist/cli/commands/command-target.js +10 -0
- package/dist/cli/commands/instances.d.ts.map +1 -1
- package/dist/cli/commands/instances.js +38 -2
- package/dist/cli/commands/message-dispatch.d.ts +17 -3
- package/dist/cli/commands/message-dispatch.d.ts.map +1 -1
- package/dist/cli/commands/message-dispatch.js +14 -8
- package/dist/cli/commands/relays.d.ts +2 -1
- package/dist/cli/commands/relays.d.ts.map +1 -1
- package/dist/cli/commands/relays.js +4 -3
- package/dist/cli/commands/respond-strict.d.ts.map +1 -1
- package/dist/cli/commands/respond-strict.js +22 -5
- package/dist/cli/commands/respond.d.ts +2 -2
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +40 -37
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +8 -4
- package/dist/cli/commands/wait-instance.d.ts +9 -1
- package/dist/cli/commands/wait-instance.d.ts.map +1 -1
- package/dist/cli/commands/wait-instance.js +15 -0
- package/dist/cli/commands/wait-poll-state.d.ts +18 -0
- package/dist/cli/commands/wait-poll-state.d.ts.map +1 -1
- package/dist/cli/commands/wait-verify.d.ts +2 -1
- package/dist/cli/commands/wait-verify.d.ts.map +1 -1
- package/dist/cli/commands/wait-verify.js +5 -1
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +37 -13
- package/dist/cli/commands/whoami.d.ts.map +1 -1
- package/dist/cli/commands/whoami.js +3 -1
- package/dist/cli/docs/agent-operations.d.ts +1 -1
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +1 -0
- package/dist/cli/types/api-responses.d.ts +3 -1
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/utils/api-client.d.ts +55 -1
- package/dist/cli/utils/api-client.d.ts.map +1 -1
- package/dist/cli/utils/api-client.js +220 -18
- package/dist/cli/utils/follow-up-command.d.ts +38 -0
- package/dist/cli/utils/follow-up-command.d.ts.map +1 -0
- package/dist/cli/utils/follow-up-command.js +57 -0
- package/dist/cli/utils/reply-ledger.d.ts +1 -1
- package/dist/cli/utils/reply-ledger.d.ts.map +1 -1
- package/dist/cli/utils/reply-ledger.js +7 -2
- package/dist/cli/utils/server-capabilities.d.ts +18 -0
- package/dist/cli/utils/server-capabilities.d.ts.map +1 -1
- package/dist/cli/utils/server-capabilities.js +36 -3
- package/dist/cli/utils/session-target.d.ts +1 -1
- package/dist/cli/utils/session-target.d.ts.map +1 -1
- package/dist/cli/utils/session-target.js +3 -0
- package/dist/cli/utils/verify-runner.d.ts +7 -0
- package/dist/cli/utils/verify-runner.d.ts.map +1 -1
- package/dist/cli/utils/verify-runner.js +51 -15
- package/dist/lib/cli-tools/session-name.d.ts.map +1 -1
- package/dist/lib/cli-tools/session-name.js +11 -3
- package/dist/lib/session/send-attempt-types.d.ts +25 -0
- package/dist/lib/session/send-attempt-types.d.ts.map +1 -1
- package/dist/lib/session/send-attempt-types.js +10 -1
- package/dist/lib/verification/session-kill-ledger.d.ts +110 -0
- package/dist/lib/verification/session-kill-ledger.d.ts.map +1 -0
- package/dist/lib/verification/session-kill-ledger.js +174 -0
- package/dist/server/locales/en/worktree.json +2 -0
- package/dist/server/locales/ja/worktree.json +2 -0
- package/dist/server/src/config/cli-tool-timing-config.js +1 -7
- package/dist/server/src/lib/auto-yes-poller.js +5 -1
- package/dist/server/src/lib/cli-tools/antigravity.js +5 -2
- package/dist/server/src/lib/cli-tools/base.js +39 -0
- package/dist/server/src/lib/cli-tools/codex.js +7 -4
- package/dist/server/src/lib/cli-tools/command-code.js +7 -3
- package/dist/server/src/lib/cli-tools/copilot.js +5 -3
- package/dist/server/src/lib/cli-tools/gemini.js +10 -2
- package/dist/server/src/lib/cli-tools/launch-keys.js +39 -0
- package/dist/server/src/lib/cli-tools/opencode-v2.js +6 -2
- package/dist/server/src/lib/cli-tools/opencode.js +5 -2
- package/dist/server/src/lib/cli-tools/session-name.js +11 -3
- package/dist/server/src/lib/cli-tools/submit-composer-read.js +16 -6
- package/dist/server/src/lib/cli-tools/submit-verified-sender.js +164 -7
- package/dist/server/src/lib/cli-tools/vibe-local.js +4 -2
- package/dist/server/src/lib/db/db-migration-path.js +63 -2
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +5 -4
- package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +2 -3
- package/dist/server/src/lib/prompt-answer-errors.js +76 -2
- package/dist/server/src/lib/session/agent-event-state.js +4 -0
- package/dist/server/src/lib/session/agent-session-lifecycle.js +6 -1
- package/dist/server/src/lib/session/claude-session.js +22 -6
- package/dist/server/src/lib/session/current-output-builder.js +5 -3
- package/dist/server/src/lib/session/current-output-history-writers.js +1 -1
- package/dist/server/src/lib/session/prompt-submit-receipt.js +155 -0
- package/dist/server/src/lib/session/prompt-waiting-guard.js +10 -3
- package/dist/server/src/lib/session/send-attempt-state.js +48 -0
- package/dist/server/src/lib/session/send-attempt-types.js +10 -1
- package/dist/server/src/lib/session/send-user-message.js +5 -4
- package/dist/server/src/lib/session/session-launch-flight.js +243 -0
- package/dist/server/src/lib/session/session-starting-state.js +40 -4
- package/dist/server/src/lib/session/structured-prompt.js +12 -9
- package/dist/server/src/lib/session/waiting-episode-binding.js +4 -2
- package/dist/server/src/lib/session-cleanup.js +32 -0
- package/dist/server/src/lib/session-key-sender.js +0 -27
- package/dist/server/src/lib/verification/env-clean-gate.js +129 -0
- package/dist/server/src/lib/verification/env-snapshot.js +11 -2
- package/dist/server/src/lib/verification/session-kill-ledger.js +174 -0
- package/package.json +5 -1
- package/release-notes/0.49.2.json +49 -0
- package/.next/server/chunks/3773.js +0 -1
- package/.next/server/chunks/5775.js +0 -1
- package/.next/server/chunks/7604.js +0 -2
- package/.next/static/chunks/3931-1a1abab16248f14d.js +0 -1
- package/.next/static/chunks/4768-ad6f82f034f21eae.js +0 -1
- package/.next/static/chunks/5794-80ac3f06f098ea29.js +0 -1
- package/.next/static/chunks/6654-f3534f35f16644bc.js +0 -1
- package/.next/static/chunks/7665-e9ef6e0a85b9fa49.js +0 -1
- package/.next/static/chunks/8606-ce17ffa77f39608e.js +0 -1
- package/.next/static/chunks/app/layout-8bfac4724277b47f.js +0 -1
- package/.next/static/chunks/app/more/page-87c84987b2765213.js +0 -1
- package/.next/static/chunks/app/page-1b820c421db48c2c.js +0 -1
- package/.next/static/chunks/app/review/page-e2fd4a590646a2d8.js +0 -1
- /package/.next/static/{fqfSDqQMweROeHUzOt_m1 → yGatWDsS532awSs51kXyd}/_buildManifest.js +0 -0
- /package/.next/static/{fqfSDqQMweROeHUzOt_m1 → yGatWDsS532awSs51kXyd}/_ssgManifest.js +0 -0
|
@@ -31,6 +31,8 @@ const terminal_keys_1 = require("../../types/terminal-keys");
|
|
|
31
31
|
const cli_tool_timing_config_1 = require("../../config/cli-tool-timing-config");
|
|
32
32
|
const tmux_pane_config_1 = require("../../config/tmux-pane-config");
|
|
33
33
|
const session_starting_state_1 = require("../session/session-starting-state");
|
|
34
|
+
const session_launch_flight_1 = require("../session/session-launch-flight");
|
|
35
|
+
const launch_keys_1 = require("./launch-keys");
|
|
34
36
|
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
35
37
|
const logger = (0, logger_1.createLogger)('cli-tools/base');
|
|
36
38
|
/**
|
|
@@ -221,6 +223,27 @@ class BaseCLITool {
|
|
|
221
223
|
* @throws Whatever {@link launchSession} threw — unchanged, after reporting
|
|
222
224
|
*/
|
|
223
225
|
async startSession(worktreeId, worktreePath, instanceId, model) {
|
|
226
|
+
// Issue #3981: one launch per session (`session-launch-flight`). A second
|
|
227
|
+
// request joins the launch in progress instead of starting its own — whose
|
|
228
|
+
// reuse branch would kill the first one's half-launched pane — and a caller
|
|
229
|
+
// that holds the input lock is refused rather than made to wait (R1). A
|
|
230
|
+
// name that does not validate is left to `launchSession` to refuse, and
|
|
231
|
+
// reported as before. A start that asks for a model the launch in
|
|
232
|
+
// progress is not starting with is refused instead of joining it (#2771).
|
|
233
|
+
let sessionName = null;
|
|
234
|
+
try {
|
|
235
|
+
sessionName = this.getSessionName(worktreeId, instanceId);
|
|
236
|
+
}
|
|
237
|
+
catch {
|
|
238
|
+
// fall through: launchSession throws on it, inside the reporting below
|
|
239
|
+
}
|
|
240
|
+
const launch = () => this.startSessionOnce(worktreeId, worktreePath, instanceId, model);
|
|
241
|
+
if (sessionName === null)
|
|
242
|
+
return launch();
|
|
243
|
+
return (0, session_launch_flight_1.runSessionLaunch)(sessionName, this.name, launch, { cliToolId: this.id, model });
|
|
244
|
+
}
|
|
245
|
+
/** {@link startSession}'s body: one launch, its failure reported once. */
|
|
246
|
+
async startSessionOnce(worktreeId, worktreePath, instanceId, model) {
|
|
224
247
|
// Issue #3195: this launch's "starting" record is written under this token
|
|
225
248
|
// (see `session-starting-state`), so the `finally` below clears this
|
|
226
249
|
// launch's record and never a later launch's of the same instance.
|
|
@@ -615,6 +638,11 @@ class BaseCLITool {
|
|
|
615
638
|
*/
|
|
616
639
|
async requireSession(label, worktreeId, instanceId, options) {
|
|
617
640
|
const sessionName = this.getSessionName(worktreeId, instanceId);
|
|
641
|
+
// Issue #3981: a pane another request is still launching reads as
|
|
642
|
+
// "exists, tool not live" and would be relaunched or typed into. Wait for
|
|
643
|
+
// that launch first — or, holding the input lock (claude and codex send
|
|
644
|
+
// under it), refuse with nothing typed (R1).
|
|
645
|
+
await (0, session_launch_flight_1.settleSessionLaunch)(sessionName, this.name);
|
|
618
646
|
const exists = await (0, tmux_1.hasSession)(sessionName);
|
|
619
647
|
if (!exists) {
|
|
620
648
|
throw new Error(`${label} session ${sessionName} does not exist. Start the session first.`);
|
|
@@ -683,6 +711,17 @@ class BaseCLITool {
|
|
|
683
711
|
}
|
|
684
712
|
return { sessionName, exists, live: false };
|
|
685
713
|
}
|
|
714
|
+
/**
|
|
715
|
+
* Type a launch's keys — its launch line, and anything that has to go in
|
|
716
|
+
* before it — in one `exclusive` turn of the instance input lock (Issue
|
|
717
|
+
* #3981, `./launch-keys`). The waits after the keys stay outside the lock.
|
|
718
|
+
*
|
|
719
|
+
* @param sessionName - tmux session name
|
|
720
|
+
* @param steps - Lines typed with Enter, or steps that type their own keys
|
|
721
|
+
*/
|
|
722
|
+
async typeLaunchLines(sessionName, steps) {
|
|
723
|
+
await (0, launch_keys_1.typeLaunchLines)(sessionName, steps);
|
|
724
|
+
}
|
|
686
725
|
/**
|
|
687
726
|
* Create the tmux session a launch types into, then wait
|
|
688
727
|
* {@link TUI_SESSION_CREATE_WAIT_MS} for it. Creation path only: on the #2070
|
|
@@ -244,11 +244,13 @@ class CodexTool extends base_1.BaseCLITool {
|
|
|
244
244
|
// as the new one's.
|
|
245
245
|
const relaunchIntoSamePane = async () => {
|
|
246
246
|
(0, agent_session_lifecycle_1.beginAgentSession)({ worktreeId, cliToolId: sources_1.CODEX_CLI_TOOL_ID, instanceId });
|
|
247
|
-
|
|
247
|
+
// Issue #3981: one writer's turn, as the first launch line below.
|
|
248
|
+
await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
|
|
248
249
|
await new Promise((resolve) => setTimeout(resolve, CODEX_INIT_WAIT_MS));
|
|
249
250
|
};
|
|
250
|
-
// Start Codex CLI in interactive mode
|
|
251
|
-
|
|
251
|
+
// Start Codex CLI in interactive mode. Issue #3981: in one writer's turn
|
|
252
|
+
// of the input lock (joined when this launch runs inside a send's).
|
|
253
|
+
await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
|
|
252
254
|
// Wait for Codex to initialize
|
|
253
255
|
await new Promise((resolve) => setTimeout(resolve, CODEX_INIT_WAIT_MS));
|
|
254
256
|
// Poll until Codex interactive prompt is ready
|
|
@@ -771,7 +773,8 @@ class CodexTool extends base_1.BaseCLITool {
|
|
|
771
773
|
}
|
|
772
774
|
catch (error) {
|
|
773
775
|
const errorMessage = (0, errors_1.getErrorMessage)(error);
|
|
774
|
-
|
|
776
|
+
// Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
|
|
777
|
+
throw new Error(`Failed to send message to Codex: ${errorMessage}`, { cause: error });
|
|
775
778
|
}
|
|
776
779
|
}
|
|
777
780
|
/**
|
|
@@ -238,11 +238,14 @@ class CommandCodeTool extends base_1.BaseCLITool {
|
|
|
238
238
|
// shared TMUX_HISTORY_LIMIT default (Issue #1624).
|
|
239
239
|
await this.createLaunchPane(sessionName, worktreePath);
|
|
240
240
|
}
|
|
241
|
-
|
|
241
|
+
// Issue #3981: in one writer's turn of the input lock; the readiness
|
|
242
|
+
// wait below stays outside it.
|
|
243
|
+
const launchCommand = buildCommandCodeLaunchCommand({
|
|
242
244
|
target: { worktreeId, cliToolId: tool_id_1.COMMAND_CODE_CLI_TOOL_ID, instanceId },
|
|
243
245
|
executablePath: this.command,
|
|
244
246
|
worktreePath,
|
|
245
|
-
})
|
|
247
|
+
});
|
|
248
|
+
await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
|
|
246
249
|
await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.COMMAND_CODE_INIT_WAIT_MS));
|
|
247
250
|
await this.waitForReady(sessionName);
|
|
248
251
|
logger.info('started-command-code-session');
|
|
@@ -368,7 +371,8 @@ class CommandCodeTool extends base_1.BaseCLITool {
|
|
|
368
371
|
// Issue #3006: passed through unwrapped so its `code` reaches the route.
|
|
369
372
|
if ((0, session_start_error_1.isSessionStartTimeoutError)(error))
|
|
370
373
|
throw error;
|
|
371
|
-
|
|
374
|
+
// Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
|
|
375
|
+
const wrapped = new Error(`Failed to send message to Command Code: ${(0, errors_1.getErrorMessage)(error)}`, { cause: error });
|
|
372
376
|
// Issue #3772: the plan review refusal comes before the body; keep its code.
|
|
373
377
|
if (error?.code === send_attempt_types_1.PLAN_REVIEW_SEND_REFUSED_CODE) {
|
|
374
378
|
throw Object.assign(wrapped, { code: send_attempt_types_1.PLAN_REVIEW_SEND_REFUSED_CODE });
|
|
@@ -380,8 +380,9 @@ class CopilotTool extends base_1.BaseCLITool {
|
|
|
380
380
|
// leaves it (`cli-tools/launch-window`).
|
|
381
381
|
(0, launch_window_1.beginLaunchWindow)(sessionName);
|
|
382
382
|
try {
|
|
383
|
-
// Start Copilot CLI in interactive mode
|
|
384
|
-
|
|
383
|
+
// Start Copilot CLI in interactive mode. Issue #3981: in one writer's
|
|
384
|
+
// turn of the input lock; the readiness wait below stays outside it.
|
|
385
|
+
await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
|
|
385
386
|
// Issue #1907: no blind sleep before this. The 4-second one that used to
|
|
386
387
|
// sit here was a guess at how long copilot takes to paint (measured on
|
|
387
388
|
// 1.0.80: banner at ~1.3 s, folder-trust dialog at ~2.5 s), and it was
|
|
@@ -742,7 +743,8 @@ class CopilotTool extends base_1.BaseCLITool {
|
|
|
742
743
|
}
|
|
743
744
|
catch (error) {
|
|
744
745
|
const errorMessage = (0, errors_1.getErrorMessage)(error);
|
|
745
|
-
|
|
746
|
+
// Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
|
|
747
|
+
throw new Error(`Failed to send message to Copilot: ${errorMessage}`, { cause: error });
|
|
746
748
|
}
|
|
747
749
|
}
|
|
748
750
|
/**
|
|
@@ -111,7 +111,8 @@ class GeminiTool extends base_1.BaseCLITool {
|
|
|
111
111
|
// already in the pane is not run as part of it. Only the keys: the
|
|
112
112
|
// waits below stay outside the lock, where a send waiting for the
|
|
113
113
|
// prompt cannot be held behind them.
|
|
114
|
-
|
|
114
|
+
// Issue #3981: through the one launch-key writer every tool shares.
|
|
115
|
+
await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
|
|
115
116
|
// Wait for Gemini to initialize (minimum wait for banner/auth)
|
|
116
117
|
await new Promise((resolve) => setTimeout(resolve, GEMINI_INIT_WAIT_MS));
|
|
117
118
|
// Poll until Gemini interactive prompt is ready
|
|
@@ -207,6 +208,9 @@ class GeminiTool extends base_1.BaseCLITool {
|
|
|
207
208
|
/**
|
|
208
209
|
* Wait for Gemini prompt before sending a message.
|
|
209
210
|
* Used by sendMessage to ensure Gemini is ready to accept input.
|
|
211
|
+
*
|
|
212
|
+
* @throws Error (`Gemini prompt not ready`) when the prompt did not appear
|
|
213
|
+
* within {@link GEMINI_PROMPT_WAIT_TIMEOUT_MS}; nothing was typed
|
|
210
214
|
*/
|
|
211
215
|
async waitForPrompt(sessionName) {
|
|
212
216
|
const startTime = Date.now();
|
|
@@ -225,7 +229,10 @@ class GeminiTool extends base_1.BaseCLITool {
|
|
|
225
229
|
}
|
|
226
230
|
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
227
231
|
}
|
|
232
|
+
// Issue #3981: give up without typing, as codex does. Sending anyway put the
|
|
233
|
+
// body into whatever held the pane (a dialog, a slow start, a shell).
|
|
228
234
|
logger.info('gemini-prompt-not-detected');
|
|
235
|
+
throw new Error('Gemini prompt not ready: timed out waiting for the input prompt before sending');
|
|
229
236
|
}
|
|
230
237
|
/**
|
|
231
238
|
* Send a message to Gemini interactive session
|
|
@@ -258,7 +265,8 @@ class GeminiTool extends base_1.BaseCLITool {
|
|
|
258
265
|
}
|
|
259
266
|
catch (error) {
|
|
260
267
|
const errorMessage = (0, errors_1.getErrorMessage)(error);
|
|
261
|
-
|
|
268
|
+
// Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
|
|
269
|
+
throw new Error(`Failed to send message to Gemini: ${errorMessage}`, { cause: error });
|
|
262
270
|
}
|
|
263
271
|
}
|
|
264
272
|
/**
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The keys a launch types into its pane, in one writer's turn (Issue #3981).
|
|
4
|
+
*
|
|
5
|
+
* #3975 put gemini's and claude's launch lines under the instance input lock;
|
|
6
|
+
* the other seven launch sites, and claude's `unset CLAUDECODE` before its
|
|
7
|
+
* line, still typed with no lock, so a send holding the composer could have
|
|
8
|
+
* them land in the middle of its body, paste or Enter. Every launch now types
|
|
9
|
+
* through {@link typeLaunchLines}: one `exclusive` turn for all of its lines
|
|
10
|
+
* (R2 of `session-launch-flight`), joined when the launcher already holds the
|
|
11
|
+
* lock (codex relaunching inside a send). The init polls and readiness waits
|
|
12
|
+
* that follow stay outside (#3975), so a send waiting for the prompt is never
|
|
13
|
+
* held behind them.
|
|
14
|
+
*
|
|
15
|
+
* @module lib/cli-tools/launch-keys
|
|
16
|
+
*/
|
|
17
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
|
+
exports.typeLaunchLines = typeLaunchLines;
|
|
19
|
+
const tmux_1 = require("../tmux/tmux");
|
|
20
|
+
const instance_input_lock_1 = require("../session/instance-input-lock");
|
|
21
|
+
/**
|
|
22
|
+
* Type `steps` into `sessionName` as one `exclusive` writer, in order.
|
|
23
|
+
*
|
|
24
|
+
* @param sessionName - tmux session name
|
|
25
|
+
* @param steps - Lines (typed with Enter) and self-typing steps
|
|
26
|
+
* @throws Whatever `withInstanceInputLock` throws when not admitted; nothing was typed then
|
|
27
|
+
*/
|
|
28
|
+
async function typeLaunchLines(sessionName, steps) {
|
|
29
|
+
await (0, instance_input_lock_1.withInstanceInputLock)(sessionName, async () => {
|
|
30
|
+
for (const step of steps) {
|
|
31
|
+
if (typeof step === 'string') {
|
|
32
|
+
await (0, tmux_1.sendKeys)(sessionName, step, true);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
await step();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
}
|
|
@@ -235,7 +235,10 @@ class OpenCodeV2Tool extends base_1.BaseCLITool {
|
|
|
235
235
|
if (port === null) {
|
|
236
236
|
logger.warn('opencode-v2-launch-without-server', { worktreeId, instanceId });
|
|
237
237
|
}
|
|
238
|
-
|
|
238
|
+
// Issue #3981: in one writer's turn of the input lock; the readiness
|
|
239
|
+
// wait below stays outside it.
|
|
240
|
+
const launchCommand = (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({ target, executablePath: executable.path, worktreePath });
|
|
241
|
+
await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
|
|
239
242
|
await this.waitForReady(sessionName);
|
|
240
243
|
await (0, runtime_1.attachOpencodeV2EventStream)(target);
|
|
241
244
|
logger.info('started-opencode-v2-session');
|
|
@@ -313,7 +316,8 @@ class OpenCodeV2Tool extends base_1.BaseCLITool {
|
|
|
313
316
|
logger.info('sent-message-to-opencode-v2-session');
|
|
314
317
|
}
|
|
315
318
|
catch (error) {
|
|
316
|
-
|
|
319
|
+
// Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
|
|
320
|
+
throw new Error(`Failed to send message to OpenCode V2: ${(0, errors_1.getErrorMessage)(error)}`, { cause: error });
|
|
317
321
|
}
|
|
318
322
|
}
|
|
319
323
|
/**
|
|
@@ -335,7 +335,9 @@ class OpenCodeTool extends base_1.BaseCLITool {
|
|
|
335
335
|
});
|
|
336
336
|
}
|
|
337
337
|
const launchedAt = Date.now();
|
|
338
|
-
|
|
338
|
+
// Issue #3981: in one writer's turn of the input lock; the readiness
|
|
339
|
+
// wait below stays outside it.
|
|
340
|
+
await this.typeLaunchLines(sessionName, [(0, launch_screen_1.withLaunchScreenCleared)(launchCommand)]);
|
|
339
341
|
// Issue #1908: poll for opencode's own composer instead of sleeping 15 s.
|
|
340
342
|
await this.waitForReady(sessionName);
|
|
341
343
|
// Issue #1763: subscribe once the server is up. Health-checked first, so
|
|
@@ -691,7 +693,8 @@ class OpenCodeTool extends base_1.BaseCLITool {
|
|
|
691
693
|
}
|
|
692
694
|
catch (error) {
|
|
693
695
|
const errorMessage = (0, errors_1.getErrorMessage)(error);
|
|
694
|
-
|
|
696
|
+
// Issue #4031: the cause keeps a failed `load-buffer`'s code (`classifySendFailure`).
|
|
697
|
+
throw new Error(`Failed to send message to OpenCode: ${errorMessage}`, { cause: error });
|
|
695
698
|
}
|
|
696
699
|
}
|
|
697
700
|
/**
|
|
@@ -44,8 +44,16 @@ const legacy_session_alias_1 = require("../tmux/legacy-session-alias");
|
|
|
44
44
|
const SESSION_NAME_PREFIX = 'mcbd-';
|
|
45
45
|
/** Shape of a session-name namespace: 8 lowercase hex digits (Issue #2866). */
|
|
46
46
|
exports.SESSION_NAMESPACE_PATTERN = /^[0-9a-f]{8}$/;
|
|
47
|
-
/**
|
|
48
|
-
|
|
47
|
+
/**
|
|
48
|
+
* CLI tool ids, longest first, so a longer id is never read as a shorter one.
|
|
49
|
+
*
|
|
50
|
+
* Read when called, not when this module loads (Issue #3981): modules loaded
|
|
51
|
+
* early (`session-starting-state`) import this one, and a module-load read of
|
|
52
|
+
* `CLI_TOOL_IDS` reaches a test's getter mock before it can answer.
|
|
53
|
+
*/
|
|
54
|
+
function cliToolIdsLongestFirst() {
|
|
55
|
+
return [...types_1.CLI_TOOL_IDS].sort((a, b) => b.length - a.length);
|
|
56
|
+
}
|
|
49
57
|
/**
|
|
50
58
|
* The namespace this process names its sessions with, or null (legacy names).
|
|
51
59
|
*
|
|
@@ -150,7 +158,7 @@ function parseSessionName(name) {
|
|
|
150
158
|
namespace = body.slice(0, dash);
|
|
151
159
|
body = body.slice(dash + 1);
|
|
152
160
|
}
|
|
153
|
-
const cliToolId =
|
|
161
|
+
const cliToolId = cliToolIdsLongestFirst().find((id) => body.startsWith(`${id}-`));
|
|
154
162
|
if (!cliToolId)
|
|
155
163
|
return null;
|
|
156
164
|
const rest = body.slice(cliToolId.length + 1);
|
|
@@ -10,6 +10,7 @@ exports.withoutTrailingBlankRows = withoutTrailingBlankRows;
|
|
|
10
10
|
exports.findPasteTokens = findPasteTokens;
|
|
11
11
|
exports.readSubmitComposer = readSubmitComposer;
|
|
12
12
|
exports.classifySubmit = classifySubmit;
|
|
13
|
+
exports.classifySubmitWithRule = classifySubmitWithRule;
|
|
13
14
|
exports.isSubmitted = isSubmitted;
|
|
14
15
|
exports.classifyPasteLanded = classifyPasteLanded;
|
|
15
16
|
exports.compactText = compactText;
|
|
@@ -452,6 +453,15 @@ function readSubmitComposer(output, cliToolId, reader, lines, windowLines, messa
|
|
|
452
453
|
* the tool's own, so every existing three-argument caller is unchanged.
|
|
453
454
|
*/
|
|
454
455
|
function classifySubmit(output, cliToolId, message, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId)) {
|
|
456
|
+
return classifySubmitWithRule(output, cliToolId, message, composerSpec).state;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* {@link classifySubmit} with the rule that decided the frame (Issue #4035).
|
|
460
|
+
* The sender logs the rule with every verdict, and treats a `submitted` from B
|
|
461
|
+
* or F — the screen saying only "the body is not in the composer" — as weaker
|
|
462
|
+
* evidence than A on a tool whose own hook reports the prompt.
|
|
463
|
+
*/
|
|
464
|
+
function classifySubmitWithRule(output, cliToolId, message, composerSpec = (0, composer_spec_1.resolveComposerSpec)(cliToolId)) {
|
|
455
465
|
const clean = (0, cli_patterns_1.stripAnsi)(output);
|
|
456
466
|
const lines = withoutTrailingBlankRows(clean.split('\n'));
|
|
457
467
|
const windowLines = lines.slice(-exports.VERIFY_WINDOW_LINES);
|
|
@@ -461,34 +471,34 @@ function classifySubmit(output, cliToolId, message, composerSpec = (0, composer_
|
|
|
461
471
|
// pinned to the bottom of the pane, and widening it to opencode's whole
|
|
462
472
|
// frame would match `esc interrupt` printed inside a reply.
|
|
463
473
|
if ((0, cli_patterns_1.detectThinking)(cliToolId, windowStr)) {
|
|
464
|
-
return 'submitted';
|
|
474
|
+
return { state: 'submitted', rule: 'A' };
|
|
465
475
|
}
|
|
466
476
|
const composer = readSubmitComposer(output, cliToolId, composerSpec.reader, lines, windowLines, message);
|
|
467
477
|
// B. No composer visible (scrolled off / dialog / still starting), or the
|
|
468
478
|
// composer is empty => the message left the box => submitted.
|
|
469
479
|
if (composer.kind !== 'text') {
|
|
470
|
-
return 'submitted';
|
|
480
|
+
return { state: 'submitted', rule: composer.kind === 'absent' ? 'B-absent' : 'B-empty' };
|
|
471
481
|
}
|
|
472
482
|
// C. A paste placeholder is still folded into the composer => body is there.
|
|
473
483
|
if (composer.rows.some((row) => PASTE_PLACEHOLDER_PATTERN.test(row) || findPasteTokens(row).tokens.length > 0)) {
|
|
474
|
-
return 'pending';
|
|
484
|
+
return { state: 'pending', rule: 'C' };
|
|
475
485
|
}
|
|
476
486
|
// D. The typed body is still sitting in the composer => resend Enter.
|
|
477
487
|
if (inputMatchesBody(composer.text, message)) {
|
|
478
|
-
return 'pending';
|
|
488
|
+
return { state: 'pending', rule: 'D' };
|
|
479
489
|
}
|
|
480
490
|
// E. A different slash command is in the composer => a completion popup
|
|
481
491
|
// replaced what we typed. (Scoped to `/…` so idle-prompt placeholders that
|
|
482
492
|
// some TUIs paint on an empty composer are never mistaken for this.)
|
|
483
493
|
if (REPLACEMENT_COMMAND_PATTERN.test(composer.text)) {
|
|
484
|
-
return 'replaced';
|
|
494
|
+
return { state: 'replaced', rule: 'E' };
|
|
485
495
|
}
|
|
486
496
|
// F. Non-empty, non-command steady-state text (idle placeholder / hint) =>
|
|
487
497
|
// submitted, preserving the pre-#1501 permissive default. Not for a codex
|
|
488
498
|
// composer above the window (Issue #3906): before #3906 that frame was
|
|
489
499
|
// read as no composer at all; text there that is not the body says
|
|
490
500
|
// neither that the message left nor that Enter would send it.
|
|
491
|
-
return composer.outsideWindow ? 'indeterminate' : 'submitted';
|
|
501
|
+
return composer.outsideWindow ? { state: 'indeterminate', rule: 'F-outside' } : { state: 'submitted', rule: 'F' };
|
|
492
502
|
}
|
|
493
503
|
/**
|
|
494
504
|
* Backward-compatible boolean view of {@link classifySubmit}: submitted vs not.
|
|
@@ -89,6 +89,13 @@
|
|
|
89
89
|
* checks it still owns the composer before every key, watches an `unseen`
|
|
90
90
|
* paste a little longer before giving up, and leaves a mark for a body that
|
|
91
91
|
* may still arrive, which the next send waits out ({@link waitOutCarriedPaste}).
|
|
92
|
+
*
|
|
93
|
+
* Issue #4035 is a claude session's first prompt reported sent when it was
|
|
94
|
+
* not. Keys typed right after the prompt appeared were drawn ~1 s later and
|
|
95
|
+
* their Enter was lost, while the read-back still showed the dim placeholder
|
|
96
|
+
* (rule F). On that first prompt a B or F verdict now waits for claude's own
|
|
97
|
+
* `UserPromptSubmit` ({@link awaitPromptReport}), and a later send that clears
|
|
98
|
+
* a body this one called sent says so ({@link reportSubmittedBodyInComposer}).
|
|
92
99
|
*/
|
|
93
100
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
94
101
|
if (k2 === undefined) k2 = k;
|
|
@@ -124,7 +131,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
124
131
|
};
|
|
125
132
|
})();
|
|
126
133
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
127
|
-
exports.LITERAL_SEND_MAX_BYTES = exports.isSubmitted = exports.classifySubmit = exports.classifyPasteLanded = exports.recheckComposerBeforeInput = void 0;
|
|
134
|
+
exports.PROMPT_REPORT_WAIT_MS = exports.LITERAL_SEND_MAX_BYTES = exports.isSubmitted = exports.classifySubmitWithRule = exports.classifySubmit = exports.classifyPasteLanded = exports.recheckComposerBeforeInput = void 0;
|
|
128
135
|
exports.clearComposerBeforeSend = clearComposerBeforeSend;
|
|
129
136
|
exports.sendMessageWithSubmitVerification = sendMessageWithSubmitVerification;
|
|
130
137
|
const childProcess = __importStar(require("child_process"));
|
|
@@ -137,6 +144,9 @@ const logger_1 = require("../../lib/logger");
|
|
|
137
144
|
const global_state_1 = require("../../lib/global-state");
|
|
138
145
|
const composer_clear_1 = require("../../lib/session/composer-clear");
|
|
139
146
|
Object.defineProperty(exports, "recheckComposerBeforeInput", { enumerable: true, get: function () { return composer_clear_1.recheckComposerBeforeInput; } });
|
|
147
|
+
const prompt_submit_receipt_1 = require("../../lib/session/prompt-submit-receipt");
|
|
148
|
+
const send_attempt_state_1 = require("../../lib/session/send-attempt-state");
|
|
149
|
+
const send_attempt_types_1 = require("../../lib/session/send-attempt-types");
|
|
140
150
|
const instance_input_lock_1 = require("../../lib/session/instance-input-lock");
|
|
141
151
|
const composer_text_1 = require("../../lib/detection/composer-text");
|
|
142
152
|
const submit_composer_read_1 = require("./submit-composer-read");
|
|
@@ -145,6 +155,7 @@ const submit_composer_read_1 = require("./submit-composer-read");
|
|
|
145
155
|
var submit_composer_read_2 = require("./submit-composer-read");
|
|
146
156
|
Object.defineProperty(exports, "classifyPasteLanded", { enumerable: true, get: function () { return submit_composer_read_2.classifyPasteLanded; } });
|
|
147
157
|
Object.defineProperty(exports, "classifySubmit", { enumerable: true, get: function () { return submit_composer_read_2.classifySubmit; } });
|
|
158
|
+
Object.defineProperty(exports, "classifySubmitWithRule", { enumerable: true, get: function () { return submit_composer_read_2.classifySubmitWithRule; } });
|
|
148
159
|
Object.defineProperty(exports, "isSubmitted", { enumerable: true, get: function () { return submit_composer_read_2.isSubmitted; } });
|
|
149
160
|
const logger = (0, logger_1.createLogger)('cli-tools/submit-verified-sender');
|
|
150
161
|
/**
|
|
@@ -203,6 +214,15 @@ const RECHECK_CAPTURE_LINES = 200;
|
|
|
203
214
|
const CARRIED_MARK_POLL_MS = 200;
|
|
204
215
|
/** Default bounded recovery Enters (each read back) before giving up (throwing). */
|
|
205
216
|
const DEFAULT_VERIFY_ATTEMPTS = 4;
|
|
217
|
+
/**
|
|
218
|
+
* How long a B/F verdict on a session's first prompt waits for the agent's own
|
|
219
|
+
* report of it (Issue #4035). Claude 2.1.314 reported the first prompt 0.66–0.74 s
|
|
220
|
+
* after the send began in all 29 submitted first sends measured; an unsent body
|
|
221
|
+
* was drawn into the composer 0.9–1.7 s after its Enter.
|
|
222
|
+
*/
|
|
223
|
+
exports.PROMPT_REPORT_WAIT_MS = 5000;
|
|
224
|
+
/** How often the report and the composer are looked at during that wait. */
|
|
225
|
+
const PROMPT_REPORT_POLL_MS = 100;
|
|
206
226
|
/** Run one tmux command, optionally feeding it `input` on stdin. */
|
|
207
227
|
function runTmux(args, input) {
|
|
208
228
|
return new Promise((resolve, reject) => {
|
|
@@ -234,6 +254,12 @@ function runTmux(args, input) {
|
|
|
234
254
|
* `load-buffer` ran. A lost ticket drops the buffer and throws before anything
|
|
235
255
|
* reaches the pane (`input lock lost, nothing was typed`).
|
|
236
256
|
*
|
|
257
|
+
* Issue #4011: a failed `load-buffer` throws with `delivery: 'not-started'`
|
|
258
|
+
* (the field `TmuxSendError` carries) — it runs before `paste-buffer`, so none
|
|
259
|
+
* of the body reached the pane, however it failed (an exit status or a timeout).
|
|
260
|
+
* Issue #4031: worded `Failed to load message into tmux buffer` and coded
|
|
261
|
+
* `PASTE_NOT_STARTED_CODE`, so `classifySendFailure` records it `not-sent`.
|
|
262
|
+
*
|
|
237
263
|
* @throws Error when either tmux command fails, or `ticket` lost the composer
|
|
238
264
|
*/
|
|
239
265
|
async function pasteBody(sessionName, message, ticket, cliToolId) {
|
|
@@ -245,7 +271,13 @@ async function pasteBody(sessionName, message, ticket, cliToolId) {
|
|
|
245
271
|
catch (error) {
|
|
246
272
|
await runTmux(['delete-buffer', '-b', bufferName]).catch(() => undefined);
|
|
247
273
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
248
|
-
|
|
274
|
+
// Issue #4031: its own wording and code, apart from `paste-buffer`'s
|
|
275
|
+
// failure below (whose body may be on the pane), so the send is recorded
|
|
276
|
+
// `not-sent` with or without a bound relay.
|
|
277
|
+
throw Object.assign(new Error(`Failed to load message into tmux buffer: ${errorMessage}`), {
|
|
278
|
+
delivery: 'not-started',
|
|
279
|
+
code: send_attempt_types_1.PASTE_NOT_STARTED_CODE,
|
|
280
|
+
});
|
|
249
281
|
}
|
|
250
282
|
if (!ticket.isCurrent()) {
|
|
251
283
|
await runTmux(['delete-buffer', '-b', bufferName]).catch(() => undefined);
|
|
@@ -599,6 +631,67 @@ async function confirmTypedBodyLanded(params) {
|
|
|
599
631
|
`${attempts * TYPED_BODY_POLL_MS}ms (it shows ${shown}); the message is ${bytes} bytes. ` +
|
|
600
632
|
'Enter was not pressed, so nothing was submitted (Issue #3366).');
|
|
601
633
|
}
|
|
634
|
+
/**
|
|
635
|
+
* Whether a verdict is one the agent's own report must back (Issue #4035):
|
|
636
|
+
* `submitted` from B or F — the screen saying only that the body is not in the
|
|
637
|
+
* composer. A (generating) stands on its own. A body starting with `/` or `!`
|
|
638
|
+
* is run by the TUI itself, which is not measured to report it as a prompt.
|
|
639
|
+
*/
|
|
640
|
+
function needsPromptReport(state, rule, message) {
|
|
641
|
+
if (state !== 'submitted' || rule === 'A')
|
|
642
|
+
return false;
|
|
643
|
+
return !/^\s*[/!]/.test(message);
|
|
644
|
+
}
|
|
645
|
+
/**
|
|
646
|
+
* Watch a session's first prompt until the agent reports it (Issue #4035).
|
|
647
|
+
*
|
|
648
|
+
* Reads the hook record and the composer every {@link PROMPT_REPORT_POLL_MS}
|
|
649
|
+
* until `deadline`, without pressing anything. The deadline is the send's, not
|
|
650
|
+
* the call's: a send that waits again after a resent Enter gets only what is
|
|
651
|
+
* left of its {@link PROMPT_REPORT_WAIT_MS} (it holds the input lock meanwhile).
|
|
652
|
+
*
|
|
653
|
+
* - the agent reported the prompt — `received`;
|
|
654
|
+
* - the screen changes its verdict — generating (A), or the body drawn into
|
|
655
|
+
* the composer after all (C/D, `pending`: the caller resends Enter, as for
|
|
656
|
+
* any typed-but-unsent body), or a completion (E) — `screen`, with the frame;
|
|
657
|
+
* - neither, to the end — `unreported`: nothing says the message left.
|
|
658
|
+
*/
|
|
659
|
+
async function awaitPromptReport(params) {
|
|
660
|
+
const { sessionName, message, cliToolId, composer, enteredAt, deadline } = params;
|
|
661
|
+
let rule = params.rule;
|
|
662
|
+
while (Date.now() < deadline) {
|
|
663
|
+
await new Promise((resolve) => setTimeout(resolve, PROMPT_REPORT_POLL_MS));
|
|
664
|
+
if ((0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt) === 'received')
|
|
665
|
+
return { verdict: 'received' };
|
|
666
|
+
const output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
|
|
667
|
+
const verdict = (0, submit_composer_read_1.classifySubmitWithRule)(output, cliToolId, message, composer);
|
|
668
|
+
if (verdict.state !== 'submitted' || verdict.rule === 'A')
|
|
669
|
+
return { verdict: 'screen', ...verdict, output };
|
|
670
|
+
rule = verdict.rule;
|
|
671
|
+
}
|
|
672
|
+
if ((0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt) === 'received')
|
|
673
|
+
return { verdict: 'received' };
|
|
674
|
+
return { verdict: 'unreported', rule };
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Say so when the pre-send clear finds the body this session last reported
|
|
678
|
+
* submitted (Issue #4035): that body never reached the agent, and the send that
|
|
679
|
+
* said `sent` for it was wrong. The instance's `lastSend` is turned
|
|
680
|
+
* `indeterminate` (the send now running records its own outcome after it).
|
|
681
|
+
*/
|
|
682
|
+
function reportSubmittedBodyInComposer(sessionName, cliToolId, composerText, cleared) {
|
|
683
|
+
if (composerText === '' || !(0, prompt_submit_receipt_1.matchesSubmittedBody)(sessionName, composerText))
|
|
684
|
+
return;
|
|
685
|
+
const target = (0, prompt_submit_receipt_1.getPromptSubmitTarget)(sessionName);
|
|
686
|
+
if (target !== null)
|
|
687
|
+
(0, send_attempt_state_1.markLastSendDiscarded)({ ...target, instanceId: target.instanceId ?? target.cliToolId });
|
|
688
|
+
logger.warn('pre-send-found-submitted-body', {
|
|
689
|
+
sessionName,
|
|
690
|
+
cliToolId,
|
|
691
|
+
cleared,
|
|
692
|
+
length: composerText.length,
|
|
693
|
+
});
|
|
694
|
+
}
|
|
602
695
|
/**
|
|
603
696
|
* Empty the composer before the body is typed into it (Issue #1880).
|
|
604
697
|
*
|
|
@@ -658,6 +751,7 @@ async function clearComposerBeforeSend(sessionName, cliToolId, composerSpec = (0
|
|
|
658
751
|
});
|
|
659
752
|
if (ticket !== undefined)
|
|
660
753
|
assertInputOwner(ticket, cliToolId, 'the pre-send clear', false);
|
|
754
|
+
reportSubmittedBodyInComposer(sessionName, cliToolId, result.discardedText, result.state !== 'content');
|
|
661
755
|
if (result.state === 'content') {
|
|
662
756
|
logger.error('pre-send-composer-clear-failed', {
|
|
663
757
|
sessionName,
|
|
@@ -742,9 +836,11 @@ async function sendUnderInputLock(params, ticket) {
|
|
|
742
836
|
}
|
|
743
837
|
catch (error) {
|
|
744
838
|
// Whether tmux put any of it into the pane is unknown — except after a
|
|
745
|
-
// refused input boundary (Issue #3992)
|
|
746
|
-
//
|
|
747
|
-
|
|
839
|
+
// refused input boundary (Issue #3992) or a failed `load-buffer` (Issue
|
|
840
|
+
// #4011, `not-started`), both before `paste-buffer`: a mark then would
|
|
841
|
+
// only hold the next send off for nothing.
|
|
842
|
+
const notStarted = error?.delivery === 'not-started';
|
|
843
|
+
if (!(0, instance_input_lock_1.isInputBoundaryRefusal)(error) && !notStarted)
|
|
748
844
|
(0, instance_input_lock_1.leaveCarriedPasteMark)(ticket);
|
|
749
845
|
throw error;
|
|
750
846
|
}
|
|
@@ -796,6 +892,8 @@ async function sendUnderInputLock(params, ticket) {
|
|
|
796
892
|
}
|
|
797
893
|
}
|
|
798
894
|
// 3. Submit as a separate command (double Enter for vibe-local's IME mode).
|
|
895
|
+
// Issue #4035: the agent's own report of the prompt counts from here.
|
|
896
|
+
const enteredAt = Date.now();
|
|
799
897
|
for (let i = 0; i < Math.max(1, submitEnterCount); i++) {
|
|
800
898
|
assertInputOwner(ticket, cliToolId, 'Enter', true);
|
|
801
899
|
await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
|
|
@@ -812,11 +910,62 @@ async function sendUnderInputLock(params, ticket) {
|
|
|
812
910
|
// was reported "could not be confirmed" — a sent message as exit 99. The
|
|
813
911
|
// last read sends nothing: no Enter goes out that is not read back.
|
|
814
912
|
const attempts = Math.max(1, verifyAttempts);
|
|
913
|
+
// Issue #4035: one wait for the agent's report per send, however many reads.
|
|
914
|
+
let promptReportDeadline = null;
|
|
815
915
|
for (let attempt = 0; attempt <= attempts; attempt++) {
|
|
816
916
|
await new Promise((resolve) => setTimeout(resolve, verifyDelayMs));
|
|
817
|
-
|
|
818
|
-
|
|
917
|
+
let output = await (0, tmux_1.capturePane)(sessionName, { startLine: -composer.verifyCaptureLines });
|
|
918
|
+
let { state, rule } = (0, submit_composer_read_1.classifySubmitWithRule)(output, cliToolId, message, composer);
|
|
919
|
+
const receipt = needsPromptReport(state, rule, message)
|
|
920
|
+
? (0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt)
|
|
921
|
+
: 'not-required';
|
|
922
|
+
// Issue #4035: every verdict names the rule that gave it, so a send reported
|
|
923
|
+
// `sent` can be traced to what the screen showed.
|
|
924
|
+
logger.info('submit-classified', { sessionName, cliToolId, attempt, state, rule, receipt });
|
|
925
|
+
if (receipt === 'awaited') {
|
|
926
|
+
// Issue #4035: the screen says only that the body is not in the composer,
|
|
927
|
+
// on a session that has not reported a prompt yet. Watch, without Enter,
|
|
928
|
+
// until the agent reports it or the composer shows the body after all.
|
|
929
|
+
promptReportDeadline ??= Date.now() + exports.PROMPT_REPORT_WAIT_MS;
|
|
930
|
+
const watched = await awaitPromptReport({
|
|
931
|
+
sessionName,
|
|
932
|
+
message,
|
|
933
|
+
cliToolId,
|
|
934
|
+
composer,
|
|
935
|
+
enteredAt,
|
|
936
|
+
rule,
|
|
937
|
+
deadline: promptReportDeadline,
|
|
938
|
+
});
|
|
939
|
+
if (watched.verdict === 'unreported') {
|
|
940
|
+
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
941
|
+
logger.error('submit-not-confirmed:prompt-unreported', {
|
|
942
|
+
sessionName,
|
|
943
|
+
cliToolId,
|
|
944
|
+
attempt,
|
|
945
|
+
rule: watched.rule,
|
|
946
|
+
waitedMs: exports.PROMPT_REPORT_WAIT_MS,
|
|
947
|
+
});
|
|
948
|
+
throw new Error(`Message submit could not be confirmed for session ${sessionName}: the composer did not show the body ` +
|
|
949
|
+
`(rule ${watched.rule}) but the agent did not report the prompt within ${exports.PROMPT_REPORT_WAIT_MS}ms ` +
|
|
950
|
+
'(Issue #4035).');
|
|
951
|
+
}
|
|
952
|
+
if (watched.verdict === 'received') {
|
|
953
|
+
logger.info('submit-confirmed-by-prompt-hook', { sessionName, cliToolId, attempt, rule });
|
|
954
|
+
state = 'submitted';
|
|
955
|
+
}
|
|
956
|
+
else {
|
|
957
|
+
({ state, rule, output } = watched);
|
|
958
|
+
logger.info('submit-classified', { sessionName, cliToolId, attempt, state, rule, receipt: 'awaited' });
|
|
959
|
+
}
|
|
960
|
+
}
|
|
819
961
|
if (state === 'submitted') {
|
|
962
|
+
// Issue #4035: only a body the screen alone called submitted is remembered
|
|
963
|
+
// for the next send's clear. One the agent reported did leave, and the same
|
|
964
|
+
// text back in the composer is claude restoring it (Esc), the history (↑),
|
|
965
|
+
// or a person typing it — not a send that never arrived.
|
|
966
|
+
if ((0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt) !== 'received') {
|
|
967
|
+
(0, prompt_submit_receipt_1.noteSubmittedBody)(sessionName, message);
|
|
968
|
+
}
|
|
820
969
|
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
821
970
|
return;
|
|
822
971
|
}
|
|
@@ -863,6 +1012,14 @@ async function sendUnderInputLock(params, ticket) {
|
|
|
863
1012
|
logger.warn('submit-not-confirmed:foreign-paste-token', { sessionName, cliToolId, attempt });
|
|
864
1013
|
continue;
|
|
865
1014
|
}
|
|
1015
|
+
// Issue #4035: the Enter thought lost may only have been late — the agent
|
|
1016
|
+
// reporting the prompt now means it went, and another Enter would land on an
|
|
1017
|
+
// empty composer, or on a dialog that the prompt just opened.
|
|
1018
|
+
if ((0, prompt_submit_receipt_1.readPromptSubmitReceipt)(sessionName, cliToolId, enteredAt) === 'received') {
|
|
1019
|
+
logger.info('submit-confirmed-by-prompt-hook', { sessionName, cliToolId, attempt, rule });
|
|
1020
|
+
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
866
1023
|
// state === 'pending' — still typed-but-unsent, resend a single Enter and re-check.
|
|
867
1024
|
logger.warn('submit-not-confirmed:resending-enter', {
|
|
868
1025
|
sessionName,
|