commandmate 0.47.2 → 0.49.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 +180 -180
- package/.next/app-path-routes-manifest.json +30 -30
- 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.js.nft.json +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page.js +1 -1
- package/.next/server/app/skills/[skillId]/page.js.nft.json +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.js +2 -2
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +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.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +30 -30
- 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/2069.js +1 -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/4243.js +1 -1
- 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 +8 -8
- 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 +5 -5
- 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/1128-914c559913546bbc.js +1 -0
- package/.next/static/chunks/{2407-a6533805a86d05bd.js → 2407-ab92ae9837c39dce.js} +1 -1
- package/.next/static/chunks/{2863-6a07ec82fb52f4dd.js → 2863-7173dc305dffc4f6.js} +1 -1
- package/.next/static/chunks/6288-6fadbba6e84393b2.js +1 -0
- package/.next/static/chunks/7665-e9ef6e0a85b9fa49.js +1 -0
- package/.next/static/chunks/8407-35bbfc84793d7004.js +1 -0
- package/.next/static/chunks/9079-987939d231704218.js +1 -0
- package/.next/static/chunks/app/{layout-538d8d2746ad1588.js → layout-aa8e66164a4367af.js} +1 -1
- package/.next/static/chunks/app/sessions/page-cfd645305e25fd33.js +1 -0
- package/.next/static/chunks/app/skills/[skillId]/{page-52ba58712faf3378.js → page-cb6e74fd9a6a571d.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-704086656fb45699.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-a8d7886703ffc7b4.js +1 -0
- package/.next/static/css/{743f79ff19ab91e9.css → db8959555c3d9c96.css} +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 +76 -8
- package/dist/cli/commands/capture.d.ts.map +1 -1
- package/dist/cli/commands/capture.js +5 -0
- 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 +19 -6
- package/dist/cli/commands/verify.d.ts.map +1 -1
- package/dist/cli/commands/verify.js +8 -1
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +101 -13
- package/dist/cli/config/duration-constants.d.ts +16 -13
- package/dist/cli/config/duration-constants.d.ts.map +1 -1
- package/dist/cli/config/duration-constants.js +21 -21
- 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 +29 -1
- package/dist/cli/types/api-responses.d.ts +145 -3
- 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/cli/utils/verify-runner.d.ts +24 -1
- package/dist/cli/utils/verify-runner.d.ts.map +1 -1
- package/dist/cli/utils/verify-runner.js +54 -1
- package/dist/config/auto-yes-duration.d.ts +56 -0
- package/dist/config/auto-yes-duration.d.ts.map +1 -0
- package/dist/config/auto-yes-duration.js +76 -0
- 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/config/auto-yes-config.js +14 -19
- package/dist/server/src/config/auto-yes-duration.js +76 -0
- 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 +59 -4
- package/dist/server/src/lib/cli-tools/submit-verified-sender.js +235 -19
- 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/composer-text.js +215 -11
- 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-chrome.js +193 -0
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +402 -539
- 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/upstream-faults.js +19 -2
- 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/hooks/structured-decision-response.js +1 -1
- 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 +124 -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 +145 -58
- 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/composer-clear.js +56 -4
- package/dist/server/src/lib/session/current-output-builder.js +66 -12
- package/dist/server/src/lib/session/send-attempt-state.js +24 -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-ops.js +152 -0
- package/dist/server/src/lib/session/waiting-episode-state-store.js +202 -0
- package/dist/server/src/lib/session/waiting-episode-state-types.js +6 -0
- package/dist/server/src/lib/session/waiting-episode-state.js +68 -91
- 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 +79 -9
- package/dist/server/src/lib/verification/gate-runner.js +172 -16
- 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 +47 -13
- package/package.json +1 -1
- package/public/sw.js +76 -4
- package/release-notes/0.48.0.json +57 -0
- package/release-notes/0.49.0.json +45 -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/server/chunks/6722.js +0 -1
- package/.next/static/chunks/5371-a549a0d2c2044d41.js +0 -1
- package/.next/static/chunks/602-1c1488959215e140.js +0 -1
- package/.next/static/chunks/6288-09feba367cc2c65e.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]/files/[...path]/page-9cf1ecc59e36a004.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-46aced20b2b1c010.js +0 -1
- /package/.next/static/{etorRtpxbQqqOzdUeXdw2 → 3_JtAZaKMJEDFIIfkHv4n}/_buildManifest.js +0 -0
- /package/.next/static/{etorRtpxbQqqOzdUeXdw2 → 3_JtAZaKMJEDFIIfkHv4n}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Which option Auto-Yes answers a question with under the `recommended`
|
|
4
|
+
* answer mode (Issue #3863).
|
|
5
|
+
*
|
|
6
|
+
* Only the choice among a question's options. Whether the screen is a
|
|
7
|
+
* question at all (`classifyAutoYesQuestion`), whether the mode lets Auto-Yes
|
|
8
|
+
* answer it, and what the contract allows are decided elsewhere; a permission
|
|
9
|
+
* dialog keeps #3822's rule (the one "allow this call once" row) and never
|
|
10
|
+
* reaches this.
|
|
11
|
+
*
|
|
12
|
+
* The rule (the user's decision of 2026-10-24):
|
|
13
|
+
*
|
|
14
|
+
* - exactly one option's title ends in a recommendation marker → that option,
|
|
15
|
+
* wherever it is in the list and wherever the cursor is;
|
|
16
|
+
* - no option is recommended (every reading `false`) → the default: the
|
|
17
|
+
* cursor's option, else option 1;
|
|
18
|
+
* - otherwise nothing is chosen: an option whose title could not be told from
|
|
19
|
+
* its description (`'unknown'`, or no reading at all), two or more
|
|
20
|
+
* recommended options, a chosen option that takes typed text, or a
|
|
21
|
+
* multi-select question.
|
|
22
|
+
*
|
|
23
|
+
* Client-safe: no server-only imports (the resolver that calls it is walked by
|
|
24
|
+
* the client-import guard).
|
|
25
|
+
*
|
|
26
|
+
* @module lib/polling/auto-yes-question-choice
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.chooseRecommendedOption = chooseRecommendedOption;
|
|
30
|
+
/**
|
|
31
|
+
* Choose a question's answer under the `recommended` mode.
|
|
32
|
+
*
|
|
33
|
+
* @param options - The question's options, as the reader read them
|
|
34
|
+
* @param recommendations - Per option, what its title says (`PromptDetectionResult.optionRecommendations`);
|
|
35
|
+
* absent or of another length reads as `'unknown'` for every option
|
|
36
|
+
* @param multiSelect - Whether the question takes several answers
|
|
37
|
+
*/
|
|
38
|
+
function chooseRecommendedOption(options, recommendations, multiSelect) {
|
|
39
|
+
if (multiSelect)
|
|
40
|
+
return { kind: 'unidentified', cause: 'multi-select' };
|
|
41
|
+
if (options.length === 0)
|
|
42
|
+
return { kind: 'unidentified', cause: 'no-options' };
|
|
43
|
+
if (recommendations === undefined || recommendations.length !== options.length) {
|
|
44
|
+
return { kind: 'unidentified', cause: 'unknown-title' };
|
|
45
|
+
}
|
|
46
|
+
if (recommendations.some((value) => value === 'unknown'))
|
|
47
|
+
return { kind: 'unidentified', cause: 'unknown-title' };
|
|
48
|
+
const recommended = options.filter((_, index) => recommendations[index] === true);
|
|
49
|
+
if (recommended.length > 1)
|
|
50
|
+
return { kind: 'unidentified', cause: 'several-recommended' };
|
|
51
|
+
const [option, basis] = recommended.length === 1
|
|
52
|
+
? [recommended[0], 'recommended']
|
|
53
|
+
: [options.find((candidate) => candidate.isDefault) ?? options[0], 'default'];
|
|
54
|
+
if (option.requiresTextInput)
|
|
55
|
+
return { kind: 'unidentified', cause: 'typed-text' };
|
|
56
|
+
return { kind: 'chosen', option, basis };
|
|
57
|
+
}
|
|
@@ -9,6 +9,15 @@
|
|
|
9
9
|
* confirm is a separate row, so a default is half an answer)
|
|
10
10
|
* - multiple_choice with default option -> default option number
|
|
11
11
|
* - multiple_choice without default -> first option number
|
|
12
|
+
* - Issue #3822: a permission dialog (a row reads as one of the effects in
|
|
13
|
+
* `auto-yes-option-effect`) -> the number of its one "allow this call once"
|
|
14
|
+
* row, wherever the default is; withheld as `allow-once-unidentified` when
|
|
15
|
+
* there is no such row or more than one
|
|
16
|
+
* - Issue #3863: a question under the `recommended` answer mode (the caller
|
|
17
|
+
* passes `question`) -> its recommended option, else its default; withheld
|
|
18
|
+
* as `recommended-option-unidentified` when that cannot be told
|
|
19
|
+
* (`auto-yes-question-choice`). A question that reads as a permission
|
|
20
|
+
* dialog keeps the allow-once rule above.
|
|
12
21
|
* - option requiring text input -> null (skip)
|
|
13
22
|
* - unknown type -> null (skip)
|
|
14
23
|
*
|
|
@@ -18,8 +27,9 @@
|
|
|
18
27
|
* omitting it (or passing one that states nothing) reproduces the pre-#1547
|
|
19
28
|
* behaviour exactly, which is what keeps contract-less operation untouched.
|
|
20
29
|
*
|
|
21
|
-
* Client-safe: no server-only imports
|
|
22
|
-
* (`hooks/useAutoYes.ts`)
|
|
30
|
+
* Client-safe: no server-only imports. A 'use client' hook
|
|
31
|
+
* (`hooks/useAutoYes.ts`) imported this module until Issue #3821 retired the
|
|
32
|
+
* browser's answers; the guard `use-auto-yes-client-imports-3748` still walks it.
|
|
23
33
|
*/
|
|
24
34
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
25
35
|
exports.MAX_DENY_MATCH_TEXT_LENGTH = exports.MAX_DENY_PATTERN_LENGTH = exports.AUTO_YES_POLICY_UNKNOWN = void 0;
|
|
@@ -31,6 +41,8 @@ exports.resolveAutoAnswer = resolveAutoAnswer;
|
|
|
31
41
|
const auto_yes_config_1 = require("../../config/auto-yes-config");
|
|
32
42
|
const auto_yes_suppression_reason_1 = require("./auto-yes-suppression-reason");
|
|
33
43
|
const prompt_answer_semantic_1 = require("../../lib/prompt-answer-semantic");
|
|
44
|
+
const auto_yes_option_effect_1 = require("./auto-yes-option-effect");
|
|
45
|
+
const auto_yes_question_choice_1 = require("./auto-yes-question-choice");
|
|
34
46
|
/** The one {@link AutoYesPolicyUnknown} value. */
|
|
35
47
|
exports.AUTO_YES_POLICY_UNKNOWN = Object.freeze({ lookupFailed: true });
|
|
36
48
|
/** Whether the lookup failed, i.e. the contract is not known (Issue #3822). */
|
|
@@ -54,14 +66,31 @@ exports.MAX_DENY_PATTERN_LENGTH = 200;
|
|
|
54
66
|
* A prompt question or option label is a few hundred characters; the bound only
|
|
55
67
|
* exists so a pathological pane cannot make every poll scan megabytes with 32
|
|
56
68
|
* patterns. Matching is over the head of the field, deterministically.
|
|
69
|
+
*
|
|
70
|
+
* Issue #3881: a field cut here was not shown to the patterns whole, exactly
|
|
71
|
+
* like an approval target cut at its 12-row cap, so a miss over its head is
|
|
72
|
+
* not a pass: it withholds as `deny-pattern-unusable` (no pattern named). A
|
|
73
|
+
* match inside the head is still `deny-pattern`.
|
|
57
74
|
*/
|
|
58
75
|
exports.MAX_DENY_MATCH_TEXT_LENGTH = 20_000;
|
|
59
|
-
/**
|
|
60
|
-
|
|
76
|
+
/**
|
|
77
|
+
* The pre-policy resolution: the rules as they were before Issue #1547, with
|
|
78
|
+
* the permission rows read by effect (Issue #3822).
|
|
79
|
+
*/
|
|
80
|
+
function resolveBaseAnswer(promptData, cliToolId, question) {
|
|
61
81
|
if (promptData.type === 'yes_no') {
|
|
62
|
-
return 'y';
|
|
82
|
+
return { answer: 'y' };
|
|
63
83
|
}
|
|
64
84
|
if (promptData.type === 'multiple_choice') {
|
|
85
|
+
// Issue #3863: a question answered with its recommended option. Not for a
|
|
86
|
+
// question whose rows read as a permission dialog — a recommendation never
|
|
87
|
+
// picks which permission to grant (#3822's rule below decides that).
|
|
88
|
+
if (question !== undefined && (0, auto_yes_option_effect_1.selectAllowOnceOption)(promptData.options, cliToolId).kind === 'not-a-permission-dialog') {
|
|
89
|
+
const choice = (0, auto_yes_question_choice_1.chooseRecommendedOption)(promptData.options, question.optionRecommendations, (0, prompt_answer_semantic_1.isMultiSelectPrompt)(promptData));
|
|
90
|
+
return choice.kind === 'chosen'
|
|
91
|
+
? { answer: choice.option.number.toString() }
|
|
92
|
+
: { answer: null, withheldBy: auto_yes_suppression_reason_1.RECOMMENDED_OPTION_UNIDENTIFIED_SUPPRESSION_REASON };
|
|
93
|
+
}
|
|
65
94
|
// Issue #2755: a checkbox question. A number ticks a box and the confirm is
|
|
66
95
|
// a separate row, so "the default option" is not an answer — it is half of
|
|
67
96
|
// one. Auto-Yes refuses the prompt instead of ticking something and stopping.
|
|
@@ -70,19 +99,28 @@ function resolveBaseAnswer(promptData) {
|
|
|
70
99
|
// / `[X]` / `[✔]`) is refused too — the sender answers such a list with
|
|
71
100
|
// Space→Next→Enter, which would tick the default and submit the list.
|
|
72
101
|
if ((0, prompt_answer_semantic_1.isMultiSelectPrompt)(promptData)) {
|
|
73
|
-
return null;
|
|
102
|
+
return { answer: null };
|
|
74
103
|
}
|
|
75
|
-
|
|
76
|
-
|
|
104
|
+
// Issue #3822: on a permission dialog the default row may save a rule,
|
|
105
|
+
// change the mode or deny (agy keeps the cursor where it was left), so the
|
|
106
|
+
// answer is the one row that allows this call once, by its number — never
|
|
107
|
+
// whatever the cursor or row 1 happens to be.
|
|
108
|
+
const selection = (0, auto_yes_option_effect_1.selectAllowOnceOption)(promptData.options, cliToolId);
|
|
109
|
+
if (selection.kind === 'unidentified') {
|
|
110
|
+
return { answer: null, withheldBy: auto_yes_suppression_reason_1.ALLOW_ONCE_UNIDENTIFIED_SUPPRESSION_REASON };
|
|
111
|
+
}
|
|
112
|
+
const target = selection.kind === 'allow-once'
|
|
113
|
+
? selection.option
|
|
114
|
+
: promptData.options.find(o => o.isDefault) ?? promptData.options[0];
|
|
77
115
|
if (!target) {
|
|
78
|
-
return null;
|
|
116
|
+
return { answer: null };
|
|
79
117
|
}
|
|
80
118
|
if (target.requiresTextInput) {
|
|
81
|
-
return null;
|
|
119
|
+
return { answer: null };
|
|
82
120
|
}
|
|
83
|
-
return target.number.toString();
|
|
121
|
+
return { answer: target.number.toString() };
|
|
84
122
|
}
|
|
85
|
-
return null;
|
|
123
|
+
return { answer: null };
|
|
86
124
|
}
|
|
87
125
|
/**
|
|
88
126
|
* Every piece of prompt text a deny pattern is matched against.
|
|
@@ -121,12 +159,14 @@ function collectDenyMatchTexts(promptData) {
|
|
|
121
159
|
* Patterns are screened by {@link validateStopPattern} (length, safe-regex2
|
|
122
160
|
* catastrophic-backtracking detection, syntax) before execution, which is the
|
|
123
161
|
* same ReDoS defence the stop-pattern path uses. A pattern that fails screening
|
|
124
|
-
* — or whose execution throws — is reported as `unusable`, not skipped.
|
|
162
|
+
* — or whose execution throws — is reported as `unusable`, not skipped. So is
|
|
163
|
+
* a miss when a text was cut at {@link MAX_DENY_MATCH_TEXT_LENGTH} (Issue #3881).
|
|
125
164
|
*/
|
|
126
165
|
function evaluateDenyPatterns(rawTexts, patterns) {
|
|
127
166
|
if (patterns.length === 0) {
|
|
128
167
|
return { outcome: 'no-match' };
|
|
129
168
|
}
|
|
169
|
+
const headCut = rawTexts.some(text => text.length > exports.MAX_DENY_MATCH_TEXT_LENGTH);
|
|
130
170
|
const texts = rawTexts.map(text => text.length > exports.MAX_DENY_MATCH_TEXT_LENGTH ? text.slice(0, exports.MAX_DENY_MATCH_TEXT_LENGTH) : text);
|
|
131
171
|
for (const pattern of patterns) {
|
|
132
172
|
if (pattern.length > exports.MAX_DENY_PATTERN_LENGTH || !(0, auto_yes_config_1.validateStopPattern)(pattern).valid) {
|
|
@@ -143,7 +183,9 @@ function evaluateDenyPatterns(rawTexts, patterns) {
|
|
|
143
183
|
}
|
|
144
184
|
}
|
|
145
185
|
}
|
|
146
|
-
|
|
186
|
+
// Issue #3881: no pattern matched the heads, but a field's tail was never
|
|
187
|
+
// shown to them — evaluated over part of the request, which is no pass.
|
|
188
|
+
return headCut ? { outcome: 'unusable' } : { outcome: 'no-match' };
|
|
147
189
|
}
|
|
148
190
|
/**
|
|
149
191
|
* Decide whether the policy forbids answering, given the prompt type and the
|
|
@@ -169,8 +211,12 @@ function evaluateDenyPatterns(rawTexts, patterns) {
|
|
|
169
211
|
* pattern the contract may state.
|
|
170
212
|
*
|
|
171
213
|
* @param policy - Contract policy; null/undefined permits everything
|
|
214
|
+
* @param denySurfaceIncomplete - Issue #3881: the texts are known to be only
|
|
215
|
+
* part of what the prompt asks about (`approvalTargetCompleteness`), so a
|
|
216
|
+
* deny miss withholds as `deny-pattern-unusable`. The hook's structured call
|
|
217
|
+
* is whole and leaves it false.
|
|
172
218
|
*/
|
|
173
|
-
function evaluatePolicyAgainstTexts(promptType, denyMatchTexts, policy) {
|
|
219
|
+
function evaluatePolicyAgainstTexts(promptType, denyMatchTexts, policy, denySurfaceIncomplete = false) {
|
|
174
220
|
if (!policy)
|
|
175
221
|
return null;
|
|
176
222
|
if (isAutoYesPolicyUnknown(policy)) {
|
|
@@ -186,6 +232,18 @@ function evaluatePolicyAgainstTexts(promptType, denyMatchTexts, policy) {
|
|
|
186
232
|
if (deny.outcome === 'unusable') {
|
|
187
233
|
return { reason: 'deny-pattern-unusable', pattern: deny.pattern };
|
|
188
234
|
}
|
|
235
|
+
// Issue #3881 (H-3): no pattern matched, but the texts are not the whole
|
|
236
|
+
// request — the approval target's upward scan stopped at its line cap with
|
|
237
|
+
// rows above it, or (review P2-1) at the top of a capture that filled its
|
|
238
|
+
// window, and the command may start there. A miss on part of the
|
|
239
|
+
// request is not a pass: the patterns could not be evaluated against what
|
|
240
|
+
// the prompt asks, which is `deny-pattern-unusable`'s fail-closed case.
|
|
241
|
+
// Only when the contract lists patterns; with none there is nothing to miss.
|
|
242
|
+
// (A field cut at MAX_DENY_MATCH_TEXT_LENGTH is the same case, reported by
|
|
243
|
+
// evaluateDenyPatterns as `unusable` above.)
|
|
244
|
+
if (denySurfaceIncomplete && policy.denyPatterns.length > 0) {
|
|
245
|
+
return { reason: 'deny-pattern-unusable' };
|
|
246
|
+
}
|
|
189
247
|
if (policy.mode === 'safe') {
|
|
190
248
|
return promptType === 'yes_no' ? null : { reason: 'type-not-allowed' };
|
|
191
249
|
}
|
|
@@ -196,7 +254,9 @@ function evaluatePolicyAgainstTexts(promptType, denyMatchTexts, policy) {
|
|
|
196
254
|
}
|
|
197
255
|
/** {@link evaluatePolicyAgainstTexts} over a detected on-screen prompt. */
|
|
198
256
|
function evaluatePolicy(promptData, policy) {
|
|
199
|
-
return evaluatePolicyAgainstTexts(promptData.type, collectDenyMatchTexts(promptData), policy
|
|
257
|
+
return evaluatePolicyAgainstTexts(promptData.type, collectDenyMatchTexts(promptData), policy,
|
|
258
|
+
// Issue #3881: cut at the line cap, or at the top of a clipped capture.
|
|
259
|
+
promptData.approvalTargetCompleteness !== undefined);
|
|
200
260
|
}
|
|
201
261
|
/**
|
|
202
262
|
* Resolve the automatic answer, reporting whether a policy withheld it.
|
|
@@ -204,13 +264,27 @@ function evaluatePolicy(promptData, policy) {
|
|
|
204
264
|
* `suppressedBy` is set only when an answer was actually withheld, so the
|
|
205
265
|
* escalation log records real suppressions and not prompts the base rules were
|
|
206
266
|
* never going to answer anyway (an empty option list, an option that needs
|
|
207
|
-
* typing). Those still resolve to null, with `suppressedBy` null.
|
|
267
|
+
* typing). Those still resolve to null, with `suppressedBy` null. Issue #3822:
|
|
268
|
+
* a permission dialog with no single "allow this call once" row is a
|
|
269
|
+
* withholding (`allow-once-unidentified`) — it is a dialog Auto-Yes would have
|
|
270
|
+
* answered before, and the operator must be told why it stopped.
|
|
208
271
|
*
|
|
209
272
|
* @param promptData - Detected prompt
|
|
210
273
|
* @param policy - Contract auto-answer policy; omit for the unconstrained behaviour
|
|
274
|
+
* @param cliToolId - The tool that drew the prompt, whose permission rows are
|
|
275
|
+
* read (Issue #3822). Omitted, every measured tool's wording is read
|
|
276
|
+
* (`auto-yes-option-effect`), so a caller that does not know the tool still
|
|
277
|
+
* never picks a row that saves a rule or changes the mode.
|
|
278
|
+
* @param question - Issue #3863: given when the prompt is a question the
|
|
279
|
+
* `recommended` answer mode answers; the answer is then its recommended
|
|
280
|
+
* option (else its default). The contract is evaluated afterwards exactly
|
|
281
|
+
* as for any answer — on the prompt as read, whichever option was chosen.
|
|
211
282
|
*/
|
|
212
|
-
function resolveAutoAnswerWithPolicy(promptData, policy) {
|
|
213
|
-
const answer = resolveBaseAnswer(promptData);
|
|
283
|
+
function resolveAutoAnswerWithPolicy(promptData, policy, cliToolId, question) {
|
|
284
|
+
const { answer, withheldBy } = resolveBaseAnswer(promptData, cliToolId, question);
|
|
285
|
+
if (withheldBy) {
|
|
286
|
+
return { answer: null, suppressedBy: withheldBy };
|
|
287
|
+
}
|
|
214
288
|
if (answer === null) {
|
|
215
289
|
return { answer: null, suppressedBy: null };
|
|
216
290
|
}
|
|
@@ -225,8 +299,9 @@ function resolveAutoAnswerWithPolicy(promptData, policy) {
|
|
|
225
299
|
*
|
|
226
300
|
* @param promptData - Detected prompt
|
|
227
301
|
* @param policy - Contract auto-answer policy; omit for the unconstrained behaviour
|
|
302
|
+
* @param cliToolId - The tool that drew the prompt; see {@link resolveAutoAnswerWithPolicy}
|
|
228
303
|
* @returns The answer string to send, or null if auto-answer is not possible
|
|
229
304
|
*/
|
|
230
|
-
function resolveAutoAnswer(promptData, policy) {
|
|
231
|
-
return resolveAutoAnswerWithPolicy(promptData, policy).answer;
|
|
305
|
+
function resolveAutoAnswer(promptData, policy, cliToolId) {
|
|
306
|
+
return resolveAutoAnswerWithPolicy(promptData, policy, cliToolId).answer;
|
|
232
307
|
}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.NO_HOOK_RECEIPT_SUPPRESSION_REASON = exports.QUESTION_CONFIRM_PAGE_SUPPRESSION_REASON = exports.STARTUP_TRUST_UNHANDLED_SUPPRESSION_REASON = exports.PARTIAL_ANSWER_SUPPRESSION_REASON = exports.POLICY_LOOKUP_FAILED_SUPPRESSION_REASON = exports.CONTRACT_SUPPRESSION_REASONS = void 0;
|
|
3
|
+
exports.NO_HOOK_RECEIPT_SUPPRESSION_REASON = exports.RECOMMENDED_OPTION_UNIDENTIFIED_SUPPRESSION_REASON = exports.ALLOW_ONCE_UNIDENTIFIED_SUPPRESSION_REASON = exports.BASE_RULE_SUPPRESSION_REASONS = exports.QUESTION_LEFT_TO_HUMAN_SUPPRESSION_REASON = exports.QUESTION_CONFIRM_PAGE_SUPPRESSION_REASON = exports.STARTUP_TRUST_UNHANDLED_SUPPRESSION_REASON = exports.PARTIAL_ANSWER_SUPPRESSION_REASON = exports.POLICY_LOOKUP_FAILED_SUPPRESSION_REASON = exports.CONTRACT_SUPPRESSION_REASONS = void 0;
|
|
4
|
+
exports.isBaseRuleSuppressionReason = isBaseRuleSuppressionReason;
|
|
4
5
|
/**
|
|
5
6
|
* Issue #3796: the reasons `resolveAutoAnswerWithPolicy` returns — the contract's
|
|
6
7
|
* verdict on the prompt as it is NOW, which a later tick re-evaluates, as
|
|
7
|
-
* opposed to a reason that remembers an event (`partial-answer`).
|
|
8
|
+
* opposed to a reason that remembers an event (`partial-answer`). Issue #3822
|
|
9
|
+
* adds the base rules' one withholding, `allow-once-unidentified`, for the same
|
|
10
|
+
* reason.
|
|
8
11
|
*/
|
|
9
12
|
exports.CONTRACT_SUPPRESSION_REASONS = new Set([
|
|
10
13
|
'mode-off',
|
|
@@ -12,6 +15,11 @@ exports.CONTRACT_SUPPRESSION_REASONS = new Set([
|
|
|
12
15
|
'deny-pattern-unusable',
|
|
13
16
|
'type-not-allowed',
|
|
14
17
|
'policy-lookup-failed',
|
|
18
|
+
// Issue #3822: not the contract's, but the same kind of verdict — on the
|
|
19
|
+
// prompt as it is now, from `resolveAutoAnswerWithPolicy`, re-evaluated later.
|
|
20
|
+
'allow-once-unidentified',
|
|
21
|
+
// Issue #3863: likewise, over a question under the `recommended` answer mode.
|
|
22
|
+
'recommended-option-unidentified',
|
|
15
23
|
]);
|
|
16
24
|
/** Issue #3822: the reason recorded when the contract lookup failed. */
|
|
17
25
|
exports.POLICY_LOOKUP_FAILED_SUPPRESSION_REASON = 'policy-lookup-failed';
|
|
@@ -21,5 +29,28 @@ exports.PARTIAL_ANSWER_SUPPRESSION_REASON = 'partial-answer';
|
|
|
21
29
|
exports.STARTUP_TRUST_UNHANDLED_SUPPRESSION_REASON = 'startup-trust-unhandled';
|
|
22
30
|
/** Issue #3748: the reason the poller records over an `AskUserQuestion` confirm page. */
|
|
23
31
|
exports.QUESTION_CONFIRM_PAGE_SUPPRESSION_REASON = 'question-confirm-page';
|
|
32
|
+
/** Issue #3822: the reason the poller records over a question the tool asks the operator. */
|
|
33
|
+
exports.QUESTION_LEFT_TO_HUMAN_SUPPRESSION_REASON = 'question-left-to-human';
|
|
34
|
+
/**
|
|
35
|
+
* Issue #3822: the reasons `resolveAutoAnswerWithPolicy` returns from its base
|
|
36
|
+
* rules, before the contract is read. Every other reason it returns is the
|
|
37
|
+
* contract's verdict ({@link CONTRACT_SUPPRESSION_REASONS} holds both kinds:
|
|
38
|
+
* both are verdicts on the prompt as it is now). A reader that tells the
|
|
39
|
+
* operator what stopped the answer — the prompt observation, agy's withheld
|
|
40
|
+
* log line — must not send them to the contract for one of these.
|
|
41
|
+
*/
|
|
42
|
+
exports.BASE_RULE_SUPPRESSION_REASONS = new Set([
|
|
43
|
+
'allow-once-unidentified',
|
|
44
|
+
// Issue #3863: a question whose recommended option could not be told.
|
|
45
|
+
'recommended-option-unidentified',
|
|
46
|
+
]);
|
|
47
|
+
/** Whether `reason` is the base rules' withholding rather than the contract's (Issue #3822). */
|
|
48
|
+
function isBaseRuleSuppressionReason(reason) {
|
|
49
|
+
return exports.BASE_RULE_SUPPRESSION_REASONS.has(reason);
|
|
50
|
+
}
|
|
51
|
+
/** Issue #3822: the reason the resolver returns over a permission dialog with no single allow-once row. */
|
|
52
|
+
exports.ALLOW_ONCE_UNIDENTIFIED_SUPPRESSION_REASON = 'allow-once-unidentified';
|
|
53
|
+
/** Issue #3863: the reason the resolver returns over a question whose recommended option could not be told. */
|
|
54
|
+
exports.RECOMMENDED_OPTION_UNIDENTIFIED_SUPPRESSION_REASON = 'recommended-option-unidentified';
|
|
24
55
|
/** Issue #3767: the reason the poller records over an agy dialog with no matching hook receipt. */
|
|
25
56
|
exports.NO_HOOK_RECEIPT_SUPPRESSION_REASON = 'no-hook-receipt';
|
|
@@ -25,21 +25,30 @@
|
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.recordPolicySuppression = recordPolicySuppression;
|
|
27
27
|
exports.getLastPolicySuppression = getLastPolicySuppression;
|
|
28
|
+
exports.suppressionPredatesAnswer = suppressionPredatesAnswer;
|
|
28
29
|
exports.forgetPolicySuppression = forgetPolicySuppression;
|
|
29
30
|
exports.clearPolicySuppressions = clearPolicySuppressions;
|
|
30
31
|
const auto_yes_state_1 = require("../../lib/auto-yes-state");
|
|
31
32
|
const global_state_1 = require("../global-state");
|
|
33
|
+
const waiting_episode_state_1 = require("../session/waiting-episode-state");
|
|
32
34
|
/** compositeKey -> the most recent policy suppression for that session. */
|
|
33
35
|
const lastPolicySuppressions = (0, global_state_1.getOrInitGlobal)('__autoYesPolicySuppressions', () => new Map());
|
|
34
36
|
/**
|
|
35
37
|
* Record that the policy withheld an answer for `instanceId`'s current prompt.
|
|
36
38
|
*
|
|
39
|
+
* Issue #3798: the record names the waiting episode open for the instance at
|
|
40
|
+
* this moment — unless the caller names one (a record carried over for the
|
|
41
|
+
* same dialog) — so it is never taken for the reason of a later wait.
|
|
42
|
+
*
|
|
37
43
|
* @param at - Epoch ms; defaults to now. Overridable so tests are deterministic.
|
|
38
44
|
*/
|
|
39
45
|
function recordPolicySuppression(worktreeId, cliToolId, instanceId, suppression, at = Date.now()) {
|
|
46
|
+
const { episodeId: carried, ...rest } = suppression;
|
|
47
|
+
const episodeId = carried ?? (0, waiting_episode_state_1.getWaitingEpisodeRecord)(worktreeId, cliToolId, instanceId)?.episodeId;
|
|
40
48
|
lastPolicySuppressions.set((0, auto_yes_state_1.buildCompositeKey)(worktreeId, cliToolId, instanceId), {
|
|
41
|
-
...
|
|
49
|
+
...rest,
|
|
42
50
|
at,
|
|
51
|
+
...(episodeId !== undefined ? { episodeId } : {}),
|
|
43
52
|
});
|
|
44
53
|
}
|
|
45
54
|
/**
|
|
@@ -50,6 +59,21 @@ function recordPolicySuppression(worktreeId, cliToolId, instanceId, suppression,
|
|
|
50
59
|
function getLastPolicySuppression(worktreeId, cliToolId, instanceId) {
|
|
51
60
|
return lastPolicySuppressions.get((0, auto_yes_state_1.buildCompositeKey)(worktreeId, cliToolId, instanceId)) ?? null;
|
|
52
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* Whether the record is older than the Auto-Yes answer to the wait it would
|
|
64
|
+
* explain (Issue #3798): the poller's last answer (`lastAnswer`) went to
|
|
65
|
+
* `waitingEpisodeId`, the wait open now, after the record was written. The
|
|
66
|
+
* success path of a send does not clear the record — it stays as history —
|
|
67
|
+
* but the answer is the newer fact, so the record is not that wait's reason
|
|
68
|
+
* any more. The push gate and `current-output` (`lastSuppressionAnswered`,
|
|
69
|
+
* which `cmate wait` reads) both decide it here. A record written at or after
|
|
70
|
+
* the answer, an answer to another episode, no answer and no wait id are not.
|
|
71
|
+
*/
|
|
72
|
+
function suppressionPredatesAnswer(suppression, waitingEpisodeId, answer) {
|
|
73
|
+
if (waitingEpisodeId === null || waitingEpisodeId === undefined || answer === null)
|
|
74
|
+
return false;
|
|
75
|
+
return answer.episodeId === waitingEpisodeId && suppression.at < answer.at;
|
|
76
|
+
}
|
|
53
77
|
/**
|
|
54
78
|
* Drop the record of one session (Issue #3796): the reason it gives no longer
|
|
55
79
|
* holds for the prompt still on screen (the contract that withheld it changed),
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The one place a prompt's screen is read as a kind of dialog for storage
|
|
4
|
+
* (Issue #3881).
|
|
5
|
+
*
|
|
6
|
+
* The response poller saves a `prompt` row from a frame it has in hand; every
|
|
7
|
+
* later reader — the chat transcript above all — has only the row's cut-down
|
|
8
|
+
* `question` and `options`. Deciding "question, permission or confirmation
|
|
9
|
+
* page?" from those again is what drew Claude's 16-column confirm page as a
|
|
10
|
+
* tool approval: its option 1 wraps (`Submit` / `answers`), so the stored
|
|
11
|
+
* option is `Submit`, and the review list is above the five rows the stored
|
|
12
|
+
* question keeps. So the kind is read here, from the frame, with the same
|
|
13
|
+
* predicates the Auto-Yes poller acts on, and stored as `promptData.reading`.
|
|
14
|
+
*
|
|
15
|
+
* What is evidence, in order:
|
|
16
|
+
*
|
|
17
|
+
* 1. the tool's confirm-page reader (`isAutoYesDeclinedConfirmFrame`, the
|
|
18
|
+
* predicate behind the poller's `question-confirm-page`) — `confirmation`;
|
|
19
|
+
* 2. a question reader's picker chrome (`isAskUserQuestion`) — `question`;
|
|
20
|
+
* 3. rows that read as a permission dialog's effects
|
|
21
|
+
* (`selectAllowOnceOption`, the resolver's own reading) — `permission`;
|
|
22
|
+
* 4. a yes/no confirmation pattern — `permission`;
|
|
23
|
+
* 5. nothing — `unknown`, which is not "not a question".
|
|
24
|
+
*
|
|
25
|
+
* Server-only: the confirm-page reader reaches `logger` → `env` → `fs`. The
|
|
26
|
+
* client reads what this wrote through `lib/detection/prompt-reading`.
|
|
27
|
+
*
|
|
28
|
+
* The second half of #3881 added no evidence here, on purpose: agy's
|
|
29
|
+
* receipt-backed reply list and copilot's / codex's questions have none on
|
|
30
|
+
* their screens, and they read `unknown` here as they did. What changed is
|
|
31
|
+
* what the answering paths do with that absence — agy's reply list is not
|
|
32
|
+
* answered on a receipt alone (`response-checker-dialog-gate`'s
|
|
33
|
+
* `isAntigravityGenericReadingOnScreen`), and the `careful` answer mode
|
|
34
|
+
* leaves copilot's / codex's unidentified lists to a human
|
|
35
|
+
* (`classifyAutoYesQuestion`'s `unidentified`). New evidence, when a reader
|
|
36
|
+
* learns some, goes in here; `tests/unit/guards/prompt-reading-sites-3881.test.ts`
|
|
37
|
+
* keeps this the only place.
|
|
38
|
+
*
|
|
39
|
+
* @module lib/polling/prompt-screen-reading
|
|
40
|
+
*/
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.captureTopOf = captureTopOf;
|
|
43
|
+
exports.withCaptureTopCompleteness = withCaptureTopCompleteness;
|
|
44
|
+
exports.readPromptScreen = readPromptScreen;
|
|
45
|
+
exports.promptDataForStorage = promptDataForStorage;
|
|
46
|
+
const types_1 = require("../../lib/cli-tools/types");
|
|
47
|
+
const tmux_pane_config_1 = require("../../config/tmux-pane-config");
|
|
48
|
+
const cli_patterns_1 = require("../../lib/detection/cli-patterns");
|
|
49
|
+
const prompt_reading_1 = require("../../types/prompt-reading");
|
|
50
|
+
const auto_yes_confirm_page_1 = require("./auto-yes-confirm-page");
|
|
51
|
+
const auto_yes_option_effect_1 = require("./auto-yes-option-effect");
|
|
52
|
+
/**
|
|
53
|
+
* Where the first row of a capture sits in the pane (Issue #3881 review P2-1).
|
|
54
|
+
*
|
|
55
|
+
* Every capture is the last `windowLines` rows of the pane
|
|
56
|
+
* (`captureSessionOutput` → `sliceOutput`), so one that came back with fewer
|
|
57
|
+
* rows than its window holds the pane's whole history and its first row is
|
|
58
|
+
* the history's first; one that filled the window may have been cut there.
|
|
59
|
+
* The same test as `isCaptureWindowSaturated` (#1670) on the row count —
|
|
60
|
+
* restated, not imported: this module may not reach `tmux-capture-cache`
|
|
61
|
+
* (Issue #1922's import rule), and the equivalence is pinned by
|
|
62
|
+
* `tests/unit/lib/polling/prompt-reading-capture-top-3881.test.ts`.
|
|
63
|
+
*
|
|
64
|
+
* That holds for a scrollback pane only (the second review's N1). A tool in
|
|
65
|
+
* the alternate screen ({@link usesAlternateScreen}: claude, copilot,
|
|
66
|
+
* opencode) keeps no history, so its capture is the visible screen whatever
|
|
67
|
+
* the window, and "fewer rows than the window" says nothing about what the
|
|
68
|
+
* tool scrolled off. Its capture is read off the screen instead
|
|
69
|
+
* ({@link screenTopOf}), once the window is known not to have cut it.
|
|
70
|
+
*
|
|
71
|
+
* Whether it did (the third review's N4): the capture layer says so when the
|
|
72
|
+
* caller asks (`headCut`, the Auto-Yes poller's `capturePollerFrame`). The row
|
|
73
|
+
* count alone cannot tell at a window of exactly {@link TUI_PANE_HEIGHT} rows
|
|
74
|
+
* (the tallest alternate-screen pane, and the poller's REDUCED window): a
|
|
75
|
+
* whole 1000-row screen and a longer pane cut to its last 1000 rows come back
|
|
76
|
+
* the same size. Above that height it can: a cut capture has as many rows as
|
|
77
|
+
* its window, more than any alternate screen holds, and a capture that tall
|
|
78
|
+
* is a pane with history (the tool is not in the alternate screen), read as
|
|
79
|
+
* a scrollback pane. At or below it, a capture that filled its window is
|
|
80
|
+
* `clipped` unless the capture layer said otherwise (`headCut === false`):
|
|
81
|
+
* #3881's second half (review (5b)) took away the 1000-row exception, where
|
|
82
|
+
* an unreported cut on a window of exactly {@link TUI_PANE_HEIGHT} rows was
|
|
83
|
+
* read off the screen — blank first and last rows are what a longer pane cut
|
|
84
|
+
* to its last 1000 rows can show too, so they cannot stand in for the capture
|
|
85
|
+
* layer's word. `undefined` (not reported) and `false` (reported whole) are
|
|
86
|
+
* two answers, not one.
|
|
87
|
+
*
|
|
88
|
+
* And the capture layer's word decides on a scrollback pane too (the fourth
|
|
89
|
+
* review's N5). `headCut === false` is a known whole history, not an unknown
|
|
90
|
+
* top: tmux returned `min(history, N)` history rows plus the visible pane for
|
|
91
|
+
* a `-S -N`, so a capture it cut has more rows than any window it serves and
|
|
92
|
+
* the slice cuts it too — a capture the slice did not cut is everything from
|
|
93
|
+
* the history's first row. Only without that word is a capture that filled
|
|
94
|
+
* its window `clipped`; "filled" is counted in rows ({@link screenRowsOf}),
|
|
95
|
+
* so a trailing newline does not turn a 999-row capture into a full
|
|
96
|
+
* 1000-row window.
|
|
97
|
+
*
|
|
98
|
+
* @param capture - The capture as returned (or its cleaned spelling: same rows)
|
|
99
|
+
* @param windowLines - The window it was captured with
|
|
100
|
+
* @param cliToolId - The tool whose pane it is; omitted, the pane is read as a
|
|
101
|
+
* scrollback pane (the reading before N1)
|
|
102
|
+
* @param headCut - Whether the window dropped rows from the top of what tmux
|
|
103
|
+
* returned, when the capture layer said; omitted, judged from the row count
|
|
104
|
+
*/
|
|
105
|
+
function captureTopOf(capture, windowLines, cliToolId, headCut) {
|
|
106
|
+
if (headCut === true)
|
|
107
|
+
return 'clipped';
|
|
108
|
+
const rows = screenRowsOf(capture).length;
|
|
109
|
+
const filled = windowLines > 0 && rows >= windowLines;
|
|
110
|
+
// A known whole history (`headCut === false`) wins over a full window.
|
|
111
|
+
const historyTop = filled && headCut === undefined ? 'clipped' : 'history-start';
|
|
112
|
+
if (cliToolId === undefined || !(0, types_1.usesAlternateScreen)(cliToolId))
|
|
113
|
+
return historyTop;
|
|
114
|
+
if (rows > tmux_pane_config_1.TUI_PANE_HEIGHT)
|
|
115
|
+
return historyTop;
|
|
116
|
+
// Not reported, and the window was filled: nothing says the top was not cut.
|
|
117
|
+
if (headCut === undefined && filled)
|
|
118
|
+
return 'clipped';
|
|
119
|
+
return screenTopOf(capture);
|
|
120
|
+
}
|
|
121
|
+
/** A capture's rows: tmux ends every row with a newline, and the last one is not a row of its own. */
|
|
122
|
+
function screenRowsOf(capture) {
|
|
123
|
+
return (capture.endsWith('\n') ? capture.slice(0, -1) : capture).split('\n');
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* An alternate-screen capture taken whole: does its content begin at the top
|
|
127
|
+
* of what the tool drew? These tools lay their content out from the screen's
|
|
128
|
+
* top down (a fresh 1000-row claude pane is a blank margin row, the banner,
|
|
129
|
+
* the turn, and blank rows to the bottom — `tests/fixtures/
|
|
130
|
+
* claude-confirm-live-3791/`), and one whose content outgrew the screen
|
|
131
|
+
* scrolls it: then the content reaches the bottom row
|
|
132
|
+
* (`head-cut-200x12.txt`), and the rows that left the top are gone. So the
|
|
133
|
+
* first row is the content's own only when the screen shows both its top
|
|
134
|
+
* margin (a blank first row) and room below (a blank last row); anything else
|
|
135
|
+
* — a content row at either edge — is `screen-full`, which is the side that
|
|
136
|
+
* withholds an answer rather than gives one.
|
|
137
|
+
*/
|
|
138
|
+
function screenTopOf(capture) {
|
|
139
|
+
const rows = screenRowsOf(capture);
|
|
140
|
+
const blank = (row) => row === undefined || (0, cli_patterns_1.stripAnsi)(row).trim() === '';
|
|
141
|
+
return rows.length > 1 && blank(rows[0]) && blank(rows[rows.length - 1]) ? 'screen-start' : 'screen-full';
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* The detection with `approvalTargetCompleteness: 'top-unknown'` on its prompt
|
|
145
|
+
* when the target's upward scan reached the frame's first row without a
|
|
146
|
+
* boundary and that row is not known to be the top of the pane's history
|
|
147
|
+
* (Issue #3881 review P2-1). Before this, `top-unknown` stayed on the
|
|
148
|
+
* detection only and the resolver read such a target as complete: a confirm
|
|
149
|
+
* whose command began above the capture, and whose rest fell within 12 rows,
|
|
150
|
+
* was answered under a contract that denies the command.
|
|
151
|
+
*
|
|
152
|
+
* A capture whose first row is where the pane's content begins
|
|
153
|
+
* (`history-start`, or `screen-start` on the alternate screen) leaves the
|
|
154
|
+
* detection as it is.
|
|
155
|
+
* Blank-row compaction during detection removes no non-blank row, so it does
|
|
156
|
+
* not change which of the two a frame is.
|
|
157
|
+
*
|
|
158
|
+
* @param detection - The tick's detection of the capture
|
|
159
|
+
* @param captureTop - Where the capture's first row sits ({@link CaptureTop}),
|
|
160
|
+
* judged by the caller that knows its window ({@link captureTopOf})
|
|
161
|
+
*/
|
|
162
|
+
function withCaptureTopCompleteness(detection, captureTop) {
|
|
163
|
+
const promptData = detection.promptData;
|
|
164
|
+
if (!promptData ||
|
|
165
|
+
promptData.approvalTarget === undefined ||
|
|
166
|
+
promptData.approvalTargetCompleteness !== undefined ||
|
|
167
|
+
detection.approvalContext?.completeness !== 'top-unknown' ||
|
|
168
|
+
!captureTopMayBeCut(captureTop)) {
|
|
169
|
+
return detection;
|
|
170
|
+
}
|
|
171
|
+
return { ...detection, promptData: { ...promptData, approvalTargetCompleteness: 'top-unknown' } };
|
|
172
|
+
}
|
|
173
|
+
/** Whether rows may be missing above a capture's first row ({@link CaptureTop}). */
|
|
174
|
+
function captureTopMayBeCut(captureTop) {
|
|
175
|
+
return captureTop === 'clipped' || captureTop === 'screen-full';
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Read the prompt's screen as a kind of dialog.
|
|
179
|
+
*
|
|
180
|
+
* @param cliToolId - The tool that drew the frame
|
|
181
|
+
* @param frame - The capture the prompt was detected on (ANSI and box drawing
|
|
182
|
+
* as captured), or the tick's own `normalizeFrame` of it — the Auto-Yes
|
|
183
|
+
* poller passes that, so a tick still normalises its capture once (#3183) —
|
|
184
|
+
* or null when the caller has none: then no confirm page can be read off it
|
|
185
|
+
* @param detection - The detection of that frame
|
|
186
|
+
* @param captureTop - Where `frame`'s first row sits in the pane, when the
|
|
187
|
+
* caller knows its capture window (Issue #3881 review P2-1)
|
|
188
|
+
* @returns The reading, or null when the detection carries no prompt
|
|
189
|
+
*/
|
|
190
|
+
function readPromptScreen(cliToolId, frame, detection, captureTop) {
|
|
191
|
+
const promptData = detection.promptData;
|
|
192
|
+
if (!promptData)
|
|
193
|
+
return null;
|
|
194
|
+
const context = detection.approvalContext;
|
|
195
|
+
const base = {
|
|
196
|
+
version: prompt_reading_1.PROMPT_READING_VERSION,
|
|
197
|
+
...(context ? { liveRange: { startRow: context.startRow, endRow: context.endRow } } : {}),
|
|
198
|
+
approvalTarget: context?.completeness ?? 'not-measured',
|
|
199
|
+
...(captureTop !== undefined ? { captureTop } : {}),
|
|
200
|
+
};
|
|
201
|
+
const confirmPage = typeof frame === 'object' && frame !== null
|
|
202
|
+
? (0, auto_yes_confirm_page_1.isAutoYesDeclinedConfirmPage)(cliToolId, frame)
|
|
203
|
+
: (0, auto_yes_confirm_page_1.isAutoYesDeclinedConfirmFrame)(cliToolId, frame);
|
|
204
|
+
if (confirmPage) {
|
|
205
|
+
return { ...base, kind: 'confirmation', phase: 'confirmation', evidence: ['confirm-page-reader'] };
|
|
206
|
+
}
|
|
207
|
+
if (promptData.type === 'multiple_choice' && promptData.isAskUserQuestion === true) {
|
|
208
|
+
const evidence = ['question-picker-chrome'];
|
|
209
|
+
if (promptData.askUserQuestion !== undefined)
|
|
210
|
+
evidence.push('ask-user-question-payload');
|
|
211
|
+
return { ...base, kind: 'question', phase: 'question', evidence };
|
|
212
|
+
}
|
|
213
|
+
if (promptData.type === 'multiple_choice') {
|
|
214
|
+
return (0, auto_yes_option_effect_1.selectAllowOnceOption)(promptData.options, cliToolId).kind === 'not-a-permission-dialog'
|
|
215
|
+
? { ...base, kind: 'unknown', evidence: [] }
|
|
216
|
+
: { ...base, kind: 'permission', evidence: ['permission-option-effect'] };
|
|
217
|
+
}
|
|
218
|
+
return { ...base, kind: 'permission', evidence: ['yes-no-pattern'] };
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* The `promptData` a `prompt` row is saved with: the detection's, with what
|
|
222
|
+
* {@link readPromptScreen} read stored beside it. Undefined when the detection
|
|
223
|
+
* carries none, exactly as before. Both writers of a new `prompt` row from a
|
|
224
|
+
* frame use it: the response poller's save, and (review P2-2) the Auto-Yes
|
|
225
|
+
* poller's audit row when it answers before any row was saved.
|
|
226
|
+
*/
|
|
227
|
+
function promptDataForStorage(cliToolId, frame, detection, captureTop) {
|
|
228
|
+
const reading = readPromptScreen(cliToolId, frame, detection, captureTop);
|
|
229
|
+
if (!detection.promptData || reading === null)
|
|
230
|
+
return detection.promptData;
|
|
231
|
+
return { ...detection.promptData, reading };
|
|
232
|
+
}
|