commandmate 0.37.0 → 0.38.1
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 +33 -33
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +12 -12
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/session/route.js +1 -1
- package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/start/route.js +1 -1
- package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/terminal/route.js +1 -1
- package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route.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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js +1 -1
- package/.next/server/app/api/hooks/claude-done/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js +1 -1
- package/.next/server/app/api/hooks/permission-request/route.js.nft.json +1 -1
- package/.next/server/app/api/hooks/permission-request/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route.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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js +1 -1
- package/.next/server/app/api/repositories/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js +1 -1
- package/.next/server/app/api/repositories/restore/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route.js +1 -1
- package/.next/server/app/api/repositories/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js +1 -1
- package/.next/server/app/api/repositories/scan/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js +1 -1
- package/.next/server/app/api/repositories/sync/route.js.nft.json +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.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]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +4 -3
- 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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -6
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +2 -7
- 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_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.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route.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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/chat/page_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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +11 -9
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +33 -33
- package/.next/server/chunks/1467.js +1 -1
- package/.next/server/chunks/1707.js +1 -1
- package/.next/server/chunks/1886.js +2 -2
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/3480.js +1 -18
- package/.next/server/chunks/3730.js +1 -1
- package/.next/server/chunks/4207.js +5 -0
- package/.next/server/chunks/4443.js +1 -1
- package/.next/server/chunks/5164.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/650.js +1 -1
- package/.next/server/chunks/6661.js +1 -1
- package/.next/server/chunks/6677.js +2 -2
- package/.next/server/chunks/6793.js +13 -0
- package/.next/server/chunks/7075.js +1 -1
- package/.next/server/chunks/8052.js +74 -0
- package/.next/server/chunks/8728.js +2 -2
- package/.next/server/chunks/9080.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{2407-c4b1d2aae7e3f59b.js → 2407-be448eda70bc19b6.js} +1 -1
- package/.next/static/chunks/4388-a778968d9c4e9327.js +1 -0
- package/.next/static/chunks/4949-fa93029d6e05db0d.js +1 -0
- package/.next/static/chunks/998-292ebcd30f329eb1.js +1 -0
- package/.next/static/chunks/app/sessions/page-fe42c8f6fd59b9e7.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-1eb4297af22afac8.js +1 -0
- package/.next/static/css/ed092b853e52b5eb.css +1 -0
- package/.next/trace +14 -14
- package/dist/cli/commands/ls.d.ts +64 -0
- package/dist/cli/commands/ls.d.ts.map +1 -1
- package/dist/cli/commands/ls.js +238 -30
- package/dist/cli/commands/respond.d.ts.map +1 -1
- package/dist/cli/commands/respond.js +14 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +154 -15
- package/dist/cli/docs/agent-operations.d.ts +1 -1
- package/dist/cli/docs/agent-operations.d.ts.map +1 -1
- package/dist/cli/docs/agent-operations.js +37 -1
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/utils/server-url.d.ts +27 -0
- package/dist/cli/utils/server-url.d.ts.map +1 -1
- package/dist/cli/utils/server-url.js +48 -6
- package/dist/lib/cli-tools/types.d.ts +22 -1
- package/dist/lib/cli-tools/types.d.ts.map +1 -1
- package/dist/lib/detection/tools/verified-against.d.ts +8 -0
- package/dist/lib/detection/tools/verified-against.d.ts.map +1 -1
- package/dist/lib/detection/tools/verified-against.js +8 -0
- package/dist/server/locales/en/worktree.json +23 -1
- package/dist/server/locales/ja/worktree.json +23 -1
- package/dist/server/src/lib/cli-tools/agent-mode-spec.js +327 -0
- package/dist/server/src/lib/cli-tools/base.js +22 -0
- package/dist/server/src/lib/cmate-parser.js +26 -6
- package/dist/server/src/lib/cmate-validator.js +354 -0
- package/dist/server/src/lib/detection/cli-patterns.js +40 -2
- package/dist/server/src/lib/detection/model-info-extractor.js +40 -3
- package/dist/server/src/lib/detection/prompt-detect-multiple-choice.js +44 -0
- package/dist/server/src/lib/detection/tools/antigravity/detect.js +9 -0
- package/dist/server/src/lib/detection/tools/command-code/detect.js +14 -3
- package/dist/server/src/lib/detection/tools/command-code/permission.js +104 -0
- package/dist/server/src/lib/detection/tools/verified-against.js +8 -0
- package/dist/server/src/lib/polling/auto-yes-dialog-gate.js +20 -2
- package/dist/server/src/lib/prompt-answer-sender.js +339 -16
- package/dist/server/src/lib/session/claude-executor.js +190 -17
- package/dist/server/src/types/cli-tool-contracts.js +75 -1
- package/dist/types/cli-tool-contracts.d.ts +162 -0
- package/dist/types/cli-tool-contracts.d.ts.map +1 -1
- package/dist/types/cli-tool-contracts.js +75 -1
- package/package.json +1 -1
- package/.next/server/chunks/6337.js +0 -1
- package/.next/server/chunks/663.js +0 -79
- package/.next/static/chunks/4388-410b1d8ed0d8d98b.js +0 -1
- package/.next/static/chunks/4949-5b97d1eb769482d2.js +0 -1
- package/.next/static/chunks/998-ac0ded6d5eeb4dc0.js +0 -1
- package/.next/static/chunks/app/sessions/page-b8651c3f17c36800.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-f993ca88fe758599.js +0 -1
- package/.next/static/css/c511ecdf1e7f18a0.css +0 -1
- /package/.next/static/{0WNCXbrakAsDUEgDarN8N → DryXJ1-iHfWxfrHkkWVy8}/_buildManifest.js +0 -0
- /package/.next/static/{0WNCXbrakAsDUEgDarN8N → DryXJ1-iHfWxfrHkkWVy8}/_ssgManifest.js +0 -0
|
@@ -3,6 +3,70 @@
|
|
|
3
3
|
* Issue #518: [DR1-08] Factory pattern with createLsCommand()
|
|
4
4
|
*/
|
|
5
5
|
import { Command } from 'commander';
|
|
6
|
+
import type { WorktreeItem } from '../types/api-responses';
|
|
7
|
+
/** One entry of the per-CLI-tool status map the list API publishes. */
|
|
8
|
+
export type CliStatusEntry = NonNullable<WorktreeItem['sessionStatusByCli']>[string];
|
|
9
|
+
/**
|
|
10
|
+
* One instance's Auto-Yes arming, as `GET /api/worktrees` sends it (Issue #2512).
|
|
11
|
+
*
|
|
12
|
+
* Mirrors: src/types/auto-yes.ts AutoYesInstanceSummary.
|
|
13
|
+
*
|
|
14
|
+
* A copy rather than an import: `tsconfig.cli.json` sets `"paths": {}`, so
|
|
15
|
+
* nothing under `src/cli` can reach `@/types/auto-yes`. The copy is kept honest
|
|
16
|
+
* by a bidirectional `AssertAssignable` in
|
|
17
|
+
* `tests/unit/cli/commands/ls-auto-yes-2575.test.ts`, which `npx tsc --noEmit`
|
|
18
|
+
* evaluates — the same guard #1843 uses for the suppression-reason union.
|
|
19
|
+
*
|
|
20
|
+
* Only ARMED instances appear in the map: the server folds expired and
|
|
21
|
+
* turned-off states away as it reads them (`getEnabledAutoYesByWorktree`), so a
|
|
22
|
+
* missing key means "not armed right now" and carries no reason. Why it stopped
|
|
23
|
+
* lives in `commandmate capture --json`'s `autoYes.stopReason`.
|
|
24
|
+
*/
|
|
25
|
+
export type AutoYesInstanceWire = {
|
|
26
|
+
enabled: boolean;
|
|
27
|
+
expiresAt: number | null;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* A list row with the two maps this command reads and `WorktreeItem` does not
|
|
31
|
+
* declare (Issue #2575).
|
|
32
|
+
*
|
|
33
|
+
* `src/cli/types/api-responses.ts` declares only the fields the CLI reads, and
|
|
34
|
+
* until this column nothing read either of these. Widened HERE rather than
|
|
35
|
+
* there, on the precedent of `PeerWorktreeItem` in `peers.ts`: the shared mirror
|
|
36
|
+
* keeps meaning what its header says, and a row from a server that predates
|
|
37
|
+
* #2512 (no `autoYesByInstance`) or answered `?includeStatus=0` (no
|
|
38
|
+
* `sessionStatusByInstance`) is still a valid row — hence both optional.
|
|
39
|
+
*
|
|
40
|
+
* `sessionStatusByInstance` is the UN-aggregated map. `sessionStatusByCli` next
|
|
41
|
+
* to it is the logical-OR over every instance of a tool, which is the right
|
|
42
|
+
* input for REASON (#1926) and the wrong one here: Auto-Yes is armed per
|
|
43
|
+
* INSTANCE, so an aggregate cannot say whether it was `claude` or `claude-2`
|
|
44
|
+
* that raised the wait.
|
|
45
|
+
*
|
|
46
|
+
* Exported so tests can assert against the wire shape rather than restate it.
|
|
47
|
+
*/
|
|
48
|
+
export interface LsWorktreeItem extends WorktreeItem {
|
|
49
|
+
autoYesByInstance?: Record<string, AutoYesInstanceWire>;
|
|
50
|
+
sessionStatusByInstance?: Partial<Record<string, CliStatusEntry>>;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `MM:SS`, or `H:MM:SS` from an hour up — the Web UI countdown's format.
|
|
54
|
+
*
|
|
55
|
+
* A second spelling of `formatTimeRemaining` (`src/config/auto-yes-config.ts`)
|
|
56
|
+
* on purpose, and the only duplication Issue #2575 accepts. That module imports
|
|
57
|
+
* `@/config/tmux-pane-config`, and `tsconfig.cli.json` sets `"paths": {}`, so a
|
|
58
|
+
* CLI module importing it compiles under lint / `tsc --noEmit` / vitest (all
|
|
59
|
+
* three resolve `@/`) and breaks only at `npm run build:cli` — a trap worth
|
|
60
|
+
* avoiding rather than walking into. The two are pinned to the same strings at
|
|
61
|
+
* the boundaries by `ls-auto-yes-2575.test.ts`, so an operator reads the same
|
|
62
|
+
* number in the browser and in the terminal.
|
|
63
|
+
*
|
|
64
|
+
* Takes a DURATION, not a deadline: the caller has already resolved `now` once
|
|
65
|
+
* for the whole table, and passing the deadline here would re-read the clock per
|
|
66
|
+
* row. Truncating means 0 < remaining < 1 s prints `00:00`, exactly as the
|
|
67
|
+
* browser countdown does one tick before it flips to OFF.
|
|
68
|
+
*/
|
|
69
|
+
export declare function formatAutoYesRemaining(remainingMs: number): string;
|
|
6
70
|
/**
|
|
7
71
|
* Create the ls command.
|
|
8
72
|
* [DR1-08] Factory pattern for addCommand() registration.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ls.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ls.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EAAwB,YAAY,EAAE,MAAM,wBAAwB,CAAC;AA0BjF,uEAAuE;AACvE,MAAM,MAAM,cAAc,GAAG,WAAW,CAAC,YAAY,CAAC,oBAAoB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAErF;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,mBAAmB,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAEjF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;IACxD,uBAAuB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;CACnE;AAoFD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAUlE;AAoOD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,OAAO,CAkFzC"}
|
package/dist/cli/commands/ls.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Issue #518: [DR1-08] Factory pattern with createLsCommand()
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.formatAutoYesRemaining = formatAutoYesRemaining;
|
|
7
8
|
exports.createLsCommand = createLsCommand;
|
|
8
9
|
const commander_1 = require("commander");
|
|
9
10
|
const api_client_1 = require("../utils/api-client");
|
|
@@ -31,6 +32,32 @@ function deriveStatus(wt) {
|
|
|
31
32
|
return 'ready';
|
|
32
33
|
return 'idle';
|
|
33
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* Whether this status entry is one of the sessions that produced `status`.
|
|
37
|
+
*
|
|
38
|
+
* `deriveStatus` folds every session of the worktree into one word, so any cell
|
|
39
|
+
* that claims to be ABOUT that word has to be sourced from a session that
|
|
40
|
+
* produced it. Two columns need the predicate and must not drift apart: REASON
|
|
41
|
+
* (#1926) applies it per tool, AUTO_YES (#2575) applies it per instance.
|
|
42
|
+
*
|
|
43
|
+
* `idle` is explained by exactly one thing (Issue #2070): `exited`, the tmux
|
|
44
|
+
* session still there with no agent in it. Everything else idle is unexplained
|
|
45
|
+
* — no entry matches, REASON stays `-`, and AUTO_YES falls back to every armed
|
|
46
|
+
* instance.
|
|
47
|
+
*/
|
|
48
|
+
function explainsStatus(entry, status) {
|
|
49
|
+
if (!entry)
|
|
50
|
+
return false;
|
|
51
|
+
if (status === 'waiting')
|
|
52
|
+
return entry.isWaitingForResponse;
|
|
53
|
+
if (status === 'running')
|
|
54
|
+
return entry.isProcessing;
|
|
55
|
+
if (status === 'ready')
|
|
56
|
+
return entry.isRunning;
|
|
57
|
+
if (status === 'idle')
|
|
58
|
+
return entry.sessionStatusReason === status_reason_1.STATUS_REASON.EXITED;
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
34
61
|
/**
|
|
35
62
|
* The per-tool status entry that explains this row's STATUS (Issue #1926).
|
|
36
63
|
*
|
|
@@ -48,28 +75,10 @@ function pickStatusEntry(wt, status) {
|
|
|
48
75
|
const byCli = wt.sessionStatusByCli;
|
|
49
76
|
if (!byCli)
|
|
50
77
|
return undefined;
|
|
51
|
-
const explains = (entry) => {
|
|
52
|
-
if (!entry)
|
|
53
|
-
return false;
|
|
54
|
-
if (status === 'waiting')
|
|
55
|
-
return entry.isWaitingForResponse;
|
|
56
|
-
if (status === 'running')
|
|
57
|
-
return entry.isProcessing;
|
|
58
|
-
if (status === 'ready')
|
|
59
|
-
return entry.isRunning;
|
|
60
|
-
// Issue #2070: `idle` gets an explanation for the first time, and only for
|
|
61
|
-
// the one reason a stopped session can carry — `exited`. Everything else
|
|
62
|
-
// about an idle row is unchanged: no entry is picked, so the REASON cell is
|
|
63
|
-
// still `-`. That is what makes this additive rather than a fourth branch of
|
|
64
|
-
// `deriveStatus` (DR3-005 keeps the STATUS vocabulary at four words).
|
|
65
|
-
if (status === 'idle')
|
|
66
|
-
return entry.sessionStatusReason === status_reason_1.STATUS_REASON.EXITED;
|
|
67
|
-
return false;
|
|
68
|
-
};
|
|
69
78
|
const preferred = wt.cliToolId ? byCli[wt.cliToolId] : undefined;
|
|
70
|
-
if (
|
|
79
|
+
if (explainsStatus(preferred, status))
|
|
71
80
|
return preferred;
|
|
72
|
-
return Object.values(byCli).find(
|
|
81
|
+
return Object.values(byCli).find((entry) => explainsStatus(entry, status));
|
|
73
82
|
}
|
|
74
83
|
/**
|
|
75
84
|
* The REASON cell: why the STATUS beside it says what it says (Issue #1926).
|
|
@@ -100,25 +109,180 @@ function deriveReason(wt) {
|
|
|
100
109
|
return '-';
|
|
101
110
|
return entry?.statusEvidence === 'none' ? `${reason} (no evidence)` : reason;
|
|
102
111
|
}
|
|
112
|
+
const MS_PER_SECOND = 1000;
|
|
113
|
+
const MS_PER_MINUTE = 60_000;
|
|
114
|
+
const MS_PER_HOUR = 3_600_000;
|
|
115
|
+
/**
|
|
116
|
+
* `MM:SS`, or `H:MM:SS` from an hour up — the Web UI countdown's format.
|
|
117
|
+
*
|
|
118
|
+
* A second spelling of `formatTimeRemaining` (`src/config/auto-yes-config.ts`)
|
|
119
|
+
* on purpose, and the only duplication Issue #2575 accepts. That module imports
|
|
120
|
+
* `@/config/tmux-pane-config`, and `tsconfig.cli.json` sets `"paths": {}`, so a
|
|
121
|
+
* CLI module importing it compiles under lint / `tsc --noEmit` / vitest (all
|
|
122
|
+
* three resolve `@/`) and breaks only at `npm run build:cli` — a trap worth
|
|
123
|
+
* avoiding rather than walking into. The two are pinned to the same strings at
|
|
124
|
+
* the boundaries by `ls-auto-yes-2575.test.ts`, so an operator reads the same
|
|
125
|
+
* number in the browser and in the terminal.
|
|
126
|
+
*
|
|
127
|
+
* Takes a DURATION, not a deadline: the caller has already resolved `now` once
|
|
128
|
+
* for the whole table, and passing the deadline here would re-read the clock per
|
|
129
|
+
* row. Truncating means 0 < remaining < 1 s prints `00:00`, exactly as the
|
|
130
|
+
* browser countdown does one tick before it flips to OFF.
|
|
131
|
+
*/
|
|
132
|
+
function formatAutoYesRemaining(remainingMs) {
|
|
133
|
+
const remaining = Math.max(0, remainingMs);
|
|
134
|
+
const hours = Math.floor(remaining / MS_PER_HOUR);
|
|
135
|
+
const minutes = Math.floor((remaining % MS_PER_HOUR) / MS_PER_MINUTE);
|
|
136
|
+
const seconds = Math.floor((remaining % MS_PER_MINUTE) / MS_PER_SECOND);
|
|
137
|
+
if (hours > 0) {
|
|
138
|
+
return `${hours}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
|
139
|
+
}
|
|
140
|
+
return `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Milliseconds of Auto-Yes left on one instance: 0 when it is not armed,
|
|
144
|
+
* Infinity when it is armed with no deadline.
|
|
145
|
+
*
|
|
146
|
+
* Everything that is not positively armed collapses to 0 — no key, `enabled`
|
|
147
|
+
* anything but true, or a deadline already past. A past `expiresAt` reaches us
|
|
148
|
+
* even though the server folds expired states away as it reads them: these are
|
|
149
|
+
* two machines' clocks, and #959's `displayEnabled = enabled && !hasExpired`
|
|
150
|
+
* falls the same way. The direction is the whole point — this cell may under-
|
|
151
|
+
* report arming, never over-report it, because over-reporting hides a prompt
|
|
152
|
+
* that only a human can clear.
|
|
153
|
+
*
|
|
154
|
+
* Infinity is not a shape the current server produces (`AutoYesState.expiresAt`
|
|
155
|
+
* is a number), but an explicit `null` beside `enabled: true` is the server
|
|
156
|
+
* saying armed-with-no-deadline, which is a fact, and the Sessions tile reads
|
|
157
|
+
* the same input as ON. Infinity also makes it lose every `min` against a real
|
|
158
|
+
* deadline, which is what "unknown expiry" should do.
|
|
159
|
+
*
|
|
160
|
+
* `null` EXACTLY, not "anything that is not a number": a row missing the key
|
|
161
|
+
* altogether is malformed rather than eternal, and the rule above decides which
|
|
162
|
+
* way malformed falls — towards `off`.
|
|
163
|
+
*/
|
|
164
|
+
function remainingAutoYesMs(entry, now) {
|
|
165
|
+
if (!entry || entry.enabled !== true)
|
|
166
|
+
return 0;
|
|
167
|
+
if (entry.expiresAt === null)
|
|
168
|
+
return Number.POSITIVE_INFINITY;
|
|
169
|
+
if (typeof entry.expiresAt !== 'number')
|
|
170
|
+
return 0;
|
|
171
|
+
return entry.expiresAt > now ? entry.expiresAt - now : 0;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The AUTO_YES cell: how long before this row loses Auto-Yes (Issue #2575).
|
|
175
|
+
*
|
|
176
|
+
* In one sentence: the remaining time of the instance that will lose Auto-Yes
|
|
177
|
+
* FIRST, among the instances that explain this row's STATUS. One already without
|
|
178
|
+
* it makes the cell `off`.
|
|
179
|
+
*
|
|
180
|
+
* The minimum, rather than the longest or a list, is what closes the gap this
|
|
181
|
+
* Issue is about. On a row where `claude` is waiting unarmed and `codex` is
|
|
182
|
+
* waiting with ten minutes left, printing `10:00` buries a prompt nobody will
|
|
183
|
+
* answer under a countdown that has nothing to do with it; the minimum prints
|
|
184
|
+
* `off`. The cost is accepted and stated in `--help`: one unarmed instance
|
|
185
|
+
* sharing a `ready` row hides the armed one's countdown, which `ls --json` still
|
|
186
|
+
* has in full.
|
|
187
|
+
*
|
|
188
|
+
* `-` means "not known", and is deliberately not `off`:
|
|
189
|
+
* - no `autoYesByInstance` at all — a server older than #2512;
|
|
190
|
+
* - a non-idle row no instance explains. Impossible against the current
|
|
191
|
+
* server, whose row-level flags are the OR of the per-instance ones. It is a
|
|
192
|
+
* guard for the day that stops being true: falling back to "every armed
|
|
193
|
+
* instance" on a `waiting` row would print a countdown beside a prompt no
|
|
194
|
+
* instance is actually going to answer.
|
|
195
|
+
*
|
|
196
|
+
* The fallback to every armed instance is therefore `idle`-only, where nothing
|
|
197
|
+
* is running and there is no session whose wait could be misrepresented. An idle
|
|
198
|
+
* row with an `exited` instance is explained (#2070), so the fallback does not
|
|
199
|
+
* fire there.
|
|
200
|
+
*
|
|
201
|
+
* `status` and `now` are arguments rather than re-derived: `now` is read once
|
|
202
|
+
* per table so two rows cannot disagree about the time, and a test can freeze it.
|
|
203
|
+
*/
|
|
204
|
+
function deriveAutoYesCell(wt, status, now) {
|
|
205
|
+
const armedByInstance = wt.autoYesByInstance;
|
|
206
|
+
if (!armedByInstance)
|
|
207
|
+
return '-';
|
|
208
|
+
const byInstance = wt.sessionStatusByInstance ?? {};
|
|
209
|
+
let targets = Object.keys(byInstance).filter(id => explainsStatus(byInstance[id], status));
|
|
210
|
+
if (targets.length === 0) {
|
|
211
|
+
if (status !== 'idle')
|
|
212
|
+
return '-';
|
|
213
|
+
targets = Object.keys(armedByInstance);
|
|
214
|
+
if (targets.length === 0)
|
|
215
|
+
return 'off';
|
|
216
|
+
}
|
|
217
|
+
// Deterministic order first, so the cell never depends on the key order the
|
|
218
|
+
// server happened to serialise: the worktree default's primary, then
|
|
219
|
+
// lexicographic. The first strict minimum in that order wins, which is what
|
|
220
|
+
// makes an equal-remaining tie resolve to the default (printed bare) rather
|
|
221
|
+
// than to whichever instance the JSON listed first.
|
|
222
|
+
const ordered = [...targets].sort((a, b) => {
|
|
223
|
+
if (a === wt.cliToolId)
|
|
224
|
+
return -1;
|
|
225
|
+
if (b === wt.cliToolId)
|
|
226
|
+
return 1;
|
|
227
|
+
return a < b ? -1 : 1;
|
|
228
|
+
});
|
|
229
|
+
let pick = ordered[0];
|
|
230
|
+
let remaining = remainingAutoYesMs(armedByInstance[pick], now);
|
|
231
|
+
for (const id of ordered.slice(1)) {
|
|
232
|
+
const candidate = remainingAutoYesMs(armedByInstance[id], now);
|
|
233
|
+
if (candidate < remaining) {
|
|
234
|
+
pick = id;
|
|
235
|
+
remaining = candidate;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const value = remaining === 0
|
|
239
|
+
? 'off'
|
|
240
|
+
: remaining === Number.POSITIVE_INFINITY
|
|
241
|
+
? 'on'
|
|
242
|
+
: formatAutoYesRemaining(remaining);
|
|
243
|
+
// The instance is named whenever it is not the default agent's primary — the
|
|
244
|
+
// row where a second agent raised the wait is exactly the row where REASON
|
|
245
|
+
// cannot say so (it is a per-tool aggregate and loses the reason for a tool
|
|
246
|
+
// with two instances), so this parenthesis is sometimes the only thing on the
|
|
247
|
+
// line that identifies the session. It is an `--instance` value verbatim.
|
|
248
|
+
return pick === wt.cliToolId ? value : `${value} (${pick})`;
|
|
249
|
+
}
|
|
103
250
|
/**
|
|
104
251
|
* Format worktrees as a table for terminal display.
|
|
105
252
|
*/
|
|
106
253
|
function formatTable(worktrees) {
|
|
107
254
|
if (worktrees.length === 0)
|
|
108
255
|
return 'No worktrees found.';
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
]
|
|
256
|
+
// Once per table, not once per row: two rows must not disagree about what
|
|
257
|
+
// "now" is, and a frozen clock in a test must produce one reading.
|
|
258
|
+
const now = Date.now();
|
|
259
|
+
// Issue #2575 APPENDS. The first five columns keep their order and their
|
|
260
|
+
// starting offsets, because operators (and the orchestrate recipes) read this
|
|
261
|
+
// table positionally — the same rule #1785 / #2038 / #2317 held for
|
|
262
|
+
// `commandmate instances`.
|
|
263
|
+
const headers = ['ID', 'NAME', 'STATUS', 'REASON', 'DEFAULT', 'AUTO_YES'];
|
|
264
|
+
const rows = worktrees.map(wt => {
|
|
265
|
+
const status = deriveStatus(wt);
|
|
266
|
+
return [
|
|
267
|
+
wt.id,
|
|
268
|
+
wt.name,
|
|
269
|
+
status,
|
|
270
|
+
deriveReason(wt),
|
|
271
|
+
wt.cliToolId || '-',
|
|
272
|
+
deriveAutoYesCell(wt, status, now),
|
|
273
|
+
];
|
|
274
|
+
});
|
|
117
275
|
// Calculate column widths
|
|
118
276
|
const colWidths = headers.map((h, i) => Math.max(h.length, ...rows.map(r => r[i].length)));
|
|
119
|
-
|
|
277
|
+
// The LAST column is not padded. An instance id runs to 64 characters, so one
|
|
278
|
+
// row carrying `off (some-very-long-instance-id)` would otherwise pad every
|
|
279
|
+
// other row out to that width and wrap the whole table on a narrow terminal.
|
|
280
|
+
// Before #2575 the last column was DEFAULT and every line did end in padding.
|
|
281
|
+
const lastCol = headers.length - 1;
|
|
282
|
+
const pad = (cell, i) => (i === lastCol ? cell : cell.padEnd(colWidths[i]));
|
|
283
|
+
const headerLine = headers.map(pad).join(' ');
|
|
120
284
|
const separator = colWidths.map(w => '-'.repeat(w)).join(' ');
|
|
121
|
-
const dataLines = rows.map(r => r.map(
|
|
285
|
+
const dataLines = rows.map(r => r.map(pad).join(' '));
|
|
122
286
|
return [headerLine, separator, ...dataLines].join('\n');
|
|
123
287
|
}
|
|
124
288
|
/**
|
|
@@ -165,6 +329,14 @@ function deriveTmuxSession(wt) {
|
|
|
165
329
|
* `WorktreeItem`, would need the same tool-picking rule the REASON column
|
|
166
330
|
* applies for display, and would make `ls --json` disagree with
|
|
167
331
|
* `GET /api/worktrees` — three costs for a shorter jq path.
|
|
332
|
+
*
|
|
333
|
+
* Issue #2575 adds a table column and nothing here, for the same reason plus
|
|
334
|
+
* one: the derived cell would be the LEAST accurate answer a machine can get.
|
|
335
|
+
* `autoYesByInstance` and `sessionStatusByInstance` are already in these rows
|
|
336
|
+
* verbatim, and a caller that needs "will anything answer this prompt" wants
|
|
337
|
+
* `commandmate wait`'s exit 10 or `capture --json`'s `autoYes`, both of which
|
|
338
|
+
* know about answers the contract policy withheld. The cell is a summary for a
|
|
339
|
+
* human reading a table.
|
|
168
340
|
*/
|
|
169
341
|
function formatOutput(worktrees, options) {
|
|
170
342
|
if (options.json) {
|
|
@@ -195,6 +367,42 @@ function createLsCommand() {
|
|
|
195
367
|
.option('--branch <prefix>', 'Filter by branch name prefix')
|
|
196
368
|
.option('--id <prefix>', 'Filter by worktree id prefix')
|
|
197
369
|
.option('--token <token>', command_helpers_1.TOKEN_WARNING)
|
|
370
|
+
// Issue #2575: AUTO_YES is a derived cell with rules an operator can be
|
|
371
|
+
// surprised by (a `ready` row can read `off` while an instance is armed),
|
|
372
|
+
// and docs/** is outside this change's scope — so until the guides catch up,
|
|
373
|
+
// this is the only place a shipped build explains the column. Same reason
|
|
374
|
+
// `wait --help` carries the unclassified dwell (#1926).
|
|
375
|
+
.addHelpText('after', `
|
|
376
|
+
AUTO_YES column (Issue #2575):
|
|
377
|
+
How much Auto-Yes is left on the instance that will lose it FIRST, among the
|
|
378
|
+
instances that explain this row's STATUS (waiting: the ones waiting; running:
|
|
379
|
+
the ones processing; ready: the ones running; idle: the ones that exited. A
|
|
380
|
+
bare idle row falls back to every armed instance).
|
|
381
|
+
|
|
382
|
+
MM:SS time left, under an hour
|
|
383
|
+
H:MM:SS time left, an hour or more
|
|
384
|
+
on armed, with no expiry the server named
|
|
385
|
+
off at least one of those instances is NOT armed, so a prompt on this
|
|
386
|
+
row waits for a human. This is the cell to look for
|
|
387
|
+
- not known: the server predates the field, or this row is not idle
|
|
388
|
+
and no instance explains its STATUS
|
|
389
|
+
|
|
390
|
+
A time left is a fact about Auto-Yes, not a promise that the prompt gets
|
|
391
|
+
answered: a contract policy can withhold the answer, and a free-text prompt
|
|
392
|
+
has none to give. \`commandmate capture <id> --json --instance <instanceId>\`
|
|
393
|
+
carries autoYes.lastSuppression (what was withheld) and autoYes.stopReason
|
|
394
|
+
(why it stopped); \`commandmate wait <id>\` returns exit 10 for a prompt no
|
|
395
|
+
agent is going to clear.
|
|
396
|
+
|
|
397
|
+
The id in parentheses is the instance the cell is about, printed when that is
|
|
398
|
+
not the default agent's primary. Pass it to capture / send / respond as
|
|
399
|
+
--instance verbatim. It names an instance for THIS column only: REASON is
|
|
400
|
+
chosen per tool with the worktree default preferred (Issue #1926), so the two
|
|
401
|
+
cells on one row can be about different sessions.
|
|
402
|
+
|
|
403
|
+
Nothing here is derived in --json: it carries sessionStatusByInstance and
|
|
404
|
+
autoYesByInstance raw, which is where the per-instance breakdown is.
|
|
405
|
+
`)
|
|
198
406
|
.action(async (options) => {
|
|
199
407
|
try {
|
|
200
408
|
const client = new api_client_1.ApiClient({ token: options.token });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"respond.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/respond.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2JpC,wBAAgB,oBAAoB,IAAI,OAAO,
|
|
1
|
+
{"version":3,"file":"respond.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/respond.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2JpC,wBAAgB,oBAAoB,IAAI,OAAO,CA4L9C"}
|
|
@@ -226,6 +226,20 @@ function createRespondCommand() {
|
|
|
226
226
|
}
|
|
227
227
|
if (refusedBeforeSending) {
|
|
228
228
|
console.error(`Error: Answer was not sent. Reason: ${reason}${result.message ? ` (${result.message})` : ''}`);
|
|
229
|
+
// Issue #2583: the operator who lands here typed WORDS at a dialog
|
|
230
|
+
// that only takes a choice — a claude / agy Bash approval refused as
|
|
231
|
+
// free text, or #2573's "No, tell … what to do differently" row. The
|
|
232
|
+
// server's sentence ends with "answer with the option number", and
|
|
233
|
+
// this is that command with the ids already filled in, so the next
|
|
234
|
+
// step is a paste rather than a trip to the docs while a dialog sits
|
|
235
|
+
// open. Printed only for the reason that means "this answer could not
|
|
236
|
+
// be mapped onto a choice", and only when the answer was not already
|
|
237
|
+
// a number (where the number itself is what was wrong).
|
|
238
|
+
if (reason === 'unresolvable_answer' && answer !== undefined && !/^\d+$/.test(answer.trim())) {
|
|
239
|
+
const target = options.instance ? ` --instance ${options.instance}` : '';
|
|
240
|
+
console.error(`Hint: answer with the option number — \`commandmate respond ${worktreeId} <number>${target}\` ` +
|
|
241
|
+
`(\`commandmate capture ${worktreeId}${target}\` prints the dialog and its numbers).`);
|
|
242
|
+
}
|
|
229
243
|
}
|
|
230
244
|
else {
|
|
231
245
|
console.error(`Warning: Response may not have been applied. Reason: ${reason}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAA2C,aAAa,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAA2C,aAAa,EAAE,MAAM,UAAU,CAAC;AAwZlF;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkG9E"}
|
|
@@ -13,6 +13,7 @@ const types_1 = require("../types");
|
|
|
13
13
|
const logger_1 = require("../utils/logger");
|
|
14
14
|
const daemon_1 = require("../utils/daemon");
|
|
15
15
|
const env_setup_1 = require("../utils/env-setup");
|
|
16
|
+
const server_url_1 = require("../utils/server-url");
|
|
16
17
|
const package_info_1 = require("../utils/package-info");
|
|
17
18
|
const input_validators_1 = require("../utils/input-validators");
|
|
18
19
|
const version_probes_1 = require("../../lib/detection/version-probes");
|
|
@@ -90,33 +91,166 @@ function printLocalhostConflict(status) {
|
|
|
90
91
|
// Config dir unreadable, record unparsable: report the server, drop the hint.
|
|
91
92
|
}
|
|
92
93
|
}
|
|
94
|
+
/** `src/app/api/push/vapid/route.ts` — public key + a `configured` flag, no secrets. */
|
|
95
|
+
const VAPID_PROBE_PATH = '/api/push/vapid';
|
|
96
|
+
/**
|
|
97
|
+
* Budget for the probe below. A loopback round trip to a healthy server is ~2ms;
|
|
98
|
+
* anything near this bound is a server that cannot answer, and an unanswered
|
|
99
|
+
* probe costs nothing but the fallback.
|
|
100
|
+
*/
|
|
101
|
+
const VAPID_PROBE_TIMEOUT_MS = 1000;
|
|
102
|
+
/**
|
|
103
|
+
* Ask the running server whether it actually holds a VAPID key pair (Issue #2585).
|
|
104
|
+
*
|
|
105
|
+
* The daemon is the only process that can answer: it was handed its environment at
|
|
106
|
+
* launch and has held it ever since, while every reader in this CLI is reconstructing
|
|
107
|
+
* that environment from the outside. `GET /api/push/vapid` already exists for the web
|
|
108
|
+
* client and returns `{configured, publicKey}` — the public key only, so this adds no
|
|
109
|
+
* exposure that the browser did not already have.
|
|
110
|
+
*
|
|
111
|
+
* @returns The server's verdict, or `null` when it did not give one — unreachable,
|
|
112
|
+
* unauthenticated, answered by something that is not this server (#2113), or not
|
|
113
|
+
* JSON. Every one of those is "I do not know", never "not configured": inventing a
|
|
114
|
+
* warning out of a failed probe is how a diagnostic starts lying.
|
|
115
|
+
*/
|
|
116
|
+
async function probeServerVapid(baseUrl) {
|
|
117
|
+
const controller = new AbortController();
|
|
118
|
+
const timer = setTimeout(() => controller.abort(), VAPID_PROBE_TIMEOUT_MS);
|
|
119
|
+
try {
|
|
120
|
+
// The one `process.env` read this path keeps, and deliberately: a token is a fact
|
|
121
|
+
// about THIS invocation (the caller's credential), not about the daemon's
|
|
122
|
+
// configuration. Without it an authenticated server answers 302 to /login, which
|
|
123
|
+
// `redirect: 'manual'` keeps visible instead of following it to an HTML 200.
|
|
124
|
+
const token = process.env.CM_AUTH_TOKEN;
|
|
125
|
+
const response = await fetch(`${baseUrl}${VAPID_PROBE_PATH}`, {
|
|
126
|
+
method: 'GET',
|
|
127
|
+
headers: {
|
|
128
|
+
Accept: 'application/json',
|
|
129
|
+
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
130
|
+
},
|
|
131
|
+
redirect: 'manual',
|
|
132
|
+
signal: controller.signal,
|
|
133
|
+
});
|
|
134
|
+
if (!response.ok)
|
|
135
|
+
return null;
|
|
136
|
+
const payload = await response.json();
|
|
137
|
+
const configured = payload?.configured;
|
|
138
|
+
return typeof configured === 'boolean' ? configured : null;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
clearTimeout(timer);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Fold the server's answer into the verdict read off its `.env` (Issue #2585).
|
|
149
|
+
*
|
|
150
|
+
* They disagree in exactly two ways, and both are real situations rather than
|
|
151
|
+
* defensive padding:
|
|
152
|
+
*
|
|
153
|
+
* - **Server has keys, `.env` names none.** They were exported into the daemon at
|
|
154
|
+
* launch. Unsupported (`commandmate init` writes the file), but real, and warning
|
|
155
|
+
* about push being off on a server that is demonstrably sending it would be wrong.
|
|
156
|
+
* - **Server has none, `.env` names both.** The file was edited after the daemon
|
|
157
|
+
* started. The warning stands — the running server still cannot send — and
|
|
158
|
+
* {@link explainVapidMismatch} adds the sentence that makes it actionable.
|
|
159
|
+
*
|
|
160
|
+
* The subject (#2124) is never reconciled, because the endpoint does not report it:
|
|
161
|
+
* it stays whatever the `.env` says, which is the only VAPID value a running server
|
|
162
|
+
* cannot be asked about.
|
|
163
|
+
*/
|
|
164
|
+
function reconcileVapid(fileVerdict, serverConfigured) {
|
|
165
|
+
if (serverConfigured === null || serverConfigured === fileVerdict.configured) {
|
|
166
|
+
return fileVerdict;
|
|
167
|
+
}
|
|
168
|
+
if (serverConfigured) {
|
|
169
|
+
return {
|
|
170
|
+
...fileVerdict,
|
|
171
|
+
configured: true,
|
|
172
|
+
status: fileVerdict.subjectIssue === null ? 'ok' : 'invalid-subject',
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
return { ...fileVerdict, configured: false, status: 'unconfigured' };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* The sentence that closes the gap between "push is off" and "but I set those keys!"
|
|
179
|
+
* (Issue #2585) — appended to the shared lines, never replacing them.
|
|
180
|
+
*
|
|
181
|
+
* Both branches exist because both were measured: #2575 spent an investigation on a
|
|
182
|
+
* shell that exported the pair for a server that never had it, and a `.env` edited
|
|
183
|
+
* under a running daemon is the same confusion with the file in the shell's place.
|
|
184
|
+
*
|
|
185
|
+
* @returns Extra lines, or nothing at all when the report needs no qualifier.
|
|
186
|
+
*/
|
|
187
|
+
function explainVapidMismatch(verdict, fileVerdict, serverConfigured, envPath) {
|
|
188
|
+
// Push works. Nothing is being reported, so there is nothing to qualify.
|
|
189
|
+
if (verdict.configured)
|
|
190
|
+
return [];
|
|
191
|
+
if (serverConfigured === false && fileVerdict.configured) {
|
|
192
|
+
return [
|
|
193
|
+
` ${envPath} does set both keys, so the running server predates that edit:`,
|
|
194
|
+
' restart it ("commandmate stop && commandmate start") to pick them up.',
|
|
195
|
+
];
|
|
196
|
+
}
|
|
197
|
+
// Names only, never values — the same rule the shared lines follow.
|
|
198
|
+
const shellOnly = fileVerdict.missingKeys.filter((key) => (process.env[key] ?? '').trim() !== '');
|
|
199
|
+
if (shellOnly.length === 0)
|
|
200
|
+
return [];
|
|
201
|
+
const pronoun = shellOnly.length > 1 ? 'them' : 'it';
|
|
202
|
+
return [
|
|
203
|
+
` This shell exports ${shellOnly.join(' and ')}, but the server was not started`,
|
|
204
|
+
` with ${pronoun}: set ${pronoun} in ${envPath} and restart the server.`,
|
|
205
|
+
];
|
|
206
|
+
}
|
|
93
207
|
/**
|
|
94
208
|
* Report the server's Web Push configuration, or nothing when it is healthy
|
|
95
|
-
* (Issues #2123 / #2124).
|
|
209
|
+
* (Issues #2123 / #2124 / #2585).
|
|
96
210
|
*
|
|
97
211
|
* The Issues' acceptance condition is "the startup log OR `commandmate status`",
|
|
98
212
|
* and this is the half that is still readable a week later — a daemon started in
|
|
99
213
|
* the background writes its stdout wherever the launcher put it, and the reader
|
|
100
214
|
* who notices "my phone stopped buzzing" reaches for `status`.
|
|
101
215
|
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
216
|
+
* ## Who is asked, in order
|
|
217
|
+
*
|
|
218
|
+
* 1. **The running server**, over `GET /api/push/vapid`. It is the only party
|
|
219
|
+
* that knows what it was launched with, and #2585 is the proof that everything
|
|
220
|
+
* else is inference.
|
|
221
|
+
* 2. **Its `.env` files alone** ({@link loadEnvFileValues}) — for the subject,
|
|
222
|
+
* which the endpoint does not report, and for the whole verdict when the probe
|
|
223
|
+
* comes back `null`.
|
|
224
|
+
*
|
|
225
|
+
* `process.env` is NOT a layer under either, which is the fix. This used to read
|
|
226
|
+
* `getEffectiveEnv()`, whose `{...process.env, ...parsed}` reproduces what
|
|
227
|
+
* `daemon.start()` hands the child — exact for a key the `.env` defines, a guess
|
|
228
|
+
* for one it does not. `CM_VAPID_*` exported in the calling terminal therefore
|
|
229
|
+
* read as the daemon's own configuration and silenced this warning for a server
|
|
230
|
+
* that had none (#2575, measured 2026-09-16: `:60301` answered
|
|
231
|
+
* `{"configured":false}` while `status` said nothing).
|
|
107
232
|
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
233
|
+
* ## When the server does not answer
|
|
234
|
+
*
|
|
235
|
+
* A stopped daemon never reaches this function — both callers return at
|
|
236
|
+
* "Not running". A *running* daemon that does not answer (auth on with no
|
|
237
|
+
* `CM_AUTH_TOKEN`, a wedged process, something else on the advertised port) falls
|
|
238
|
+
* back to the `.env` verdict, and never to the shell. The residual is then the
|
|
239
|
+
* mirror of the bug that was fixed: a pair exported into the daemon at launch and
|
|
240
|
+
* absent from `.env` reads as unconfigured, i.e. a warning that is not warranted.
|
|
241
|
+
* That direction is the deliberate one — a false warning names the variables and
|
|
242
|
+
* the file and can be checked in one command, whereas the silence it replaces is
|
|
243
|
+
* what #2575 could not diagnose at all.
|
|
113
244
|
*
|
|
114
245
|
* Silent on a healthy install — that silence is the negative control both Issues
|
|
115
246
|
* ask for. Never throws: a diagnostic must not turn `status` into a failure.
|
|
116
247
|
*/
|
|
117
|
-
function printVapidStatus(
|
|
248
|
+
async function printVapidStatus(status, envPath) {
|
|
118
249
|
try {
|
|
119
|
-
const
|
|
250
|
+
const fileVerdict = (0, vapid_1.inspectVapidConfig)((0, server_url_1.loadEnvFileValues)(envPath));
|
|
251
|
+
const serverConfigured = status.url ? await probeServerVapid(status.url) : null;
|
|
252
|
+
const verdict = reconcileVapid(fileVerdict, serverConfigured);
|
|
253
|
+
const lines = (0, vapid_1.formatVapidReportLines)(verdict);
|
|
120
254
|
if (lines.length === 0)
|
|
121
255
|
return;
|
|
122
256
|
console.log('');
|
|
@@ -124,6 +258,9 @@ function printVapidStatus(env) {
|
|
|
124
258
|
for (const line of lines.slice(1)) {
|
|
125
259
|
console.log(line);
|
|
126
260
|
}
|
|
261
|
+
for (const line of explainVapidMismatch(verdict, fileVerdict, serverConfigured, envPath)) {
|
|
262
|
+
console.log(line);
|
|
263
|
+
}
|
|
127
264
|
}
|
|
128
265
|
catch {
|
|
129
266
|
// Unreadable .env, unparsable value: report the server, drop the hint.
|
|
@@ -202,7 +339,8 @@ async function showSingleStatus(issueNo) {
|
|
|
202
339
|
// Issue #2113: the advertised localhost URL may not reach this server at all
|
|
203
340
|
printLocalhostConflict(status);
|
|
204
341
|
// Issue #2123 / #2124: whether Web Push can work at all on this server
|
|
205
|
-
|
|
342
|
+
// Issue #2585: asked of the server, and read off its .env — never off this shell
|
|
343
|
+
await printVapidStatus(status, envPath);
|
|
206
344
|
}
|
|
207
345
|
/**
|
|
208
346
|
* Show status for all servers (main + all worktrees)
|
|
@@ -295,7 +433,8 @@ async function statusCommand(options = {}) {
|
|
|
295
433
|
// Issue #2113: the advertised localhost URL may not reach this server at all
|
|
296
434
|
printLocalhostConflict(status);
|
|
297
435
|
// Issue #2123 / #2124: whether Web Push can work at all on this server
|
|
298
|
-
|
|
436
|
+
// Issue #2585: asked of the server, and read off its .env — never off this shell
|
|
437
|
+
await printVapidStatus(status, envPath);
|
|
299
438
|
// Issue #332: Show IP restriction status
|
|
300
439
|
// Issue #1266: read the env the server actually runs with. An exported CM_ALLOWED_IPS
|
|
301
440
|
// shadowed the .env one here, reporting an ACL the server does not enforce.
|