commandmate 0.22.1 → 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 +86 -86
- package/.next/app-path-routes-manifest.json +17 -17
- 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/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 +17 -17
- 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-63dacfbab082ca8d.js → 6488-95ba9d24a76f0cc5.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/{page-c1be93f2595d0803.js → page-966a451ae7b0903a.js} +1 -1
- package/.next/trace +12 -12
- package/dist/cli/docs/agent-operations.d.ts +1 -1
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +5 -1
- package/dist/cli/utils/api-client.d.ts.map +1 -1
- package/dist/cli/utils/api-client.js +9 -2
- package/dist/cli/utils/server-url.d.ts +23 -0
- package/dist/cli/utils/server-url.d.ts.map +1 -1
- package/dist/cli/utils/server-url.js +33 -0
- 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/{d4vh4O18WEhXs4WbdShIs → wH6K6QNPHSdATFkVoIcy3}/_buildManifest.js +0 -0
- /package/.next/static/{d4vh4O18WEhXs4WbdShIs → wH6K6QNPHSdATFkVoIcy3}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Deciding which frames are a turn's real boundaries (Issue #1763).
|
|
4
|
+
*
|
|
5
|
+
* opencode repeats both of the frames CommandMate reads as one-off facts, and
|
|
6
|
+
* in both cases the repeat is byte-identical to the original. A source that
|
|
7
|
+
* mapped frames one-to-one would therefore report the same event several times,
|
|
8
|
+
* and the status layer — which reads only the *newest* event — would turn that
|
|
9
|
+
* into a wrong verdict. This module tells the first from the rest.
|
|
10
|
+
*
|
|
11
|
+
* ## `session.idle` — the end of a turn
|
|
12
|
+
*
|
|
13
|
+
* It is opencode's `Stop`: #1758 §5.3.1 held a session on an approval dialog
|
|
14
|
+
* for 10 minutes 19 seconds and not one `session.idle` arrived for it, so the
|
|
15
|
+
* event really does mean "the turn finished" rather than "the agent is not
|
|
16
|
+
* busy". `commandmate wait` may key off it. What it may not do is count them:
|
|
17
|
+
*
|
|
18
|
+
* - **Abnormal endings fire twice.** An abort emitted `session.idle` at
|
|
19
|
+
* 08:15:00.416 and again at 08:15:00.435 — 19 ms apart, same session, same
|
|
20
|
+
* turn (§5.3.2). Provider errors do the same. Normal endings fire once.
|
|
21
|
+
* - **The payload has no turn identifier.** It is `{ "sessionID": "ses_…" }`
|
|
22
|
+
* and nothing else, so two idles cannot be told apart by looking at them
|
|
23
|
+
* (§5.3.3). Claude's `Stop` carried `prompt_id`; this does not.
|
|
24
|
+
* - **An idle can arrive for a turn this connection never watched start** — a
|
|
25
|
+
* stream opened mid-session, a resubscribe after a restart — and treating
|
|
26
|
+
* that as a completion resolves a `wait` for work that is not over.
|
|
27
|
+
*
|
|
28
|
+
* So: **arm on `session.status(busy)`, complete on the first `session.idle`
|
|
29
|
+
* after arming, drop the rest.** `session.status(idle)` is deliberately inert —
|
|
30
|
+
* it is emitted in the same millisecond as `session.idle` and is the same
|
|
31
|
+
* signal, so honouring both would double every turn (§5.3.2 rule 4).
|
|
32
|
+
*
|
|
33
|
+
* ## `message.updated` — the start of a turn
|
|
34
|
+
*
|
|
35
|
+
* `user_prompt_submit` has no event of its own; it is `message.updated` with
|
|
36
|
+
* `info.role === "user"`. That frame is **re-emitted for the same message
|
|
37
|
+
* several times per turn, including after `session.idle`** — measured live on
|
|
38
|
+
* 1.18.3 while implementing this Issue:
|
|
39
|
+
*
|
|
40
|
+
* ```
|
|
41
|
+
* 13:53:14.251 session.idle
|
|
42
|
+
* 13:53:14.297 message.updated role=user id=msg_ffb668eec001WToZ7VW0lQgmoa
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* Both copies carry `time: { created: … }` and nothing else, so nothing in the
|
|
46
|
+
* payload distinguishes them. Mapped one-to-one, the newest event after a
|
|
47
|
+
* finished turn is `user_prompt_submit`, which `status-mapping` reads as
|
|
48
|
+
* **`running`** — so `commandmate wait` would hang on every completed opencode
|
|
49
|
+
* turn until the 30-minute staleness bound expired. The fix has the same shape:
|
|
50
|
+
* **announce the first `message.updated` for a message id, suppress the
|
|
51
|
+
* repeats.**
|
|
52
|
+
*
|
|
53
|
+
* Unlike the arming state, announced ids **survive a reconnect**. A genuinely
|
|
54
|
+
* new prompt always carries a new id, so keeping them costs nothing and closes
|
|
55
|
+
* the window where a reconnect lands between a turn's end and its trailing
|
|
56
|
+
* repeat.
|
|
57
|
+
*
|
|
58
|
+
* The gate is a pure state machine over frame types so it can be driven from
|
|
59
|
+
* fixtures. The subscription owns one per connection.
|
|
60
|
+
*
|
|
61
|
+
* @module lib/hooks/sources/opencode/turn-gate
|
|
62
|
+
*/
|
|
63
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
64
|
+
exports.MAX_TRACKED_USER_MESSAGES = exports.MAX_TRACKED_TURN_SESSIONS = void 0;
|
|
65
|
+
exports.createTurnGate = createTurnGate;
|
|
66
|
+
const event_mapper_1 = require("../event-mapper");
|
|
67
|
+
/**
|
|
68
|
+
* Cap on remembered sessions.
|
|
69
|
+
*
|
|
70
|
+
* One opencode server can host several sessions (#1758 §5.6.1) and a long-lived
|
|
71
|
+
* TUI accumulates them, so the map is bounded. The oldest is dropped, which at
|
|
72
|
+
* worst re-arms an ancient session — the failure mode of forgetting is a
|
|
73
|
+
* suppressed idle, never a spurious completion.
|
|
74
|
+
*/
|
|
75
|
+
exports.MAX_TRACKED_TURN_SESSIONS = 64;
|
|
76
|
+
/**
|
|
77
|
+
* Cap on remembered user-message ids.
|
|
78
|
+
*
|
|
79
|
+
* Larger than the session cap because it counts prompts rather than sessions,
|
|
80
|
+
* and because these survive reconnects. Forgetting the oldest costs one
|
|
81
|
+
* re-announced `user_prompt_submit` for a prompt from thousands of turns ago.
|
|
82
|
+
*/
|
|
83
|
+
exports.MAX_TRACKED_USER_MESSAGES = 512;
|
|
84
|
+
/** `properties.sessionID`, or null. */
|
|
85
|
+
function sessionIdOf(payload) {
|
|
86
|
+
const properties = (0, event_mapper_1.isPlainObject)(payload.properties) ? payload.properties : {};
|
|
87
|
+
return (0, event_mapper_1.readNestedString)(properties, ['sessionID']);
|
|
88
|
+
}
|
|
89
|
+
/** `properties.status.type` for `session.status`. */
|
|
90
|
+
function statusType(payload) {
|
|
91
|
+
const properties = (0, event_mapper_1.isPlainObject)(payload.properties) ? payload.properties : {};
|
|
92
|
+
return (0, event_mapper_1.readNestedString)(properties, ['status', 'type']);
|
|
93
|
+
}
|
|
94
|
+
/** `properties.error.name` for `session.error` — `MessageAbortedError`, `APIError`, … */
|
|
95
|
+
function errorName(payload) {
|
|
96
|
+
const properties = (0, event_mapper_1.isPlainObject)(payload.properties) ? payload.properties : {};
|
|
97
|
+
return (0, event_mapper_1.readNestedString)(properties, ['error', 'name']);
|
|
98
|
+
}
|
|
99
|
+
/** `properties.info.role` / `properties.info.id` for `message.updated`. */
|
|
100
|
+
function messageInfo(payload) {
|
|
101
|
+
const properties = (0, event_mapper_1.isPlainObject)(payload.properties) ? payload.properties : {};
|
|
102
|
+
return {
|
|
103
|
+
role: (0, event_mapper_1.readNestedString)(properties, ['info', 'role']),
|
|
104
|
+
id: (0, event_mapper_1.readNestedString)(properties, ['info', 'id']),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Drop the oldest entries until the collection fits. */
|
|
108
|
+
function trim(keys, max) {
|
|
109
|
+
// Both Map and Set iterate in insertion order, so the head is the oldest.
|
|
110
|
+
while (keys.size > max) {
|
|
111
|
+
const oldest = keys.keys().next();
|
|
112
|
+
if (oldest.done)
|
|
113
|
+
break;
|
|
114
|
+
keys.delete(oldest.value);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Build a gate.
|
|
119
|
+
*
|
|
120
|
+
* @param maxSessions - Cap on remembered sessions; defaults to
|
|
121
|
+
* {@link MAX_TRACKED_TURN_SESSIONS}
|
|
122
|
+
* @param maxUserMessages - Cap on remembered user-message ids; defaults to
|
|
123
|
+
* {@link MAX_TRACKED_USER_MESSAGES}
|
|
124
|
+
*/
|
|
125
|
+
function createTurnGate(maxSessions = exports.MAX_TRACKED_TURN_SESSIONS, maxUserMessages = exports.MAX_TRACKED_USER_MESSAGES) {
|
|
126
|
+
const phases = new Map();
|
|
127
|
+
const announced = new Set();
|
|
128
|
+
const remember = (sessionId, phase) => {
|
|
129
|
+
phases.delete(sessionId);
|
|
130
|
+
phases.set(sessionId, phase);
|
|
131
|
+
trim(phases, maxSessions);
|
|
132
|
+
};
|
|
133
|
+
return {
|
|
134
|
+
observe(type, payload) {
|
|
135
|
+
if (type === 'message.updated') {
|
|
136
|
+
const { role, id } = messageInfo(payload);
|
|
137
|
+
// Only the user's own message is `user_prompt_submit`; the assistant's
|
|
138
|
+
// updates carry the reply and map to nothing.
|
|
139
|
+
if (role !== 'user' || id === null)
|
|
140
|
+
return { kind: 'ignored' };
|
|
141
|
+
const sessionId = sessionIdOf(payload) ?? '';
|
|
142
|
+
if (announced.has(id)) {
|
|
143
|
+
return { kind: 'suppressed', sessionId, reason: 'already-announced' };
|
|
144
|
+
}
|
|
145
|
+
announced.add(id);
|
|
146
|
+
trim(announced, maxUserMessages);
|
|
147
|
+
return { kind: 'announced', sessionId, messageId: id };
|
|
148
|
+
}
|
|
149
|
+
if (type === 'session.status') {
|
|
150
|
+
// Only `busy` arms. `idle` here is the same signal as `session.idle`,
|
|
151
|
+
// emitted in the same millisecond, and honouring both would count every
|
|
152
|
+
// turn twice (#1758 §5.3.2 rule 4).
|
|
153
|
+
if (statusType(payload) !== 'busy')
|
|
154
|
+
return { kind: 'ignored' };
|
|
155
|
+
const sessionId = sessionIdOf(payload);
|
|
156
|
+
if (sessionId === null)
|
|
157
|
+
return { kind: 'ignored' };
|
|
158
|
+
remember(sessionId, 'busy');
|
|
159
|
+
return { kind: 'armed', sessionId };
|
|
160
|
+
}
|
|
161
|
+
if (type === 'session.error') {
|
|
162
|
+
const sessionId = sessionIdOf(payload);
|
|
163
|
+
if (sessionId === null)
|
|
164
|
+
return { kind: 'ignored' };
|
|
165
|
+
// Not a completion: the idle that follows is. Reported so the caller can
|
|
166
|
+
// tell "finished" from "gave up" — `session.idle` alone cannot (§5.3.3
|
|
167
|
+
// requirement 3).
|
|
168
|
+
return { kind: 'failed', sessionId, errorName: errorName(payload) };
|
|
169
|
+
}
|
|
170
|
+
if (type !== 'session.idle')
|
|
171
|
+
return { kind: 'ignored' };
|
|
172
|
+
const sessionId = sessionIdOf(payload);
|
|
173
|
+
if (sessionId === null)
|
|
174
|
+
return { kind: 'ignored' };
|
|
175
|
+
const phase = phases.get(sessionId);
|
|
176
|
+
if (phase === undefined) {
|
|
177
|
+
return { kind: 'suppressed', sessionId, reason: 'never-armed' };
|
|
178
|
+
}
|
|
179
|
+
if (phase === 'idle') {
|
|
180
|
+
return { kind: 'suppressed', sessionId, reason: 'already-completed' };
|
|
181
|
+
}
|
|
182
|
+
remember(sessionId, 'idle');
|
|
183
|
+
return { kind: 'completed', sessionId };
|
|
184
|
+
},
|
|
185
|
+
isArmed(sessionId) {
|
|
186
|
+
return phases.get(sessionId) === 'busy';
|
|
187
|
+
},
|
|
188
|
+
reset() {
|
|
189
|
+
phases.clear();
|
|
190
|
+
// `announced` is deliberately kept — see the module comment.
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The in-flight decisions a push source is holding, and the one call a receiver
|
|
4
|
+
* makes to answer one (Issue #1759, constraint C2).
|
|
5
|
+
*
|
|
6
|
+
* A hook is answered in the body of the request it arrived on. opencode is
|
|
7
|
+
* answered by `POST`ing to a different URL, minutes later if need be, on a
|
|
8
|
+
* connection the event never travelled over (#1758 §5.5). Those are not two
|
|
9
|
+
* spellings of one operation, and a receiver that branched on which it was
|
|
10
|
+
* dealing with would be a receiver that knows the tool — the thing this whole
|
|
11
|
+
* abstraction exists to remove.
|
|
12
|
+
*
|
|
13
|
+
* {@link answerPendingDecision} is the seam. It opens a slot, hands the
|
|
14
|
+
* decision to {@link AgentEventSource.decide}, and returns whatever body the
|
|
15
|
+
* source left behind — `{}` when the source answered out of band, because there
|
|
16
|
+
* is then nothing for the response to carry. A push source fills the slot
|
|
17
|
+
* synchronously; a pull source ignores it and calls REST. The caller writes the
|
|
18
|
+
* returned object either way.
|
|
19
|
+
*
|
|
20
|
+
* The open slots are also what {@link AgentEventSource.listPending} answers with
|
|
21
|
+
* for push sources (C7): a hook that has not been replied to yet is the only
|
|
22
|
+
* pending state a push transport has, and a hook that was dropped is simply
|
|
23
|
+
* gone — there is no `GET /permission` to re-read it from.
|
|
24
|
+
*
|
|
25
|
+
* @module lib/hooks/sources/pending-decisions
|
|
26
|
+
*/
|
|
27
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
28
|
+
exports.MAX_OPEN_DECISIONS_PER_INSTANCE = void 0;
|
|
29
|
+
exports.openDecisionSlot = openDecisionSlot;
|
|
30
|
+
exports.closeDecisionSlot = closeDecisionSlot;
|
|
31
|
+
exports.listOpenDecisions = listOpenDecisions;
|
|
32
|
+
exports.fillDecisionSlot = fillDecisionSlot;
|
|
33
|
+
exports.resetPendingDecisions = resetPendingDecisions;
|
|
34
|
+
exports.answerPendingDecision = answerPendingDecision;
|
|
35
|
+
const auto_yes_state_1 = require("../../../lib/auto-yes-state");
|
|
36
|
+
const logger_1 = require("../../../lib/logger");
|
|
37
|
+
const logger = (0, logger_1.createLogger)('lib/hooks/sources/pending-decisions');
|
|
38
|
+
const pendingByInstance = (globalThis.__agentSourcePendingDecisions ??= new Map());
|
|
39
|
+
/**
|
|
40
|
+
* Cap on simultaneously open slots for one instance.
|
|
41
|
+
*
|
|
42
|
+
* An agent asks one thing at a time, so anything above a handful means slots
|
|
43
|
+
* are leaking rather than that a human is very busy. The oldest is dropped
|
|
44
|
+
* rather than the newest refused: the newest is the one somebody is waiting on.
|
|
45
|
+
*/
|
|
46
|
+
exports.MAX_OPEN_DECISIONS_PER_INSTANCE = 16;
|
|
47
|
+
function keyOf(ref) {
|
|
48
|
+
return (0, auto_yes_state_1.buildCompositeKey)(ref.worktreeId, ref.cliToolId, ref.instanceId);
|
|
49
|
+
}
|
|
50
|
+
/** Register a decision as in flight. Always paired with {@link closeDecisionSlot}. */
|
|
51
|
+
function openDecisionSlot(ref, decision) {
|
|
52
|
+
const key = keyOf(ref);
|
|
53
|
+
const slot = { key, ref, decision, body: null };
|
|
54
|
+
const open = pendingByInstance.get(key) ?? [];
|
|
55
|
+
open.push(slot);
|
|
56
|
+
while (open.length > exports.MAX_OPEN_DECISIONS_PER_INSTANCE)
|
|
57
|
+
open.shift();
|
|
58
|
+
pendingByInstance.set(key, open);
|
|
59
|
+
return slot;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Remove a slot and take whatever the source wrote into it.
|
|
63
|
+
*
|
|
64
|
+
* @returns The response body, or `{}` when the source answered out of band —
|
|
65
|
+
* which is also, and not by accident, the byte-for-byte no-decision body
|
|
66
|
+
* every hook-based tool reads as "carry on" (#1721 D5).
|
|
67
|
+
*/
|
|
68
|
+
function closeDecisionSlot(slot) {
|
|
69
|
+
const open = pendingByInstance.get(slot.key);
|
|
70
|
+
if (open) {
|
|
71
|
+
const index = open.indexOf(slot);
|
|
72
|
+
if (index >= 0)
|
|
73
|
+
open.splice(index, 1);
|
|
74
|
+
if (open.length === 0)
|
|
75
|
+
pendingByInstance.delete(slot.key);
|
|
76
|
+
}
|
|
77
|
+
return slot.body ?? {};
|
|
78
|
+
}
|
|
79
|
+
/** The decisions currently in flight for one instance. */
|
|
80
|
+
function listOpenDecisions(ref) {
|
|
81
|
+
return (pendingByInstance.get(keyOf(ref)) ?? []).map((slot) => slot.decision);
|
|
82
|
+
}
|
|
83
|
+
/** Fill the slot a push source is answering, if it is still open. */
|
|
84
|
+
function fillDecisionSlot(ref, decisionId, body) {
|
|
85
|
+
const open = pendingByInstance.get(keyOf(ref));
|
|
86
|
+
if (!open)
|
|
87
|
+
return false;
|
|
88
|
+
const slot = open.find((candidate) => candidate.decision.id === decisionId);
|
|
89
|
+
if (!slot)
|
|
90
|
+
return false;
|
|
91
|
+
slot.body = body;
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
/** Drop every open slot. For tests; production only ever closes what it opened. */
|
|
95
|
+
function resetPendingDecisions() {
|
|
96
|
+
pendingByInstance.clear();
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Answer one decision, whichever way this source answers things.
|
|
100
|
+
*
|
|
101
|
+
* The single call a receiver route makes. It does not know — and after this
|
|
102
|
+
* function exists, cannot find out without going out of its way — whether the
|
|
103
|
+
* verdict left through the response body or through a second HTTP call.
|
|
104
|
+
*
|
|
105
|
+
* @returns The body to write. `{}` means "nothing to say here", which for a
|
|
106
|
+
* hook is the measured no-decision reply and for a pull source is simply the
|
|
107
|
+
* ack of a request whose answer went elsewhere.
|
|
108
|
+
*/
|
|
109
|
+
async function answerPendingDecision(source, ref, decision, verdict) {
|
|
110
|
+
const slot = openDecisionSlot(ref, decision);
|
|
111
|
+
try {
|
|
112
|
+
await source.decide(ref, decision, verdict);
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
// Closed even when `decide` throws: a source that failed to deliver must
|
|
116
|
+
// still not leave the receiver holding a slot, and the empty body that then
|
|
117
|
+
// comes back is the fail-open answer for every push tool.
|
|
118
|
+
logger.warn('agent-source-decide-failed', {
|
|
119
|
+
worktreeId: ref.worktreeId,
|
|
120
|
+
cliToolId: ref.cliToolId,
|
|
121
|
+
instanceId: ref.instanceId ?? ref.cliToolId,
|
|
122
|
+
decisionId: decision.id,
|
|
123
|
+
error: error instanceof Error ? error.message : String(error),
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return closeDecisionSlot(slot);
|
|
127
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Which {@link AgentEventSource} speaks for which CLI tool (Issue #1759).
|
|
4
|
+
*
|
|
5
|
+
* The lookup that replaces "assume Claude". A receiver holds a
|
|
6
|
+
* {@link CLIToolType} — it came off the hook URL or the request body — and asks
|
|
7
|
+
* here; it never imports a tool's module and never compares against a tool id.
|
|
8
|
+
*
|
|
9
|
+
* ## Held on `globalThis`
|
|
10
|
+
*
|
|
11
|
+
* Not decoration. `agent-event-state` documents what happened the last time a
|
|
12
|
+
* shared map lived in module scope (#1736): under `next dev` every route
|
|
13
|
+
* handler is bundled separately, so `/api/hooks/agent-event` and
|
|
14
|
+
* `/api/hooks/permission-request` each got their own copy of the module, one
|
|
15
|
+
* wrote and the other read, and every field came back null — with no error, no
|
|
16
|
+
* warning and a perfectly well-formed response. A registry has the same shape
|
|
17
|
+
* of failure available to it: a source registered in one bundle would be absent
|
|
18
|
+
* in another, and the fallback below would silently take over. So the map is
|
|
19
|
+
* process-wide, and the registration is idempotent.
|
|
20
|
+
*
|
|
21
|
+
* ## Unregistered tools
|
|
22
|
+
*
|
|
23
|
+
* {@link getAgentEventSource} always answers. A tool with no source gets the
|
|
24
|
+
* compatibility source from `./legacy-relay`, which preserves the pre-#1759
|
|
25
|
+
* receiver behaviour for the hand-configured hooks of #1549. Ask
|
|
26
|
+
* {@link hasAgentEventSource} when the distinction matters.
|
|
27
|
+
*
|
|
28
|
+
* @module lib/hooks/sources/registry
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.registerAgentEventSource = registerAgentEventSource;
|
|
32
|
+
exports.hasAgentEventSource = hasAgentEventSource;
|
|
33
|
+
exports.getAgentEventSource = getAgentEventSource;
|
|
34
|
+
exports.listAgentEventSources = listAgentEventSources;
|
|
35
|
+
exports.unregisterAgentEventSource = unregisterAgentEventSource;
|
|
36
|
+
const legacy_relay_1 = require("./legacy-relay");
|
|
37
|
+
const source_1 = require("./claude/source");
|
|
38
|
+
const source_2 = require("./copilot/source");
|
|
39
|
+
const source_3 = require("./gemini/source");
|
|
40
|
+
const source_4 = require("./antigravity/source");
|
|
41
|
+
const source_5 = require("./codex/source");
|
|
42
|
+
const source_6 = require("./opencode/source");
|
|
43
|
+
const registered = (globalThis.__agentEventSources ??= new Map());
|
|
44
|
+
/** Memoised compatibility sources, so repeated lookups return one object. */
|
|
45
|
+
const legacy = (globalThis.__agentEventLegacySources ??= new Map());
|
|
46
|
+
/**
|
|
47
|
+
* Add or replace a tool's source.
|
|
48
|
+
*
|
|
49
|
+
* @param source - The implementation; its own `cliToolId` is the key
|
|
50
|
+
*/
|
|
51
|
+
function registerAgentEventSource(source) {
|
|
52
|
+
registered.set(source.cliToolId, source);
|
|
53
|
+
// A tool that has a real source must not keep answering from the
|
|
54
|
+
// compatibility one anywhere — including from a memo taken before it was
|
|
55
|
+
// registered, which is reachable in `next dev` where registration order
|
|
56
|
+
// across bundles is not fixed.
|
|
57
|
+
legacy.delete(source.cliToolId);
|
|
58
|
+
}
|
|
59
|
+
/** Whether this tool has a real implementation, as opposed to the fallback. */
|
|
60
|
+
function hasAgentEventSource(cliToolId) {
|
|
61
|
+
return registered.has(cliToolId);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The source for one tool. Never null.
|
|
65
|
+
*
|
|
66
|
+
* @returns The registered implementation, or the compatibility source that
|
|
67
|
+
* keeps a hand-configured #1549 hook working until this tool has one
|
|
68
|
+
*/
|
|
69
|
+
function getAgentEventSource(cliToolId) {
|
|
70
|
+
const source = registered.get(cliToolId);
|
|
71
|
+
if (source)
|
|
72
|
+
return source;
|
|
73
|
+
const existing = legacy.get(cliToolId);
|
|
74
|
+
if (existing)
|
|
75
|
+
return existing;
|
|
76
|
+
const fallback = (0, legacy_relay_1.createLegacyRelaySource)(cliToolId);
|
|
77
|
+
legacy.set(cliToolId, fallback);
|
|
78
|
+
return fallback;
|
|
79
|
+
}
|
|
80
|
+
/** Every tool with a real implementation. Ordered by registration. */
|
|
81
|
+
function listAgentEventSources() {
|
|
82
|
+
return [...registered.values()];
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Undo a registration. For tests — production only ever adds.
|
|
86
|
+
*
|
|
87
|
+
* The mutation "take Claude out of the registry" that Issue #1759 asks to be
|
|
88
|
+
* proved lethal is spelled with this.
|
|
89
|
+
*/
|
|
90
|
+
function unregisterAgentEventSource(cliToolId) {
|
|
91
|
+
registered.delete(cliToolId);
|
|
92
|
+
legacy.delete(cliToolId);
|
|
93
|
+
}
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
// Built-in registrations
|
|
96
|
+
// ---------------------------------------------------------------------------
|
|
97
|
+
//
|
|
98
|
+
// Statically imported and registered on load, rather than through a
|
|
99
|
+
// side-effecting `import './claude'` somewhere else: an import a bundler is
|
|
100
|
+
// free to consider unused is a registration that disappears in a production
|
|
101
|
+
// build, and "the source is silently absent" is the exact failure this module's
|
|
102
|
+
// globalThis comment is about.
|
|
103
|
+
//
|
|
104
|
+
// Phase 4-2…4-5 adds one line here per tool. That, plus the tool's own file, is
|
|
105
|
+
// the whole of "adding a tool" — see docs/design/agent-event-source-interface.md.
|
|
106
|
+
registerAgentEventSource(source_1.claudeAgentEventSource);
|
|
107
|
+
registerAgentEventSource(source_2.copilotAgentEventSource);
|
|
108
|
+
registerAgentEventSource(source_3.geminiAgentEventSource);
|
|
109
|
+
registerAgentEventSource(source_4.antigravityAgentEventSource);
|
|
110
|
+
registerAgentEventSource(source_5.codexAgentEventSource);
|
|
111
|
+
registerAgentEventSource(source_6.opencodeAgentEventSource);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `AgentEventSource` — the one seam every agent CLI plugs its lifecycle events
|
|
4
|
+
* into (Issue #1759, Phase 4-1 of Epic #1720).
|
|
5
|
+
*
|
|
6
|
+
* Phases 1-3 left the *consuming* half of the structured-event pipeline already
|
|
7
|
+
* tool-agnostic: `agent-event-state`, `permission-decision-service`,
|
|
8
|
+
* `current-output-builder`, `status-mapping` and `prompt-waiting-composition`
|
|
9
|
+
* all key off `(worktreeId, cliToolId, instanceId)` and branch on nothing else.
|
|
10
|
+
* What stayed Claude-shaped is the half that *produces* the events and the half
|
|
11
|
+
* that *answers* them. This module is the contract for that half, so Phase
|
|
12
|
+
* 4-2…4-5 adds a tool by adding a file rather than by copying Claude's seams.
|
|
13
|
+
*
|
|
14
|
+
* Every type below exists because a measurement demanded it. The two spikes
|
|
15
|
+
* that took those measurements are the specification:
|
|
16
|
+
*
|
|
17
|
+
* - `docs/design/agent-hooks-phase4-live-verification.md` (#1757) — codex /
|
|
18
|
+
* copilot / gemini / antigravity, five push-mode hook implementations that
|
|
19
|
+
* disagree with each other about spelling, casing, correlation keys, config
|
|
20
|
+
* location and — most importantly — what silence means.
|
|
21
|
+
* - `docs/design/opencode-server-live-verification.md` (#1758) — opencode,
|
|
22
|
+
* which is not a hook implementation at all: CommandMate subscribes to *its*
|
|
23
|
+
* HTTP server over SSE and answers with a separate REST call. §9.1 of that
|
|
24
|
+
* report lists eight constraints (C1…C8) and §9.2 sketches this interface;
|
|
25
|
+
* the shapes here follow it.
|
|
26
|
+
*
|
|
27
|
+
* Three of those constraints are worth restating at the top of the file,
|
|
28
|
+
* because getting them wrong is silent:
|
|
29
|
+
*
|
|
30
|
+
* - **C1 — the direction of travel is not fixed.** Hooks push into
|
|
31
|
+
* `POST /api/hooks/agent-event`. opencode has to be *subscribed to*. So a
|
|
32
|
+
* source has a lifecycle (`subscribe` / `Subscription.close`), even when
|
|
33
|
+
* the push implementations make it a no-op.
|
|
34
|
+
* - **C2 — the reply channel is not fixed.** A hook is answered in the body of
|
|
35
|
+
* the request it arrived on; opencode is answered by `POST`ing to a
|
|
36
|
+
* different URL entirely. {@link AgentEventSource.decide} hides which.
|
|
37
|
+
* - **C3 — silence does not mean the same thing twice.** Claude / codex /
|
|
38
|
+
* copilot walk on when nobody answers (fail-open). antigravity reads an
|
|
39
|
+
* empty object as *deny* and stops every tool call. opencode waits forever
|
|
40
|
+
* (10m19s measured, no timeout). {@link NoDecisionBehavior} is a declared
|
|
41
|
+
* field for exactly this reason: "we abstain, which is the safe default" is
|
|
42
|
+
* a sentence that is only true for some of the tools.
|
|
43
|
+
*
|
|
44
|
+
* @module lib/hooks/sources/types
|
|
45
|
+
*/
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The one call every agent's `startSession` makes when it creates a pane
|
|
4
|
+
* (Issue #1759, seam S8).
|
|
5
|
+
*
|
|
6
|
+
* `beginAgentEventGeneration` fences a recreated session off from the previous
|
|
7
|
+
* process's events: the state is keyed by (worktree, tool, instance), a key the
|
|
8
|
+
* new session reuses verbatim, so without the fence the *old* process's last
|
|
9
|
+
* `user_prompt_submit` reads as the new one's and a freshly started session
|
|
10
|
+
* publishes `running` before anybody has typed into it (#1723).
|
|
11
|
+
*
|
|
12
|
+
* Before this Issue there was exactly one call to it in the entire codebase —
|
|
13
|
+
* `claude-session.ts`, on the creation path. Every other tool starts through
|
|
14
|
+
* its own `startSession` in `src/lib/cli-tools/<tool>.ts` and has no fence at
|
|
15
|
+
* all. That was invisible while Claude was the only tool emitting events, and
|
|
16
|
+
* becomes a real defect the moment Phase 4-2 lands: codex would inherit the
|
|
17
|
+
* previous codex process's verdict on every restart.
|
|
18
|
+
*
|
|
19
|
+
* So the fence is a helper a `startSession` can call without knowing anything
|
|
20
|
+
* about the event system, and Claude's call now goes through it. Adding a tool
|
|
21
|
+
* means adding this one line to that tool's creation path — see
|
|
22
|
+
* `docs/design/agent-event-source-interface.md`.
|
|
23
|
+
*
|
|
24
|
+
* ## Where it goes in `startSession`
|
|
25
|
+
*
|
|
26
|
+
* On the **creation** path only, and **before** the pane is created:
|
|
27
|
+
*
|
|
28
|
+
* - not on the reuse path — a `startSession` that finds a healthy session and
|
|
29
|
+
* returns is the same generation, and fencing there would throw away a
|
|
30
|
+
* still-valid verdict on every reconnect;
|
|
31
|
+
* - before creation, so there is no window in which a live pane is judged
|
|
32
|
+
* against a stale generation;
|
|
33
|
+
* - unconditionally, even if the launch then fails — falling back to the
|
|
34
|
+
* screen scraper is always safe, and trusting a dead session's events is
|
|
35
|
+
* not.
|
|
36
|
+
*
|
|
37
|
+
* @module lib/session/agent-session-lifecycle
|
|
38
|
+
*/
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.beginAgentSession = beginAgentSession;
|
|
41
|
+
exports.prepareAgentLaunch = prepareAgentLaunch;
|
|
42
|
+
const sources_1 = require("../../lib/hooks/sources");
|
|
43
|
+
const agent_event_state_1 = require("../../lib/session/agent-event-state");
|
|
44
|
+
const logger_1 = require("../../lib/logger");
|
|
45
|
+
const logger = (0, logger_1.createLogger)('lib/session/agent-session-lifecycle');
|
|
46
|
+
/**
|
|
47
|
+
* Open a new event generation for an agent instance that is about to start.
|
|
48
|
+
*
|
|
49
|
+
* Safe to call for a tool that emits nothing: the fence is a timestamp, and a
|
|
50
|
+
* tool with no events simply never has any to fence.
|
|
51
|
+
*
|
|
52
|
+
* @param target - The instance being created
|
|
53
|
+
* @param at - Epoch ms; defaults to now
|
|
54
|
+
*/
|
|
55
|
+
function beginAgentSession(target, at = Date.now()) {
|
|
56
|
+
(0, agent_event_state_1.beginAgentEventGeneration)(target.worktreeId, target.cliToolId, target.instanceId, at);
|
|
57
|
+
const source = (0, sources_1.getAgentEventSource)(target.cliToolId);
|
|
58
|
+
logger.info('agent-session-generation-begun', {
|
|
59
|
+
worktreeId: target.worktreeId,
|
|
60
|
+
cliToolId: target.cliToolId,
|
|
61
|
+
instanceId: target.instanceId ?? target.cliToolId,
|
|
62
|
+
transport: source.transport,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The command that starts this agent, with whatever config it needs written
|
|
67
|
+
* first (S3 / S4).
|
|
68
|
+
*
|
|
69
|
+
* A thin pass-through to the tool's source, and the reason a session module
|
|
70
|
+
* does not import a settings generator: which file gets written, and whether
|
|
71
|
+
* one gets written at all, is the source's business.
|
|
72
|
+
*
|
|
73
|
+
* Never throws — see {@link AgentEventSource.prepareLaunch}. A tool whose
|
|
74
|
+
* config could not be written starts bare, which is the pre-#1722 status quo.
|
|
75
|
+
*
|
|
76
|
+
* @param target - The instance being started
|
|
77
|
+
* @param executablePath - Resolved path to the agent CLI
|
|
78
|
+
* @returns The command line, and the config file when one was written
|
|
79
|
+
*/
|
|
80
|
+
function prepareAgentLaunch(target, executablePath) {
|
|
81
|
+
return (0, sources_1.getAgentEventSource)(target.cliToolId).prepareLaunch(target, executablePath);
|
|
82
|
+
}
|
|
@@ -26,7 +26,8 @@ const promises_1 = require("fs/promises");
|
|
|
26
26
|
const logger_1 = require("../../lib/logger");
|
|
27
27
|
const cli_tool_timing_config_1 = require("../../config/cli-tool-timing-config");
|
|
28
28
|
const types_1 = require("../../lib/cli-tools/types");
|
|
29
|
-
const
|
|
29
|
+
const sources_1 = require("../../lib/hooks/sources");
|
|
30
|
+
const agent_session_lifecycle_1 = require("../../lib/session/agent-session-lifecycle");
|
|
30
31
|
const agent_event_state_1 = require("../../lib/session/agent-event-state");
|
|
31
32
|
const session_start_error_1 = require("../../lib/session/session-start-error");
|
|
32
33
|
const logger = (0, logger_1.createLogger)('claude-session');
|
|
@@ -566,7 +567,10 @@ async function startClaudeSession(options) {
|
|
|
566
567
|
// live pane is matched against a stale generation. Bumped even if the start
|
|
567
568
|
// then fails: falling back to the scraper is always safe, trusting a dead
|
|
568
569
|
// session's events is not.
|
|
569
|
-
|
|
570
|
+
// Issue #1759: through the shared helper, which is the one call every
|
|
571
|
+
// tool's `startSession` makes. Claude's was the only fence in the codebase;
|
|
572
|
+
// making it the helper's job is what lets Phase 4-2…4-5 have one too.
|
|
573
|
+
(0, agent_session_lifecycle_1.beginAgentSession)({ worktreeId, cliToolId: sources_1.CLAUDE_CLI_TOOL_ID, instanceId });
|
|
570
574
|
try {
|
|
571
575
|
// Create tmux session. Scrollback depth comes from the shared
|
|
572
576
|
// TMUX_HISTORY_LIMIT default (Issue #1624) — do not re-hardcode it here.
|
|
@@ -594,7 +598,10 @@ async function startClaudeSession(options) {
|
|
|
594
598
|
//
|
|
595
599
|
// Falls back to the bare path on any failure; a session that starts without
|
|
596
600
|
// hooks is the pre-#1722 status quo, and a session that fails to start is not.
|
|
597
|
-
|
|
601
|
+
// Issue #1759: which config file gets written, and whether one is written
|
|
602
|
+
// at all, belongs to the tool's `AgentEventSource` (S3/S4). Claude's
|
|
603
|
+
// delegates to `buildClaudeLaunchCommand`, unchanged.
|
|
604
|
+
const launchCommand = (0, agent_session_lifecycle_1.prepareAgentLaunch)({ worktreeId, cliToolId: sources_1.CLAUDE_CLI_TOOL_ID, instanceId }, claudePath).command;
|
|
598
605
|
// Start Claude CLI in interactive mode using dynamically resolved path
|
|
599
606
|
await (0, tmux_1.sendKeys)(sessionName, launchCommand, true);
|
|
600
607
|
// Wait for Claude to initialize with dynamic detection (OCP-001)
|