commandmate 0.33.3 → 0.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-build-manifest.json +146 -146
- package/.next/app-path-routes-manifest.json +29 -29
- 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/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/session/route.js +1 -1
- package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/start/route.js +2 -2
- package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/terminal/route.js +3 -3
- package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route.js +1 -1
- package/.next/server/app/api/relays/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route.js +1 -1
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route_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/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_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.js +2 -2
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_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/chat/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +8 -8
- 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 +29 -29
- package/.next/server/chunks/1049.js +1 -0
- package/.next/server/chunks/1501.js +4 -4
- package/.next/server/chunks/1886.js +2 -2
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/3241.js +1 -1
- package/.next/server/chunks/3323.js +1 -1
- package/.next/server/chunks/3480.js +2 -2
- package/.next/server/chunks/4443.js +1 -1
- package/.next/server/chunks/4802.js +1 -1
- package/.next/server/chunks/5164.js +1 -1
- package/.next/server/chunks/5571.js +1 -1
- package/.next/server/chunks/595.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6285.js +1 -1
- package/.next/server/chunks/6286.js +7 -7
- package/.next/server/chunks/6337.js +1 -1
- package/.next/server/chunks/650.js +1 -1
- package/.next/server/chunks/663.js +1 -1
- package/.next/server/chunks/6677.js +25 -0
- package/.next/server/chunks/7075.js +1 -0
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8583.js +1 -0
- package/.next/server/chunks/8918.js +4 -2
- package/.next/server/chunks/9080.js +1 -0
- package/.next/server/chunks/964.js +1 -0
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/2053-9ac860ab4e92ac89.js +1 -0
- package/.next/static/chunks/2652-18b8fea64413467e.js +1 -0
- package/.next/static/chunks/{4718-814f4ecfd7fcc513.js → 4718-2d9f0397a8f931c4.js} +1 -1
- package/.next/static/chunks/{8361-9bb887203c456edb.js → 8361-0142beb59be2abf3.js} +1 -1
- package/.next/static/chunks/app/{page-022090bf6f932818.js → page-26a42881c8648cd3.js} +1 -1
- package/.next/static/chunks/app/sessions/page-a3ab6f122ec60d5a.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-a39ec2a0732d11a6.js +1 -0
- package/.next/static/css/b09bede85744e1cf.css +1 -0
- package/.next/trace +13 -13
- package/dist/cli/commands/ask.d.ts.map +1 -1
- package/dist/cli/commands/ask.js +11 -2
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +8 -4
- package/dist/cli/commands/send.d.ts.map +1 -1
- package/dist/cli/commands/send.js +18 -0
- package/dist/cli/commands/wait.d.ts +18 -3
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +137 -2
- package/dist/cli/docs/agent-operations.d.ts +2 -2
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +41 -1
- package/dist/cli/utils/session-target.d.ts +23 -6
- package/dist/cli/utils/session-target.d.ts.map +1 -1
- package/dist/cli/utils/session-target.js +33 -5
- package/dist/server/locales/en/worktree.json +21 -2
- package/dist/server/locales/ja/worktree.json +21 -2
- package/dist/server/src/config/schedule-config.js +45 -3
- package/dist/server/src/lib/cli-tools/antigravity.js +95 -10
- package/dist/server/src/lib/cli-tools/submit-verified-sender.js +377 -16
- package/dist/server/src/lib/cmate-parser.js +8 -1
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +140 -19
- package/dist/server/src/lib/detection/tools/claude/detect.js +13 -2
- package/dist/server/src/lib/detection/tools/claude/picker-chrome.js +239 -0
- package/dist/server/src/lib/detection/tools/claude/prompt.js +74 -6
- package/dist/server/src/lib/hooks/sources/claude/history.js +391 -34
- package/dist/server/src/lib/hooks/sources/claude/transcript.js +91 -0
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +114 -11
- package/dist/server/src/lib/polling/response-checker.js +82 -3
- package/dist/server/src/lib/schedule-manager.js +178 -19
- package/dist/server/src/lib/session/ask-user-question-prompt.js +4 -2
- package/dist/server/src/lib/session/claude-executor.js +33 -2
- package/dist/server/src/lib/session/resolve-session-target.js +37 -9
- package/dist/server/src/lib/verification/env-clean-gate.js +81 -4
- package/dist/server/src/types/agent-transcript.js +143 -1
- package/package.json +1 -1
- package/.next/server/chunks/1068.js +0 -1
- package/.next/server/chunks/6808.js +0 -1
- package/.next/server/chunks/7875.js +0 -25
- package/.next/server/chunks/9553.js +0 -1
- package/.next/static/chunks/2053-3f299a7a2c7d6767.js +0 -1
- package/.next/static/chunks/8772-9be53a530950d804.js +0 -1
- package/.next/static/chunks/app/sessions/page-584adf11ae51df10.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-3af707e74a75172b.js +0 -1
- package/.next/static/css/acd46e25427a2080.css +0 -1
- /package/.next/static/{9x6U1h52hH_r6pOsGwI_p → gniPBCKoXtbIOQey8kNcx}/_buildManifest.js +0 -0
- /package/.next/static/{9x6U1h52hH_r6pOsGwI_p → gniPBCKoXtbIOQey8kNcx}/_ssgManifest.js +0 -0
|
@@ -54,9 +54,11 @@
|
|
|
54
54
|
* @module lib/polling/auto-yes-dialog-gate
|
|
55
55
|
*/
|
|
56
56
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
57
|
-
exports.AUTO_YES_DIALOG_GATE_ENV_VAR = exports.AUTO_YES_DIALOG_GATE_DEFAULT_MODE = exports.AUTO_YES_DIALOG_GATE_MODES = void 0;
|
|
57
|
+
exports.UNSUPPORTED_DIALOG_LAYOUT_REASON = exports.PROMPT_NO_LONGER_ACTIVE_REASON = exports.AUTO_YES_DIALOG_GATE_ENV_VAR = exports.AUTO_YES_DIALOG_GATE_DEFAULT_MODE = exports.AUTO_YES_DIALOG_GATE_MODES = void 0;
|
|
58
58
|
exports.resolveAutoYesDialogGateMode = resolveAutoYesDialogGateMode;
|
|
59
59
|
exports.evaluateAutoYesDialogGate = evaluateAutoYesDialogGate;
|
|
60
|
+
exports.evaluateDialogPresence = evaluateDialogPresence;
|
|
61
|
+
exports.judgePromptResponse = judgePromptResponse;
|
|
60
62
|
const frame_1 = require("../../lib/detection/tools/frame");
|
|
61
63
|
const registry_1 = require("../../lib/detection/tools/registry");
|
|
62
64
|
/** Every accepted value of {@link AutoYesDialogGateMode}, for parsing and tests. */
|
|
@@ -168,23 +170,124 @@ const GATED_PROMPT_TYPE = 'multiple_choice';
|
|
|
168
170
|
* @param env - Environment to read the kill switch from; injectable for tests
|
|
169
171
|
*/
|
|
170
172
|
function evaluateAutoYesDialogGate(cliToolId, promptType, cleanOutput, env = process.env) {
|
|
171
|
-
const detector = (0, registry_1.getToolStatusDetector)(cliToolId);
|
|
172
|
-
const mode = resolveAutoYesDialogGateMode(cliToolId, env);
|
|
173
173
|
// A tool nobody has measured is not gated whatever the table says. Belt and
|
|
174
174
|
// braces on purpose: the failure mode of getting this wrong is Auto-Yes going
|
|
175
175
|
// permanently silent for that tool, which looks exactly like a hung worker.
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
176
|
+
// `judgeDialogPresence` holds that rule; Issue #2457 split it out so the
|
|
177
|
+
// history-save and `/prompt-response` paths judge a frame the same way this
|
|
178
|
+
// one does instead of re-deriving the rollout table.
|
|
179
|
+
const presence = judgeDialogPresence(cliToolId, promptType, cleanOutput, resolveAutoYesDialogGateMode(cliToolId, env));
|
|
180
180
|
return {
|
|
181
181
|
// `keys` is a dialog and still not answerable: opencode's button strip takes
|
|
182
182
|
// ←/→ + Enter, so the digit is swallowed and the Enter confirms whatever is
|
|
183
183
|
// highlighted — asking to Reject would Approve (#1893). Sending nothing is
|
|
184
184
|
// the only safe answer, and `wait` still stops for the frame.
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
185
|
+
//
|
|
186
|
+
// Issue #2457: this extra test is what makes `allowed` unusable as an
|
|
187
|
+
// "is there a dialog here?" answer, and why the save path reads
|
|
188
|
+
// {@link evaluateDialogPresence} instead.
|
|
189
|
+
allowed: presence.gated
|
|
190
|
+
? presence.dialog !== null && presence.dialog.answerMode === 'numbered'
|
|
191
|
+
: true,
|
|
192
|
+
dialog: presence.dialog,
|
|
193
|
+
mode: presence.mode,
|
|
194
|
+
gated: presence.gated,
|
|
189
195
|
};
|
|
190
196
|
}
|
|
197
|
+
/** The one reading of a frame both gates share. `mode` is resolved by the caller. */
|
|
198
|
+
function judgeDialogPresence(cliToolId, promptType, frame, mode) {
|
|
199
|
+
const detector = (0, registry_1.getToolStatusDetector)(cliToolId);
|
|
200
|
+
if (promptType !== GATED_PROMPT_TYPE || !detector.hasDialogRules || mode === 'legacy') {
|
|
201
|
+
return { present: true, dialog: null, mode, gated: false };
|
|
202
|
+
}
|
|
203
|
+
const dialog = detector.detectDialog((0, frame_1.normalizeFrame)(frame));
|
|
204
|
+
return { present: dialog !== null, dialog, mode, gated: true };
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Does this frame POSITIVELY carry a dialog for the numbered-list candidate the
|
|
208
|
+
* generic parser found on it? (Issue #2457)
|
|
209
|
+
*
|
|
210
|
+
* The same rollout table, the same `hasDialogRules` cross-check and the same
|
|
211
|
+
* `detectDialog` seam Auto-Yes reads — and deliberately NOT the same env var.
|
|
212
|
+
* `CM_AUTOYES_DIALOG_GATE` is the kill switch for *answering* prompts without a
|
|
213
|
+
* human: an operator who sets it because their unattended pipeline stopped
|
|
214
|
+
* replying is saying nothing at all about which rows belong in History, and
|
|
215
|
+
* letting that flag also decide what gets stored would make the chat surface's
|
|
216
|
+
* contents depend on an Auto-Yes setting. So this reads
|
|
217
|
+
* {@link AUTO_YES_DIALOG_GATE_DEFAULT_MODE} directly.
|
|
218
|
+
*
|
|
219
|
+
* Auto-Yes being enabled or disabled is likewise not a condition here: the false
|
|
220
|
+
* `1. / 2. / 3.` row #2457 reported was saved by the response poller, which runs
|
|
221
|
+
* for every session whether or not anything is auto-answering it.
|
|
222
|
+
*
|
|
223
|
+
* @param cliToolId - CLI tool the frame came from
|
|
224
|
+
* @param promptType - How the generic parser classified the frame; anything but
|
|
225
|
+
* `multiple_choice` is left alone (see the module docstring on `yes_no`)
|
|
226
|
+
* @param frame - The WHOLE capture the candidate was read off, **as captured**.
|
|
227
|
+
* Never the extracted response, the question alone or a tail window: the rules
|
|
228
|
+
* `detectDialog` applies are about where the block sits in the pane, so a
|
|
229
|
+
* fragment answers a different question from the one being asked.
|
|
230
|
+
*
|
|
231
|
+
* And never a `stripBoxDrawing`-ed string, which is the one place this differs
|
|
232
|
+
* from {@link evaluateAutoYesDialogGate}. That function is handed the spelling
|
|
233
|
+
* Auto-Yes already had in hand (`captureAndCleanOutput`); this one is handed
|
|
234
|
+
* the capture, because that is the spelling on which ALL FOUR gated tools have
|
|
235
|
+
* working rules. opencode is the proof and it is already documented in
|
|
236
|
+
* `tests/unit/detection/tools/dialogs.test.ts`: its permission strip is
|
|
237
|
+
* anchored on the input box's own gutter (#1893's anchor, which must not be
|
|
238
|
+
* weakened), so with the box drawing removed its live dialog reads as `null`.
|
|
239
|
+
* For Auto-Yes `null` and `keys` both mean "send nothing" and the difference
|
|
240
|
+
* is invisible; here `null` would mean "there is no prompt on this screen",
|
|
241
|
+
* which about an open approval is simply false. `normalizeFrame` runs
|
|
242
|
+
* `stripAnsi` itself and each tool's rule applies `stripBoxDrawing` where it
|
|
243
|
+
* needs it, so nothing is lost by handing over the capture — and
|
|
244
|
+
* `stripBoxDrawing` never runs twice over the same row.
|
|
245
|
+
*/
|
|
246
|
+
function evaluateDialogPresence(cliToolId, promptType, frame) {
|
|
247
|
+
return judgeDialogPresence(cliToolId, promptType, frame, exports.AUTO_YES_DIALOG_GATE_DEFAULT_MODE[cliToolId] ?? 'legacy');
|
|
248
|
+
}
|
|
249
|
+
/** `/prompt-response`'s refusal when the prompt it was asked to answer is gone. */
|
|
250
|
+
exports.PROMPT_NO_LONGER_ACTIVE_REASON = 'prompt_no_longer_active';
|
|
251
|
+
/**
|
|
252
|
+
* `/prompt-response`'s refusal when an AskUserQuestion picker IS on screen but
|
|
253
|
+
* the tool's own dialog rule could not vouch for it (Issue #2486).
|
|
254
|
+
*/
|
|
255
|
+
exports.UNSUPPORTED_DIALOG_LAYOUT_REASON = 'unsupported_dialog_layout';
|
|
256
|
+
/**
|
|
257
|
+
* Fixed text, never quoting the answer (SEC-003, as in `prompt-answer-semantic`),
|
|
258
|
+
* so it is safe to return to a client verbatim.
|
|
259
|
+
*/
|
|
260
|
+
const UNSUPPORTED_DIALOG_LAYOUT_MESSAGE = 'An AskUserQuestion picker is on screen, but its layout could not be verified as one of the ' +
|
|
261
|
+
"agent's dialogs, so no key was sent. Answer it in the terminal, or retry once the screen has settled.";
|
|
262
|
+
/**
|
|
263
|
+
* May `/prompt-response` answer this frame? Null when it may; otherwise why not
|
|
264
|
+
* (Issue #2486).
|
|
265
|
+
*
|
|
266
|
+
* The route has refused whenever the generic parser found no prompt OR the gate
|
|
267
|
+
* could not vouch for the one it found (#161, #2457), and it called both
|
|
268
|
+
* `prompt_no_longer_active`. For the second half that was sometimes false: in
|
|
269
|
+
* #2486 an AskUserQuestion picker with a preview pane was open on screen, `wait`
|
|
270
|
+
* had just exited 10 for it, and `respond` said the prompt was gone. The two
|
|
271
|
+
* cases need different next steps — retry versus answer at the pane — so they
|
|
272
|
+
* get different reasons.
|
|
273
|
+
*
|
|
274
|
+
* The evidence for "a picker IS on screen" is the picker's own footer
|
|
275
|
+
* (`Enter to select · … navigate`, which sets `isAskUserQuestion`), not the
|
|
276
|
+
* parser's candidate alone: #2457's reply frames are candidates too, and for
|
|
277
|
+
* them `prompt_no_longer_active` stays the answer.
|
|
278
|
+
*
|
|
279
|
+
* @param promptCheck - What the generic parser (or agy's reader) found on the frame
|
|
280
|
+
* @param presence - {@link evaluateDialogPresence} for the same frame
|
|
281
|
+
*/
|
|
282
|
+
function judgePromptResponse(promptCheck, presence) {
|
|
283
|
+
if (promptCheck.isPrompt && presence.present)
|
|
284
|
+
return null;
|
|
285
|
+
const promptData = promptCheck.promptData;
|
|
286
|
+
if (promptCheck.isPrompt &&
|
|
287
|
+
presence.gated &&
|
|
288
|
+
promptData?.type === 'multiple_choice' &&
|
|
289
|
+
promptData.isAskUserQuestion === true) {
|
|
290
|
+
return { reason: exports.UNSUPPORTED_DIALOG_LAYOUT_REASON, message: UNSUPPORTED_DIALOG_LAYOUT_MESSAGE };
|
|
291
|
+
}
|
|
292
|
+
return { reason: exports.PROMPT_NO_LONGER_ACTIVE_REASON };
|
|
293
|
+
}
|
|
@@ -5,6 +5,7 @@ exports.PENDING_SCRAPE_HOLD_MS = void 0;
|
|
|
5
5
|
exports.incompleteResult = incompleteResult;
|
|
6
6
|
exports.buildPromptExtractionResult = buildPromptExtractionResult;
|
|
7
7
|
exports.detectPromptOnCleanFrame = detectPromptOnCleanFrame;
|
|
8
|
+
exports.isNumberedDialogVouched = isNumberedDialogVouched;
|
|
8
9
|
exports.detectPromptWithOptions = detectPromptWithOptions;
|
|
9
10
|
exports.extractResponse = extractResponse;
|
|
10
11
|
exports.resetPendingScrapedResponses = resetPendingScrapedResponses;
|
|
@@ -31,6 +32,10 @@ const response_cleaner_1 = require("../response-cleaner");
|
|
|
31
32
|
const copilot_constants_1 = require("../../config/copilot-constants");
|
|
32
33
|
const tui_accumulator_1 = require("../tui-accumulator");
|
|
33
34
|
const prompt_dedup_1 = require("./prompt-dedup");
|
|
35
|
+
// Issue #2457: the same rollout table, `hasDialogRules` cross-check and
|
|
36
|
+
// `detectDialog` seam Auto-Yes reads, reached through the presence helper rather
|
|
37
|
+
// than through `evaluateAutoYesDialogGate` — see `isNumberedDialogVouched`.
|
|
38
|
+
const auto_yes_dialog_gate_1 = require("./auto-yes-dialog-gate");
|
|
34
39
|
const prompt_dedup_state_1 = require("./prompt-dedup-state");
|
|
35
40
|
const response_dedup_1 = require("./response-dedup");
|
|
36
41
|
const structured_history_gate_1 = require("./structured-history-gate");
|
|
@@ -230,6 +235,55 @@ function detectPromptOnCleanFrame(cleanOutput, cliToolId, precomputedLines) {
|
|
|
230
235
|
const promptOptions = (0, cli_patterns_1.buildDetectPromptOptions)(cliToolId);
|
|
231
236
|
return (0, prompt_detector_1.detectPrompt)(cleanOutput, precomputedLines ? { ...promptOptions, precomputedLines } : promptOptions);
|
|
232
237
|
}
|
|
238
|
+
/**
|
|
239
|
+
* Is the generic parser's numbered-list candidate a dialog the tool vouches for?
|
|
240
|
+
* (Issue #2457)
|
|
241
|
+
*
|
|
242
|
+
* ## The candidate this removes
|
|
243
|
+
*
|
|
244
|
+
* `detectPrompt` classifies a frame as `multiple_choice` from the ROWS alone,
|
|
245
|
+
* and for Claude `buildDetectPromptOptions` returns
|
|
246
|
+
* `requireDefaultIndicator: false` — so a reply that happens to answer in
|
|
247
|
+
* Markdown ("1. … 2. … 3. …") is a candidate with no `❯` anywhere near it.
|
|
248
|
+
* Every one of those was stored as a `prompt` message, and the chat surface drew
|
|
249
|
+
* a tool-approval chip over an ordinary answer.
|
|
250
|
+
*
|
|
251
|
+
* ## Why the whole frame, and only the frame
|
|
252
|
+
*
|
|
253
|
+
* `detectDialog` decides by POSITION and CHROME — where the option block sits
|
|
254
|
+
* relative to the transcript tail, what (if anything) is drawn under it. None of
|
|
255
|
+
* that survives being handed the extracted response, the question string or a
|
|
256
|
+
* tail window, so the caller passes the same capture the candidate came off, as
|
|
257
|
+
* captured: `evaluateDialogPresence` documents why the box drawing must still be
|
|
258
|
+
* on it.
|
|
259
|
+
*
|
|
260
|
+
* ## What a `false` means downstream
|
|
261
|
+
*
|
|
262
|
+
* Not "there is no output here" — only "this is not a prompt". The caller falls
|
|
263
|
+
* through to the ordinary completion/partial reading, so a real reply is still
|
|
264
|
+
* saved by the normal path and a half-written one still reports
|
|
265
|
+
* `isComplete: false`.
|
|
266
|
+
*
|
|
267
|
+
* @param cliToolId - CLI tool the frame came from
|
|
268
|
+
* @param promptDetection - What the generic parser (or a tool reader) answered
|
|
269
|
+
* @param frame - The whole capture this tick made, as captured
|
|
270
|
+
* @returns True when the candidate may be treated as a live prompt
|
|
271
|
+
*/
|
|
272
|
+
function isNumberedDialogVouched(cliToolId, promptDetection, frame) {
|
|
273
|
+
const presence = (0, auto_yes_dialog_gate_1.evaluateDialogPresence)(cliToolId, promptDetection.promptData?.type, frame);
|
|
274
|
+
if (presence.present)
|
|
275
|
+
return true;
|
|
276
|
+
// `debug`, not `info`: the poller re-reads a static idle pane every 2s, so a
|
|
277
|
+
// reply carrying a numbered list would print this on every tick for as long as
|
|
278
|
+
// it stays on screen. The suppression is not silent where it matters — nothing
|
|
279
|
+
// is stored, so History simply shows the reply the ordinary path saves.
|
|
280
|
+
logger.debug('prompt-candidate-not-vouched', {
|
|
281
|
+
cliToolId,
|
|
282
|
+
promptType: promptDetection.promptData?.type,
|
|
283
|
+
gateMode: presence.mode,
|
|
284
|
+
});
|
|
285
|
+
return false;
|
|
286
|
+
}
|
|
233
287
|
/**
|
|
234
288
|
* Internal helper: detect prompt with CLI-tool-specific options.
|
|
235
289
|
*
|
|
@@ -432,7 +486,13 @@ function extractResponse(output, lastCapturedLine, cliToolId, captureWindowLines
|
|
|
432
486
|
cliToolId === 'command-code') {
|
|
433
487
|
const fullOutput = lines.join('\n');
|
|
434
488
|
const promptDetection = detectPromptWithOptions(fullOutput, cliToolId);
|
|
435
|
-
|
|
489
|
+
// Issue #2457: a candidate the tool's own rules cannot vouch for is not a
|
|
490
|
+
// prompt, and returning here would declare the turn finished ON IT — the
|
|
491
|
+
// early-completion half of the defect. Falling through leaves the ordinary
|
|
492
|
+
// completion/partial reading to answer, which is what a reply containing a
|
|
493
|
+
// numbered list needs. The gate is handed `fullOutput`, the capture itself,
|
|
494
|
+
// not the string `detectPromptWithOptions` cleaned for the parser.
|
|
495
|
+
if (promptDetection.isPrompt && isNumberedDialogVouched(cliToolId, promptDetection, fullOutput)) {
|
|
436
496
|
return buildPromptExtractionResult(lines, lastCapturedLine, totalLines, bufferReset, cliToolId, findRecentUserPromptIndex, promptDetection, captureWindowSaturated);
|
|
437
497
|
}
|
|
438
498
|
}
|
|
@@ -700,8 +760,11 @@ function extractResponse(output, lastCapturedLine, cliToolId, captureWindowLines
|
|
|
700
760
|
// Check if this is an interactive prompt
|
|
701
761
|
if (cliToolId !== 'opencode') {
|
|
702
762
|
const fullOutput = lines.join('\n');
|
|
763
|
+
// Issue #2457: same gate as the early check above — this is the site a frame
|
|
764
|
+
// reaches when the completion rules said "unfinished", so a candidate
|
|
765
|
+
// accepted here would end the turn on it just the same.
|
|
703
766
|
const promptDetection = detectPromptWithOptions(fullOutput, cliToolId);
|
|
704
|
-
if (promptDetection.isPrompt) {
|
|
767
|
+
if (promptDetection.isPrompt && isNumberedDialogVouched(cliToolId, promptDetection, fullOutput)) {
|
|
705
768
|
return buildPromptExtractionResult(lines, lastCapturedLine, totalLines, bufferReset, cliToolId, findRecentUserPromptIndex, promptDetection, captureWindowSaturated);
|
|
706
769
|
}
|
|
707
770
|
}
|
|
@@ -1067,7 +1130,23 @@ async function checkForResponse(worktreeId, cliToolId, instanceId) {
|
|
|
1067
1130
|
}
|
|
1068
1131
|
// Response is complete! Check if it's a prompt.
|
|
1069
1132
|
const promptDetection = result.promptDetection ?? detectPromptWithOptions(result.response, cliToolId);
|
|
1070
|
-
|
|
1133
|
+
// Issue #2457: the gate is applied HERE as well as in `extractResponse`, and
|
|
1134
|
+
// to a carried `result.promptDetection` as well as to one derived on this
|
|
1135
|
+
// line. Two independent reasons, either one sufficient:
|
|
1136
|
+
//
|
|
1137
|
+
// 1. the fallback above reads `result.response` — the EXTRACTED text, with
|
|
1138
|
+
// the pane's chrome already cut off — so a reply's `1. / 2. / 3.` rows
|
|
1139
|
+
// look even more like a dialog here than they did upstream, and a tool
|
|
1140
|
+
// the early check never runs for (opencode) reaches the save path only
|
|
1141
|
+
// through this line;
|
|
1142
|
+
// 2. `promptDetection` carried from `extractResponse` is the one thing that
|
|
1143
|
+
// could walk a candidate past the gate unexamined, and this is the last
|
|
1144
|
+
// position before the row is written.
|
|
1145
|
+
//
|
|
1146
|
+
// The frame is the capture this tick made — never `result.response`, which
|
|
1147
|
+
// has lost the position `detectDialog` judges by.
|
|
1148
|
+
const promptIsLive = promptDetection.isPrompt && isNumberedDialogVouched(cliToolId, promptDetection, output);
|
|
1149
|
+
if (promptIsLive) {
|
|
1071
1150
|
// Issue #565: Content hash-based duplicate prompt prevention
|
|
1072
1151
|
const promptContent = promptDetection.rawContent || promptDetection.cleanContent;
|
|
1073
1152
|
const normalizedForDedup = (0, prompt_dedup_1.normalizePromptForDedup)(promptContent, cliToolId);
|
|
@@ -58,6 +58,37 @@ function isCronJobActive(cronJob) {
|
|
|
58
58
|
}
|
|
59
59
|
return true;
|
|
60
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Attach the execution callback to a cron job.
|
|
63
|
+
*
|
|
64
|
+
* The callback closes over the {@link ScheduleState}, never over the entry the
|
|
65
|
+
* timer was built from (Issue #2456). Two things follow, and both are load
|
|
66
|
+
* bearing when a timer is replaced while its schedule keeps running:
|
|
67
|
+
*
|
|
68
|
+
* - the tick executes `state.entry`, so a Message/CLI Tool/Permission edit
|
|
69
|
+
* picked up by a later sync is the one the next run uses;
|
|
70
|
+
* - the tick reads `state.isExecuting`, the single guard every timer this
|
|
71
|
+
* schedule ever owns shares. `protect: true` cannot stand in for it: the
|
|
72
|
+
* callback returns `undefined` rather than the execution's Promise, so croner
|
|
73
|
+
* never sees itself as blocking, and a fresh timer with its own state would
|
|
74
|
+
* start a second run on top of a live one.
|
|
75
|
+
*
|
|
76
|
+
* @param state - The schedule state the callback executes
|
|
77
|
+
* @param cronJob - The cron job to attach the callback to
|
|
78
|
+
*/
|
|
79
|
+
function scheduleExecution(state, cronJob) {
|
|
80
|
+
cronJob.schedule(() => {
|
|
81
|
+
// Issue #1343: executeSchedule() rejects if its own error handling fails
|
|
82
|
+
// (e.g. the DB is still down when writing the 'failed' log). Without this
|
|
83
|
+
// catch the rejection is silently unhandled.
|
|
84
|
+
void (0, job_executor_1.executeSchedule)(state).catch((error) => {
|
|
85
|
+
logger.error('execution:unhandled', {
|
|
86
|
+
name: state.entry.name,
|
|
87
|
+
error: error instanceof Error ? error.message : String(error),
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
61
92
|
function createScheduleState(worktreeId, scheduleId, entry) {
|
|
62
93
|
const cronJob = new croner_1.Cron(entry.cronExpression, {
|
|
63
94
|
paused: false,
|
|
@@ -70,18 +101,102 @@ function createScheduleState(worktreeId, scheduleId, entry) {
|
|
|
70
101
|
isExecuting: false,
|
|
71
102
|
entry,
|
|
72
103
|
};
|
|
73
|
-
cronJob
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
104
|
+
scheduleExecution(state, cronJob);
|
|
105
|
+
return state;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Move a live schedule onto a new cron expression (Issue #2456).
|
|
109
|
+
*
|
|
110
|
+
* The bug this exists for: the sync loop used to answer a changed CMATE.md row
|
|
111
|
+
* with `existingState.entry = entry`, which updates every field the executor
|
|
112
|
+
* reads at run time but not the pattern `croner` compiled into the timer at
|
|
113
|
+
* construction. A Cron edit was therefore accepted by the parser, written to the
|
|
114
|
+
* DB, shown by the API — and ignored by the thing that actually fires, for as
|
|
115
|
+
* long as the server stayed up.
|
|
116
|
+
*
|
|
117
|
+
* ## Order of operations
|
|
118
|
+
*
|
|
119
|
+
* The replacement is built **paused** first, so the only step that can reject a
|
|
120
|
+
* pattern happens while the old timer is still the one and only live timer, and
|
|
121
|
+
* a rejected pattern leaves the schedule exactly as it was. Only then is the old
|
|
122
|
+
* timer stopped and the replacement resumed — in that order, so the two are
|
|
123
|
+
* never runnable at the same instant. `state.cronJob` and `state.entry` are
|
|
124
|
+
* published last, together, so a caller that reads the state never sees a timer
|
|
125
|
+
* and an entry that disagree.
|
|
126
|
+
*
|
|
127
|
+
* A pause costs nothing here: `resume()` follows synchronously, so no tick can
|
|
128
|
+
* pass while the replacement is paused and there is nothing to "catch up" on.
|
|
129
|
+
* The new expression's first run is its first occurrence after now, which is
|
|
130
|
+
* what a schedule edit should mean.
|
|
131
|
+
*
|
|
132
|
+
* ## Failure
|
|
133
|
+
*
|
|
134
|
+
* Failure keeps the old timer and the old entry, and says so — no
|
|
135
|
+
* `schedule:updated`. What it must never do is leave two live timers, so the
|
|
136
|
+
* candidate (which has never run) is the one discarded. If the failure was
|
|
137
|
+
* `stop()` on the old timer, that timer is left in whatever state it reached:
|
|
138
|
+
* either it stopped, and the next sync's inactive-state recovery rebuilds it
|
|
139
|
+
* from the newest entry, or it survived on its old expression. Both are
|
|
140
|
+
* recoverable, and the caller invalidates this worktree's mtime cache so the
|
|
141
|
+
* next sync retries even though CMATE.md has not been touched again.
|
|
142
|
+
*
|
|
143
|
+
* @param state - The live schedule state (kept, so its execution guard survives)
|
|
144
|
+
* @param entry - The entry carrying the new cron expression
|
|
145
|
+
* @returns true when the schedule now runs on `entry.cronExpression`
|
|
146
|
+
*/
|
|
147
|
+
function replaceCronExpression(state, entry) {
|
|
148
|
+
const previousCron = state.entry.cronExpression;
|
|
149
|
+
const failed = (phase, error) => {
|
|
150
|
+
logger.error('schedule:update-failed', {
|
|
151
|
+
scheduleId: state.scheduleId,
|
|
152
|
+
worktreeId: state.worktreeId,
|
|
153
|
+
previousCron,
|
|
154
|
+
cron: entry.cronExpression,
|
|
155
|
+
phase,
|
|
156
|
+
error: error instanceof Error ? error.message : String(error),
|
|
82
157
|
});
|
|
158
|
+
return false;
|
|
159
|
+
};
|
|
160
|
+
let candidate = null;
|
|
161
|
+
try {
|
|
162
|
+
candidate = new croner_1.Cron(entry.cronExpression, { paused: true, protect: true });
|
|
163
|
+
scheduleExecution(state, candidate);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
if (candidate) {
|
|
167
|
+
try {
|
|
168
|
+
candidate.stop();
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
// The candidate never ran; nothing else to reclaim
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return failed('prepare', error);
|
|
175
|
+
}
|
|
176
|
+
try {
|
|
177
|
+
state.cronJob.stop();
|
|
178
|
+
candidate.resume();
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
try {
|
|
182
|
+
candidate.stop();
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
// The candidate never ran; nothing else to reclaim
|
|
186
|
+
}
|
|
187
|
+
return failed('swap', error);
|
|
188
|
+
}
|
|
189
|
+
state.cronJob = candidate;
|
|
190
|
+
state.entry = entry;
|
|
191
|
+
// Deliberately without the message: the prompt body is not an operational
|
|
192
|
+
// fact and execution_logs already holds it.
|
|
193
|
+
logger.info('schedule:updated', {
|
|
194
|
+
scheduleId: state.scheduleId,
|
|
195
|
+
worktreeId: state.worktreeId,
|
|
196
|
+
previousCron,
|
|
197
|
+
cron: entry.cronExpression,
|
|
83
198
|
});
|
|
84
|
-
return
|
|
199
|
+
return true;
|
|
85
200
|
}
|
|
86
201
|
/**
|
|
87
202
|
* Get or initialize the global manager state.
|
|
@@ -124,6 +239,9 @@ function getLazyDbInstance() {
|
|
|
124
239
|
* Issue #406: Async I/O for readCmateFile() to avoid event loop blocking.
|
|
125
240
|
* Issue #409: Uses mtime caching to skip unchanged CMATE.md files
|
|
126
241
|
* and batchUpsertSchedules() for efficient DB operations.
|
|
242
|
+
* Issue #2456: A changed Cron column swaps the timer (replaceCronExpression);
|
|
243
|
+
* everything else about an existing schedule is an entry update that leaves the
|
|
244
|
+
* timer alone.
|
|
127
245
|
*
|
|
128
246
|
* DJ-007: isSyncing guard prevents concurrent execution when async
|
|
129
247
|
* operations exceed the 60-second polling interval.
|
|
@@ -188,10 +306,6 @@ async function syncSchedules() {
|
|
|
188
306
|
for (let i = 0; i < entries.length; i++) {
|
|
189
307
|
const entry = entries[i];
|
|
190
308
|
const scheduleId = scheduleIds[i];
|
|
191
|
-
if (manager.schedules.size >= exports.MAX_CONCURRENT_SCHEDULES) {
|
|
192
|
-
logger.warn('schedule:max-concurrent-reached', { limit: exports.MAX_CONCURRENT_SCHEDULES });
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
309
|
activeScheduleIds.add(scheduleId);
|
|
196
310
|
// Skip disabled or incomplete entries
|
|
197
311
|
if (!entry.enabled || !entry.cronExpression) {
|
|
@@ -214,16 +328,61 @@ async function syncSchedules() {
|
|
|
214
328
|
catch {
|
|
215
329
|
// Ignore cleanup errors for inactive cron jobs
|
|
216
330
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
331
|
+
// Issue #2456: recover onto the newest entry, and keep the same
|
|
332
|
+
// ScheduleState so a still-running execution's guard survives the
|
|
333
|
+
// exchange rather than being reset by a fresh object.
|
|
334
|
+
try {
|
|
335
|
+
const recovered = new croner_1.Cron(entry.cronExpression, { paused: false, protect: true });
|
|
336
|
+
scheduleExecution(existingState, recovered);
|
|
337
|
+
existingState.cronJob = recovered;
|
|
338
|
+
existingState.entry = entry;
|
|
339
|
+
logger.warn('schedule:recreated-inactive', { name: entry.name, cron: entry.cronExpression });
|
|
340
|
+
}
|
|
341
|
+
catch (recoverError) {
|
|
342
|
+
manager.cmateFileCache.delete(worktree.path);
|
|
343
|
+
logger.error('schedule:update-failed', {
|
|
344
|
+
scheduleId,
|
|
345
|
+
worktreeId: worktree.id,
|
|
346
|
+
previousCron: existingState.entry.cronExpression,
|
|
347
|
+
cron: entry.cronExpression,
|
|
348
|
+
phase: 'recover',
|
|
349
|
+
error: recoverError instanceof Error ? recoverError.message : String(recoverError),
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
// Issue #2456: a changed Cron column has to reach the timer, not
|
|
355
|
+
// just the entry the executor reads. String comparison on purpose —
|
|
356
|
+
// the parser has already trimmed the cell, and two spellings of the
|
|
357
|
+
// same schedule are a rewrite the operator asked for.
|
|
358
|
+
if (existingState.entry.cronExpression !== entry.cronExpression) {
|
|
359
|
+
if (!replaceCronExpression(existingState, entry)) {
|
|
360
|
+
// The old timer and the old entry are still in force. Drop this
|
|
361
|
+
// worktree's mtime cache so the next sync retries even though
|
|
362
|
+
// CMATE.md itself has not changed again — without this the file
|
|
363
|
+
// would have to be touched to get another attempt.
|
|
364
|
+
manager.cmateFileCache.delete(worktree.path);
|
|
365
|
+
}
|
|
220
366
|
continue;
|
|
221
367
|
}
|
|
222
|
-
//
|
|
368
|
+
// Metadata-only change (Message / CLI Tool / Permission / model):
|
|
369
|
+
// the timer stays, and the next tick reads this entry through the
|
|
370
|
+
// shared state.
|
|
223
371
|
existingState.entry = entry;
|
|
224
372
|
continue;
|
|
225
373
|
}
|
|
226
|
-
// Create new cron job
|
|
374
|
+
// Create new cron job. The cap belongs here and only here (Issue
|
|
375
|
+
// #2456): it bounds how many timers exist, so refusing a new one must
|
|
376
|
+
// not also refuse to update, disable or clean up the ones already
|
|
377
|
+
// running — nor abandon the rest of the sync, which is what the
|
|
378
|
+
// previous `return` did.
|
|
379
|
+
if (manager.schedules.size >= exports.MAX_CONCURRENT_SCHEDULES) {
|
|
380
|
+
logger.warn('schedule:max-concurrent-reached', {
|
|
381
|
+
limit: exports.MAX_CONCURRENT_SCHEDULES,
|
|
382
|
+
name: entry.name,
|
|
383
|
+
});
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
227
386
|
try {
|
|
228
387
|
const state = createScheduleState(worktree.id, scheduleId, entry);
|
|
229
388
|
manager.schedules.set(scheduleId, state);
|
|
@@ -100,9 +100,11 @@ function corresponds(a, b) {
|
|
|
100
100
|
* Containment rather than the prefix rule the labels use, because the two are
|
|
101
101
|
* extracted differently. An option label is a parsed line; the question is
|
|
102
102
|
* whatever the detector's upward scan swept together, and on a real capture that
|
|
103
|
-
*
|
|
103
|
+
* was several lines glued into one — before Issue #2486 the canary frame yielded
|
|
104
104
|
* `"⏺ I'll load the TaskCreate tool schema first. ☐ First task Which task would
|
|
105
|
-
* you like to start with?"` for a question that is only its last clause.
|
|
105
|
+
* you like to start with?"` for a question that is only its last clause. The
|
|
106
|
+
* picker's tab row now caps that scan, but the scan still reads at most a few
|
|
107
|
+
* rows, so a long question arrives cut and containment is still the right test.
|
|
106
108
|
*
|
|
107
109
|
* The floor stops a short question ("Continue?") from matching unrelated prose;
|
|
108
110
|
* the uniqueness requirement in {@link matchAskUserQuestion} does the rest. On
|
|
@@ -106,7 +106,7 @@ function truncateOutput(output) {
|
|
|
106
106
|
* - vibe-local: [-p <message> -y] or [--model <model> -p <message> -y]
|
|
107
107
|
* - opencode: run --format json [-m <model>] [--agent <a>] [--variant <v>] [-c] [--title <t>] <message>
|
|
108
108
|
* - antigravity: -p <message> --dangerously-skip-permissions
|
|
109
|
-
* - command-code: -p <message> --output-format json [--yolo | --permission-mode <permission>]
|
|
109
|
+
* - command-code: -p <message> --output-format json [--yolo | --permission-mode <permission>] --no-auto-update
|
|
110
110
|
* - others: -p <message> (fallback)
|
|
111
111
|
*
|
|
112
112
|
* @param message - Prompt message
|
|
@@ -201,13 +201,44 @@ function buildCliArgs(message, cliToolId, permission, options) {
|
|
|
201
201
|
// `--yolo` does not override `.commandcode/settings.json`
|
|
202
202
|
// `permissions.deny`; a denied tool call still ends the run with exit 4,
|
|
203
203
|
// which {@link describeCommandCodeExit} names in the failure reason.
|
|
204
|
+
//
|
|
205
|
+
// ## Issue #2454: `yolo` is a Permission *column* value, and the default
|
|
206
|
+
//
|
|
207
|
+
// Every `--permission-mode` value leaves print mode read-only. The 1.53.0
|
|
208
|
+
// bundle injects a `print-permission-gate` mod whenever `--yolo` was not
|
|
209
|
+
// passed, and that mod answers `edit_file` / `write_file` /
|
|
210
|
+
// `shell_command` / `monitor_command` / `kill_shell` with `block: true`;
|
|
211
|
+
// the mode flag never reaches it. A blocked call does not fail the run —
|
|
212
|
+
// it ends exit 0 with `subtype: "success"` — so a schedule that asked for
|
|
213
|
+
// `default` looked successful and changed nothing.
|
|
214
|
+
//
|
|
215
|
+
// So the column now spells `--yolo` as the value `yolo`
|
|
216
|
+
// ({@link COMMAND_CODE_SCHEDULE_PERMISSIONS}, copilot's shape), and the
|
|
217
|
+
// parser fills an empty cell with it. The `else` below used to be the
|
|
218
|
+
// only way to reach `--yolo` and was unreachable from a schedule, because
|
|
219
|
+
// `DEFAULT_PERMISSIONS['command-code']` was `'default'`.
|
|
204
220
|
const args = ['-p', message, '--output-format', 'json'];
|
|
205
|
-
if (schedule_config_1.
|
|
221
|
+
if (permission === schedule_config_1.COMMAND_CODE_YOLO_PERMISSION) {
|
|
222
|
+
args.push('--yolo');
|
|
223
|
+
}
|
|
224
|
+
else if (schedule_config_1.COMMAND_CODE_PERMISSIONS.includes(permission)) {
|
|
206
225
|
args.push('--permission-mode', permission);
|
|
207
226
|
}
|
|
208
227
|
else {
|
|
228
|
+
// Not reachable through the parser (it falls back to `yolo`); this is
|
|
229
|
+
// the direct-call guard.
|
|
209
230
|
args.push('--yolo');
|
|
210
231
|
}
|
|
232
|
+
// Issue #2454: without this, `resolveCliStartupPlan` runs an update check
|
|
233
|
+
// and a background self-update on every scheduled run. Spelled as a
|
|
234
|
+
// literal for the same reason `getCommandForTool` spells `commandcode` as
|
|
235
|
+
// one — importing `COMMAND_CODE_LAUNCH_FLAGS` from
|
|
236
|
+
// `@/lib/cli-tools/command-code` would pull the tmux transport into the
|
|
237
|
+
// scheduler's dependency graph. The unit test imports both and asserts
|
|
238
|
+
// the spelling matches, so the copy cannot drift. `--trust` /
|
|
239
|
+
// `--skip-onboarding` are *not* copied: print mode dispatches before the
|
|
240
|
+
// TUI's trust and onboarding gates, so they have nothing to answer.
|
|
241
|
+
args.push('--no-auto-update');
|
|
211
242
|
return args;
|
|
212
243
|
}
|
|
213
244
|
case 'antigravity':
|