@baique/pi-web-sky 0.1.55 → 0.1.57
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-path-routes-manifest.json +8 -4
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +2 -2
- package/.next/react-loadable-manifest.json +2 -2
- package/.next/required-server-files.js +3 -2
- package/.next/required-server-files.json +3 -2
- package/.next/routes-manifest.json +28 -0
- package/.next/server/app/_global-error/page.js +2 -2
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +4 -3
- package/.next/server/app/_not-found.segments/_full.segment.rsc +4 -3
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +4 -3
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +3 -2
- package/.next/server/app/api/agent/[id]/bash-output/route.js +2 -2
- package/.next/server/app/api/agent/[id]/events/route.js +2 -2
- package/.next/server/app/api/agent/[id]/events/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/[id]/route.js +1 -1
- package/.next/server/app/api/agent/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/new/route.js +1 -1
- package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
- package/.next/server/app/api/agent/running/route.js +1 -1
- package/.next/server/app/api/agent/running/route.js.nft.json +1 -1
- package/.next/server/app/api/app-update/route.js +1 -1
- package/.next/server/app/api/auth/all-providers/route.js +1 -1
- package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -1
- package/.next/server/app/api/auth/login/[provider]/route.js +1 -1
- package/.next/server/app/api/auth/logout/[provider]/route.js +1 -1
- package/.next/server/app/api/auth/providers/route.js +1 -1
- package/.next/server/app/api/board-assets/[...path]/route.js +2 -2
- package/.next/server/app/api/board-assets/route.js +2 -2
- package/.next/server/app/api/boards/[id]/add-session/route.js +1 -0
- package/.next/server/app/api/boards/[id]/add-session/route.js.nft.json +1 -0
- package/.next/server/app/api/boards/[id]/add-session/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/boards/[id]/reconcile/route.js +1 -1
- package/.next/server/app/api/boards/[id]/route.js +1 -1
- package/.next/server/app/api/boards/reorder/route.js +2 -2
- package/.next/server/app/api/boards/route.js +1 -1
- package/.next/server/app/api/cwd/browse/route.js +1 -1
- package/.next/server/app/api/cwd/validate/route.js +2 -2
- package/.next/server/app/api/default-cwd/route.js +2 -2
- package/.next/server/app/api/file-index/route.js +2 -2
- package/.next/server/app/api/files/[...path]/route.js +3 -3
- package/.next/server/app/api/git/diff/route.js +1 -1
- package/.next/server/app/api/git/status/route.js +1 -1
- package/.next/server/app/api/home/route.js +1 -1
- package/.next/server/app/api/mcp/route.js +2 -2
- package/.next/server/app/api/models/route.js +2 -2
- package/.next/server/app/api/models-config/catalog/route.js +1 -1
- package/.next/server/app/api/models-config/discover/route.js +1 -1
- package/.next/server/app/api/models-config/route.js +1 -1
- package/.next/server/app/api/models-config/test/route.js +1 -1
- package/.next/server/app/api/plugins/route.js +2 -2
- package/.next/server/app/api/project-trust/route.js +1 -1
- package/.next/server/app/api/project-trust/route.js.nft.json +1 -1
- package/.next/server/app/api/quota/route.js +1 -1
- package/.next/server/app/api/search/route.js +3 -3
- package/.next/server/app/api/sessions/[id]/auto-name/route.js +2 -2
- package/.next/server/app/api/sessions/[id]/auto-name/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/context/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +2 -2
- package/.next/server/app/api/sessions/[id]/export/route.js +2 -2
- package/.next/server/app/api/sessions/[id]/minimap/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/minimap/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/state/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/state/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/todos/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/todos/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/route.js +1 -1
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/summary/route.js +2 -2
- package/.next/server/app/api/skills/check/route.js +1 -1
- package/.next/server/app/api/skills/install/route.js +2 -2
- package/.next/server/app/api/skills/route.js +1 -1
- package/.next/server/app/api/skills/search/route.js +1 -1
- package/.next/server/app/api/skills/update/route.js +1 -1
- package/.next/server/app/api/subagents/[id]/route.js +1 -0
- package/.next/server/app/api/subagents/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/subagents/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/subagents/profiles/route.js +30 -0
- package/.next/server/app/api/subagents/profiles/route.js.nft.json +1 -0
- package/.next/server/app/api/subagents/profiles/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/subagents/settings/route.js +1 -0
- package/.next/server/app/api/subagents/settings/route.js.nft.json +1 -0
- package/.next/server/app/api/subagents/settings/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/task-card-questions/[id]/answer/route.js +2 -2
- package/.next/server/app/api/task-card-questions/route.js +2 -2
- package/.next/server/app/api/task-cards/[id]/route.js +1 -1
- package/.next/server/app/api/task-cards/route.js +1 -1
- package/.next/server/app/api/task-cards/unbind/route.js +3 -3
- package/.next/server/app/api/task-scheduler/status/route.js +1 -1
- package/.next/server/app/api/task-scheduler/status/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/[id]/assign-session/route.js +2 -12
- package/.next/server/app/api/tasks/[id]/board/route.js +1 -1
- package/.next/server/app/api/tasks/[id]/route.js +1 -1
- package/.next/server/app/api/tasks/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/tasks/reorder/route.js +2 -12
- package/.next/server/app/api/tasks/route.js +2 -12
- package/.next/server/app/api/terminal/[id]/events/route.js +2 -2
- package/.next/server/app/api/terminal/[id]/route.js +2 -2
- package/.next/server/app/api/terminal/route.js +2 -2
- package/.next/server/app/api/worktrees/route.js +2 -2
- package/.next/server/app/api/yjs-version/route.js +1 -1
- package/.next/server/app/favicon.ico/route.js +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +6 -5
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -5
- package/.next/server/app/index.segments/_full.segment.rsc +6 -5
- package/.next/server/app/index.segments/_tree.segment.rsc +3 -2
- package/.next/server/app/manifest.webmanifest/route.js +2 -2
- package/.next/server/app/page.js +175 -8
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +8 -4
- package/.next/server/chunks/1937.js +14 -13
- package/.next/server/chunks/2524.js +2 -2
- package/.next/server/chunks/3379.js +1 -1
- package/.next/server/chunks/3500.js +1 -1
- package/.next/server/chunks/402.js +28 -7
- package/.next/server/chunks/426.js +14 -0
- package/.next/server/chunks/4367.js +1 -1
- package/.next/server/chunks/4457.js +3 -13
- package/.next/server/chunks/4980.js +1 -1
- package/.next/server/chunks/542.js +23 -4
- package/.next/server/chunks/5794.js +2 -2
- package/.next/server/chunks/5940.js +1 -1
- package/.next/server/chunks/6337.js +1 -1
- package/.next/server/chunks/6429.js +15 -2
- package/.next/server/chunks/6525.js +25 -4
- package/.next/server/chunks/6583.js +12 -11
- package/.next/server/chunks/7048.js +6 -0
- package/.next/server/instrumentation.js +1 -1
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/middleware.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/static/MPBMmQqmDG8zo8tM_bkDy/_buildManifest.js +1 -0
- package/.next/static/chunks/752.bafff304e6b00987.js +1 -0
- package/.next/static/chunks/8088.39866dc5f1d15868.js +1 -0
- package/.next/static/chunks/app/_global-error/page-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/bash-output/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/events/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/agent/[id]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/agent/new/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/agent/running/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/app-update/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/auth/all-providers/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/auth/api-key/[provider]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/auth/login/[provider]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/auth/logout/[provider]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/auth/providers/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/board-assets/[...path]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/board-assets/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/boards/[id]/add-session/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/boards/[id]/reconcile/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/boards/[id]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/boards/reorder/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/boards/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/cwd/browse/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/cwd/validate/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/default-cwd/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/file-index/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/files/[...path]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/git/diff/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/git/status/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/home/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/mcp/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/models/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/models-config/catalog/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/models-config/discover/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/models-config/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/models-config/test/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/plugins/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/project-trust/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/quota/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/search/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/context/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/export/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/minimap/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/state/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/todos/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/sessions/summary/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/skills/check/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/skills/install/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/skills/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/skills/search/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/skills/update/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/subagents/[id]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/subagents/profiles/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/subagents/settings/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/task-card-questions/[id]/answer/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/task-card-questions/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/task-cards/[id]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/task-cards/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/task-cards/unbind/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/task-scheduler/status/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/tasks/[id]/assign-session/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/tasks/[id]/board/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/tasks/[id]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/tasks/reorder/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/tasks/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/terminal/[id]/events/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/terminal/[id]/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/terminal/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/worktrees/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/api/yjs-version/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/layout-fae2b226b3c78448.js +1 -0
- package/.next/static/chunks/app/manifest.webmanifest/route-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/app/page-d5af3bd535589daf.js +256 -0
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-ad6e695deb9de65c.js +1 -0
- package/.next/static/chunks/{webpack-b0effde51c1651b8.js → webpack-1ce35e1249cfd931.js} +1 -1
- package/.next/static/css/bb9361c7f832a89d.css +1 -0
- package/.next/static/css/c7d127e07b1a786c.css +1 -0
- package/.next/trace +8 -7
- package/.next/trace-build +1 -1
- package/.next/types/app/api/boards/[id]/add-session/route.ts +353 -0
- package/.next/types/app/api/subagents/[id]/route.ts +353 -0
- package/.next/types/app/api/subagents/profiles/route.ts +353 -0
- package/.next/types/app/api/subagents/settings/route.ts +353 -0
- package/.next/types/routes.d.ts +5 -1
- package/.next/types/validator.ts +36 -0
- package/lib/api-types.ts +10 -0
- package/lib/board-reconcile.test.mjs +46 -8
- package/lib/board-reconcile.ts +57 -1
- package/lib/board-store.test.mjs +2 -2
- package/lib/chat-lazy-load.test.mjs +0 -62
- package/lib/chat-lazy-load.ts +0 -13
- package/lib/chat-only.ts +23 -0
- package/lib/draft-stash.ts +4 -5
- package/lib/file-types.ts +16 -1
- package/lib/i18n/messages/en.ts +91 -0
- package/lib/i18n/messages/zh-CN.ts +91 -0
- package/lib/id.test.mjs +38 -0
- package/lib/id.ts +17 -0
- package/lib/ime-guard.test.mjs +52 -0
- package/lib/ime-guard.ts +54 -0
- package/lib/message-text.ts +24 -0
- package/lib/models-cache.ts +1 -1
- package/lib/pi-types.ts +19 -1
- package/lib/pin-store.ts +85 -0
- package/lib/powershell-settings.ts +106 -0
- package/lib/quoted-selection.ts +4 -0
- package/lib/rpc-manager.activity.test.mjs +223 -0
- package/lib/rpc-manager.test.mjs +22 -0
- package/lib/rpc-manager.title.test.mjs +152 -0
- package/lib/rpc-manager.ts +301 -28
- package/lib/session-activity.test.mjs +123 -0
- package/lib/session-activity.ts +77 -0
- package/lib/session-delete.test.mjs +45 -41
- package/lib/session-delete.ts +8 -34
- package/lib/session-family.test.mjs +49 -0
- package/lib/session-family.ts +80 -0
- package/lib/session-index-scanner.test.mjs +364 -2
- package/lib/session-index-scanner.ts +199 -55
- package/lib/session-reader.noscan.test.mjs +371 -0
- package/lib/session-reader.project.test.mjs +30 -52
- package/lib/session-reader.test.mjs +2 -65
- package/lib/session-reader.ts +177 -213
- package/lib/session-scanner.test.mjs +151 -38
- package/lib/session-scanner.ts +140 -61
- package/lib/session-search.ts +6 -5
- package/lib/session-time-group.test.mjs +38 -0
- package/lib/session-time-group.ts +55 -0
- package/lib/settings-navigation.ts +124 -0
- package/lib/sqlite-db.test.mjs +26 -0
- package/lib/sqlite-db.ts +10 -1
- package/lib/subagent-extension.test.mjs +424 -0
- package/lib/subagent-extension.ts +309 -0
- package/lib/subagent-input.test.mjs +63 -0
- package/lib/subagent-input.ts +71 -0
- package/lib/subagent-profile-precedence.ts +20 -0
- package/lib/subagent-prompt.test.mjs +64 -0
- package/lib/subagent-prompt.ts +31 -0
- package/lib/subagent-queue.test.mjs +35 -0
- package/lib/subagent-queue.ts +74 -0
- package/lib/subagent-runtime.test.mjs +150 -0
- package/lib/subagent-runtime.ts +629 -0
- package/lib/subagent-session-title.test.mjs +120 -0
- package/lib/subagent-settings.test.mjs +50 -0
- package/lib/subagent-settings.ts +93 -0
- package/lib/subagents.test.mjs +601 -0
- package/lib/subagents.ts +602 -0
- package/lib/task-scheduler.test.mjs +27 -0
- package/lib/task-scheduler.ts +8 -1
- package/lib/task-store.activity.test.mjs +141 -0
- package/lib/task-store.meta-row.test.mjs +25 -5
- package/lib/task-store.partial-row.test.mjs +198 -0
- package/lib/task-store.subtree.test.mjs +172 -0
- package/lib/task-store.test.mjs +46 -20
- package/lib/task-store.ts +344 -68
- package/lib/tool-presets.ts +4 -0
- package/lib/types.ts +19 -0
- package/lib/worktree-isolation.test.mjs +51 -0
- package/next.config.ts +3 -1
- package/package.json +1 -1
- package/.next/static/bsW3fla0-BlBHVMKtAM5I/_buildManifest.js +0 -1
- package/.next/static/chunks/752.0ad92735d5f38143.js +0 -1
- package/.next/static/chunks/8088.53d9cdaf15634d4b.js +0 -1
- package/.next/static/chunks/app/_global-error/page-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/bash-output/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/events/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/agent/[id]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/agent/new/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/agent/running/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/app-update/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/auth/all-providers/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/auth/api-key/[provider]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/auth/login/[provider]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/auth/logout/[provider]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/auth/providers/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/board-assets/[...path]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/board-assets/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/boards/[id]/reconcile/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/boards/[id]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/boards/reorder/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/boards/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/cwd/browse/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/cwd/validate/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/default-cwd/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/file-index/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/files/[...path]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/git/diff/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/git/status/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/home/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/mcp/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/models/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/models-config/catalog/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/models-config/discover/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/models-config/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/models-config/test/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/plugins/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/project-trust/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/quota/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/search/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/context/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/export/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/minimap/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/state/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/todos/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/sessions/summary/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/skills/check/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/skills/install/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/skills/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/skills/search/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/skills/update/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/task-card-questions/[id]/answer/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/task-card-questions/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/task-cards/[id]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/task-cards/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/task-cards/unbind/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/task-scheduler/status/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/tasks/[id]/assign-session/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/tasks/[id]/board/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/tasks/[id]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/tasks/reorder/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/tasks/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/terminal/[id]/events/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/terminal/[id]/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/terminal/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/worktrees/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/api/yjs-version/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/layout-dace09825b2d3857.js +0 -1
- package/.next/static/chunks/app/manifest.webmanifest/route-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/app/page-64b9f4b3567a2f73.js +0 -89
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-2d5f6296c7e693c6.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-2d5f6296c7e693c6.js +0 -1
- package/.next/static/css/fd25673802257262.css +0 -1
- package/lib/extension-command.test.mjs +0 -63
- package/lib/extension-command.ts +0 -81
- package/lib/subagent-widget.test.mjs +0 -87
- package/lib/subagent-widget.ts +0 -109
- /package/.next/static/{bsW3fla0-BlBHVMKtAM5I → MPBMmQqmDG8zo8tM_bkDy}/_ssgManifest.js +0 -0
|
@@ -6,17 +6,24 @@
|
|
|
6
6
|
// CLI 新建),使列表读取退化为纯单表查询。
|
|
7
7
|
//
|
|
8
8
|
// 一轮 tick 做的事:
|
|
9
|
-
// 1. scanSessionFileMeta():全量 readdir + stat
|
|
10
|
-
// 2. 与 session_meta 现有行 diff
|
|
11
|
-
// - 磁盘有、库无 → 读 header(scanOneSessionHead)→
|
|
9
|
+
// 1. scanSessionFileMeta():全量 readdir + stat(不读内容,递归到子目录),拿磁盘会话全集
|
|
10
|
+
// 2. 与 session_meta 现有行 diff(path 是会话与文件的唯一绑定,行匹配 path 优先):
|
|
11
|
+
// - 磁盘有、库无 → 读 header(scanOneSessionHead)→ 用 **header 的 id** 建行
|
|
12
|
+
// (子目录里的 `session.jsonl` 没有文件名 id 可猜)→ resolveProject 算
|
|
12
13
|
// project_key → INSERT(created/mtime/first_message)
|
|
13
14
|
// - 磁盘有、库有、mtime 变 → 读 header 首行校验 parent_id(重挂收敛)+ 刷 modified
|
|
14
|
-
// - 库有、磁盘无 →
|
|
15
|
-
// 3.
|
|
15
|
+
// - 库有、磁盘无 → 删前磁盘复检 + 年轻行保护后 DELETE
|
|
16
|
+
// 3. last_reply 回填:`last_reply IS NULL` 的行读一次文件尾(无回复写 '')→ 存量会话的
|
|
17
|
+
// 「最后一条消息」入库存档,读取路径从此不再读文件
|
|
18
|
+
// 4. 归属收敛:子会话继承父会话 task_id(多层脏链一轮收敛)
|
|
19
|
+
// 5. 全程幂等(session_id 主键 upsert 语义),可重复执行。
|
|
16
20
|
//
|
|
17
|
-
//
|
|
18
|
-
//
|
|
19
|
-
//
|
|
21
|
+
// 明确不做:不读文件尾部追外部改名/标题(title 由本应用改名写库);存量 `last_reply`
|
|
22
|
+
// 仅一次性回填(见下)。外部改动导致 mtime 变化只刷新排序键(且单调,不回退);
|
|
23
|
+
// header 首行仅用于 parent_id 校验(成本可忽略,父链以磁盘 header 为权威)。
|
|
24
|
+
//
|
|
25
|
+
// last_reply 三态:NULL = 未回填(读一次文件尾)、'' = 回填过但无回复、文本 = 真实回复。
|
|
26
|
+
// 事件链路(agent_settled)写真实回复,列表/看板卡只读库。
|
|
20
27
|
//
|
|
21
28
|
// 调度:startSessionIndexScanner() 在 instrumentation.ts 注册(globalThis
|
|
22
29
|
// 防热重载重复启动),启动即跑首轮 + 定期续跑;runSessionIndexScan() 提供
|
|
@@ -26,11 +33,12 @@ import { existsSync } from "fs";
|
|
|
26
33
|
import { getDb } from "./sqlite-db";
|
|
27
34
|
import { projectIdentityKey } from "./project-identity";
|
|
28
35
|
import { sessionPathKey } from "./session-path";
|
|
29
|
-
import { scanOneSessionHead, scanSessionFileMeta } from "./session-scanner";
|
|
36
|
+
import { scanOneSessionHead, scanSessionFileMeta, readSessionTail, type SessionFileMeta } from "./session-scanner";
|
|
30
37
|
import { resolveProject } from "./worktree";
|
|
31
38
|
|
|
32
39
|
/** 一轮扫描的变更摘要(日志/测试断言用)。 */
|
|
33
40
|
export interface SessionIndexScanSummary {
|
|
41
|
+
/** 本轮在磁盘上解析出的会话数(非会话 jsonl 不计;同 id 多副本只算一个)。 */
|
|
34
42
|
scanned: number;
|
|
35
43
|
inserted: number;
|
|
36
44
|
updated: number;
|
|
@@ -40,36 +48,115 @@ export interface SessionIndexScanSummary {
|
|
|
40
48
|
/** 默认扫描周期:30s(外部/CLI 新建会话最长等一个周期进列表)。 */
|
|
41
49
|
export const SESSION_INDEX_SCAN_INTERVAL_MS = 30_000;
|
|
42
50
|
|
|
51
|
+
/** 归属收敛单轮扫描最多继承几层(单条 UPDATE 一次只能修一层,见 runSessionIndexScan;
|
|
52
|
+
* 正常链路最多 2–3 层,8 是防病态深链/环的上限)。 */
|
|
53
|
+
const INHERIT_MAX_PASSES = 8;
|
|
54
|
+
|
|
55
|
+
/** 删除分支的「年轻行保护」窗口:行 `updated` 在最近 60s 内则不删(见 runSessionIndexScan)。 */
|
|
56
|
+
const YOUNG_ROW_PROTECT_MS = 60_000;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* 单文件立即索引:新会话文件已落盘但等不及后台扫描时调用(如 fork_branch 创建
|
|
60
|
+
* 的引用分支,需立刻出现在会话列表)。幂等 upsert,parent 由调用方显式指定
|
|
61
|
+
* (磁盘 header 的父路径反查需要全量 path 映射,单文件场景不划算)。
|
|
62
|
+
* `taskId` 为会话归属(调用方传入源会话的 task_id):归属继承必须在建行时完成,
|
|
63
|
+
* 否则会话会先以临时会话现身聊天区(V1 两区重复)。ON CONFLICT 不覆盖已有归属。
|
|
64
|
+
*/
|
|
65
|
+
export async function indexSessionFileNow(
|
|
66
|
+
filePath: string,
|
|
67
|
+
parentSessionId: string | null,
|
|
68
|
+
taskId: string | null = null,
|
|
69
|
+
): Promise<void> {
|
|
70
|
+
const head = scanOneSessionHead(filePath);
|
|
71
|
+
if (!head) return;
|
|
72
|
+
const projectKey = await resolveProject(head.cwd).then((p) => projectIdentityKey(p?.projectRoot ?? head.cwd));
|
|
73
|
+
getDb()
|
|
74
|
+
.prepare(
|
|
75
|
+
`INSERT INTO session_meta
|
|
76
|
+
(session_id, task_id, updated, pinned, path, cwd, project_key, title, first_message, parent_id, created, modified)
|
|
77
|
+
VALUES (?, ?, ?, 0, ?, ?, ?, NULL, ?, ?, ?, ?)
|
|
78
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
79
|
+
path = excluded.path,
|
|
80
|
+
cwd = excluded.cwd,
|
|
81
|
+
project_key = excluded.project_key,
|
|
82
|
+
-- first_message 只补空:调用方不传(NULL)时不再把已有的首条消息擦掉。
|
|
83
|
+
first_message = COALESCE(session_meta.first_message, excluded.first_message),
|
|
84
|
+
parent_id = excluded.parent_id,
|
|
85
|
+
created = excluded.created,
|
|
86
|
+
modified = excluded.modified`,
|
|
87
|
+
)
|
|
88
|
+
.run(
|
|
89
|
+
head.id,
|
|
90
|
+
taskId,
|
|
91
|
+
Date.now(),
|
|
92
|
+
filePath,
|
|
93
|
+
head.cwd,
|
|
94
|
+
projectKey,
|
|
95
|
+
head.firstMessage || null,
|
|
96
|
+
parentSessionId,
|
|
97
|
+
head.created.getTime(),
|
|
98
|
+
Date.now(),
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
43
102
|
/** 一轮全量扫描。`sessionsDir` 仅在测试注入(默认走 agentDir)。 */
|
|
44
103
|
export async function runSessionIndexScan(
|
|
45
104
|
sessionsDir?: string,
|
|
46
105
|
): Promise<SessionIndexScanSummary> {
|
|
47
|
-
//
|
|
48
|
-
// id
|
|
106
|
+
// 磁盘 → 会话 id:path 优先(path 是会话与文件的唯一绑定),header 是 id 的权威。
|
|
107
|
+
// 同 id 多文件(pi 整文件重写留旧副本、子目录里同名副本)只认最新 mtime 文件——
|
|
108
|
+
// 与「path 指向最新」一致。注意不能按文件名提示归组:子目录里的
|
|
109
|
+
// `session.jsonl`、`*_scout_0_transcript.jsonl` 末段提示会撞名(都叫
|
|
110
|
+
// session/transcript),按提示去重会把不同会话当成同一个丢掉。
|
|
49
111
|
const allDiskFiles = await scanSessionFileMeta(sessionsDir);
|
|
50
|
-
const newestByFile = new Map<string, { path: string; id: string; modified: Date }>();
|
|
51
|
-
for (const f of allDiskFiles) {
|
|
52
|
-
const cur = newestByFile.get(f.id);
|
|
53
|
-
if (!cur || f.modified.getTime() > cur.modified.getTime()) newestByFile.set(f.id, f);
|
|
54
|
-
}
|
|
55
|
-
const diskFiles = [...newestByFile.values()];
|
|
56
|
-
const summary: SessionIndexScanSummary = { scanned: diskFiles.length, inserted: 0, updated: 0, deleted: 0 };
|
|
57
112
|
|
|
58
113
|
const db = getDb();
|
|
59
|
-
const selectAll = db.prepare("SELECT session_id, modified, path, parent_id, first_message FROM session_meta").all() as Array<{
|
|
114
|
+
const selectAll = db.prepare("SELECT session_id, modified, updated, path, parent_id, first_message FROM session_meta").all() as Array<{
|
|
60
115
|
session_id: string;
|
|
61
116
|
modified: number | null;
|
|
117
|
+
updated: number;
|
|
62
118
|
path: string | null;
|
|
63
119
|
parent_id: string | null;
|
|
64
120
|
first_message: string | null;
|
|
65
121
|
}>;
|
|
66
|
-
const
|
|
122
|
+
const rowById = new Map(selectAll.map((r) => [r.session_id, r]));
|
|
123
|
+
const rowByPath = new Map(
|
|
124
|
+
selectAll.filter((r) => r.path).map((r) => [sessionPathKey(r.path as string), r.session_id]),
|
|
125
|
+
);
|
|
67
126
|
|
|
127
|
+
type SessionHead = NonNullable<ReturnType<typeof scanOneSessionHead>>;
|
|
128
|
+
const resolved = new Map<string, { file: SessionFileMeta; head?: SessionHead }>();
|
|
129
|
+
// 本轮在磁盘上见到过的会话 id——删除分支的反面。
|
|
68
130
|
const seenOnDisk = new Set<string>();
|
|
131
|
+
const keepNewest = (sessionId: string, file: SessionFileMeta, head?: SessionHead): void => {
|
|
132
|
+
const cur = resolved.get(sessionId);
|
|
133
|
+
if (cur && cur.file.modified.getTime() >= file.modified.getTime()) return;
|
|
134
|
+
resolved.set(sessionId, { file, head });
|
|
135
|
+
};
|
|
69
136
|
|
|
70
|
-
|
|
137
|
+
for (const file of allDiskFiles) {
|
|
138
|
+
// 1) path 已绑库行 → 直接用库行 id,不读文件(header 不再参与:行已经指向本文件)。
|
|
139
|
+
const boundRowId = rowByPath.get(sessionPathKey(file.path));
|
|
140
|
+
if (boundRowId !== undefined) {
|
|
141
|
+
keepNewest(boundRowId, file);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
// 2) path 未绑库行(新文件 / 被移动的文件 / 同 id 旧副本)→ 读 header,id 以 header 为准。
|
|
145
|
+
const head = scanOneSessionHead(file.path);
|
|
146
|
+
if (head) {
|
|
147
|
+
keepNewest(head.id, file, head);
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
// 3) header 读不出会话(非会话 jsonl、写到一半的坏行)→ 不建行也不刷列;
|
|
151
|
+
// 只有文件名提示能对上库行时才算「该会话的文件还在磁盘」,免得读不出内容就删行。
|
|
152
|
+
if (file.id && rowById.has(file.id)) seenOnDisk.add(file.id);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const summary: SessionIndexScanSummary = { scanned: resolved.size, inserted: 0, updated: 0, deleted: 0 };
|
|
156
|
+
|
|
157
|
+
// 磁盘全量 path→id 映射(parent 路径反查父会话 id;含子目录里的文件)。
|
|
71
158
|
const pathToId = new Map<string, string>();
|
|
72
|
-
for (const
|
|
159
|
+
for (const [sessionId, entry] of resolved) pathToId.set(sessionPathKey(entry.file.path), sessionId);
|
|
73
160
|
|
|
74
161
|
// 同 cwd 目录的 project_key 共享一次 resolve(缓存 promise,防重复 git 调用)。
|
|
75
162
|
const cwdToProjectKey = new Map<string, Promise<string>>();
|
|
@@ -82,20 +169,29 @@ export async function runSessionIndexScan(
|
|
|
82
169
|
path = excluded.path,
|
|
83
170
|
cwd = excluded.cwd,
|
|
84
171
|
project_key = excluded.project_key,
|
|
85
|
-
first_message
|
|
172
|
+
-- first_message 只补空(COALESCE):库内已有首条消息时不被这次 upsert 的 NULL/旧值擦掉。
|
|
173
|
+
-- 内容派生列的「变化收敛」由 reconcileFromHead 单独负责(走 mtime 前移/欠账分支)。
|
|
174
|
+
first_message = COALESCE(session_meta.first_message, excluded.first_message),
|
|
86
175
|
parent_id = excluded.parent_id,
|
|
87
176
|
created = excluded.created,
|
|
88
|
-
modified
|
|
177
|
+
-- modified 也单调:path 迁移(文件被移动/重写)时不能用更旧的 mtime 把事件
|
|
178
|
+
-- 链路刚写的「现在就活跃」拉回去(与 updateModifiedStmt 同一约定)。
|
|
179
|
+
modified = CASE
|
|
180
|
+
WHEN session_meta.modified IS NULL OR excluded.modified > session_meta.modified
|
|
181
|
+
THEN excluded.modified ELSE session_meta.modified END`,
|
|
182
|
+
);
|
|
183
|
+
// modified 单调:事件链路刚写的「现在就活跃」不能被下一轮扫描用更旧的 mtime
|
|
184
|
+
// 拉回去(列表读取会触发懒初始化扫描 → 这是可达路径)。
|
|
185
|
+
const updateModifiedStmt = db.prepare(
|
|
186
|
+
"UPDATE session_meta SET modified = ? WHERE session_id = ? AND (modified IS NULL OR modified < ?)",
|
|
89
187
|
);
|
|
90
|
-
const updateModifiedStmt = db.prepare("UPDATE session_meta SET modified = ? WHERE session_id = ?");
|
|
91
188
|
const updateParentStmt = db.prepare("UPDATE session_meta SET parent_id = ? WHERE session_id = ?");
|
|
92
189
|
const updateFirstMessageStmt = db.prepare("UPDATE session_meta SET first_message = ? WHERE session_id = ?");
|
|
93
190
|
const deleteStmt = db.prepare("DELETE FROM session_meta WHERE session_id = ?");
|
|
94
191
|
|
|
95
|
-
//
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if (!head) return;
|
|
192
|
+
// resolve project + upsert(新文件或老行补全索引列共用)。header 由调用方传入:
|
|
193
|
+
// 已读过的不重复读(子目录里的文件每轮都要靠 header 认 id)。
|
|
194
|
+
const upsertFromDisk = async (file: SessionFileMeta, head: SessionHead, sessionId: string): Promise<void> => {
|
|
99
195
|
let projectPromise = cwdToProjectKey.get(head.cwd);
|
|
100
196
|
if (!projectPromise) {
|
|
101
197
|
projectPromise = resolveProject(head.cwd).then((p) => projectIdentityKey(p?.projectRoot ?? head.cwd));
|
|
@@ -106,7 +202,7 @@ export async function runSessionIndexScan(
|
|
|
106
202
|
? (pathToId.get(sessionPathKey(head.parentSessionPath)) ?? null)
|
|
107
203
|
: null;
|
|
108
204
|
insertStmt.run(
|
|
109
|
-
|
|
205
|
+
sessionId,
|
|
110
206
|
Date.now(),
|
|
111
207
|
file.path,
|
|
112
208
|
head.cwd,
|
|
@@ -122,56 +218,104 @@ export async function runSessionIndexScan(
|
|
|
122
218
|
// first_message 是内容派生列:文件写入了首条消息,索引必须跟随——
|
|
123
219
|
// 否则 persist 建行的会话(first_message 恒 NULL)标题永远冻结。
|
|
124
220
|
// 返回是否更新了 first_message(供 NULL 欠账补跑计数)。
|
|
125
|
-
const reconcileFromHead = (file:
|
|
221
|
+
const reconcileFromHead = (file: SessionFileMeta, dbRow: { parent_id: string | null; first_message: string | null }, sessionId: string): boolean => {
|
|
126
222
|
const head = scanOneSessionHead(file.path);
|
|
127
223
|
if (!head) return false;
|
|
128
224
|
const parentId = head.parentSessionPath
|
|
129
225
|
? (pathToId.get(sessionPathKey(head.parentSessionPath)) ?? null)
|
|
130
226
|
: null;
|
|
131
227
|
if (parentId !== dbRow.parent_id) {
|
|
132
|
-
updateParentStmt.run(parentId,
|
|
228
|
+
updateParentStmt.run(parentId, sessionId);
|
|
133
229
|
}
|
|
134
230
|
if (head.firstMessage && head.firstMessage !== dbRow.first_message) {
|
|
135
|
-
updateFirstMessageStmt.run(head.firstMessage,
|
|
231
|
+
updateFirstMessageStmt.run(head.firstMessage, sessionId);
|
|
136
232
|
return true;
|
|
137
233
|
}
|
|
138
234
|
return false;
|
|
139
235
|
};
|
|
140
236
|
|
|
141
|
-
for (const
|
|
142
|
-
|
|
143
|
-
|
|
237
|
+
for (const [sessionId, entry] of resolved) {
|
|
238
|
+
const { file } = entry;
|
|
239
|
+
seenOnDisk.add(sessionId);
|
|
240
|
+
const dbRow = rowById.get(sessionId);
|
|
144
241
|
if (dbRow === undefined || !dbRow.path || dbRow.path !== file.path) {
|
|
145
|
-
// 磁盘有、库无 → 建行;库行 path 空(
|
|
146
|
-
// 用磁盘最新文件 upsert 修正(path
|
|
147
|
-
|
|
242
|
+
// 磁盘有、库无 → 建行;库行 path 空(pin/rename 建的行)/ 指向旧副本 / 文件被移动
|
|
243
|
+
// → 用磁盘最新文件 upsert 修正(path 指向最新,不保留旧 path)。
|
|
244
|
+
const head = entry.head ?? scanOneSessionHead(file.path);
|
|
245
|
+
if (!head) continue; // header 读不出 → 不写半行,下一轮再看
|
|
246
|
+
await upsertFromDisk(file, head, sessionId);
|
|
148
247
|
summary.inserted += 1;
|
|
149
|
-
} else if (dbRow.modified === null ||
|
|
150
|
-
// mtime
|
|
151
|
-
//
|
|
248
|
+
} else if (dbRow.modified === null || file.modified.getTime() > dbRow.modified) {
|
|
249
|
+
// mtime 前移(真的又活跃了):刷新排序键;同时收敛派生列——parent 链(删除会话
|
|
250
|
+
// 级联重挂/外部重挂会改 header.parentSession)与 first_message(内容写入
|
|
152
251
|
// 后标题必须跟随)。磁盘 header 是父链唯一权威,文件头是标题事实源。
|
|
153
|
-
|
|
154
|
-
|
|
252
|
+
// 只认「前移」:modified 已被事件链路写成 now() 时,库里值 >= mtime(文件头/尾巴
|
|
253
|
+
// 还没落盘),若用 !== 判等,每轮扫描都会多读一次 header 并记一次幻影 updated,
|
|
254
|
+
// 「幂等扫描」不再成立(mtime 真变新的场景由下面的 > 覆盖,不受影响)。
|
|
255
|
+
reconcileFromHead(file, dbRow, sessionId);
|
|
256
|
+
updateModifiedStmt.run(file.modified.getTime(), sessionId, file.modified.getTime());
|
|
155
257
|
summary.updated += 1;
|
|
156
258
|
} else if (!dbRow.first_message) {
|
|
157
259
|
// first_message 欠账补跑:persist 建行的老会话(first_message 恒 NULL)
|
|
158
260
|
// 在 mtime 已同步后仍需回填一次;文件已有首条消息则写入,否则保持 NULL。
|
|
159
|
-
if (reconcileFromHead(file, dbRow)) {
|
|
261
|
+
if (reconcileFromHead(file, dbRow, sessionId)) {
|
|
160
262
|
summary.updated += 1;
|
|
161
263
|
}
|
|
162
264
|
}
|
|
163
265
|
}
|
|
164
266
|
|
|
165
267
|
// 库有、磁盘无 → 删除(会话被外部/本应用删除)。
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
268
|
+
const deleteCheckedAt = Date.now();
|
|
269
|
+
for (const row of selectAll) {
|
|
270
|
+
if (seenOnDisk.has(row.session_id)) continue;
|
|
271
|
+
// 删前以磁盘复检:扫描快照后新建/移动的会话(persist 建行 + 文件落盘)
|
|
272
|
+
// 可能不在本轮快照里,直接删会把刚建的行误删成“列表消失”。path 指向
|
|
273
|
+
// 存在的文件 → 跳过(下一轮扫描会正常 diff)。
|
|
274
|
+
if (row.path && existsSync(row.path)) continue;
|
|
275
|
+
// 年轻行保护:内置 subagent 等会话是「先建行、SDK 惰性 flush 才落盘」,行刚建
|
|
276
|
+
// 完时磁盘上还没有对应文件。这种行删了会在下一轮重新建行 → 列表闪断 + 归属丢失。
|
|
277
|
+
// 只跳过、下一轮再判(外部删除的新会话最多晚 60s 从列表消失)。
|
|
278
|
+
// 前提:扫描器的 upsert 只在**新建行**时写 updated;ON CONFLICT 分支不写 updated
|
|
279
|
+
// (顶上的 INSERT 列了 updated,但 DO UPDATE SET 列表里没有它)—— 若把
|
|
280
|
+
// updated = excluded.updated 加进冲突分支,每轮扫描都会把自己的行重新变
|
|
281
|
+
// 「年轻」,外部删除就永不收敛。
|
|
282
|
+
if (deleteCheckedAt - row.updated < YOUNG_ROW_PROTECT_MS) continue;
|
|
283
|
+
deleteStmt.run(row.session_id);
|
|
284
|
+
summary.deleted += 1;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// 归属收敛:子会话 task_id 为空而父会话有归属 → 继承父(自愈旧数据与写库失败的窗口;
|
|
288
|
+
// 「归属按子树存」是本应用的约定,用户单独把子会话移出任务的状态不会出现)。
|
|
289
|
+
// 单条 UPDATE 每轮只能修一层(SQLite 用语句开始时的快照求值,实测 A(T)←B←C 只修 B),
|
|
290
|
+
// 故循环到无变化为止,使多层脏链在一轮扫描内整体收敛。
|
|
291
|
+
const inheritTaskStmt = db.prepare(
|
|
292
|
+
`UPDATE session_meta AS c
|
|
293
|
+
SET task_id = (SELECT p.task_id FROM session_meta AS p WHERE p.session_id = c.parent_id)
|
|
294
|
+
WHERE c.task_id IS NULL
|
|
295
|
+
AND c.parent_id IS NOT NULL
|
|
296
|
+
AND EXISTS (SELECT 1 FROM session_meta AS p WHERE p.session_id = c.parent_id AND p.task_id IS NOT NULL)`,
|
|
297
|
+
);
|
|
298
|
+
for (let pass = 0; pass < INHERIT_MAX_PASSES; pass += 1) {
|
|
299
|
+
const changes = Number(inheritTaskStmt.run().changes); // changes 类型为 number|bigint
|
|
300
|
+
if (changes === 0) break;
|
|
301
|
+
summary.updated += changes;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// last_reply 一次性回填(存量会话):三态里只有 NULL 才读文件尾——读一次拿到
|
|
305
|
+
// 「最后一条 assistant 回复」(无回复写 ''),之后读取路径(列表/看板卡)再也不摸盘。
|
|
306
|
+
// 文件不可读/不存在 → 保持 NULL,下一轮再试(与删除分支的磁盘复检同思路)。
|
|
307
|
+
const pendingReplyRows = db
|
|
308
|
+
.prepare("SELECT session_id, path FROM session_meta WHERE last_reply IS NULL AND path IS NOT NULL")
|
|
309
|
+
.all() as Array<{ session_id: string; path: string }>;
|
|
310
|
+
if (pendingReplyRows.length > 0) {
|
|
311
|
+
const backfillReplyStmt = db.prepare(
|
|
312
|
+
"UPDATE session_meta SET last_reply = ? WHERE session_id = ? AND last_reply IS NULL",
|
|
313
|
+
);
|
|
314
|
+
for (const row of pendingReplyRows) {
|
|
315
|
+
const tail = readSessionTail(row.path);
|
|
316
|
+
if (!tail) continue;
|
|
317
|
+
backfillReplyStmt.run(tail.lastReply || "", row.session_id);
|
|
318
|
+
summary.updated += 1;
|
|
175
319
|
}
|
|
176
320
|
}
|
|
177
321
|
|
|
@@ -226,7 +370,7 @@ export function startSessionIndexScanner(): void {
|
|
|
226
370
|
let tickInFlight = false;
|
|
227
371
|
const firstScanResult = runSessionIndexScan()
|
|
228
372
|
.then((summary) => {
|
|
229
|
-
console.log(`[pi-web] session index scan: +${summary.inserted} ~${summary.updated} -${summary.deleted} (${summary.scanned}
|
|
373
|
+
console.log(`[pi-web] session index scan: +${summary.inserted} ~${summary.updated} -${summary.deleted} (${summary.scanned} sessions)`);
|
|
230
374
|
return { ok: true as const };
|
|
231
375
|
})
|
|
232
376
|
.catch((e) => {
|