commandmate 0.42.2 → 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 +176 -176
- package/.next/app-path-routes-manifest.json +34 -34
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +15 -15
- 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 +1 -1
- package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route.js.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 +103 -1
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +2 -2
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route.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 +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route.js +1 -1
- package/.next/server/app/api/relays/route.js.nft.json +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route.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 +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 +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 +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 +3 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route.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 +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 +3 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route.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 +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.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 +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route.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 -103
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +3 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +3 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route.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 -103
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +103 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/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 +9 -9
- 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 +34 -34
- package/.next/server/chunks/1068.js +1 -1
- package/.next/server/chunks/1210.js +1 -1
- package/.next/server/chunks/1501.js +3 -3
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/22.js +1 -1
- package/.next/server/chunks/2283.js +15 -0
- package/.next/server/chunks/2328.js +1 -1
- package/.next/server/chunks/2404.js +4 -3
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/252.js +1 -1
- package/.next/server/chunks/2816.js +1 -1
- package/.next/server/chunks/3543.js +1 -1
- package/.next/server/chunks/3730.js +1 -1
- package/.next/server/chunks/3945.js +1 -1
- package/.next/server/chunks/4207.js +3 -3
- package/.next/server/chunks/4802.js +1 -1
- package/.next/server/chunks/488.js +1 -0
- package/.next/server/chunks/5064.js +1 -1
- package/.next/server/chunks/5326.js +1 -1
- package/.next/server/chunks/5456.js +1 -1
- package/.next/server/chunks/5571.js +1 -1
- package/.next/server/chunks/5775.js +1 -1
- package/.next/server/chunks/611.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6285.js +1 -1
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6474.js +14 -0
- package/.next/server/chunks/650.js +1 -1
- package/.next/server/chunks/6661.js +1 -1
- package/.next/server/chunks/6781.js +1 -1
- package/.next/server/chunks/6793.js +1 -1
- package/.next/server/chunks/6927.js +1 -0
- package/.next/server/chunks/7491.js +3 -0
- package/.next/server/chunks/7506.js +1 -1
- package/.next/server/chunks/7685.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 +2 -2
- 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/8800.js +4 -3
- package/.next/server/chunks/8918.js +108 -6
- package/.next/server/chunks/9130.js +3 -3
- package/.next/server/chunks/{8052.js → 9353.js} +4 -2
- package/.next/server/chunks/9390.js +3 -0
- package/.next/server/chunks/9627.js +3 -3
- package/.next/server/chunks/967.js +1 -0
- package/.next/server/chunks/9731.js +3 -3
- package/.next/server/chunks/9882.js +3 -3
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/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/2053-85a974ddfe7498fe.js +1 -0
- package/.next/static/chunks/{2407-6b9e12c099fa598c.js → 2407-340774f1a24f2b45.js} +1 -1
- package/.next/static/chunks/5449-6cb80bab2bd06b79.js +1 -0
- package/.next/static/chunks/5521-c358c31f60e5e689.js +1 -0
- package/.next/static/chunks/591-0a45801e83f26f24.js +1 -0
- package/.next/static/chunks/8165-3853772f6ae1299b.js +1 -0
- 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-5b95e1236dcd9ef6.js → layout-0fc249fb7de75a27.js} +1 -1
- package/.next/static/chunks/app/review/page-ff9efae3f86eb840.js +1 -0
- package/.next/static/chunks/app/sessions/page-55297155e7bf01b9.js +1 -0
- package/.next/static/chunks/app/skills/[skillId]/page-9ee7a381636e60cb.js +1 -0
- package/.next/static/chunks/app/skills/page-182e16168b2fc098.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-d2103e0c25be83c8.js +1 -0
- package/.next/static/css/38070d879efa1371.css +1 -0
- package/.next/trace +13 -13
- package/README.md +58 -620
- package/dist/cli/commands/ask.d.ts.map +1 -1
- package/dist/cli/commands/ask.js +23 -149
- 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/reply.d.ts +40 -0
- package/dist/cli/commands/reply.d.ts.map +1 -0
- package/dist/cli/commands/reply.js +133 -0
- package/dist/cli/commands/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/commands/wait.d.ts +5 -0
- package/dist/cli/commands/wait.d.ts.map +1 -1
- package/dist/cli/commands/wait.js +10 -1
- package/dist/cli/docs/agent-operations.d.ts +2 -2
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +13 -0
- package/dist/cli/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/program.d.ts.map +1 -1
- package/dist/cli/program.js +4 -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/reply-ledger.d.ts +95 -0
- package/dist/cli/utils/reply-ledger.d.ts.map +1 -0
- package/dist/cli/utils/reply-ledger.js +187 -0
- package/dist/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/cli-tools/copilot-executable.d.ts +9 -0
- package/dist/lib/cli-tools/copilot-executable.d.ts.map +1 -1
- package/dist/lib/cli-tools/copilot-executable.js +21 -5
- package/dist/lib/cli-tools/opencode-executable.d.ts +103 -0
- package/dist/lib/cli-tools/opencode-executable.d.ts.map +1 -0
- package/dist/lib/cli-tools/opencode-executable.js +179 -0
- package/dist/lib/cli-tools/types.d.ts +1 -1
- package/dist/lib/cli-tools/types.d.ts.map +1 -1
- package/dist/lib/cli-tools/types.js +5 -1
- package/dist/lib/detection/tools/verified-against.d.ts +15 -0
- package/dist/lib/detection/tools/verified-against.d.ts.map +1 -1
- package/dist/lib/detection/tools/verified-against.js +17 -1
- package/dist/lib/detection/version-probes.d.ts.map +1 -1
- package/dist/lib/detection/version-probes.js +14 -1
- package/dist/lib/security/pairing-code.d.ts +2 -1
- package/dist/lib/security/pairing-code.d.ts.map +1 -1
- package/dist/lib/session/tmux-session-surface.d.ts.map +1 -1
- package/dist/lib/session/tmux-session-surface.js +1 -1
- package/dist/server/locales/en/worktree.json +72 -20
- package/dist/server/locales/ja/worktree.json +72 -20
- package/dist/server/server.js +23 -0
- package/dist/server/src/config/cli-tool-timing-config.js +19 -1
- package/dist/server/src/config/detection-evidence-config.js +3 -0
- package/dist/server/src/config/image-extensions.js +1 -0
- package/dist/server/src/config/schedule-config.js +55 -1
- package/dist/server/src/lib/auto-yes-poller.js +69 -4
- package/dist/server/src/lib/cli-tools/agent-mode-spec.js +54 -2
- package/dist/server/src/lib/cli-tools/base.js +6 -2
- package/dist/server/src/lib/cli-tools/command-code-plan-review.js +175 -0
- package/dist/server/src/lib/cli-tools/command-code.js +81 -2
- package/dist/server/src/lib/cli-tools/composer-spec.js +10 -0
- package/dist/server/src/lib/cli-tools/copilot-executable.js +21 -5
- package/dist/server/src/lib/cli-tools/graceful-exit.js +15 -1
- package/dist/server/src/lib/cli-tools/index.js +3 -1
- package/dist/server/src/lib/cli-tools/install-hints.js +9 -3
- package/dist/server/src/lib/cli-tools/liveness-spec.js +19 -0
- package/dist/server/src/lib/cli-tools/manager.js +2 -0
- package/dist/server/src/lib/cli-tools/opencode-executable.js +179 -0
- package/dist/server/src/lib/cli-tools/opencode-v2.js +369 -0
- package/dist/server/src/lib/cli-tools/opencode.js +29 -5
- package/dist/server/src/lib/cli-tools/types.js +5 -1
- package/dist/server/src/lib/cmate-cli-tool-parser.js +65 -7
- package/dist/server/src/lib/cmate-parser.js +12 -0
- package/dist/server/src/lib/cmate-validator.js +13 -1
- package/dist/server/src/lib/detection/cli-patterns.js +172 -3
- package/dist/server/src/lib/detection/model-info-extractor.js +79 -7
- package/dist/server/src/lib/detection/status-detector.js +10 -1
- package/dist/server/src/lib/detection/tools/codex/cli-patterns.js +2 -1
- package/dist/server/src/lib/detection/tools/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/detection/tools/opencode-v2/detect.js +253 -0
- package/dist/server/src/lib/detection/tools/opencode-v2/dialog-title.js +48 -0
- package/dist/server/src/lib/detection/tools/registry.js +2 -0
- package/dist/server/src/lib/detection/tools/run-detection.js +9 -0
- package/dist/server/src/lib/detection/tools/verified-against.js +17 -1
- package/dist/server/src/lib/detection/upstream-faults.js +8 -0
- package/dist/server/src/lib/detection/version-probes.js +14 -1
- package/dist/server/src/lib/hooks/agent-session-telemetry.js +36 -1
- package/dist/server/src/lib/hooks/sources/claude/transcript.js +33 -1
- package/dist/server/src/lib/hooks/sources/opencode/log-diagnosis.js +105 -0
- package/dist/server/src/lib/hooks/sources/opencode/source.js +7 -1
- package/dist/server/src/lib/hooks/sources/opencode-v2/client.js +422 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/decision-labels.js +24 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/history.js +421 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/ingest.js +271 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/mappers.js +165 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/payloads.js +351 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/ports.js +230 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/reattach.js +149 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/runtime.js +180 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/secrets.js +182 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/source.js +295 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/subscription.js +455 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/tool-id.js +18 -0
- package/dist/server/src/lib/hooks/sources/opencode-v2/usage.js +214 -0
- package/dist/server/src/lib/hooks/sources/registry.js +2 -0
- package/dist/server/src/lib/hooks/structured-decision-response.js +14 -5
- package/dist/server/src/lib/job-executor.js +2 -1
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +15 -1
- package/dist/server/src/lib/polling/structured-history-gate.js +19 -5
- package/dist/server/src/lib/relay/relay-delivery.js +4 -1
- package/dist/server/src/lib/session/agent-event-state.js +24 -0
- package/dist/server/src/lib/session/claude-executor.js +186 -12
- package/dist/server/src/lib/session/claude-session.js +131 -15
- package/dist/server/src/lib/session/current-output-builder.js +27 -3
- package/dist/server/src/lib/session/send-user-message.js +4 -0
- package/dist/server/src/lib/session/session-start-error.js +20 -0
- package/dist/server/src/lib/session/structured-prompt.js +54 -0
- package/dist/server/src/lib/session/tmux-session-surface.js +1 -1
- package/dist/server/src/lib/skills/agent-state-paths.js +39 -0
- package/dist/server/src/lib/skills/compatibility-matrix.js +65 -0
- package/dist/server/src/lib/skills/receipt-owned-paths.js +118 -0
- package/dist/server/src/lib/tmux/tmux.js +73 -2
- package/dist/server/src/lib/verification/env-clean-gate.js +281 -10
- package/dist/server/src/lib/verification/gate-runner.js +29 -2
- package/dist/server/src/lib/verification/scope-gate.js +58 -4
- package/dist/server/src/types/cli-tool-contracts.js +10 -2
- package/dist/types/cli-tool-contracts.d.ts +16 -5
- package/dist/types/cli-tool-contracts.d.ts.map +1 -1
- package/dist/types/cli-tool-contracts.js +10 -2
- package/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 +19 -7
- package/release-notes/0.43.0.json +130 -0
- package/release-notes/0.44.0.json +82 -0
- package/scripts/hooks/cmate-agent-event.sh +14 -0
- package/scripts/opencode-v2/launch.sh +226 -0
- package/.next/server/chunks/1990.js +0 -103
- package/.next/server/chunks/3707.js +0 -15
- package/.next/server/chunks/4443.js +0 -3
- package/.next/server/chunks/5164.js +0 -1
- package/.next/server/chunks/5742.js +0 -1
- 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/5449-550bd273dccc3ae4.js +0 -1
- package/.next/static/chunks/7705-2a2936551b0cf9a3.js +0 -1
- package/.next/static/chunks/8165-934ee7ff3b4ddfd4.js +0 -1
- package/.next/static/chunks/app/review/page-30616daa1dc595c2.js +0 -1
- package/.next/static/chunks/app/sessions/page-1a8ba152bbcb9efb.js +0 -1
- package/.next/static/chunks/app/skills/[skillId]/page-ab7e432b69fccb3b.js +0 -1
- package/.next/static/chunks/app/skills/page-56b4fa11223e0cbd.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-59f5337e031518c6.js +0 -1
- package/.next/static/css/b3f433d52b8ed5c8.css +0 -1
- /package/.next/static/{MXZXkcFAnpELZnxxHB4iJ → wu7SUiHTirFcrpo5teyZ3}/_buildManifest.js +0 -0
- /package/.next/static/{MXZXkcFAnpELZnxxHB4iJ → wu7SUiHTirFcrpo5teyZ3}/_ssgManifest.js +0 -0
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Manages Claude CLI sessions within tmux for each worktree
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.CLAUDE_PROMPT_POLL_INTERVAL = exports.CLAUDE_SEND_PROMPT_WAIT_TIMEOUT = exports.CLAUDE_PROMPT_WAIT_TIMEOUT = exports.CLAUDE_POST_PROMPT_DELAY = exports.CLAUDE_INIT_POLL_INTERVAL = exports.CLAUDE_INIT_TIMEOUT = void 0;
|
|
7
|
+
exports.CLAUDE_PROMPT_POLL_INTERVAL = exports.CLAUDE_SEND_PROMPT_WAIT_TIMEOUT = exports.CLAUDE_PROMPT_WAIT_TIMEOUT = exports.CLAUDE_TRUST_DIALOG_EXITED = exports.CLAUDE_TRUST_DIALOG_CURSOR_STUCK = exports.CLAUDE_POST_PROMPT_DELAY = exports.CLAUDE_INIT_POLL_INTERVAL = exports.CLAUDE_INIT_TIMEOUT = void 0;
|
|
8
8
|
exports.clearCachedClaudePath = clearCachedClaudePath;
|
|
9
9
|
exports.isSessionHealthy = isSessionHealthy;
|
|
10
10
|
exports.getSessionName = getSessionName;
|
|
@@ -130,6 +130,122 @@ exports.CLAUDE_INIT_POLL_INTERVAL = 300;
|
|
|
130
130
|
* @see Issue #152 - First message not being sent after session start
|
|
131
131
|
*/
|
|
132
132
|
exports.CLAUDE_POST_PROMPT_DELAY = 500;
|
|
133
|
+
/**
|
|
134
|
+
* Polls (of CLAUDE_INIT_POLL_INTERVAL) a still-open trust dialog is given to
|
|
135
|
+
* close after being answered before it is answered again (Issue #3078). The
|
|
136
|
+
* measured close is ~950 ms (Issue #1637), so 10 polls = 3 s is not a race.
|
|
137
|
+
*/
|
|
138
|
+
const TRUST_DIALOG_REANSWER_POLLS = 10;
|
|
139
|
+
/** Upper bound on trust dialog answers per session start (Issue #3078). */
|
|
140
|
+
const TRUST_DIALOG_MAX_ANSWERS = 3;
|
|
141
|
+
/**
|
|
142
|
+
* Polls a cursor move is given to show up on screen before the next one is
|
|
143
|
+
* sent (Issue #3089). 3 polls = ~900 ms: a TUI that is not taking keys yet
|
|
144
|
+
* swallows the move, and the next one goes in once the screen still shows the
|
|
145
|
+
* cursor off `Yes`.
|
|
146
|
+
*/
|
|
147
|
+
const TRUST_DIALOG_MOVE_SETTLE_POLLS = 3;
|
|
148
|
+
/**
|
|
149
|
+
* Upper bound on single cursor moves per session start (Issue #3089). 20 moves
|
|
150
|
+
* at TRUST_DIALOG_MOVE_SETTLE_POLLS apart is ~18 s of a TUI that will not move its
|
|
151
|
+
* cursor; past that the start fails without ever pressing Enter.
|
|
152
|
+
*/
|
|
153
|
+
const TRUST_DIALOG_MAX_MOVES = 20;
|
|
154
|
+
/** Reported when the cursor never reached `Yes` (Issue #3089). A fixed string, never captured output. */
|
|
155
|
+
exports.CLAUDE_TRUST_DIALOG_CURSOR_STUCK = 'trust dialog: cursor did not reach "Yes, I trust this folder"';
|
|
156
|
+
/** Reported when Claude Code quit from the trust dialog (Issue #3089). A fixed string, never captured output. */
|
|
157
|
+
exports.CLAUDE_TRUST_DIALOG_EXITED = 'trust dialog: Claude Code exited to the shell';
|
|
158
|
+
/**
|
|
159
|
+
* One poll's answer to the folder-trust dialog (Issue #201 / #3078 / #3089).
|
|
160
|
+
*
|
|
161
|
+
* Enter confirms whichever option the cursor is on, and since 2.1.259 that is
|
|
162
|
+
* `No, exit` by default (which quits Claude Code). So Enter is sent only when
|
|
163
|
+
* THIS screen shows the cursor on `Yes, I trust this folder`. Otherwise one
|
|
164
|
+
* move key goes in, and the screen is read again on a later poll: sending
|
|
165
|
+
* `Down Enter` together lost the `Down` to a TUI that was not taking keys yet
|
|
166
|
+
* and confirmed `No, exit` (Issue #3089). Both are bounded: Enter is repeated
|
|
167
|
+
* TRUST_DIALOG_REANSWER_POLLS apart up to TRUST_DIALOG_MAX_ANSWERS times for a
|
|
168
|
+
* dialog that outlives it, and a cursor that has not reached Yes after
|
|
169
|
+
* TRUST_DIALOG_MAX_MOVES moves fails the start without Enter.
|
|
170
|
+
*
|
|
171
|
+
* @param sessionName - tmux session name
|
|
172
|
+
* @param dialogScreen - ANSI-stripped pane output when the dialog is open, else null
|
|
173
|
+
* @param state - Mutated in place
|
|
174
|
+
* @throws {SessionStartFailedError} When the move budget is spent
|
|
175
|
+
*/
|
|
176
|
+
async function answerTrustDialog(sessionName, dialogScreen, state) {
|
|
177
|
+
if (state.pollsSinceAnswer !== null)
|
|
178
|
+
state.pollsSinceAnswer++;
|
|
179
|
+
if (state.pollsSinceMove !== null)
|
|
180
|
+
state.pollsSinceMove++;
|
|
181
|
+
if (dialogScreen === null)
|
|
182
|
+
return;
|
|
183
|
+
if (!state.seen) {
|
|
184
|
+
state.seen = true;
|
|
185
|
+
state.shellTellsExit = await paneCommandIsAgent(sessionName);
|
|
186
|
+
}
|
|
187
|
+
const keys = (0, cli_patterns_1.resolveClaudeTrustDialogKeys)(dialogScreen);
|
|
188
|
+
if (keys === null)
|
|
189
|
+
return;
|
|
190
|
+
if (keys.length === 1) {
|
|
191
|
+
// Cursor on Yes, on this very screen: the Issue #201 Enter.
|
|
192
|
+
const due = state.pollsSinceAnswer === null ||
|
|
193
|
+
(state.pollsSinceAnswer >= TRUST_DIALOG_REANSWER_POLLS && state.answers < TRUST_DIALOG_MAX_ANSWERS);
|
|
194
|
+
if (!due)
|
|
195
|
+
return;
|
|
196
|
+
try {
|
|
197
|
+
await (0, tmux_1.sendKeys)(sessionName, '', true);
|
|
198
|
+
state.pollsSinceAnswer = 0;
|
|
199
|
+
state.answers++;
|
|
200
|
+
logger.info('trust-dialog-detected', { keys: 'Enter', attempt: state.answers });
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Left unhandled so a later poll answers the dialog again
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
// Cursor off Yes: one move, then look again before anything else.
|
|
208
|
+
if (state.pollsSinceMove !== null && state.pollsSinceMove < TRUST_DIALOG_MOVE_SETTLE_POLLS)
|
|
209
|
+
return;
|
|
210
|
+
if (state.moves >= TRUST_DIALOG_MAX_MOVES) {
|
|
211
|
+
throw new session_start_error_1.SessionStartFailedError('Claude Code', sessionName, exports.CLAUDE_TRUST_DIALOG_CURSOR_STUCK);
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
await (0, tmux_1.sendSpecialKeys)(sessionName, [keys[0]]);
|
|
215
|
+
state.pollsSinceMove = 0;
|
|
216
|
+
state.moves++;
|
|
217
|
+
logger.info('trust-dialog-cursor-move', { key: keys[0], attempt: state.moves });
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
// Left unhandled so a later poll moves the cursor again
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Whether the pane's foreground process is a shell again (Issue #3089). A
|
|
225
|
+
* pane tmux cannot describe is not called exited; the start budget still
|
|
226
|
+
* bounds that case. Only asked when {@link TrustDialogState.shellTellsExit}.
|
|
227
|
+
*
|
|
228
|
+
* @param sessionName - tmux session name
|
|
229
|
+
*/
|
|
230
|
+
async function hasReturnedToShell(sessionName) {
|
|
231
|
+
const command = await readPaneCommand(sessionName);
|
|
232
|
+
return command !== null && (0, cli_patterns_1.isShellPaneCommand)(command);
|
|
233
|
+
}
|
|
234
|
+
/** Whether the pane's foreground command is known and is not a shell (Issue #3089). */
|
|
235
|
+
async function paneCommandIsAgent(sessionName) {
|
|
236
|
+
const command = await readPaneCommand(sessionName);
|
|
237
|
+
return command !== null && !(0, cli_patterns_1.isShellPaneCommand)(command);
|
|
238
|
+
}
|
|
239
|
+
/** `#{pane_current_command}`, or null when it cannot be read. */
|
|
240
|
+
async function readPaneCommand(sessionName) {
|
|
241
|
+
try {
|
|
242
|
+
const command = await (0, tmux_1.getPaneCurrentCommand)(sessionName);
|
|
243
|
+
return typeof command === 'string' ? command : null;
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
133
249
|
/**
|
|
134
250
|
* Prompt wait timeout before message send (milliseconds)
|
|
135
251
|
*
|
|
@@ -565,7 +681,8 @@ async function startClaudeSession(options) {
|
|
|
565
681
|
const pollInterval = exports.CLAUDE_INIT_POLL_INTERVAL;
|
|
566
682
|
const startTime = Date.now();
|
|
567
683
|
let initialized = false;
|
|
568
|
-
|
|
684
|
+
// Issue #3078 / #3089: the trust dialog's progress this start.
|
|
685
|
+
const trust = { pollsSinceAnswer: null, pollsSinceMove: null, answers: 0, moves: 0, seen: false, shellTellsExit: false };
|
|
569
686
|
while (Date.now() - startTime < maxWaitTime) {
|
|
570
687
|
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
571
688
|
// SF-001: Use getCleanPaneOutput helper (DRY)
|
|
@@ -579,28 +696,27 @@ async function startClaudeSession(options) {
|
|
|
579
696
|
if (cleanOutput === null) {
|
|
580
697
|
continue;
|
|
581
698
|
}
|
|
699
|
+
// Issue #201 / #3078 / #3089: answer the folder-trust dialog. Checked
|
|
700
|
+
// BEFORE the prompt: the dialog's cursor row (`❯ No, exit`) wears the
|
|
701
|
+
// prompt glyph, so an open dialog is never read as a ready prompt.
|
|
702
|
+
const trustDialogOpen = (0, cli_patterns_1.isClaudeTrustDialogOpen)(cleanOutput);
|
|
703
|
+
await answerTrustDialog(sessionName, trustDialogOpen ? cleanOutput : null, trust);
|
|
582
704
|
// Claude is ready when we see the prompt (DRY-001)
|
|
583
705
|
// Use CLAUDE_PROMPT_PATTERN from cli-patterns.ts for consistency
|
|
584
706
|
// Note: CLAUDE_SEPARATOR_PATTERN was removed from initialization check (Issue #187, P1-1)
|
|
585
|
-
if (cli_patterns_1.CLAUDE_PROMPT_PATTERN.test(cleanOutput)) {
|
|
707
|
+
if (!trustDialogOpen && cli_patterns_1.CLAUDE_PROMPT_PATTERN.test(cleanOutput)) {
|
|
586
708
|
// Wait for stability after prompt detection (CONS-007, DOC-001)
|
|
587
709
|
await new Promise((resolve) => setTimeout(resolve, exports.CLAUDE_POST_PROMPT_DELAY));
|
|
588
710
|
logger.info('claude-initialized-in');
|
|
589
711
|
initialized = true;
|
|
590
712
|
break;
|
|
591
713
|
}
|
|
592
|
-
// Issue #
|
|
593
|
-
//
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
logger.info('trust-dialog-detected');
|
|
599
|
-
}
|
|
600
|
-
catch {
|
|
601
|
-
// Left unhandled so the next poll answers the dialog again
|
|
602
|
-
}
|
|
603
|
-
// Continue polling to wait for prompt detection
|
|
714
|
+
// Issue #3089: the dialog is gone and no prompt came up. If the pane is
|
|
715
|
+
// back at its shell, Claude Code quit (an Enter that landed on
|
|
716
|
+
// `No, exit`); nothing will ever draw a prompt, so fail now instead of
|
|
717
|
+
// spending the rest of the budget (and answering the shell).
|
|
718
|
+
if (!trustDialogOpen && trust.shellTellsExit && (await hasReturnedToShell(sessionName))) {
|
|
719
|
+
throw new session_start_error_1.SessionStartFailedError('Claude Code', sessionName, exports.CLAUDE_TRUST_DIALOG_EXITED);
|
|
604
720
|
}
|
|
605
721
|
// Issue #1637: fail fast on a start that cannot succeed. The budget is
|
|
606
722
|
// 60s of patience for a *slow* start; a session already showing a
|
|
@@ -301,6 +301,9 @@ function summarizeAskUserQuestion(episode) {
|
|
|
301
301
|
question: first.question,
|
|
302
302
|
labels: first.choices.map((choice) => choice.label),
|
|
303
303
|
questionCount: episode.spec.questions.length,
|
|
304
|
+
// Issue #2951: a question that takes a typed answer, so the panel and the
|
|
305
|
+
// phone sheet can offer an input for it.
|
|
306
|
+
...(first.custom ? { custom: true } : {}),
|
|
304
307
|
};
|
|
305
308
|
}
|
|
306
309
|
/**
|
|
@@ -999,7 +1002,10 @@ async function buildPayload(db, worktreeId, cliToolId, instanceId) {
|
|
|
999
1002
|
// same way `structuredEvents.pendingDecisions[].kind` is, through the one
|
|
1000
1003
|
// reader in `pending-decision-kind`.
|
|
1001
1004
|
const addressesQuestion = promptWaiting !== null && (0, pending_decision_kind_1.pendingDecisionKind)(promptWaiting.toolName) === 'question';
|
|
1002
|
-
const decisionOptions = addressableDecisionId !== null && !addressesQuestion
|
|
1005
|
+
const decisionOptions = addressableDecisionId !== null && !addressesQuestion
|
|
1006
|
+
? // Issue #2951: in the tool's own words (OpenCode V2: `Always allow`).
|
|
1007
|
+
(0, structured_prompt_1.structuredDecisionOptionsFor)(cliToolId)
|
|
1008
|
+
: null;
|
|
1003
1009
|
const structuredFacts = promptWaiting === null
|
|
1004
1010
|
? null
|
|
1005
1011
|
: {
|
|
@@ -1096,7 +1102,16 @@ async function buildPayload(db, worktreeId, cliToolId, instanceId) {
|
|
|
1096
1102
|
// an unclassified frame, and writing a "detection failed" row for a turn the
|
|
1097
1103
|
// agent itself told us had ended would put a false stall into the audit trail
|
|
1098
1104
|
// `capture --prompts` prints.
|
|
1099
|
-
|
|
1105
|
+
//
|
|
1106
|
+
// Issue #2965: not while the agent holds a decision this server can answer by
|
|
1107
|
+
// id (OpenCode V2 / opencode approvals and questions). The frame may still be
|
|
1108
|
+
// one the scraper cannot read, but "nothing could answer it" is false then,
|
|
1109
|
+
// and the row landed in the chat as a meaningless assistant line. Fed to the
|
|
1110
|
+
// tracker as "not unclassified" rather than merely not written, so the run —
|
|
1111
|
+
// and the 60 seconds — start afresh if the frame is still unreadable once the
|
|
1112
|
+
// decision is gone (answered, expired, or the source dropped).
|
|
1113
|
+
const answerableOverAgentApi = (0, structured_prompt_1.hasApiAnswerableDecision)(eventSource.capabilities.eventIdentity, structuredEvents.pendingDecisions ?? []);
|
|
1114
|
+
const unclassifiedVerdict = (0, unclassified_frame_tracker_1.observeUnclassifiedFrame)(compositeKey, merged.isUnclassifiedActive && !answerableOverAgentApi);
|
|
1100
1115
|
if (unclassifiedVerdict.shouldRecord) {
|
|
1101
1116
|
recordUnclassifiedFrame(db, {
|
|
1102
1117
|
worktreeId,
|
|
@@ -1136,7 +1151,16 @@ async function buildPayload(db, worktreeId, cliToolId, instanceId) {
|
|
|
1136
1151
|
}
|
|
1137
1152
|
// Issue #1725: the structured layer saw a dialog the scraper did not. That
|
|
1138
1153
|
// gap is the fact worth keeping — see recordStructuredPrompt.
|
|
1139
|
-
|
|
1154
|
+
//
|
|
1155
|
+
// Issue #2965: except while that dialog can be answered over the agent's API
|
|
1156
|
+
// — the live payload already carries its id and replies, so the row says
|
|
1157
|
+
// nothing true. Not marked recorded either: should the decision expire with
|
|
1158
|
+
// the dialog still open, the row is written then (the safe side).
|
|
1159
|
+
if (promptWaiting !== null &&
|
|
1160
|
+
structuredFacts !== null &&
|
|
1161
|
+
!scraperPromptWaiting &&
|
|
1162
|
+
!promptWaiting.recorded &&
|
|
1163
|
+
!answerableOverAgentApi) {
|
|
1140
1164
|
(0, agent_event_state_1.markStructuredPromptRecorded)(worktreeId, cliToolId, instanceId);
|
|
1141
1165
|
recordStructuredPrompt(db, {
|
|
1142
1166
|
worktreeId,
|
|
@@ -47,6 +47,7 @@ const logger_1 = require("../../lib/logger");
|
|
|
47
47
|
const worktree_session_ownership_1 = require("../../lib/cli-tools/worktree-session-ownership");
|
|
48
48
|
const session_name_1 = require("../../lib/cli-tools/session-name");
|
|
49
49
|
const prompt_waiting_guard_1 = require("../../lib/session/prompt-waiting-guard");
|
|
50
|
+
const session_start_error_1 = require("../../lib/session/session-start-error");
|
|
50
51
|
const opencode_1 = require("../../lib/cli-tools/opencode");
|
|
51
52
|
const logger = (0, logger_1.createLogger)('session/send-user-message');
|
|
52
53
|
function getErrorMessage(error) {
|
|
@@ -313,6 +314,9 @@ async function sendUserMessage(db, params) {
|
|
|
313
314
|
}
|
|
314
315
|
catch (error) {
|
|
315
316
|
logger.error('failed-to-send-message-to:', { error: getErrorMessage(error) });
|
|
317
|
+
if ((0, session_start_error_1.isSessionStartTimeoutError)(error)) {
|
|
318
|
+
return { ok: false, stage: 'send', error: error.message, code: session_start_error_1.SESSION_STARTING_CODE };
|
|
319
|
+
}
|
|
316
320
|
return { ok: false, stage: 'send', error: getErrorMessage(error) };
|
|
317
321
|
}
|
|
318
322
|
// 5. Create user message in database (History source: chat_messages).
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
32
32
|
exports.SessionStartUnavailableError = exports.SessionStartFailedError = exports.SessionStartTimeoutError = exports.SESSION_START_UNAVAILABLE_CODE = exports.SESSION_START_FAILED_CODE = exports.SESSION_STARTING_CODE = void 0;
|
|
33
|
+
exports.buildSessionExitedToShellMessage = buildSessionExitedToShellMessage;
|
|
33
34
|
exports.isSessionStartTimeoutError = isSessionStartTimeoutError;
|
|
34
35
|
exports.isSafeSessionStartError = isSafeSessionStartError;
|
|
35
36
|
exports.isSessionStartUnavailableError = isSessionStartUnavailableError;
|
|
@@ -81,6 +82,25 @@ class SessionStartTimeoutError extends Error {
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
exports.SessionStartTimeoutError = SessionStartTimeoutError;
|
|
85
|
+
/**
|
|
86
|
+
* The message for a start timeout whose pane is back at a shell (Issue #3093).
|
|
87
|
+
*
|
|
88
|
+
* {@link SessionStartTimeoutError} says "the process is still running, so this
|
|
89
|
+
* is a slow start … nothing needs repairing" — true for a slow cold start, and
|
|
90
|
+
* exactly wrong when the agent quit during startup (e.g. a trust dialog that
|
|
91
|
+
* was answered with "No, exit"): the reader was told to wait for a process that
|
|
92
|
+
* no longer exists. Built from the tool's display name and the session name
|
|
93
|
+
* only, for the same SEC-SF-002 reason as the classes in this module.
|
|
94
|
+
*
|
|
95
|
+
* @param toolName - Display name of the CLI tool (e.g. `Claude Code`)
|
|
96
|
+
* @param sessionName - tmux session whose pane is back at a shell
|
|
97
|
+
*/
|
|
98
|
+
function buildSessionExitedToShellMessage(toolName, sessionName) {
|
|
99
|
+
return (`${toolName} exited before reaching its input prompt: the tmux session '${sessionName}' ` +
|
|
100
|
+
'is back at a shell, so this is not a slow start and waiting will not help. The message ' +
|
|
101
|
+
'was not delivered. Run `commandmate capture <worktree-id>` to see why it exited (for ' +
|
|
102
|
+
'example a startup dialog answered with exit, or a missing login), fix that, then send again.');
|
|
103
|
+
}
|
|
84
104
|
/**
|
|
85
105
|
* The CLI tool printed an error that startup cannot recover from.
|
|
86
106
|
*
|
|
@@ -35,12 +35,15 @@
|
|
|
35
35
|
*/
|
|
36
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
37
|
exports.MAX_STRUCTURED_PROMPT_MESSAGE_LENGTH = exports.STRUCTURED_DECISION_OPTIONS = void 0;
|
|
38
|
+
exports.structuredDecisionOptionsFor = structuredDecisionOptionsFor;
|
|
38
39
|
exports.isAddressableDecision = isAddressableDecision;
|
|
40
|
+
exports.hasApiAnswerableDecision = hasApiAnswerableDecision;
|
|
39
41
|
exports.buildStructuredPromptQuestion = buildStructuredPromptQuestion;
|
|
40
42
|
exports.buildStructuredPromptData = buildStructuredPromptData;
|
|
41
43
|
exports.buildStructuredPromptHistoryRecord = buildStructuredPromptHistoryRecord;
|
|
42
44
|
exports.isStructuredPromptWaitingData = isStructuredPromptWaitingData;
|
|
43
45
|
const models_1 = require("../../types/models");
|
|
46
|
+
const decision_labels_1 = require("../../lib/hooks/sources/opencode-v2/decision-labels");
|
|
44
47
|
/**
|
|
45
48
|
* The three verdicts an approval dialog accepts, in the order `respond` numbers
|
|
46
49
|
* them (Issue #1898).
|
|
@@ -67,6 +70,32 @@ exports.STRUCTURED_DECISION_OPTIONS = [
|
|
|
67
70
|
// eslint-disable-next-line no-restricted-syntax -- CLI answer vocabulary, not display text
|
|
68
71
|
{ number: 3, label: 'Reject', reply: 'reject' },
|
|
69
72
|
];
|
|
73
|
+
/**
|
|
74
|
+
* A tool's own words for the approval verdicts, keyed by wire reply
|
|
75
|
+
* (Issue #2951). Only tools whose dialog words differ from
|
|
76
|
+
* {@link STRUCTURED_DECISION_OPTIONS} are here: OpenCode V2 draws `Always allow`
|
|
77
|
+
* where v1 draws `Allow always`.
|
|
78
|
+
*/
|
|
79
|
+
const DECISION_LABELS_BY_TOOL = {
|
|
80
|
+
'opencode-v2': decision_labels_1.OPENCODE_V2_DECISION_LABELS,
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* The approval verdicts in the words of the tool that asked (Issue #2951).
|
|
84
|
+
*
|
|
85
|
+
* What `capture --json` publishes as `decisionOptions` and what `respond`
|
|
86
|
+
* matches a label against, so both say what the tool's own dialog says. Only
|
|
87
|
+
* the LABEL differs per tool: the number and the wire reply are the shared
|
|
88
|
+
* list's, so `2` still means `always` everywhere. Every tool without its own
|
|
89
|
+
* words gets {@link STRUCTURED_DECISION_OPTIONS} itself (the same object).
|
|
90
|
+
*
|
|
91
|
+
* @param cliToolId - The tool the approval belongs to
|
|
92
|
+
*/
|
|
93
|
+
function structuredDecisionOptionsFor(cliToolId) {
|
|
94
|
+
const labels = DECISION_LABELS_BY_TOOL[cliToolId];
|
|
95
|
+
if (!labels)
|
|
96
|
+
return exports.STRUCTURED_DECISION_OPTIONS;
|
|
97
|
+
return exports.STRUCTURED_DECISION_OPTIONS.map((option) => labels[option.reply] ? { ...option, label: labels[option.reply] } : option);
|
|
98
|
+
}
|
|
70
99
|
/** Bound on the agent's `message`, which is prose and only ever displayed. */
|
|
71
100
|
exports.MAX_STRUCTURED_PROMPT_MESSAGE_LENGTH = 500;
|
|
72
101
|
/**
|
|
@@ -89,6 +118,31 @@ exports.MAX_STRUCTURED_PROMPT_MESSAGE_LENGTH = 500;
|
|
|
89
118
|
function isAddressableDecision(value) {
|
|
90
119
|
return typeof value === 'string' && value !== '';
|
|
91
120
|
}
|
|
121
|
+
/**
|
|
122
|
+
* Whether the agent is holding a decision this server can answer over the
|
|
123
|
+
* agent's own API right now (Issue #2965).
|
|
124
|
+
*
|
|
125
|
+
* The gate on the two "the detection layer could not read this" rows — the
|
|
126
|
+
* unclassified-frame row and the structured-prompt row
|
|
127
|
+
* ({@link buildStructuredPromptQuestion}). Both exist to record a dialog nobody
|
|
128
|
+
* could answer; while this is true somebody can, by id, and the row is a
|
|
129
|
+
* meaningless line in the chat (OpenCode V2 approvals and questions, #2945;
|
|
130
|
+
* v1 opencode's approvals, which carry the same `permission-id`). All three
|
|
131
|
+
* conjuncts are required, and each failing one puts the row back — the safe
|
|
132
|
+
* side:
|
|
133
|
+
*
|
|
134
|
+
* - the source publishes per-decision ids (`eventIdentity: 'permission-id'`);
|
|
135
|
+
* - a pending decision carries one ({@link isAddressableDecision});
|
|
136
|
+
* - its delivery window has not expired (a verdict can still reach the agent).
|
|
137
|
+
*
|
|
138
|
+
* @param eventIdentity - `capabilities.eventIdentity` of the tool's event source
|
|
139
|
+
* @param pendingDecisions - the decisions the turn is holding, as published
|
|
140
|
+
*/
|
|
141
|
+
function hasApiAnswerableDecision(eventIdentity, pendingDecisions) {
|
|
142
|
+
if (eventIdentity !== 'permission-id')
|
|
143
|
+
return false;
|
|
144
|
+
return pendingDecisions.some((decision) => isAddressableDecision(decision.id) && !decision.deliveryExpired);
|
|
145
|
+
}
|
|
92
146
|
/** How each source reads in the one-line question. */
|
|
93
147
|
const SOURCE_LABEL = {
|
|
94
148
|
notification: 'Notification(permission_prompt)',
|
|
@@ -343,7 +343,7 @@ function isLiveAttachEligibleSession(sessionName) {
|
|
|
343
343
|
* `tests/unit/tmux/session-surface-2317.test.ts`, so a tool moving in or out of
|
|
344
344
|
* the alternate screen breaks a test rather than silently dropping the hint.
|
|
345
345
|
*/
|
|
346
|
-
exports.ALT_SCREEN_TOOLS = ['claude', 'opencode', 'copilot'];
|
|
346
|
+
exports.ALT_SCREEN_TOOLS = ['claude', 'opencode', 'copilot', 'opencode-v2'];
|
|
347
347
|
/** Whether `attach` should warn that a bare attach shows no transcript. */
|
|
348
348
|
function usesAltScreen(cliToolId) {
|
|
349
349
|
return exports.ALT_SCREEN_TOOLS.includes(cliToolId);
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* State files an agent CLI writes into the worktree on its own (Issue #3126)
|
|
4
|
+
*
|
|
5
|
+
* Command Code leaves `.commandcode/settings.local.json` and
|
|
6
|
+
* `.commandcode/taste/**` behind in any folder it runs in. Counted as change,
|
|
7
|
+
* they made a contract's `requireScopeClean` fail on a worktree whose worker
|
|
8
|
+
* stayed inside `allow`, and made `work-evidence` pass on one nobody worked in.
|
|
9
|
+
*
|
|
10
|
+
* Unlike receipt-owned paths (#3092) there is no receipt to vouch for them, so
|
|
11
|
+
* the declaration below is the whole rule, and it names files, never a whole
|
|
12
|
+
* directory: `.commandcode/` also holds things a task may legitimately change,
|
|
13
|
+
* and allowing it wholesale would wave those through. Callers apply this to
|
|
14
|
+
* **untracked** entries only, as for #3092: a committed or tracked-and-modified
|
|
15
|
+
* file is history the branch carries.
|
|
16
|
+
*
|
|
17
|
+
* Only paths whose existence is confirmed are declared. Other agents (claude,
|
|
18
|
+
* codex, ...) are deliberately absent until someone has seen them write one.
|
|
19
|
+
*
|
|
20
|
+
* @module lib/skills/agent-state-paths
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.AGENT_STATE_DIR_PREFIXES = exports.AGENT_STATE_FILES = void 0;
|
|
24
|
+
exports.isAgentStatePath = isAgentStatePath;
|
|
25
|
+
exports.isAgentStateUntrackedEntry = isAgentStateUntrackedEntry;
|
|
26
|
+
/** Exact repository-relative files an agent CLI manages itself. */
|
|
27
|
+
exports.AGENT_STATE_FILES = ['.commandcode/settings.local.json'];
|
|
28
|
+
/** Directory prefixes (with trailing slash) an agent CLI manages itself. */
|
|
29
|
+
exports.AGENT_STATE_DIR_PREFIXES = ['.commandcode/taste/'];
|
|
30
|
+
/** Whether `path` is a declared agent-managed state path. */
|
|
31
|
+
function isAgentStatePath(path) {
|
|
32
|
+
if (exports.AGENT_STATE_FILES.includes(path))
|
|
33
|
+
return true;
|
|
34
|
+
return exports.AGENT_STATE_DIR_PREFIXES.some((prefix) => path.startsWith(prefix) && !path.slice(prefix.length).split('/').includes('..'));
|
|
35
|
+
}
|
|
36
|
+
/** Whether a porcelain record is an untracked file made only of such paths. */
|
|
37
|
+
function isAgentStateUntrackedEntry(entry) {
|
|
38
|
+
return entry.status === '??' && entry.paths.every(isAgentStatePath);
|
|
39
|
+
}
|
|
@@ -81,6 +81,7 @@ const NOT_MEASURED_SKIP_REASON_KEY = 'skills.compatibility.skipReason.notMeasure
|
|
|
81
81
|
exports.AGENT_RELOAD_MESSAGE_KEYS = {
|
|
82
82
|
SESSION_RESTART: 'skills.compatibility.reload.sessionRestart',
|
|
83
83
|
SESSION_RESTART_NO_SLASH: 'skills.compatibility.reload.sessionRestartNoSlash',
|
|
84
|
+
PICKED_UP_LIVE: 'skills.compatibility.reload.pickedUpLive',
|
|
84
85
|
UNKNOWN: 'skills.compatibility.reload.unknown',
|
|
85
86
|
};
|
|
86
87
|
/** Known limitation keys attached to an axis outcome. */
|
|
@@ -113,6 +114,15 @@ const MEASURED_DATE_2026_09_05 = '2026-09-05';
|
|
|
113
114
|
* deliberately *not* recorded as a row — see the `gemini` entry below.
|
|
114
115
|
*/
|
|
115
116
|
const OTHER_AGENTS_EVIDENCE_SOURCE = 'https://github.com/Kewton/CommandMate/blob/main/docs/reference/skill-agent-compatibility.md#9-gemini--copilot-probe-log-issue-2302';
|
|
117
|
+
/**
|
|
118
|
+
* Evidence reference for the OpenCode V2 (opencode2) 2.0.18 measurement
|
|
119
|
+
* (Issue #2975).
|
|
120
|
+
*
|
|
121
|
+
* The reference doc carries the harness, the controls and the raw
|
|
122
|
+
* `GET /api/skill` / message output.
|
|
123
|
+
*/
|
|
124
|
+
const OPENCODE_V2_EVIDENCE_SOURCE = 'https://github.com/Kewton/CommandMate/blob/main/docs/reference/skill-agent-compatibility.md#10-opencode-v2-probe-log-issue-2975';
|
|
125
|
+
const MEASURED_DATE_2026_09_29 = '2026-09-29';
|
|
116
126
|
function unmeasuredEntry(agent) {
|
|
117
127
|
return {
|
|
118
128
|
agent,
|
|
@@ -345,6 +355,61 @@ const AGENT_DISCOVERY_MATRIX = [
|
|
|
345
355
|
reloadKey: exports.AGENT_RELOAD_MESSAGE_KEYS.SESSION_RESTART,
|
|
346
356
|
skipReasonKey: null,
|
|
347
357
|
},
|
|
358
|
+
{
|
|
359
|
+
agent: 'opencode-v2',
|
|
360
|
+
// Issue #2975, opencode2 2.0.18. Measured on its own rather than copied off
|
|
361
|
+
// the v1 row: the values happen to match v1's, but the release, the day and
|
|
362
|
+
// the route that makes invocation work are different.
|
|
363
|
+
//
|
|
364
|
+
// Ten probe Skills were planted, one per candidate root, each told to
|
|
365
|
+
// answer a unique token. `GET /api/skill` returned eight of them with their
|
|
366
|
+
// absolute SKILL.md paths — project `.opencode/skills`, `.opencode/skill`,
|
|
367
|
+
// `.claude/skills`, `.agents/skills`; home `.claude/skills`,
|
|
368
|
+
// `.agents/skills`, `.config/opencode/skills`, `.config/opencode/skill` —
|
|
369
|
+
// and not the two negative controls (`.github/skills`,
|
|
370
|
+
// `$HOME/.opencode/skills`). Both CommandMate install roots are among the
|
|
371
|
+
// eight, and the byte-identical dual-root install is listed once.
|
|
372
|
+
discoveryRoots: [constants_1.SKILL_INSTALL_ROOT_PREFIX, constants_1.SKILL_CLAUDE_INSTALL_ROOT_PREFIX],
|
|
373
|
+
discovery: {
|
|
374
|
+
outcome: 'verified',
|
|
375
|
+
evidenceKind: 'mechanical',
|
|
376
|
+
labelKey: exports.AGENT_AXIS_OUTCOME_LABEL_KEYS.verified,
|
|
377
|
+
evidenceKindKey: exports.AGENT_EVIDENCE_KIND_LABEL_KEYS.mechanical,
|
|
378
|
+
limitationKey: null,
|
|
379
|
+
},
|
|
380
|
+
invocation: {
|
|
381
|
+
// Submitting `/probe-agents-root ` produced a `skill` tool part with
|
|
382
|
+
// `input.id: "probe-agents-root"` and the Skill's absolute directory in
|
|
383
|
+
// its metadata, and the agent answered `PROBE_OK_probe-agents-root`;
|
|
384
|
+
// `.claude/skills` did the same with its own token. Unlike v1 the TUI
|
|
385
|
+
// does not expand the Skill — the user message is the literal
|
|
386
|
+
// `/probe-agents-root ` (a markdown command, by contrast, is replaced by
|
|
387
|
+
// its template) — so it is the model calling the `skill` tool. The tool
|
|
388
|
+
// part is the discriminator, not the token: `/probe-home-dotopencode-root`
|
|
389
|
+
// (never discovered) came back with a *different* Skill's token.
|
|
390
|
+
//
|
|
391
|
+
// The limitation is the same as v1's: typing the name after `/` shows
|
|
392
|
+
// "No matching commands" (positive control `/rev` → `/review`, negative
|
|
393
|
+
// control `/zzzznotacommand` → nothing), and the `ctrl+p` palette has no
|
|
394
|
+
// row for it either. What v2 adds is an `@` completion — `@probe` lists
|
|
395
|
+
// every discovered Skill tagged `skill`, and the `/skills` picker inserts
|
|
396
|
+
// `@name` — so v2 does have its own way in, just not a slash command.
|
|
397
|
+
outcome: 'verified',
|
|
398
|
+
evidenceKind: 'mechanical',
|
|
399
|
+
labelKey: exports.AGENT_AXIS_OUTCOME_LABEL_KEYS.verified,
|
|
400
|
+
evidenceKindKey: exports.AGENT_EVIDENCE_KIND_LABEL_KEYS.mechanical,
|
|
401
|
+
limitationKey: exports.AGENT_LIMITATION_MESSAGE_KEYS.NO_SLASH_COMMAND,
|
|
402
|
+
},
|
|
403
|
+
testedVersion: '2.0.18',
|
|
404
|
+
testedDate: MEASURED_DATE_2026_09_29,
|
|
405
|
+
evidenceSource: OPENCODE_V2_EVIDENCE_SOURCE,
|
|
406
|
+
// Also measured, and the opposite of v1: the server does NOT need a
|
|
407
|
+
// restart. A Skill planted while it ran appeared in `GET /api/skill` within
|
|
408
|
+
// seconds, and one planted into `$HOME/.agents/skills` mid-session was run
|
|
409
|
+
// in that same session — so the guidance is "no new session needed".
|
|
410
|
+
reloadKey: exports.AGENT_RELOAD_MESSAGE_KEYS.PICKED_UP_LIVE,
|
|
411
|
+
skipReasonKey: null,
|
|
412
|
+
},
|
|
348
413
|
];
|
|
349
414
|
/** The measured matrix, in CLI-tool declaration order. */
|
|
350
415
|
function getSkillAgentMatrix() {
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Files CommandMate itself placed into a worktree by installing a Skill (Issue #3092)
|
|
4
|
+
*
|
|
5
|
+
* `skill install` leaves `.agents/skills/<id>/…` and `.claude/skills/<id>/…`
|
|
6
|
+
* untracked. Counted as change, those files made `work-evidence` pass on a
|
|
7
|
+
* worktree nobody had worked in (`uncommitted=74`), and made a contract's
|
|
8
|
+
* `requireScopeClean` fail on a worktree whose agent stayed inside `allow`.
|
|
9
|
+
*
|
|
10
|
+
* The answer is the receipt, and only the receipt. A path is reported as
|
|
11
|
+
* CommandMate-owned when **all** of the following hold, so that nothing the
|
|
12
|
+
* user or the agent wrote can be laundered through it into a false "no work":
|
|
13
|
+
*
|
|
14
|
+
* - a receipt parses at `.agents/skills/<id>/.commandmate-receipt.json`, and
|
|
15
|
+
* its `skill_id` is that directory's name;
|
|
16
|
+
* - the root it names is `<known install prefix>/<skill_id>` — a receipt
|
|
17
|
+
* claiming `src` or `.commandcode` as a root claims nothing;
|
|
18
|
+
* - the file is listed in the receipt's `files`, is a regular file, and its
|
|
19
|
+
* bytes still hash to the recorded `sha256`. A Skill file the agent edited
|
|
20
|
+
* is the agent's change and stays counted;
|
|
21
|
+
* - for the receipt itself in a secondary root: byte-identical to the
|
|
22
|
+
* primary's.
|
|
23
|
+
*
|
|
24
|
+
* Callers apply the result to **untracked** entries only. A committed or
|
|
25
|
+
* tracked-and-modified Skill file is history the branch carries, and judging
|
|
26
|
+
* it is unchanged by this module.
|
|
27
|
+
*
|
|
28
|
+
* @module lib/skills/receipt-owned-paths
|
|
29
|
+
*/
|
|
30
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
31
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
32
|
+
};
|
|
33
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
34
|
+
exports.collectSkillReceiptOwnedPaths = collectSkillReceiptOwnedPaths;
|
|
35
|
+
const crypto_1 = require("crypto");
|
|
36
|
+
const fs_1 = require("fs");
|
|
37
|
+
const path_1 = __importDefault(require("path"));
|
|
38
|
+
const constants_1 = require("../../lib/skills/constants");
|
|
39
|
+
const install_plan_1 = require("../../lib/skills/install-plan");
|
|
40
|
+
function sha256Hex(bytes) {
|
|
41
|
+
return (0, crypto_1.createHash)('sha256').update(bytes).digest('hex');
|
|
42
|
+
}
|
|
43
|
+
/** Read a regular file (never through a link), or null. */
|
|
44
|
+
function readRegularFile(absolute) {
|
|
45
|
+
try {
|
|
46
|
+
if (!(0, fs_1.lstatSync)(absolute).isFile())
|
|
47
|
+
return null;
|
|
48
|
+
return (0, fs_1.readFileSync)(absolute);
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** A receipt-relative payload path that cannot leave its root. */
|
|
55
|
+
function isSafeRelativePath(relative) {
|
|
56
|
+
if (relative === '' || relative.startsWith('/') || relative.includes('\\'))
|
|
57
|
+
return false;
|
|
58
|
+
return relative.split('/').every((segment) => segment !== '' && segment !== '.' && segment !== '..');
|
|
59
|
+
}
|
|
60
|
+
function isValidSkillId(skillId) {
|
|
61
|
+
return constants_1.SKILL_ID_PATTERN.test(skillId) && skillId.length <= constants_1.SKILL_ID_MAX_LENGTH;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Repository-relative POSIX paths of every untouched file a recorded Skill
|
|
65
|
+
* install placed in this worktree, receipts included.
|
|
66
|
+
*
|
|
67
|
+
* Never throws: an unreadable directory or receipt contributes nothing, which
|
|
68
|
+
* leaves those files counted exactly as before #3092.
|
|
69
|
+
*/
|
|
70
|
+
function collectSkillReceiptOwnedPaths(worktreePath) {
|
|
71
|
+
const owned = new Set();
|
|
72
|
+
const primaryAbs = path_1.default.join(worktreePath, constants_1.SKILL_PRIMARY_INSTALL_ROOT_PREFIX);
|
|
73
|
+
let skillDirs;
|
|
74
|
+
try {
|
|
75
|
+
skillDirs = (0, fs_1.readdirSync)(primaryAbs);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return owned;
|
|
79
|
+
}
|
|
80
|
+
for (const skillId of skillDirs) {
|
|
81
|
+
if (!isValidSkillId(skillId))
|
|
82
|
+
continue;
|
|
83
|
+
const primaryRoot = `${constants_1.SKILL_PRIMARY_INSTALL_ROOT_PREFIX}/${skillId}`;
|
|
84
|
+
const receiptBytes = readRegularFile(path_1.default.join(worktreePath, primaryRoot, install_plan_1.SKILL_RECEIPT_FILENAME));
|
|
85
|
+
if (receiptBytes === null)
|
|
86
|
+
continue;
|
|
87
|
+
const receipt = (0, install_plan_1.parseInstalledReceipt)(receiptBytes);
|
|
88
|
+
if (receipt === null || receipt.skill_id !== skillId)
|
|
89
|
+
continue;
|
|
90
|
+
const allowedRoots = new Set(constants_1.SKILL_INSTALL_ROOT_PREFIXES.map((prefix) => `${prefix}/${skillId}`));
|
|
91
|
+
const roots = (0, install_plan_1.receiptInstallRoots)(receipt);
|
|
92
|
+
// The receipt that names the roots must live in the primary one.
|
|
93
|
+
if (roots[0] !== primaryRoot)
|
|
94
|
+
continue;
|
|
95
|
+
for (const root of roots) {
|
|
96
|
+
if (typeof root !== 'string' || !allowedRoots.has(root))
|
|
97
|
+
continue;
|
|
98
|
+
const rootReceipt = readRegularFile(path_1.default.join(worktreePath, root, install_plan_1.SKILL_RECEIPT_FILENAME));
|
|
99
|
+
if (rootReceipt !== null && rootReceipt.equals(receiptBytes)) {
|
|
100
|
+
owned.add(`${root}/${install_plan_1.SKILL_RECEIPT_FILENAME}`);
|
|
101
|
+
}
|
|
102
|
+
for (const file of receipt.files) {
|
|
103
|
+
if (!file ||
|
|
104
|
+
typeof file.path !== 'string' ||
|
|
105
|
+
typeof file.sha256 !== 'string' ||
|
|
106
|
+
!isSafeRelativePath(file.path) ||
|
|
107
|
+
file.path === install_plan_1.SKILL_RECEIPT_FILENAME) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
const bytes = readRegularFile(path_1.default.join(worktreePath, root, file.path));
|
|
111
|
+
if (bytes !== null && sha256Hex(bytes) === file.sha256.toLowerCase()) {
|
|
112
|
+
owned.add(`${root}/${file.path}`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return owned;
|
|
118
|
+
}
|