commandmate 0.43.0 → 0.44.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 +209 -209
- package/.next/app-path-routes-manifest.json +36 -36
- 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.js.nft.json +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route.js +2 -2
- package/.next/server/app/api/app/update/route.js.nft.json +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.js.nft.json +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route.js.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.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.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.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.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.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.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 +2 -2
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route.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/escalation/route.js +1 -1
- package/.next/server/app/api/push/escalation/route.js.nft.json +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.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/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.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/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.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.nft.json +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.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.js.nft.json +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.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.js +1 -1
- package/.next/server/app/api/skills/[id]/route.js.nft.json +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 +2 -2
- 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.js +1 -1
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route.js.nft.json +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.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.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.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.nft.json +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.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.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.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.js.nft.json +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.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.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route.js.nft.json +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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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.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]/instances/notes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.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.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.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.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 +7 -7
- 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.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.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.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]/opencode/diff/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.js.nft.json +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.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.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.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 +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.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.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route.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 +103 -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.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.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.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.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.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.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/config/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.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]/cancel/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route.js.nft.json +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.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.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.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/apply-default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route.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.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 +1 -1
- 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_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 +3 -3
- 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 +36 -36
- package/.next/server/chunks/1501.js +3 -3
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2283.js +15 -0
- package/.next/server/chunks/2328.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/4207.js +1 -1
- package/.next/server/chunks/4802.js +1 -1
- package/.next/server/chunks/488.js +1 -0
- package/.next/server/chunks/5326.js +1 -1
- package/.next/server/chunks/5456.js +1 -1
- package/.next/server/chunks/611.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6474.js +14 -0
- package/.next/server/chunks/650.js +1 -0
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/{5742.js → 6927.js} +1 -1
- package/.next/server/chunks/7506.js +1 -1
- package/.next/server/chunks/7905.js +1 -1
- package/.next/server/chunks/8543.js +1 -1
- package/.next/server/chunks/8581.js +1 -1
- package/.next/server/chunks/8728.js +2 -2
- package/.next/server/chunks/8782.js +1 -0
- package/.next/server/chunks/8791.js +1 -1
- package/.next/server/chunks/8918.js +105 -3
- package/.next/server/chunks/9130.js +1 -1
- package/.next/server/chunks/9390.js +1 -1
- package/.next/server/chunks/967.js +1 -1
- package/.next/server/chunks/9731.js +3 -3
- package/.next/server/chunks/9882.js +2 -2
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages-manifest.json +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/server/src/middleware.js +2 -2
- package/.next/server/src/middleware.js.map +1 -1
- package/.next/static/chunks/{1642-767aed8e7c61ef7f.js → 1642-fb2e176aaadbd137.js} +1 -1
- package/.next/static/chunks/2053-85a974ddfe7498fe.js +1 -0
- package/.next/static/chunks/{2407-940df9b11fadafc6.js → 2407-340774f1a24f2b45.js} +1 -1
- package/.next/static/chunks/{2619-a305ad4810f1393a.js → 2619-04bc32f026a0d946.js} +1 -1
- package/.next/static/chunks/5521-c358c31f60e5e689.js +1 -0
- package/.next/static/chunks/591-0a45801e83f26f24.js +1 -0
- package/.next/static/chunks/{8165-3525fb42f1b4976e.js → 8165-3853772f6ae1299b.js} +1 -1
- package/.next/static/chunks/{8566-a6a7c70558927410.js → 8566-aeda747542072ace.js} +1 -1
- package/.next/static/chunks/8811-29eaa24237f48558.js +1 -0
- package/.next/static/chunks/{9619-22adf5367c4b7080.js → 9619-84aced0846cbe3ac.js} +1 -1
- package/.next/static/chunks/app/{layout-057c850cd0df978e.js → layout-0fc249fb7de75a27.js} +1 -1
- package/.next/static/chunks/app/sessions/page-55297155e7bf01b9.js +1 -0
- package/.next/static/chunks/app/skills/[skillId]/{page-74aac15286504ef4.js → page-9ee7a381636e60cb.js} +1 -1
- package/.next/static/chunks/app/worktrees/[id]/page-d2103e0c25be83c8.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/{page-c601f3b3ece6557e.js → page-373ea37b16d930c7.js} +1 -1
- package/.next/static/css/38070d879efa1371.css +1 -0
- package/.next/trace +13 -13
- package/README.md +58 -620
- package/dist/cli/commands/capture.d.ts.map +1 -1
- package/dist/cli/commands/capture.js +11 -1
- package/dist/cli/commands/docs.d.ts.map +1 -1
- package/dist/cli/commands/docs.js +5 -0
- package/dist/cli/commands/remote.d.ts +24 -1
- package/dist/cli/commands/remote.d.ts.map +1 -1
- package/dist/cli/commands/remote.js +155 -6
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +255 -112
- package/dist/cli/commands/stop.d.ts.map +1 -1
- package/dist/cli/commands/stop.js +53 -1
- package/dist/cli/commands/sync.js +3 -3
- package/dist/cli/docs/setup-guide.d.ts +14 -0
- package/dist/cli/docs/setup-guide.d.ts.map +1 -0
- package/dist/cli/docs/setup-guide.js +366 -0
- package/dist/cli/types/api-responses.d.ts +11 -0
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/types/index.d.ts +2 -0
- package/dist/cli/types/index.d.ts.map +1 -1
- package/dist/cli/utils/daemon.d.ts +42 -2
- package/dist/cli/utils/daemon.d.ts.map +1 -1
- package/dist/cli/utils/daemon.js +222 -40
- package/dist/cli/utils/docs-reader.d.ts +6 -0
- package/dist/cli/utils/docs-reader.d.ts.map +1 -1
- package/dist/cli/utils/docs-reader.js +14 -13
- package/dist/cli/utils/npm-runner.d.ts +12 -0
- package/dist/cli/utils/npm-runner.d.ts.map +1 -1
- package/dist/cli/utils/npm-runner.js +36 -0
- package/dist/cli/utils/process-inspect.d.ts +55 -0
- package/dist/cli/utils/process-inspect.d.ts.map +1 -0
- package/dist/cli/utils/process-inspect.js +214 -0
- package/dist/cli/utils/remote-pairing.d.ts +68 -0
- package/dist/cli/utils/remote-pairing.d.ts.map +1 -0
- package/dist/cli/utils/remote-pairing.js +117 -0
- package/dist/cli/utils/server-identity.d.ts +50 -0
- package/dist/cli/utils/server-identity.d.ts.map +1 -0
- package/dist/cli/utils/server-identity.js +118 -0
- package/dist/cli/utils/server-ready.d.ts +13 -0
- package/dist/cli/utils/server-ready.d.ts.map +1 -1
- package/dist/cli/utils/server-ready.js +16 -0
- package/dist/lib/security/pairing-code.d.ts +2 -1
- package/dist/lib/security/pairing-code.d.ts.map +1 -1
- package/dist/server/locales/en/worktree.json +28 -6
- package/dist/server/locales/ja/worktree.json +28 -6
- package/dist/server/src/config/image-extensions.js +1 -0
- package/dist/server/src/lib/auto-yes-poller.js +22 -0
- package/dist/server/src/lib/cli-tools/command-code-plan-review.js +175 -0
- package/dist/server/src/lib/cli-tools/command-code.js +27 -2
- package/dist/server/src/lib/detection/cli-patterns.js +94 -1
- package/dist/server/src/lib/detection/tools/codex/detect.js +26 -0
- package/dist/server/src/lib/detection/tools/command-code/plan-review-state.js +75 -0
- package/dist/server/src/lib/hooks/sources/claude/transcript.js +33 -1
- package/dist/server/src/lib/session/claude-executor.js +2 -2
- package/dist/server/src/lib/session/claude-session.js +131 -15
- package/dist/server/src/lib/session/session-start-error.js +20 -0
- package/dist/server/src/lib/skills/agent-state-paths.js +39 -0
- package/dist/server/src/lib/skills/receipt-owned-paths.js +118 -0
- package/dist/server/src/lib/tmux/tmux.js +25 -0
- package/dist/server/src/lib/verification/env-clean-gate.js +195 -6
- package/dist/server/src/lib/verification/gate-runner.js +29 -2
- package/dist/server/src/lib/verification/scope-gate.js +58 -4
- package/docs/en/architecture.md +722 -0
- package/docs/en/user-guide/agents-guide.md +306 -0
- package/docs/en/user-guide/cli-setup-guide.md +676 -0
- package/docs/en/user-guide/cmate-schedules-guide.md +388 -0
- package/docs/en/user-guide/commands-guide.md +467 -0
- package/docs/en/user-guide/quick-start.md +231 -0
- package/docs/en/user-guide/webapp-guide.md +1020 -0
- package/docs/en/user-guide/workflow-examples.md +463 -0
- package/package.json +18 -7
- package/release-notes/0.44.0.json +82 -0
- package/.next/server/chunks/1990.js +0 -103
- package/.next/server/chunks/3707.js +0 -15
- package/.next/server/chunks/6491.js +0 -103
- package/.next/server/chunks/7004.js +0 -1
- package/.next/server/chunks/8673.js +0 -14
- package/.next/static/chunks/2039-117a361f795ddc4b.js +0 -1
- package/.next/static/chunks/2053-611dd27d42721b79.js +0 -1
- package/.next/static/chunks/3778-56f41fc2cecb8c43.js +0 -1
- package/.next/static/chunks/7705-1f58d4c03d991fcf.js +0 -1
- package/.next/static/chunks/app/sessions/page-1a8ba152bbcb9efb.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-eab0bf7564d3f9e2.js +0 -1
- package/.next/static/css/b3f433d52b8ed5c8.css +0 -1
- /package/.next/static/{BVkBYdceLRvMROqQIqeBx → wu7SUiHTirFcrpo5teyZ3}/_buildManifest.js +0 -0
- /package/.next/static/{BVkBYdceLRvMROqQIqeBx → wu7SUiHTirFcrpo5teyZ3}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
[日本語版](../architecture.md)
|
|
2
|
+
|
|
3
|
+
# CommandMate Architecture
|
|
4
|
+
|
|
5
|
+
> Architecture design document for a development companion tool that opens Claude Code / tmux sessions per git worktree and allows chat operations from a smartphone browser.
|
|
6
|
+
|
|
7
|
+
This document defines the technical architecture of **CommandMate**.
|
|
8
|
+
|
|
9
|
+
- What processes/components make up the system
|
|
10
|
+
- How Claude CLI / tmux / Web UI cooperate
|
|
11
|
+
- Which responsibilities belong to which layer
|
|
12
|
+
|
|
13
|
+
It serves as a guide during implementation.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 0. Scope & Notation
|
|
18
|
+
|
|
19
|
+
- Scope: The entire `CommandMate` application
|
|
20
|
+
- Next.js (App Router) based Web UI
|
|
21
|
+
- Node.js API / WebSocket server
|
|
22
|
+
- tmux + Claude CLI session management
|
|
23
|
+
- SQLite / local FS persistence
|
|
24
|
+
- Out of scope:
|
|
25
|
+
- Claude model behavior
|
|
26
|
+
- Specific integration implementations with other tools (mySwiftAgent / myAgentDesk, etc.)
|
|
27
|
+
|
|
28
|
+
Naming / Terminology:
|
|
29
|
+
|
|
30
|
+
- **worktree**: A branch directory managed as a git worktree
|
|
31
|
+
- **worktreeId**: A URL-safe identifier (e.g., `feature-foo`)
|
|
32
|
+
- **tmux session**: A tmux session named `cw_{worktreeId}`
|
|
33
|
+
- **Stop hook**: A completion hook set via Claude CLI's `CLAUDE_HOOKS_STOP`
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 1. System Goals
|
|
38
|
+
|
|
39
|
+
### 1.1 Goals
|
|
40
|
+
|
|
41
|
+
- Manage **independent Claude CLI sessions** per git worktree
|
|
42
|
+
- Provide a **per-branch chat UI** accessible from smartphone or PC browsers
|
|
43
|
+
- Use Stop hooks for **event-driven updates** without polling for the latest responses
|
|
44
|
+
- Safely store conversation history / detailed logs locally
|
|
45
|
+
|
|
46
|
+
### 1.2 Non-goals
|
|
47
|
+
|
|
48
|
+
- Operating as a multi-user SaaS (this is for local developers)
|
|
49
|
+
- Public exposure across security boundaries / multi-tenant operation
|
|
50
|
+
|
|
51
|
+
### 1.3 Implemented Features
|
|
52
|
+
|
|
53
|
+
- **CLI Tool Support** (Implemented in Issue #4, extended in Issue #368/#379/#545)
|
|
54
|
+
- Supports 7 tools: Claude Code, Codex CLI, Gemini CLI, Vibe-Local (Ollama), OpenCode, GitHub Copilot, Antigravity (the authority is `CLI_TOOL_IDS` in `src/lib/cli-tools/types.ts`)
|
|
55
|
+
- Extensible design via Strategy pattern
|
|
56
|
+
- Select 2-4 agents per worktree (`selected_agents` column)
|
|
57
|
+
- Vibe-Local supports Ollama model selection (`vibe_local_model` column)
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. Context & Assumptions
|
|
62
|
+
|
|
63
|
+
### 2.1 Prerequisites
|
|
64
|
+
|
|
65
|
+
- Runs on the developer's local machine
|
|
66
|
+
- macOS / Linux assumed (tmux / Claude CLI must be available)
|
|
67
|
+
- Claude CLI is installed and:
|
|
68
|
+
- Can be launched with the `claude` command
|
|
69
|
+
- Supports setting `CLAUDE_HOOKS_STOP`
|
|
70
|
+
- Multiple branch directories are managed via git worktree
|
|
71
|
+
|
|
72
|
+
### 2.2 Execution Modes
|
|
73
|
+
|
|
74
|
+
- **Local mode (default)**
|
|
75
|
+
- `MCBD_BIND = 127.0.0.1`
|
|
76
|
+
- Connections from the same machine only
|
|
77
|
+
- **LAN access mode (optional)**
|
|
78
|
+
- `CM_BIND = 0.0.0.0`
|
|
79
|
+
- Reverse proxy authentication recommended (details: `docs/security-guide.md`)
|
|
80
|
+
- Accessible from smartphones on the same network
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3. High-level Architecture
|
|
85
|
+
|
|
86
|
+
### 3.1 Component Diagram
|
|
87
|
+
|
|
88
|
+
```mermaid
|
|
89
|
+
graph TD
|
|
90
|
+
subgraph Browser["Smartphone/PC Browser"]
|
|
91
|
+
UI_A[Screen A: Worktree List]
|
|
92
|
+
UI_B[Screen B: Chat Screen]
|
|
93
|
+
UI_C[Screen C: Log Viewer]
|
|
94
|
+
UI_WS[WebSocket Client]
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
subgraph Next["Next.js / Node.js Application"]
|
|
98
|
+
App["Next.js UI (App Router)"]
|
|
99
|
+
API_Send[/POST /api/worktrees/:id/send/]
|
|
100
|
+
API_WT[/GET /api/worktrees/ .../]
|
|
101
|
+
API_Hook[/POST /api/hooks/claude-done/]
|
|
102
|
+
API_Logs[/GET /api/worktrees/:id/logs/ .../]
|
|
103
|
+
WS_Server[WebSocket Server]
|
|
104
|
+
DB[(SQLite db.sqlite)]
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
subgraph TmuxClaude["tmux / Claude CLI"]
|
|
108
|
+
T[(tmux server)]
|
|
109
|
+
S1[tmux session: cw_main]
|
|
110
|
+
S2[tmux session: cw_feature-foo]
|
|
111
|
+
CL1[Claude CLI Process]
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
subgraph FS["Local Filesystem"]
|
|
115
|
+
Logs[".claude_logs/ (Markdown logs)"]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
UI_A --> App
|
|
119
|
+
UI_B --> App
|
|
120
|
+
UI_C --> App
|
|
121
|
+
UI_WS <---> WS_Server
|
|
122
|
+
|
|
123
|
+
App --> API_WT
|
|
124
|
+
App --> API_Send
|
|
125
|
+
App --> API_Logs
|
|
126
|
+
|
|
127
|
+
API_Send --> T
|
|
128
|
+
API_Hook --> T
|
|
129
|
+
|
|
130
|
+
API_WT --> DB
|
|
131
|
+
API_Logs --> Logs
|
|
132
|
+
API_Hook --> DB
|
|
133
|
+
API_Hook --> Logs
|
|
134
|
+
API_Hook --> WS_Server
|
|
135
|
+
|
|
136
|
+
CL1 -->|"Stop hook"| API_Hook
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 3.2 Processes & Ports
|
|
140
|
+
|
|
141
|
+
- **Next.js / Node.js process**
|
|
142
|
+
- Port: MCBD_PORT (e.g., 3000)
|
|
143
|
+
- Bind: MCBD_BIND (127.0.0.1 or 0.0.0.0)
|
|
144
|
+
- Features:
|
|
145
|
+
- HTTP server (UI, API Routes)
|
|
146
|
+
- WebSocket server
|
|
147
|
+
- SQLite connection
|
|
148
|
+
- **tmux server**
|
|
149
|
+
- Uses the existing tmux server on the system
|
|
150
|
+
- Launches CLI tools in sessions named `cw_{worktreeId}`
|
|
151
|
+
- **CLI tool process (Claude Code / Codex CLI)**
|
|
152
|
+
- The selected CLI tool runs within each tmux session
|
|
153
|
+
- Sends completion notifications via the command set in `CLAUDE_HOOKS_STOP` (for Claude Code)
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 4. Data Model
|
|
158
|
+
|
|
159
|
+
### 4.1 Worktree
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
interface Worktree {
|
|
163
|
+
id: string; // URL-safe ID ("main", "feature-foo", etc.)
|
|
164
|
+
name: string; // Display name ("main", "feature/foo", etc.)
|
|
165
|
+
path: string; // Absolute path "/path/to/root/feature/foo"
|
|
166
|
+
lastMessageSummary?: string; // Summary of the last message
|
|
167
|
+
updatedAt?: Date; // Timestamp of last message
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
- **id**: Identifier normalized to a URL-parameter-safe format
|
|
172
|
+
- Example: `feature/foo` → `feature-foo`
|
|
173
|
+
- **path**: Absolute path based on `MCBD_ROOT_DIR`
|
|
174
|
+
- **updatedAt**: Used for sorting the worktree list by last update time
|
|
175
|
+
|
|
176
|
+
### 4.2 ChatMessage
|
|
177
|
+
|
|
178
|
+
```typescript
|
|
179
|
+
type ChatRole = "user" | "claude";
|
|
180
|
+
|
|
181
|
+
interface ChatMessage {
|
|
182
|
+
id: string; // UUID
|
|
183
|
+
worktreeId: string; // Worktree.id
|
|
184
|
+
role: ChatRole;
|
|
185
|
+
content: string; // Full text for UI display
|
|
186
|
+
summary?: string; // Optional short summary
|
|
187
|
+
timestamp: Date;
|
|
188
|
+
logFileName?: string; // Corresponding Markdown log file name
|
|
189
|
+
requestId?: string; // Future extension: 1 send = 1 UUID
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
- **content**: Text displayed directly in the chat UI (prompt/response).
|
|
194
|
+
- **summary**: Summary for `Worktree.lastMessageSummary` (optional).
|
|
195
|
+
- **logFileName**: Link to the detailed log file in `.claude_logs/`.
|
|
196
|
+
|
|
197
|
+
### 4.3 WorktreeSessionState
|
|
198
|
+
|
|
199
|
+
```typescript
|
|
200
|
+
interface WorktreeSessionState {
|
|
201
|
+
worktreeId: string;
|
|
202
|
+
lastCapturedLine: number; // Last line count obtained via tmux capture-pane
|
|
203
|
+
}
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
- On Stop hook, the entire scrollback is captured via `tmux capture-pane`.
|
|
207
|
+
- Lines after `lastCapturedLine` are treated as "new output" for differential extraction.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
## 5. Core Flows
|
|
212
|
+
|
|
213
|
+
### 5.1 Startup & Worktree Scan
|
|
214
|
+
|
|
215
|
+
1. On app startup, scan git worktrees based on `MCBD_ROOT_DIR`.
|
|
216
|
+
2. Store/update Worktree records in the DB based on the scanned worktree information.
|
|
217
|
+
3. If existing `cw_{worktreeId}` tmux sessions exist, reconcile them with Worktrees (optional).
|
|
218
|
+
|
|
219
|
+
### 5.2 Message Send Flow (UI → Claude)
|
|
220
|
+
|
|
221
|
+
**Overview**
|
|
222
|
+
|
|
223
|
+
```mermaid
|
|
224
|
+
sequenceDiagram
|
|
225
|
+
participant UI as UI (Screen B)
|
|
226
|
+
participant API as API_Send
|
|
227
|
+
participant T as tmux
|
|
228
|
+
participant CL as Claude CLI
|
|
229
|
+
|
|
230
|
+
UI->>API: POST /api/worktrees/:id/send { message }
|
|
231
|
+
API->>T: Check session existence (cw_{worktreeId})
|
|
232
|
+
alt No session
|
|
233
|
+
API->>T: tmux new-session (cw_{worktreeId})
|
|
234
|
+
API->>T: export CLAUDE_HOOKS_STOP=...
|
|
235
|
+
API->>T: Start claude
|
|
236
|
+
end
|
|
237
|
+
API->>T: tmux send-keys "message"
|
|
238
|
+
API-->>UI: 202 Accepted (send complete)
|
|
239
|
+
Note over UI: Display "Sending..." bubble
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
**Detailed Steps**
|
|
243
|
+
|
|
244
|
+
1. UI (Screen B) sends `POST /api/worktrees/:id/send` with `{ message }`.
|
|
245
|
+
2. API:
|
|
246
|
+
- Retrieves the Worktree from worktreeId and references the path.
|
|
247
|
+
- Checks session existence with `tmux has-session -t cw_{worktreeId}`.
|
|
248
|
+
- If not found, executes UC-2 (lazy startup flow, described below).
|
|
249
|
+
3. Sends the message to Claude CLI with `tmux send-keys -t cw_{worktreeId} "<message>" C-m`.
|
|
250
|
+
4. API responds immediately with 202 (Accepted). The UI displays the user's message plus a "Sending..." bubble.
|
|
251
|
+
|
|
252
|
+
### 5.3 Stop Hook Processing Flow (Claude → API → Logs/DB)
|
|
253
|
+
|
|
254
|
+
```mermaid
|
|
255
|
+
sequenceDiagram
|
|
256
|
+
participant CL as Claude CLI
|
|
257
|
+
participant Hook as CLAUDE_HOOKS_STOP
|
|
258
|
+
participant API as API_Hook
|
|
259
|
+
participant T as tmux
|
|
260
|
+
participant DB as SQLite
|
|
261
|
+
participant FS as .claude_logs
|
|
262
|
+
participant WS as WebSocket
|
|
263
|
+
|
|
264
|
+
CL-->>Hook: Completion hook invocation
|
|
265
|
+
Hook->>API: POST /api/hooks/claude-done { worktreeId }
|
|
266
|
+
API->>T: tmux capture-pane (capture full scrollback)
|
|
267
|
+
API->>API: Differential extraction (lines after lastCapturedLine)
|
|
268
|
+
API->>FS: Save as Markdown log
|
|
269
|
+
API->>DB: Update ChatMessage and Worktree.updatedAt
|
|
270
|
+
API->>WS: Publish new ChatMessage
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Detailed Steps**
|
|
274
|
+
|
|
275
|
+
1. When Claude CLI completes processing, it executes the command set in `CLAUDE_HOOKS_STOP`.
|
|
276
|
+
- Example:
|
|
277
|
+
```
|
|
278
|
+
HOOK_COMMAND="curl -X POST http://localhost:3000/api/hooks/claude-done \
|
|
279
|
+
-H 'Content-Type: application/json' \
|
|
280
|
+
-d '{\"worktreeId\":\"{worktreeId}\"}'"
|
|
281
|
+
export CLAUDE_HOOKS_STOP="${HOOK_COMMAND}"
|
|
282
|
+
```
|
|
283
|
+
2. `API_Hook` receives `POST /api/hooks/claude-done`:
|
|
284
|
+
- Reads `WorktreeSessionState.lastCapturedLine` (default 0).
|
|
285
|
+
- Captures scrollback with `tmux capture-pane -p -S -10000 -t cw_{worktreeId}`.
|
|
286
|
+
3. Counts lines in the captured text:
|
|
287
|
+
- Extracts only lines after `lastCapturedLine` as "new output".
|
|
288
|
+
- Future extension: If markers (`### REQUEST {id} START/END`) are introduced, only that range can be extracted.
|
|
289
|
+
4. Saves the extracted diff as Markdown under `.claude_logs/`.
|
|
290
|
+
5. Creates a `ChatMessage` record (`role = "claude"`) with the linked `logFileName`.
|
|
291
|
+
6. Updates `Worktree.lastMessageSummary` and `updatedAt`.
|
|
292
|
+
7. Publishes the new `ChatMessage` via WebSocket to all clients viewing the relevant worktree.
|
|
293
|
+
|
|
294
|
+
### 5.4 WebSocket Flow
|
|
295
|
+
|
|
296
|
+
- Clients subscribe by specifying a `worktreeId` upon connection.
|
|
297
|
+
- The server manages rooms/channels per `worktreeId`.
|
|
298
|
+
- When a new `ChatMessage` is saved, it broadcasts to all clients subscribed to that `worktreeId`.
|
|
299
|
+
|
|
300
|
+
Message format example:
|
|
301
|
+
```json
|
|
302
|
+
{
|
|
303
|
+
"type": "chat_message_created",
|
|
304
|
+
"worktreeId": "feature-foo",
|
|
305
|
+
"message": {
|
|
306
|
+
"id": "uuid",
|
|
307
|
+
"role": "claude",
|
|
308
|
+
"content": "Claude's response...",
|
|
309
|
+
"timestamp": "2025-11-16T03:00:00.000Z",
|
|
310
|
+
"logFileName": "20251116-030000-feature-foo-bd2f8c3d.md"
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### 5.5 Error / Recovery Flow
|
|
316
|
+
|
|
317
|
+
**When Stop hook doesn't arrive**
|
|
318
|
+
|
|
319
|
+
- UI side:
|
|
320
|
+
- If "Sending..." isn't replaced after a set period (e.g., 120 seconds), display a warning bubble.
|
|
321
|
+
- Server side:
|
|
322
|
+
- Log a timeout in the Hook API (implementation-dependent).
|
|
323
|
+
- Manual checking of `.claude_logs/` or tmux state is expected.
|
|
324
|
+
|
|
325
|
+
**When tmux session / Claude process crashes**
|
|
326
|
+
|
|
327
|
+
- During `API_Send`, check tmux session / process state with `tmux has-session`.
|
|
328
|
+
- If no session / Claude not found, restart via UC-2.
|
|
329
|
+
- Re-set `CLAUDE_HOOKS_STOP` when restarting Claude CLI.
|
|
330
|
+
|
|
331
|
+
---
|
|
332
|
+
|
|
333
|
+
## 6. tmux & CLI Tool Integration
|
|
334
|
+
|
|
335
|
+
### 6.1 Session Naming Convention
|
|
336
|
+
|
|
337
|
+
- Session name: `mcbd-{ns}-{cliToolId}-{worktreeId}[-{suffix}]` (Issue #2866)
|
|
338
|
+
- `{ns}` is a per-server namespace (8 hex digits, stored in the DB), so two servers with the same worktree ID never share a session name
|
|
339
|
+
- A legacy `mcbd-{cliToolId}-{worktreeId}[-{suffix}]` session is adopted by the server and keeps its legacy name
|
|
340
|
+
- Names are built and split in one place: `src/lib/cli-tools/session-name.ts` (`resolveSessionName` / `parseSessionName`)
|
|
341
|
+
- The ns lives in the server's DB, so the CLI cannot compute it. The server publishes `tmuxSessionNamespace` at the top level of `GET /api/worktrees` and the name actually in use as `agentInstances[].sessionName` on `GET /api/worktrees/[id]` (Issue #2867)
|
|
342
|
+
- Example:
|
|
343
|
+
- Claude: `mcbd-0a1b2c3d-claude-feature-foo` (legacy: `mcbd-claude-feature-foo`)
|
|
344
|
+
- One session per worktree is maintained.
|
|
345
|
+
- Note: Migration from old naming convention `cw_{worktreeId}`: Implemented in Issue #4
|
|
346
|
+
|
|
347
|
+
### 6.1.5 CLI Tool Abstraction Layer (Implemented in Issue #4)
|
|
348
|
+
|
|
349
|
+
**Design Pattern:**
|
|
350
|
+
- CLI tool abstraction via Strategy pattern
|
|
351
|
+
- `BaseCLITool` abstract class defines the common interface:
|
|
352
|
+
```typescript
|
|
353
|
+
abstract class BaseCLITool {
|
|
354
|
+
abstract id: CLIToolType;
|
|
355
|
+
abstract name: string;
|
|
356
|
+
abstract command: string;
|
|
357
|
+
|
|
358
|
+
abstract isInstalled(): Promise<boolean>;
|
|
359
|
+
abstract isRunning(worktreeId: string): Promise<boolean>;
|
|
360
|
+
abstract startSession(worktreeId: string, worktreePath: string): Promise<void>;
|
|
361
|
+
abstract sendMessage(worktreeId: string, message: string): Promise<void>;
|
|
362
|
+
abstract killSession(worktreeId: string): Promise<boolean>;
|
|
363
|
+
getSessionName(worktreeId: string): string;
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Implementation Classes:**
|
|
368
|
+
- `ClaudeTool` - Claude Code CLI
|
|
369
|
+
- `CodexTool` - Codex CLI
|
|
370
|
+
- `GeminiTool` - Gemini CLI (Issue #368)
|
|
371
|
+
- `VibeLocalTool` - Vibe-Local / Ollama (Issue #368)
|
|
372
|
+
- `OpenCodeTool` - OpenCode (Issue #379)
|
|
373
|
+
- `CopilotTool` - GitHub Copilot CLI (Issue #545)
|
|
374
|
+
|
|
375
|
+
**Management:**
|
|
376
|
+
- `CLIToolManager` singleton class manages each tool instance
|
|
377
|
+
- Retrieves the appropriate tool based on the worktree's `cliToolId`
|
|
378
|
+
|
|
379
|
+
**Benefits:**
|
|
380
|
+
- Easy to add new CLI tools (just extend `BaseCLITool`)
|
|
381
|
+
- API layer depends only on abstract interfaces, not specific implementations
|
|
382
|
+
- Encapsulates tool-specific logic
|
|
383
|
+
|
|
384
|
+
### 6.2 UC-2: Lazy Session Startup Flow
|
|
385
|
+
|
|
386
|
+
```bash
|
|
387
|
+
# {sessionName} = cw_{worktreeId}
|
|
388
|
+
# {worktreePath} = /path/to/root/feature/foo
|
|
389
|
+
tmux new-session -d -s "{sessionName}" -c "{worktreePath}"
|
|
390
|
+
|
|
391
|
+
HOOK_COMMAND="curl -X POST http://localhost:3000/api/hooks/claude-done \
|
|
392
|
+
-H 'Content-Type: application/json' \
|
|
393
|
+
-d '{\"worktreeId\":\"{worktreeId}\"}'"
|
|
394
|
+
|
|
395
|
+
tmux send-keys -t "{sessionName}" "export CLAUDE_HOOKS_STOP='${HOOK_COMMAND}'" C-m
|
|
396
|
+
tmux send-keys -t "{sessionName}" "claude" C-m
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
- The wrapper for executing tmux commands directly from the API is organized in `src/lib/tmux.ts`.
|
|
400
|
+
|
|
401
|
+
### 6.3 Health Monitoring (Variable Intensity)
|
|
402
|
+
|
|
403
|
+
- Simple implementation: Only check "session existence".
|
|
404
|
+
- For more robustness:
|
|
405
|
+
- `tmux list-panes -F "#{pane_pid}"` → Use `ps` to verify the PID is `claude`.
|
|
406
|
+
- If in prompt state (claude has exited), re-set `CLAUDE_HOOKS_STOP` + restart claude.
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
## 7. Persistence
|
|
411
|
+
|
|
412
|
+
### 7.1 SQLite (db.sqlite)
|
|
413
|
+
|
|
414
|
+
- Storage location example: `~/.mycodebranchdesk/db.sqlite`
|
|
415
|
+
- Tables (conceptual):
|
|
416
|
+
- **worktrees**:
|
|
417
|
+
- id, name, path, last_message_summary, updated_at
|
|
418
|
+
- **cli_tool_id** (added: Issue #4, extended in #379/#545/#988) - CLI tool to use ('claude' | 'codex' | 'gemini' | 'vibe-local' | 'opencode' | 'copilot' | 'antigravity')
|
|
419
|
+
- **selected_agents** (added: Issue #368) - Selected 2-4 agents (JSON array, e.g., '["claude","vibe-local"]')
|
|
420
|
+
- **vibe_local_model** (added: Issue #368) - Ollama model name for Vibe-Local (nullable)
|
|
421
|
+
- repository_path, repository_name, description
|
|
422
|
+
- last_user_message, last_user_message_at
|
|
423
|
+
- favorite, status, link
|
|
424
|
+
- **chat_messages**:
|
|
425
|
+
- id, worktree_id, role, content, summary, timestamp, log_file_name, request_id
|
|
426
|
+
- message_type, prompt_data
|
|
427
|
+
- **session_states**:
|
|
428
|
+
- worktree_id, last_captured_line
|
|
429
|
+
|
|
430
|
+
### 7.2 Markdown Logs (.claude_logs/)
|
|
431
|
+
|
|
432
|
+
- A `.claude_logs/` directory is created directly under each worktree directory.
|
|
433
|
+
- File naming convention:
|
|
434
|
+
|
|
435
|
+
`{YYYYMMDD}-{HHmmss}-{worktreeId}-{uuid}.md`
|
|
436
|
+
|
|
437
|
+
- Content example:
|
|
438
|
+
```markdown
|
|
439
|
+
# CommandMate Log
|
|
440
|
+
|
|
441
|
+
## Worktree
|
|
442
|
+
feature/foo
|
|
443
|
+
|
|
444
|
+
## Timestamp
|
|
445
|
+
2025-11-16T03:00:00Z
|
|
446
|
+
|
|
447
|
+
## User
|
|
448
|
+
|
|
449
|
+
<User's prompt>
|
|
450
|
+
|
|
451
|
+
## Claude
|
|
452
|
+
|
|
453
|
+
<Claude's full response>
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
- Deletion policy:
|
|
457
|
+
- v1 does not perform automatic deletion; future cleanup via CLI is under consideration.
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## 8. Configuration
|
|
462
|
+
|
|
463
|
+
### 8.1 Environment Variables (Planned)
|
|
464
|
+
|
|
465
|
+
- `MCBD_ROOT_DIR` (required)
|
|
466
|
+
- Root directory for git worktree management
|
|
467
|
+
- `MCBD_PORT` (optional, default: 3000)
|
|
468
|
+
- `MCBD_BIND` (optional, default: 127.0.0.1)
|
|
469
|
+
- Potentially added in the future:
|
|
470
|
+
- `MCBD_DB_PATH` (storage location for db.sqlite)
|
|
471
|
+
- `MCBD_LOG_LEVEL` (log output level)
|
|
472
|
+
|
|
473
|
+
A `.env.example` file is expected to be included in the repository.
|
|
474
|
+
|
|
475
|
+
---
|
|
476
|
+
|
|
477
|
+
## 9. Security Model
|
|
478
|
+
|
|
479
|
+
### 9.1 Local Mode
|
|
480
|
+
|
|
481
|
+
- Default is `MCBD_BIND=127.0.0.1`
|
|
482
|
+
- Access is limited to the same machine.
|
|
483
|
+
- Security risk is essentially dependent on the OS user.
|
|
484
|
+
|
|
485
|
+
### 9.2 LAN Access Mode
|
|
486
|
+
|
|
487
|
+
- When `CM_BIND=0.0.0.0`, access from any device on the same LAN is possible
|
|
488
|
+
- Reverse proxy authentication (Nginx / Caddy, etc.) is recommended (details: `docs/security-guide.md`)
|
|
489
|
+
- HTTPS / TLS termination is delegated to the reverse proxy
|
|
490
|
+
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## 10. Extensibility & Future Work
|
|
494
|
+
|
|
495
|
+
### 10.1 Stop Hook Extension
|
|
496
|
+
|
|
497
|
+
- Future design allows including `requestId` in the Stop hook payload:
|
|
498
|
+
|
|
499
|
+
```json
|
|
500
|
+
{ "worktreeId": "{worktreeId}", "requestId": "{requestId}" }
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
- By embedding it in `ChatMessage.requestId` and log names, you can more precisely trace "which request this response belongs to."
|
|
504
|
+
|
|
505
|
+
### 10.2 Multi-LLM / Multi-Session ✅ Implemented (Issue #4, extended in #368/#379/#545)
|
|
506
|
+
|
|
507
|
+
**Implementation:**
|
|
508
|
+
- Supports 7 tools: Claude Code / Codex / Gemini / Vibe-Local / OpenCode / GitHub Copilot / Antigravity
|
|
509
|
+
- Each worktree manages its CLI tool via the `cliToolId` field
|
|
510
|
+
- Abstraction via Strategy pattern:
|
|
511
|
+
- `BaseCLITool` abstract class
|
|
512
|
+
- `ClaudeTool` / `CodexTool` / `GeminiTool` / `VibeLocalTool` / `OpenCodeTool` / `CopilotTool` / `AntigravityTool` implementation classes
|
|
513
|
+
- `CLIToolManager` singleton for managing tool instances
|
|
514
|
+
- Database schema: `worktrees.cli_tool_id` column (default: 'claude')
|
|
515
|
+
- Supported APIs:
|
|
516
|
+
- `POST /api/worktrees/:id/send` - Send message
|
|
517
|
+
- `POST /api/worktrees/:id/respond` - Respond to prompt
|
|
518
|
+
- `POST /api/worktrees/:id/kill-session` - Kill session
|
|
519
|
+
- `GET /api/worktrees` - List worktrees (including session state)
|
|
520
|
+
|
|
521
|
+
**Future Extensions:**
|
|
522
|
+
- To add other CLIs, implement by extending `BaseCLITool`
|
|
523
|
+
- If Stop hook specifications differ, handle within each tool class
|
|
524
|
+
|
|
525
|
+
### 10.3 Real-Time Status Detection ✅ Implemented (Issue #31)
|
|
526
|
+
|
|
527
|
+
**Implementation:**
|
|
528
|
+
- Real-time detection of CLI tool state by directly parsing terminal output
|
|
529
|
+
- Visual status indicators displayed in the sidebar
|
|
530
|
+
- Polling updates every 2 seconds
|
|
531
|
+
|
|
532
|
+
**Status Types:**
|
|
533
|
+
|
|
534
|
+
| Status | Display | Detection Condition |
|
|
535
|
+
|--------|---------|---------------------|
|
|
536
|
+
| `idle` | Gray ● | Session not started |
|
|
537
|
+
| `ready` | Green ● | Input prompt `❯` displayed |
|
|
538
|
+
| `running` | Blue spinner | Thinking indicator detected |
|
|
539
|
+
| `waiting` | Yellow ● | Interactive prompt detected |
|
|
540
|
+
|
|
541
|
+
**Detection Logic:**
|
|
542
|
+
1. Capture terminal output via `captureSessionOutput()`
|
|
543
|
+
2. Strip ANSI escape codes
|
|
544
|
+
3. Filter empty lines and extract the last 15 lines
|
|
545
|
+
4. Pattern match in priority order:
|
|
546
|
+
- Interactive prompt → `waiting`
|
|
547
|
+
- Thinking indicator (`✻ Thinking…`) → `running`
|
|
548
|
+
- Input prompt (`❯`) → `ready`
|
|
549
|
+
- Otherwise → `running` (assumed processing)
|
|
550
|
+
|
|
551
|
+
**Related Files:**
|
|
552
|
+
- `src/config/status-colors.ts` - Centralized status color management
|
|
553
|
+
- `src/lib/cli-patterns.ts` - CLI tool-specific pattern definitions
|
|
554
|
+
- `src/lib/prompt-detector.ts` - Prompt detection
|
|
555
|
+
- `src/types/sidebar.ts` - Status determination logic
|
|
556
|
+
|
|
557
|
+
For details, see [Status Indicator](./features/sidebar-status-indicator.md).
|
|
558
|
+
|
|
559
|
+
### 10.4 Repository Deletion ✅ Implemented (Issue #69)
|
|
560
|
+
|
|
561
|
+
**Implementation:**
|
|
562
|
+
- API endpoint and UI for deleting registered repositories
|
|
563
|
+
- Batch cleanup of related worktrees, sessions, and pollers
|
|
564
|
+
- Centralized session stop processing via Facade pattern
|
|
565
|
+
|
|
566
|
+
**API:**
|
|
567
|
+
- `DELETE /api/repositories` - Delete repository (specify `repositoryPath` in request body)
|
|
568
|
+
|
|
569
|
+
**Request/Response:**
|
|
570
|
+
```json
|
|
571
|
+
// Request
|
|
572
|
+
{ "repositoryPath": "/path/to/repository" }
|
|
573
|
+
|
|
574
|
+
// Response (200 OK)
|
|
575
|
+
{
|
|
576
|
+
"success": true,
|
|
577
|
+
"deletedWorktreeCount": 3,
|
|
578
|
+
"warnings": []
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
**Error Responses:**
|
|
583
|
+
|
|
584
|
+
| Status | Condition |
|
|
585
|
+
|--------|-----------|
|
|
586
|
+
| 400 | `repositoryPath` not specified |
|
|
587
|
+
| 404 | Repository does not exist |
|
|
588
|
+
|
|
589
|
+
**Deletion Flow:**
|
|
590
|
+
1. Get all worktree IDs belonging to the repository
|
|
591
|
+
2. Kill tmux sessions for each worktree (if kill fails, record in warnings and continue)
|
|
592
|
+
3. Stop response-pollers
|
|
593
|
+
4. Clean up WebSocket subscription state
|
|
594
|
+
5. CASCADE delete worktree records from DB
|
|
595
|
+
6. Broadcast `repository_deleted` event
|
|
596
|
+
|
|
597
|
+
**Gradual Error Handling:**
|
|
598
|
+
- DB deletion continues even when session kill fails
|
|
599
|
+
- Failure information is returned in the `warnings` array
|
|
600
|
+
|
|
601
|
+
**UI Implementation:**
|
|
602
|
+
- Delete button (×) appears on hover over repository filter chips
|
|
603
|
+
- Confirmation dialog requires typing "delete"
|
|
604
|
+
- Warning icon (⚠️) displayed for repositories set via `WORKTREE_REPOS` environment variable
|
|
605
|
+
|
|
606
|
+
**Related Files:**
|
|
607
|
+
- `src/lib/session-cleanup.ts` - Session/poller stop Facade
|
|
608
|
+
- `src/app/api/repositories/route.ts` - DELETE endpoint
|
|
609
|
+
- `src/lib/db.ts` - `getWorktreeIdsByRepository()`, `deleteRepositoryWorktrees()`
|
|
610
|
+
- `src/lib/ws-server.ts` - `cleanupRooms()`
|
|
611
|
+
|
|
612
|
+
### 10.5 Observability
|
|
613
|
+
|
|
614
|
+
- For the future:
|
|
615
|
+
- Response time (latency) measurement
|
|
616
|
+
- Error rates
|
|
617
|
+
- Per-session history metrics
|
|
618
|
+
- Extension fields in ChatMessage and Worktree for metadata to enable visualization.
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
## 11. UI Layout Architecture (PC, Issue #727 / #730 / #747)
|
|
623
|
+
|
|
624
|
+
> **Note**: The legacy desktop left-pane model (history / files / memo, MobileTabBar) introduced in #600 has been replaced by the ActivityBar model described in this chapter. Reorganizing the older descriptions is out of scope here.
|
|
625
|
+
|
|
626
|
+
This chapter covers the **responsibility boundaries, state ownership, and data flow** of the top-level PC UI layout (why the structure exists and who owns which state). Visual layout, interactions (keyboard / Tooltip), and the component catalog are owned by [./UI_UX_GUIDE.md](./UI_UX_GUIDE.md) as the single source of truth and are not duplicated here.
|
|
627
|
+
|
|
628
|
+
### 11.1 Component Responsibilities and State Ownership
|
|
629
|
+
|
|
630
|
+
- **ActivityBar** (`src/components/worktree/ActivityBar.tsx`): A fully controlled component that **does not own** the activity-selection state. It receives `active` / `onToggle` as props and renders `ACTIVITIES` from `@/config/activity-bar-config` (the 6 activities: Files / Git / Notes / Schedules / Agent / Timer). The one exception is the sidebar toggle at the top (Issue #747), which reads `{ isOpen, toggle }` directly from `useSidebarContext()` and is placed outside the `role="tablist"` so it does not interfere with tab keyboard navigation.
|
|
631
|
+
- **ActivityPane** (`ActivityPane.tsx`): A stateless, table-driven dispatcher. It picks exactly one node — `activities[active]` — from the parent-built `ActivityContentMap` (`Partial<Record<ActivityId, ReactNode>>`) and renders it through an `ErrorBoundary`. Because a single `active` key resolves to a single node, **rendering multiple activities simultaneously is structurally impossible**.
|
|
632
|
+
- **TerminalContainer** (`TerminalContainer.tsx`, Issue #730): Wraps a `terminal` slot (always rendered) and an optional `history` slot. Since Issue #744, the top-level History column is no longer rendered on PC; History was moved inside each terminal split (see §12). The `history` prop and the `useHistoryPaneState` wiring are kept for backward compatibility with the #730 single-column layout.
|
|
633
|
+
- **WorktreeDesktopLayout** (`WorktreeDesktopLayout.tsx`, Issue #730): A **2-column layout** of ActivityPane and the Right pane. Issue #730 simplified it from 4 columns to 2 (History moved into the TerminalContainer in the Right pane, and the ActivityBar moved to full-height rendering in the parent). When `activityPane === null`, both the activity column and its boundary PaneResizer are hidden.
|
|
634
|
+
- **PaneResizer** (`PaneResizer.tsx`): A generic resizer that owns only transient drag state. It **only reports a pixel delta via `onResize(delta)`**; the parent decides the final pane width. It is reused for both the Activity↔Right boundary in WorktreeDesktopLayout and the History↔Terminal boundary in TerminalContainer.
|
|
635
|
+
|
|
636
|
+
### 11.2 State Owners (Custom Hooks)
|
|
637
|
+
|
|
638
|
+
- **useActivityBarState** (`src/hooks/useActivityBarState.ts`): The single source of truth for the `active` state. It persists to `commandmate.worktree.activeActivity`, but the **closed state (null) is intentionally not persisted** (only the last selected activity is stored so it reopens on revisit). On invalid/missing values it falls back to `DEFAULT_ACTIVITY = 'files'`; the initial render is deterministically `DEFAULT_ACTIVITY` and the localStorage read happens in a post-mount `useEffect` (to avoid hydration mismatch).
|
|
639
|
+
- **SidebarContext** (`src/contexts/SidebarContext.tsx`): Owns the sidebar `isOpen` via `useReducer`. The ActivityBar hamburger (Issue #747) reads this context directly, forming a separate data-flow path from the props-based activity selection.
|
|
640
|
+
|
|
641
|
+
The orchestrator (`WorktreeDetailRefactored.tsx`) calls `useActivityBarState`, builds the `ActivityContentMap`, and wires ActivityBar / ActivityPane / WorktreeDesktopLayout together.
|
|
642
|
+
|
|
643
|
+
### 11.3 Data-Flow Diagram
|
|
644
|
+
|
|
645
|
+
```mermaid
|
|
646
|
+
graph TD
|
|
647
|
+
Parent["WorktreeDetailRefactored<br/>(orchestrator)"]
|
|
648
|
+
ActState["useActivityBarState<br/>(owns active / localStorage)"]
|
|
649
|
+
SideCtx["SidebarContext<br/>(owns isOpen)"]
|
|
650
|
+
Bar["ActivityBar<br/>(stateless)"]
|
|
651
|
+
Pane["ActivityPane<br/>(table-driven dispatch)"]
|
|
652
|
+
Layout["WorktreeDesktopLayout<br/>(2 columns + PaneResizer)"]
|
|
653
|
+
Term["TerminalContainer<br/>(terminal + optional history)"]
|
|
654
|
+
|
|
655
|
+
ActState -->|active| Parent
|
|
656
|
+
Parent -->|onToggle| ActState
|
|
657
|
+
Parent -->|active / onToggle| Bar
|
|
658
|
+
Bar -->|"sidebar toggle (Issue #747)"| SideCtx
|
|
659
|
+
Parent -->|"activityPane (nullable)"| Layout
|
|
660
|
+
Parent -->|"ActivityContentMap"| Pane
|
|
661
|
+
Pane --> Layout
|
|
662
|
+
Layout -->|rightPane| Term
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
> **Forward reference**: The per-agent (per-CLI) session status indicator is already implemented in Issue #743 / #749 / #751 (per-split header status and the DesktopHeader agent status row). It is out of scope for this chapter and may be documented later (optional).
|
|
666
|
+
|
|
667
|
+
---
|
|
668
|
+
|
|
669
|
+
## 12. TerminalSplits Strategy (PC, Issue #728 / #736 / #744)
|
|
670
|
+
|
|
671
|
+
This chapter covers the PC terminal's 1–3 splits and the per-(worktreeId, cliToolId) fan-out polling strategy that runs independently per split.
|
|
672
|
+
|
|
673
|
+
### 12.1 Split State Management (useTerminalSplits)
|
|
674
|
+
|
|
675
|
+
- The state owner is `src/hooks/useTerminalSplits.ts` (Issue #728). It is **intentionally kept out of** the VS Code-style layout reducer (activityBar / historyPane, etc.) to avoid action bloat.
|
|
676
|
+
- Constants (`src/config/terminal-split-config.ts`): `MIN_SPLITS = 1`, `MAX_SPLITS = 3`, `DEFAULT_SPLIT_CONFIG = { splits: [{ cliToolId: 'claude' }], widths: [1] }`.
|
|
677
|
+
- Persistence is **per worktree** (splits + widths are stored in localStorage under `getTerminalSplitsStorageKey(worktreeId)`). On a worktreeId change the state is reloaded and `focusedSplitIndex` is reset to 0.
|
|
678
|
+
- On load, the config is validated by `isValidSplitConfig` (`splits.length ∈ [1, 3]`, `widths.length === splits.length`, each width finite and positive); on failure it falls back to `DEFAULT_SPLIT_CONFIG` (defense against external edits / stale data).
|
|
679
|
+
- **Same-CLI duplicate-selection guard**: `setSplitCliTool` rejects the change if another split already uses that CLI, and `availableCliTools(idx)` returns a list excluding in-use CLIs (the UI `<select>` disables those options). Because the number of CLI types (6) exceeds `MAX_SPLITS` (3), `addSplit`'s unused-CLI assignment never runs out.
|
|
680
|
+
|
|
681
|
+
### 12.2 per-(worktreeId, cliToolId) Fan-out Polling (useTerminalPanePolling)
|
|
682
|
+
|
|
683
|
+
- Each `TerminalSplitPaneContent` owns one instance of `src/hooks/useTerminalPanePolling.ts` and calls `GET /api/worktrees/{worktreeId}/current-output?cliTool={cliToolId}` **independently** (split 0 = Claude and split 1 = Codex poll on their own).
|
|
684
|
+
- Owned state: `output` / `isRunning` / `isThinking` / `isSelectionListActive` / `attaching` (true until the first successful fetch) / `autoScroll` (per pane) / prompt. Auto-Yes state and History messages are global at activeCliTab scope, so they are **intentionally not owned** here.
|
|
685
|
+
- **Stale-response discard (2 axes)**: a `requestId` incremented on every fetch, and an `inFlightCliToolRef` that records the current CLI on every render, are compared at response time; any response that does not match (out-of-order or CLI-switch crossing) is discarded. A response whose server-provided `cliToolId` differs from the requested CLI is also discarded.
|
|
686
|
+
- The polling cadence switches on `isRunning` (`ACTIVE_POLLING_INTERVAL_MS = 2000` / `IDLE_POLLING_INTERVAL_MS = 5000`). Ticks where `document.visibilityState === 'hidden'` are skipped, and a single re-fetch runs when visibility is restored (polling stops in the background).
|
|
687
|
+
- On a change of `compositeKey = {worktreeId}::{cliToolId}`, `requestId` is bumped, output / prompt are cleared, and the pane returns to the `attaching` state (treated as a fresh attach).
|
|
688
|
+
|
|
689
|
+
### 12.3 per-split Message History and Namespace Separation
|
|
690
|
+
|
|
691
|
+
- **useSplitMessages** (`src/hooks/useSplitMessages.ts`, Issue #744): Each split independently fetches `GET /api/worktrees/{worktreeId}/messages?cliTool={cliToolId}` (`SPLIT_MESSAGES_POLL_INTERVAL_MS = 5000`). The parent's `state.messages` is already filtered to activeCliTab, so it cannot be reused to show split A=Claude and split B=Codex at the same time. The stale-guard is identical in form to useTerminalPanePolling.
|
|
692
|
+
- **makeHistoryNamespace** (`src/lib/terminal-highlight.ts`, Issue #744): `CSS.highlights` is a global Map keyed by name, so multiple HistoryPanes using the same namespace (`HISTORY_SEARCH_NAMESPACE`) would clobber each other's search highlights. `makeHistoryNamespace(splitIndex)` returns a namespace suffixed by the split index (`history-search-{idx}`, etc.) so each split keeps its highlights under a distinct registry key, avoiding collisions. `applyHistoryHighlights` and friends default to the shared namespace when the `namespace` argument is omitted, so Mobile / single-pane calls are unchanged (backward compatible).
|
|
693
|
+
|
|
694
|
+
### 12.4 Difference from the Mobile Path
|
|
695
|
+
|
|
696
|
+
- On Mobile, `MobileTerminalTab` owns a **single instance** of `useTerminalPanePolling` and mounts it only while the terminal tab is shown (polling only the one CLI corresponding to activeCliTab).
|
|
697
|
+
- Issue #736 removed the terminal reducer slice, so both PC and Mobile obtain output from `useTerminalPanePolling`. The difference is that PC starts up to `MAX_SPLITS` (3) instances **in parallel**, one per split.
|
|
698
|
+
|
|
699
|
+
### 12.5 Data-Flow Diagram
|
|
700
|
+
|
|
701
|
+
```mermaid
|
|
702
|
+
graph TD
|
|
703
|
+
Splits["useTerminalSplits<br/>(owns splits / widths / focusedSplitIndex)"]
|
|
704
|
+
Container["TerminalSplitContainer<br/>(delegates each split via renderPane)"]
|
|
705
|
+
P0["TerminalSplitPaneContent[0]<br/>cliTool=claude"]
|
|
706
|
+
P1["TerminalSplitPaneContent[1]<br/>cliTool=codex"]
|
|
707
|
+
Poll0["useTerminalPanePolling"]
|
|
708
|
+
Msg0["useSplitMessages"]
|
|
709
|
+
Poll1["useTerminalPanePolling"]
|
|
710
|
+
API0["/current-output?cliTool=claude"]
|
|
711
|
+
API0b["/messages?cliTool=claude"]
|
|
712
|
+
API1["/current-output?cliTool=codex"]
|
|
713
|
+
|
|
714
|
+
Splits --> Container
|
|
715
|
+
Container --> P0
|
|
716
|
+
Container --> P1
|
|
717
|
+
P0 --> Poll0 --> API0
|
|
718
|
+
P0 --> Msg0 --> API0b
|
|
719
|
+
P1 --> Poll1 --> API1
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
> **Note**: The History pane's visibility / width is shared across all splits via `useHistoryPaneState` in the MVP (per-split independent toggle / width is a future extension).
|