@ai-agent-forge/agent-forge 0.88.1 → 0.88.3
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/CHANGELOG.md +71 -0
- package/README.md +1 -1
- package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
- package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
- package/bundled-plugins/coding-tools/agent-forge.json +1 -1
- package/bundled-plugins/coding-tools/plugin.json +1 -1
- package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
- package/bundled-plugins/compaction-policy/plugin.json +1 -1
- package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
- package/bundled-plugins/overflow-policy/plugin.json +1 -1
- package/bundled-plugins/provider-failover/agent-forge.json +1 -1
- package/bundled-plugins/provider-failover/plugin.json +1 -1
- package/bundled-plugins/retry-policy/agent-forge.json +1 -1
- package/bundled-plugins/retry-policy/plugin.json +1 -1
- package/dist/artifacts/paged-read.d.ts +6 -1
- package/dist/artifacts/paged-read.d.ts.map +1 -1
- package/dist/artifacts/paged-read.js.map +1 -1
- package/dist/bundle/.build-manifest.json +283 -263
- package/dist/bundle/chunks/{anthropic-messages-PLAKXR73.js → anthropic-messages-3FJHRAJL.js} +2 -2
- package/dist/bundle/chunks/anthropic.js +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-OUWQ2AZD.js → azure-openai-responses-GCL47IDS.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/{chunk-Z72JWUZ4.js → chunk-32YDZI4J.js} +1 -1
- package/dist/bundle/chunks/{chunk-AQLNTW2B.js → chunk-755VNWIF.js} +17 -16
- package/dist/bundle/chunks/{chunk-LZOEQITZ.js → chunk-B42Y2VME.js} +120 -104
- package/dist/bundle/chunks/{chunk-DRQDKNXA.js → chunk-BVVSHK6W.js} +1 -1
- package/dist/bundle/chunks/{chunk-6R7UI4IY.js → chunk-QDLOMKF6.js} +1 -1
- package/dist/bundle/chunks/{chunk-D3ARGZFR.js → chunk-V3ACW7VD.js} +3 -3
- package/dist/bundle/chunks/{google-generative-ai-DLII6DAT.js → google-generative-ai-6BMXWA44.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-G7BZL7GM.js → google-vertex-6H7NLRTK.js} +1 -1
- package/dist/bundle/chunks/image-resize-worker.js +3 -3
- package/dist/bundle/chunks/{mistral-conversations-JXUK24ID.js → mistral-conversations-IXUHSFSJ.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-5GSGFIPG.js → openai-codex-responses-YHUAEVCM.js} +1 -1
- package/dist/bundle/chunks/openai-codex.js +1 -1
- package/dist/bundle/chunks/{openai-completions-EI2I6DTG.js → openai-completions-ULQCFC72.js} +1 -1
- package/dist/bundle/chunks/openai-responses-NLLAJDPS.js +2 -0
- package/dist/bundle/chunks/{openrouter-images-G4GQRUSG.js → openrouter-images-GZZQZXMS.js} +1 -1
- package/dist/bundle/chunks/openrouter.js +1 -1
- package/dist/bundle/chunks/{pi-messages-PWU2VJMR.js → pi-messages-EJTI2EJ3.js} +1 -1
- package/dist/bundle/chunks/virtual-modules-TQWEGNNZ.js +5 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/client.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts +0 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/config-selector.d.ts.map +1 -1
- package/dist/cli/config-selector.js +1 -1
- package/dist/cli/config-selector.js.map +1 -1
- package/dist/cli/experimental/cli.d.ts +3 -3
- package/dist/cli/experimental/cli.d.ts.map +1 -1
- package/dist/cli/experimental/cli.js +2 -2
- package/dist/cli/experimental/cli.js.map +1 -1
- package/dist/cli/experimental/commands/agent-forge.d.ts +15 -0
- package/dist/cli/experimental/commands/agent-forge.d.ts.map +1 -0
- package/dist/cli/experimental/commands/{pi.js → agent-forge.js} +4 -4
- package/dist/cli/experimental/commands/agent-forge.js.map +1 -0
- package/dist/cli/plugin-command.d.ts.map +1 -1
- package/dist/cli/plugin-command.js +8 -2
- package/dist/cli/plugin-command.js.map +1 -1
- package/dist/cli/startup-ui.d.ts.map +1 -1
- package/dist/cli/startup-ui.js +1 -1
- package/dist/cli/startup-ui.js.map +1 -1
- package/dist/config.d.ts +4 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -7
- package/dist/config.js.map +1 -1
- package/dist/core/agent-forge-manifest.d.ts +7 -0
- package/dist/core/agent-forge-manifest.d.ts.map +1 -0
- package/dist/core/{pi-manifest.js → agent-forge-manifest.js} +4 -4
- package/dist/core/agent-forge-manifest.js.map +1 -0
- package/dist/core/agent-session-compaction.d.ts +1 -1
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +3 -3
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-internal.d.ts +2 -0
- package/dist/core/agent-session-internal.d.ts.map +1 -1
- package/dist/core/agent-session-internal.js.map +1 -1
- package/dist/core/agent-session-lifecycle.d.ts.map +1 -1
- package/dist/core/agent-session-lifecycle.js +12 -1
- package/dist/core/agent-session-lifecycle.js.map +1 -1
- package/dist/core/agent-session-projection.d.ts.map +1 -1
- package/dist/core/agent-session-projection.js +3 -3
- package/dist/core/agent-session-projection.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +3 -1
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js +2 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session-store.d.ts.map +1 -1
- package/dist/core/agent-session-store.js +6 -1
- package/dist/core/agent-session-store.js.map +1 -1
- package/dist/core/agent-session-tools.d.ts.map +1 -1
- package/dist/core/agent-session-tools.js +13 -0
- package/dist/core/agent-session-tools.js.map +1 -1
- package/dist/core/agent-session.d.ts +24 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +58 -4
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/experimental.d.ts.map +1 -1
- package/dist/core/experimental.js +1 -3
- package/dist/core/experimental.js.map +1 -1
- package/dist/core/extensions/capability-runtime-store.d.ts +20 -1
- package/dist/core/extensions/capability-runtime-store.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime-store.js +67 -0
- package/dist/core/extensions/capability-runtime-store.js.map +1 -1
- package/dist/core/extensions/capability-runtime-types.d.ts +14 -0
- package/dist/core/extensions/capability-runtime-types.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime-types.js +7 -1
- package/dist/core/extensions/capability-runtime-types.js.map +1 -1
- package/dist/core/extensions/capability-runtime.d.ts.map +1 -1
- package/dist/core/extensions/capability-runtime.js +144 -42
- package/dist/core/extensions/capability-runtime.js.map +1 -1
- package/dist/core/extensions/virtual-modules.d.ts.map +1 -1
- package/dist/core/extensions/virtual-modules.js +6 -1
- package/dist/core/extensions/virtual-modules.js.map +1 -1
- package/dist/core/facade/coding-agent-facade.d.ts +1 -1
- package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
- package/dist/core/facade/coding-agent-facade.js +1 -1
- package/dist/core/facade/coding-agent-facade.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/cli.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/cli.js +2 -0
- package/dist/core/i18n/locales/zh-cn/cli.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-final.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-final.js +3 -3
- package/dist/core/i18n/locales/zh-cn/core-contract-final.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js +1 -1
- package/dist/core/i18n/locales/zh-cn/core-contract-plugins.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/core-errors.js +1 -1
- package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/index.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/index.js +2 -0
- package/dist/core/i18n/locales/zh-cn/index.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/interactive-mode.js +5 -0
- package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts +7 -0
- package/dist/core/i18n/locales/zh-cn/session-cleanup.d.ts.map +1 -0
- package/dist/core/i18n/locales/zh-cn/session-cleanup.js +15 -0
- package/dist/core/i18n/locales/zh-cn/session-cleanup.js.map +1 -0
- package/dist/core/i18n/locales/zh-cn/slash-commands.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/slash-commands.js +1 -0
- package/dist/core/i18n/locales/zh-cn/slash-commands.js.map +1 -1
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.d.ts.map +1 -1
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.js +2 -0
- package/dist/core/i18n/locales/zh-cn/tui-components-misc.js.map +1 -1
- package/dist/core/model-resolver.d.ts +2 -0
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +4 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-resource-collection.d.ts.map +1 -1
- package/dist/core/package-resource-collection.js +5 -5
- package/dist/core/package-resource-collection.js.map +1 -1
- package/dist/core/provider-composer.d.ts.map +1 -1
- package/dist/core/provider-composer.js +3 -3
- package/dist/core/provider-composer.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +1 -1
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +30 -8
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-cleanup.d.ts +49 -0
- package/dist/core/session-cleanup.d.ts.map +1 -0
- package/dist/core/session-cleanup.js +159 -0
- package/dist/core/session-cleanup.js.map +1 -0
- package/dist/core/session-index.d.ts +75 -0
- package/dist/core/session-index.d.ts.map +1 -0
- package/dist/core/session-index.js +455 -0
- package/dist/core/session-index.js.map +1 -0
- package/dist/core/session-manager.d.ts +9 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +206 -51
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +5 -10
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +5 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +12 -1
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/timings.d.ts.map +1 -1
- package/dist/core/timings.js +1 -3
- package/dist/core/timings.js.map +1 -1
- package/dist/core/tools/capability-mount.d.ts +40 -0
- package/dist/core/tools/capability-mount.d.ts.map +1 -0
- package/dist/core/tools/capability-mount.js +112 -0
- package/dist/core/tools/capability-mount.js.map +1 -0
- package/dist/core/tools/render-utils.d.ts +1 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/tool-definition.d.ts +1 -1
- package/dist/core/tools/tool-definition.d.ts.map +1 -1
- package/dist/core/tools/tool-definition.js.map +1 -1
- package/dist/core/trace-retention.d.ts +16 -1
- package/dist/core/trace-retention.d.ts.map +1 -1
- package/dist/core/trace-retention.js +43 -20
- package/dist/core/trace-retention.js.map +1 -1
- package/dist/export-html/ansi-to-html.d.ts.map +1 -0
- package/dist/export-html/ansi-to-html.js.map +1 -0
- package/dist/{core/export-html → export-html}/index.d.ts +1 -1
- package/dist/export-html/index.d.ts.map +1 -0
- package/dist/{core/export-html → export-html}/index.js +5 -5
- package/dist/export-html/index.js.map +1 -0
- package/dist/{core/export-html → export-html}/tool-renderer.d.ts +2 -2
- package/dist/export-html/tool-renderer.d.ts.map +1 -0
- package/dist/export-html/tool-renderer.js.map +1 -0
- package/dist/{modes/interactive → host}/model-catalog-refresh.d.ts +1 -1
- package/dist/host/model-catalog-refresh.d.ts.map +1 -0
- package/dist/{modes/interactive → host}/model-catalog-refresh.js +1 -1
- package/dist/host/model-catalog-refresh.js.map +1 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -12
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +26 -14
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/agents-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/agents-view.js +1 -1
- package/dist/modes/interactive/components/agents-view.js.map +1 -1
- package/dist/modes/interactive/components/armin.d.ts.map +1 -1
- package/dist/modes/interactive/components/armin.js +1 -1
- package/dist/modes/interactive/components/armin.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts +6 -0
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +108 -27
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +1 -1
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts +1 -1
- package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
- package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +1 -1
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-entry.js +1 -1
- package/dist/modes/interactive/components/custom-entry.js.map +1 -1
- package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-message.js +1 -1
- package/dist/modes/interactive/components/custom-message.js.map +1 -1
- package/dist/modes/interactive/components/daxnuts.d.ts.map +1 -1
- package/dist/modes/interactive/components/daxnuts.js +1 -1
- package/dist/modes/interactive/components/daxnuts.js.map +1 -1
- package/dist/modes/interactive/components/dialog-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-editor.js +1 -1
- package/dist/modes/interactive/components/dialog-editor.js.map +1 -1
- package/dist/modes/interactive/components/dialog-input.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-input.js +1 -1
- package/dist/modes/interactive/components/dialog-input.js.map +1 -1
- package/dist/modes/interactive/components/dialog-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/dialog-selector.js +1 -1
- package/dist/modes/interactive/components/dialog-selector.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js +1 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
- package/dist/modes/interactive/components/dynamic-border.js +1 -1
- package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts +1 -1
- package/dist/modes/interactive/components/first-time-setup.d.ts.map +1 -1
- package/dist/modes/interactive/components/first-time-setup.js +1 -1
- package/dist/modes/interactive/components/first-time-setup.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +1 -1
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts +1 -1
- package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
- package/dist/modes/interactive/components/mermaid.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +2 -2
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +1 -1
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/components/plugin-manager-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/plugin-manager-entry.js +1 -1
- package/dist/modes/interactive/components/plugin-manager-entry.js.map +1 -1
- package/dist/modes/interactive/components/plugin-selection-entry.d.ts.map +1 -1
- package/dist/modes/interactive/components/plugin-selection-entry.js +1 -1
- package/dist/modes/interactive/components/plugin-selection-entry.js.map +1 -1
- package/dist/modes/interactive/components/queue-manager-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/queue-manager-selector.js +1 -1
- package/dist/modes/interactive/components/queue-manager-selector.js.map +1 -1
- package/dist/modes/interactive/components/render-types.d.ts +1 -1
- package/dist/modes/interactive/components/render-types.d.ts.map +1 -1
- package/dist/modes/interactive/components/render-types.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector-search.js +5 -1
- package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +11 -2
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +1 -1
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-submenu.js +1 -1
- package/dist/modes/interactive/components/settings-submenu.js.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/show-images-selector.js +1 -1
- package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/dist/modes/interactive/components/status-indicator.js +1 -1
- package/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/theme-selector.js +1 -1
- package/dist/modes/interactive/components/theme-selector.js.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/thinking-selector.js +1 -1
- package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +19 -0
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +139 -4
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/tool-run-group.d.ts +44 -0
- package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -0
- package/dist/modes/interactive/components/tool-run-group.js +121 -0
- package/dist/modes/interactive/components/tool-run-group.js.map +1 -0
- package/dist/modes/interactive/components/tree-list.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-list.js +1 -1
- package/dist/modes/interactive/components/tree-list.js.map +1 -1
- package/dist/modes/interactive/components/tree-render.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-render.js +1 -1
- package/dist/modes/interactive/components/tree-render.js.map +1 -1
- package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/tree-selector.js +1 -1
- package/dist/modes/interactive/components/tree-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message-selector.js +1 -1
- package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
- package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/user-message.js +1 -1
- package/dist/modes/interactive/components/user-message.js.map +1 -1
- package/dist/modes/interactive/components/workflow-view.d.ts.map +1 -1
- package/dist/modes/interactive/components/workflow-view.js +1 -1
- package/dist/modes/interactive/components/workflow-view.js.map +1 -1
- package/dist/modes/interactive/interactive-auth.d.ts +1 -1
- package/dist/modes/interactive/interactive-auth.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-auth.js +1 -1
- package/dist/modes/interactive/interactive-auth.js.map +1 -1
- package/dist/modes/interactive/interactive-commands.d.ts +125 -6
- package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-commands.js +698 -4
- package/dist/modes/interactive/interactive-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-events.d.ts +174 -0
- package/dist/modes/interactive/interactive-events.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-events.js +704 -0
- package/dist/modes/interactive/interactive-events.js.map +1 -0
- package/dist/modes/interactive/interactive-format.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-format.js +1 -1
- package/dist/modes/interactive/interactive-format.js.map +1 -1
- package/dist/modes/interactive/interactive-lifecycle.d.ts +94 -0
- package/dist/modes/interactive/interactive-lifecycle.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-lifecycle.js +177 -0
- package/dist/modes/interactive/interactive-lifecycle.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts +254 -129
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +275 -2101
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/interactive-queues.d.ts +96 -0
- package/dist/modes/interactive/interactive-queues.d.ts.map +1 -0
- package/dist/modes/interactive/interactive-queues.js +183 -0
- package/dist/modes/interactive/interactive-queues.js.map +1 -0
- package/dist/modes/interactive/interactive-selectors.d.ts +95 -5
- package/dist/modes/interactive/interactive-selectors.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-selectors.js +517 -6
- package/dist/modes/interactive/interactive-selectors.js.map +1 -1
- package/dist/modes/interactive/startup-services.d.ts +31 -0
- package/dist/modes/interactive/startup-services.d.ts.map +1 -0
- package/dist/modes/interactive/startup-services.js +123 -0
- package/dist/modes/interactive/startup-services.js.map +1 -0
- package/dist/modes/memory-preheat.d.ts +11 -0
- package/dist/modes/memory-preheat.d.ts.map +1 -0
- package/dist/modes/memory-preheat.js +20 -0
- package/dist/modes/memory-preheat.js.map +1 -0
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -1
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/plugins/ecosystem/cli.d.ts.map +1 -1
- package/dist/plugins/ecosystem/cli.js +6 -3
- package/dist/plugins/ecosystem/cli.js.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts +7 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
- package/dist/plugins/ecosystem/node-plugin-bootstrap.js +50 -3
- package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.d.ts +28 -16
- package/dist/plugins/ecosystem/plugin-bootstrap.d.ts.map +1 -1
- package/dist/plugins/ecosystem/plugin-bootstrap.js +35 -33
- package/dist/plugins/ecosystem/plugin-bootstrap.js.map +1 -1
- package/dist/profile/plugin-profiles.d.ts +1 -1
- package/dist/profile/plugin-profiles.d.ts.map +1 -1
- package/dist/profile/plugin-profiles.js +18 -0
- package/dist/profile/plugin-profiles.js.map +1 -1
- package/dist/remote/server-assembly.d.ts.map +1 -1
- package/dist/remote/server-assembly.js +7 -2
- package/dist/remote/server-assembly.js.map +1 -1
- package/dist/{profiles → suites}/builtin-suites.d.ts +14 -4
- package/dist/suites/builtin-suites.d.ts.map +1 -0
- package/dist/{profiles → suites}/builtin-suites.js +20 -5
- package/dist/suites/builtin-suites.js.map +1 -0
- package/dist/suites/resolved-agent-profile.d.ts.map +1 -0
- package/dist/suites/resolved-agent-profile.js.map +1 -0
- package/dist/suites/suite-lifecycle.d.ts.map +1 -0
- package/dist/suites/suite-lifecycle.js.map +1 -0
- package/dist/suites/suite-loader.d.ts.map +1 -0
- package/dist/suites/suite-loader.js.map +1 -0
- package/dist/{modes/interactive/theme → theme}/dark.json +1 -1
- package/dist/{modes/interactive/theme → theme}/light.json +1 -1
- package/dist/{modes/interactive/theme → theme}/theme-controller.d.ts +1 -1
- package/dist/theme/theme-controller.d.ts.map +1 -0
- package/dist/{modes/interactive/theme → theme}/theme-controller.js +1 -1
- package/dist/theme/theme-controller.js.map +1 -0
- package/dist/{modes/interactive/theme → theme}/theme.d.ts +1 -1
- package/dist/theme/theme.d.ts.map +1 -0
- package/dist/{modes/interactive/theme → theme}/theme.js +5 -5
- package/dist/theme/theme.js.map +1 -0
- package/docs/compaction.md +7 -7
- package/docs/environment-variables.md +10 -4
- package/docs/keybindings.md +3 -3
- package/docs/models.md +17 -17
- package/docs/packages.md +1 -1
- package/docs/prompt-templates.md +1 -1
- package/docs/rpc.md +2 -2
- package/docs/sdk.md +5 -5
- package/docs/session-format.md +3 -3
- package/docs/settings.md +368 -354
- package/docs/shell-aliases.md +1 -1
- package/docs/skills.md +1 -1
- package/docs/terminal-setup.md +17 -17
- package/docs/themes.md +5 -5
- package/docs/tmux.md +4 -4
- package/docs/tui.md +1 -1
- package/docs/windows.md +1 -1
- package/examples/extensions/bash-spawn-hook/index.ts +1 -1
- package/examples/extensions/dynamic-resources/dynamic.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -6
- package/examples/extensions/with-deps/plugin.json +1 -1
- package/package.json +2 -2
- package/dist/bundle/chunks/openai-responses-AUJQ3NWT.js +0 -2
- package/dist/bundle/chunks/virtual-modules-WF6WRHP7.js +0 -5
- package/dist/cli/experimental/commands/pi.d.ts +0 -15
- package/dist/cli/experimental/commands/pi.d.ts.map +0 -1
- package/dist/cli/experimental/commands/pi.js.map +0 -1
- package/dist/core/export-html/ansi-to-html.d.ts.map +0 -1
- package/dist/core/export-html/ansi-to-html.js.map +0 -1
- package/dist/core/export-html/index.d.ts.map +0 -1
- package/dist/core/export-html/index.js.map +0 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +0 -1
- package/dist/core/export-html/tool-renderer.js.map +0 -1
- package/dist/core/pi-manifest.d.ts +0 -7
- package/dist/core/pi-manifest.d.ts.map +0 -1
- package/dist/core/pi-manifest.js.map +0 -1
- package/dist/modes/interactive/model-catalog-refresh.d.ts.map +0 -1
- package/dist/modes/interactive/model-catalog-refresh.js.map +0 -1
- package/dist/modes/interactive/theme/theme-controller.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme-controller.js.map +0 -1
- package/dist/modes/interactive/theme/theme.d.ts.map +0 -1
- package/dist/modes/interactive/theme/theme.js.map +0 -1
- package/dist/profiles/builtin-suites.d.ts.map +0 -1
- package/dist/profiles/builtin-suites.js.map +0 -1
- package/dist/profiles/resolved-agent-profile.d.ts.map +0 -1
- package/dist/profiles/resolved-agent-profile.js.map +0 -1
- package/dist/profiles/suite-lifecycle.d.ts.map +0 -1
- package/dist/profiles/suite-lifecycle.js.map +0 -1
- package/dist/profiles/suite-loader.d.ts.map +0 -1
- package/dist/profiles/suite-loader.js.map +0 -1
- package/dist/utils/deprecation.d.ts +0 -4
- package/dist/utils/deprecation.d.ts.map +0 -1
- package/dist/utils/deprecation.js +0 -13
- package/dist/utils/deprecation.js.map +0 -1
- /package/dist/{core/export-html → export-html}/ansi-to-html.d.ts +0 -0
- /package/dist/{core/export-html → export-html}/ansi-to-html.js +0 -0
- /package/dist/{core/export-html → export-html}/template.css +0 -0
- /package/dist/{core/export-html → export-html}/template.html +0 -0
- /package/dist/{core/export-html → export-html}/template.js +0 -0
- /package/dist/{core/export-html → export-html}/tool-renderer.js +0 -0
- /package/dist/{core/export-html → export-html}/vendor/highlight.min.js +0 -0
- /package/dist/{core/export-html → export-html}/vendor/marked.min.js +0 -0
- /package/dist/{profiles → suites}/resolved-agent-profile.d.ts +0 -0
- /package/dist/{profiles → suites}/resolved-agent-profile.js +0 -0
- /package/dist/{profiles → suites}/suite-lifecycle.d.ts +0 -0
- /package/dist/{profiles → suites}/suite-lifecycle.js +0 -0
- /package/dist/{profiles → suites}/suite-loader.d.ts +0 -0
- /package/dist/{profiles → suites}/suite-loader.js +0 -0
- /package/dist/{modes/interactive/theme → theme}/theme-schema.json +0 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { readdir, stat } from "node:fs/promises";
|
|
4
|
+
import { basename, dirname, isAbsolute, join, relative } from "node:path";
|
|
5
|
+
import { getAgentDir, getSessionsDir } from "../config.js";
|
|
6
|
+
import { AGENT_SESSIONS_DIR_NAME } from "./agent-session-paths.js";
|
|
7
|
+
/**
|
|
8
|
+
* 会话元数据索引(session-index.json),设计契约见 docs/design/会话索引.md。
|
|
9
|
+
*
|
|
10
|
+
* 索引是文件系统的投影、永远不是事实源;条目内部分两层:关系(file/dir/id/cwd)
|
|
11
|
+
* 由 readdir 对账保证,内容缓存由 file_mtime_ms 令牌保证(mtime 未变才可信,
|
|
12
|
+
* 变了就重读刷新)。写钩子是预热优化、不承担正确性(设计 §4);读路径
|
|
13
|
+
* (listSessionsViaIndex)负责对账自愈与全量重建。不加跨进程锁——丢失的更新
|
|
14
|
+
* 会被令牌机制限定为无害,下次读取对账时按文件系统纠正(设计 §6)。
|
|
15
|
+
*/
|
|
16
|
+
const SESSION_INDEX_VERSION = 1;
|
|
17
|
+
const SESSION_INDEX_FILE_NAME = "session-index.json";
|
|
18
|
+
/** 节流落盘窗口(设计 §4:每轮消息追加标脏,10s 落盘一次)。 */
|
|
19
|
+
const FLUSH_THROTTLE_MS = 10_000;
|
|
20
|
+
/** 索引文件路径(与 plugin-state.json 同级;getAgentDir() 尊重 AGENT_FORGE_DIR)。 */
|
|
21
|
+
export function getSessionIndexPath() {
|
|
22
|
+
return join(getAgentDir(), SESSION_INDEX_FILE_NAME);
|
|
23
|
+
}
|
|
24
|
+
let pendingFlush;
|
|
25
|
+
let flushTimer;
|
|
26
|
+
let exitHookRegistered = false;
|
|
27
|
+
function clearPending() {
|
|
28
|
+
pendingFlush = undefined;
|
|
29
|
+
if (flushTimer !== undefined) {
|
|
30
|
+
clearTimeout(flushTimer);
|
|
31
|
+
flushTimer = undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function ensureExitFlushHook() {
|
|
35
|
+
if (exitHookRegistered)
|
|
36
|
+
return;
|
|
37
|
+
exitHookRegistered = true;
|
|
38
|
+
process.once("exit", () => {
|
|
39
|
+
flushSessionIndexNow();
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function armDirty(indexPath, state) {
|
|
43
|
+
pendingFlush = { indexPath, state };
|
|
44
|
+
ensureExitFlushHook();
|
|
45
|
+
if (flushTimer === undefined) {
|
|
46
|
+
flushTimer = setTimeout(() => {
|
|
47
|
+
flushTimer = undefined;
|
|
48
|
+
flushSessionIndexNow();
|
|
49
|
+
}, FLUSH_THROTTLE_MS);
|
|
50
|
+
flushTimer.unref();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** 立即落盘脏状态(测试与 exit 钩子共用);无脏状态时为 no-op。 */
|
|
54
|
+
export function flushSessionIndexNow() {
|
|
55
|
+
const pending = pendingFlush;
|
|
56
|
+
if (!pending)
|
|
57
|
+
return;
|
|
58
|
+
clearPending();
|
|
59
|
+
try {
|
|
60
|
+
writeStateSync(pending.indexPath, pending.state);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// 失败留给对账自愈(设计 §6),不向会话写入路径传播。
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// 读写原语
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
function emptyState() {
|
|
70
|
+
return { version: SESSION_INDEX_VERSION, updated_at_ms: 0, projects: [], sessions: [] };
|
|
71
|
+
}
|
|
72
|
+
function safeMs(value) {
|
|
73
|
+
return Number.isFinite(value) ? value : 0;
|
|
74
|
+
}
|
|
75
|
+
function isSessionFileName(file) {
|
|
76
|
+
return file.endsWith(".jsonl") && !file.endsWith(".trace.jsonl");
|
|
77
|
+
}
|
|
78
|
+
function isFiniteNumber(value) {
|
|
79
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* 条目级最小形状校验:必填字段类型/finite 不符的条目直接丢弃(视同缺失,交给
|
|
83
|
+
* 对账/重建自愈,覆盖设计 §2 目标 3 的字段级损坏);可选字段仅在为 string 时
|
|
84
|
+
* 保留,否则按键缺席处理。
|
|
85
|
+
*/
|
|
86
|
+
function coerceSessionEntry(value) {
|
|
87
|
+
if (typeof value !== "object" || value === null)
|
|
88
|
+
return null;
|
|
89
|
+
const raw = value;
|
|
90
|
+
if (typeof raw.file !== "string" || typeof raw.dir !== "string" || typeof raw.id !== "string")
|
|
91
|
+
return null;
|
|
92
|
+
if (typeof raw.cwd !== "string")
|
|
93
|
+
return null;
|
|
94
|
+
if (!isFiniteNumber(raw.created_ms) || !isFiniteNumber(raw.modified_ms) || !isFiniteNumber(raw.message_count)) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
if (typeof raw.first_message !== "string")
|
|
98
|
+
return null;
|
|
99
|
+
return {
|
|
100
|
+
file: raw.file,
|
|
101
|
+
dir: raw.dir,
|
|
102
|
+
id: raw.id,
|
|
103
|
+
cwd: raw.cwd,
|
|
104
|
+
...(isFiniteNumber(raw.file_mtime_ms) ? { file_mtime_ms: raw.file_mtime_ms } : {}),
|
|
105
|
+
...(typeof raw.name === "string" ? { name: raw.name } : {}),
|
|
106
|
+
...(typeof raw.parent_session_path === "string" ? { parent_session_path: raw.parent_session_path } : {}),
|
|
107
|
+
...(typeof raw.profile_id === "string" ? { profile_id: raw.profile_id } : {}),
|
|
108
|
+
...(typeof raw.profile_version === "string" ? { profile_version: raw.profile_version } : {}),
|
|
109
|
+
created_ms: raw.created_ms,
|
|
110
|
+
modified_ms: raw.modified_ms,
|
|
111
|
+
message_count: raw.message_count,
|
|
112
|
+
first_message: raw.first_message,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
function coerceProjectEntry(value) {
|
|
116
|
+
if (typeof value !== "object" || value === null)
|
|
117
|
+
return null;
|
|
118
|
+
const raw = value;
|
|
119
|
+
// 项目条目只有 dir/cwd 关系;last_active 由成员条目 modified_ms 服务时派生
|
|
120
|
+
// (设计 §3),入库时的任何附加键一律忽略。
|
|
121
|
+
if (typeof raw.dir !== "string" || typeof raw.cwd !== "string")
|
|
122
|
+
return null;
|
|
123
|
+
return { dir: raw.dir, cwd: raw.cwd };
|
|
124
|
+
}
|
|
125
|
+
/** 读取并校验索引文件;不存在/JSON 损坏/版本不符返回 null(由调用方重建或忽略)。 */
|
|
126
|
+
function readIndexFile(indexPath) {
|
|
127
|
+
let content;
|
|
128
|
+
try {
|
|
129
|
+
content = readFileSync(indexPath, "utf8");
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
try {
|
|
135
|
+
const parsed = JSON.parse(content);
|
|
136
|
+
if (parsed.version !== SESSION_INDEX_VERSION)
|
|
137
|
+
return null;
|
|
138
|
+
if (!Array.isArray(parsed.projects) || !Array.isArray(parsed.sessions))
|
|
139
|
+
return null;
|
|
140
|
+
const projects = parsed.projects.map(coerceProjectEntry).filter((entry) => {
|
|
141
|
+
return entry !== null;
|
|
142
|
+
});
|
|
143
|
+
const sessions = parsed.sessions.map(coerceSessionEntry).filter((entry) => {
|
|
144
|
+
return entry !== null;
|
|
145
|
+
});
|
|
146
|
+
return { version: SESSION_INDEX_VERSION, updated_at_ms: 0, projects, sessions };
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/** 原子写(temp + rename,同 ecosystem/state.ts 模式);同步 API 供 exit 钩子共用。 */
|
|
153
|
+
function writeStateSync(indexPath, state) {
|
|
154
|
+
const parent = dirname(indexPath);
|
|
155
|
+
mkdirSync(parent, { recursive: true });
|
|
156
|
+
const temporaryPath = join(parent, `.${basename(indexPath)}.${randomUUID()}.tmp`);
|
|
157
|
+
try {
|
|
158
|
+
state.updated_at_ms = Date.now();
|
|
159
|
+
writeFileSync(temporaryPath, `${JSON.stringify(state)}\n`, "utf8");
|
|
160
|
+
renameSync(temporaryPath, indexPath);
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
try {
|
|
164
|
+
unlinkSync(temporaryPath);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// rename 成功后 tmp 已不存在;清理失败不掩盖写入结果。
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/** 可变状态:优先续用未落盘的脏快照,避免节流窗口内的读-改-写互相覆盖。 */
|
|
172
|
+
function loadMutableState(indexPath) {
|
|
173
|
+
if (pendingFlush?.indexPath === indexPath)
|
|
174
|
+
return pendingFlush.state;
|
|
175
|
+
return readIndexFile(indexPath) ?? emptyState();
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* 解析会话路径在索引中的位置:dir = 相对 sessions 根的父目录名(不从 cwd 重推导,
|
|
179
|
+
* 规避 Windows 盘符大小写陷阱,设计 §3),file = basename。
|
|
180
|
+
* sessions 根之外、根一级散落文件、非 `*.jsonl` 与 `*.trace.jsonl` 一律返回 null。
|
|
181
|
+
*/
|
|
182
|
+
function locationInRoot(sessionsRoot, sessionPath) {
|
|
183
|
+
const rel = relative(sessionsRoot, sessionPath);
|
|
184
|
+
if (rel === "" || rel.startsWith("..") || isAbsolute(rel))
|
|
185
|
+
return null;
|
|
186
|
+
const dir = dirname(rel);
|
|
187
|
+
if (dir === "." || dir === "..")
|
|
188
|
+
return null;
|
|
189
|
+
const file = basename(rel);
|
|
190
|
+
if (!isSessionFileName(file))
|
|
191
|
+
return null;
|
|
192
|
+
return { dir, file };
|
|
193
|
+
}
|
|
194
|
+
function findSessionEntry(state, dir, file) {
|
|
195
|
+
return state.sessions.find((entry) => entry.dir === dir && entry.file === file);
|
|
196
|
+
}
|
|
197
|
+
function touchProject(state, dir, cwd) {
|
|
198
|
+
if (state.projects.some((project) => project.dir === dir))
|
|
199
|
+
return;
|
|
200
|
+
state.projects.push({ dir, cwd });
|
|
201
|
+
}
|
|
202
|
+
function addSessionFromInfo(state, dir, file, info, mtimeMs) {
|
|
203
|
+
state.sessions = state.sessions.filter((entry) => !(entry.dir === dir && entry.file === file));
|
|
204
|
+
state.sessions.push({
|
|
205
|
+
file,
|
|
206
|
+
dir,
|
|
207
|
+
id: info.id,
|
|
208
|
+
cwd: info.cwd,
|
|
209
|
+
...(info.name === undefined ? {} : { name: info.name }),
|
|
210
|
+
...(info.parentSessionPath === undefined ? {} : { parent_session_path: info.parentSessionPath }),
|
|
211
|
+
...(info.profileId === undefined ? {} : { profile_id: info.profileId }),
|
|
212
|
+
...(info.profileVersion === undefined ? {} : { profile_version: info.profileVersion }),
|
|
213
|
+
...(mtimeMs === undefined ? {} : { file_mtime_ms: mtimeMs }),
|
|
214
|
+
created_ms: safeMs(info.created.getTime()),
|
|
215
|
+
modified_ms: safeMs(info.modified.getTime()),
|
|
216
|
+
message_count: info.messageCount,
|
|
217
|
+
first_message: info.firstMessage,
|
|
218
|
+
});
|
|
219
|
+
touchProject(state, dir, info.cwd);
|
|
220
|
+
}
|
|
221
|
+
// ---------------------------------------------------------------------------
|
|
222
|
+
// 写路径(设计 §4)
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
/**
|
|
225
|
+
* upsert 单会话条目并按 immediate 决定落盘时机。预热优化(设计 §4):条目缺失
|
|
226
|
+
* 或过期由读路径的 mtime 令牌对账刷新,不承担正确性。内部错误一律吞掉
|
|
227
|
+
* (fail-open):索引是投影,写入失败由下次读取对账自愈,绝不影响会话持久化。
|
|
228
|
+
*/
|
|
229
|
+
export function recordSessionUpdate(input) {
|
|
230
|
+
try {
|
|
231
|
+
const sessionsRoot = getSessionsDir();
|
|
232
|
+
const location = locationInRoot(sessionsRoot, input.sessionPath);
|
|
233
|
+
if (!location)
|
|
234
|
+
return;
|
|
235
|
+
// 缓存有效期令牌 = 当前文件 mtime;stat 失败则条目不带令牌(视为过期,无害)。
|
|
236
|
+
let mtimeMs;
|
|
237
|
+
try {
|
|
238
|
+
mtimeMs = statSync(input.sessionPath).mtimeMs;
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
mtimeMs = undefined;
|
|
242
|
+
}
|
|
243
|
+
const indexPath = getSessionIndexPath();
|
|
244
|
+
const state = loadMutableState(indexPath);
|
|
245
|
+
state.sessions = state.sessions.filter((entry) => !(entry.dir === location.dir && entry.file === location.file));
|
|
246
|
+
const modifiedMs = safeMs(input.modifiedMs);
|
|
247
|
+
state.sessions.push({
|
|
248
|
+
file: location.file,
|
|
249
|
+
dir: location.dir,
|
|
250
|
+
id: input.sessionId,
|
|
251
|
+
cwd: input.cwd,
|
|
252
|
+
...(input.name === undefined ? {} : { name: input.name }),
|
|
253
|
+
...(input.parentSessionPath === undefined ? {} : { parent_session_path: input.parentSessionPath }),
|
|
254
|
+
...(input.profileId === undefined ? {} : { profile_id: input.profileId }),
|
|
255
|
+
...(input.profileVersion === undefined ? {} : { profile_version: input.profileVersion }),
|
|
256
|
+
...(mtimeMs === undefined ? {} : { file_mtime_ms: mtimeMs }),
|
|
257
|
+
created_ms: safeMs(input.createdMs),
|
|
258
|
+
modified_ms: modifiedMs,
|
|
259
|
+
message_count: input.messageCount,
|
|
260
|
+
first_message: input.firstMessage,
|
|
261
|
+
});
|
|
262
|
+
touchProject(state, location.dir, input.cwd);
|
|
263
|
+
if (input.immediate) {
|
|
264
|
+
clearPending();
|
|
265
|
+
writeStateSync(indexPath, state);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
armDirty(indexPath, state);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// 索引维护绝不影响会话写入(设计 §4/§6)。
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* 按路径移除条目并立即原子落盘;索引不存在/损坏/路径不在 sessions 根时静默 no-op
|
|
277
|
+
* (不抛错、不重建,设计 §6)。
|
|
278
|
+
*/
|
|
279
|
+
export function removeSessionFromIndex(sessionPath) {
|
|
280
|
+
try {
|
|
281
|
+
const location = locationInRoot(getSessionsDir(), sessionPath);
|
|
282
|
+
if (!location)
|
|
283
|
+
return;
|
|
284
|
+
const indexPath = getSessionIndexPath();
|
|
285
|
+
const state = loadMutableState(indexPath);
|
|
286
|
+
const before = state.sessions.length;
|
|
287
|
+
state.sessions = state.sessions.filter((entry) => !(entry.dir === location.dir && entry.file === location.file));
|
|
288
|
+
if (state.sessions.length === before)
|
|
289
|
+
return;
|
|
290
|
+
clearPending();
|
|
291
|
+
writeStateSync(indexPath, state);
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// 对账会在下次读取自愈(设计 §6)。
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
// 读路径与对账(设计 §5)
|
|
299
|
+
// ---------------------------------------------------------------------------
|
|
300
|
+
function sessionInfoFromEntry(sessionsRoot, entry) {
|
|
301
|
+
return {
|
|
302
|
+
path: join(sessionsRoot, entry.dir, entry.file),
|
|
303
|
+
id: entry.id,
|
|
304
|
+
cwd: entry.cwd,
|
|
305
|
+
...(entry.name === undefined ? {} : { name: entry.name }),
|
|
306
|
+
...(entry.parent_session_path === undefined ? {} : { parentSessionPath: entry.parent_session_path }),
|
|
307
|
+
...(entry.profile_id === undefined ? {} : { profileId: entry.profile_id }),
|
|
308
|
+
...(entry.profile_version === undefined ? {} : { profileVersion: entry.profile_version }),
|
|
309
|
+
created: new Date(entry.created_ms),
|
|
310
|
+
modified: new Date(entry.modified_ms),
|
|
311
|
+
messageCount: entry.message_count,
|
|
312
|
+
firstMessage: entry.first_message,
|
|
313
|
+
allMessagesText: "",
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
function sortedSessions(sessionsRoot, state) {
|
|
317
|
+
const ordered = [...state.sessions].sort((a, b) => b.modified_ms - a.modified_ms || b.file.localeCompare(a.file));
|
|
318
|
+
return ordered.map((entry) => sessionInfoFromEntry(sessionsRoot, entry));
|
|
319
|
+
}
|
|
320
|
+
/** 重建路径:由全量扫描结果构建索引状态,逐文件 stat 写入 mtime 令牌。 */
|
|
321
|
+
async function stateFromSessions(sessionsRoot, sessions) {
|
|
322
|
+
const state = emptyState();
|
|
323
|
+
for (const info of sessions) {
|
|
324
|
+
const location = locationInRoot(sessionsRoot, info.path);
|
|
325
|
+
if (!location)
|
|
326
|
+
continue;
|
|
327
|
+
let mtimeMs;
|
|
328
|
+
try {
|
|
329
|
+
mtimeMs = (await stat(info.path)).mtimeMs;
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
mtimeMs = undefined;
|
|
333
|
+
}
|
|
334
|
+
addSessionFromInfo(state, location.dir, location.file, info, mtimeMs);
|
|
335
|
+
}
|
|
336
|
+
return state;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* 对账:目录名集合 diff + 目录内文件名集合 diff,逐文件 stat 与条目的
|
|
340
|
+
* file_mtime_ms 令牌比对(设计 §5)——条目缺失 → buildInfo 补;mtime 与令牌
|
|
341
|
+
* 一致 → 缓存可信直接沿用;不一致或令牌缺失 → buildInfo 重读刷新缓存与新令牌
|
|
342
|
+
* (重读失败 = 文件已不再是会话 → 剔除陈旧条目);索引有、磁盘无 → 剔除;
|
|
343
|
+
* 消失目录连同其 project 行剔除。返回是否有变更。
|
|
344
|
+
*/
|
|
345
|
+
async function reconcileIndex(sessionsRoot, state, buildInfo, signal) {
|
|
346
|
+
// 磁盘清单:目录名 → (文件名 → stat mtime)。stat 失败(readdir 与 stat 之间
|
|
347
|
+
// 被删/不可读)视同本轮缺席,下轮对账收敛。
|
|
348
|
+
const diskDirs = new Map();
|
|
349
|
+
let rootEntries;
|
|
350
|
+
try {
|
|
351
|
+
rootEntries = await readdir(sessionsRoot, { withFileTypes: true });
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// sessions 根不可读视同空盘:剔除全部条目(索引是投影,根恢复后重建)。
|
|
355
|
+
rootEntries = [];
|
|
356
|
+
}
|
|
357
|
+
for (const entry of rootEntries) {
|
|
358
|
+
if (entry.name === AGENT_SESSIONS_DIR_NAME)
|
|
359
|
+
continue;
|
|
360
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
361
|
+
continue;
|
|
362
|
+
let fileNames;
|
|
363
|
+
try {
|
|
364
|
+
fileNames = await readdir(join(sessionsRoot, entry.name));
|
|
365
|
+
}
|
|
366
|
+
catch {
|
|
367
|
+
// 目录不可读视同已清空,其索引条目被剔除(悬挂容忍,设计 §6)。
|
|
368
|
+
fileNames = [];
|
|
369
|
+
}
|
|
370
|
+
const files = new Map();
|
|
371
|
+
for (const file of fileNames) {
|
|
372
|
+
if (!isSessionFileName(file))
|
|
373
|
+
continue;
|
|
374
|
+
signal?.throwIfAborted();
|
|
375
|
+
try {
|
|
376
|
+
files.set(file, (await stat(join(sessionsRoot, entry.name, file))).mtimeMs);
|
|
377
|
+
}
|
|
378
|
+
catch {
|
|
379
|
+
// 本轮视同缺席。
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
diskDirs.set(entry.name, files);
|
|
383
|
+
}
|
|
384
|
+
let changed = false;
|
|
385
|
+
for (const [dir, files] of diskDirs) {
|
|
386
|
+
for (const [file, mtimeMs] of files) {
|
|
387
|
+
const existing = findSessionEntry(state, dir, file);
|
|
388
|
+
if (existing && existing.file_mtime_ms !== undefined && existing.file_mtime_ms === mtimeMs)
|
|
389
|
+
continue;
|
|
390
|
+
signal?.throwIfAborted();
|
|
391
|
+
const info = await buildInfo(join(sessionsRoot, dir, file));
|
|
392
|
+
if (!info) {
|
|
393
|
+
if (existing) {
|
|
394
|
+
// 文件已不再解析为会话(损坏/改写):剔除陈旧条目。
|
|
395
|
+
state.sessions = state.sessions.filter((candidate) => candidate !== existing);
|
|
396
|
+
changed = true;
|
|
397
|
+
}
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
addSessionFromInfo(state, dir, file, info, mtimeMs);
|
|
401
|
+
changed = true;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
const keptSessions = state.sessions.filter((entry) => diskDirs.get(entry.dir)?.has(entry.file));
|
|
405
|
+
if (keptSessions.length !== state.sessions.length) {
|
|
406
|
+
state.sessions = keptSessions;
|
|
407
|
+
changed = true;
|
|
408
|
+
}
|
|
409
|
+
const keptProjects = state.projects.filter((project) => diskDirs.has(project.dir));
|
|
410
|
+
if (keptProjects.length !== state.projects.length) {
|
|
411
|
+
state.projects = keptProjects;
|
|
412
|
+
changed = true;
|
|
413
|
+
}
|
|
414
|
+
return changed;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* listAll 默认布局分支的索引读路径。返回 undefined 表示索引层意外失败(IO 等),
|
|
418
|
+
* 调用方应回退到旧全量扫描(fail-open,设计 §5);中止按惯例抛 AbortError。
|
|
419
|
+
*/
|
|
420
|
+
export async function listSessionsViaIndex(input) {
|
|
421
|
+
const { sessionsRoot, buildInfo, scanAll, onHit, signal } = input;
|
|
422
|
+
try {
|
|
423
|
+
signal?.throwIfAborted();
|
|
424
|
+
const indexPath = getSessionIndexPath();
|
|
425
|
+
let state;
|
|
426
|
+
if (pendingFlush?.indexPath === indexPath) {
|
|
427
|
+
// 节流窗口内已积累的更新是对账基准:对账落盘不得把窗口内更新回退覆盖。
|
|
428
|
+
state = pendingFlush.state;
|
|
429
|
+
}
|
|
430
|
+
else {
|
|
431
|
+
const fromDisk = readIndexFile(indexPath);
|
|
432
|
+
if (fromDisk === null) {
|
|
433
|
+
// 缺失/损坏/版本不符 → 旧扫描全量重建并落盘(与旧行为同价,设计 §5.1)。
|
|
434
|
+
const sessions = await scanAll();
|
|
435
|
+
writeStateSync(indexPath, await stateFromSessions(sessionsRoot, sessions));
|
|
436
|
+
return sessions;
|
|
437
|
+
}
|
|
438
|
+
state = fromDisk;
|
|
439
|
+
}
|
|
440
|
+
const changed = await reconcileIndex(sessionsRoot, state, buildInfo, signal);
|
|
441
|
+
if (changed) {
|
|
442
|
+
if (pendingFlush?.indexPath === indexPath)
|
|
443
|
+
clearPending();
|
|
444
|
+
writeStateSync(indexPath, state);
|
|
445
|
+
}
|
|
446
|
+
const sessions = sortedSessions(sessionsRoot, state);
|
|
447
|
+
onHit?.(sessions);
|
|
448
|
+
return sessions;
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
451
|
+
signal?.throwIfAborted();
|
|
452
|
+
return undefined;
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
//# sourceMappingURL=session-index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-index.js","sourceRoot":"","sources":["../../src/core/session-index.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { type Dirent, mkdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { readdir, stat } from \"node:fs/promises\";\nimport { basename, dirname, isAbsolute, join, relative } from \"node:path\";\nimport { getAgentDir, getSessionsDir } from \"../config.ts\";\nimport { AGENT_SESSIONS_DIR_NAME } from \"./agent-session-paths.ts\";\nimport type { SessionInfo } from \"./session-manager.ts\";\n\n/**\n * 会话元数据索引(session-index.json),设计契约见 docs/design/会话索引.md。\n *\n * 索引是文件系统的投影、永远不是事实源;条目内部分两层:关系(file/dir/id/cwd)\n * 由 readdir 对账保证,内容缓存由 file_mtime_ms 令牌保证(mtime 未变才可信,\n * 变了就重读刷新)。写钩子是预热优化、不承担正确性(设计 §4);读路径\n * (listSessionsViaIndex)负责对账自愈与全量重建。不加跨进程锁——丢失的更新\n * 会被令牌机制限定为无害,下次读取对账时按文件系统纠正(设计 §6)。\n */\n\nconst SESSION_INDEX_VERSION = 1;\nconst SESSION_INDEX_FILE_NAME = \"session-index.json\";\n/** 节流落盘窗口(设计 §4:每轮消息追加标脏,10s 落盘一次)。 */\nconst FLUSH_THROTTLE_MS = 10_000;\n\nexport interface SessionIndexProjectEntry {\n\t/** 项目目录名(getDefaultSessionDirPath(cwd) 的编码目录名,不从 cwd 重推导)。 */\n\tdir: string;\n\tcwd: string;\n}\n\nexport interface SessionIndexSessionEntry {\n\t/** 会话文件 basename;键 = (dir, file)。 */\n\tfile: string;\n\tdir: string;\n\tid: string;\n\tcwd: string;\n\t/**\n\t * 缓存有效期令牌:条目写入时该会话文件的 stat mtime。缺失或与磁盘不一致 =\n\t * 缓存过期,对账时重读刷新(设计 §3/§5)。\n\t */\n\tfile_mtime_ms?: number;\n\tname?: string;\n\tparent_session_path?: string;\n\t/** 创建时锁定的 profile(可选字段,向后可读;与 SessionHeader 对应)。 */\n\tprofile_id?: string;\n\tprofile_version?: string;\n\tcreated_ms: number;\n\tmodified_ms: number;\n\tmessage_count: number;\n\tfirst_message: string;\n}\n\ninterface SessionIndexFile {\n\tversion: number;\n\tupdated_at_ms: number;\n\tprojects: SessionIndexProjectEntry[];\n\tsessions: SessionIndexSessionEntry[];\n}\n\nexport interface SessionIndexUpdateInput {\n\t/** 绝对会话文件路径(默认布局下位于 sessions 根之内)。 */\n\tsessionPath: string;\n\tsessionId: string;\n\tcwd: string;\n\tname?: string;\n\tparentSessionPath?: string;\n\tprofileId?: string;\n\tprofileVersion?: string;\n\tcreatedMs: number;\n\tmodifiedMs: number;\n\tmessageCount: number;\n\tfirstMessage: string;\n\t/** true = 同步原子落盘;false = 标脏,节流窗口内落盘。 */\n\timmediate: boolean;\n}\n\nexport interface ListSessionsViaIndexInput {\n\t/** sessions 根目录(…/sessions)绝对路径。 */\n\tsessionsRoot: string;\n\t/** 完整 SessionInfo 构建器(session-manager 的 buildSessionInfo);返回 null = 非会话文件。 */\n\tbuildInfo: (path: string) => Promise<SessionInfo | null>;\n\t/** 旧全量扫描委托:索引缺失/损坏/版本不符时用于重建索引(与旧 listAll 同价)。 */\n\tscanAll: () => Promise<SessionInfo[]>;\n\t/** 索引命中时的单次完整已排序快照回调(重建路径的进度由 scanAll 按旧语义发布)。 */\n\tonHit?: (sessions: SessionInfo[]) => void;\n\tsignal?: AbortSignal;\n}\n\n/** 索引文件路径(与 plugin-state.json 同级;getAgentDir() 尊重 AGENT_FORGE_DIR)。 */\nexport function getSessionIndexPath(): string {\n\treturn join(getAgentDir(), SESSION_INDEX_FILE_NAME);\n}\n\n// ---------------------------------------------------------------------------\n// 模块级脏状态:pendingFlush 捕获写入目标与快照,进程 exit 时同步落盘。\n// 按路径比较,测试间 ENV_AGENT_DIR 切换不会串写。\n// ---------------------------------------------------------------------------\n\ninterface PendingFlush {\n\tindexPath: string;\n\tstate: SessionIndexFile;\n}\n\nlet pendingFlush: PendingFlush | undefined;\nlet flushTimer: ReturnType<typeof setTimeout> | undefined;\nlet exitHookRegistered = false;\n\nfunction clearPending(): void {\n\tpendingFlush = undefined;\n\tif (flushTimer !== undefined) {\n\t\tclearTimeout(flushTimer);\n\t\tflushTimer = undefined;\n\t}\n}\n\nfunction ensureExitFlushHook(): void {\n\tif (exitHookRegistered) return;\n\texitHookRegistered = true;\n\tprocess.once(\"exit\", () => {\n\t\tflushSessionIndexNow();\n\t});\n}\n\nfunction armDirty(indexPath: string, state: SessionIndexFile): void {\n\tpendingFlush = { indexPath, state };\n\tensureExitFlushHook();\n\tif (flushTimer === undefined) {\n\t\tflushTimer = setTimeout(() => {\n\t\t\tflushTimer = undefined;\n\t\t\tflushSessionIndexNow();\n\t\t}, FLUSH_THROTTLE_MS);\n\t\tflushTimer.unref();\n\t}\n}\n\n/** 立即落盘脏状态(测试与 exit 钩子共用);无脏状态时为 no-op。 */\nexport function flushSessionIndexNow(): void {\n\tconst pending = pendingFlush;\n\tif (!pending) return;\n\tclearPending();\n\ttry {\n\t\twriteStateSync(pending.indexPath, pending.state);\n\t} catch {\n\t\t// 失败留给对账自愈(设计 §6),不向会话写入路径传播。\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// 读写原语\n// ---------------------------------------------------------------------------\n\nfunction emptyState(): SessionIndexFile {\n\treturn { version: SESSION_INDEX_VERSION, updated_at_ms: 0, projects: [], sessions: [] };\n}\n\nfunction safeMs(value: number): number {\n\treturn Number.isFinite(value) ? value : 0;\n}\n\nfunction isSessionFileName(file: string): boolean {\n\treturn file.endsWith(\".jsonl\") && !file.endsWith(\".trace.jsonl\");\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value);\n}\n\n/**\n * 条目级最小形状校验:必填字段类型/finite 不符的条目直接丢弃(视同缺失,交给\n * 对账/重建自愈,覆盖设计 §2 目标 3 的字段级损坏);可选字段仅在为 string 时\n * 保留,否则按键缺席处理。\n */\nfunction coerceSessionEntry(value: unknown): SessionIndexSessionEntry | null {\n\tif (typeof value !== \"object\" || value === null) return null;\n\tconst raw = value as Record<string, unknown>;\n\tif (typeof raw.file !== \"string\" || typeof raw.dir !== \"string\" || typeof raw.id !== \"string\") return null;\n\tif (typeof raw.cwd !== \"string\") return null;\n\tif (!isFiniteNumber(raw.created_ms) || !isFiniteNumber(raw.modified_ms) || !isFiniteNumber(raw.message_count)) {\n\t\treturn null;\n\t}\n\tif (typeof raw.first_message !== \"string\") return null;\n\treturn {\n\t\tfile: raw.file,\n\t\tdir: raw.dir,\n\t\tid: raw.id,\n\t\tcwd: raw.cwd,\n\t\t...(isFiniteNumber(raw.file_mtime_ms) ? { file_mtime_ms: raw.file_mtime_ms } : {}),\n\t\t...(typeof raw.name === \"string\" ? { name: raw.name } : {}),\n\t\t...(typeof raw.parent_session_path === \"string\" ? { parent_session_path: raw.parent_session_path } : {}),\n\t\t...(typeof raw.profile_id === \"string\" ? { profile_id: raw.profile_id } : {}),\n\t\t...(typeof raw.profile_version === \"string\" ? { profile_version: raw.profile_version } : {}),\n\t\tcreated_ms: raw.created_ms,\n\t\tmodified_ms: raw.modified_ms,\n\t\tmessage_count: raw.message_count,\n\t\tfirst_message: raw.first_message,\n\t};\n}\n\nfunction coerceProjectEntry(value: unknown): SessionIndexProjectEntry | null {\n\tif (typeof value !== \"object\" || value === null) return null;\n\tconst raw = value as Record<string, unknown>;\n\t// 项目条目只有 dir/cwd 关系;last_active 由成员条目 modified_ms 服务时派生\n\t// (设计 §3),入库时的任何附加键一律忽略。\n\tif (typeof raw.dir !== \"string\" || typeof raw.cwd !== \"string\") return null;\n\treturn { dir: raw.dir, cwd: raw.cwd };\n}\n\n/** 读取并校验索引文件;不存在/JSON 损坏/版本不符返回 null(由调用方重建或忽略)。 */\nfunction readIndexFile(indexPath: string): SessionIndexFile | null {\n\tlet content: string;\n\ttry {\n\t\tcontent = readFileSync(indexPath, \"utf8\");\n\t} catch {\n\t\treturn null;\n\t}\n\ttry {\n\t\tconst parsed = JSON.parse(content) as { version?: unknown; projects?: unknown; sessions?: unknown };\n\t\tif (parsed.version !== SESSION_INDEX_VERSION) return null;\n\t\tif (!Array.isArray(parsed.projects) || !Array.isArray(parsed.sessions)) return null;\n\t\tconst projects = parsed.projects.map(coerceProjectEntry).filter((entry): entry is SessionIndexProjectEntry => {\n\t\t\treturn entry !== null;\n\t\t});\n\t\tconst sessions = parsed.sessions.map(coerceSessionEntry).filter((entry): entry is SessionIndexSessionEntry => {\n\t\t\treturn entry !== null;\n\t\t});\n\t\treturn { version: SESSION_INDEX_VERSION, updated_at_ms: 0, projects, sessions };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/** 原子写(temp + rename,同 ecosystem/state.ts 模式);同步 API 供 exit 钩子共用。 */\nfunction writeStateSync(indexPath: string, state: SessionIndexFile): void {\n\tconst parent = dirname(indexPath);\n\tmkdirSync(parent, { recursive: true });\n\tconst temporaryPath = join(parent, `.${basename(indexPath)}.${randomUUID()}.tmp`);\n\ttry {\n\t\tstate.updated_at_ms = Date.now();\n\t\twriteFileSync(temporaryPath, `${JSON.stringify(state)}\\n`, \"utf8\");\n\t\trenameSync(temporaryPath, indexPath);\n\t} finally {\n\t\ttry {\n\t\t\tunlinkSync(temporaryPath);\n\t\t} catch {\n\t\t\t// rename 成功后 tmp 已不存在;清理失败不掩盖写入结果。\n\t\t}\n\t}\n}\n\n/** 可变状态:优先续用未落盘的脏快照,避免节流窗口内的读-改-写互相覆盖。 */\nfunction loadMutableState(indexPath: string): SessionIndexFile {\n\tif (pendingFlush?.indexPath === indexPath) return pendingFlush.state;\n\treturn readIndexFile(indexPath) ?? emptyState();\n}\n\n/**\n * 解析会话路径在索引中的位置:dir = 相对 sessions 根的父目录名(不从 cwd 重推导,\n * 规避 Windows 盘符大小写陷阱,设计 §3),file = basename。\n * sessions 根之外、根一级散落文件、非 `*.jsonl` 与 `*.trace.jsonl` 一律返回 null。\n */\nfunction locationInRoot(sessionsRoot: string, sessionPath: string): { dir: string; file: string } | null {\n\tconst rel = relative(sessionsRoot, sessionPath);\n\tif (rel === \"\" || rel.startsWith(\"..\") || isAbsolute(rel)) return null;\n\tconst dir = dirname(rel);\n\tif (dir === \".\" || dir === \"..\") return null;\n\tconst file = basename(rel);\n\tif (!isSessionFileName(file)) return null;\n\treturn { dir, file };\n}\n\nfunction findSessionEntry(state: SessionIndexFile, dir: string, file: string): SessionIndexSessionEntry | undefined {\n\treturn state.sessions.find((entry) => entry.dir === dir && entry.file === file);\n}\n\nfunction touchProject(state: SessionIndexFile, dir: string, cwd: string): void {\n\tif (state.projects.some((project) => project.dir === dir)) return;\n\tstate.projects.push({ dir, cwd });\n}\n\nfunction addSessionFromInfo(\n\tstate: SessionIndexFile,\n\tdir: string,\n\tfile: string,\n\tinfo: SessionInfo,\n\tmtimeMs?: number,\n): void {\n\tstate.sessions = state.sessions.filter((entry) => !(entry.dir === dir && entry.file === file));\n\tstate.sessions.push({\n\t\tfile,\n\t\tdir,\n\t\tid: info.id,\n\t\tcwd: info.cwd,\n\t\t...(info.name === undefined ? {} : { name: info.name }),\n\t\t...(info.parentSessionPath === undefined ? {} : { parent_session_path: info.parentSessionPath }),\n\t\t...(info.profileId === undefined ? {} : { profile_id: info.profileId }),\n\t\t...(info.profileVersion === undefined ? {} : { profile_version: info.profileVersion }),\n\t\t...(mtimeMs === undefined ? {} : { file_mtime_ms: mtimeMs }),\n\t\tcreated_ms: safeMs(info.created.getTime()),\n\t\tmodified_ms: safeMs(info.modified.getTime()),\n\t\tmessage_count: info.messageCount,\n\t\tfirst_message: info.firstMessage,\n\t});\n\ttouchProject(state, dir, info.cwd);\n}\n\n// ---------------------------------------------------------------------------\n// 写路径(设计 §4)\n// ---------------------------------------------------------------------------\n\n/**\n * upsert 单会话条目并按 immediate 决定落盘时机。预热优化(设计 §4):条目缺失\n * 或过期由读路径的 mtime 令牌对账刷新,不承担正确性。内部错误一律吞掉\n * (fail-open):索引是投影,写入失败由下次读取对账自愈,绝不影响会话持久化。\n */\nexport function recordSessionUpdate(input: SessionIndexUpdateInput): void {\n\ttry {\n\t\tconst sessionsRoot = getSessionsDir();\n\t\tconst location = locationInRoot(sessionsRoot, input.sessionPath);\n\t\tif (!location) return;\n\t\t// 缓存有效期令牌 = 当前文件 mtime;stat 失败则条目不带令牌(视为过期,无害)。\n\t\tlet mtimeMs: number | undefined;\n\t\ttry {\n\t\t\tmtimeMs = statSync(input.sessionPath).mtimeMs;\n\t\t} catch {\n\t\t\tmtimeMs = undefined;\n\t\t}\n\t\tconst indexPath = getSessionIndexPath();\n\t\tconst state = loadMutableState(indexPath);\n\t\tstate.sessions = state.sessions.filter((entry) => !(entry.dir === location.dir && entry.file === location.file));\n\t\tconst modifiedMs = safeMs(input.modifiedMs);\n\t\tstate.sessions.push({\n\t\t\tfile: location.file,\n\t\t\tdir: location.dir,\n\t\t\tid: input.sessionId,\n\t\t\tcwd: input.cwd,\n\t\t\t...(input.name === undefined ? {} : { name: input.name }),\n\t\t\t...(input.parentSessionPath === undefined ? {} : { parent_session_path: input.parentSessionPath }),\n\t\t\t...(input.profileId === undefined ? {} : { profile_id: input.profileId }),\n\t\t\t...(input.profileVersion === undefined ? {} : { profile_version: input.profileVersion }),\n\t\t\t...(mtimeMs === undefined ? {} : { file_mtime_ms: mtimeMs }),\n\t\t\tcreated_ms: safeMs(input.createdMs),\n\t\t\tmodified_ms: modifiedMs,\n\t\t\tmessage_count: input.messageCount,\n\t\t\tfirst_message: input.firstMessage,\n\t\t});\n\t\ttouchProject(state, location.dir, input.cwd);\n\t\tif (input.immediate) {\n\t\t\tclearPending();\n\t\t\twriteStateSync(indexPath, state);\n\t\t} else {\n\t\t\tarmDirty(indexPath, state);\n\t\t}\n\t} catch {\n\t\t// 索引维护绝不影响会话写入(设计 §4/§6)。\n\t}\n}\n\n/**\n * 按路径移除条目并立即原子落盘;索引不存在/损坏/路径不在 sessions 根时静默 no-op\n * (不抛错、不重建,设计 §6)。\n */\nexport function removeSessionFromIndex(sessionPath: string): void {\n\ttry {\n\t\tconst location = locationInRoot(getSessionsDir(), sessionPath);\n\t\tif (!location) return;\n\t\tconst indexPath = getSessionIndexPath();\n\t\tconst state = loadMutableState(indexPath);\n\t\tconst before = state.sessions.length;\n\t\tstate.sessions = state.sessions.filter((entry) => !(entry.dir === location.dir && entry.file === location.file));\n\t\tif (state.sessions.length === before) return;\n\t\tclearPending();\n\t\twriteStateSync(indexPath, state);\n\t} catch {\n\t\t// 对账会在下次读取自愈(设计 §6)。\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// 读路径与对账(设计 §5)\n// ---------------------------------------------------------------------------\n\nfunction sessionInfoFromEntry(sessionsRoot: string, entry: SessionIndexSessionEntry): SessionInfo {\n\treturn {\n\t\tpath: join(sessionsRoot, entry.dir, entry.file),\n\t\tid: entry.id,\n\t\tcwd: entry.cwd,\n\t\t...(entry.name === undefined ? {} : { name: entry.name }),\n\t\t...(entry.parent_session_path === undefined ? {} : { parentSessionPath: entry.parent_session_path }),\n\t\t...(entry.profile_id === undefined ? {} : { profileId: entry.profile_id }),\n\t\t...(entry.profile_version === undefined ? {} : { profileVersion: entry.profile_version }),\n\t\tcreated: new Date(entry.created_ms),\n\t\tmodified: new Date(entry.modified_ms),\n\t\tmessageCount: entry.message_count,\n\t\tfirstMessage: entry.first_message,\n\t\tallMessagesText: \"\",\n\t};\n}\n\nfunction sortedSessions(sessionsRoot: string, state: SessionIndexFile): SessionInfo[] {\n\tconst ordered = [...state.sessions].sort((a, b) => b.modified_ms - a.modified_ms || b.file.localeCompare(a.file));\n\treturn ordered.map((entry) => sessionInfoFromEntry(sessionsRoot, entry));\n}\n\n/** 重建路径:由全量扫描结果构建索引状态,逐文件 stat 写入 mtime 令牌。 */\nasync function stateFromSessions(sessionsRoot: string, sessions: SessionInfo[]): Promise<SessionIndexFile> {\n\tconst state = emptyState();\n\tfor (const info of sessions) {\n\t\tconst location = locationInRoot(sessionsRoot, info.path);\n\t\tif (!location) continue;\n\t\tlet mtimeMs: number | undefined;\n\t\ttry {\n\t\t\tmtimeMs = (await stat(info.path)).mtimeMs;\n\t\t} catch {\n\t\t\tmtimeMs = undefined;\n\t\t}\n\t\taddSessionFromInfo(state, location.dir, location.file, info, mtimeMs);\n\t}\n\treturn state;\n}\n\n/**\n * 对账:目录名集合 diff + 目录内文件名集合 diff,逐文件 stat 与条目的\n * file_mtime_ms 令牌比对(设计 §5)——条目缺失 → buildInfo 补;mtime 与令牌\n * 一致 → 缓存可信直接沿用;不一致或令牌缺失 → buildInfo 重读刷新缓存与新令牌\n * (重读失败 = 文件已不再是会话 → 剔除陈旧条目);索引有、磁盘无 → 剔除;\n * 消失目录连同其 project 行剔除。返回是否有变更。\n */\nasync function reconcileIndex(\n\tsessionsRoot: string,\n\tstate: SessionIndexFile,\n\tbuildInfo: (path: string) => Promise<SessionInfo | null>,\n\tsignal?: AbortSignal,\n): Promise<boolean> {\n\t// 磁盘清单:目录名 → (文件名 → stat mtime)。stat 失败(readdir 与 stat 之间\n\t// 被删/不可读)视同本轮缺席,下轮对账收敛。\n\tconst diskDirs = new Map<string, Map<string, number>>();\n\tlet rootEntries: Dirent[];\n\ttry {\n\t\trootEntries = await readdir(sessionsRoot, { withFileTypes: true });\n\t} catch {\n\t\t// sessions 根不可读视同空盘:剔除全部条目(索引是投影,根恢复后重建)。\n\t\trootEntries = [];\n\t}\n\tfor (const entry of rootEntries) {\n\t\tif (entry.name === AGENT_SESSIONS_DIR_NAME) continue;\n\t\tif (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n\t\tlet fileNames: string[];\n\t\ttry {\n\t\t\tfileNames = await readdir(join(sessionsRoot, entry.name));\n\t\t} catch {\n\t\t\t// 目录不可读视同已清空,其索引条目被剔除(悬挂容忍,设计 §6)。\n\t\t\tfileNames = [];\n\t\t}\n\t\tconst files = new Map<string, number>();\n\t\tfor (const file of fileNames) {\n\t\t\tif (!isSessionFileName(file)) continue;\n\t\t\tsignal?.throwIfAborted();\n\t\t\ttry {\n\t\t\t\tfiles.set(file, (await stat(join(sessionsRoot, entry.name, file))).mtimeMs);\n\t\t\t} catch {\n\t\t\t\t// 本轮视同缺席。\n\t\t\t}\n\t\t}\n\t\tdiskDirs.set(entry.name, files);\n\t}\n\n\tlet changed = false;\n\n\tfor (const [dir, files] of diskDirs) {\n\t\tfor (const [file, mtimeMs] of files) {\n\t\t\tconst existing = findSessionEntry(state, dir, file);\n\t\t\tif (existing && existing.file_mtime_ms !== undefined && existing.file_mtime_ms === mtimeMs) continue;\n\t\t\tsignal?.throwIfAborted();\n\t\t\tconst info = await buildInfo(join(sessionsRoot, dir, file));\n\t\t\tif (!info) {\n\t\t\t\tif (existing) {\n\t\t\t\t\t// 文件已不再解析为会话(损坏/改写):剔除陈旧条目。\n\t\t\t\t\tstate.sessions = state.sessions.filter((candidate) => candidate !== existing);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\taddSessionFromInfo(state, dir, file, info, mtimeMs);\n\t\t\tchanged = true;\n\t\t}\n\t}\n\n\tconst keptSessions = state.sessions.filter((entry) => diskDirs.get(entry.dir)?.has(entry.file));\n\tif (keptSessions.length !== state.sessions.length) {\n\t\tstate.sessions = keptSessions;\n\t\tchanged = true;\n\t}\n\n\tconst keptProjects = state.projects.filter((project) => diskDirs.has(project.dir));\n\tif (keptProjects.length !== state.projects.length) {\n\t\tstate.projects = keptProjects;\n\t\tchanged = true;\n\t}\n\n\treturn changed;\n}\n\n/**\n * listAll 默认布局分支的索引读路径。返回 undefined 表示索引层意外失败(IO 等),\n * 调用方应回退到旧全量扫描(fail-open,设计 §5);中止按惯例抛 AbortError。\n */\nexport async function listSessionsViaIndex(input: ListSessionsViaIndexInput): Promise<SessionInfo[] | undefined> {\n\tconst { sessionsRoot, buildInfo, scanAll, onHit, signal } = input;\n\ttry {\n\t\tsignal?.throwIfAborted();\n\t\tconst indexPath = getSessionIndexPath();\n\t\tlet state: SessionIndexFile;\n\t\tif (pendingFlush?.indexPath === indexPath) {\n\t\t\t// 节流窗口内已积累的更新是对账基准:对账落盘不得把窗口内更新回退覆盖。\n\t\t\tstate = pendingFlush.state;\n\t\t} else {\n\t\t\tconst fromDisk = readIndexFile(indexPath);\n\t\t\tif (fromDisk === null) {\n\t\t\t\t// 缺失/损坏/版本不符 → 旧扫描全量重建并落盘(与旧行为同价,设计 §5.1)。\n\t\t\t\tconst sessions = await scanAll();\n\t\t\t\twriteStateSync(indexPath, await stateFromSessions(sessionsRoot, sessions));\n\t\t\t\treturn sessions;\n\t\t\t}\n\t\t\tstate = fromDisk;\n\t\t}\n\t\tconst changed = await reconcileIndex(sessionsRoot, state, buildInfo, signal);\n\t\tif (changed) {\n\t\t\tif (pendingFlush?.indexPath === indexPath) clearPending();\n\t\t\twriteStateSync(indexPath, state);\n\t\t}\n\t\tconst sessions = sortedSessions(sessionsRoot, state);\n\t\tonHit?.(sessions);\n\t\treturn sessions;\n\t} catch {\n\t\tsignal?.throwIfAborted();\n\t\treturn undefined;\n\t}\n}\n"]}
|
|
@@ -297,6 +297,15 @@ export declare class SessionManager {
|
|
|
297
297
|
*/
|
|
298
298
|
private _hasConversation;
|
|
299
299
|
_persist(entry: SessionEntry): void;
|
|
300
|
+
/**
|
|
301
|
+
* 会话索引写钩子(设计 docs/design/会话索引.md §4)。定位是预热优化,不承担
|
|
302
|
+
* 正确性:条目缺失或过期由读路径的 mtime 令牌对账刷新。仅在默认布局且已落盘
|
|
303
|
+
* (flushed = 会话文件已存在于磁盘)时生效;自定义 --session-dir 与 inMemory
|
|
304
|
+
* 会话不进索引。字段从内存 fileEntries 派生(deriveSessionIndexFields,与
|
|
305
|
+
* buildSessionInfo 逐语义对齐)。索引维护的任何失败都在 recordSessionUpdate
|
|
306
|
+
* 内部吞掉,绝不影响会话持久化。
|
|
307
|
+
*/
|
|
308
|
+
private notifySessionIndex;
|
|
300
309
|
private _appendEntry;
|
|
301
310
|
/** Append a message as child of current leaf, then advance leaf. Returns entry id.
|
|
302
311
|
* Does not allow writing CompactionSummaryMessage and BranchSummaryMessage directly.
|