commandmate 0.42.2 → 0.43.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 +148 -148
- package/.next/app-path-routes-manifest.json +25 -25
- 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_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/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.js +1 -1
- package/.next/server/app/api/daily-summary/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js.nft.json +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 +103 -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/clone/[jobId]/route.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route.js +1 -1
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route.js +1 -1
- package/.next/server/app/api/skills/[id]/route_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.js +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route.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.js +3 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +3 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +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]/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 -103
- 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 +3 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +3 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +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 +3 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +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 -103
- 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 +104 -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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +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 -1
- 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_client-reference-manifest.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_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 +9 -9
- 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 +25 -25
- package/.next/server/chunks/1068.js +1 -1
- package/.next/server/chunks/1210.js +1 -1
- package/.next/server/chunks/1501.js +3 -3
- package/.next/server/chunks/1990.js +1 -1
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/22.js +1 -1
- package/.next/server/chunks/2328.js +1 -1
- package/.next/server/chunks/2404.js +4 -3
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/252.js +1 -1
- package/.next/server/chunks/2816.js +1 -1
- package/.next/server/chunks/3543.js +1 -1
- package/.next/server/chunks/3730.js +1 -1
- package/.next/server/chunks/3945.js +1 -1
- package/.next/server/chunks/4207.js +3 -3
- package/.next/server/chunks/5064.js +1 -1
- package/.next/server/chunks/5571.js +1 -1
- package/.next/server/chunks/5742.js +1 -1
- package/.next/server/chunks/5775.js +1 -1
- package/.next/server/chunks/611.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6285.js +1 -1
- package/.next/server/chunks/6491.js +103 -0
- package/.next/server/chunks/6661.js +1 -1
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/6793.js +1 -1
- package/.next/server/chunks/7491.js +3 -0
- package/.next/server/chunks/7685.js +1 -1
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8581.js +2 -2
- package/.next/server/chunks/8673.js +6 -6
- package/.next/server/chunks/8728.js +2 -2
- package/.next/server/chunks/8791.js +1 -1
- package/.next/server/chunks/8800.js +4 -3
- package/.next/server/chunks/8918.js +5 -5
- package/.next/server/chunks/9130.js +3 -3
- package/.next/server/chunks/{8052.js → 9353.js} +4 -2
- package/.next/server/chunks/9390.js +3 -0
- package/.next/server/chunks/9627.js +3 -3
- package/.next/server/chunks/967.js +1 -0
- package/.next/server/chunks/9731.js +3 -3
- package/.next/server/chunks/9882.js +3 -3
- 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/{1642-fb2e176aaadbd137.js → 1642-767aed8e7c61ef7f.js} +1 -1
- package/.next/static/chunks/{2407-6b9e12c099fa598c.js → 2407-940df9b11fadafc6.js} +1 -1
- package/.next/static/chunks/{2619-04bc32f026a0d946.js → 2619-a305ad4810f1393a.js} +1 -1
- package/.next/static/chunks/5449-6cb80bab2bd06b79.js +1 -0
- package/.next/static/chunks/7705-1f58d4c03d991fcf.js +1 -0
- package/.next/static/chunks/8165-3525fb42f1b4976e.js +1 -0
- package/.next/static/chunks/app/{layout-5b95e1236dcd9ef6.js → layout-057c850cd0df978e.js} +1 -1
- package/.next/static/chunks/app/review/page-ff9efae3f86eb840.js +1 -0
- package/.next/static/chunks/app/skills/[skillId]/page-74aac15286504ef4.js +1 -0
- package/.next/static/chunks/app/skills/page-182e16168b2fc098.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-eab0bf7564d3f9e2.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/{page-373ea37b16d930c7.js → page-c601f3b3ece6557e.js} +1 -1
- package/.next/trace +13 -13
- package/README.md +3 -3
- package/dist/cli/commands/ask.d.ts.map +1 -1
- package/dist/cli/commands/ask.js +23 -149
- package/dist/cli/commands/reply.d.ts +40 -0
- package/dist/cli/commands/reply.d.ts.map +1 -0
- package/dist/cli/commands/reply.js +133 -0
- package/dist/cli/commands/wait.d.ts +5 -0
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +10 -1
- 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 +13 -0
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/program.js +4 -0
- package/dist/cli/utils/reply-ledger.d.ts +95 -0
- package/dist/cli/utils/reply-ledger.d.ts.map +1 -0
- package/dist/cli/utils/reply-ledger.js +187 -0
- package/dist/lib/cli-tools/copilot-executable.d.ts +9 -0
- package/dist/lib/cli-tools/copilot-executable.d.ts.map +1 -1
- package/dist/lib/cli-tools/copilot-executable.js +21 -5
- package/dist/lib/cli-tools/opencode-executable.d.ts +103 -0
- package/dist/lib/cli-tools/opencode-executable.d.ts.map +1 -0
- package/dist/lib/cli-tools/opencode-executable.js +179 -0
- package/dist/lib/cli-tools/types.d.ts +1 -1
- package/dist/lib/cli-tools/types.d.ts.map +1 -1
- package/dist/lib/cli-tools/types.js +5 -1
- package/dist/lib/detection/tools/verified-against.d.ts +15 -0
- package/dist/lib/detection/tools/verified-against.d.ts.map +1 -1
- package/dist/lib/detection/tools/verified-against.js +17 -1
- package/dist/lib/detection/version-probes.d.ts.map +1 -1
- package/dist/lib/detection/version-probes.js +14 -1
- package/dist/lib/session/tmux-session-surface.d.ts.map +1 -1
- package/dist/lib/session/tmux-session-surface.js +1 -1
- package/dist/server/locales/en/worktree.json +44 -14
- package/dist/server/locales/ja/worktree.json +44 -14
- package/dist/server/server.js +23 -0
- package/dist/server/src/config/cli-tool-timing-config.js +19 -1
- package/dist/server/src/config/detection-evidence-config.js +3 -0
- package/dist/server/src/config/schedule-config.js +55 -1
- package/dist/server/src/lib/auto-yes-poller.js +47 -4
- package/dist/server/src/lib/cli-tools/agent-mode-spec.js +54 -2
- package/dist/server/src/lib/cli-tools/base.js +6 -2
- package/dist/server/src/lib/cli-tools/command-code.js +55 -1
- package/dist/server/src/lib/cli-tools/composer-spec.js +10 -0
- package/dist/server/src/lib/cli-tools/copilot-executable.js +21 -5
- package/dist/server/src/lib/cli-tools/graceful-exit.js +15 -1
- package/dist/server/src/lib/cli-tools/index.js +3 -1
- package/dist/server/src/lib/cli-tools/install-hints.js +9 -3
- package/dist/server/src/lib/cli-tools/liveness-spec.js +19 -0
- package/dist/server/src/lib/cli-tools/manager.js +2 -0
- package/dist/server/src/lib/cli-tools/opencode-executable.js +179 -0
- package/dist/server/src/lib/cli-tools/opencode-v2.js +369 -0
- package/dist/server/src/lib/cli-tools/opencode.js +29 -5
- package/dist/server/src/lib/cli-tools/types.js +5 -1
- package/dist/server/src/lib/cmate-cli-tool-parser.js +65 -7
- package/dist/server/src/lib/cmate-parser.js +12 -0
- package/dist/server/src/lib/cmate-validator.js +13 -1
- package/dist/server/src/lib/detection/cli-patterns.js +78 -2
- package/dist/server/src/lib/detection/model-info-extractor.js +79 -7
- package/dist/server/src/lib/detection/status-detector.js +10 -1
- package/dist/server/src/lib/detection/tools/codex/cli-patterns.js +2 -1
- package/dist/server/src/lib/detection/tools/opencode-v2/detect.js +253 -0
- package/dist/server/src/lib/detection/tools/opencode-v2/dialog-title.js +48 -0
- package/dist/server/src/lib/detection/tools/registry.js +2 -0
- package/dist/server/src/lib/detection/tools/run-detection.js +9 -0
- package/dist/server/src/lib/detection/tools/verified-against.js +17 -1
- package/dist/server/src/lib/detection/upstream-faults.js +8 -0
- package/dist/server/src/lib/detection/version-probes.js +14 -1
- package/dist/server/src/lib/hooks/agent-session-telemetry.js +36 -1
- package/dist/server/src/lib/hooks/sources/opencode/log-diagnosis.js +105 -0
- package/dist/server/src/lib/hooks/sources/opencode/source.js +7 -1
- package/dist/server/src/lib/hooks/sources/opencode-v2/client.js +422 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/decision-labels.js +24 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/history.js +421 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/ingest.js +271 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/mappers.js +165 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/payloads.js +351 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/ports.js +230 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/reattach.js +149 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/runtime.js +180 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/secrets.js +182 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/source.js +295 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/subscription.js +455 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/tool-id.js +18 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/usage.js +214 -0
- package/dist/server/src/lib/hooks/sources/registry.js +2 -0
- package/dist/server/src/lib/hooks/structured-decision-response.js +14 -5
- package/dist/server/src/lib/job-executor.js +2 -1
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +15 -1
- package/dist/server/src/lib/polling/structured-history-gate.js +19 -5
- package/dist/server/src/lib/relay/relay-delivery.js +4 -1
- package/dist/server/src/lib/session/agent-event-state.js +24 -0
- package/dist/server/src/lib/session/claude-executor.js +184 -10
- package/dist/server/src/lib/session/current-output-builder.js +27 -3
- package/dist/server/src/lib/session/send-user-message.js +4 -0
- package/dist/server/src/lib/session/structured-prompt.js +54 -0
- package/dist/server/src/lib/session/tmux-session-surface.js +1 -1
- package/dist/server/src/lib/skills/compatibility-matrix.js +65 -0
- package/dist/server/src/lib/tmux/tmux.js +48 -2
- package/dist/server/src/lib/verification/env-clean-gate.js +87 -5
- package/dist/server/src/types/cli-tool-contracts.js +10 -2
- package/dist/types/cli-tool-contracts.d.ts +16 -5
- package/dist/types/cli-tool-contracts.d.ts.map +1 -1
- package/dist/types/cli-tool-contracts.js +10 -2
- package/package.json +2 -1
- package/release-notes/0.43.0.json +130 -0
- package/scripts/hooks/cmate-agent-event.sh +14 -0
- package/scripts/opencode-v2/launch.sh +226 -0
- package/.next/server/chunks/4443.js +0 -3
- package/.next/server/chunks/5164.js +0 -1
- package/.next/server/chunks/650.js +0 -1
- package/.next/static/chunks/5449-550bd273dccc3ae4.js +0 -1
- package/.next/static/chunks/7705-2a2936551b0cf9a3.js +0 -1
- package/.next/static/chunks/8165-934ee7ff3b4ddfd4.js +0 -1
- package/.next/static/chunks/app/review/page-30616daa1dc595c2.js +0 -1
- package/.next/static/chunks/app/skills/[skillId]/page-ab7e432b69fccb3b.js +0 -1
- package/.next/static/chunks/app/skills/page-56b4fa11223e0cbd.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-59f5337e031518c6.js +0 -1
- /package/.next/static/{MXZXkcFAnpELZnxxHB4iJ → BVkBYdceLRvMROqQIqeBx}/_buildManifest.js +0 -0
- /package/.next/static/{MXZXkcFAnpELZnxxHB4iJ → BVkBYdceLRvMROqQIqeBx}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* OpenCode V2 (`opencode2`) CLI tool (Issue #2934, Epic #2370 Phase 1).
|
|
4
|
+
*
|
|
5
|
+
* A separate tool from `opencode` (v1), not a version branch of it: OpenCode
|
|
6
|
+
* 2.0's server, event vocabulary and screen all differ, and v1 keeps every
|
|
7
|
+
* behaviour it had (Epic #2370, decision 1).
|
|
8
|
+
*
|
|
9
|
+
* ## The pane
|
|
10
|
+
*
|
|
11
|
+
* One tmux pane holds both processes OpenCode V2 needs. The launch line runs
|
|
12
|
+
* `scripts/opencode-v2/launch.sh`, which starts `opencode2 serve` on the
|
|
13
|
+
* instance's own port with the instance's own password, waits for
|
|
14
|
+
* `GET /openapi.json`, runs `opencode2 --server <url> <worktree>` in the
|
|
15
|
+
* foreground, and — through a trap on EXIT / HUP / INT / TERM — stops the server
|
|
16
|
+
* whichever way the TUI goes. So `/exit`, a crashed TUI and `tmux kill-session`
|
|
17
|
+
* all release the port (the #1905 failure, prevented by construction), and a
|
|
18
|
+
* CommandMate restart leaves both running because neither is CommandMate's
|
|
19
|
+
* child.
|
|
20
|
+
*
|
|
21
|
+
* ## What is structured and what is read off the screen
|
|
22
|
+
*
|
|
23
|
+
* - state (running / ready / waiting) comes from the server's SSE stream
|
|
24
|
+
* (`@/lib/hooks/sources/opencode-v2`), subscribed once the TUI is up;
|
|
25
|
+
* - sending goes through the TUI's composer via tmux, as for v1's fallback
|
|
26
|
+
* path (D6). `session.prompt` is not used: it addresses a session by id, and
|
|
27
|
+
* the TUI may be showing a different one;
|
|
28
|
+
* - the screen scraper still reads the pane, as every tool's fallback.
|
|
29
|
+
*
|
|
30
|
+
* Phase 2 adds approvals / questions / History, Phase 3 richer screen reading
|
|
31
|
+
* and quick keys ({@link OpenCodeV2Tool.navigationKeys}, Issue #2966).
|
|
32
|
+
*
|
|
33
|
+
* @module lib/cli-tools/opencode-v2
|
|
34
|
+
*/
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.OpenCodeV2Tool = exports.OPENCODE_V2_NAVIGATION_KEY_VALUES = exports.OPENCODE_V2_RESUME_RETRY_MS = exports.OPENCODE_V2_READY_MAX_ATTEMPTS = exports.OPENCODE_V2_READY_POLL_INTERVAL_MS = void 0;
|
|
37
|
+
exports.parseOpencodeV2Version = parseOpencodeV2Version;
|
|
38
|
+
exports.toOpencodeV2ComposerText = toOpencodeV2ComposerText;
|
|
39
|
+
const child_process_1 = require("child_process");
|
|
40
|
+
const util_1 = require("util");
|
|
41
|
+
const base_1 = require("./base");
|
|
42
|
+
const terminal_keys_1 = require("../../types/terminal-keys");
|
|
43
|
+
const tmux_1 = require("../tmux/tmux");
|
|
44
|
+
const cli_patterns_1 = require("../detection/cli-patterns");
|
|
45
|
+
const submit_verified_sender_1 = require("./submit-verified-sender");
|
|
46
|
+
const tmux_capture_cache_1 = require("../tmux/tmux-capture-cache");
|
|
47
|
+
const tmux_pane_config_1 = require("../../config/tmux-pane-config");
|
|
48
|
+
const logger_1 = require("../../lib/logger");
|
|
49
|
+
const errors_1 = require("../../lib/errors");
|
|
50
|
+
const agent_session_lifecycle_1 = require("../../lib/session/agent-session-lifecycle");
|
|
51
|
+
const runtime_1 = require("../../lib/hooks/sources/opencode-v2/runtime");
|
|
52
|
+
const client_1 = require("../../lib/hooks/sources/opencode-v2/client");
|
|
53
|
+
const ports_1 = require("../../lib/hooks/sources/opencode-v2/ports");
|
|
54
|
+
const subscription_1 = require("../../lib/hooks/sources/opencode-v2/subscription");
|
|
55
|
+
const tool_id_1 = require("../../lib/hooks/sources/opencode-v2/tool-id");
|
|
56
|
+
const graceful_exit_1 = require("./graceful-exit");
|
|
57
|
+
const cli_tool_timing_config_1 = require("../../config/cli-tool-timing-config");
|
|
58
|
+
const install_hints_1 = require("./install-hints");
|
|
59
|
+
const opencode_executable_1 = require("./opencode-executable");
|
|
60
|
+
const logger = (0, logger_1.createLogger)('cli-tools/opencode-v2');
|
|
61
|
+
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
62
|
+
/** Interval between composer polls (launch and send). */
|
|
63
|
+
exports.OPENCODE_V2_READY_POLL_INTERVAL_MS = 500;
|
|
64
|
+
/** Composer polls after the launch line before giving up (30 s at 500 ms). */
|
|
65
|
+
exports.OPENCODE_V2_READY_MAX_ATTEMPTS = 60;
|
|
66
|
+
/** Rows captured when looking for the composer. The pane is 200 rows tall. */
|
|
67
|
+
const OPENCODE_V2_READY_CAPTURE_LINES = tmux_pane_config_1.OPENCODE_PANE_HEIGHT;
|
|
68
|
+
/**
|
|
69
|
+
* How long a failed lazy resume is not retried (ms). `isRunning` is polled, and
|
|
70
|
+
* a server that is really gone must not be probed on every poll.
|
|
71
|
+
*/
|
|
72
|
+
exports.OPENCODE_V2_RESUME_RETRY_MS = 30_000;
|
|
73
|
+
/**
|
|
74
|
+
* The version `opencode2 --version` reports, or null when the output is not
|
|
75
|
+
* OpenCode V2's. Issue #2939: the same rule OpenCode 1.x is told apart by
|
|
76
|
+
* (`./opencode-executable`), so `1.18.33` is not V2 and `opencode v2.0.18` is.
|
|
77
|
+
*/
|
|
78
|
+
function parseOpencodeV2Version(output) {
|
|
79
|
+
const info = (0, opencode_executable_1.parseOpencodeVersionOutput)(output);
|
|
80
|
+
return info?.generation === 'v2' ? info.version : null;
|
|
81
|
+
}
|
|
82
|
+
/** A bare `/<name>`: a slash command with no argument and no whitespace at all. */
|
|
83
|
+
const BARE_SLASH_COMMAND = /^\/\S+$/;
|
|
84
|
+
/**
|
|
85
|
+
* The text to type for `message` (Issue #2950).
|
|
86
|
+
*
|
|
87
|
+
* The TUI opens its command dropdown on any composer text starting with `/`,
|
|
88
|
+
* and while it is open Enter picks a row instead of submitting — so a bare
|
|
89
|
+
* `/probe-agentsskills` sits in the composer ("No matching commands") and runs
|
|
90
|
+
* nothing, while `/probe-agentsskills ` (one trailing space) closes the
|
|
91
|
+
* dropdown and runs. The palette already inserts `` `${trigger} ` `` (see
|
|
92
|
+
* `loadOpencodeSkills` in `@/lib/slash-commands`, "The trailing space is
|
|
93
|
+
* load-bearing"), but the send route trims the body, so the space never
|
|
94
|
+
* arrives. It is put back here, and only for a bare `/<name>`: a command with
|
|
95
|
+
* an argument already has a space after the name, and ordinary text does not
|
|
96
|
+
* open the dropdown.
|
|
97
|
+
*/
|
|
98
|
+
function toOpencodeV2ComposerText(message) {
|
|
99
|
+
return BARE_SLASH_COMMAND.test(message) ? `${message} ` : message;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The leader-chord letters OpenCode V2 2.0.18 answers on its home screen, as
|
|
103
|
+
* sent by `OpencodeQuickKeys`' v2 strip (Issue #2966): `a` agents, `l`
|
|
104
|
+
* sessions, `m` models. `n` (new session) is also sent, but is already in
|
|
105
|
+
* {@link NAVIGATION_KEY_VALUES} (#2254), so it is not listed twice.
|
|
106
|
+
*
|
|
107
|
+
* Deliberately narrower than v1's `OPENCODE_CHORD_ONLY_VALUES`. Measured on
|
|
108
|
+
* 2.0.18 (private tmux socket, 80 columns, isolated `HOME` / XDG dirs):
|
|
109
|
+
* `ctrl+x t` is not `theme_list` any more — on the home screen the leader lets
|
|
110
|
+
* the `t` through into the composer, and inside a session it opens a terminal
|
|
111
|
+
* pane. `g` / `u` / `r` / `c` work only inside a session and type their letter
|
|
112
|
+
* into the composer otherwise; the strip does not offer them for v2 (see
|
|
113
|
+
* `OpencodeQuickKeys`), so they are not declared either.
|
|
114
|
+
*/
|
|
115
|
+
const OPENCODE_V2_CHORD_ONLY_VALUES = ['a', 'l', 'm'];
|
|
116
|
+
/**
|
|
117
|
+
* Everything an OpenCode V2 pane may be sent through `/special-keys`: the base
|
|
118
|
+
* pad plus the `ctrl+x` leader, `ctrl+p` / `ctrl+t`, and the three chord
|
|
119
|
+
* letters above (Issue #2966).
|
|
120
|
+
*/
|
|
121
|
+
exports.OPENCODE_V2_NAVIGATION_KEY_VALUES = [
|
|
122
|
+
...terminal_keys_1.NAVIGATION_KEY_VALUES,
|
|
123
|
+
terminal_keys_1.OPENCODE_LEADER_KEY,
|
|
124
|
+
...terminal_keys_1.OPENCODE_DIRECT_KEY_VALUES,
|
|
125
|
+
...OPENCODE_V2_CHORD_ONLY_VALUES,
|
|
126
|
+
];
|
|
127
|
+
class OpenCodeV2Tool extends base_1.BaseCLITool {
|
|
128
|
+
id = tool_id_1.OPENCODE_V2_CLI_TOOL_ID;
|
|
129
|
+
name = 'OpenCode V2';
|
|
130
|
+
command = tool_id_1.OPENCODE_V2_COMMAND;
|
|
131
|
+
/** Last lazy-resume attempt per session name, for {@link OPENCODE_V2_RESUME_RETRY_MS}. */
|
|
132
|
+
resumeAttemptedAt = new Map();
|
|
133
|
+
/**
|
|
134
|
+
* Declare the keys OpenCode V2's quick keys send (Issue #2966).
|
|
135
|
+
*
|
|
136
|
+
* Without this override the route validates against the base pad and answers
|
|
137
|
+
* 400 for `C-p` / `C-t` / `C-x`, so the palette, the variant cycle and every
|
|
138
|
+
* leader chord on the strip would be unsendable. The leader is `ctrl+x`, the
|
|
139
|
+
* same default as v1 — 2.0.18's own palette prints `ctrl+x m`, `ctrl+x a`,
|
|
140
|
+
* `ctrl+x l`, `ctrl+x n`.
|
|
141
|
+
*
|
|
142
|
+
* @returns This tool's {@link NavigationKeySpec}
|
|
143
|
+
*/
|
|
144
|
+
navigationKeys() {
|
|
145
|
+
return {
|
|
146
|
+
keys: exports.OPENCODE_V2_NAVIGATION_KEY_VALUES,
|
|
147
|
+
leaderKey: terminal_keys_1.OPENCODE_LEADER_KEY,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Installed means an executable that identifies itself as OpenCode V2
|
|
152
|
+
* (`opencode v<semver>`, D1): `opencode2`, or — Issue #2939 — an `opencode`
|
|
153
|
+
* that answers as V2, for an operator who has V2 under that name only.
|
|
154
|
+
*/
|
|
155
|
+
async isInstalled() {
|
|
156
|
+
return (await (0, opencode_executable_1.resolveOpencodeV2Executable)()).executable !== null;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Whether the instance's tmux session exists.
|
|
160
|
+
*
|
|
161
|
+
* A live session this process holds no subscription for — a pane that
|
|
162
|
+
* outlived a CommandMate restart — gets its event stream back here, fire and
|
|
163
|
+
* forget and at most every {@link OPENCODE_V2_RESUME_RETRY_MS}, so status
|
|
164
|
+
* comes from the server again as soon as anything polls the pane.
|
|
165
|
+
*/
|
|
166
|
+
async isRunning(worktreeId, instanceId) {
|
|
167
|
+
const sessionName = this.getSessionName(worktreeId, instanceId);
|
|
168
|
+
const running = await (0, tmux_1.hasSession)(sessionName);
|
|
169
|
+
if (running)
|
|
170
|
+
this.resumeInBackground(worktreeId, sessionName, instanceId);
|
|
171
|
+
return running;
|
|
172
|
+
}
|
|
173
|
+
resumeInBackground(worktreeId, sessionName, instanceId) {
|
|
174
|
+
const target = (0, runtime_1.opencodeV2Target)(worktreeId, instanceId);
|
|
175
|
+
if ((0, subscription_1.isOpencodeV2Subscribed)(target))
|
|
176
|
+
return;
|
|
177
|
+
const now = Date.now();
|
|
178
|
+
const last = this.resumeAttemptedAt.get(sessionName);
|
|
179
|
+
if (last !== undefined && now - last < exports.OPENCODE_V2_RESUME_RETRY_MS)
|
|
180
|
+
return;
|
|
181
|
+
this.resumeAttemptedAt.set(sessionName, now);
|
|
182
|
+
void (async () => {
|
|
183
|
+
try {
|
|
184
|
+
const worktreePath = await (0, tmux_1.getSessionWorkingDirectory)(sessionName);
|
|
185
|
+
if (worktreePath === null)
|
|
186
|
+
return;
|
|
187
|
+
await (0, runtime_1.resumeOpencodeV2EventStream)(target, worktreePath);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
logger.debug('opencode-v2-lazy-resume-failed', { error: (0, errors_1.getErrorMessage)(error) });
|
|
191
|
+
}
|
|
192
|
+
})();
|
|
193
|
+
}
|
|
194
|
+
async launchSession(worktreeId, worktreePath, instanceId) {
|
|
195
|
+
// Issue #2939: the file that answered as V2 is the file the line runs.
|
|
196
|
+
const executable = (await (0, opencode_executable_1.resolveOpencodeV2Executable)()).executable;
|
|
197
|
+
if (!executable) {
|
|
198
|
+
throw (0, install_hints_1.missingToolError)(this);
|
|
199
|
+
}
|
|
200
|
+
const sessionName = this.getSessionName(worktreeId, instanceId);
|
|
201
|
+
const target = (0, runtime_1.opencodeV2Target)(worktreeId, instanceId);
|
|
202
|
+
const geometry = { windowWidth: (0, tmux_pane_config_1.resolveOpencodePaneWidth)(), windowHeight: tmux_pane_config_1.OPENCODE_PANE_HEIGHT };
|
|
203
|
+
const exists = await (0, tmux_1.hasSession)(sessionName);
|
|
204
|
+
if (exists) {
|
|
205
|
+
await this.reconcileExistingSession(sessionName, worktreePath, geometry);
|
|
206
|
+
if (await this.isToolLive(sessionName, { confirm: true })) {
|
|
207
|
+
await (0, runtime_1.resumeOpencodeV2EventStream)(target, worktreePath);
|
|
208
|
+
logger.info('opencode-v2-session-exists');
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
logger.warn('opencode-v2-session-relaunch', { sessionName });
|
|
212
|
+
// The pane is back at its shell, so whatever it held is gone with it.
|
|
213
|
+
await (0, runtime_1.releaseOpencodeV2Server)(target);
|
|
214
|
+
}
|
|
215
|
+
(0, agent_session_lifecycle_1.beginAgentSession)(target);
|
|
216
|
+
try {
|
|
217
|
+
if (!exists) {
|
|
218
|
+
await (0, tmux_1.createSession)({ sessionName, workingDirectory: worktreePath });
|
|
219
|
+
await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_SESSION_CREATE_WAIT_MS));
|
|
220
|
+
}
|
|
221
|
+
try {
|
|
222
|
+
await execFileAsync('tmux', [
|
|
223
|
+
'resize-window', '-t', (0, tmux_1.exactTarget)(sessionName),
|
|
224
|
+
'-x', String(geometry.windowWidth), '-y', String(geometry.windowHeight),
|
|
225
|
+
]);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
// Non-fatal, as for v1: the TUI still starts at whatever size it gets.
|
|
229
|
+
}
|
|
230
|
+
// Port and password first: the launch line is built from both.
|
|
231
|
+
const port = await (0, runtime_1.reserveOpencodeV2Server)(target, worktreePath);
|
|
232
|
+
if (port === null) {
|
|
233
|
+
logger.warn('opencode-v2-launch-without-server', { worktreeId, instanceId });
|
|
234
|
+
}
|
|
235
|
+
await (0, tmux_1.sendKeys)(sessionName, (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({ target, executablePath: executable.path, worktreePath }), true);
|
|
236
|
+
await this.waitForReady(sessionName);
|
|
237
|
+
await (0, runtime_1.attachOpencodeV2EventStream)(target);
|
|
238
|
+
logger.info('started-opencode-v2-session');
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
throw new Error(`Failed to start OpenCode V2 session: ${(0, errors_1.getErrorMessage)(error)}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Poll until the composer is on screen (or give up quietly). */
|
|
245
|
+
async waitForReady(sessionName) {
|
|
246
|
+
for (let attempt = 0; attempt < exports.OPENCODE_V2_READY_MAX_ATTEMPTS; attempt++) {
|
|
247
|
+
try {
|
|
248
|
+
const output = (0, cli_patterns_1.stripAnsi)(await (0, tmux_1.capturePane)(sessionName, OPENCODE_V2_READY_CAPTURE_LINES));
|
|
249
|
+
if ((0, cli_patterns_1.isOpencodeV2ComposerVisible)(output)) {
|
|
250
|
+
logger.info('opencode-v2-composer-detected', { attempt });
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
// The pane may not be readable yet; keep polling.
|
|
256
|
+
}
|
|
257
|
+
await new Promise((resolve) => setTimeout(resolve, exports.OPENCODE_V2_READY_POLL_INTERVAL_MS));
|
|
258
|
+
}
|
|
259
|
+
logger.info('opencode-v2-ready-detection-timeout');
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Wait for the composer before typing into it (D6).
|
|
264
|
+
*
|
|
265
|
+
* Issue #2971: a dialog open over the composer (model / variant picker,
|
|
266
|
+
* Commands, Sessions, agents) leaves the footer on screen, so the composer
|
|
267
|
+
* check alone passes and the text went into the dialog's filter. The send is
|
|
268
|
+
* refused instead, on the first frame that shows one: the dialog is someone's
|
|
269
|
+
* choice in progress, so it is neither dismissed (Escape would throw that
|
|
270
|
+
* choice away) nor waited out (nothing closes it but a person).
|
|
271
|
+
*
|
|
272
|
+
* @throws When a dialog is open, or when the composer does not appear within
|
|
273
|
+
* {@link OPENCODE_V2_COMPOSER_WAIT_MS}
|
|
274
|
+
*/
|
|
275
|
+
async waitForComposer(sessionName) {
|
|
276
|
+
const deadline = Date.now() + cli_tool_timing_config_1.OPENCODE_V2_COMPOSER_WAIT_MS;
|
|
277
|
+
for (;;) {
|
|
278
|
+
let dialog = null;
|
|
279
|
+
try {
|
|
280
|
+
const output = (0, cli_patterns_1.stripAnsi)(await (0, tmux_1.capturePane)(sessionName, OPENCODE_V2_READY_CAPTURE_LINES));
|
|
281
|
+
dialog = (0, cli_patterns_1.findOpencodeV2DialogTitle)(output);
|
|
282
|
+
if (dialog === null && (0, cli_patterns_1.isOpencodeV2ComposerVisible)(output))
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// Treated as "not yet".
|
|
287
|
+
}
|
|
288
|
+
if (dialog !== null) {
|
|
289
|
+
throw new Error(`OpenCode V2 composer not available: the "${dialog}" dialog is open. ` +
|
|
290
|
+
'Close it (esc) or finish the choice, then send again');
|
|
291
|
+
}
|
|
292
|
+
if (Date.now() >= deadline)
|
|
293
|
+
break;
|
|
294
|
+
await new Promise((resolve) => setTimeout(resolve, exports.OPENCODE_V2_READY_POLL_INTERVAL_MS));
|
|
295
|
+
}
|
|
296
|
+
throw new Error('OpenCode V2 composer not ready: timed out waiting for it before sending');
|
|
297
|
+
}
|
|
298
|
+
async sendMessage(worktreeId, message, instanceId) {
|
|
299
|
+
const sessionName = this.getSessionName(worktreeId, instanceId);
|
|
300
|
+
if (!(await (0, tmux_1.hasSession)(sessionName))) {
|
|
301
|
+
throw new Error(`OpenCode V2 session ${sessionName} does not exist. Start the session first.`);
|
|
302
|
+
}
|
|
303
|
+
await this.relaunchIfToolExited(worktreeId, instanceId);
|
|
304
|
+
try {
|
|
305
|
+
await this.waitForComposer(sessionName);
|
|
306
|
+
await (0, submit_verified_sender_1.sendMessageWithSubmitVerification)({
|
|
307
|
+
sessionName,
|
|
308
|
+
message: toOpencodeV2ComposerText(message),
|
|
309
|
+
cliToolId: tool_id_1.OPENCODE_V2_CLI_TOOL_ID,
|
|
310
|
+
composer: this.describeComposer(),
|
|
311
|
+
});
|
|
312
|
+
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
313
|
+
logger.info('sent-message-to-opencode-v2-session');
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
throw new Error(`Failed to send message to OpenCode V2: ${(0, errors_1.getErrorMessage)(error)}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Stop the TUI and, through the wrapper's trap, its server.
|
|
321
|
+
*
|
|
322
|
+
* `/exit` and a separate Enter first (the declared graceful sequence), then
|
|
323
|
+
* the postcondition: the session gone AND the port no longer answering. If
|
|
324
|
+
* either fails the session is killed — the SIGHUP reaches the wrapper, whose
|
|
325
|
+
* trap stops the server. Everything the instance held (subscription, port,
|
|
326
|
+
* password file) is released at the end.
|
|
327
|
+
*/
|
|
328
|
+
async killSession(worktreeId, instanceId) {
|
|
329
|
+
const sessionName = this.getSessionName(worktreeId, instanceId);
|
|
330
|
+
const target = (0, runtime_1.opencodeV2Target)(worktreeId, instanceId);
|
|
331
|
+
const port = (0, ports_1.getAssignedOpencodeV2Port)(target);
|
|
332
|
+
try {
|
|
333
|
+
if (await (0, tmux_1.hasSession)(sessionName)) {
|
|
334
|
+
await (0, tmux_1.sendKeys)(sessionName, graceful_exit_1.OPENCODE_V2_EXIT_COMMAND_TEXT, false);
|
|
335
|
+
await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.TUI_TEXT_INPUT_WAIT_MS));
|
|
336
|
+
await (0, tmux_1.sendSpecialKeys)(sessionName, ['Enter']);
|
|
337
|
+
await new Promise((resolve) => setTimeout(resolve, cli_tool_timing_config_1.OPENCODE_V2_EXIT_WAIT_MS));
|
|
338
|
+
const verdict = await (0, graceful_exit_1.verifyGracefulExit)({
|
|
339
|
+
sessionAlive: () => (0, tmux_1.hasSession)(sessionName),
|
|
340
|
+
portAnswering: port === null
|
|
341
|
+
? null
|
|
342
|
+
: async () => (await (0, client_1.probeOpencodeV2Server)(port, '')).kind !== 'unreachable',
|
|
343
|
+
});
|
|
344
|
+
if (!verdict.ok) {
|
|
345
|
+
logger.info('opencode-v2-graceful-exit-postcondition-unmet', {
|
|
346
|
+
sessionName,
|
|
347
|
+
reason: verdict.reason,
|
|
348
|
+
...(port !== null ? { port } : {}),
|
|
349
|
+
});
|
|
350
|
+
await (0, tmux_1.killSession)(sessionName);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
await (0, tmux_1.killSession)(sessionName);
|
|
355
|
+
}
|
|
356
|
+
(0, tmux_capture_cache_1.invalidateCache)(sessionName);
|
|
357
|
+
this.resumeAttemptedAt.delete(sessionName);
|
|
358
|
+
logger.info('stopped-opencode-v2-session');
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
361
|
+
logger.error('session:stop-failed', { error: (0, errors_1.getErrorMessage)(error) });
|
|
362
|
+
throw error;
|
|
363
|
+
}
|
|
364
|
+
finally {
|
|
365
|
+
await (0, runtime_1.releaseOpencodeV2Server)(target);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
exports.OpenCodeV2Tool = OpenCodeV2Tool;
|
|
@@ -73,6 +73,8 @@ const opencode_session_store_1 = require("../../lib/session/opencode-session-sto
|
|
|
73
73
|
const graceful_exit_1 = require("./graceful-exit");
|
|
74
74
|
const cli_tool_timing_config_1 = require("../../config/cli-tool-timing-config");
|
|
75
75
|
const install_hints_1 = require("./install-hints");
|
|
76
|
+
const opencode_executable_1 = require("./opencode-executable");
|
|
77
|
+
const log_diagnosis_1 = require("../../lib/hooks/sources/opencode/log-diagnosis");
|
|
76
78
|
const logger = (0, logger_1.createLogger)('cli-tools/opencode');
|
|
77
79
|
const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
|
|
78
80
|
/**
|
|
@@ -227,6 +229,14 @@ class OpenCodeTool extends base_1.BaseCLITool {
|
|
|
227
229
|
leaderKey: terminal_keys_1.OPENCODE_LEADER_KEY,
|
|
228
230
|
};
|
|
229
231
|
}
|
|
232
|
+
/**
|
|
233
|
+
* Installed means an `opencode` on PATH that reports a 1.x version (Issue
|
|
234
|
+
* #2939). `which opencode` is not enough: npm `@opencode/cli` registers
|
|
235
|
+
* `opencode` for OpenCode V2 too. See `./opencode-executable`.
|
|
236
|
+
*/
|
|
237
|
+
async isInstalled() {
|
|
238
|
+
return (await (0, opencode_executable_1.resolveOpencodeV1Executable)()).executable !== null;
|
|
239
|
+
}
|
|
230
240
|
/**
|
|
231
241
|
* Check if OpenCode session is running for a worktree
|
|
232
242
|
*/
|
|
@@ -242,9 +252,12 @@ class OpenCodeTool extends base_1.BaseCLITool {
|
|
|
242
252
|
* @param worktreePath - Worktree path
|
|
243
253
|
*/
|
|
244
254
|
async launchSession(worktreeId, worktreePath, instanceId) {
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
255
|
+
// Issue #2939: one resolution decides both whether to start and what to
|
|
256
|
+
// run, so the launch line names the very file that answered as 1.x.
|
|
257
|
+
const resolution = await (0, opencode_executable_1.resolveOpencodeV1Executable)();
|
|
258
|
+
const executable = resolution.executable;
|
|
259
|
+
if (!executable) {
|
|
260
|
+
throw (0, install_hints_1.missingToolError)(this, (0, opencode_executable_1.describeOpencodeV1Unavailable)(resolution));
|
|
248
261
|
}
|
|
249
262
|
const sessionName = this.getSessionName(worktreeId, instanceId);
|
|
250
263
|
const target = (0, runtime_1.opencodeTarget)(worktreeId, instanceId);
|
|
@@ -355,7 +368,7 @@ class OpenCodeTool extends base_1.BaseCLITool {
|
|
|
355
368
|
// variable, because CommandMate holds the connection (#1846).
|
|
356
369
|
const plannedCommand = (0, agent_session_lifecycle_1.buildAgentLaunchCommandLine)({
|
|
357
370
|
target,
|
|
358
|
-
executablePath:
|
|
371
|
+
executablePath: executable.path,
|
|
359
372
|
worktreePath,
|
|
360
373
|
});
|
|
361
374
|
// Issue #2038: continue the conversation this instance was in before it
|
|
@@ -379,6 +392,7 @@ class OpenCodeTool extends base_1.BaseCLITool {
|
|
|
379
392
|
sessionId: resumeSessionId,
|
|
380
393
|
});
|
|
381
394
|
}
|
|
395
|
+
const launchedAt = Date.now();
|
|
382
396
|
await (0, tmux_1.sendKeys)(sessionName, launchCommand, true);
|
|
383
397
|
// Issue #1908: poll for opencode's own composer instead of sleeping 15 s.
|
|
384
398
|
await this.waitForReady(sessionName);
|
|
@@ -393,7 +407,17 @@ class OpenCodeTool extends base_1.BaseCLITool {
|
|
|
393
407
|
// with the server already listening, which the fixed 15 s wait did not
|
|
394
408
|
// guarantee: the 22.8 s run had nothing to probe at 15 s and would have
|
|
395
409
|
// lost structured events for the whole session.
|
|
396
|
-
await (0, runtime_1.attachOpencodeEventStream)(target);
|
|
410
|
+
const attached = await (0, runtime_1.attachOpencodeEventStream)(target);
|
|
411
|
+
// Issue #2939 (D2): a server that never answered may be OpenCode 1.x
|
|
412
|
+
// dying on the database OpenCode V2 migrated. opencode's own log says so;
|
|
413
|
+
// when it does, that is the start error. Otherwise nothing changes.
|
|
414
|
+
if (!attached && (0, ports_1.getAssignedOpencodePort)(target) !== null) {
|
|
415
|
+
const conflict = await (0, log_diagnosis_1.findOpencodeSharedDataConflict)(launchedAt);
|
|
416
|
+
if (conflict !== null) {
|
|
417
|
+
logger.warn('opencode-shared-data-conflict', { worktreeId, finding: conflict });
|
|
418
|
+
throw new Error((0, log_diagnosis_1.buildOpencodeSharedDataConflictMessage)(conflict));
|
|
419
|
+
}
|
|
420
|
+
}
|
|
397
421
|
logger.info('started-opencode-session:sessionname');
|
|
398
422
|
}
|
|
399
423
|
catch (error) {
|
|
@@ -24,7 +24,7 @@ exports.isImageCapableCLITool = isImageCapableCLITool;
|
|
|
24
24
|
* T2.1: Single source of truth for CLI tool IDs
|
|
25
25
|
* CLIToolType is derived from this constant (DRY principle)
|
|
26
26
|
*/
|
|
27
|
-
exports.CLI_TOOL_IDS = ['claude', 'codex', 'gemini', 'vibe-local', 'opencode', 'copilot', 'antigravity', 'command-code'];
|
|
27
|
+
exports.CLI_TOOL_IDS = ['claude', 'codex', 'gemini', 'vibe-local', 'opencode', 'copilot', 'antigravity', 'command-code', 'opencode-v2'];
|
|
28
28
|
/**
|
|
29
29
|
* CLI tools that render inside the terminal's alternate screen (Issue #1268).
|
|
30
30
|
*
|
|
@@ -48,6 +48,9 @@ const ALTERNATE_SCREEN_CLI_TOOLS = new Set([
|
|
|
48
48
|
// INLINE -- measured on 1.40.1, `#{alternate_on}` is 0 and the pane keeps its
|
|
49
49
|
// scrollback -- so its captured line count really is a monotonic cursor, the
|
|
50
50
|
// way codex's and agy's are.
|
|
51
|
+
// Issue #2934: OpenCode V2's TUI is the same full-screen toolkit as v1's
|
|
52
|
+
// (`#{alternate_on}` 1 on 2.0.18, measured 2026-09-28).
|
|
53
|
+
'opencode-v2',
|
|
51
54
|
]);
|
|
52
55
|
/**
|
|
53
56
|
* Whether a CLI tool renders in the terminal's alternate screen, making the
|
|
@@ -195,6 +198,7 @@ exports.CLI_TOOL_DISPLAY_NAMES = {
|
|
|
195
198
|
copilot: 'Copilot',
|
|
196
199
|
antigravity: 'Antigravity',
|
|
197
200
|
'command-code': 'Command Code',
|
|
201
|
+
'opencode-v2': 'OpenCode V2',
|
|
198
202
|
};
|
|
199
203
|
/**
|
|
200
204
|
* Check if a string is a valid CLIToolType
|
|
@@ -16,9 +16,12 @@
|
|
|
16
16
|
* - resolveScheduleCommandOptions(): CMATE.md row -> executor options (Issue #2044)
|
|
17
17
|
* - TOOLS_WITH_MODEL_SUPPORT: Set of tools supporting --model in CMATE.md
|
|
18
18
|
* - TOOLS_WITH_RUN_OPTIONS: Set of tools whose column accepts a flag list
|
|
19
|
+
* - TOOLS_WITH_VARIANT_ON_MODEL: tools whose variant rides on the model (Issue #2982)
|
|
20
|
+
* - validateVariantHasModel(): refuse a model-less variant for those tools (Issue #2982)
|
|
19
21
|
*/
|
|
20
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.OPENCODE_COLUMN_SYNTAX = exports.TOOLS_WITH_RUN_OPTIONS = exports.TOOLS_WITH_MODEL_SUPPORT = void 0;
|
|
23
|
+
exports.OPENCODE_V2_COLUMN_SYNTAX = exports.OPENCODE_COLUMN_SYNTAX = exports.TOOLS_WITH_VARIANT_ON_MODEL = exports.TOOLS_WITH_RUN_OPTIONS = exports.TOOLS_WITH_MODEL_SUPPORT = void 0;
|
|
24
|
+
exports.validateVariantHasModel = validateVariantHasModel;
|
|
22
25
|
exports.tokenizeCliToolColumn = tokenizeCliToolColumn;
|
|
23
26
|
exports.parseCliToolColumn = parseCliToolColumn;
|
|
24
27
|
exports.validateCopilotModelName = validateCopilotModelName;
|
|
@@ -57,8 +60,14 @@ const opencode_constants_1 = require("../config/opencode-constants");
|
|
|
57
60
|
* format `opencode run --help` documents for `-m, --model` (measured on
|
|
58
61
|
* opencode 1.18.21). It is not prefixed with `ollama/` — see
|
|
59
62
|
* `buildCliArgs()` for why that prefix went away.
|
|
63
|
+
*
|
|
64
|
+
* ## `opencode-v2` (Issue #2982)
|
|
65
|
+
*
|
|
66
|
+
* `opencode2 run -m` takes the same `provider/model` value (plus an optional
|
|
67
|
+
* `#variant`, see {@link TOOLS_WITH_VARIANT_ON_MODEL}), and the executor's
|
|
68
|
+
* `opencode-v2` case has built `-m` since #2974.
|
|
60
69
|
*/
|
|
61
|
-
exports.TOOLS_WITH_MODEL_SUPPORT = new Set(['copilot', 'opencode']);
|
|
70
|
+
exports.TOOLS_WITH_MODEL_SUPPORT = new Set(['copilot', 'opencode', 'opencode-v2']);
|
|
62
71
|
/**
|
|
63
72
|
* CLI Tools whose CMATE.md column is a **flag list** rather than one fixed shape
|
|
64
73
|
* (Issue #2044).
|
|
@@ -73,8 +82,28 @@ exports.TOOLS_WITH_MODEL_SUPPORT = new Set(['copilot', 'opencode']);
|
|
|
73
82
|
* CommandMate can drive (`--agent`, `--variant`, `-c`, `--title`), and a
|
|
74
83
|
* schedule that wants `--agent plan --variant high` cannot say so in three
|
|
75
84
|
* tokens. Membership here is what {@link parseCliToolColumn} branches on.
|
|
85
|
+
*
|
|
86
|
+
* Issue #2982: `opencode-v2` joins with the same five column flags. Its
|
|
87
|
+
* `opencode2 run` has `-m`, `--agent`, `-c` and `--title` with v1's meaning;
|
|
88
|
+
* `--variant` is the one difference, see {@link TOOLS_WITH_VARIANT_ON_MODEL}.
|
|
76
89
|
*/
|
|
77
|
-
exports.TOOLS_WITH_RUN_OPTIONS = new Set(['opencode']);
|
|
90
|
+
exports.TOOLS_WITH_RUN_OPTIONS = new Set(['opencode', 'opencode-v2']);
|
|
91
|
+
/**
|
|
92
|
+
* Tools whose CLI has no `--variant` flag and takes the variant as a suffix of
|
|
93
|
+
* the model instead: `-m provider/model#variant` (Issue #2982).
|
|
94
|
+
*
|
|
95
|
+
* `opencode2 run` (2.0.18, measured in #2974) answers `--variant` with
|
|
96
|
+
* "Unrecognized flag" and exit 1. The column still spells the variant as
|
|
97
|
+
* `--variant <name>` — the same grammar, dialog field and writer order as v1 —
|
|
98
|
+
* and `claude-executor.ts` composes `model#variant`. Two consequences are
|
|
99
|
+
* enforced by {@link validateVariantHasModel}:
|
|
100
|
+
*
|
|
101
|
+
* - a variant **without a model** has nothing to ride on, and is an error
|
|
102
|
+
* rather than a silently dropped option;
|
|
103
|
+
* - `#` in the model itself is not a way around it: `MODEL_NAME_PATTERN`
|
|
104
|
+
* already refuses `#`, so `--model x#high` is rejected as an invalid model.
|
|
105
|
+
*/
|
|
106
|
+
exports.TOOLS_WITH_VARIANT_ON_MODEL = new Set(['opencode-v2']);
|
|
78
107
|
/**
|
|
79
108
|
* The opencode column grammar, as one line, for error messages.
|
|
80
109
|
*
|
|
@@ -82,6 +111,28 @@ exports.TOOLS_WITH_RUN_OPTIONS = new Set(['opencode']);
|
|
|
82
111
|
* the flags the loop accepts are edited together.
|
|
83
112
|
*/
|
|
84
113
|
exports.OPENCODE_COLUMN_SYNTAX = 'opencode [--model <provider/model>] [--agent <name>] [--variant <name>] [--continue] [--title <text>]';
|
|
114
|
+
/**
|
|
115
|
+
* The opencode-v2 column grammar, as one line, for error messages (Issue #2982).
|
|
116
|
+
*
|
|
117
|
+
* Same flags as {@link OPENCODE_COLUMN_SYNTAX}; `--variant` is nested inside
|
|
118
|
+
* the `--model` bracket because it is only valid alongside a model.
|
|
119
|
+
*/
|
|
120
|
+
exports.OPENCODE_V2_COLUMN_SYNTAX = 'opencode-v2 [--model <provider/model> [--variant <name>]] [--agent <name>] [--continue] [--title <text>]';
|
|
121
|
+
/**
|
|
122
|
+
* Error for a variant given without a model, for the tools in
|
|
123
|
+
* {@link TOOLS_WITH_VARIANT_ON_MODEL} (Issue #2982). Shared by the column
|
|
124
|
+
* parser and `cmate-writer.validateScheduleInput()` so the file and the
|
|
125
|
+
* form refuse the same row with the same words.
|
|
126
|
+
*
|
|
127
|
+
* @returns The error message, or undefined when the combination is fine
|
|
128
|
+
*/
|
|
129
|
+
function validateVariantHasModel(cliToolId, model, variant) {
|
|
130
|
+
if (!exports.TOOLS_WITH_VARIANT_ON_MODEL.has(cliToolId))
|
|
131
|
+
return undefined;
|
|
132
|
+
if (!variant?.trim() || model?.trim())
|
|
133
|
+
return undefined;
|
|
134
|
+
return `${cliToolId} option "--variant" needs "--model" (sent as -m <provider/model>#<variant>)`;
|
|
135
|
+
}
|
|
85
136
|
// =============================================================================
|
|
86
137
|
// Parse Functions
|
|
87
138
|
// =============================================================================
|
|
@@ -154,7 +205,8 @@ function tokenizeCliToolColumn(raw) {
|
|
|
154
205
|
* - **a missing value** — `--agent --title x` would make `--title` the agent
|
|
155
206
|
* name, and a value starting with `-` is the DR4-001 injection shape anyway.
|
|
156
207
|
*
|
|
157
|
-
* @param cliToolId -
|
|
208
|
+
* @param cliToolId - `opencode` or `opencode-v2` (Issue #2982); echoed into
|
|
209
|
+
* error messages and picks the syntax hint
|
|
158
210
|
* @param tokens - Tokens after the tool id
|
|
159
211
|
* @returns The parsed options, or an error
|
|
160
212
|
*/
|
|
@@ -218,10 +270,15 @@ function parseOpencodeRunFlags(cliToolId, tokens) {
|
|
|
218
270
|
parsed.continueSession = true;
|
|
219
271
|
break;
|
|
220
272
|
}
|
|
221
|
-
default:
|
|
222
|
-
|
|
273
|
+
default: {
|
|
274
|
+
const syntax = cliToolId === 'opencode-v2' ? exports.OPENCODE_V2_COLUMN_SYNTAX : exports.OPENCODE_COLUMN_SYNTAX;
|
|
275
|
+
return { cliToolId, error: `${cliToolId} only supports: ${syntax}` };
|
|
276
|
+
}
|
|
223
277
|
}
|
|
224
278
|
}
|
|
279
|
+
const variantError = validateVariantHasModel(cliToolId, parsed.model, parsed.variant);
|
|
280
|
+
if (variantError)
|
|
281
|
+
return { cliToolId, error: variantError };
|
|
225
282
|
return parsed;
|
|
226
283
|
}
|
|
227
284
|
/**
|
|
@@ -508,7 +565,8 @@ function parseAndValidateCliToolColumn(raw) {
|
|
|
508
565
|
* {@link TOOLS_WITH_MODEL_SUPPORT} for the model, exactly as that line did, so
|
|
509
566
|
* the two agree about which tools take one; the run options are additionally
|
|
510
567
|
* gated on {@link TOOLS_WITH_RUN_OPTIONS} so a future tool cannot inherit
|
|
511
|
-
* opencode's flags by accident.
|
|
568
|
+
* opencode's flags by accident. For `opencode-v2` (Issue #2982) the variant is
|
|
569
|
+
* passed on as-is; the executor folds it into `-m model#variant`.
|
|
512
570
|
*
|
|
513
571
|
* Living here rather than in `job-executor.ts` is the point: the column's
|
|
514
572
|
* grammar is this module's business, and a scheduler that re-states any part of
|
|
@@ -206,6 +206,12 @@ function parseSchedulesSection(rows) {
|
|
|
206
206
|
logger.warn('parse:invalid-cli-tool', { name: sanitizedName, cliToolId: resolvedCliToolId });
|
|
207
207
|
continue;
|
|
208
208
|
}
|
|
209
|
+
// Issue #2934: registered but not schedulable (SCHEDULE_UNSUPPORTED_CLI_TOOLS,
|
|
210
|
+
// empty since #2974). Skipped like an unknown tool, so no run is built for it.
|
|
211
|
+
if (!(0, schedule_config_1.isScheduleSupportedCliTool)(resolvedCliToolId)) {
|
|
212
|
+
logger.warn('parse:unsupported-cli-tool', { name: sanitizedName, cliToolId: resolvedCliToolId });
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
209
215
|
const defaultPermission = schedule_config_1.DEFAULT_PERMISSIONS[resolvedCliToolId] ?? '';
|
|
210
216
|
let permission = permissionStr?.trim() || defaultPermission;
|
|
211
217
|
// Validate permission against allowed values
|
|
@@ -237,6 +243,12 @@ function parseSchedulesSection(rows) {
|
|
|
237
243
|
case 'command-code':
|
|
238
244
|
allowedValues = schedule_config_1.COMMAND_CODE_SCHEDULE_PERMISSIONS;
|
|
239
245
|
break;
|
|
246
|
+
// Issue #2974: `default` (no flag) / `auto` (`--auto`). An empty cell
|
|
247
|
+
// resolves to `default`, so an `ask` rule fails the run rather than being
|
|
248
|
+
// approved unattended.
|
|
249
|
+
case 'opencode-v2':
|
|
250
|
+
allowedValues = schedule_config_1.OPENCODE_V2_PERMISSIONS;
|
|
251
|
+
break;
|
|
240
252
|
case 'gemini':
|
|
241
253
|
case 'vibe-local':
|
|
242
254
|
case 'opencode':
|
|
@@ -225,6 +225,16 @@ function validateSchedulesSection(rows) {
|
|
|
225
225
|
field: 'cliTool',
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
|
+
// Issue #2934: a registered tool that cannot be scheduled
|
|
229
|
+
// (SCHEDULE_UNSUPPORTED_CLI_TOOLS, empty since #2974). The parser skips the
|
|
230
|
+
// same rows.
|
|
231
|
+
if (parsed && (0, types_1.isCliToolType)(parsed.cliToolId) && !(0, schedule_config_1.isScheduleSupportedCliTool)(parsed.cliToolId)) {
|
|
232
|
+
errors.push({
|
|
233
|
+
row: i,
|
|
234
|
+
message: `Row ${i + 1}: CLI Tool "${parsed.cliToolId}" is not supported in schedules yet`,
|
|
235
|
+
field: 'cliTool',
|
|
236
|
+
});
|
|
237
|
+
}
|
|
228
238
|
// Validate permission (6th column)
|
|
229
239
|
// Empty/missing permission is allowed -- parser applies default per CLI tool
|
|
230
240
|
const permissionStr = row[5];
|
|
@@ -245,7 +255,9 @@ function validateSchedulesSection(rows) {
|
|
|
245
255
|
: cliToolId === 'copilot' ? schedule_config_1.COPILOT_PERMISSIONS
|
|
246
256
|
: cliToolId === 'antigravity' ? schedule_config_1.ANTIGRAVITY_PERMISSIONS
|
|
247
257
|
: cliToolId === 'command-code' ? schedule_config_1.COMMAND_CODE_SCHEDULE_PERMISSIONS
|
|
248
|
-
:
|
|
258
|
+
// Issue #2974: `default` / `auto`, the parser's and the dialog's list.
|
|
259
|
+
: cliToolId === 'opencode-v2' ? schedule_config_1.OPENCODE_V2_PERMISSIONS
|
|
260
|
+
: [];
|
|
249
261
|
if (!allowedValues.includes(trimmedPermission)) {
|
|
250
262
|
errors.push({
|
|
251
263
|
row: i,
|