commandmate 0.22.2 → 0.23.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 +108 -108
- package/.next/app-path-routes-manifest.json +21 -21
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +12 -12
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/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 +1 -1
- 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/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.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/external-apps/route.js.nft.json +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route.js +1 -1
- package/.next/server/app/api/fs/browse/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route.js.nft.json +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 +1 -1
- 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.js +1 -1
- package/.next/server/app/api/metrics/vibe/route.js.nft.json +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/subscriptions/route.js +1 -1
- package/.next/server/app/api/push/subscriptions/route.js.nft.json +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route.js +1 -1
- package/.next/server/app/api/push/vapid/route.js.nft.json +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/repositories/excluded/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/skills/installations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route.js +1 -1
- package/.next/server/app/api/skills/operations/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route.js +1 -1
- package/.next/server/app/api/skills/reindex/route.js.nft.json +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.js +1 -4
- package/.next/server/app/api/tasks/[taskId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route.js +1 -4
- package/.next/server/app/api/tasks/[taskId]/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route.js +1 -1
- package/.next/server/app/api/templates/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route.js +1 -1
- package/.next/server/app/api/templates/route.js.nft.json +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/todos/route.js +1 -1
- package/.next/server/app/api/todos/route.js.nft.json +1 -1
- package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route.js.nft.json +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route.js +1 -1
- package/.next/server/app/api/verification/runs/route.js.nft.json +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]/cli-tool/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.js.nft.json +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 +2 -2
- 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]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js.nft.json +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 +2 -2
- 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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js.nft.json +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]/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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/marp-render/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/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]/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 +2 -2
- 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 +1 -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 -3
- 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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route.js.nft.json +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 +1 -1
- 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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js.nft.json +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]/start-polling/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/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.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route.js.nft.json +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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route.js.nft.json +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/route.js +1 -4
- package/.next/server/app/api/worktrees/[id]/verify/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/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_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route.js +1 -1
- package/.next/server/app/proxy/[...path]/route.js.nft.json +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.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +2 -2
- package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +21 -21
- package/.next/server/chunks/1029.js +1 -1
- package/.next/server/chunks/1068.js +1 -1
- 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/2546.js +1 -1
- package/.next/server/chunks/3241.js +1 -0
- package/.next/server/chunks/3417.js +1 -1
- package/.next/server/chunks/406.js +10 -6
- package/.next/server/chunks/4444.js +1 -1
- package/.next/server/chunks/5959.js +4 -5
- package/.next/server/chunks/5998.js +1 -12
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6274.js +3 -3
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6781.js +1 -0
- package/.next/server/chunks/7458.js +6 -0
- package/.next/server/chunks/{3753.js → 7970.js} +57 -32
- package/.next/server/chunks/8536.js +1 -1
- package/.next/server/chunks/8807.js +180 -127
- package/.next/server/chunks/9058.js +1 -1
- package/.next/server/chunks/9067.js +1 -1
- package/.next/server/chunks/9360.js +1 -1
- package/.next/server/chunks/9687.js +2 -2
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/server/src/middleware.js.map +1 -1
- package/.next/static/chunks/{6488-53a3e1d78e4fe8f7.js → 6488-95ba9d24a76f0cc5.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/{page-6dc0b8c4e808ea3e.js → page-966a451ae7b0903a.js} +1 -1
- package/.next/trace +12 -12
- package/dist/server/src/config/log-config.js +10 -1
- package/dist/server/src/config/safe-directory.js +103 -0
- package/dist/server/src/config/system-directories.js +74 -9
- package/dist/server/src/lib/cli-tools/antigravity.js +19 -2
- package/dist/server/src/lib/cli-tools/codex.js +95 -1
- package/dist/server/src/lib/cli-tools/copilot.js +30 -1
- package/dist/server/src/lib/cli-tools/gemini.js +28 -2
- package/dist/server/src/lib/cli-tools/opencode.js +51 -2
- package/dist/server/src/lib/git/git-default-branch.js +59 -0
- package/dist/server/src/lib/hooks/agent-event-service.js +205 -0
- package/dist/server/src/lib/hooks/agent-event-types.js +7 -86
- package/dist/server/src/lib/hooks/hook-settings-generator.js +26 -11
- package/dist/server/src/lib/hooks/permission-decision-service.js +269 -0
- package/dist/server/src/lib/hooks/sources/abstain.js +78 -0
- package/dist/server/src/lib/hooks/sources/antigravity/hooks-config.js +372 -0
- package/dist/server/src/lib/hooks/sources/antigravity/source.js +225 -0
- package/dist/server/src/lib/hooks/sources/antigravity/tool-id.js +16 -0
- package/dist/server/src/lib/hooks/sources/claude/source.js +143 -0
- package/dist/server/src/lib/hooks/sources/claude/tool-id.js +18 -0
- package/dist/server/src/lib/hooks/sources/codex/hooks-config.js +465 -0
- package/dist/server/src/lib/hooks/sources/codex/source.js +138 -0
- package/dist/server/src/lib/hooks/sources/codex/tool-id.js +15 -0
- package/dist/server/src/lib/hooks/sources/copilot/hook-settings.js +473 -0
- package/dist/server/src/lib/hooks/sources/copilot/source.js +210 -0
- package/dist/server/src/lib/hooks/sources/copilot/tool-id.js +15 -0
- package/dist/server/src/lib/hooks/sources/define-source.js +169 -0
- package/dist/server/src/lib/hooks/sources/event-mapper.js +157 -0
- package/dist/server/src/lib/hooks/sources/gemini/event-vocabulary.js +102 -0
- package/dist/server/src/lib/hooks/sources/gemini/settings-generator.js +315 -0
- package/dist/server/src/lib/hooks/sources/gemini/shared-config-tree.js +103 -0
- package/dist/server/src/lib/hooks/sources/gemini/source.js +151 -0
- package/dist/server/src/lib/hooks/sources/gemini/tool-id.js +17 -0
- package/dist/server/src/lib/hooks/sources/hook-event-vocabulary.js +111 -0
- package/dist/server/src/lib/hooks/sources/index.js +62 -0
- package/dist/server/src/lib/hooks/sources/legacy-relay.js +84 -0
- package/dist/server/src/lib/hooks/sources/opencode/client.js +299 -0
- package/dist/server/src/lib/hooks/sources/opencode/ingest.js +261 -0
- package/dist/server/src/lib/hooks/sources/opencode/mappers.js +154 -0
- package/dist/server/src/lib/hooks/sources/opencode/payloads.js +189 -0
- package/dist/server/src/lib/hooks/sources/opencode/ports.js +295 -0
- package/dist/server/src/lib/hooks/sources/opencode/runtime.js +159 -0
- package/dist/server/src/lib/hooks/sources/opencode/source.js +250 -0
- package/dist/server/src/lib/hooks/sources/opencode/subscription.js +422 -0
- package/dist/server/src/lib/hooks/sources/opencode/tool-id.js +14 -0
- package/dist/server/src/lib/hooks/sources/opencode/turn-gate.js +193 -0
- package/dist/server/src/lib/hooks/sources/pending-decisions.js +127 -0
- package/dist/server/src/lib/hooks/sources/registry.js +111 -0
- package/dist/server/src/lib/hooks/sources/types.js +46 -0
- package/dist/server/src/lib/session/agent-session-lifecycle.js +82 -0
- package/dist/server/src/lib/session/claude-session.js +10 -3
- package/dist/server/src/lib/tasks/contract-message.js +175 -0
- package/dist/server/src/lib/verification/env-clean-gate.js +320 -0
- package/dist/server/src/lib/verification/env-snapshot.js +474 -0
- package/dist/server/src/lib/verification/gate-runner.js +802 -0
- package/dist/server/src/lib/verification/scope-gate.js +402 -0
- package/dist/server/src/lib/verification/verify-config.js +281 -0
- package/package.json +1 -1
- package/scripts/hooks/cmate-agent-event.sh +73 -3
- package/.next/server/chunks/8856.js +0 -4
- /package/.next/static/{XpKfn5x6H-mtTaXI9yNmb → wH6K6QNPHSdATFkVoIcy3}/_buildManifest.js +0 -0
- /package/.next/static/{XpKfn5x6H-mtTaXI9yNmb → wH6K6QNPHSdATFkVoIcy3}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The hook spellings and payload field names that several agent CLIs happen to
|
|
4
|
+
* share (Issue #1759, S1/S2 lifted out of `agent-event-types`).
|
|
5
|
+
*
|
|
6
|
+
* `agent-event-types` used to carry `CLAUDE_HOOK_EVENT_NAMES` and
|
|
7
|
+
* `extractClaudeEventDetail` next to the seven-word vocabulary. That put one
|
|
8
|
+
* tool's spelling inside the module every tool-agnostic consumer imports, and
|
|
9
|
+
* the predictable next move — a Phase 4-2 implementer adding `BeforeTool` to
|
|
10
|
+
* the same table — is exactly the copy-paste Epic #1720 exists to stop. The
|
|
11
|
+
* words stayed in `agent-event-types`; the spellings moved here, where a source
|
|
12
|
+
* *chooses* them.
|
|
13
|
+
*
|
|
14
|
+
* The table below is not "Claude's table". #1757 §8.1 measured all four new
|
|
15
|
+
* tools, and Claude, codex and copilot spell these events identically; gemini
|
|
16
|
+
* renames half of them (`BeforeTool` / `AfterTool` / `BeforeAgent` /
|
|
17
|
+
* `AfterAgent`) and antigravity ships no event-name field at all. So this is
|
|
18
|
+
* the CamelCase dialect three tools share, and a source that speaks a different
|
|
19
|
+
* one brings its own mappers.
|
|
20
|
+
*
|
|
21
|
+
* @module lib/hooks/sources/hook-event-vocabulary
|
|
22
|
+
*/
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.TOOL_CALL_ID_FIELDS = exports.SESSION_ID_FIELDS = exports.CAMEL_CASE_HOOK_EVENT_NAMES = void 0;
|
|
25
|
+
exports.extractSnakeCaseEventDetail = extractSnakeCaseEventDetail;
|
|
26
|
+
const event_mapper_1 = require("./event-mapper");
|
|
27
|
+
/**
|
|
28
|
+
* `hook_event_name` values, in the CamelCase dialect Claude / codex / copilot
|
|
29
|
+
* share, mapped onto the seven words.
|
|
30
|
+
*
|
|
31
|
+
* Only the events CommandMate registers appear. An unmapped name is refused
|
|
32
|
+
* rather than filed under something adjacent — the whole value of a structured
|
|
33
|
+
* event is that it says precisely what happened.
|
|
34
|
+
*
|
|
35
|
+
* `PermissionRequest` is deliberately absent: its response body is a decision
|
|
36
|
+
* the agent obeys, which is the opposite contract to the fire-and-forget event
|
|
37
|
+
* route (#1724). It travels through {@link AgentEventSource.encodeVerdict}.
|
|
38
|
+
*
|
|
39
|
+
* `PostToolUse` is here on the strength of a measurement taken for #1726 rather
|
|
40
|
+
* than of the #1721 spike, which recorded it as unobserved. Driving a live
|
|
41
|
+
* Claude v2.1.223 session on 2026-08-06 with a `PostToolUse` hook registered:
|
|
42
|
+
*
|
|
43
|
+
* ```
|
|
44
|
+
* 15:36:04.112 PreToolUse AskUserQuestion (picker drawn)
|
|
45
|
+
* 15:36:10.127 Notification permission_prompt (picker still up)
|
|
46
|
+
* 15:36:28.643 PostToolUse AskUserQuestion (the human answered)
|
|
47
|
+
* 15:36:29.992 Stop
|
|
48
|
+
* ```
|
|
49
|
+
*
|
|
50
|
+
* It fires, and it is the precise signal — "this tool call is over" — where
|
|
51
|
+
* `Stop` is "the turn is over" and can be minutes later if the agent keeps
|
|
52
|
+
* working after the answer.
|
|
53
|
+
*/
|
|
54
|
+
exports.CAMEL_CASE_HOOK_EVENT_NAMES = {
|
|
55
|
+
Stop: 'stop',
|
|
56
|
+
SubagentStop: 'stop',
|
|
57
|
+
Notification: 'notification',
|
|
58
|
+
SessionStart: 'session_start',
|
|
59
|
+
SessionEnd: 'session_end',
|
|
60
|
+
UserPromptSubmit: 'user_prompt_submit',
|
|
61
|
+
// Issue #1726. Injected with matcher `AskUserQuestion`, so in practice these
|
|
62
|
+
// only ever arrive for that tool — but a receiver re-reads `tool_name` rather
|
|
63
|
+
// than trusting the matcher, because a user's own settings.json is
|
|
64
|
+
// concatenated with the injected one and may register a wider matcher.
|
|
65
|
+
PreToolUse: 'pre_tool_use',
|
|
66
|
+
PostToolUse: 'post_tool_use',
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Payload keys that carry the agent's own session id, in preference order
|
|
70
|
+
* (#1757 R4).
|
|
71
|
+
*
|
|
72
|
+
* `session_id` covers Claude, codex, copilot and gemini; `conversationId` is
|
|
73
|
+
* antigravity's protojson spelling of the same thing. Never an identity key —
|
|
74
|
+
* `/clear` mints a new one while the instance is unchanged (#1721).
|
|
75
|
+
*/
|
|
76
|
+
exports.SESSION_ID_FIELDS = ['session_id', 'conversationId'];
|
|
77
|
+
/**
|
|
78
|
+
* Payload keys that correlate one tool call (#1757 R5).
|
|
79
|
+
*
|
|
80
|
+
* `tool_use_id` is Claude's and codex's; it is absent from `PermissionRequest`
|
|
81
|
+
* on both (D2), so nothing may require it.
|
|
82
|
+
*/
|
|
83
|
+
exports.TOOL_CALL_ID_FIELDS = ['tool_use_id'];
|
|
84
|
+
/**
|
|
85
|
+
* The event's subtype for a snake_case payload, or null when it has none.
|
|
86
|
+
*
|
|
87
|
+
* Each event spells this differently and none of them share a field:
|
|
88
|
+
*
|
|
89
|
+
* - `Notification` → `notification_type` (`permission_prompt` / `idle_prompt`).
|
|
90
|
+
* This is also what a `Notification` matcher is tested against — **not**
|
|
91
|
+
* `message`, which is English prose for a human (#1721 D3).
|
|
92
|
+
* - `SessionEnd` → `reason` (`clear` / `prompt_input_exit` / …)
|
|
93
|
+
* - `SessionStart` → `source` (`startup` / `clear` / …)
|
|
94
|
+
* - `PreToolUse` / `PostToolUse` → `tool_name` (`AskUserQuestion`), Issue #1726
|
|
95
|
+
*
|
|
96
|
+
* `stop` and `user_prompt_submit` have no subtype, so they answer null.
|
|
97
|
+
*/
|
|
98
|
+
function extractSnakeCaseEventDetail(event, payload) {
|
|
99
|
+
const field = event === 'notification'
|
|
100
|
+
? 'notification_type'
|
|
101
|
+
: event === 'session_end'
|
|
102
|
+
? 'reason'
|
|
103
|
+
: event === 'session_start'
|
|
104
|
+
? 'source'
|
|
105
|
+
: event === 'pre_tool_use' || event === 'post_tool_use'
|
|
106
|
+
? 'tool_name'
|
|
107
|
+
: null;
|
|
108
|
+
if (field === null)
|
|
109
|
+
return null;
|
|
110
|
+
return (0, event_mapper_1.boundDetail)((0, event_mapper_1.readStringField)(payload, field));
|
|
111
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `AgentEventSource` — the public surface (Issue #1759).
|
|
4
|
+
*
|
|
5
|
+
* Import from here rather than from the files underneath. Importing `./registry`
|
|
6
|
+
* is what registers the built-in sources, so this barrel is also the guarantee
|
|
7
|
+
* that a caller who reached for the types got the implementations too.
|
|
8
|
+
*
|
|
9
|
+
* The spec this implements is `docs/design/agent-event-source-interface.md`,
|
|
10
|
+
* which also carries the checklist for adding a tool.
|
|
11
|
+
*
|
|
12
|
+
* @module lib/hooks/sources
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.OPENCODE_CLI_TOOL_ID = exports.CODEX_CLI_TOOL_ID = exports.ANTIGRAVITY_CLI_TOOL_ID = exports.GEMINI_CLI_TOOL_ID = exports.COPILOT_CLI_TOOL_ID = exports.CLAUDE_CLI_TOOL_ID = exports.isAbstainSafe = exports.describeNoDecision = exports.describeAbstain = exports.resetPendingDecisions = exports.openDecisionSlot = exports.listOpenDecisions = exports.closeDecisionSlot = exports.answerPendingDecision = exports.TOOL_CALL_ID_FIELDS = exports.SESSION_ID_FIELDS = exports.extractSnakeCaseEventDetail = exports.CAMEL_CASE_HOOK_EVENT_NAMES = exports.whenNamed = exports.runEventMappers = exports.resetUnknownEventTallies = exports.readStringField = exports.readNestedString = exports.readFirstStringField = exports.isPlainObject = exports.getUnknownEventTally = exports.fromNameTable = exports.boundDetail = exports.definePushHookSource = exports.definePullEventSource = exports.unregisterAgentEventSource = exports.registerAgentEventSource = exports.listAgentEventSources = exports.hasAgentEventSource = exports.getAgentEventSource = void 0;
|
|
16
|
+
var registry_1 = require("./registry");
|
|
17
|
+
Object.defineProperty(exports, "getAgentEventSource", { enumerable: true, get: function () { return registry_1.getAgentEventSource; } });
|
|
18
|
+
Object.defineProperty(exports, "hasAgentEventSource", { enumerable: true, get: function () { return registry_1.hasAgentEventSource; } });
|
|
19
|
+
Object.defineProperty(exports, "listAgentEventSources", { enumerable: true, get: function () { return registry_1.listAgentEventSources; } });
|
|
20
|
+
Object.defineProperty(exports, "registerAgentEventSource", { enumerable: true, get: function () { return registry_1.registerAgentEventSource; } });
|
|
21
|
+
Object.defineProperty(exports, "unregisterAgentEventSource", { enumerable: true, get: function () { return registry_1.unregisterAgentEventSource; } });
|
|
22
|
+
var define_source_1 = require("./define-source");
|
|
23
|
+
Object.defineProperty(exports, "definePullEventSource", { enumerable: true, get: function () { return define_source_1.definePullEventSource; } });
|
|
24
|
+
Object.defineProperty(exports, "definePushHookSource", { enumerable: true, get: function () { return define_source_1.definePushHookSource; } });
|
|
25
|
+
var event_mapper_1 = require("./event-mapper");
|
|
26
|
+
Object.defineProperty(exports, "boundDetail", { enumerable: true, get: function () { return event_mapper_1.boundDetail; } });
|
|
27
|
+
Object.defineProperty(exports, "fromNameTable", { enumerable: true, get: function () { return event_mapper_1.fromNameTable; } });
|
|
28
|
+
Object.defineProperty(exports, "getUnknownEventTally", { enumerable: true, get: function () { return event_mapper_1.getUnknownEventTally; } });
|
|
29
|
+
Object.defineProperty(exports, "isPlainObject", { enumerable: true, get: function () { return event_mapper_1.isPlainObject; } });
|
|
30
|
+
Object.defineProperty(exports, "readFirstStringField", { enumerable: true, get: function () { return event_mapper_1.readFirstStringField; } });
|
|
31
|
+
Object.defineProperty(exports, "readNestedString", { enumerable: true, get: function () { return event_mapper_1.readNestedString; } });
|
|
32
|
+
Object.defineProperty(exports, "readStringField", { enumerable: true, get: function () { return event_mapper_1.readStringField; } });
|
|
33
|
+
Object.defineProperty(exports, "resetUnknownEventTallies", { enumerable: true, get: function () { return event_mapper_1.resetUnknownEventTallies; } });
|
|
34
|
+
Object.defineProperty(exports, "runEventMappers", { enumerable: true, get: function () { return event_mapper_1.runEventMappers; } });
|
|
35
|
+
Object.defineProperty(exports, "whenNamed", { enumerable: true, get: function () { return event_mapper_1.whenNamed; } });
|
|
36
|
+
var hook_event_vocabulary_1 = require("./hook-event-vocabulary");
|
|
37
|
+
Object.defineProperty(exports, "CAMEL_CASE_HOOK_EVENT_NAMES", { enumerable: true, get: function () { return hook_event_vocabulary_1.CAMEL_CASE_HOOK_EVENT_NAMES; } });
|
|
38
|
+
Object.defineProperty(exports, "extractSnakeCaseEventDetail", { enumerable: true, get: function () { return hook_event_vocabulary_1.extractSnakeCaseEventDetail; } });
|
|
39
|
+
Object.defineProperty(exports, "SESSION_ID_FIELDS", { enumerable: true, get: function () { return hook_event_vocabulary_1.SESSION_ID_FIELDS; } });
|
|
40
|
+
Object.defineProperty(exports, "TOOL_CALL_ID_FIELDS", { enumerable: true, get: function () { return hook_event_vocabulary_1.TOOL_CALL_ID_FIELDS; } });
|
|
41
|
+
var pending_decisions_1 = require("./pending-decisions");
|
|
42
|
+
Object.defineProperty(exports, "answerPendingDecision", { enumerable: true, get: function () { return pending_decisions_1.answerPendingDecision; } });
|
|
43
|
+
Object.defineProperty(exports, "closeDecisionSlot", { enumerable: true, get: function () { return pending_decisions_1.closeDecisionSlot; } });
|
|
44
|
+
Object.defineProperty(exports, "listOpenDecisions", { enumerable: true, get: function () { return pending_decisions_1.listOpenDecisions; } });
|
|
45
|
+
Object.defineProperty(exports, "openDecisionSlot", { enumerable: true, get: function () { return pending_decisions_1.openDecisionSlot; } });
|
|
46
|
+
Object.defineProperty(exports, "resetPendingDecisions", { enumerable: true, get: function () { return pending_decisions_1.resetPendingDecisions; } });
|
|
47
|
+
var abstain_1 = require("./abstain");
|
|
48
|
+
Object.defineProperty(exports, "describeAbstain", { enumerable: true, get: function () { return abstain_1.describeAbstain; } });
|
|
49
|
+
Object.defineProperty(exports, "describeNoDecision", { enumerable: true, get: function () { return abstain_1.describeNoDecision; } });
|
|
50
|
+
Object.defineProperty(exports, "isAbstainSafe", { enumerable: true, get: function () { return abstain_1.isAbstainSafe; } });
|
|
51
|
+
var tool_id_1 = require("./claude/tool-id");
|
|
52
|
+
Object.defineProperty(exports, "CLAUDE_CLI_TOOL_ID", { enumerable: true, get: function () { return tool_id_1.CLAUDE_CLI_TOOL_ID; } });
|
|
53
|
+
var tool_id_2 = require("./copilot/tool-id");
|
|
54
|
+
Object.defineProperty(exports, "COPILOT_CLI_TOOL_ID", { enumerable: true, get: function () { return tool_id_2.COPILOT_CLI_TOOL_ID; } });
|
|
55
|
+
var tool_id_3 = require("./gemini/tool-id");
|
|
56
|
+
Object.defineProperty(exports, "GEMINI_CLI_TOOL_ID", { enumerable: true, get: function () { return tool_id_3.GEMINI_CLI_TOOL_ID; } });
|
|
57
|
+
var tool_id_4 = require("./antigravity/tool-id");
|
|
58
|
+
Object.defineProperty(exports, "ANTIGRAVITY_CLI_TOOL_ID", { enumerable: true, get: function () { return tool_id_4.ANTIGRAVITY_CLI_TOOL_ID; } });
|
|
59
|
+
var tool_id_5 = require("./codex/tool-id");
|
|
60
|
+
Object.defineProperty(exports, "CODEX_CLI_TOOL_ID", { enumerable: true, get: function () { return tool_id_5.CODEX_CLI_TOOL_ID; } });
|
|
61
|
+
var tool_id_6 = require("./opencode/tool-id");
|
|
62
|
+
Object.defineProperty(exports, "OPENCODE_CLI_TOOL_ID", { enumerable: true, get: function () { return tool_id_6.OPENCODE_CLI_TOOL_ID; } });
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The source used for a tool that has no source yet (Issue #1759).
|
|
4
|
+
*
|
|
5
|
+
* `POST /api/hooks/agent-event` has accepted `{"tool":"codex","event":"stop"}`
|
|
6
|
+
* since #1549, from hooks operators wired up by hand following
|
|
7
|
+
* `docs/user-guide/agent-event-hooks.md`. Those requests work today, and Phase
|
|
8
|
+
* 4-1 is a refactor: if asking the registry for an unregistered tool returned
|
|
9
|
+
* nothing, every one of them would start failing on the day this abstraction
|
|
10
|
+
* landed, for a reason that has nothing to do with what changed.
|
|
11
|
+
*
|
|
12
|
+
* So an unregistered tool gets this: the CamelCase name table and the
|
|
13
|
+
* snake_case subtype extraction that the receiver applied to every tool before
|
|
14
|
+
* the abstraction existed, which is exactly the behaviour being preserved. It
|
|
15
|
+
* is *not* a claim that the table is right for that tool — gemini spells four
|
|
16
|
+
* of the seven differently and antigravity spells none of them — only that a
|
|
17
|
+
* hook posting `{"event":"stop"}` keeps working while its tool waits for Phase
|
|
18
|
+
* 4-2…4-5.
|
|
19
|
+
*
|
|
20
|
+
* Its capabilities say so: `supportedEvents` is empty, which is the honest
|
|
21
|
+
* answer to "what does this tool emit?" when nobody has measured it. A caller
|
|
22
|
+
* that consults capabilities gets "unknown", not a confident wrong answer.
|
|
23
|
+
*
|
|
24
|
+
* Registering a real source for a tool replaces this automatically; there is no
|
|
25
|
+
* list to remove it from.
|
|
26
|
+
*
|
|
27
|
+
* @module lib/hooks/sources/legacy-relay
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.createLegacyRelaySource = createLegacyRelaySource;
|
|
31
|
+
const ask_user_question_payload_1 = require("../../../lib/hooks/ask-user-question-payload");
|
|
32
|
+
const permission_request_payload_1 = require("../../../lib/hooks/permission-request-payload");
|
|
33
|
+
const source_1 = require("./claude/source");
|
|
34
|
+
const define_source_1 = require("./define-source");
|
|
35
|
+
const event_mapper_1 = require("./event-mapper");
|
|
36
|
+
const hook_event_vocabulary_1 = require("./hook-event-vocabulary");
|
|
37
|
+
/**
|
|
38
|
+
* Build the compatibility source for one tool.
|
|
39
|
+
*
|
|
40
|
+
* @param cliToolId - The tool nobody has written a source for yet
|
|
41
|
+
*/
|
|
42
|
+
function createLegacyRelaySource(cliToolId) {
|
|
43
|
+
return (0, define_source_1.definePushHookSource)({
|
|
44
|
+
cliToolId,
|
|
45
|
+
// The conservative reading, and the one that is true of the relay path this
|
|
46
|
+
// stands in for: a hook whose server does not answer is fail-open on every
|
|
47
|
+
// tool measured so far (#1757 §1.2). It is stated rather than inherited so
|
|
48
|
+
// that a tool where it is false — antigravity — cannot quietly ride on it;
|
|
49
|
+
// that tool gets a real source in Phase 4-4, with its own value.
|
|
50
|
+
noDecision: { kind: 'proceeds' },
|
|
51
|
+
capabilities: {
|
|
52
|
+
// Deliberately empty. Nothing has been measured for this tool through
|
|
53
|
+
// this path, and an empty list reads as "unknown" where a copy of
|
|
54
|
+
// Claude's list would read as a promise.
|
|
55
|
+
supportedEvents: [],
|
|
56
|
+
configScope: 'none',
|
|
57
|
+
decisionTimeoutSeconds: null,
|
|
58
|
+
},
|
|
59
|
+
mappers: (0, event_mapper_1.fromNameTable)(hook_event_vocabulary_1.CAMEL_CASE_HOOK_EVENT_NAMES),
|
|
60
|
+
nativeEventNameFields: ['hook_event_name'],
|
|
61
|
+
conversationIdFields: hook_event_vocabulary_1.SESSION_ID_FIELDS,
|
|
62
|
+
toolCallIdFields: hook_event_vocabulary_1.TOOL_CALL_ID_FIELDS,
|
|
63
|
+
extractDetail: hook_event_vocabulary_1.extractSnakeCaseEventDetail,
|
|
64
|
+
// Both receivers applied these parsers to every tool before #1759, so both
|
|
65
|
+
// stay wired here. They are strict — a payload that is not in Claude's
|
|
66
|
+
// shape answers null, which becomes "no structured data" / "no decision" —
|
|
67
|
+
// so applying them to a tool whose shape is unknown costs nothing and
|
|
68
|
+
// changes no behaviour that existed on the day this file landed.
|
|
69
|
+
parsePermissionRequest: (payload) => (0, permission_request_payload_1.parsePermissionRequestPayload)(payload),
|
|
70
|
+
parseQuestion: (payload) => (0, ask_user_question_payload_1.parseAskUserQuestionPayload)(payload),
|
|
71
|
+
// Likewise the verdict body: the permission receiver emitted Claude's shape
|
|
72
|
+
// for whatever tool reached it. **A real source must override this.**
|
|
73
|
+
// antigravity in particular reads an empty object as a denial and stops the
|
|
74
|
+
// tool call (#1757 P10), so Phase 4-4 has to encode abstention positively
|
|
75
|
+
// rather than inherit anything from here.
|
|
76
|
+
encodeVerdict: source_1.encodeClaudeVerdict,
|
|
77
|
+
// CommandMate does not inject config for these tools; their `startSession`
|
|
78
|
+
// in `src/lib/cli-tools/<tool>.ts` launches them bare.
|
|
79
|
+
prepareLaunch: (_target, executablePath) => ({
|
|
80
|
+
command: executablePath,
|
|
81
|
+
settingsPath: null,
|
|
82
|
+
}),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Talking to one opencode server (Issue #1763).
|
|
4
|
+
*
|
|
5
|
+
* The server is not a separate process. #1758 §5.1.2 measured that the plain
|
|
6
|
+
* `opencode` TUI *is* an HTTP server when it is given `--port`: `/global/health`,
|
|
7
|
+
* `/event`, `GET /permission` and the reply endpoints all answered identically
|
|
8
|
+
* to `opencode serve`. So there is no daemon to supervise here — the server's
|
|
9
|
+
* lifetime is the pane's lifetime, and everything in this file is a request to
|
|
10
|
+
* a port that either answers or does not.
|
|
11
|
+
*
|
|
12
|
+
* Four measurements shape the choices below.
|
|
13
|
+
*
|
|
14
|
+
* - **The subscription is legacy `GET /event`.** `GET /api/event` (v2) goes
|
|
15
|
+
* silent after the first three frames of a turn, reproducibly, and
|
|
16
|
+
* `GET /api/session/:id/event?after=<seq>` returns zero bytes — so neither
|
|
17
|
+
* the newer envelope nor durable replay is usable on 1.18.3 (#1758 §5.2.2).
|
|
18
|
+
* - **The frames name their event in the JSON, not in the SSE `event:` field.**
|
|
19
|
+
* Every frame is a bare `data:` line, so a named `EventSource` listener picks
|
|
20
|
+
* up nothing. The parser below reads `data:` and nothing else.
|
|
21
|
+
* - **Replies go to `POST /permission/:requestID/reply`.** There are two
|
|
22
|
+
* endpoints and they differ (#1758 §5.5.2): the per-session one takes
|
|
23
|
+
* `{"response":…}` and cannot carry a reason, while this one takes
|
|
24
|
+
* `{"reply":…, "message"?:…}` and the message reaches the agent verbatim —
|
|
25
|
+
* it turned up in the tool part's `state.error`. One had to be picked and
|
|
26
|
+
* fixed; this is the superset, and a denial CommandMate cannot explain is a
|
|
27
|
+
* denial the agent cannot act on.
|
|
28
|
+
* - **Absence is free to detect.** A closed port fails in under a millisecond
|
|
29
|
+
* (§5.7.2), so health checks cost nothing and every call here is allowed to
|
|
30
|
+
* be attempted rather than guarded by cached state.
|
|
31
|
+
*
|
|
32
|
+
* Nothing in this module throws. A source that cannot reach its agent has to
|
|
33
|
+
* degrade to the screen scraper, and an exception on the way to that decision
|
|
34
|
+
* would take the caller down with it.
|
|
35
|
+
*
|
|
36
|
+
* @module lib/hooks/sources/opencode/client
|
|
37
|
+
*/
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.OPENCODE_REQUEST_TIMEOUT_MS = exports.OPENCODE_SERVER_HOST = void 0;
|
|
40
|
+
exports.opencodeBaseUrl = opencodeBaseUrl;
|
|
41
|
+
exports.fetchOpencodeHealth = fetchOpencodeHealth;
|
|
42
|
+
exports.fetchOpencodePendingPermissions = fetchOpencodePendingPermissions;
|
|
43
|
+
exports.fetchOpencodePendingQuestions = fetchOpencodePendingQuestions;
|
|
44
|
+
exports.fetchOpencodeActivity = fetchOpencodeActivity;
|
|
45
|
+
exports.replyOpencodePermission = replyOpencodePermission;
|
|
46
|
+
exports.replyOpencodeQuestion = replyOpencodeQuestion;
|
|
47
|
+
exports.createSseParser = createSseParser;
|
|
48
|
+
exports.readOpencodeEventStream = readOpencodeEventStream;
|
|
49
|
+
const logger_1 = require("../../../../lib/logger");
|
|
50
|
+
const logger = (0, logger_1.createLogger)('lib/hooks/sources/opencode/client');
|
|
51
|
+
/**
|
|
52
|
+
* The only host an opencode server is ever addressed on.
|
|
53
|
+
*
|
|
54
|
+
* `--hostname` defaults to this and the spike confirmed the LAN address refuses
|
|
55
|
+
* connections (#1758 §5.8.3). The server is unauthenticated by default, so
|
|
56
|
+
* binding it anywhere else would publish an arbitrary-command execution API to
|
|
57
|
+
* the network; `--mdns`, which flips the default to `0.0.0.0`, is never passed.
|
|
58
|
+
*/
|
|
59
|
+
exports.OPENCODE_SERVER_HOST = '127.0.0.1';
|
|
60
|
+
/** Timeout for the small request/response calls. Generous: they answer in ms. */
|
|
61
|
+
exports.OPENCODE_REQUEST_TIMEOUT_MS = 5_000;
|
|
62
|
+
/** `http://127.0.0.1:<port>`. */
|
|
63
|
+
function opencodeBaseUrl(port) {
|
|
64
|
+
return `http://${exports.OPENCODE_SERVER_HOST}:${port}`;
|
|
65
|
+
}
|
|
66
|
+
function isPlainObject(value) {
|
|
67
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* One JSON request, with a timeout, that answers null instead of throwing.
|
|
71
|
+
*
|
|
72
|
+
* @param url - Absolute URL on the loopback server
|
|
73
|
+
* @param init - Method / body; a timeout signal is added
|
|
74
|
+
* @returns The parsed body, or null on any failure at all
|
|
75
|
+
*/
|
|
76
|
+
async function requestJson(url, init) {
|
|
77
|
+
try {
|
|
78
|
+
const response = await fetch(url, {
|
|
79
|
+
...init,
|
|
80
|
+
signal: AbortSignal.timeout(exports.OPENCODE_REQUEST_TIMEOUT_MS),
|
|
81
|
+
});
|
|
82
|
+
if (!response.ok)
|
|
83
|
+
return null;
|
|
84
|
+
return (await response.json());
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
// Includes the ordinary case: nothing is listening because the pane exited.
|
|
88
|
+
logger.debug('opencode-request-failed', {
|
|
89
|
+
url,
|
|
90
|
+
error: error instanceof Error ? error.message : String(error),
|
|
91
|
+
});
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Ask whether an opencode server is listening on this port.
|
|
97
|
+
*
|
|
98
|
+
* @returns Its health and version, or null when nothing answered
|
|
99
|
+
*/
|
|
100
|
+
async function fetchOpencodeHealth(port) {
|
|
101
|
+
const body = await requestJson(`${opencodeBaseUrl(port)}/global/health`);
|
|
102
|
+
if (!isPlainObject(body))
|
|
103
|
+
return null;
|
|
104
|
+
if (body.healthy !== true)
|
|
105
|
+
return null;
|
|
106
|
+
return { healthy: true, version: typeof body.version === 'string' ? body.version : null };
|
|
107
|
+
}
|
|
108
|
+
/** An array body, or an empty array — `GET /permission` answers a bare array. */
|
|
109
|
+
function asObjectArray(body) {
|
|
110
|
+
if (!Array.isArray(body))
|
|
111
|
+
return [];
|
|
112
|
+
return body.filter(isPlainObject);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The approvals currently waiting on a human (#1758 §5.4).
|
|
116
|
+
*
|
|
117
|
+
* This is what makes a missed `permission.asked` recoverable: the event is
|
|
118
|
+
* gone, but the pending state is still readable, which is the whole of the
|
|
119
|
+
* reconnect strategy since `?after=<seq>` returns nothing.
|
|
120
|
+
*/
|
|
121
|
+
async function fetchOpencodePendingPermissions(port) {
|
|
122
|
+
return asObjectArray(await requestJson(`${opencodeBaseUrl(port)}/permission`));
|
|
123
|
+
}
|
|
124
|
+
/** The questions currently waiting on a human. */
|
|
125
|
+
async function fetchOpencodePendingQuestions(port) {
|
|
126
|
+
return asObjectArray(await requestJson(`${opencodeBaseUrl(port)}/question`));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Whether any session on this server is working (#1758 §5.7.4).
|
|
130
|
+
*
|
|
131
|
+
* `GET /session/status` answers `{"ses_…":{"type":"busy"|"idle"}}`. Note what
|
|
132
|
+
* this does *not* answer: a session blocked on an approval reads `busy`, so
|
|
133
|
+
* this says "the turn is not over", never "the agent is thinking".
|
|
134
|
+
*
|
|
135
|
+
* @returns `busy` when any session is busy, `idle` when none is, null when the
|
|
136
|
+
* server could not be asked
|
|
137
|
+
*/
|
|
138
|
+
async function fetchOpencodeActivity(port) {
|
|
139
|
+
const body = await requestJson(`${opencodeBaseUrl(port)}/session/status`);
|
|
140
|
+
if (!isPlainObject(body))
|
|
141
|
+
return null;
|
|
142
|
+
for (const value of Object.values(body)) {
|
|
143
|
+
if (isPlainObject(value) && value.type === 'busy')
|
|
144
|
+
return 'busy';
|
|
145
|
+
}
|
|
146
|
+
return 'idle';
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Answer one approval.
|
|
150
|
+
*
|
|
151
|
+
* @param port - The instance's server
|
|
152
|
+
* @param requestId - `per_…`, from `permission.asked` / `GET /permission`
|
|
153
|
+
* @param reply - `once` runs it and asks again next time; `always` saves the
|
|
154
|
+
* pattern; `reject` fails the tool call
|
|
155
|
+
* @param message - Shown to the agent verbatim on a rejection. Only this
|
|
156
|
+
* endpoint can carry it
|
|
157
|
+
* @returns Whether the server accepted it
|
|
158
|
+
*/
|
|
159
|
+
async function replyOpencodePermission(port, requestId, reply, message) {
|
|
160
|
+
const body = { reply };
|
|
161
|
+
if (message)
|
|
162
|
+
body.message = message;
|
|
163
|
+
const result = await requestJson(`${opencodeBaseUrl(port)}/permission/${encodeURIComponent(requestId)}/reply`, {
|
|
164
|
+
method: 'POST',
|
|
165
|
+
headers: { 'Content-Type': 'application/json' },
|
|
166
|
+
body: JSON.stringify(body),
|
|
167
|
+
});
|
|
168
|
+
return result !== null;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Answer one question.
|
|
172
|
+
*
|
|
173
|
+
* @param answers - One array of selected labels per question, in the order the
|
|
174
|
+
* `question.asked` frame listed them
|
|
175
|
+
*/
|
|
176
|
+
async function replyOpencodeQuestion(port, questionId, answers) {
|
|
177
|
+
const result = await requestJson(`${opencodeBaseUrl(port)}/question/${encodeURIComponent(questionId)}/reply`, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers: { 'Content-Type': 'application/json' },
|
|
180
|
+
body: JSON.stringify({ answers }),
|
|
181
|
+
});
|
|
182
|
+
return result !== null;
|
|
183
|
+
}
|
|
184
|
+
// =============================================================================
|
|
185
|
+
// SSE
|
|
186
|
+
// =============================================================================
|
|
187
|
+
/**
|
|
188
|
+
* Incremental parser for the one SSE shape opencode emits.
|
|
189
|
+
*
|
|
190
|
+
* `GET /event` sends frames with no `event:` line — a `data:` line, then a
|
|
191
|
+
* blank line. Multi-line `data:` is joined with `\n` per the SSE spec, though
|
|
192
|
+
* 1.18.3 has never been observed to send one; supporting it costs a line and
|
|
193
|
+
* removes a class of silent truncation.
|
|
194
|
+
*
|
|
195
|
+
* @returns A parser whose `push` returns whatever frames the chunk completed
|
|
196
|
+
*/
|
|
197
|
+
function createSseParser() {
|
|
198
|
+
let buffer = '';
|
|
199
|
+
let dataLines = [];
|
|
200
|
+
const completed = [];
|
|
201
|
+
const finishEvent = () => {
|
|
202
|
+
if (dataLines.length === 0)
|
|
203
|
+
return;
|
|
204
|
+
completed.push(dataLines.join('\n'));
|
|
205
|
+
dataLines = [];
|
|
206
|
+
};
|
|
207
|
+
const consumeLine = (rawLine) => {
|
|
208
|
+
const line = rawLine.endsWith('\r') ? rawLine.slice(0, -1) : rawLine;
|
|
209
|
+
if (line === '') {
|
|
210
|
+
finishEvent();
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (line.startsWith(':'))
|
|
214
|
+
return; // comment / keepalive
|
|
215
|
+
if (line.startsWith('data:')) {
|
|
216
|
+
dataLines.push(line.slice(5).replace(/^ /, ''));
|
|
217
|
+
}
|
|
218
|
+
// `id:` / `event:` / `retry:` are not used by this server; ignored.
|
|
219
|
+
};
|
|
220
|
+
return {
|
|
221
|
+
push(chunk) {
|
|
222
|
+
buffer += chunk;
|
|
223
|
+
let newlineIndex = buffer.indexOf('\n');
|
|
224
|
+
while (newlineIndex >= 0) {
|
|
225
|
+
consumeLine(buffer.slice(0, newlineIndex));
|
|
226
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
227
|
+
newlineIndex = buffer.indexOf('\n');
|
|
228
|
+
}
|
|
229
|
+
return completed.splice(0, completed.length);
|
|
230
|
+
},
|
|
231
|
+
flush() {
|
|
232
|
+
if (buffer !== '') {
|
|
233
|
+
consumeLine(buffer);
|
|
234
|
+
buffer = '';
|
|
235
|
+
}
|
|
236
|
+
finishEvent();
|
|
237
|
+
return completed.splice(0, completed.length);
|
|
238
|
+
},
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Subscribe to one server's event stream.
|
|
243
|
+
*
|
|
244
|
+
* Yields parsed frames until the connection ends or `signal` aborts. A frame
|
|
245
|
+
* that is not JSON is skipped rather than ending the stream: a malformed line
|
|
246
|
+
* is a bug in one frame, not a reason to stop watching the session.
|
|
247
|
+
*
|
|
248
|
+
* Ending is normal and is the caller's cue to reconnect — the connection dies
|
|
249
|
+
* without a clean EOF when the server goes away (`transfer closed with
|
|
250
|
+
* outstanding read data remaining`, #1758 §5.7.2).
|
|
251
|
+
*
|
|
252
|
+
* @param port - The instance's server
|
|
253
|
+
* @param signal - Aborted by the subscription to close the stream
|
|
254
|
+
*/
|
|
255
|
+
async function* readOpencodeEventStream(port, signal) {
|
|
256
|
+
const response = await fetch(`${opencodeBaseUrl(port)}/event`, {
|
|
257
|
+
signal,
|
|
258
|
+
headers: { Accept: 'text/event-stream' },
|
|
259
|
+
});
|
|
260
|
+
if (!response.ok || !response.body) {
|
|
261
|
+
throw new Error(`opencode /event responded ${response.status}`);
|
|
262
|
+
}
|
|
263
|
+
const reader = response.body.getReader();
|
|
264
|
+
const decoder = new TextDecoder();
|
|
265
|
+
const parser = createSseParser();
|
|
266
|
+
try {
|
|
267
|
+
for (;;) {
|
|
268
|
+
const { done, value } = await reader.read();
|
|
269
|
+
if (done)
|
|
270
|
+
break;
|
|
271
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
272
|
+
for (const raw of parser.push(chunk)) {
|
|
273
|
+
const frame = safeParseFrame(raw);
|
|
274
|
+
if (frame)
|
|
275
|
+
yield frame;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
for (const raw of parser.flush()) {
|
|
279
|
+
const frame = safeParseFrame(raw);
|
|
280
|
+
if (frame)
|
|
281
|
+
yield frame;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
finally {
|
|
285
|
+
// `cancel` on an already-aborted stream rejects; the connection is going
|
|
286
|
+
// away either way, so the failure is not actionable.
|
|
287
|
+
await reader.cancel().catch(() => { });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/** JSON, or null when the frame was not an object. */
|
|
291
|
+
function safeParseFrame(raw) {
|
|
292
|
+
try {
|
|
293
|
+
const parsed = JSON.parse(raw);
|
|
294
|
+
return isPlainObject(parsed) ? parsed : null;
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
return null;
|
|
298
|
+
}
|
|
299
|
+
}
|