commandmate 0.30.1 → 0.31.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 +164 -164
- package/.next/app-path-routes-manifest.json +28 -28
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +9 -9
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/session/route.js +1 -1
- package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/start/route.js +3 -3
- 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 +4 -4
- package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route.js +1 -1
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route.js +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route.js +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_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 +4 -3
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +4 -3
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/chat/page.js +2 -2
- package/.next/server/app/chat/page.js.nft.json +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.js +2 -2
- package/.next/server/app/more/page.js.nft.json +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +1 -1
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page.js +2 -2
- package/.next/server/app/repositories/page.js.nft.json +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page.js +1 -1
- package/.next/server/app/review/page.js.nft.json +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page.js.nft.json +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page.js +2 -2
- package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page.js +2 -2
- package/.next/server/app/skills/installed/page.js.nft.json +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page.js +1 -1
- package/.next/server/app/skills/page.js.nft.json +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +10 -10
- package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +28 -28
- package/.next/server/chunks/1058.js +1 -1
- package/.next/server/chunks/1068.js +1 -1
- package/.next/server/chunks/1262.js +1 -1
- package/.next/server/chunks/1886.js +3 -3
- package/.next/server/chunks/1990.js +103 -0
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2328.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/261.js +1 -1
- package/.next/server/chunks/3123.js +1 -1
- package/.next/server/chunks/3241.js +1 -1
- package/.next/server/chunks/3480.js +5 -4
- package/.next/server/chunks/4299.js +1 -1
- package/.next/server/chunks/4393.js +1 -1
- package/.next/server/chunks/4443.js +1 -5
- package/.next/server/chunks/5017.js +1 -1
- package/.next/server/chunks/5043.js +1 -1
- package/.next/server/chunks/5164.js +1 -1
- package/.next/server/chunks/552.js +2 -2
- package/.next/server/chunks/6072.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/663.js +4 -3
- package/.next/server/chunks/6894.js +2 -2
- package/.next/server/chunks/7187.js +1 -0
- package/.next/server/chunks/7472.js +1 -1
- package/.next/server/chunks/{880.js → 7859.js} +6 -6
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8800.js +2 -2
- package/.next/server/chunks/8918.js +7 -0
- package/.next/server/chunks/9123.js +2 -2
- package/.next/server/chunks/9130.js +4 -4
- package/.next/server/chunks/9627.js +1 -1
- package/.next/server/chunks/9696.js +2 -2
- package/.next/server/chunks/9798.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/1783-11c9b4d8a52ebd91.js +1 -0
- package/.next/static/chunks/4718-de1224c9e8a6e7fc.js +1 -0
- package/.next/static/chunks/6022-2fa0b5a82d4ce7b6.js +1 -0
- package/.next/static/chunks/{5229-6c89475b61bd2c8b.js → 6170-951b9f5fe6b4b3b5.js} +1 -1
- package/.next/static/chunks/app/chat/{page-9aa2011410895b0d.js → page-37d7615d17d7e2a0.js} +1 -1
- package/.next/static/chunks/app/layout-4c2f21e3f653ee4c.js +1 -0
- package/.next/static/chunks/app/more/{page-333bba1c8bbc9c11.js → page-353a3924e6d7968e.js} +1 -1
- package/.next/static/chunks/app/{page-214f7ffa13a0cf10.js → page-c2bf871d953a1d6f.js} +1 -1
- package/.next/static/chunks/app/repositories/{page-4951cac905e50224.js → page-7d0f26df0537254c.js} +1 -1
- package/.next/static/chunks/app/review/{page-a0899b2d285318c3.js → page-e3f141b2829973e9.js} +1 -1
- package/.next/static/chunks/app/sessions/{page-fb36145ec732092a.js → page-53f188ed9ca49e5f.js} +1 -1
- package/.next/static/chunks/app/skills/[skillId]/{page-9099e26b60442873.js → page-80569b720aea59cc.js} +1 -1
- package/.next/static/chunks/app/skills/installed/{page-182e32368696d824.js → page-dbd2690ad72da95b.js} +1 -1
- package/.next/static/chunks/app/skills/{page-d3fdc88239ebe0ab.js → page-dacd36f9c11aa7da.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/page-97205088520255a5.js +1 -0
- package/.next/static/css/5c13ea243dfdcb66.css +1 -0
- package/.next/trace +13 -13
- package/README.md +37 -11
- package/dist/cli/commands/attach.d.ts +50 -0
- package/dist/cli/commands/attach.d.ts.map +1 -0
- package/dist/cli/commands/attach.js +204 -0
- package/dist/cli/commands/capture.d.ts.map +1 -1
- package/dist/cli/commands/capture.js +114 -0
- package/dist/cli/commands/instances.d.ts.map +1 -1
- package/dist/cli/commands/instances.js +23 -2
- package/dist/cli/commands/ls.d.ts.map +1 -1
- package/dist/cli/commands/ls.js +41 -1
- package/dist/cli/config/cli-dependencies.d.ts.map +1 -1
- package/dist/cli/config/cli-dependencies.js +34 -0
- package/dist/cli/program.d.ts.map +1 -1
- package/dist/cli/program.js +5 -0
- package/dist/cli/types/index.d.ts +36 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/config/tmux-pane-config.d.ts +153 -0
- package/dist/config/tmux-pane-config.d.ts.map +1 -0
- package/dist/config/tmux-pane-config.js +172 -0
- package/dist/lib/cli-tools/session-name.d.ts +44 -0
- package/dist/lib/cli-tools/session-name.d.ts.map +1 -0
- package/dist/lib/cli-tools/session-name.js +57 -0
- package/dist/lib/cli-tools/types.d.ts +1 -1
- package/dist/lib/cli-tools/types.d.ts.map +1 -1
- package/dist/lib/cli-tools/types.js +6 -1
- package/dist/lib/cli-tools/validation.d.ts +34 -0
- package/dist/lib/cli-tools/validation.d.ts.map +1 -0
- package/dist/lib/cli-tools/validation.js +41 -0
- package/dist/lib/detection/status-reason.d.ts +18 -0
- package/dist/lib/detection/status-reason.d.ts.map +1 -1
- package/dist/lib/detection/status-reason.js +18 -0
- package/dist/lib/detection/tools/verified-against.d.ts +57 -7
- package/dist/lib/detection/tools/verified-against.d.ts.map +1 -1
- package/dist/lib/detection/tools/verified-against.js +59 -8
- package/dist/lib/detection/version-probes.d.ts +26 -5
- package/dist/lib/detection/version-probes.d.ts.map +1 -1
- package/dist/lib/detection/version-probes.js +28 -6
- package/dist/lib/session/tmux-session-surface.d.ts +369 -0
- package/dist/lib/session/tmux-session-surface.d.ts.map +1 -0
- package/dist/lib/session/tmux-session-surface.js +525 -0
- package/dist/server/src/config/cli-tool-timing-config.js +12 -1
- package/dist/server/src/config/detection-evidence-config.js +5 -0
- package/dist/server/src/config/schedule-config.js +28 -1
- package/dist/server/src/lib/cli-tools/antigravity.js +2 -2
- package/dist/server/src/lib/cli-tools/base.js +13 -8
- package/dist/server/src/lib/cli-tools/claude.js +20 -0
- package/dist/server/src/lib/cli-tools/codex.js +205 -61
- package/dist/server/src/lib/cli-tools/command-code.js +349 -0
- package/dist/server/src/lib/cli-tools/composer-spec.js +6 -0
- package/dist/server/src/lib/cli-tools/copilot.js +2 -2
- package/dist/server/src/lib/cli-tools/gemini.js +2 -2
- package/dist/server/src/lib/cli-tools/graceful-exit.js +16 -1
- package/dist/server/src/lib/cli-tools/index.js +4 -1
- package/dist/server/src/lib/cli-tools/install-hints.js +131 -0
- package/dist/server/src/lib/cli-tools/liveness-spec.js +18 -0
- package/dist/server/src/lib/cli-tools/manager.js +2 -0
- package/dist/server/src/lib/cli-tools/opencode.js +2 -2
- package/dist/server/src/lib/cli-tools/start-availability.js +18 -11
- package/dist/server/src/lib/cli-tools/types.js +6 -1
- package/dist/server/src/lib/cli-tools/vibe-local.js +2 -2
- package/dist/server/src/lib/cmate-parser.js +6 -0
- package/dist/server/src/lib/detection/cli-patterns.js +441 -8
- package/dist/server/src/lib/detection/opencode-modal-overlay.js +66 -100
- package/dist/server/src/lib/detection/selection-shape.js +341 -0
- package/dist/server/src/lib/detection/sgr-background.js +210 -0
- package/dist/server/src/lib/detection/status-detector.js +6 -0
- package/dist/server/src/lib/detection/status-reason.js +18 -0
- package/dist/server/src/lib/detection/tools/antigravity/detect.js +38 -15
- package/dist/server/src/lib/detection/tools/codex/cli-patterns.js +392 -0
- package/dist/server/src/lib/detection/tools/codex/detect.js +83 -2
- package/dist/server/src/lib/detection/tools/command-code/detect.js +159 -0
- package/dist/server/src/lib/detection/tools/registry.js +6 -4
- package/dist/server/src/lib/detection/tools/verified-against.js +59 -8
- package/dist/server/src/lib/detection/version-probes.js +28 -6
- package/dist/server/src/lib/hooks/sources/antigravity/history.js +101 -21
- package/dist/server/src/lib/hooks/sources/antigravity/transcript.js +39 -0
- package/dist/server/src/lib/hooks/sources/claude/history.js +245 -21
- package/dist/server/src/lib/hooks/sources/claude/transcript.js +175 -13
- package/dist/server/src/lib/hooks/sources/codex/history.js +84 -15
- package/dist/server/src/lib/hooks/sources/codex/hooks-config.js +130 -17
- package/dist/server/src/lib/hooks/sources/codex/relay-install.js +145 -0
- package/dist/server/src/lib/hooks/sources/command-code/history.js +865 -0
- package/dist/server/src/lib/hooks/sources/command-code/hooks-config.js +390 -0
- package/dist/server/src/lib/hooks/sources/command-code/source.js +290 -0
- package/dist/server/src/lib/hooks/sources/command-code/tool-id.js +18 -0
- package/dist/server/src/lib/hooks/sources/command-code/transcript.js +604 -0
- package/dist/server/src/lib/hooks/sources/index.js +3 -1
- package/dist/server/src/lib/hooks/sources/opencode/history.js +57 -3
- package/dist/server/src/lib/hooks/sources/opencode/transcript.js +24 -28
- package/dist/server/src/lib/hooks/sources/registry.js +4 -0
- package/dist/server/src/lib/hooks/sources/turn-body.js +77 -19
- package/dist/server/src/lib/hooks/stop-history-capture.js +58 -25
- package/dist/server/src/lib/job-executor.js +12 -0
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +6 -0
- package/dist/server/src/lib/polling/response-checker.js +112 -7
- package/dist/server/src/lib/polling/structured-history-gate.js +15 -8
- package/dist/server/src/lib/realtime/types.js +15 -5
- package/dist/server/src/lib/response-cleaner.js +24 -1
- package/dist/server/src/lib/response-extractor.js +11 -0
- package/dist/server/src/lib/session/claude-executor.js +223 -4
- package/dist/server/src/lib/session/cli-session.js +52 -0
- package/dist/server/src/lib/session/tmux-session-surface.js +525 -0
- package/dist/server/src/lib/skills/compatibility-matrix.js +117 -1
- package/dist/server/src/lib/tmux/geometry-delegation.js +143 -0
- package/dist/server/src/lib/tmux/read-mode-pager.js +76 -10
- package/dist/server/src/lib/tmux/read-mode.js +44 -2
- package/dist/server/src/lib/tmux/session-hook-scripts.js +249 -0
- package/dist/server/src/lib/tmux/session-hooks.js +122 -0
- package/dist/server/src/lib/tmux/session-status-options.js +213 -0
- package/dist/server/src/lib/tmux/tmux.js +79 -2
- package/dist/server/src/lib/version-checker.js +110 -0
- package/dist/server/src/lib/ws-server.js +16 -10
- package/dist/server/src/types/agent-transcript.js +73 -1
- package/dist/server/src/types/terminal-keys.js +131 -3
- package/dist/types/terminal-keys.d.ts +100 -3
- package/dist/types/terminal-keys.d.ts.map +1 -1
- package/dist/types/terminal-keys.js +131 -3
- package/package.json +1 -1
- package/.next/server/chunks/3099.js +0 -5
- package/.next/server/chunks/7824.js +0 -1
- package/.next/static/chunks/3916-0e929d089282dc5d.js +0 -1
- package/.next/static/chunks/6022-7a7d1760fc9814c7.js +0 -1
- package/.next/static/chunks/6381-dbf04a99647f6018.js +0 -1
- package/.next/static/chunks/app/layout-6a26ea22d5cf03dc.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-aac399392ec8c273.js +0 -1
- package/.next/static/css/23f9c40ecc458c77.css +0 -1
- /package/.next/static/{pcpB4K6KreMzu2qbhvuRY → nXW4dPkpE_9xUf_9ySRff}/_buildManifest.js +0 -0
- /package/.next/static/{pcpB4K6KreMzu2qbhvuRY → nXW4dPkpE_9xUf_9ySRff}/_ssgManifest.js +0 -0
|
@@ -90,7 +90,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
90
90
|
};
|
|
91
91
|
})();
|
|
92
92
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
93
|
-
exports.CLAUDE_TRANSCRIPT_TAIL_BYTES = void 0;
|
|
93
|
+
exports.CLAUDE_TURN_RECHECK_LIMIT = exports.CLAUDE_TRANSCRIPT_TAIL_BYTES = void 0;
|
|
94
94
|
exports.resetClaudeTranscriptSessions = resetClaudeTranscriptSessions;
|
|
95
95
|
exports.resolveClaudeSessionId = resolveClaudeSessionId;
|
|
96
96
|
exports.claudeProjectsRoot = claudeProjectsRoot;
|
|
@@ -324,6 +324,12 @@ async function captureClaudeTranscriptTurn(target, capture) {
|
|
|
324
324
|
});
|
|
325
325
|
}
|
|
326
326
|
const pending = await selectUnwrittenClaudeTurns(target, built.turns);
|
|
327
|
+
// Before anything is written: the rows that are already there (#2264). This
|
|
328
|
+
// is deliberately ahead of the early return below, because "the newest turn
|
|
329
|
+
// is already a row" is the state the nine short rows the Issue measured were
|
|
330
|
+
// stuck in — the reader answered true and did nothing while the transcript
|
|
331
|
+
// beside it held the missing paragraph.
|
|
332
|
+
await refreshClaudeTurnRows(target, built.turns.slice(0, built.turns.length - pending.turns.length).slice(-exports.CLAUDE_TURN_RECHECK_LIMIT), path);
|
|
327
333
|
if (pending.turns.length === 0) {
|
|
328
334
|
// The anchor is the newest turn in the window, so there is nothing to
|
|
329
335
|
// write and the newest turn is a row. True, for the reason
|
|
@@ -352,12 +358,23 @@ async function captureClaudeTranscriptTurn(target, capture) {
|
|
|
352
358
|
// by timestamp, and each turn's `/send` row is adopted against the previous
|
|
353
359
|
// turn's start, so a later turn must not get to claim a row an earlier one
|
|
354
360
|
// is about to ask for.
|
|
361
|
+
//
|
|
362
|
+
// Every prompt row is recorded before any reply is written (Issue #2273).
|
|
363
|
+
// That is what lets a reply be dated at its turn's END without overtaking
|
|
364
|
+
// the NEXT turn's prompt: a queued `/send` row is written while this turn is
|
|
365
|
+
// still running, so its instant is only knowable once that row has been
|
|
366
|
+
// recorded. With one turn pending — the ordinary case — this is the single
|
|
367
|
+
// call it always was.
|
|
368
|
+
const userRows = [];
|
|
369
|
+
for (let index = 0; index < pending.turns.length; index += 1) {
|
|
370
|
+
const previousStartedAt = index === 0 ? pending.previousStartedAt : pending.turns[index - 1].startedAt;
|
|
371
|
+
userRows.push(await recordClaudeUserTurn(target, pending.turns[index], previousStartedAt));
|
|
372
|
+
}
|
|
373
|
+
const lastRecordAt = lastClaudeAssistantRecordAt(parsed.records);
|
|
355
374
|
let captured = false;
|
|
356
375
|
for (let index = 0; index < pending.turns.length; index += 1) {
|
|
357
376
|
const turn = pending.turns[index];
|
|
358
|
-
|
|
359
|
-
const userRow = await recordClaudeUserTurn(target, turn, previousStartedAt);
|
|
360
|
-
captured = await writeClaudeTurn(target, (0, transcript_1.renderClaudeTurn)(turn), resolveAssistantTimestampMs(turn, userRow), path);
|
|
377
|
+
captured = await writeClaudeTurn(target, turn, (0, transcript_1.renderClaudeTurn)(turn), resolveAssistantTimestampMs(turn, userRows[index], lastRecordAt.get(turn.promptUuid) ?? 0, nextTurnOpensAt(pending.turns, userRows, index)), path);
|
|
361
378
|
}
|
|
362
379
|
return captured;
|
|
363
380
|
}
|
|
@@ -493,6 +510,11 @@ function collectHeadlessClaudeTurn(records, sessionId) {
|
|
|
493
510
|
promptIsOperatorInput: false,
|
|
494
511
|
blocks,
|
|
495
512
|
assistantRecords,
|
|
513
|
+
// Never handed to a writer, so neither flag can be read off it; false is the
|
|
514
|
+
// value that would refuse the write if one were ever attempted.
|
|
515
|
+
closed: false,
|
|
516
|
+
superseded: false,
|
|
517
|
+
stopReasonObserved: false,
|
|
496
518
|
overflowed,
|
|
497
519
|
};
|
|
498
520
|
}
|
|
@@ -632,22 +654,87 @@ async function recordClaudeUserTurn(target, turn, previousStartedAt = 0) {
|
|
|
632
654
|
/**
|
|
633
655
|
* When the assistant row for this turn is dated.
|
|
634
656
|
*
|
|
635
|
-
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
639
|
-
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
645
|
-
*
|
|
657
|
+
* **The turn's LAST assistant record, not its prompt (Issue #2273).** #2121
|
|
658
|
+
* dated the reply by the prompt record's clock so that a row written a poll late
|
|
659
|
+
* still sorted where the conversation put it, and #2196 moved it one millisecond
|
|
660
|
+
* on so that `groupMessagesIntoPairs` — which orders by timestamp and nothing
|
|
661
|
+
* else — could never return the answer above the question. Both properties
|
|
662
|
+
* survive: `earliest` is a floor this never goes under.
|
|
663
|
+
*
|
|
664
|
+
* What neither accounted for is the row that lands BETWEEN the prompt and the
|
|
665
|
+
* reply. A tool approval is written when the dialog appears, seconds into the
|
|
666
|
+
* turn, and the chat surface orders its rows by timestamp — so a reply dated at
|
|
667
|
+
* the turn's start draws ABOVE an approval that really happened before it. The
|
|
668
|
+
* measured case is in the Issue: prompt `04:49:50.989Z`, reply `04:49:54.000Z`,
|
|
669
|
+
* approval `04:49:57.513Z`, rendered as question → answer → approval.
|
|
670
|
+
*
|
|
671
|
+
* The turn's last assistant record is the moment the reply was finished, so
|
|
672
|
+
* everything the turn produced on the way sorts before it. `lastRecordAt` is 0
|
|
673
|
+
* when the window held no timestamped assistant record for the turn, and the row
|
|
674
|
+
* is then dated exactly where #2196 put it.
|
|
675
|
+
*
|
|
676
|
+
* `nextTurnOpensAt` is the ceiling. The next turn's prompt row may be a `/send`
|
|
677
|
+
* row written while THIS turn was still running — a queued prompt — and a reply
|
|
678
|
+
* that overtook it would be paired with the wrong question.
|
|
679
|
+
*
|
|
680
|
+
* @param lastRecordAt - Epoch ms of the turn's last assistant record, or 0
|
|
681
|
+
* @param nextTurnOpensAt - Epoch ms of the next turn's user row, or null when
|
|
682
|
+
* this is the newest turn in the window
|
|
646
683
|
*/
|
|
647
|
-
function resolveAssistantTimestampMs(turn, userRow) {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
684
|
+
function resolveAssistantTimestampMs(turn, userRow, lastRecordAt = 0, nextTurnOpensAt = null) {
|
|
685
|
+
const earliest = userRow.timestampMs === null
|
|
686
|
+
? turn.startedAt
|
|
687
|
+
: Math.max(turn.startedAt, userRow.timestampMs + 1);
|
|
688
|
+
const latest = nextTurnOpensAt === null ? Number.POSITIVE_INFINITY : nextTurnOpensAt - 1;
|
|
689
|
+
return Math.max(earliest, Math.min(lastRecordAt, latest));
|
|
690
|
+
}
|
|
691
|
+
/**
|
|
692
|
+
* When each turn's last assistant record was written (Issue #2273).
|
|
693
|
+
*
|
|
694
|
+
* Keyed by `promptUuid`, which is the turn key {@link buildClaudeTurns} uses, and
|
|
695
|
+
* walked over the same records with the same two rules — sidechains skipped, a
|
|
696
|
+
* prompt record opening a turn — so the two passes cannot disagree about which
|
|
697
|
+
* turn a record belongs to. It is a second pass rather than a field on the
|
|
698
|
+
* accumulator because `./transcript` is not this Issue's to change.
|
|
699
|
+
*
|
|
700
|
+
* Only `assistant` records count. A turn's `user` records are its tool RESULTS,
|
|
701
|
+
* and the last of those is a step the agent took before it had finished
|
|
702
|
+
* answering; the reply is dated by the agent's last word.
|
|
703
|
+
*
|
|
704
|
+
* @returns `promptUuid` → epoch ms; absent for a turn with no timestamped
|
|
705
|
+
* assistant record
|
|
706
|
+
*/
|
|
707
|
+
function lastClaudeAssistantRecordAt(records) {
|
|
708
|
+
const at = new Map();
|
|
709
|
+
let key = null;
|
|
710
|
+
for (const record of records) {
|
|
711
|
+
if (record.isSidechain)
|
|
712
|
+
continue;
|
|
713
|
+
if ((0, transcript_1.isClaudePromptRecord)(record)) {
|
|
714
|
+
key = record.uuid;
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
if (record.type !== 'assistant' || key === null || record.timestampMs === null)
|
|
718
|
+
continue;
|
|
719
|
+
if (record.timestampMs > (at.get(key) ?? 0))
|
|
720
|
+
at.set(key, record.timestampMs);
|
|
721
|
+
}
|
|
722
|
+
return at;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* The instant the next pending turn's prompt row carries, or null (Issue #2273).
|
|
726
|
+
*
|
|
727
|
+
* The user row's own timestamp when there is one, because that is what History
|
|
728
|
+
* sorts on and it can be EARLIER than the turn's start — an adopted `/send` row
|
|
729
|
+
* was written when CommandMate handed the text to the pane, which for a queued
|
|
730
|
+
* prompt is while the previous turn was still running. The turn's start is the
|
|
731
|
+
* fallback for a turn that produced no row at all.
|
|
732
|
+
*/
|
|
733
|
+
function nextTurnOpensAt(turns, userRows, index) {
|
|
734
|
+
const next = turns[index + 1];
|
|
735
|
+
if (!next)
|
|
736
|
+
return null;
|
|
737
|
+
return userRows[index + 1]?.timestampMs ?? next.startedAt;
|
|
651
738
|
}
|
|
652
739
|
/**
|
|
653
740
|
* The transcript file for this instance, or null.
|
|
@@ -717,6 +804,113 @@ async function readClaudeTranscriptTail(path) {
|
|
|
717
804
|
await handle?.close().catch(() => { });
|
|
718
805
|
}
|
|
719
806
|
}
|
|
807
|
+
/**
|
|
808
|
+
* How many already-written turns are re-rendered and compared (Issue #2264).
|
|
809
|
+
*
|
|
810
|
+
* The repair half of #2264 has to look at rows the reader has **already**
|
|
811
|
+
* written, which is the one thing the anchor rule deliberately does not do — so
|
|
812
|
+
* it is bounded here rather than by the window. Three, because the poller runs
|
|
813
|
+
* every two seconds and re-rendering the whole 4 MiB window on every tick would
|
|
814
|
+
* turn a repair into the most expensive thing the poll does, while a row that is
|
|
815
|
+
* going to grow grows within a second of being written.
|
|
816
|
+
*
|
|
817
|
+
* The cost of the bound is only paid by rows the old code left short: those are
|
|
818
|
+
* repaired on the next read that still has the turn among its newest three, and
|
|
819
|
+
* a session that has moved four turns past one of them keeps it. The Issue's own
|
|
820
|
+
* nine rows were all the newest turn at the time, so all nine are inside it.
|
|
821
|
+
*/
|
|
822
|
+
exports.CLAUDE_TURN_RECHECK_LIMIT = 3;
|
|
823
|
+
/**
|
|
824
|
+
* Replace a saved row whose body has since grown (Issue #2264).
|
|
825
|
+
*
|
|
826
|
+
* The second half of the fix, and the half that repairs what the first half
|
|
827
|
+
* only stops happening again. A row keyed `claude-turn:<uuid>` is written once
|
|
828
|
+
* and every later read answers "already saved" — so the nine short rows the
|
|
829
|
+
* Issue measured were frozen, and the scrape that could have replaced them was
|
|
830
|
+
* suppressed two seconds later by that same idempotency answer.
|
|
831
|
+
*
|
|
832
|
+
* **Strictly longer, never merely different.** Equality is the ordinary case and
|
|
833
|
+
* must cost nothing, and a body that got *shorter* between two reads is not a
|
|
834
|
+
* turn that grew — it is a window that slid, or a truncation marker, and
|
|
835
|
+
* overwriting a full reply with a shorter one is the one outcome worse than the
|
|
836
|
+
* bug. Longer implies different, so one comparison covers both halves of the
|
|
837
|
+
* Issue's "differs and is longer".
|
|
838
|
+
*
|
|
839
|
+
* `message_updated`, never `message`: the row already existed and was already
|
|
840
|
+
* delivered when it was created (#2195), so a client that appended instead of
|
|
841
|
+
* replacing would show the reply twice.
|
|
842
|
+
*
|
|
843
|
+
* @param existing - The row `findMessageByRequestId` answered with
|
|
844
|
+
* @returns Whether the row was replaced
|
|
845
|
+
*/
|
|
846
|
+
async function growClaudeTurnRow(target, existing, rendered, path) {
|
|
847
|
+
const instanceId = target.instanceId ?? target.cliToolId;
|
|
848
|
+
const previousLength = existing.content.length;
|
|
849
|
+
if (rendered.body.length <= previousLength)
|
|
850
|
+
return false;
|
|
851
|
+
const [{ getDbInstance }, { updateMessageContent }, { broadcastMessage }] = await Promise.all([
|
|
852
|
+
Promise.resolve().then(() => __importStar(require('../../../../lib/db/db-instance'))),
|
|
853
|
+
Promise.resolve().then(() => __importStar(require('../../../../lib/db'))),
|
|
854
|
+
Promise.resolve().then(() => __importStar(require('../../../../lib/ws-server'))),
|
|
855
|
+
]);
|
|
856
|
+
updateMessageContent(getDbInstance(), existing.id, rendered.body);
|
|
857
|
+
broadcastMessage('message_updated', {
|
|
858
|
+
worktreeId: target.worktreeId,
|
|
859
|
+
message: { ...existing, content: rendered.body },
|
|
860
|
+
});
|
|
861
|
+
logger.info('claude-transcript-turn-updated', {
|
|
862
|
+
worktreeId: target.worktreeId,
|
|
863
|
+
instanceId,
|
|
864
|
+
sessionId: rendered.sessionId,
|
|
865
|
+
requestId: existing.requestId,
|
|
866
|
+
path,
|
|
867
|
+
previousLength,
|
|
868
|
+
bodyLength: rendered.body.length,
|
|
869
|
+
textBlocks: rendered.textBlocks,
|
|
870
|
+
toolBlocks: rendered.toolBlocks,
|
|
871
|
+
});
|
|
872
|
+
return true;
|
|
873
|
+
}
|
|
874
|
+
/**
|
|
875
|
+
* Re-read the newest already-written turns and grow the short ones (#2264).
|
|
876
|
+
*
|
|
877
|
+
* Runs before the pending turns are written and independently of whether there
|
|
878
|
+
* are any — the case it exists for is precisely the one
|
|
879
|
+
* {@link captureClaudeTranscriptTurn} used to return `true` from without doing
|
|
880
|
+
* anything: the newest turn already has a row, and that row is missing its last
|
|
881
|
+
* paragraph.
|
|
882
|
+
*
|
|
883
|
+
* Turns that are still open are skipped rather than compared. Their body is by
|
|
884
|
+
* definition not the final one, and a repair that raced the agent would rewrite
|
|
885
|
+
* the row on every poll of a long turn.
|
|
886
|
+
*
|
|
887
|
+
* The database is asked before the turn is rendered, so a candidate with no row
|
|
888
|
+
* — every candidate, in a session this reader has never written to — costs one
|
|
889
|
+
* indexed lookup and no Markdown.
|
|
890
|
+
*
|
|
891
|
+
* @param candidates - Already-written turns, oldest first, at most {@link CLAUDE_TURN_RECHECK_LIMIT}
|
|
892
|
+
* @returns How many rows were replaced
|
|
893
|
+
*/
|
|
894
|
+
async function refreshClaudeTurnRows(target, candidates, path) {
|
|
895
|
+
if (candidates.length === 0)
|
|
896
|
+
return 0;
|
|
897
|
+
const [{ getDbInstance }, { findMessageByRequestId }] = await Promise.all([
|
|
898
|
+
Promise.resolve().then(() => __importStar(require('../../../../lib/db/db-instance'))),
|
|
899
|
+
Promise.resolve().then(() => __importStar(require('../../../../lib/db'))),
|
|
900
|
+
]);
|
|
901
|
+
const db = getDbInstance();
|
|
902
|
+
let updated = 0;
|
|
903
|
+
for (const turn of candidates) {
|
|
904
|
+
if (!(0, transcript_1.isClaudeTurnWritable)(turn))
|
|
905
|
+
continue;
|
|
906
|
+
const existing = findMessageByRequestId(db, target.worktreeId, (0, agent_transcript_1.claudeTurnRequestId)(turn.promptUuid));
|
|
907
|
+
if (!existing)
|
|
908
|
+
continue;
|
|
909
|
+
if (await growClaudeTurnRow(target, existing, (0, transcript_1.renderClaudeTurn)(turn), path))
|
|
910
|
+
updated += 1;
|
|
911
|
+
}
|
|
912
|
+
return updated;
|
|
913
|
+
}
|
|
720
914
|
/**
|
|
721
915
|
* Write one rendered turn, unless it is already there.
|
|
722
916
|
*
|
|
@@ -731,8 +925,33 @@ async function readClaudeTranscriptTail(path) {
|
|
|
731
925
|
*
|
|
732
926
|
* @returns Whether History holds this turn as the agent's own Markdown
|
|
733
927
|
*/
|
|
734
|
-
async function writeClaudeTurn(target, rendered, timestampMs, path) {
|
|
928
|
+
async function writeClaudeTurn(target, turn, rendered, timestampMs, path) {
|
|
735
929
|
const instanceId = target.instanceId ?? target.cliToolId;
|
|
930
|
+
if (!(0, transcript_1.isClaudeTurnWritable)(turn)) {
|
|
931
|
+
// The agent has not said `end_turn` for this prompt and no later prompt has
|
|
932
|
+
// taken over, so what is in the file is a turn in progress. Writing it would
|
|
933
|
+
// put a reply with its last paragraph missing into History **permanently** —
|
|
934
|
+
// the row is keyed on the prompt's `uuid`, so every later read finds it and
|
|
935
|
+
// answers "already saved". That is Issue #2264 exactly: 9 of `claude-2`'s 20
|
|
936
|
+
// turns on 2026-09-03 were saved as a bare `> **Tool calls (1)**` with not
|
|
937
|
+
// one character of prose, because the Stop hook beat the last append and the
|
|
938
|
+
// emptiness guard below cannot see the difference — a turn cut off after its
|
|
939
|
+
// tool calls renders a *non-empty* body.
|
|
940
|
+
//
|
|
941
|
+
// Handing it back to the scraper costs the Markdown rendering for this turn
|
|
942
|
+
// and nothing else: the Stop receiver asks again after a short delay, and
|
|
943
|
+
// the poller asks again when the pane returns to the composer.
|
|
944
|
+
logger.info('claude-transcript-turn-open', {
|
|
945
|
+
worktreeId: target.worktreeId,
|
|
946
|
+
instanceId,
|
|
947
|
+
sessionId: rendered.sessionId,
|
|
948
|
+
promptUuid: rendered.promptUuid,
|
|
949
|
+
assistantRecords: turn.assistantRecords,
|
|
950
|
+
textBlocks: rendered.textBlocks,
|
|
951
|
+
toolBlocks: rendered.toolBlocks,
|
|
952
|
+
});
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
736
955
|
if (rendered.body.length === 0) {
|
|
737
956
|
// The turn is open but the agent has not written anything to the file yet —
|
|
738
957
|
// the prompt record is there and the assistant records are not. Answering
|
|
@@ -762,12 +981,17 @@ async function writeClaudeTurn(target, rendered, timestampMs, path) {
|
|
|
762
981
|
Promise.resolve().then(() => __importStar(require('../../../../lib/ws-server'))),
|
|
763
982
|
]);
|
|
764
983
|
const db = getDbInstance();
|
|
765
|
-
|
|
984
|
+
const existing = findMessageByRequestId(db, target.worktreeId, requestId);
|
|
985
|
+
if (existing) {
|
|
766
986
|
logger.debug('claude-transcript-turn-already-saved', {
|
|
767
987
|
worktreeId: target.worktreeId,
|
|
768
988
|
instanceId,
|
|
769
989
|
requestId,
|
|
770
990
|
});
|
|
991
|
+
// The row may still be one of the short ones #2264 was reported for, and
|
|
992
|
+
// this is the one place that knows both the row and the turn. See
|
|
993
|
+
// {@link growClaudeTurnRow}.
|
|
994
|
+
await growClaudeTurnRow(target, existing, rendered, path);
|
|
771
995
|
return true;
|
|
772
996
|
}
|
|
773
997
|
const message = createMessage(db, {
|
|
@@ -36,9 +36,12 @@
|
|
|
36
36
|
* is therefore keyed on the *prompt* record, never on a `requestId`.
|
|
37
37
|
* 3. **`type: "user"` is mostly not the user.** Of 19 user records in the
|
|
38
38
|
* sampled session, 18 were `tool_result` payloads. Tool results, `isMeta`
|
|
39
|
-
* placeholders (`[Image: original 1440x2170…]`), and the
|
|
39
|
+
* placeholders (`[Image: original 1440x2170…]`), and the built-in command
|
|
40
40
|
* bookkeeping records (`<command-name>`, `<local-command-stdout>`) all have
|
|
41
|
-
* `type: "user"` and none of them is a prompt.
|
|
41
|
+
* `type: "user"` and none of them is a prompt. The one `<command-…>` shape
|
|
42
|
+
* that *is* a prompt — a project command, recorded `<command-message>` first
|
|
43
|
+
* — is Issue #2265; see {@link CLAUDE_SLASH_COMMAND_PREFIX} and
|
|
44
|
+
* {@link isClaudePromptRecord}.
|
|
42
45
|
* 4. **`thinking` blocks can be empty.** The block arrives with a `signature`
|
|
43
46
|
* and `thinking: ""` when the text is not retained, so an empty one is
|
|
44
47
|
* skipped rather than rendered as a blank quote.
|
|
@@ -53,13 +56,16 @@
|
|
|
53
56
|
* @module lib/hooks/sources/claude/transcript
|
|
54
57
|
*/
|
|
55
58
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
-
exports.CLAUDE_HUMAN_PROMPT_SOURCES = exports.CLAUDE_HUMAN_ORIGIN_KIND = exports.CLAUDE_THINKING_LABEL = exports.MAX_CLAUDE_TOOL_DETAIL_LENGTH = exports.MAX_CLAUDE_TURN_BLOCKS = exports.CLAUDE_TURN_TRUNCATION_MARKER = exports.MAX_CLAUDE_TURN_BODY_LENGTH = exports.CLAUDE_PROJECTS_DIR_SEGMENTS = void 0;
|
|
59
|
+
exports.CLAUDE_END_TURN_STOP_REASON = exports.CLAUDE_HUMAN_PROMPT_SOURCES = exports.CLAUDE_HUMAN_ORIGIN_KIND = exports.CLAUDE_SLASH_COMMAND_PREFIX = exports.CLAUDE_THINKING_LABEL = exports.MAX_CLAUDE_TOOL_DETAIL_LENGTH = exports.MAX_CLAUDE_TURN_BLOCKS = exports.CLAUDE_TURN_TRUNCATION_MARKER = exports.MAX_CLAUDE_TURN_BODY_LENGTH = exports.CLAUDE_PROJECTS_DIR_SEGMENTS = void 0;
|
|
57
60
|
exports.claudeProjectSlug = claudeProjectSlug;
|
|
61
|
+
exports.claudeSlashCommandPrompt = claudeSlashCommandPrompt;
|
|
58
62
|
exports.readClaudeContentBlock = readClaudeContentBlock;
|
|
59
63
|
exports.readClaudeTranscriptRecord = readClaudeTranscriptRecord;
|
|
60
64
|
exports.parseClaudeTranscript = parseClaudeTranscript;
|
|
61
65
|
exports.isClaudePromptRecord = isClaudePromptRecord;
|
|
62
66
|
exports.isClaudeOperatorPromptRecord = isClaudeOperatorPromptRecord;
|
|
67
|
+
exports.isClaudeTurnClosingRecord = isClaudeTurnClosingRecord;
|
|
68
|
+
exports.isClaudeTurnWritable = isClaudeTurnWritable;
|
|
63
69
|
exports.createClaudeTurn = createClaudeTurn;
|
|
64
70
|
exports.buildClaudeTurns = buildClaudeTurns;
|
|
65
71
|
exports.renderClaudeTurn = renderClaudeTurn;
|
|
@@ -111,18 +117,97 @@ exports.CLAUDE_THINKING_LABEL = 'Thinking';
|
|
|
111
117
|
/**
|
|
112
118
|
* Prefixes that mark a `type: "user"` record as bookkeeping rather than a prompt.
|
|
113
119
|
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
120
|
+
* Three since Issue #2265, which took `<command-message>` off the list — see
|
|
121
|
+
* {@link CLAUDE_SLASH_COMMAND_PREFIX} for the census that separated the two
|
|
122
|
+
* shapes the `<command-…>` trio is written in. What is left is the bookkeeping
|
|
123
|
+
* of a **built-in** command: `<command-name>` first is how Claude records
|
|
124
|
+
* `/model`, `/compact`, `/clear`, `/login` and `/plan`, `<local-command-stdout>`
|
|
125
|
+
* is that command's output, and `<local-command-caveat>` is the preamble in
|
|
126
|
+
* front of it. Treating any of them as a prompt would open a turn that the agent
|
|
127
|
+
* never answers, and the reply to the *next* real prompt would be filed under it.
|
|
119
128
|
*/
|
|
120
129
|
const CLAUDE_SYNTHETIC_PROMPT_PREFIXES = [
|
|
121
130
|
'<local-command-caveat>',
|
|
122
131
|
'<local-command-stdout>',
|
|
123
132
|
'<command-name>',
|
|
124
|
-
'<command-message>',
|
|
125
133
|
];
|
|
134
|
+
/**
|
|
135
|
+
* The tag a slash command the operator typed opens with (Issue #2265).
|
|
136
|
+
*
|
|
137
|
+
* ## The two shapes, and why the leading tag is the discriminator
|
|
138
|
+
*
|
|
139
|
+
* Claude writes the same three tags for two quite different events, and it
|
|
140
|
+
* writes them in a different **order** for each. Measured over every
|
|
141
|
+
* `type: "user"` record under `~/.claude/projects` on 2026-09-03 whose text
|
|
142
|
+
* opens with one of the `<command-…>` tags — 222 records:
|
|
143
|
+
*
|
|
144
|
+
* | leading tag | count | `<command-name>` values |
|
|
145
|
+
* |---|---|---|
|
|
146
|
+
* | `<command-message>` | 118 | `/orchestrate`, `/release`, `/uat`, `/worktree-cleanup`, `/worktree-new`, `/multi-stage-design-review`, `/cmate-*` |
|
|
147
|
+
* | `<command-name>` | 104 | `/model`, `/compact`, `/clear`, `/login`, `/plan` |
|
|
148
|
+
*
|
|
149
|
+
* The split is exact and it is the split that matters here. The 118 are
|
|
150
|
+
* *project and user commands* — a `.claude/commands/*.md` or a skill, expanded
|
|
151
|
+
* into instructions the agent then works through, which is a turn with a reply
|
|
152
|
+
* in it. The 104 are commands Claude Code executes itself; their whole output is
|
|
153
|
+
* the `<local-command-stdout>` record that follows and the agent never answers
|
|
154
|
+
* them.
|
|
155
|
+
*
|
|
156
|
+
* Before #2265 both were excluded, on the reading that a slash command is not
|
|
157
|
+
* "the operator's text". That cost the 118 their entire turn: the reply was
|
|
158
|
+
* folded into whichever turn came before — already saved, so
|
|
159
|
+
* `selectUnwrittenClaudeTurns` answered "nothing to write", and the answer *this*
|
|
160
|
+
* reader gives is also what suppresses the scraper's copy. The measured loss was
|
|
161
|
+
* a `/release v0.30.1` turn of 7 text blocks and an `/orchestrate` turn of 8,
|
|
162
|
+
* neither of which reached History by any path at all.
|
|
163
|
+
*
|
|
164
|
+
* ## `origin`, and the versions that carry it
|
|
165
|
+
*
|
|
166
|
+
* The 118 also answer {@link isClaudeOperatorPromptRecord}, but only on recent
|
|
167
|
+
* Claude Code: of them, every record from 2.1.238 onwards (46) carries
|
|
168
|
+
* `origin: {"kind": "human"}` and every record before it (72, versions 2.1.220
|
|
169
|
+
* … 2.1.235) carries neither marker — those predate the field. On an old
|
|
170
|
+
* version the turn is still opened and its reply still written; only the `user`
|
|
171
|
+
* row is skipped, which is #2196's stated degradation and not a new one.
|
|
172
|
+
*/
|
|
173
|
+
exports.CLAUDE_SLASH_COMMAND_PREFIX = '<command-message>';
|
|
174
|
+
/** `<command-name>/release</command-name>` — the command itself. */
|
|
175
|
+
const CLAUDE_COMMAND_NAME_PATTERN = /<command-name>([\s\S]*?)<\/command-name>/;
|
|
176
|
+
/** `<command-args>v0.30.1</command-args>` — absent on a bare invocation. */
|
|
177
|
+
const CLAUDE_COMMAND_ARGS_PATTERN = /<command-args>([\s\S]*?)<\/command-args>/;
|
|
178
|
+
/**
|
|
179
|
+
* The line the operator typed, rebuilt from a slash-command record (Issue #2265).
|
|
180
|
+
*
|
|
181
|
+
* `<command-name>` and `<command-args>` back into `/release v0.30.1`, which is
|
|
182
|
+
* the string that was in the composer and — for a command CommandMate sent — the
|
|
183
|
+
* string `sendUserMessage` already wrote to `chat_messages`. That equality is
|
|
184
|
+
* what makes the `/send` row *adoptable* instead of duplicated: `recordUserTurn`
|
|
185
|
+
* compares on normalised content, and the raw record text
|
|
186
|
+
* (`<command-message>release</command-message>\n<command-name>…`) matches nothing
|
|
187
|
+
* a person ever sent.
|
|
188
|
+
*
|
|
189
|
+
* Returns null for anything that is not this shape, including a
|
|
190
|
+
* `<command-message>` record with no `<command-name>` in it. Null is what keeps
|
|
191
|
+
* {@link isClaudePromptRecord} from opening a turn it could not name: a record
|
|
192
|
+
* whose command cannot be read would otherwise reach History as its own XML,
|
|
193
|
+
* which is exactly the class of mistake #2196's positive-evidence rule exists to
|
|
194
|
+
* avoid. No such record was observed — all 118 carried both tags.
|
|
195
|
+
*
|
|
196
|
+
* @param text - The record's text, as {@link ClaudeTranscriptRecord.text} holds it
|
|
197
|
+
* @returns `/name args`, `/name` when there are no arguments, or null
|
|
198
|
+
*/
|
|
199
|
+
function claudeSlashCommandPrompt(text) {
|
|
200
|
+
const trimmed = text.trim();
|
|
201
|
+
if (!trimmed.startsWith(exports.CLAUDE_SLASH_COMMAND_PREFIX))
|
|
202
|
+
return null;
|
|
203
|
+
const name = CLAUDE_COMMAND_NAME_PATTERN.exec(trimmed)?.[1].trim() ?? '';
|
|
204
|
+
if (name.length === 0)
|
|
205
|
+
return null;
|
|
206
|
+
// Absent on a bare invocation, and empty on a command invoked with no
|
|
207
|
+
// arguments; both mean the prompt is the command name on its own.
|
|
208
|
+
const args = CLAUDE_COMMAND_ARGS_PATTERN.exec(trimmed)?.[1].trim() ?? '';
|
|
209
|
+
return args.length === 0 ? name : `${name} ${args}`;
|
|
210
|
+
}
|
|
126
211
|
/**
|
|
127
212
|
* Read one `message.content` element.
|
|
128
213
|
*
|
|
@@ -235,6 +320,7 @@ function readClaudeTranscriptRecord(value) {
|
|
|
235
320
|
isCompactSummary: value.isCompactSummary === true,
|
|
236
321
|
isInterruption: (0, event_mapper_1.readStringField)(value, 'interruptedMessageId') !== null,
|
|
237
322
|
timestampMs: Number.isFinite(parsed) ? parsed : null,
|
|
323
|
+
stopReason: message ? (0, event_mapper_1.readStringField)(message, 'stop_reason') : null,
|
|
238
324
|
blocks,
|
|
239
325
|
text,
|
|
240
326
|
};
|
|
@@ -279,11 +365,19 @@ function parseClaudeTranscript(text) {
|
|
|
279
365
|
*
|
|
280
366
|
* - it carries a `tool_result` block — 18 of the 19 user records in the sampled
|
|
281
367
|
* session were these;
|
|
282
|
-
* - `isMeta` is true — the image placeholders
|
|
283
|
-
*
|
|
284
|
-
*
|
|
368
|
+
* - `isMeta` is true — the image placeholders, the local-command caveat, and
|
|
369
|
+
* the body of the `.claude/commands/*.md` or skill a slash command expands
|
|
370
|
+
* to, which arrives on its own record right behind the one below;
|
|
371
|
+
* - its text opens with one of {@link CLAUDE_SYNTHETIC_PROMPT_PREFIXES} — a
|
|
372
|
+
* built-in command and its output;
|
|
285
373
|
* - it has no text at all, or no `uuid` to name the turn with.
|
|
286
374
|
*
|
|
375
|
+
* A record opening with {@link CLAUDE_SLASH_COMMAND_PREFIX} is the fifth case
|
|
376
|
+
* and the one Issue #2265 changed: it **is** a prompt, because the operator
|
|
377
|
+
* typed `/release v0.30.1` and the agent answers it at length. It qualifies only
|
|
378
|
+
* when {@link claudeSlashCommandPrompt} can actually read the command out of it,
|
|
379
|
+
* so a shape this reader could not name never opens a turn.
|
|
380
|
+
*
|
|
287
381
|
* Everything else is treated as a prompt, including `[Request interrupted by
|
|
288
382
|
* user]`. That is deliberate: an interruption really does end the turn, and the
|
|
289
383
|
* records after it really do belong to whatever came next.
|
|
@@ -300,6 +394,8 @@ function isClaudePromptRecord(record) {
|
|
|
300
394
|
const text = record.text.trim();
|
|
301
395
|
if (text.length === 0)
|
|
302
396
|
return false;
|
|
397
|
+
if (text.startsWith(exports.CLAUDE_SLASH_COMMAND_PREFIX))
|
|
398
|
+
return claudeSlashCommandPrompt(text) !== null;
|
|
303
399
|
return !CLAUDE_SYNTHETIC_PROMPT_PREFIXES.some((prefix) => text.startsWith(prefix));
|
|
304
400
|
}
|
|
305
401
|
/**
|
|
@@ -345,6 +441,14 @@ exports.CLAUDE_HUMAN_PROMPT_SOURCES = ['typed', 'queued'];
|
|
|
345
441
|
* is the pre-#2196 behaviour — an orphaned assistant pair, which is untidy, and
|
|
346
442
|
* not a fabricated user message, which is wrong.
|
|
347
443
|
*
|
|
444
|
+
* Issue #2265 widened what reaches here by one shape — the project-command
|
|
445
|
+
* record `isClaudePromptRecord` now accepts — and the rule holds on it without
|
|
446
|
+
* change: of the 118 such records under `~/.claude/projects` on 2026-09-03, the
|
|
447
|
+
* 46 written by Claude Code 2.1.238 and later carry `origin: {"kind": "human"}`
|
|
448
|
+
* and answer true, and the 72 written before the field existed carry no marker
|
|
449
|
+
* and answer false. The second group loses its `user` row and keeps its reply,
|
|
450
|
+
* which is this function's designed degradation rather than a new gap.
|
|
451
|
+
*
|
|
348
452
|
* `isCompactSummary` and `isInterruption` are then checked explicitly even
|
|
349
453
|
* though nothing observed carries a human marker *and* either flag. They are not
|
|
350
454
|
* redundant by construction: compaction and interruption are both things the
|
|
@@ -362,16 +466,62 @@ function isClaudeOperatorPromptRecord(record) {
|
|
|
362
466
|
return record.originKind === exports.CLAUDE_HUMAN_ORIGIN_KIND;
|
|
363
467
|
return record.promptSource !== null && exports.CLAUDE_HUMAN_PROMPT_SOURCES.includes(record.promptSource);
|
|
364
468
|
}
|
|
469
|
+
/**
|
|
470
|
+
* `message.stop_reason` on the record that ends a reply (Issue #2264).
|
|
471
|
+
*
|
|
472
|
+
* The other value this reader cares about is `tool_use`, which is not named as
|
|
473
|
+
* a constant because nothing branches on it: everything that is not `end_turn`
|
|
474
|
+
* leaves the turn open.
|
|
475
|
+
*/
|
|
476
|
+
exports.CLAUDE_END_TURN_STOP_REASON = 'end_turn';
|
|
477
|
+
/**
|
|
478
|
+
* Whether this assistant record is the one that ended the reply (Issue #2264).
|
|
479
|
+
*
|
|
480
|
+
* `end_turn` **and** prose on the same record. See
|
|
481
|
+
* {@link ClaudeTurnAccumulator.closed} for why neither half alone is the rule,
|
|
482
|
+
* and note that the emptiness test here is the one `renderClaudeTurn` applies to
|
|
483
|
+
* a text block — a block whose `text` trims to nothing is not rendered, so it
|
|
484
|
+
* cannot be what makes a turn look finished either.
|
|
485
|
+
*/
|
|
486
|
+
function isClaudeTurnClosingRecord(record) {
|
|
487
|
+
if (record.type !== 'assistant')
|
|
488
|
+
return false;
|
|
489
|
+
if (record.stopReason !== exports.CLAUDE_END_TURN_STOP_REASON)
|
|
490
|
+
return false;
|
|
491
|
+
return record.blocks.some((block) => block.type === 'text' && (block.text ?? '').trim().length > 0);
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Whether a writer may record this turn (Issue #2264).
|
|
495
|
+
*
|
|
496
|
+
* Either proof that nothing more is coming: the agent said so
|
|
497
|
+
* ({@link ClaudeTurnAccumulator.closed}), or it has moved on to another prompt
|
|
498
|
+
* ({@link ClaudeTurnAccumulator.superseded}).
|
|
499
|
+
*/
|
|
500
|
+
function isClaudeTurnWritable(turn) {
|
|
501
|
+
if (turn.closed || turn.superseded)
|
|
502
|
+
return true;
|
|
503
|
+
// No record of this turn said why it stopped, so there is no evidence to
|
|
504
|
+
// refuse it on. See {@link ClaudeTurnAccumulator.stopReasonObserved}: this is
|
|
505
|
+
// unreachable against every Claude version measured, and it is what keeps a
|
|
506
|
+
// version that stops writing the field from silently disabling the reader.
|
|
507
|
+
return !turn.stopReasonObserved;
|
|
508
|
+
}
|
|
365
509
|
/** A brand-new accumulator for one turn. */
|
|
366
510
|
function createClaudeTurn(record, sessionId) {
|
|
367
511
|
return {
|
|
368
512
|
sessionId: record.sessionId ?? sessionId,
|
|
369
513
|
promptUuid: record.uuid,
|
|
370
514
|
startedAt: record.timestampMs ?? 0,
|
|
371
|
-
|
|
515
|
+
// A slash command's record is XML and the operator typed a line; #2265 puts
|
|
516
|
+
// the line on the turn so that the `user` row reads `/release v0.30.1` and
|
|
517
|
+
// the `/send` row holding those same bytes is adopted rather than doubled.
|
|
518
|
+
promptText: claudeSlashCommandPrompt(record.text) ?? record.text,
|
|
372
519
|
promptIsOperatorInput: isClaudeOperatorPromptRecord(record),
|
|
373
520
|
blocks: [],
|
|
374
521
|
assistantRecords: 0,
|
|
522
|
+
closed: false,
|
|
523
|
+
superseded: false,
|
|
524
|
+
stopReasonObserved: false,
|
|
375
525
|
overflowed: false,
|
|
376
526
|
};
|
|
377
527
|
}
|
|
@@ -416,6 +566,13 @@ function buildClaudeTurns(records, sessionId) {
|
|
|
416
566
|
continue;
|
|
417
567
|
}
|
|
418
568
|
current.assistantRecords += 1;
|
|
569
|
+
// Assigned rather than or-ed, so the value left standing is the *last*
|
|
570
|
+
// assistant record's answer. A turn that ends on a `tool_use` record after
|
|
571
|
+
// an earlier `end_turn` — which is what a turn Claude resumed looks like —
|
|
572
|
+
// is open again, and that is the reading the Issue's census supports.
|
|
573
|
+
current.closed = isClaudeTurnClosingRecord(record);
|
|
574
|
+
if (record.stopReason !== null)
|
|
575
|
+
current.stopReasonObserved = true;
|
|
419
576
|
for (const block of record.blocks) {
|
|
420
577
|
if (current.blocks.length >= exports.MAX_CLAUDE_TURN_BLOCKS) {
|
|
421
578
|
current.overflowed = true;
|
|
@@ -424,6 +581,11 @@ function buildClaudeTurns(records, sessionId) {
|
|
|
424
581
|
current.blocks.push(block);
|
|
425
582
|
}
|
|
426
583
|
}
|
|
584
|
+
// Every turn but the last one has a later prompt behind it, and a prompt is
|
|
585
|
+
// proof the agent moved on. See {@link ClaudeTurnAccumulator.superseded}.
|
|
586
|
+
for (let index = 0; index < turns.length - 1; index += 1) {
|
|
587
|
+
turns[index].superseded = true;
|
|
588
|
+
}
|
|
427
589
|
return { turns, orphanedAssistantRecords, sidechainRecords };
|
|
428
590
|
}
|
|
429
591
|
/**
|