commandmate 0.45.0 → 0.46.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 +333 -328
- package/.next/app-path-routes-manifest.json +24 -24
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +3 -3
- package/.next/react-loadable-manifest.json +6 -6
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_not-found/page.js +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/versions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/release-notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/capabilities/route.js +1 -1
- package/.next/server/app/api/capabilities/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/browse/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/fs/recent-paths/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/hooks/agent-event/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/metrics/vibe/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/escalation/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/[relayId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/relays/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/remote/pair/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/repositories/validate-path/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/settings/default-surface-mode/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/installations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/operations/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/reindex/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/tasks/[taskId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/verification/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route.js +1 -1
- package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/clear-composer/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-reference/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +3 -3
- 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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/direct-input/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/env/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/notes/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/instances/opencode/route_client-reference-manifest.js +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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/diff/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/session/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/opencode/share/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/resolve-target/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/respond/route_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +3 -3
- package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +3 -3
- 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_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_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/git-workflow/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/[skillId]/update-plan/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tasks/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/config/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/cancel/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/[runId]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/verify/runs/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/apply-default-agents/route_client-reference-manifest.js +1 -1
- package/.next/server/app/api/worktrees/route.js +1 -1
- package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
- package/.next/server/app/login/page.js +1 -1
- 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 +1 -1
- 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.js +1 -1
- package/.next/server/app/offline/page.js.nft.json +1 -1
- package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +1 -1
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
- package/.next/server/app/repositories/page.js +2 -2
- package/.next/server/app/repositories/page.js.nft.json +1 -1
- package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
- package/.next/server/app/review/page.js +1 -1
- package/.next/server/app/review/page.js.nft.json +1 -1
- package/.next/server/app/review/page_client-reference-manifest.js +1 -1
- package/.next/server/app/sessions/page.js +1 -1
- package/.next/server/app/sessions/page.js.nft.json +1 -1
- package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/[skillId]/page.js +2 -2
- package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -1
- package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/installed/page.js +1 -1
- package/.next/server/app/skills/installed/page.js.nft.json +1 -1
- package/.next/server/app/skills/installed/page_client-reference-manifest.js +1 -1
- package/.next/server/app/skills/page.js +1 -1
- package/.next/server/app/skills/page.js.nft.json +1 -1
- package/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/page.js +12 -9
- package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page.js +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
- package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +24 -24
- package/.next/server/chunks/1341.js +1 -1
- package/.next/server/chunks/1501.js +2 -2
- package/.next/server/chunks/2119.js +1 -1
- package/.next/server/chunks/2283.js +15 -13
- package/.next/server/chunks/2335.js +1 -0
- package/.next/server/chunks/2404.js +4 -4
- package/.next/server/chunks/2445.js +1 -1
- package/.next/server/chunks/2460.js +1 -1
- package/.next/server/chunks/2560.js +1 -1
- package/.next/server/chunks/3543.js +1 -1
- package/.next/server/chunks/3945.js +1 -1
- package/.next/server/chunks/4072.js +15 -0
- package/.next/server/chunks/4207.js +1 -1
- package/.next/server/chunks/{4802.js → 4243.js} +1 -1
- package/.next/server/chunks/4718.js +3 -3
- package/.next/server/chunks/4837.js +3 -3
- package/.next/server/chunks/5209.js +1 -1
- package/.next/server/chunks/5625.js +2 -2
- package/.next/server/chunks/6130.js +1 -1
- package/.next/server/chunks/6345.js +1 -0
- package/.next/server/chunks/6401.js +1 -1
- package/.next/server/chunks/6722.js +1 -0
- package/.next/server/chunks/8098.js +1 -1
- package/.next/server/chunks/8356.js +1 -1
- package/.next/server/chunks/8581.js +25 -29
- package/.next/server/chunks/8728.js +1 -1
- package/.next/server/chunks/8800.js +4 -4
- package/.next/server/chunks/9731.js +1 -1
- package/.next/server/chunks/9862.js +1 -0
- 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/_error.js +2 -2
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{7485.8a2a9d7c5396aa26.js → 1111.5ab4f0ffb0d944e5.js} +2 -2
- package/.next/static/chunks/{2407-dd4a0f04f1349221.js → 2407-acb644c5487e1720.js} +1 -1
- package/.next/static/chunks/{2619-a305ad4810f1393a.js → 2619-04bc32f026a0d946.js} +1 -1
- package/.next/static/chunks/2717.21abf5b6bbd45520.js +1 -0
- package/.next/static/chunks/2770-db80aedf6384d594.js +1 -0
- package/.next/static/chunks/2863-6a07ec82fb52f4dd.js +1 -0
- package/.next/static/chunks/3201-c01f1feed69020e6.js +1 -0
- package/.next/static/chunks/3662-5a27ee39a3ecba49.js +1 -0
- package/.next/static/chunks/4541-b0ce0bf829ae79b7.js +1 -0
- package/.next/static/chunks/4768-ad6f82f034f21eae.js +1 -0
- package/.next/static/chunks/5371-a94ed618148287a0.js +1 -0
- package/.next/static/chunks/5794-947fb4934d8be193.js +1 -0
- package/.next/static/chunks/5927-54315d21f323e204.js +1 -0
- package/.next/static/chunks/602-25e45a2422d2a3ea.js +1 -0
- package/.next/static/chunks/6288-09feba367cc2c65e.js +1 -0
- package/.next/static/chunks/6606-02ddc006686a6b7d.js +1 -0
- package/.next/static/chunks/6654-f3534f35f16644bc.js +1 -0
- package/.next/static/chunks/7730-011e137be64403ae.js +1 -0
- package/.next/static/chunks/8165-263172c17ae8e8c3.js +1 -0
- package/.next/static/chunks/8606-cf6bdbff44a764cf.js +1 -0
- package/.next/static/chunks/934-a37509667baa86ee.js +1 -0
- package/.next/static/chunks/9465-e5a351baa941f31b.js +1 -0
- package/.next/static/chunks/953.31c52a251deda22d.js +1 -0
- package/.next/static/chunks/app/layout-ae30ce63569c22be.js +1 -0
- package/.next/static/chunks/app/repositories/page-71f5a5ac29b0370d.js +1 -0
- package/.next/static/chunks/app/review/page-e2fd4a590646a2d8.js +1 -0
- package/.next/static/chunks/app/sessions/page-9859ed61e93e6890.js +1 -0
- package/.next/static/chunks/app/skills/[skillId]/page-52ba58712faf3378.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-9cf1ecc59e36a004.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/page-2eb1d0fd0a077b7e.js +1 -0
- package/.next/static/chunks/app/worktrees/[id]/terminal/{page-c601f3b3ece6557e.js → page-373ea37b16d930c7.js} +1 -1
- package/.next/static/chunks/{webpack-165d8df9acd1c5d4.js → webpack-c0b821f340afdebf.js} +1 -1
- package/.next/static/css/743f79ff19ab91e9.css +1 -0
- package/.next/trace +13 -13
- package/dist/server/locales/en/worktree.json +48 -17
- package/dist/server/locales/ja/worktree.json +48 -17
- package/dist/server/src/config/activity-bar-config.js +56 -9
- package/dist/server/src/lib/auto-yes-poller.js +16 -163
- package/dist/server/src/lib/polling/auto-yes-enter-fallback-state.js +1 -1
- package/dist/server/src/lib/polling/auto-yes-poller-state.js +52 -0
- package/dist/server/src/lib/polling/auto-yes-prompt-suppression.js +125 -0
- package/dist/server/src/lib/polling/prompt-dedup-state.js +26 -7
- package/dist/server/src/lib/polling/prompt-dedup.js +125 -6
- package/dist/server/src/lib/polling/response-checker.js +53 -2
- package/dist/server/src/lib/polling/response-dedup.js +159 -14
- package/dist/server/src/lib/polling/response-poller-core.js +47 -26
- package/dist/server/src/lib/session/next-action-helper.js +2 -15
- package/dist/server/src/lib/verification/env-clean-gate.js +14 -1
- package/dist/server/src/lib/verification/gate-runner.js +17 -11
- package/dist/server/src/lib/verification/scope-gate.js +169 -3
- package/dist/server/src/types/sidebar.js +1 -0
- package/docs/en/architecture.md +26 -14
- package/docs/en/user-guide/webapp-guide.md +31 -18
- package/package.json +1 -1
- package/release-notes/0.45.1.json +38 -0
- package/release-notes/0.46.0.json +110 -0
- package/.next/server/chunks/1674.js +0 -15
- package/.next/server/chunks/364.js +0 -1
- package/.next/server/chunks/488.js +0 -1
- package/.next/server/chunks/5326.js +0 -1
- package/.next/server/chunks/6927.js +0 -1
- package/.next/static/chunks/1642-767aed8e7c61ef7f.js +0 -1
- package/.next/static/chunks/2053-390e77fce43b555c.js +0 -1
- package/.next/static/chunks/2770-827a64760bab8a3a.js +0 -1
- package/.next/static/chunks/3922.f45dcfc1e7da552a.js +0 -1
- package/.next/static/chunks/4727-5d695d71e3fdf97b.js +0 -1
- package/.next/static/chunks/4768-fc0aa1d0891cac08.js +0 -1
- package/.next/static/chunks/5521-c358c31f60e5e689.js +0 -1
- package/.next/static/chunks/6192-a67df090838b9aad.js +0 -1
- package/.next/static/chunks/6322-f1b30ed0ee43518f.js +0 -1
- package/.next/static/chunks/6654-ac431270fac1a283.js +0 -1
- package/.next/static/chunks/8165-3525fb42f1b4976e.js +0 -1
- package/.next/static/chunks/8283-26ad31a4670ea52d.js +0 -1
- package/.next/static/chunks/8318-01e7d1e5ad0a15a3.js +0 -1
- package/.next/static/chunks/8566-aeda747542072ace.js +0 -1
- package/.next/static/chunks/8606-79c36d4c204bbd38.js +0 -1
- package/.next/static/chunks/8811-29eaa24237f48558.js +0 -1
- package/.next/static/chunks/953.19e4c8178c9eac4c.js +0 -1
- package/.next/static/chunks/9619-6c17a271f7f98fbb.js +0 -1
- package/.next/static/chunks/998-2eb5883186abd0bd.js +0 -1
- package/.next/static/chunks/app/layout-07d040cb3d3ea657.js +0 -1
- package/.next/static/chunks/app/repositories/page-6f7511f4ac8449e2.js +0 -1
- package/.next/static/chunks/app/review/page-95f749caae382f46.js +0 -1
- package/.next/static/chunks/app/sessions/page-2af68c63211c751f.js +0 -1
- package/.next/static/chunks/app/skills/[skillId]/page-9ee7a381636e60cb.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/files/[...path]/page-5445205c8dd80109.js +0 -1
- package/.next/static/chunks/app/worktrees/[id]/page-35f0e31a725d1c89.js +0 -1
- package/.next/static/css/057f64a65726c439.css +0 -1
- /package/.next/static/{TPWbZB3zBp3Zv_eFEOlmt → zI2nQ6WKboSbFbMF4EtrJ}/_buildManifest.js +0 -0
- /package/.next/static/{TPWbZB3zBp3Zv_eFEOlmt → zI2nQ6WKboSbFbMF4EtrJ}/_ssgManifest.js +0 -0
|
@@ -6,15 +6,54 @@
|
|
|
6
6
|
* Uses SHA-256 content hash with an in-memory cache (Map<pollerKey, hash>).
|
|
7
7
|
* Design decision [DR1-006]: In-memory only (no DB layer).
|
|
8
8
|
* Process restart may cause a single duplicate, which is acceptable (KISS).
|
|
9
|
+
*
|
|
10
|
+
* ## How often the skip says so (Issue #3538)
|
|
11
|
+
*
|
|
12
|
+
* A full-screen TUI (copilot, opencode) keeps polling while it sits on a
|
|
13
|
+
* prompt, so the same prompt is a duplicate on every 2 s tick until it is
|
|
14
|
+
* answered, and `duplicate-prompt-skipped` used to be logged on each of them.
|
|
15
|
+
* The run of duplicate ticks is counted here, the same way `response-dedup`
|
|
16
|
+
* counts `duplicate-response-skipped` (#3519): the line is written on the first
|
|
17
|
+
* tick of a run and then once per {@link DUPLICATE_PROMPT_SKIP_LOG_TICK_INTERVAL}
|
|
18
|
+
* ticks. The count is about one particular cached hash, so it never outlives
|
|
19
|
+
* it — the functions below that drop or move the hash drop or move the count
|
|
20
|
+
* too. The one exception runs the other way: a tick that reads a frame with no
|
|
21
|
+
* live prompt on it ends the run without touching the hash
|
|
22
|
+
* ({@link resetDuplicatePromptSkipStreak}), because the prompt left the screen
|
|
23
|
+
* while the guard still has to keep it from being saved twice. A returning
|
|
24
|
+
* prompt is then still suppressed, but its first duplicate logs as the first
|
|
25
|
+
* of a new run.
|
|
26
|
+
*
|
|
27
|
+
* Only the log line is thinned. `recordPromptDedupSkip` (#1695) is still called
|
|
28
|
+
* on every duplicate tick; its tally is what `capture --json` reports.
|
|
9
29
|
*/
|
|
10
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
+
exports.DUPLICATE_PROMPT_SKIP_LOG_TICK_INTERVAL = void 0;
|
|
11
32
|
exports.isDuplicatePrompt = isDuplicatePrompt;
|
|
33
|
+
exports.claimDuplicatePromptSkipLog = claimDuplicatePromptSkipLog;
|
|
34
|
+
exports.resetDuplicatePromptSkipStreak = resetDuplicatePromptSkipStreak;
|
|
12
35
|
exports.clearPromptHashCache = clearPromptHashCache;
|
|
13
36
|
exports.renamePromptHashCacheKey = renamePromptHashCacheKey;
|
|
37
|
+
exports.renamePromptHashCacheKeys = renamePromptHashCacheKeys;
|
|
14
38
|
exports.normalizePromptForDedup = normalizePromptForDedup;
|
|
15
39
|
const crypto_1 = require("crypto");
|
|
16
40
|
const global_state_1 = require("../global-state");
|
|
41
|
+
const response_dedup_1 = require("./response-dedup");
|
|
17
42
|
const promptHashCache = (0, global_state_1.getOrInitGlobal)('__promptHashCache', () => new Map());
|
|
43
|
+
/**
|
|
44
|
+
* In-memory cache: pollerKey -> how many duplicate ticks in a row the current
|
|
45
|
+
* cached prompt hash has been skipped (Issue #3538). Absence means none yet.
|
|
46
|
+
*
|
|
47
|
+
* On `globalThis` for the same reason `promptHashCache` is, and cleared and
|
|
48
|
+
* moved at exactly the same moments — see the module comment.
|
|
49
|
+
*/
|
|
50
|
+
const duplicatePromptSkipStreak = (0, global_state_1.getOrInitGlobal)('__duplicatePromptSkipStreak', () => new Map());
|
|
51
|
+
/**
|
|
52
|
+
* How many duplicate ticks separate two `duplicate-prompt-skipped` lines
|
|
53
|
+
* (Issue #3538). Shared with `duplicate-response-skipped` (#3519): one line a
|
|
54
|
+
* minute at the poller's 2 s tick.
|
|
55
|
+
*/
|
|
56
|
+
exports.DUPLICATE_PROMPT_SKIP_LOG_TICK_INTERVAL = response_dedup_1.DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL;
|
|
18
57
|
/**
|
|
19
58
|
* Check if the given prompt content is a duplicate of the last saved prompt
|
|
20
59
|
* for the same pollerKey. If not a duplicate, updates the cache.
|
|
@@ -29,8 +68,50 @@ function isDuplicatePrompt(pollerKey, content) {
|
|
|
29
68
|
return true;
|
|
30
69
|
}
|
|
31
70
|
promptHashCache.set(pollerKey, hash);
|
|
71
|
+
// Issue #3538: a new prompt starts a new run of duplicate ticks.
|
|
72
|
+
duplicatePromptSkipStreak.delete(pollerKey);
|
|
32
73
|
return false;
|
|
33
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Count one duplicate prompt tick for this pollerKey and say whether it should
|
|
77
|
+
* be logged (Issue #3538).
|
|
78
|
+
*
|
|
79
|
+
* A claim: it advances the count, so call it exactly once per duplicate tick.
|
|
80
|
+
* Logs on the first tick of a run and then on every
|
|
81
|
+
* {@link DUPLICATE_PROMPT_SKIP_LOG_TICK_INTERVAL}th tick after it (ticks 1,
|
|
82
|
+
* 1+N, 1+2N, …).
|
|
83
|
+
*
|
|
84
|
+
* @param pollerKey - Poller key ("worktreeId:cliToolId")
|
|
85
|
+
* @returns Whether to log, the run length so far, and the ticks left unlogged
|
|
86
|
+
* since the previous line
|
|
87
|
+
*/
|
|
88
|
+
function claimDuplicatePromptSkipLog(pollerKey) {
|
|
89
|
+
const consecutive = (duplicatePromptSkipStreak.get(pollerKey) ?? 0) + 1;
|
|
90
|
+
duplicatePromptSkipStreak.set(pollerKey, consecutive);
|
|
91
|
+
const log = (consecutive - 1) % exports.DUPLICATE_PROMPT_SKIP_LOG_TICK_INTERVAL === 0;
|
|
92
|
+
const suppressed = consecutive === 1 ? 0 : exports.DUPLICATE_PROMPT_SKIP_LOG_TICK_INTERVAL - 1;
|
|
93
|
+
return { log, consecutive, suppressed };
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* End the current run of duplicate prompt ticks for this pollerKey without
|
|
97
|
+
* touching the cached hash (Issue #3538).
|
|
98
|
+
*
|
|
99
|
+
* Called by `response-checker` in two places: `extractCompletedTurn`, when the
|
|
100
|
+
* frame was read and is unfinished (a working screen), and `checkForResponse`,
|
|
101
|
+
* when a finished frame carries no live prompt (a reply). The prompt is no
|
|
102
|
+
* longer on screen, so if the same prompt comes back the next duplicate is the
|
|
103
|
+
* first of a new run and logs. Not called on a tick that skipped extraction on
|
|
104
|
+
* the line count (a null result) or returned on the cursor, nor on a tick that
|
|
105
|
+
* ended before extraction: none of them says the prompt has left the screen,
|
|
106
|
+
* so the run carries on through them. The hash stays: whether the
|
|
107
|
+
* returning prompt is saved again is the guard's question (#565), and this
|
|
108
|
+
* Issue only thins the log line.
|
|
109
|
+
*
|
|
110
|
+
* @param pollerKey - Poller key ("worktreeId:cliToolId")
|
|
111
|
+
*/
|
|
112
|
+
function resetDuplicatePromptSkipStreak(pollerKey) {
|
|
113
|
+
duplicatePromptSkipStreak.delete(pollerKey);
|
|
114
|
+
}
|
|
34
115
|
/**
|
|
35
116
|
* Clear the prompt hash cache for a specific pollerKey.
|
|
36
117
|
* Called during session cleanup / stopPolling.
|
|
@@ -39,6 +120,8 @@ function isDuplicatePrompt(pollerKey, content) {
|
|
|
39
120
|
*/
|
|
40
121
|
function clearPromptHashCache(pollerKey) {
|
|
41
122
|
promptHashCache.delete(pollerKey);
|
|
123
|
+
// Issue #3538: the skip count is about the same hash.
|
|
124
|
+
duplicatePromptSkipStreak.delete(pollerKey);
|
|
42
125
|
}
|
|
43
126
|
/**
|
|
44
127
|
* Move the cached hash from one pollerKey to another.
|
|
@@ -48,18 +131,54 @@ function clearPromptHashCache(pollerKey) {
|
|
|
48
131
|
* re-save the prompt it is currently sitting on as a fresh message, which is
|
|
49
132
|
* the duplicate this module exists to prevent.
|
|
50
133
|
*
|
|
51
|
-
* No-op when nothing is cached under `oldKey`.
|
|
134
|
+
* No-op when nothing is cached under `oldKey`. A batch of renames whose keys
|
|
135
|
+
* overlap must go through {@link renamePromptHashCacheKeys} instead.
|
|
52
136
|
*
|
|
53
137
|
* @param oldKey - Poller key the cache entry lives under
|
|
54
138
|
* @param newKey - Poller key it should live under
|
|
55
139
|
*/
|
|
56
140
|
function renamePromptHashCacheKey(oldKey, newKey) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
141
|
+
renamePromptHashCacheKeys([{ oldKey, newKey }]);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Move the prompt hash and its skip count for a whole batch of pollerKeys
|
|
145
|
+
* (Issue #3553).
|
|
146
|
+
*
|
|
147
|
+
* Every source key is lifted before any destination is written, so a swap
|
|
148
|
+
* (A→B, B→A) or a chain (A→B→C) cannot overwrite a source that has not moved
|
|
149
|
+
* yet. Per pair this is exactly {@link renamePromptHashCacheKey}: nothing
|
|
150
|
+
* happens at the destination when the source held no hash.
|
|
151
|
+
*
|
|
152
|
+
* @param renames - Poller key moves applied together; `oldKey === newKey` is ignored
|
|
153
|
+
*/
|
|
154
|
+
function renamePromptHashCacheKeys(renames) {
|
|
155
|
+
const lifted = [];
|
|
156
|
+
for (const { oldKey, newKey } of renames) {
|
|
157
|
+
if (oldKey === newKey)
|
|
158
|
+
continue;
|
|
159
|
+
lifted.push({
|
|
160
|
+
newKey,
|
|
161
|
+
hash: promptHashCache.get(oldKey),
|
|
162
|
+
streak: duplicatePromptSkipStreak.get(oldKey),
|
|
163
|
+
});
|
|
164
|
+
promptHashCache.delete(oldKey);
|
|
165
|
+
duplicatePromptSkipStreak.delete(oldKey);
|
|
166
|
+
}
|
|
167
|
+
for (const { newKey, hash, streak } of lifted) {
|
|
168
|
+
if (hash === undefined)
|
|
169
|
+
continue;
|
|
62
170
|
promptHashCache.set(newKey, hash);
|
|
171
|
+
// Issue #3538: the skip count moves with the hash, so a rename mid-run does
|
|
172
|
+
// not restart the thinning and log as if a new run had begun. Whenever the
|
|
173
|
+
// hash under `newKey` is replaced, so is its count — a count left over from
|
|
174
|
+
// the hash that was there before is about a different prompt.
|
|
175
|
+
if (streak !== undefined) {
|
|
176
|
+
duplicatePromptSkipStreak.set(newKey, streak);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
duplicatePromptSkipStreak.delete(newKey);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
63
182
|
}
|
|
64
183
|
/**
|
|
65
184
|
* Normalize prompt content before deduplication check.
|
|
@@ -491,6 +491,20 @@ function extractCompletedTurn(ctx, output, lastCapturedLine) {
|
|
|
491
491
|
// Extract response
|
|
492
492
|
const result = extractResponse(output, lastCapturedLine, cliToolId, tmux_capture_cache_1.CACHE_MAX_CAPTURE_LINES);
|
|
493
493
|
if (!result || !result.isComplete) {
|
|
494
|
+
// Issue #3538: an unfinished frame was read and carries no live prompt (the
|
|
495
|
+
// early prompt check in `extractResponse` would have returned it complete),
|
|
496
|
+
// so a run of duplicate prompt ticks is over; the hash is kept — see the
|
|
497
|
+
// helper. Only when the frame WAS read: a null result is extraction being
|
|
498
|
+
// skipped on the line count ("no new output"), which says nothing about
|
|
499
|
+
// whether the prompt is still on screen, and neither do the cursor returns
|
|
500
|
+
// further down.
|
|
501
|
+
//
|
|
502
|
+
// Issue #3552: the same frame ends a run of duplicate response ticks for
|
|
503
|
+
// the same reason — an unfinished frame is not the saved reply.
|
|
504
|
+
if (result) {
|
|
505
|
+
(0, prompt_dedup_1.resetDuplicatePromptSkipStreak)(pollerKey);
|
|
506
|
+
(0, response_dedup_1.resetDuplicateResponseSkipStreak)(pollerKey);
|
|
507
|
+
}
|
|
494
508
|
// DR-004 windowing: Only check tail lines
|
|
495
509
|
const { thinkingPattern } = (0, cli_patterns_1.getCliToolPatterns)(cliToolId);
|
|
496
510
|
const cleanOutput = (0, cli_patterns_1.stripAnsi)(output);
|
|
@@ -565,7 +579,19 @@ function savePromptMessage(ctx, promptDetection, result, isFullScreenTui) {
|
|
|
565
579
|
// classified (#1676) look identical from the CLI — both say "nothing was
|
|
566
580
|
// recorded". Count the skip so the payload can tell them apart.
|
|
567
581
|
(0, prompt_dedup_state_1.recordPromptDedupSkip)(worktreeId, cliToolId, instanceId);
|
|
568
|
-
|
|
582
|
+
// Issue #3538: the tally above is counted on every tick; the log line is
|
|
583
|
+
// not. A full-screen TUI sits on its prompt for as long as it stays
|
|
584
|
+
// unanswered, a duplicate every 2 s. The first tick of a run logs exactly
|
|
585
|
+
// as before; after that one line per `DUPLICATE_PROMPT_SKIP_LOG_TICK_INTERVAL`
|
|
586
|
+
// ticks, with the run length and how many ticks went unlogged (#3519).
|
|
587
|
+
const skipLog = (0, prompt_dedup_1.claimDuplicatePromptSkipLog)(pollerKey);
|
|
588
|
+
if (skipLog.log) {
|
|
589
|
+
logger.info('duplicate-prompt-skipped', {
|
|
590
|
+
worktreeId,
|
|
591
|
+
cliToolId,
|
|
592
|
+
...(skipLog.consecutive > 1 ? { consecutive: skipLog.consecutive, suppressed: skipLog.suppressed } : {}),
|
|
593
|
+
});
|
|
594
|
+
}
|
|
569
595
|
return false;
|
|
570
596
|
}
|
|
571
597
|
// Issue #571: Clean TUI decorations from Copilot prompt content before saving
|
|
@@ -723,7 +749,21 @@ async function recheckDuplicateResponse(ctx, result, claudeMetadata) {
|
|
|
723
749
|
// logged nothing at all, so a reply that never reached History left no
|
|
724
750
|
// trace anywhere. Same action name shape as its sibling so both skips
|
|
725
751
|
// are found by one grep.
|
|
726
|
-
|
|
752
|
+
//
|
|
753
|
+
// Issue #3519: but not on every tick. A finished screen that stays up is a
|
|
754
|
+
// duplicate on each of the cycle's 900 ticks, and logging all of them was
|
|
755
|
+
// 51,933 lines a day. The first tick of a run logs exactly as before; after
|
|
756
|
+
// that one line per `DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL` ticks, with
|
|
757
|
+
// the run length and how many ticks went unlogged since the last line.
|
|
758
|
+
const skipLog = (0, response_dedup_1.claimDuplicateResponseSkipLog)(pollerKey);
|
|
759
|
+
if (skipLog.log) {
|
|
760
|
+
logger.info('duplicate-response-skipped', {
|
|
761
|
+
worktreeId,
|
|
762
|
+
cliToolId,
|
|
763
|
+
instanceId: resolvedInstanceId,
|
|
764
|
+
...(skipLog.consecutive > 1 ? { consecutive: skipLog.consecutive, suppressed: skipLog.suppressed } : {}),
|
|
765
|
+
});
|
|
766
|
+
}
|
|
727
767
|
(0, db_1.updateSessionState)(db, worktreeId, cliToolId, result.lineCount, resolvedInstanceId);
|
|
728
768
|
// Issue #2399: the skip above is about the SCREEN, and until this Issue
|
|
729
769
|
// it also ended the tick for the TRANSCRIPT READER 100 lines below —
|
|
@@ -1154,10 +1194,19 @@ async function checkForResponse(worktreeId, cliToolId, instanceId) {
|
|
|
1154
1194
|
// has lost the position `detectDialog` judges by.
|
|
1155
1195
|
const promptIsLive = promptDetection.isPrompt && (0, response_checker_dialog_gate_1.isNumberedDialogVouched)(cliToolId, promptDetection, output);
|
|
1156
1196
|
if (promptIsLive) {
|
|
1197
|
+
// Issue #3552: a live prompt is not the saved reply, so a run of
|
|
1198
|
+
// duplicate response ticks is over; the response hash is kept (a resume
|
|
1199
|
+
// after the answer must not re-save the reply underneath, #2230).
|
|
1200
|
+
(0, response_dedup_1.resetDuplicateResponseSkipStreak)(pollerKey);
|
|
1157
1201
|
return savePromptMessage(ctx, promptDetection, result, isFullScreenTui);
|
|
1158
1202
|
}
|
|
1203
|
+
// Issue #3538: a finished frame without a live prompt ends the run of
|
|
1204
|
+
// duplicate prompt ticks, as an unfinished one does in `extractCompletedTurn`.
|
|
1205
|
+
(0, prompt_dedup_1.resetDuplicatePromptSkipStreak)(pollerKey);
|
|
1159
1206
|
// Validate response content is not empty
|
|
1160
1207
|
if (!result.response || result.response.trim() === '') {
|
|
1208
|
+
// Issue #3552: an empty response is not the saved reply either.
|
|
1209
|
+
(0, response_dedup_1.resetDuplicateResponseSkipStreak)(pollerKey);
|
|
1161
1210
|
(0, db_1.updateSessionState)(db, worktreeId, cliToolId, result.lineCount, resolvedInstanceId);
|
|
1162
1211
|
return false;
|
|
1163
1212
|
}
|
|
@@ -1168,6 +1217,8 @@ async function checkForResponse(worktreeId, cliToolId, instanceId) {
|
|
|
1168
1217
|
const cleanedResponse = cleanCompletedResponse(cliToolId, result, pollerKey);
|
|
1169
1218
|
// If cleaned response is empty or just "[No content]", skip saving
|
|
1170
1219
|
if (!cleanedResponse || cleanedResponse.trim() === '' || cleanedResponse === '[No content]') {
|
|
1220
|
+
// Issue #3552: nor is one that cleans down to nothing.
|
|
1221
|
+
(0, response_dedup_1.resetDuplicateResponseSkipStreak)(pollerKey);
|
|
1171
1222
|
(0, db_1.updateSessionState)(db, worktreeId, cliToolId, result.lineCount, resolvedInstanceId);
|
|
1172
1223
|
(0, db_1.clearInProgressMessageId)(db, worktreeId, cliToolId, resolvedInstanceId);
|
|
1173
1224
|
return false;
|
|
@@ -39,15 +39,29 @@
|
|
|
39
39
|
* hash, and the worktree rename all have to treat the two the same, and the
|
|
40
40
|
* only way to guarantee that without touching `response-poller-core` (which
|
|
41
41
|
* owns those three calls) is for one function to clear both.
|
|
42
|
+
*
|
|
43
|
+
* ## The third cache: how often the skip says so (#3519)
|
|
44
|
+
*
|
|
45
|
+
* The skip logs `duplicate-response-skipped` so a reply missing from History
|
|
46
|
+
* leaves a grep-able trace (#1695). Logged on every tick, a screen that stays
|
|
47
|
+
* up writes that line every 2 s for the whole cycle — 51,933 lines in 24 h,
|
|
48
|
+
* 80% of the server log. The run of duplicate ticks is counted here so the line
|
|
49
|
+
* is written on the first tick of a run and then once per
|
|
50
|
+
* {@link DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL} ticks. The count is about
|
|
51
|
+
* one particular cached hash, so it lives and dies with it for the same reason
|
|
52
|
+
* the recheck does.
|
|
42
53
|
*/
|
|
43
54
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
-
exports.STRUCTURED_HISTORY_RECHECK_TICK_INTERVAL = void 0;
|
|
55
|
+
exports.DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL = exports.STRUCTURED_HISTORY_RECHECK_TICK_INTERVAL = void 0;
|
|
45
56
|
exports.isDuplicateResponse = isDuplicateResponse;
|
|
57
|
+
exports.claimDuplicateResponseSkipLog = claimDuplicateResponseSkipLog;
|
|
58
|
+
exports.resetDuplicateResponseSkipStreak = resetDuplicateResponseSkipStreak;
|
|
46
59
|
exports.markStructuredHistoryRecheckPending = markStructuredHistoryRecheckPending;
|
|
47
60
|
exports.settleStructuredHistoryRecheck = settleStructuredHistoryRecheck;
|
|
48
61
|
exports.claimStructuredHistoryRecheck = claimStructuredHistoryRecheck;
|
|
49
62
|
exports.clearResponseHashCache = clearResponseHashCache;
|
|
50
63
|
exports.renameResponseHashCacheKey = renameResponseHashCacheKey;
|
|
64
|
+
exports.renameResponseHashCacheKeys = renameResponseHashCacheKeys;
|
|
51
65
|
const crypto_1 = require("crypto");
|
|
52
66
|
const global_state_1 = require("../global-state");
|
|
53
67
|
const responseHashCache = (0, global_state_1.getOrInitGlobal)('__responseHashCache', () => new Map());
|
|
@@ -79,6 +93,27 @@ const structuredHistoryRecheckCache = (0, global_state_1.getOrInitGlobal)('__str
|
|
|
79
93
|
* or the cycle ends, the entry is gone.
|
|
80
94
|
*/
|
|
81
95
|
exports.STRUCTURED_HISTORY_RECHECK_TICK_INTERVAL = 3;
|
|
96
|
+
/**
|
|
97
|
+
* In-memory cache: pollerKey -> how many duplicate ticks in a row the current
|
|
98
|
+
* cached hash has been skipped (Issue #3519). Absence means none yet.
|
|
99
|
+
*
|
|
100
|
+
* On `globalThis` for the same reason `responseHashCache` is, and cleared and
|
|
101
|
+
* moved at exactly the same moments — see the module comment. A new
|
|
102
|
+
* (non-duplicate) response restarts it in {@link isDuplicateResponse}, and a
|
|
103
|
+
* tick that reads the frame and finds no reply on it ends the run without
|
|
104
|
+
* touching the hash — see {@link resetDuplicateResponseSkipStreak} (#3552).
|
|
105
|
+
*/
|
|
106
|
+
const duplicateResponseSkipStreak = (0, global_state_1.getOrInitGlobal)('__duplicateResponseSkipStreak', () => new Map());
|
|
107
|
+
/**
|
|
108
|
+
* How many duplicate ticks separate two `duplicate-response-skipped` lines
|
|
109
|
+
* (Issue #3519).
|
|
110
|
+
*
|
|
111
|
+
* At the poller's 2 s tick this is one line a minute while a finished screen
|
|
112
|
+
* stays up, so a 900-tick cycle writes 30 lines instead of 899. The first tick
|
|
113
|
+
* of a run always logs, so the #1695 trace — "this reply was skipped, at this
|
|
114
|
+
* time" — is still there for every run; what is dropped is the repetition.
|
|
115
|
+
*/
|
|
116
|
+
exports.DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL = 30;
|
|
82
117
|
/**
|
|
83
118
|
* Check whether the given response content was already saved during the current
|
|
84
119
|
* polling cycle for the same pollerKey. If it is new, updates the cache.
|
|
@@ -93,8 +128,52 @@ function isDuplicateResponse(pollerKey, content) {
|
|
|
93
128
|
return true;
|
|
94
129
|
}
|
|
95
130
|
responseHashCache.set(pollerKey, hash);
|
|
131
|
+
// Issue #3519: a new response starts a new run of duplicate ticks.
|
|
132
|
+
duplicateResponseSkipStreak.delete(pollerKey);
|
|
96
133
|
return false;
|
|
97
134
|
}
|
|
135
|
+
/**
|
|
136
|
+
* Count one duplicate tick for this pollerKey and say whether it should be
|
|
137
|
+
* logged (Issue #3519).
|
|
138
|
+
*
|
|
139
|
+
* A claim, like {@link claimStructuredHistoryRecheck}: it advances the count, so
|
|
140
|
+
* call it exactly once per duplicate tick. Logs on the first tick of a run and
|
|
141
|
+
* then on every {@link DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL}th tick after
|
|
142
|
+
* it (ticks 1, 1+N, 1+2N, …).
|
|
143
|
+
*
|
|
144
|
+
* @param pollerKey - Poller key ("worktreeId:instanceId")
|
|
145
|
+
* @returns Whether to log, the run length so far, and the ticks left unlogged
|
|
146
|
+
* since the previous line
|
|
147
|
+
*/
|
|
148
|
+
function claimDuplicateResponseSkipLog(pollerKey) {
|
|
149
|
+
const consecutive = (duplicateResponseSkipStreak.get(pollerKey) ?? 0) + 1;
|
|
150
|
+
duplicateResponseSkipStreak.set(pollerKey, consecutive);
|
|
151
|
+
const log = (consecutive - 1) % exports.DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL === 0;
|
|
152
|
+
const suppressed = consecutive === 1 ? 0 : exports.DUPLICATE_RESPONSE_SKIP_LOG_TICK_INTERVAL - 1;
|
|
153
|
+
return { log, consecutive, suppressed };
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* End the current run of duplicate response ticks for this pollerKey without
|
|
157
|
+
* touching the cached hash (Issue #3552).
|
|
158
|
+
*
|
|
159
|
+
* Called by `response-checker` on the ticks that read the frame and decide it
|
|
160
|
+
* is not a duplicate of the saved reply: an unfinished frame
|
|
161
|
+
* (`extractCompletedTurn`), a finished frame with a live prompt on it, and a
|
|
162
|
+
* finished frame whose response is empty. The reply is no longer on screen, so
|
|
163
|
+
* if the same reply comes back the next duplicate is the first of a new run and
|
|
164
|
+
* logs. The hash stays: whether the returning reply is saved again is the
|
|
165
|
+
* guard's question (#1268), and this only thins the log line (#3519).
|
|
166
|
+
*
|
|
167
|
+
* Not called at the entrance of a finished frame — that would make every
|
|
168
|
+
* duplicate tick the first of its run — nor on a tick that skipped extraction
|
|
169
|
+
* on the line count (null) or returned on the cursor: neither says the reply
|
|
170
|
+
* has left the screen (the same judgement as #3538).
|
|
171
|
+
*
|
|
172
|
+
* @param pollerKey - Poller key ("worktreeId:instanceId")
|
|
173
|
+
*/
|
|
174
|
+
function resetDuplicateResponseSkipStreak(pollerKey) {
|
|
175
|
+
duplicateResponseSkipStreak.delete(pollerKey);
|
|
176
|
+
}
|
|
98
177
|
/**
|
|
99
178
|
* Note that the transcript reader has unfinished business for this pollerKey
|
|
100
179
|
* (Issue #2399).
|
|
@@ -177,6 +256,57 @@ function claimStructuredHistoryRecheck(pollerKey) {
|
|
|
177
256
|
function clearResponseHashCache(pollerKey) {
|
|
178
257
|
responseHashCache.delete(pollerKey);
|
|
179
258
|
structuredHistoryRecheckCache.delete(pollerKey);
|
|
259
|
+
// Issue #3519: the skip count is about the same hash.
|
|
260
|
+
duplicateResponseSkipStreak.delete(pollerKey);
|
|
261
|
+
}
|
|
262
|
+
/** Remove everything held under `key` and return it. */
|
|
263
|
+
function takeResponseDedupState(key) {
|
|
264
|
+
const state = {
|
|
265
|
+
hash: responseHashCache.get(key),
|
|
266
|
+
recheck: structuredHistoryRecheckCache.get(key),
|
|
267
|
+
streak: duplicateResponseSkipStreak.get(key),
|
|
268
|
+
};
|
|
269
|
+
responseHashCache.delete(key);
|
|
270
|
+
structuredHistoryRecheckCache.delete(key);
|
|
271
|
+
duplicateResponseSkipStreak.delete(key);
|
|
272
|
+
return state;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Write state lifted by {@link takeResponseDedupState} under `key`.
|
|
276
|
+
*
|
|
277
|
+
* `replaceRecheckWithHash` is the one difference between the batch and the
|
|
278
|
+
* single rename (Issue #3553): when a hash lands, the batch also replaces the
|
|
279
|
+
* recheck under `key` — deleting it when the source had none — so a recheck
|
|
280
|
+
* owed for a different turn is not attached to the hash that just arrived. The
|
|
281
|
+
* single rename keeps its earlier behaviour and leaves such a recheck alone.
|
|
282
|
+
*/
|
|
283
|
+
function putResponseDedupState(key, state, replaceRecheckWithHash) {
|
|
284
|
+
if (state.hash !== undefined)
|
|
285
|
+
responseHashCache.set(key, state.hash);
|
|
286
|
+
// Issue #2399: the recheck caveat moves with the hash it is about. Leaving it
|
|
287
|
+
// behind would strand a turn whose transcript is still open — the new key
|
|
288
|
+
// starts owing nothing, so every later tick returns at the dedup guard and the
|
|
289
|
+
// Markdown row is never written. It moves without a hash too: the
|
|
290
|
+
// `lineCountIsCursor` path marks it with no hash cached.
|
|
291
|
+
if (state.recheck !== undefined) {
|
|
292
|
+
structuredHistoryRecheckCache.set(key, state.recheck);
|
|
293
|
+
}
|
|
294
|
+
else if (replaceRecheckWithHash && state.hash !== undefined) {
|
|
295
|
+
structuredHistoryRecheckCache.delete(key);
|
|
296
|
+
}
|
|
297
|
+
// Issue #3519: the skip count moves with the hash too, so a rename mid-run
|
|
298
|
+
// does not restart the thinning and log as if a new run had begun.
|
|
299
|
+
// Issue #3552: whenever the hash under `newKey` is replaced, so is its count
|
|
300
|
+
// — a count left over from the hash that was there before is about a
|
|
301
|
+
// different reply (the same rule as `renamePromptHashCacheKey`, #3538).
|
|
302
|
+
if (state.hash === undefined)
|
|
303
|
+
return;
|
|
304
|
+
if (state.streak !== undefined) {
|
|
305
|
+
duplicateResponseSkipStreak.set(key, state.streak);
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
duplicateResponseSkipStreak.delete(key);
|
|
309
|
+
}
|
|
180
310
|
}
|
|
181
311
|
/**
|
|
182
312
|
* Move the cached hash from one pollerKey to another.
|
|
@@ -186,7 +316,8 @@ function clearResponseHashCache(pollerKey) {
|
|
|
186
316
|
* during THIS turn?", and the turn does not end just because the ID moved —
|
|
187
317
|
* dropping it would re-save the screen currently on display.
|
|
188
318
|
*
|
|
189
|
-
* No-op when nothing is cached under `oldKey`.
|
|
319
|
+
* No-op when nothing is cached under `oldKey`. A batch of renames whose keys
|
|
320
|
+
* overlap must go through {@link renameResponseHashCacheKeys} instead.
|
|
190
321
|
*
|
|
191
322
|
* @param oldKey - Poller key the cache entry lives under
|
|
192
323
|
* @param newKey - Poller key it should live under
|
|
@@ -194,16 +325,30 @@ function clearResponseHashCache(pollerKey) {
|
|
|
194
325
|
function renameResponseHashCacheKey(oldKey, newKey) {
|
|
195
326
|
if (oldKey === newKey)
|
|
196
327
|
return;
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
328
|
+
putResponseDedupState(newKey, takeResponseDedupState(oldKey), false);
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Move the response dedup state of a whole batch of pollerKeys (Issue #3553).
|
|
332
|
+
*
|
|
333
|
+
* Every source key is lifted before any destination is written, so a swap
|
|
334
|
+
* (A→B, B→A) or a chain (A→B→C) cannot overwrite a source that has not moved
|
|
335
|
+
* yet — calling {@link renameResponseHashCacheKey} once per pair would leave
|
|
336
|
+
* A with its own state and B empty after a swap. Each destination ends up with
|
|
337
|
+
* exactly what its source held: hash, skip count and recheck, the recheck
|
|
338
|
+
* moving even without a hash. A recheck already at the destination is
|
|
339
|
+
* replaced along with the hash, never kept beside the moved one.
|
|
340
|
+
*
|
|
341
|
+
* Pairs with `oldKey === newKey` are ignored.
|
|
342
|
+
*
|
|
343
|
+
* @param renames - Poller key moves applied together
|
|
344
|
+
*/
|
|
345
|
+
function renameResponseHashCacheKeys(renames) {
|
|
346
|
+
const lifted = [];
|
|
347
|
+
for (const { oldKey, newKey } of renames) {
|
|
348
|
+
if (oldKey === newKey)
|
|
349
|
+
continue;
|
|
350
|
+
lifted.push({ newKey, state: takeResponseDedupState(oldKey) });
|
|
351
|
+
}
|
|
352
|
+
for (const { newKey, state } of lifted)
|
|
353
|
+
putResponseDedupState(newKey, state, true);
|
|
209
354
|
}
|
|
@@ -532,8 +532,11 @@ function splitPollerKey(pollerKey) {
|
|
|
532
532
|
* one in-flight TUI response may be truncated at the rename boundary; the next
|
|
533
533
|
* turn accumulates normally.
|
|
534
534
|
*
|
|
535
|
-
* Takes the whole batch because IDs can swap (A→B, B→A)
|
|
536
|
-
* removed before any destination key is written.
|
|
535
|
+
* Takes the whole batch because IDs can swap (A→B, B→A) or chain (A→B→C):
|
|
536
|
+
* every source key is removed before any destination key is written. That
|
|
537
|
+
* includes the dedup state (Issue #3553) — of running pollers and paused chains
|
|
538
|
+
* alike — which is lifted off every source key in one pass and only then
|
|
539
|
+
* written, so a pair handled early cannot overwrite a source handled later.
|
|
537
540
|
*
|
|
538
541
|
* @param renames - Worktree ID pairs being applied
|
|
539
542
|
* @param resolveCliToolId - Maps a poller's (worktree, instance) back to its CLI
|
|
@@ -596,33 +599,21 @@ function migrateResponsePollerWorktreeIds(renames, resolveCliToolId) {
|
|
|
596
599
|
coordinator.pendingRestart.delete(move.oldKey);
|
|
597
600
|
carried.set(move.newKey, { startedAt: exports.pollingStartTimes.get(move.oldKey) });
|
|
598
601
|
exports.pollingStartTimes.delete(move.oldKey);
|
|
599
|
-
(0, prompt_dedup_1.renamePromptHashCacheKey)(move.oldKey, move.newKey);
|
|
600
|
-
(0, response_dedup_1.renameResponseHashCacheKey)(move.oldKey, move.newKey);
|
|
601
|
-
// Issue #1695: the prompt hash moved on the line above, so the guard keeps
|
|
602
|
-
// suppressing the prompt on screen under the new ID. Its tally has to move
|
|
603
|
-
// with it, or `capture --json` reports zero skips for a session that is
|
|
604
|
-
// still skipping. Old worktree ID comes back out of the key we just left.
|
|
605
|
-
const movedFrom = splitPollerKey(move.oldKey);
|
|
606
|
-
if (movedFrom) {
|
|
607
|
-
(0, prompt_dedup_state_1.renamePromptDedupSkips)(movedFrom.worktreeId, move.newWorktreeId, move.cliToolId, move.instanceId);
|
|
608
|
-
}
|
|
609
602
|
(0, tui_accumulator_1.clearTuiAccumulator)(move.oldKey);
|
|
610
603
|
}
|
|
604
|
+
// Stop the abandoned pollers before any dedup state is written: the stop
|
|
605
|
+
// clears every cache under its key, and that key can be the destination of
|
|
606
|
+
// another move in this batch (A:x paused → B:x while B:x is abandoned).
|
|
607
|
+
// Stopped afterwards, it erased the state that had just arrived (#3553).
|
|
608
|
+
// An abandoned key is never a move source, so nothing still to be moved is
|
|
609
|
+
// lost here; and the paused chains are collected after it, as before, so a
|
|
610
|
+
// pause the stop ends is not carried.
|
|
611
611
|
for (const pollerKey of abandoned) {
|
|
612
612
|
stopPollingByKey(pollerKey);
|
|
613
613
|
logger.warn('poller:migrate-abandoned', { pollerKey });
|
|
614
614
|
}
|
|
615
|
-
//
|
|
616
|
-
for
|
|
617
|
-
const startedAt = carried.get(move.newKey)?.startedAt;
|
|
618
|
-
exports.pollingStartTimes.set(move.newKey, startedAt ?? Date.now());
|
|
619
|
-
if (isFullScreenTui(move.cliToolId)) {
|
|
620
|
-
(0, tui_accumulator_1.initTuiAccumulator)(move.newKey);
|
|
621
|
-
}
|
|
622
|
-
scheduleNextResponsePoll(move.newWorktreeId, move.cliToolId, move.instanceId);
|
|
623
|
-
}
|
|
624
|
-
// Issue #2230: a chain paused on a prompt has no timer, so the loop above
|
|
625
|
-
// never sees it — but it is holding the response hash for the turn it paused
|
|
615
|
+
// Issue #2230: a chain paused on a prompt has no timer, so the loops here
|
|
616
|
+
// never see it — but it is holding the response hash for the turn it paused
|
|
626
617
|
// on, and `/respond` will resume it under the NEW ID. Move the hash and the
|
|
627
618
|
// pause mark with it; the chain itself stays paused until that resume.
|
|
628
619
|
const pausedMoves = [];
|
|
@@ -635,11 +626,41 @@ function migrateResponsePollerWorktreeIds(renames, resolveCliToolId) {
|
|
|
635
626
|
continue;
|
|
636
627
|
pausedMoves.push({ oldKey: pollerKey, newKey: `${newWorktreeId}:${parts.instanceId}` });
|
|
637
628
|
}
|
|
629
|
+
// Issue #3553: the dedup state of the whole batch moves in one call per map
|
|
630
|
+
// family, each lifting every source before writing any destination. Re-keyed
|
|
631
|
+
// pair by pair, a swap left A with its own state and B empty.
|
|
632
|
+
(0, prompt_dedup_1.renamePromptHashCacheKeys)(moves);
|
|
633
|
+
(0, response_dedup_1.renameResponseHashCacheKeys)([...moves, ...pausedMoves]);
|
|
634
|
+
// Issue #1695: the prompt hash moved above, so the guard keeps suppressing
|
|
635
|
+
// the prompt on screen under the new ID. Its tally has to move with it, or
|
|
636
|
+
// `capture --json` reports zero skips for a session that is still skipping.
|
|
637
|
+
// Old worktree ID comes back out of the key being left.
|
|
638
|
+
(0, prompt_dedup_state_1.renamePromptDedupSkipsBatch)(moves.flatMap((move) => {
|
|
639
|
+
const movedFrom = splitPollerKey(move.oldKey);
|
|
640
|
+
return movedFrom
|
|
641
|
+
? [{
|
|
642
|
+
oldWorktreeId: movedFrom.worktreeId,
|
|
643
|
+
newWorktreeId: move.newWorktreeId,
|
|
644
|
+
cliToolId: move.cliToolId,
|
|
645
|
+
instanceId: move.instanceId,
|
|
646
|
+
}]
|
|
647
|
+
: [];
|
|
648
|
+
}));
|
|
649
|
+
// Phase 2: restart each poller under its new identity.
|
|
650
|
+
for (const move of moves) {
|
|
651
|
+
const startedAt = carried.get(move.newKey)?.startedAt;
|
|
652
|
+
exports.pollingStartTimes.set(move.newKey, startedAt ?? Date.now());
|
|
653
|
+
if (isFullScreenTui(move.cliToolId)) {
|
|
654
|
+
(0, tui_accumulator_1.initTuiAccumulator)(move.newKey);
|
|
655
|
+
}
|
|
656
|
+
scheduleNextResponsePoll(move.newWorktreeId, move.cliToolId, move.instanceId);
|
|
657
|
+
}
|
|
658
|
+
// Issue #2230: the pause marks of the chains collected above follow their
|
|
659
|
+
// hashes (moved with the batch). All removed before any is added, for the
|
|
660
|
+
// same swap reason.
|
|
638
661
|
for (const move of pausedMoves)
|
|
639
662
|
coordinator.pausedOnPrompt.delete(move.oldKey);
|
|
640
|
-
for (const move of pausedMoves)
|
|
641
|
-
(0, response_dedup_1.renameResponseHashCacheKey)(move.oldKey, move.newKey);
|
|
663
|
+
for (const move of pausedMoves)
|
|
642
664
|
coordinator.pausedOnPrompt.add(move.newKey);
|
|
643
|
-
}
|
|
644
665
|
return moves;
|
|
645
666
|
}
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
* Next Action Helper - Derived state for worktree next actions and review status.
|
|
4
4
|
*
|
|
5
5
|
* Issue #600: UX refresh - provides getNextAction() and getReviewStatus()
|
|
6
|
-
* for Review screen and
|
|
6
|
+
* for the Review screen (via `/api/worktrees`) and the sidebar row
|
|
7
|
+
* (`toBranchItem` in `src/types/sidebar.ts`).
|
|
7
8
|
*
|
|
8
9
|
* Uses exhaustive check (satisfies never) pattern to catch future
|
|
9
10
|
* SessionStatus extensions at compile time [DR2-005].
|
|
10
11
|
*/
|
|
11
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
13
|
exports.NEXT_ACTION_KEYS = void 0;
|
|
13
|
-
exports.isNextActionKey = isNextActionKey;
|
|
14
14
|
exports.getNextAction = getNextAction;
|
|
15
15
|
exports.getReviewStatus = getReviewStatus;
|
|
16
16
|
/**
|
|
@@ -31,19 +31,6 @@ exports.NEXT_ACTION_KEYS = {
|
|
|
31
31
|
checkStalled: 'nextAction.checkStalled',
|
|
32
32
|
running: 'nextAction.running',
|
|
33
33
|
};
|
|
34
|
-
const NEXT_ACTION_KEY_SET = new Set(Object.values(exports.NEXT_ACTION_KEYS));
|
|
35
|
-
/**
|
|
36
|
-
* Whether a value is a key this module produces (Issue #1787).
|
|
37
|
-
*
|
|
38
|
-
* `Worktree.nextAction` is a plain `string` on the wire, and a server that
|
|
39
|
-
* predates this Issue still sends the old English literal. Callers must gate
|
|
40
|
-
* `t()` on this: next-intl reports a missing key by rendering the key path, so
|
|
41
|
-
* feeding it `"Approve / Reject"` would put `worktree.Approve / Reject` on
|
|
42
|
-
* screen. Anything that fails this test is rendered verbatim instead.
|
|
43
|
-
*/
|
|
44
|
-
function isNextActionKey(value) {
|
|
45
|
-
return NEXT_ACTION_KEY_SET.has(value);
|
|
46
|
-
}
|
|
47
34
|
/**
|
|
48
35
|
* Determine the next action for a given session state.
|
|
49
36
|
*
|
|
@@ -39,6 +39,7 @@ exports.ENV_CLEAN_GUIDANCE = exports.MAX_REPORTED_ENV_CHANGES = exports.isLivePi
|
|
|
39
39
|
exports.resolveRequireEnvClean = resolveRequireEnvClean;
|
|
40
40
|
exports.attributeSessionName = attributeSessionName;
|
|
41
41
|
exports.attributeAnchor = attributeAnchor;
|
|
42
|
+
exports.isZcompdumpEntry = isZcompdumpEntry;
|
|
42
43
|
exports.demoVitestPid = demoVitestPid;
|
|
43
44
|
exports.attributeHomeEntry = attributeHomeEntry;
|
|
44
45
|
exports.resolveTaskSessionName = resolveTaskSessionName;
|
|
@@ -200,6 +201,17 @@ exports.readLivePidCwd = readLivePidCwd;
|
|
|
200
201
|
* established.
|
|
201
202
|
*/
|
|
202
203
|
const DEMO_VITEST_HOME_ENTRY = /^\.commandmate-demo-vitest-([1-9]\d*)$/;
|
|
204
|
+
/**
|
|
205
|
+
* zsh's `compinit` cache: `~/.zcompdump` itself, and the `~/.zcompdump.<host>.<pid>`
|
|
206
|
+
* scratch file it writes before renaming (#3664). A worker's shell start makes
|
|
207
|
+
* it; the pid in it is already gone by the time the gate looks. Only these two
|
|
208
|
+
* shapes — any other `.zcompdump*` name stays a violation.
|
|
209
|
+
*/
|
|
210
|
+
const ZCOMPDUMP_HOME_ENTRY = /^\.zcompdump(?:\.[A-Za-z0-9._-]+\.[1-9]\d*)?$/;
|
|
211
|
+
/** Whether a `$HOME` entry name is a zsh compinit cache file (#3664). */
|
|
212
|
+
function isZcompdumpEntry(name) {
|
|
213
|
+
return ZCOMPDUMP_HOME_ENTRY.test(name);
|
|
214
|
+
}
|
|
203
215
|
const isLivePid = (pid) => {
|
|
204
216
|
try {
|
|
205
217
|
process.kill(pid, 0);
|
|
@@ -581,7 +593,8 @@ function diffEnvSnapshots(baseline, final, context, options = {}) {
|
|
|
581
593
|
const afterKeys = new Set(after.entries.map((entry) => entry.key));
|
|
582
594
|
// Only `home-entries`, and only by the whole name: the same string under
|
|
583
595
|
// `~/.commandmate` is a different directory and stays counted.
|
|
584
|
-
const isIgnoredByConfig = (entry) => probeId === 'home-entries' &&
|
|
596
|
+
const isIgnoredByConfig = (entry) => probeId === 'home-entries' &&
|
|
597
|
+
(ignoredHomeEntries.has(entry.key) || isZcompdumpEntry(entry.key));
|
|
585
598
|
const added = [];
|
|
586
599
|
const ignoredAdded = [];
|
|
587
600
|
const taskSessionAdded = [];
|