commandmate 0.23.0 → 0.25.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 +415 -406
- package/.next/app-path-routes-manifest.json +27 -26
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +9 -9
- package/.next/react-loadable-manifest.json +4 -4
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js +1 -1
- package/.next/server/app/api/assistant/conversation/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js +1 -1
- package/.next/server/app/api/assistant/current-output/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js +1 -1
- package/.next/server/app/api/assistant/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/session/route.js +1 -1
- package/.next/server/app/api/assistant/session/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/start/route.js +1 -1
- package/.next/server/app/api/assistant/start/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/terminal/route.js +2 -2
- package/.next/server/app/api/assistant/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js +1 -1
- package/.next/server/app/api/assistant/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route.js +1 -1
- package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js +1 -1
- package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_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 -0
- package/.next/server/app/api/push/escalation/route.js.nft.json +1 -0
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/push/subscriptions/route.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/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route.js +1 -1
- package/.next/server/app/api/repositories/[id]/todos/route_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/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.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.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.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.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route.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]/execution-logs/[logId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_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.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.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.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.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.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.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.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.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]/interrupt/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route.js +5 -5
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/schedules/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route.js +2 -2
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_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/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route.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.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.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route.js.nft.json +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/chat/page.js +2 -2
- package/.next/server/app/chat/page.js.nft.json +1 -1
- package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page.js +2 -2
- package/.next/server/app/login/page.js.nft.json +1 -1
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
- package/.next/server/app/more/page.js +2 -2
- package/.next/server/app/more/page.js.nft.json +1 -1
- package/.next/server/app/more/page_client-reference-manifest.js +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +1 -1
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page.js +2 -2
- package/.next/server/app/repositories/page.js.nft.json +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page.js +1 -1
- package/.next/server/app/review/page.js.nft.json +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page.js.nft.json +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page.js +2 -2
- package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page.js +2 -2
- package/.next/server/app/skills/installed/page.js.nft.json +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page.js +2 -2
- package/.next/server/app/skills/page.js.nft.json +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js +2 -2
- 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 +7 -7
- package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +27 -26
- package/.next/server/chunks/1029.js +1 -1
- package/.next/server/chunks/1296.js +1 -1
- package/.next/server/chunks/1366.js +1 -1
- package/.next/server/chunks/1601.js +7 -0
- package/.next/server/chunks/1825.js +1 -1
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2404.js +1 -1
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/2546.js +1 -1
- package/.next/server/chunks/3346.js +1 -1
- package/.next/server/chunks/3417.js +1 -1
- package/.next/server/chunks/3480.js +1 -1
- package/.next/server/chunks/3543.js +1 -1
- package/.next/server/chunks/3945.js +1 -1
- package/.next/server/chunks/4393.js +1 -0
- package/.next/server/chunks/4444.js +1 -1
- package/.next/server/chunks/4455.js +1 -0
- package/.next/server/chunks/5164.js +1 -0
- package/.next/server/chunks/5571.js +1 -1
- package/.next/server/chunks/5959.js +5 -5
- package/.next/server/chunks/5998.js +1 -1
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6159.js +1 -1
- package/.next/server/chunks/6274.js +2 -2
- package/.next/server/chunks/6285.js +1 -1
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/7458.js +5 -5
- package/.next/server/chunks/848.js +1 -1
- package/.next/server/chunks/8536.js +1 -1
- package/.next/server/chunks/8730.js +1 -0
- package/.next/server/chunks/880.js +21 -0
- package/.next/server/chunks/8807.js +134 -129
- package/.next/server/chunks/9058.js +1 -1
- package/.next/server/chunks/9123.js +8 -8
- package/.next/server/chunks/9328.js +1 -1
- package/.next/server/chunks/9358.js +1 -1
- package/.next/server/chunks/9373.js +3 -3
- package/.next/server/chunks/9687.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-manifest.json +5 -5
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- 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/static/chunks/2053-dfac2d49227cc942.js +1 -0
- package/.next/static/chunks/3898-ef488bfa804507d9.js +1 -0
- package/.next/static/chunks/4322-dfd5a7119b5ba4fc.js +1 -0
- package/.next/static/chunks/{4974-eaf66770bfa9dea0.js → 4974-35592ec312322124.js} +1 -1
- package/.next/static/chunks/5229-35f9acab97a553c5.js +1 -0
- package/.next/static/chunks/6381-51f9c4a128aadc0b.js +1 -0
- package/.next/static/chunks/7229.7f0f5a7032b612b4.js +1 -0
- package/.next/static/chunks/{9599-d29d2f8eeaf7c249.js → 8649-f551b0010dba4986.js} +1 -1
- package/.next/static/chunks/9263.f2034ec525abcf72.js +1 -0
- package/.next/static/chunks/app/api/app/update/{route-973ec48531555712.js → route-fae89f8d4cc3ff97.js} +1 -1
- package/.next/static/chunks/app/api/app/update-check/{route-973ec48531555712.js → route-fae89f8d4cc3ff97.js} +1 -1
- package/.next/static/chunks/app/api/assistant/conversation/{route-973ec48531555712.js → route-fae89f8d4cc3ff97.js} +1 -1
- package/.next/static/chunks/app/api/assistant/current-output/{route-973ec48531555712.js → route-fae89f8d4cc3ff97.js} +1 -1
- package/.next/static/chunks/app/api/assistant/messages/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/assistant/session/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/assistant/start/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/assistant/terminal/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/assistant/tools/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/auth/login/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/auth/logout/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/auth/status/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/daily-summary/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/daily-summary/status/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/external-apps/[id]/health/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/external-apps/[id]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/external-apps/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/fs/browse/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/fs/recent-paths/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/hooks/agent-event/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/hooks/claude-done/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/hooks/permission-request/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/metrics/vibe/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/ollama/models/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/push/escalation/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/push/subscriptions/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/push/vapid/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/todos/[todoId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/[id]/todos/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/clone/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/excluded/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/restore/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/scan/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/sync/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/repositories/validate-path/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/sidebar/group-order/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/skills/[id]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/skills/installations/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/skills/operations/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/skills/reindex/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/skills/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/slash-commands/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/tasks/[taskId]/cancel/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/tasks/[taskId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/templates/[id]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/templates/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/todos/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/verification/runs/[runId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/verification/runs/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/capture/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/logs/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/memos/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/messages/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/respond/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/search/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/send/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update-plan/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/skills/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/start-polling/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tasks/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/timers/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/todos/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/tree/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/api/worktrees/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/chat/page-439b35c9cb90dbe0.js +1 -0
- package/.next/static/chunks/app/layout-6a26ea22d5cf03dc.js +1 -0
- package/.next/static/chunks/app/login/page-eefd515d8c37e5ee.js +1 -0
- package/.next/static/chunks/app/manifest.webmanifest/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/more/page-889b7546a8a553dc.js +1 -0
- package/.next/static/chunks/app/page-a8d04ac0e3e4c9fc.js +1 -0
- package/.next/static/chunks/app/proxy/[...path]/route-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/repositories/page-f3c4d8839b1ca203.js +1 -0
- package/.next/static/chunks/app/review/page-6dc88649fe88ac16.js +1 -0
- package/.next/static/chunks/app/sessions/page-2c9ed9e969097688.js +1 -0
- package/.next/static/chunks/app/skills/[skillId]/page-19beef6121c4c982.js +1 -0
- package/.next/static/chunks/app/skills/installed/page-d5b9cef6d21fabda.js +1 -0
- package/.next/static/chunks/app/skills/page-06ef637e07dd9377.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-5fed3984fafcd910.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/layout-fae89f8d4cc3ff97.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-207c69540fd856ef.js +1 -0
- package/.next/static/chunks/{webpack-180bebdee221b6f4.js → webpack-9d892a9ff07c289d.js} +1 -1
- package/.next/static/css/e865c4979a41aa03.css +1 -0
- package/.next/static/ehkNc5xDMDkXlua08Bwq0/_buildManifest.js +1 -0
- package/.next/trace +12 -12
- package/.next/types/app/api/push/escalation/route.ts +347 -0
- package/.next/types/routes.d.ts +2 -1
- package/.next/types/validator.ts +9 -0
- package/README.md +96 -45
- package/dist/cli/commands/capture.d.ts.map +1 -1
- package/dist/cli/commands/capture.js +6 -0
- package/dist/cli/commands/instances.d.ts.map +1 -1
- package/dist/cli/commands/instances.js +19 -1
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +6 -0
- package/dist/cli/commands/verify.js +6 -1
- package/dist/cli/types/api-responses.d.ts +46 -0
- package/dist/cli/types/api-responses.d.ts.map +1 -1
- package/dist/cli/utils/verify-runner.d.ts.map +1 -1
- package/dist/cli/utils/verify-runner.js +17 -1
- package/dist/server/locales/en/notifications.json +20 -1
- package/dist/server/locales/ja/notifications.json +20 -1
- package/dist/server/server.js +23 -0
- package/dist/server/src/config/activity-bar-config.js +5 -1
- package/dist/server/src/lib/auto-yes-poller.js +40 -4
- package/dist/server/src/lib/cli-tools/codex.js +58 -29
- package/dist/server/src/lib/db/db.js +2 -1
- package/dist/server/src/lib/db/migrations/index.js +2 -0
- package/dist/server/src/lib/db/migrations/runner.js +1 -1
- package/dist/server/src/lib/db/migrations/v56-gate-result-source.js +58 -0
- package/dist/server/src/lib/db/verification-db.js +26 -6
- package/dist/server/src/lib/detection/cli-patterns.js +148 -6
- package/dist/server/src/lib/detection/model-info-extractor.js +384 -0
- package/dist/server/src/lib/detection/status-detector.js +28 -0
- package/dist/server/src/lib/hooks/sources/antigravity/source.js +4 -0
- package/dist/server/src/lib/hooks/sources/claude/source.js +7 -0
- package/dist/server/src/lib/hooks/sources/codex/source.js +5 -0
- package/dist/server/src/lib/hooks/sources/define-source.js +8 -0
- package/dist/server/src/lib/hooks/sources/event-mapper.js +20 -0
- package/dist/server/src/lib/hooks/sources/opencode/ingest.js +6 -0
- package/dist/server/src/lib/hooks/sources/opencode/mappers.js +22 -0
- package/dist/server/src/lib/hooks/sources/opencode/source.js +3 -0
- package/dist/server/src/lib/polling/response-checker.js +47 -0
- package/dist/server/src/lib/push/escalation-settings.js +114 -0
- package/dist/server/src/lib/push/index.js +21 -1
- package/dist/server/src/lib/push/notification-dedup.js +35 -0
- package/dist/server/src/lib/push/push-sender.js +66 -7
- package/dist/server/src/lib/push/waiting-push-notifier.js +231 -0
- package/dist/server/src/lib/realtime/waiting-broadcast.js +93 -0
- package/dist/server/src/lib/session/agent-event-state.js +260 -0
- package/dist/server/src/lib/session/current-output-builder.js +24 -0
- package/dist/server/src/lib/session/next-action-helper.js +93 -0
- package/dist/server/src/lib/session/prompt-waiting-composition.js +38 -0
- package/dist/server/src/lib/session/waiting-episode-state.js +136 -0
- package/dist/server/src/lib/session/waiting-kind.js +59 -0
- package/dist/server/src/lib/tasks/contract-message.js +64 -21
- package/dist/server/src/lib/tasks/contract-parser.js +58 -12
- package/dist/server/src/lib/verification/gate-runner.js +64 -22
- package/dist/server/src/lib/verification/verify-config.js +84 -51
- package/dist/server/src/lib/ws-server.js +9 -0
- package/dist/server/src/types/sidebar.js +68 -0
- package/package.json +1 -1
- package/.next/server/chunks/3451.js +0 -1
- package/.next/server/chunks/6283.js +0 -1
- package/.next/server/chunks/646.js +0 -21
- package/.next/static/chunks/2053-52d3c82014e1cd54.js +0 -1
- package/.next/static/chunks/4560-0917ae2e6a0e5400.js +0 -1
- package/.next/static/chunks/6488-95ba9d24a76f0cc5.js +0 -1
- package/.next/static/chunks/7229.edb331fb9fbafa27.js +0 -1
- package/.next/static/chunks/744-fa8c0ae444c8338c.js +0 -1
- package/.next/static/chunks/9263.5259f73f89220d64.js +0 -1
- package/.next/static/chunks/app/api/assistant/messages/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/assistant/session/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/assistant/start/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/assistant/terminal/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/assistant/tools/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/auth/login/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/auth/logout/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/auth/status/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/daily-summary/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/daily-summary/status/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/external-apps/[id]/health/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/external-apps/[id]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/external-apps/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/fs/browse/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/fs/recent-paths/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/hooks/agent-event/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/hooks/claude-done/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/hooks/permission-request/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/metrics/vibe/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/ollama/models/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/push/subscriptions/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/push/vapid/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/todos/[todoId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/[id]/todos/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/clone/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/excluded/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/restore/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/scan/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/sync/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/repositories/validate-path/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/sidebar/group-order/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/skills/[id]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/skills/installations/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/skills/operations/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/skills/reindex/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/skills/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/slash-commands/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/tasks/[taskId]/cancel/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/tasks/[taskId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/templates/[id]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/templates/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/todos/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/verification/runs/[runId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/verification/runs/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/capture/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/logs/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/memos/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/messages/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/respond/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/search/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/send/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/update-plan/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/skills/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/start-polling/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tasks/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/timers/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/todos/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/tree/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/[runId]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/verify/runs/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/api/worktrees/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/chat/page-83a2238ab453afaa.js +0 -1
- package/.next/static/chunks/app/layout-86574192bd3c0e6b.js +0 -1
- package/.next/static/chunks/app/login/page-0247a3fb569bb22b.js +0 -1
- package/.next/static/chunks/app/manifest.webmanifest/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/more/page-1619018cac999bbc.js +0 -1
- package/.next/static/chunks/app/page-a34d26812f085b6c.js +0 -1
- package/.next/static/chunks/app/proxy/[...path]/route-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/repositories/page-202680fe6ec169c8.js +0 -1
- package/.next/static/chunks/app/review/page-b559bfb11c46931b.js +0 -1
- package/.next/static/chunks/app/sessions/page-3fa7e767d0ab3889.js +0 -1
- package/.next/static/chunks/app/skills/[skillId]/page-10d6f983e5f06ffb.js +0 -1
- package/.next/static/chunks/app/skills/installed/page-6641f95e6a6e5f9d.js +0 -1
- package/.next/static/chunks/app/skills/page-184f8e23e31a3667.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-6041d3c3db326317.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/layout-973ec48531555712.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-966a451ae7b0903a.js +0 -1
- package/.next/static/css/d3453a6876553d32.css +0 -1
- package/.next/static/wH6K6QNPHSdATFkVoIcy3/_buildManifest.js +0 -1
- /package/.next/static/{wH6K6QNPHSdATFkVoIcy3 → ehkNc5xDMDkXlua08Bwq0}/_ssgManifest.js +0 -0
|
@@ -28,7 +28,20 @@ const prompt_dedup_1 = require("./prompt-dedup");
|
|
|
28
28
|
const response_dedup_1 = require("./response-dedup");
|
|
29
29
|
const response_poller_core_1 = require("./response-poller-core");
|
|
30
30
|
const push_1 = require("../../lib/push");
|
|
31
|
+
// Issue #1790: imported by deep path, not through `@/lib/push`. Suites that
|
|
32
|
+
// replace the barrel to count notifications (e.g. the #1547 escalation test)
|
|
33
|
+
// would otherwise get `undefined` here and take down module evaluation.
|
|
34
|
+
const waiting_push_notifier_1 = require("../../lib/push/waiting-push-notifier");
|
|
35
|
+
const waiting_episode_state_1 = require("../../lib/session/waiting-episode-state");
|
|
31
36
|
const task_transition_service_1 = require("../../lib/tasks/task-transition-service");
|
|
37
|
+
// Issue #1790: arm the waiting-edge push subscription.
|
|
38
|
+
//
|
|
39
|
+
// It has to exist before the first edge, and `server.ts` reaches this module at
|
|
40
|
+
// boot (it imports `polling/response-poller` for `stopAllPolling`, which pulls
|
|
41
|
+
// in `response-poller-core` and then this file), so this is the earliest hook
|
|
42
|
+
// the notification path owns. Idempotent by replacement, and it starts no timer
|
|
43
|
+
// and touches no database until a wait actually opens.
|
|
44
|
+
(0, waiting_push_notifier_1.startWaitingPushNotifier)();
|
|
32
45
|
/**
|
|
33
46
|
* Creates an incomplete extraction result with empty response.
|
|
34
47
|
* Centralizes the repeated pattern of returning an in-progress/incomplete state.
|
|
@@ -465,13 +478,39 @@ async function checkForResponse(worktreeId, cliToolId, instanceId) {
|
|
|
465
478
|
});
|
|
466
479
|
// Web Push fan-out (Issue #1125): agent is now waiting for a prompt reply.
|
|
467
480
|
// Fire-and-forget — push is advisory and must never block/break the poller.
|
|
481
|
+
//
|
|
482
|
+
// Issue #1790: the wait is now named by #1786's episode rather than by the
|
|
483
|
+
// prompt text. The two lines below are ordered, not incidental:
|
|
484
|
+
//
|
|
485
|
+
// 1. the notification is raised first, while it still has the prompt's
|
|
486
|
+
// own question to quote — it records the episode in the dedup, so
|
|
487
|
+
// whichever path reports the wait second says nothing;
|
|
488
|
+
// 2. `observeWaitingEdge` then opens that same episode, which is what
|
|
489
|
+
// lets the edge listener (and #1788's WebSocket frame) agree with this
|
|
490
|
+
// call about *which* wait this is instead of raising a second one.
|
|
491
|
+
//
|
|
492
|
+
// Both use one timestamp so the episode the notification claims and the
|
|
493
|
+
// episode the store opens are the same number.
|
|
494
|
+
const promptObservedAt = Date.now();
|
|
495
|
+
const promptWaitingSince = (0, waiting_episode_state_1.getWaitingEpisode)(worktreeId, cliToolId, instanceId)?.since ?? promptObservedAt;
|
|
468
496
|
void (0, push_1.notifyPushSubscribers)({
|
|
469
497
|
worktreeId,
|
|
470
498
|
worktreeName: worktree.name,
|
|
471
499
|
kind: 'prompt',
|
|
472
500
|
agentName: resolvedInstanceId,
|
|
501
|
+
instanceId: resolvedInstanceId,
|
|
502
|
+
waitingKind: 'prompt',
|
|
503
|
+
waitingSince: promptWaitingSince,
|
|
473
504
|
excerpt: promptDetection.promptData?.question ?? promptSaveContent,
|
|
474
505
|
}).catch(() => { });
|
|
506
|
+
(0, waiting_episode_state_1.observeWaitingEdge)({
|
|
507
|
+
worktreeId,
|
|
508
|
+
cliToolId,
|
|
509
|
+
instanceId,
|
|
510
|
+
waiting: true,
|
|
511
|
+
kind: 'prompt',
|
|
512
|
+
now: promptObservedAt,
|
|
513
|
+
});
|
|
475
514
|
if (!isFullScreenTui) {
|
|
476
515
|
(0, response_poller_core_1.stopPolling)(worktreeId, cliToolId, instanceId);
|
|
477
516
|
}
|
|
@@ -562,6 +601,14 @@ async function checkForResponse(worktreeId, cliToolId, instanceId) {
|
|
|
562
601
|
});
|
|
563
602
|
// Broadcast message to WebSocket clients
|
|
564
603
|
(0, ws_server_1.broadcastMessage)('message', { worktreeId, message });
|
|
604
|
+
// Issue #1790: the agent has just produced a reply, so whatever it was
|
|
605
|
+
// waiting for is over. Closing the episode here is what makes a *second*
|
|
606
|
+
// prompt in the same session notify again: without it a wait opened by the
|
|
607
|
+
// prompt branch above could stay open until a browser next probes the status
|
|
608
|
+
// API, and every later prompt would be folded into that stale episode and
|
|
609
|
+
// silently deduped. Nothing to close is a no-op, and no notification is
|
|
610
|
+
// raised for a closing edge.
|
|
611
|
+
(0, waiting_episode_state_1.observeWaitingEdge)({ worktreeId, cliToolId, instanceId, waiting: false });
|
|
565
612
|
// Web Push fan-out (Issue #1125): session completed (running → idle).
|
|
566
613
|
// Fire-and-forget — push is advisory and must never block/break the poller.
|
|
567
614
|
void (0, push_1.notifyPushSubscribers)({
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* The "still waiting" reminder setting (Issue #1790).
|
|
4
|
+
*
|
|
5
|
+
* A wait that nobody answers is the case push notifications exist for, and one
|
|
6
|
+
* notification is easy to miss — so after a threshold the server sends exactly
|
|
7
|
+
* one more. How long to wait, and whether to do it at all, is a user decision,
|
|
8
|
+
* and it is a *server-side* one: the check runs in the background with no
|
|
9
|
+
* request and no browser attached, so it cannot read a device's localStorage the
|
|
10
|
+
* way #1788's in-app toggle does. It is therefore stored once for the install
|
|
11
|
+
* and applies to every subscribed device.
|
|
12
|
+
*
|
|
13
|
+
* ## Why the SQL lives here
|
|
14
|
+
*
|
|
15
|
+
* `app_settings` (migration v27) is the generic key-value store this rides on,
|
|
16
|
+
* so no migration is added. Its typed helpers live in `db/app-settings-db`, but
|
|
17
|
+
* both existing ones are `string[]`-shaped and this value is an object with two
|
|
18
|
+
* fields of different types; a third helper there would be a fourth reader of
|
|
19
|
+
* the same table with no shared logic to gain. Keeping the accessor beside its
|
|
20
|
+
* only consumer also keeps the defaults — which the escalation tick applies on
|
|
21
|
+
* every failure path — in one file.
|
|
22
|
+
*
|
|
23
|
+
* Every read is total: a missing row, malformed JSON, an out-of-range threshold
|
|
24
|
+
* or an unopenable database all resolve to {@link DEFAULT_ESCALATION_SETTINGS}
|
|
25
|
+
* rather than throwing. The caller is a background timer whose failure mode
|
|
26
|
+
* must be "no reminder", never "the server logs an exception every minute".
|
|
27
|
+
*
|
|
28
|
+
* @module lib/push/escalation-settings
|
|
29
|
+
*/
|
|
30
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.MAX_ESCALATION_THRESHOLD_MINUTES = exports.MIN_ESCALATION_THRESHOLD_MINUTES = exports.ESCALATION_THRESHOLD_CHOICES = exports.DEFAULT_ESCALATION_SETTINGS = exports.ESCALATION_SETTINGS_KEY = void 0;
|
|
32
|
+
exports.normalizeEscalationSettings = normalizeEscalationSettings;
|
|
33
|
+
exports.getPushEscalationSettings = getPushEscalationSettings;
|
|
34
|
+
exports.setPushEscalationSettings = setPushEscalationSettings;
|
|
35
|
+
const db_instance_1 = require("../../lib/db/db-instance");
|
|
36
|
+
const logger_1 = require("../../lib/logger");
|
|
37
|
+
const logger = (0, logger_1.createLogger)('push/escalation-settings');
|
|
38
|
+
/** `app_settings.key` this setting is stored under. */
|
|
39
|
+
exports.ESCALATION_SETTINGS_KEY = 'push_escalation';
|
|
40
|
+
/**
|
|
41
|
+
* On by default at ten minutes, per the Issue.
|
|
42
|
+
*
|
|
43
|
+
* Defaulting to *on* is the same call #1788 made for the in-app toast: a user
|
|
44
|
+
* who never opened the settings screen is the one most likely to walk away from
|
|
45
|
+
* a waiting agent, and the cost of being wrong is one extra notification per
|
|
46
|
+
* unanswered wait — bounded, because there is only ever one.
|
|
47
|
+
*/
|
|
48
|
+
exports.DEFAULT_ESCALATION_SETTINGS = {
|
|
49
|
+
enabled: true,
|
|
50
|
+
thresholdMinutes: 10,
|
|
51
|
+
};
|
|
52
|
+
/** The thresholds the settings UI offers, in minutes. */
|
|
53
|
+
exports.ESCALATION_THRESHOLD_CHOICES = [5, 10, 30, 60];
|
|
54
|
+
/** Guard rails for a hand-written value: at least a minute, at most a day. */
|
|
55
|
+
exports.MIN_ESCALATION_THRESHOLD_MINUTES = 1;
|
|
56
|
+
exports.MAX_ESCALATION_THRESHOLD_MINUTES = 1440;
|
|
57
|
+
/**
|
|
58
|
+
* Narrow arbitrary input to a usable setting, filling each field independently.
|
|
59
|
+
*
|
|
60
|
+
* Field-by-field rather than all-or-nothing so that a bad threshold does not
|
|
61
|
+
* silently switch the reminder back on (or off): the half the user did set is
|
|
62
|
+
* the half that is honoured.
|
|
63
|
+
*/
|
|
64
|
+
function normalizeEscalationSettings(value) {
|
|
65
|
+
if (typeof value !== 'object' || value === null)
|
|
66
|
+
return { ...exports.DEFAULT_ESCALATION_SETTINGS };
|
|
67
|
+
const record = value;
|
|
68
|
+
const enabled = typeof record.enabled === 'boolean' ? record.enabled : exports.DEFAULT_ESCALATION_SETTINGS.enabled;
|
|
69
|
+
const raw = record.thresholdMinutes;
|
|
70
|
+
const thresholdMinutes = typeof raw === 'number' &&
|
|
71
|
+
Number.isFinite(raw) &&
|
|
72
|
+
raw >= exports.MIN_ESCALATION_THRESHOLD_MINUTES &&
|
|
73
|
+
raw <= exports.MAX_ESCALATION_THRESHOLD_MINUTES
|
|
74
|
+
? Math.round(raw)
|
|
75
|
+
: exports.DEFAULT_ESCALATION_SETTINGS.thresholdMinutes;
|
|
76
|
+
return { enabled, thresholdMinutes };
|
|
77
|
+
}
|
|
78
|
+
/** Read the setting. Never throws — see the module docblock. */
|
|
79
|
+
function getPushEscalationSettings() {
|
|
80
|
+
try {
|
|
81
|
+
const row = (0, db_instance_1.getDbInstance)()
|
|
82
|
+
.prepare('SELECT value FROM app_settings WHERE key = ?')
|
|
83
|
+
.get(exports.ESCALATION_SETTINGS_KEY);
|
|
84
|
+
if (!row)
|
|
85
|
+
return { ...exports.DEFAULT_ESCALATION_SETTINGS };
|
|
86
|
+
return normalizeEscalationSettings(JSON.parse(row.value));
|
|
87
|
+
}
|
|
88
|
+
catch (error) {
|
|
89
|
+
logger.warn('escalation-settings-read-failed', {
|
|
90
|
+
error: error instanceof Error ? error.message : String(error),
|
|
91
|
+
});
|
|
92
|
+
return { ...exports.DEFAULT_ESCALATION_SETTINGS };
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Persist the setting, normalizing first so a malformed request cannot store a
|
|
97
|
+
* value later reads would have to reject anyway.
|
|
98
|
+
*
|
|
99
|
+
* @returns What was actually written.
|
|
100
|
+
*/
|
|
101
|
+
function setPushEscalationSettings(value) {
|
|
102
|
+
const settings = normalizeEscalationSettings(value);
|
|
103
|
+
const now = Date.now();
|
|
104
|
+
(0, db_instance_1.getDbInstance)()
|
|
105
|
+
.prepare(`
|
|
106
|
+
INSERT INTO app_settings (key, value, created_at, updated_at)
|
|
107
|
+
VALUES (?, ?, ?, ?)
|
|
108
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
109
|
+
value = excluded.value,
|
|
110
|
+
updated_at = excluded.updated_at
|
|
111
|
+
`)
|
|
112
|
+
.run(exports.ESCALATION_SETTINGS_KEY, JSON.stringify(settings), now, now);
|
|
113
|
+
return settings;
|
|
114
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/** Web Push module barrel (Issue #1125). */
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.DEFAULT_DEDUP_WINDOW_MS = exports.resetNotificationDedup = exports.shouldSendNotification = exports.resolvePushLocale = exports.buildExcerpt = exports.buildPushPayload = exports.notifyPushSubscribers = exports.getVapidPublicKey = exports.isPushConfigured = exports.getVapidConfig = void 0;
|
|
4
|
+
exports.MAX_ESCALATION_THRESHOLD_MINUTES = exports.MIN_ESCALATION_THRESHOLD_MINUTES = exports.ESCALATION_SETTINGS_KEY = exports.ESCALATION_THRESHOLD_CHOICES = exports.DEFAULT_ESCALATION_SETTINGS = exports.normalizeEscalationSettings = exports.setPushEscalationSettings = exports.getPushEscalationSettings = exports.ESCALATION_TICK_MS = exports.pendingEscalationCount = exports.runEscalationTick = exports.handleWaitingTransition = exports.isWaitingPushNotifierActive = exports.stopWaitingPushNotifier = exports.startWaitingPushNotifier = exports.resetWaitingPushDedup = exports.shouldSendWaitingPush = exports.DEFAULT_DEDUP_WINDOW_MS = exports.resetNotificationDedup = exports.shouldSendNotification = exports.resolvePushLocale = exports.buildExcerpt = exports.buildPushPayload = exports.notifyPushSubscribers = exports.getVapidPublicKey = exports.isPushConfigured = exports.getVapidConfig = void 0;
|
|
5
5
|
var vapid_1 = require("./vapid");
|
|
6
6
|
Object.defineProperty(exports, "getVapidConfig", { enumerable: true, get: function () { return vapid_1.getVapidConfig; } });
|
|
7
7
|
Object.defineProperty(exports, "isPushConfigured", { enumerable: true, get: function () { return vapid_1.isPushConfigured; } });
|
|
@@ -15,3 +15,23 @@ var notification_dedup_1 = require("./notification-dedup");
|
|
|
15
15
|
Object.defineProperty(exports, "shouldSendNotification", { enumerable: true, get: function () { return notification_dedup_1.shouldSendNotification; } });
|
|
16
16
|
Object.defineProperty(exports, "resetNotificationDedup", { enumerable: true, get: function () { return notification_dedup_1.resetNotificationDedup; } });
|
|
17
17
|
Object.defineProperty(exports, "DEFAULT_DEDUP_WINDOW_MS", { enumerable: true, get: function () { return notification_dedup_1.DEFAULT_DEDUP_WINDOW_MS; } });
|
|
18
|
+
Object.defineProperty(exports, "shouldSendWaitingPush", { enumerable: true, get: function () { return notification_dedup_1.shouldSendWaitingPush; } });
|
|
19
|
+
Object.defineProperty(exports, "resetWaitingPushDedup", { enumerable: true, get: function () { return notification_dedup_1.resetWaitingPushDedup; } });
|
|
20
|
+
// Waiting-edge driven notifications (Issue #1790).
|
|
21
|
+
var waiting_push_notifier_1 = require("./waiting-push-notifier");
|
|
22
|
+
Object.defineProperty(exports, "startWaitingPushNotifier", { enumerable: true, get: function () { return waiting_push_notifier_1.startWaitingPushNotifier; } });
|
|
23
|
+
Object.defineProperty(exports, "stopWaitingPushNotifier", { enumerable: true, get: function () { return waiting_push_notifier_1.stopWaitingPushNotifier; } });
|
|
24
|
+
Object.defineProperty(exports, "isWaitingPushNotifierActive", { enumerable: true, get: function () { return waiting_push_notifier_1.isWaitingPushNotifierActive; } });
|
|
25
|
+
Object.defineProperty(exports, "handleWaitingTransition", { enumerable: true, get: function () { return waiting_push_notifier_1.handleWaitingTransition; } });
|
|
26
|
+
Object.defineProperty(exports, "runEscalationTick", { enumerable: true, get: function () { return waiting_push_notifier_1.runEscalationTick; } });
|
|
27
|
+
Object.defineProperty(exports, "pendingEscalationCount", { enumerable: true, get: function () { return waiting_push_notifier_1.pendingEscalationCount; } });
|
|
28
|
+
Object.defineProperty(exports, "ESCALATION_TICK_MS", { enumerable: true, get: function () { return waiting_push_notifier_1.ESCALATION_TICK_MS; } });
|
|
29
|
+
var escalation_settings_1 = require("./escalation-settings");
|
|
30
|
+
Object.defineProperty(exports, "getPushEscalationSettings", { enumerable: true, get: function () { return escalation_settings_1.getPushEscalationSettings; } });
|
|
31
|
+
Object.defineProperty(exports, "setPushEscalationSettings", { enumerable: true, get: function () { return escalation_settings_1.setPushEscalationSettings; } });
|
|
32
|
+
Object.defineProperty(exports, "normalizeEscalationSettings", { enumerable: true, get: function () { return escalation_settings_1.normalizeEscalationSettings; } });
|
|
33
|
+
Object.defineProperty(exports, "DEFAULT_ESCALATION_SETTINGS", { enumerable: true, get: function () { return escalation_settings_1.DEFAULT_ESCALATION_SETTINGS; } });
|
|
34
|
+
Object.defineProperty(exports, "ESCALATION_THRESHOLD_CHOICES", { enumerable: true, get: function () { return escalation_settings_1.ESCALATION_THRESHOLD_CHOICES; } });
|
|
35
|
+
Object.defineProperty(exports, "ESCALATION_SETTINGS_KEY", { enumerable: true, get: function () { return escalation_settings_1.ESCALATION_SETTINGS_KEY; } });
|
|
36
|
+
Object.defineProperty(exports, "MIN_ESCALATION_THRESHOLD_MINUTES", { enumerable: true, get: function () { return escalation_settings_1.MIN_ESCALATION_THRESHOLD_MINUTES; } });
|
|
37
|
+
Object.defineProperty(exports, "MAX_ESCALATION_THRESHOLD_MINUTES", { enumerable: true, get: function () { return escalation_settings_1.MAX_ESCALATION_THRESHOLD_MINUTES; } });
|
|
@@ -15,6 +15,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.DEFAULT_DEDUP_WINDOW_MS = void 0;
|
|
16
16
|
exports.shouldSendNotification = shouldSendNotification;
|
|
17
17
|
exports.resetNotificationDedup = resetNotificationDedup;
|
|
18
|
+
exports.shouldSendWaitingPush = shouldSendWaitingPush;
|
|
19
|
+
exports.resetWaitingPushDedup = resetWaitingPushDedup;
|
|
18
20
|
const crypto_1 = require("crypto");
|
|
19
21
|
/** Default suppression window: repeats of identical content within this are dropped. */
|
|
20
22
|
exports.DEFAULT_DEDUP_WINDOW_MS = 30_000;
|
|
@@ -40,3 +42,36 @@ function shouldSendNotification(event, now = Date.now(), windowMs = exports.DEFA
|
|
|
40
42
|
function resetNotificationDedup() {
|
|
41
43
|
lastSent.clear();
|
|
42
44
|
}
|
|
45
|
+
const waitingSent = globalThis.__waitingPushDedup ??
|
|
46
|
+
(globalThis.__waitingPushDedup = new Map());
|
|
47
|
+
/**
|
|
48
|
+
* Whether this waiting notification should be sent, recording it if so.
|
|
49
|
+
*
|
|
50
|
+
* Replaces the content hash for the waiting path (Issue #1790). Content was
|
|
51
|
+
* never the right key here: two identical `Do you want to proceed?` prompts
|
|
52
|
+
* seconds apart are two separate waits a human has to answer twice, and the
|
|
53
|
+
* 30 s window dropped the second one — while a single wait that outlives the
|
|
54
|
+
* window could be notified again for the same question. The episode's `since`
|
|
55
|
+
* is the wait's identity, so "one notification per wait" becomes exact:
|
|
56
|
+
*
|
|
57
|
+
* - first notification of an episode → sent, recorded;
|
|
58
|
+
* - any repeat for the same `since` → suppressed, however it arrived (the
|
|
59
|
+
* poller and the edge listener both report the same wait);
|
|
60
|
+
* - the escalation → allowed exactly once per episode;
|
|
61
|
+
* - a new episode (the wait ended and another began) → sent again, even if the
|
|
62
|
+
* prompt text and the elapsed time are identical.
|
|
63
|
+
*/
|
|
64
|
+
function shouldSendWaitingPush(event) {
|
|
65
|
+
const key = `${event.worktreeId}::${event.instanceId}`;
|
|
66
|
+
const escalated = event.escalated === true;
|
|
67
|
+
const prev = waitingSent.get(key);
|
|
68
|
+
if (prev && prev.since === event.since && (prev.escalated || !escalated)) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
waitingSent.set(key, { since: event.since, escalated });
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
/** Clear the episode-scoped state (for tests). */
|
|
75
|
+
function resetWaitingPushDedup() {
|
|
76
|
+
waitingSent.clear();
|
|
77
|
+
}
|
|
@@ -64,6 +64,36 @@ function buildExcerpt(text, maxLength = MAX_EXCERPT_LENGTH) {
|
|
|
64
64
|
return collapsed;
|
|
65
65
|
return collapsed.slice(0, maxLength - 1).trimEnd() + '…';
|
|
66
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Whether this wait can only be dealt with at the terminal (Issue #1790).
|
|
69
|
+
*
|
|
70
|
+
* A `menu` (selection list / pager) and an `unclassified` wait share the one
|
|
71
|
+
* fact the reader acts on: tapping the notification will not present anything
|
|
72
|
+
* to answer. `prompt` — and an absent kind, which is every pre-#1790 caller —
|
|
73
|
+
* keeps the original "waiting for your reply" wording.
|
|
74
|
+
*/
|
|
75
|
+
function needsTerminal(waitingKind) {
|
|
76
|
+
return waitingKind === 'menu' || waitingKind === 'unclassified';
|
|
77
|
+
}
|
|
78
|
+
/** The body for a waiting notification, in the reader's language. */
|
|
79
|
+
function buildWaitingBody(event, messages, excerpt, now) {
|
|
80
|
+
const terminal = needsTerminal(event.waitingKind);
|
|
81
|
+
if (event.escalated) {
|
|
82
|
+
// The excerpt is dropped on purpose: after ten minutes the question is no
|
|
83
|
+
// longer news, the elapsed time is.
|
|
84
|
+
const elapsedMs = now - (event.waitingSince ?? now);
|
|
85
|
+
const minutes = String(Math.max(1, Math.floor(elapsedMs / 60_000)));
|
|
86
|
+
return (terminal ? messages.stillWaitingTerminal : messages.stillWaitingPrompt).replace('{minutes}', minutes);
|
|
87
|
+
}
|
|
88
|
+
if (terminal) {
|
|
89
|
+
return excerpt
|
|
90
|
+
? messages.terminalAttentionWithExcerpt.replace('{excerpt}', excerpt)
|
|
91
|
+
: messages.terminalAttention;
|
|
92
|
+
}
|
|
93
|
+
return excerpt
|
|
94
|
+
? messages.promptWaitingWithExcerpt.replace('{excerpt}', excerpt)
|
|
95
|
+
: messages.promptWaiting;
|
|
96
|
+
}
|
|
67
97
|
/** Build the minimal notification payload for an event, in the reader's language. */
|
|
68
98
|
function buildPushPayload(event, locale = i18n_config_1.DEFAULT_LOCALE, now = Date.now()) {
|
|
69
99
|
const excerpt = buildExcerpt(event.excerpt);
|
|
@@ -71,9 +101,7 @@ function buildPushPayload(event, locale = i18n_config_1.DEFAULT_LOCALE, now = Da
|
|
|
71
101
|
const title = `${event.worktreeName}${agentSuffix}`;
|
|
72
102
|
const messages = PUSH_MESSAGES[resolvePushLocale(locale)];
|
|
73
103
|
const body = event.kind === 'prompt'
|
|
74
|
-
? excerpt
|
|
75
|
-
? messages.promptWaitingWithExcerpt.replace('{excerpt}', excerpt)
|
|
76
|
-
: messages.promptWaiting
|
|
104
|
+
? buildWaitingBody(event, messages, excerpt, now)
|
|
77
105
|
: excerpt
|
|
78
106
|
? messages.completionWithExcerpt.replace('{excerpt}', excerpt)
|
|
79
107
|
: messages.completion;
|
|
@@ -83,8 +111,12 @@ function buildPushPayload(event, locale = i18n_config_1.DEFAULT_LOCALE, now = Da
|
|
|
83
111
|
body,
|
|
84
112
|
worktreeId: event.worktreeId,
|
|
85
113
|
url: `/worktrees/${event.worktreeId}`,
|
|
114
|
+
// Unchanged by #1790, and deliberately: the escalation carries the same tag
|
|
115
|
+
// as the notification it follows up, so the Service Worker replaces the
|
|
116
|
+
// stale one instead of stacking a second card for the same wait.
|
|
86
117
|
tag: `${event.worktreeId}:${event.kind}`,
|
|
87
118
|
timestamp: now,
|
|
119
|
+
...(event.waitingKind ? { waitingKind: event.waitingKind } : {}),
|
|
88
120
|
};
|
|
89
121
|
}
|
|
90
122
|
async function sendToOne(sub, payload) {
|
|
@@ -102,19 +134,46 @@ async function sendToOne(sub, payload) {
|
|
|
102
134
|
logger.warn('push-send-failed', { statusCode: statusCode ?? 'unknown' });
|
|
103
135
|
}
|
|
104
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Which guard applies to this event (Issue #1790).
|
|
139
|
+
*
|
|
140
|
+
* An episode-scoped waiting notification is deduped by the wait it belongs to;
|
|
141
|
+
* everything else — every completion, and any prompt event that predates the
|
|
142
|
+
* episode store — keeps the content hash and its 30 s window. Both record as
|
|
143
|
+
* they decide, so this must be called exactly once per event.
|
|
144
|
+
*/
|
|
145
|
+
function passesDedup(event) {
|
|
146
|
+
if (event.kind === 'prompt' && typeof event.waitingSince === 'number') {
|
|
147
|
+
return (0, notification_dedup_1.shouldSendWaitingPush)({
|
|
148
|
+
worktreeId: event.worktreeId,
|
|
149
|
+
instanceId: event.instanceId ?? event.agentName ?? '',
|
|
150
|
+
since: event.waitingSince,
|
|
151
|
+
escalated: event.escalated,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
return (0, notification_dedup_1.shouldSendNotification)({
|
|
155
|
+
worktreeId: event.worktreeId,
|
|
156
|
+
kind: event.kind,
|
|
157
|
+
content: event.excerpt,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
105
160
|
/**
|
|
106
161
|
* Fan out a notification to all subscriptions opted into this event's kind.
|
|
107
162
|
* Never throws — push is advisory and must not disrupt the poller. No-op when
|
|
108
163
|
* push is unconfigured, deduped, or there are no matching subscriptions.
|
|
164
|
+
*
|
|
165
|
+
* `now` is injectable because the escalation body quotes how long the wait has
|
|
166
|
+
* lasted (Issue #1790): the reminder is raised from a periodic check that knows
|
|
167
|
+
* the tick's time, and reading the clock again here would report a different
|
|
168
|
+
* elapsed time from the one that decided to send.
|
|
109
169
|
*/
|
|
110
|
-
async function notifyPushSubscribers(event) {
|
|
170
|
+
async function notifyPushSubscribers(event, now = Date.now()) {
|
|
111
171
|
try {
|
|
112
172
|
const config = (0, vapid_1.getVapidConfig)();
|
|
113
173
|
if (!config)
|
|
114
174
|
return;
|
|
115
|
-
if (!(
|
|
175
|
+
if (!passesDedup(event))
|
|
116
176
|
return;
|
|
117
|
-
}
|
|
118
177
|
const db = (0, db_instance_1.getDbInstance)();
|
|
119
178
|
const subscriptions = (0, push_subscriptions_db_1.getPushSubscriptionsForKind)(db, event.kind);
|
|
120
179
|
if (subscriptions.length === 0)
|
|
@@ -132,7 +191,7 @@ async function notifyPushSubscribers(event) {
|
|
|
132
191
|
byLocale.set(locale, [sub]);
|
|
133
192
|
}
|
|
134
193
|
await Promise.all(Array.from(byLocale, ([locale, subs]) => {
|
|
135
|
-
const payload = JSON.stringify(buildPushPayload(event, locale));
|
|
194
|
+
const payload = JSON.stringify(buildPushPayload(event, locale, now));
|
|
136
195
|
return Promise.all(subs.map((sub) => sendToOne(sub, payload)));
|
|
137
196
|
}));
|
|
138
197
|
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Send a push notification when an agent starts waiting, and one reminder if it
|
|
4
|
+
* is still waiting later (Issue #1790).
|
|
5
|
+
*
|
|
6
|
+
* ## Why this subscribes rather than detects
|
|
7
|
+
*
|
|
8
|
+
* The prompt notification used to be raised from one line inside the response
|
|
9
|
+
* poller, which made it inherit every one of that poller's boundaries: it only
|
|
10
|
+
* runs when a send-family API or Auto-Yes started it, it stops itself on the
|
|
11
|
+
* first prompt of a turn, it gives up after `MAX_POLLING_DURATION`, and it can
|
|
12
|
+
* only see waits the screen scraper classified as `isPrompt`. A wait that began
|
|
13
|
+
* after a `tmux` keystroke, a second prompt in the same turn, a wait that only
|
|
14
|
+
* the agent's own hook events reported, and a selection list were all silently
|
|
15
|
+
* unnotifiable.
|
|
16
|
+
*
|
|
17
|
+
* #1786 made the waiting edge observable exactly once, in
|
|
18
|
+
* `waiting-episode-state`, and #1788 already subscribes to it for the WebSocket
|
|
19
|
+
* frame. This module is the same subscription for push — it captures no pane,
|
|
20
|
+
* runs no detector, and keeps no "was it waiting last time?" of its own.
|
|
21
|
+
*
|
|
22
|
+
* ## The poller still notifies, and that is deliberate
|
|
23
|
+
*
|
|
24
|
+
* Contrary to the Issue's premise, the edge is *not* observed by a background
|
|
25
|
+
* process: `observeWaitingEdge`'s only caller is `worktree-status-helper`, on
|
|
26
|
+
* the worktree list / detail API probe. So the edge fires when a client is
|
|
27
|
+
* looking, and moving push onto it *alone* would have swapped one blind spot
|
|
28
|
+
* (no poller) for a worse one (nobody has the app open — the very situation a
|
|
29
|
+
* phone notification is for). The poller therefore keeps its call, and
|
|
30
|
+
* `response-checker` opens the same episode through `observeWaitingEdge` so both
|
|
31
|
+
* producers name the wait identically; `shouldSendWaitingPush` then collapses
|
|
32
|
+
* them to one notification. See the commit message for the measurement.
|
|
33
|
+
*
|
|
34
|
+
* ## Escalation
|
|
35
|
+
*
|
|
36
|
+
* There is no existing server-side sweep over waiting sessions to ride on, so
|
|
37
|
+
* this keeps a small interval of its own. It exists only while some wait is
|
|
38
|
+
* outstanding — created on the first open episode, cleared when the last one
|
|
39
|
+
* closes — so an install with nothing waiting has no timer, and one that never
|
|
40
|
+
* configured VAPID never even gets that far.
|
|
41
|
+
*
|
|
42
|
+
* Everything here is advisory: a failure must not disturb the status read that
|
|
43
|
+
* observed the edge (`emit` contains listener throws) nor the poller.
|
|
44
|
+
*
|
|
45
|
+
* @module lib/push/waiting-push-notifier
|
|
46
|
+
*/
|
|
47
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
exports.ESCALATION_TICK_MS = void 0;
|
|
49
|
+
exports.handleWaitingTransition = handleWaitingTransition;
|
|
50
|
+
exports.runEscalationTick = runEscalationTick;
|
|
51
|
+
exports.startWaitingPushNotifier = startWaitingPushNotifier;
|
|
52
|
+
exports.stopWaitingPushNotifier = stopWaitingPushNotifier;
|
|
53
|
+
exports.isWaitingPushNotifierActive = isWaitingPushNotifierActive;
|
|
54
|
+
exports.pendingEscalationCount = pendingEscalationCount;
|
|
55
|
+
const auto_yes_state_1 = require("../../lib/auto-yes-state");
|
|
56
|
+
const db_instance_1 = require("../../lib/db/db-instance");
|
|
57
|
+
const worktree_db_1 = require("../../lib/db/worktree-db");
|
|
58
|
+
const logger_1 = require("../../lib/logger");
|
|
59
|
+
const waiting_episode_state_1 = require("../../lib/session/waiting-episode-state");
|
|
60
|
+
const escalation_settings_1 = require("./escalation-settings");
|
|
61
|
+
const push_sender_1 = require("./push-sender");
|
|
62
|
+
const vapid_1 = require("./vapid");
|
|
63
|
+
const logger = (0, logger_1.createLogger)('push/waiting-notifier');
|
|
64
|
+
/** How often outstanding waits are re-checked. Minute granularity is enough. */
|
|
65
|
+
exports.ESCALATION_TICK_MS = 60_000;
|
|
66
|
+
const pending = globalThis.__waitingPushPending ??
|
|
67
|
+
(globalThis.__waitingPushPending = new Map());
|
|
68
|
+
/**
|
|
69
|
+
* The worktree's display name, for the notification title.
|
|
70
|
+
*
|
|
71
|
+
* Falls back to the id rather than dropping the notification: a database that
|
|
72
|
+
* cannot answer is a reason to send a less readable title, not a reason to
|
|
73
|
+
* leave the user waiting in silence.
|
|
74
|
+
*/
|
|
75
|
+
function resolveWorktreeName(worktreeId) {
|
|
76
|
+
try {
|
|
77
|
+
return (0, worktree_db_1.getWorktreeById)((0, db_instance_1.getDbInstance)(), worktreeId)?.name ?? worktreeId;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return worktreeId;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
/** Fan one waiting notification out. Never throws. */
|
|
84
|
+
async function sendWaitingPush(wait, escalated, now) {
|
|
85
|
+
const instanceId = wait.instanceId ?? wait.cliToolId;
|
|
86
|
+
try {
|
|
87
|
+
await (0, push_sender_1.notifyPushSubscribers)({
|
|
88
|
+
worktreeId: wait.worktreeId,
|
|
89
|
+
worktreeName: resolveWorktreeName(wait.worktreeId),
|
|
90
|
+
kind: 'prompt',
|
|
91
|
+
agentName: instanceId,
|
|
92
|
+
instanceId,
|
|
93
|
+
waitingKind: wait.kind,
|
|
94
|
+
waitingSince: wait.since,
|
|
95
|
+
escalated,
|
|
96
|
+
},
|
|
97
|
+
// The deciding tick's clock, not a fresh reading: the reminder's body
|
|
98
|
+
// quotes the elapsed time this call was made on.
|
|
99
|
+
now);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
logger.warn('waiting-push-failed', {
|
|
103
|
+
worktreeId: wait.worktreeId,
|
|
104
|
+
instanceId,
|
|
105
|
+
escalated,
|
|
106
|
+
error: error instanceof Error ? error.message : String(error),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function startEscalationTimer() {
|
|
111
|
+
if (globalThis.__waitingPushEscalationTimer !== undefined)
|
|
112
|
+
return;
|
|
113
|
+
const timer = setInterval(() => {
|
|
114
|
+
runEscalationTick();
|
|
115
|
+
}, exports.ESCALATION_TICK_MS);
|
|
116
|
+
// Never hold the process open for a reminder; the server exiting is a far
|
|
117
|
+
// stronger signal than "someone might still be waiting".
|
|
118
|
+
timer.unref?.();
|
|
119
|
+
globalThis.__waitingPushEscalationTimer = timer;
|
|
120
|
+
}
|
|
121
|
+
function stopEscalationTimerIfIdle() {
|
|
122
|
+
if (pending.size > 0)
|
|
123
|
+
return;
|
|
124
|
+
const timer = globalThis.__waitingPushEscalationTimer;
|
|
125
|
+
if (timer !== undefined) {
|
|
126
|
+
clearInterval(timer);
|
|
127
|
+
globalThis.__waitingPushEscalationTimer = undefined;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Handle one crossing of the waiting edge.
|
|
132
|
+
*
|
|
133
|
+
* Exported for tests, which drive it directly rather than through the
|
|
134
|
+
* subscription so a failure points at this function and not at #1786's store.
|
|
135
|
+
*/
|
|
136
|
+
function handleWaitingTransition(transition) {
|
|
137
|
+
// Nothing downstream can do anything without VAPID keys, so an install
|
|
138
|
+
// without push does not track waits, does not read the database and does not
|
|
139
|
+
// start a timer — it is inert rather than merely quiet.
|
|
140
|
+
if (!(0, vapid_1.isPushConfigured)())
|
|
141
|
+
return;
|
|
142
|
+
const key = (0, auto_yes_state_1.buildCompositeKey)(transition.worktreeId, transition.cliToolId, transition.instanceId);
|
|
143
|
+
if (!transition.waiting || transition.since === null) {
|
|
144
|
+
pending.delete(key);
|
|
145
|
+
stopEscalationTimerIfIdle();
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
const wait = {
|
|
149
|
+
worktreeId: transition.worktreeId,
|
|
150
|
+
cliToolId: transition.cliToolId,
|
|
151
|
+
instanceId: transition.instanceId,
|
|
152
|
+
since: transition.since,
|
|
153
|
+
kind: transition.kind,
|
|
154
|
+
};
|
|
155
|
+
pending.set(key, wait);
|
|
156
|
+
startEscalationTimer();
|
|
157
|
+
void sendWaitingPush(wait, false, transition.at);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Re-notify every wait that has outlived the threshold, once each.
|
|
161
|
+
*
|
|
162
|
+
* Exported so tests can advance a fake clock instead of a real minute.
|
|
163
|
+
*/
|
|
164
|
+
function runEscalationTick(now = Date.now()) {
|
|
165
|
+
if (pending.size === 0) {
|
|
166
|
+
stopEscalationTimerIfIdle();
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const settings = (0, escalation_settings_1.getPushEscalationSettings)();
|
|
170
|
+
const thresholdMs = settings.thresholdMinutes * 60_000;
|
|
171
|
+
for (const [key, wait] of Array.from(pending)) {
|
|
172
|
+
// The episode store, not this map, is the authority on whether the wait is
|
|
173
|
+
// still going: it is written by the status probe, so an answer given in
|
|
174
|
+
// another tab — or a wait whose closing edge this module never saw — is
|
|
175
|
+
// caught here even when `pending` still lists it.
|
|
176
|
+
const episode = (0, waiting_episode_state_1.getWaitingEpisode)(wait.worktreeId, wait.cliToolId, wait.instanceId);
|
|
177
|
+
if (episode === null || episode.since !== wait.since) {
|
|
178
|
+
pending.delete(key);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (!settings.enabled)
|
|
182
|
+
continue;
|
|
183
|
+
if (now - wait.since < thresholdMs)
|
|
184
|
+
continue;
|
|
185
|
+
// Dropped before sending, not after: the reminder is once per episode, and
|
|
186
|
+
// an in-flight fan-out must not be able to earn a second one.
|
|
187
|
+
pending.delete(key);
|
|
188
|
+
void sendWaitingPush({ ...wait, kind: episode.kind ?? wait.kind }, true, now);
|
|
189
|
+
}
|
|
190
|
+
stopEscalationTimerIfIdle();
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Subscribe to the waiting edge.
|
|
194
|
+
*
|
|
195
|
+
* Idempotent by replacement, like #1788's broadcast: calling it again drops the
|
|
196
|
+
* previous subscription rather than adding a second one, so a module evaluated
|
|
197
|
+
* twice cannot double-notify.
|
|
198
|
+
*
|
|
199
|
+
* @returns The unsubscribe function (also reachable as
|
|
200
|
+
* {@link stopWaitingPushNotifier}).
|
|
201
|
+
*/
|
|
202
|
+
function startWaitingPushNotifier() {
|
|
203
|
+
stopWaitingPushNotifier();
|
|
204
|
+
const unsubscribe = (0, waiting_episode_state_1.onWaitingTransition)((transition) => {
|
|
205
|
+
handleWaitingTransition(transition);
|
|
206
|
+
});
|
|
207
|
+
globalThis.__waitingPushUnsubscribe = unsubscribe;
|
|
208
|
+
return unsubscribe;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Drop the subscription, the outstanding waits and the timer. Safe when none is
|
|
212
|
+
* active, and the seam a test uses to leave no interval behind (CI runs the
|
|
213
|
+
* whole suite in one process).
|
|
214
|
+
*/
|
|
215
|
+
function stopWaitingPushNotifier() {
|
|
216
|
+
const existing = globalThis.__waitingPushUnsubscribe;
|
|
217
|
+
if (existing) {
|
|
218
|
+
existing();
|
|
219
|
+
globalThis.__waitingPushUnsubscribe = undefined;
|
|
220
|
+
}
|
|
221
|
+
pending.clear();
|
|
222
|
+
stopEscalationTimerIfIdle();
|
|
223
|
+
}
|
|
224
|
+
/** Whether a subscription is currently active. Test seam. */
|
|
225
|
+
function isWaitingPushNotifierActive() {
|
|
226
|
+
return globalThis.__waitingPushUnsubscribe !== undefined;
|
|
227
|
+
}
|
|
228
|
+
/** How many waits are awaiting their reminder. Test seam. */
|
|
229
|
+
function pendingEscalationCount() {
|
|
230
|
+
return pending.size;
|
|
231
|
+
}
|