@xopcai/xopc 0.0.90 → 0.0.92
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/README.md +36 -12
- package/README.zh-CN.md +36 -12
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +41 -0
- package/dist/gateway/static/root/assets/agents-uwPn7ZW9.js +222 -0
- package/dist/gateway/static/root/assets/apps-page-CWKdhSPU.js +1 -0
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-CpyoFbs4.js → attachment-preview-renderer-DBAxQXb-.js} +2 -2
- package/dist/gateway/static/root/assets/{attachment-process-heavy-CqVriadb.js → attachment-process-heavy-Csq3TrrP.js} +4 -4
- package/dist/gateway/static/root/assets/channels-settings-hEhW7Mbk.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-BrtH2VzC.js → channels-status-swr-XzddfJW2.js} +1 -1
- package/dist/gateway/static/root/assets/copy-Dv6d4Dvw.js +1 -0
- package/dist/gateway/static/root/assets/{cron-api-CyqbgfHM.js → cron-api--I8LJ44S.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-B0kvgZGR.js +1 -0
- package/dist/gateway/static/root/assets/dist-CYgHMQO0.js +1 -0
- package/dist/gateway/static/root/assets/{extension-debug-page-D6Ak0STa.js → extension-debug-page-6cRP0nA9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Q0P3d6DW.js → extension-page-DpwIkspI.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-CL55LwU_.js → extension-settings-page-DYbnQUxH.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-Dqa9iTWl.js → fetch-DTN0w7rV.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-HUR6JElP.js → field-primitives-CslW6HwD.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-2UiKevxG.js +1 -0
- package/dist/gateway/static/root/assets/index-BUKUv7QW.css +1 -0
- package/dist/gateway/static/root/assets/{index-BYcGfwcE.js → index-DnevRVa6.js} +63 -59
- package/dist/gateway/static/root/assets/logs-page-sOP4TXJ4.js +1 -0
- package/dist/gateway/static/root/assets/note-detail-page-B91pLkEI.css +1 -0
- package/dist/gateway/static/root/assets/note-detail-page-DvW2qg4i.js +179 -0
- package/dist/gateway/static/root/assets/note-time-BEiibLJv.js +1 -0
- package/dist/gateway/static/root/assets/notes-page-BFQaquHU.js +1 -0
- package/dist/gateway/static/root/assets/{pdf-BnEvgIXZ.js → pdf-epILhEOn.js} +1 -1
- package/dist/gateway/static/root/assets/preload-helper-zJ_50EbN.js +1 -0
- package/dist/gateway/static/root/assets/sessions-page-CptjDKAX.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-BctKqHcf.js +2 -0
- package/dist/gateway/static/root/assets/{settings-form-section-a0qGVOlr.js → settings-form-section-QJh5ruel.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-V3p-hISB.js +2 -0
- package/dist/gateway/static/root/assets/share-preview-page-DBsvvbmD.js +2 -0
- package/dist/gateway/static/root/assets/skills-page-q2zPUJAR.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-C0Ehmdo5.js → theme-store-ht5iswWS.js} +1 -1
- package/dist/gateway/static/root/assets/toast-z0toXu32.js +1 -0
- package/dist/gateway/static/root/assets/url-CWWpfkq1.js +3 -0
- package/dist/gateway/static/root/assets/{utils-DRQryzdn.js → utils-DhPv9xoB.js} +1 -1
- package/dist/gateway/static/root/assets/vendor-codemirror-DYoKfS8f.js +45 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-DLSKUipa.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-page.utils-DnG8JBhV.js → workflow-page.utils-CJqnPWkW.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-DRRQ1A0l.js +27 -0
- package/dist/gateway/static/root/index.html +10 -8
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +7 -7
- package/dist/src/agent/agent-scope.js +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-config.d.ts +2 -9
- package/dist/src/agent/mcp/bundle-mcp-config.js +10 -34
- package/dist/src/agent/mcp/bundle-mcp-config.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-policy.js +2 -2
- package/dist/src/agent/mcp/bundle-mcp-policy.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +5 -5
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/index.js +2 -2
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/build-direct-message-content.js +1 -1
- package/dist/src/agent/service.js +4 -4
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +3 -3
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/chat-commands/agent-edit.js +2 -2
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/command-catalog.js +0 -4
- package/dist/src/cli/command-catalog.js.map +1 -1
- package/dist/src/cli/command-loaders.js +1 -2
- package/dist/src/cli/command-loaders.js.map +1 -1
- package/dist/src/cli/command-manifest.js +0 -4
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +2 -2
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +4 -4
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.d.ts +0 -1
- package/dist/src/config/index.js +6 -7
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/schema.d.ts +36 -6
- package/dist/src/config/schema.js +13 -11
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/connectors/builtin-catalog.d.ts +2 -0
- package/dist/src/connectors/builtin-catalog.js +152 -0
- package/dist/src/connectors/builtin-catalog.js.map +1 -0
- package/dist/src/connectors/catalog.d.ts +5 -0
- package/dist/src/connectors/catalog.js +13 -0
- package/dist/src/connectors/catalog.js.map +1 -0
- package/dist/src/connectors/health.d.ts +3 -0
- package/dist/src/connectors/health.js +61 -0
- package/dist/src/connectors/health.js.map +1 -0
- package/dist/src/connectors/install.d.ts +5 -0
- package/dist/src/connectors/install.js +46 -0
- package/dist/src/connectors/install.js.map +1 -0
- package/dist/src/connectors/instances.d.ts +4 -0
- package/dist/src/connectors/instances.js +43 -0
- package/dist/src/connectors/instances.js.map +1 -0
- package/dist/src/connectors/materialize.d.ts +9 -0
- package/dist/src/connectors/materialize.js +76 -0
- package/dist/src/connectors/materialize.js.map +1 -0
- package/dist/src/connectors/oauth.d.ts +22 -0
- package/dist/src/connectors/oauth.js +99 -0
- package/dist/src/connectors/oauth.js.map +1 -0
- package/dist/src/connectors/providers.d.ts +9 -0
- package/dist/src/connectors/providers.js +20 -0
- package/dist/src/connectors/providers.js.map +1 -0
- package/dist/src/connectors/secret-store.d.ts +7 -0
- package/dist/src/connectors/secret-store.js +47 -0
- package/dist/src/connectors/secret-store.js.map +1 -0
- package/dist/src/connectors/types.d.ts +102 -0
- package/dist/src/connectors/types.js +1 -0
- package/dist/src/connectors/usage.d.ts +6 -0
- package/dist/src/connectors/usage.js +63 -0
- package/dist/src/connectors/usage.js.map +1 -0
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.js +3 -3
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.d.ts +1 -0
- package/dist/src/gateway/hono/lib/config-payload.js +2 -1
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/middleware/auth.js +1 -2
- package/dist/src/gateway/hono/middleware/auth.js.map +1 -1
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.d.ts +2 -2
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +12 -0
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/connectors.d.ts +3 -0
- package/dist/src/gateway/hono/routes/connectors.js +177 -0
- package/dist/src/gateway/hono/routes/connectors.js.map +1 -0
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/home.d.ts +12 -0
- package/dist/src/gateway/hono/routes/home.js +50 -0
- package/dist/src/gateway/hono/routes/home.js.map +1 -0
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/lazy-bundles.js +20 -4
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/notes.d.ts +3 -0
- package/dist/src/gateway/hono/routes/notes.js +305 -0
- package/dist/src/gateway/hono/routes/notes.js.map +1 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +4 -4
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service.d.ts +3 -0
- package/dist/src/gateway/service.js +11 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/gateway/workspace-ripgrep.d.ts +6 -0
- package/dist/src/gateway/workspace-ripgrep.js +62 -11
- package/dist/src/gateway/workspace-ripgrep.js.map +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/mcp/channel-bridge.js.map +1 -1
- package/dist/src/notes/attachment-ref.d.ts +9 -0
- package/dist/src/notes/attachment-ref.js +27 -0
- package/dist/src/notes/attachment-ref.js.map +1 -0
- package/dist/src/notes/index.d.ts +4 -0
- package/dist/src/notes/index.js +4 -0
- package/dist/src/notes/note-attachment-sync.d.ts +7 -0
- package/dist/src/notes/note-attachment-sync.js +46 -0
- package/dist/src/notes/note-attachment-sync.js.map +1 -0
- package/dist/src/notes/note-index-meta.d.ts +14 -0
- package/dist/src/notes/note-index-meta.js +87 -0
- package/dist/src/notes/note-index-meta.js.map +1 -0
- package/dist/src/notes/paths.d.ts +5 -0
- package/dist/src/notes/paths.js +23 -0
- package/dist/src/notes/paths.js.map +1 -0
- package/dist/src/notes/service.d.ts +53 -0
- package/dist/src/notes/service.js +373 -0
- package/dist/src/notes/service.js.map +1 -0
- package/dist/src/notes/store.d.ts +34 -0
- package/dist/src/notes/store.js +342 -0
- package/dist/src/notes/store.js.map +1 -0
- package/dist/src/notes/types.d.ts +199 -0
- package/dist/src/notes/types.js +1 -0
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.js +2 -2
- package/dist/src/session/init-session-turn.js +2 -2
- package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
- package/dist/src/session/parity/sessions-json-file.js +1 -1
- package/dist/src/session/parity/transcript-file-lock.js +2 -2
- package/dist/src/session/parity/transcript-paths.js +1 -1
- package/dist/src/session/resolve-session.js +4 -4
- package/dist/src/session/search-index-cache.js +1 -1
- package/dist/src/session/search-index.js +1 -1
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/store.d.ts +2 -0
- package/dist/src/session/store.js +27 -7
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui.js +3 -3
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-cPvvYLXo.js +0 -222
- package/dist/gateway/static/root/assets/apps-page-Bk1_P5FJ.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-CZoeQwHz.js +0 -1
- package/dist/gateway/static/root/assets/cron-dreaming-jobs-Ip703-qM.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-BpLdiQN8.js +0 -1
- package/dist/gateway/static/root/assets/dist-BTWC-BTN.js +0 -45
- package/dist/gateway/static/root/assets/dist-BpAiK86n.js +0 -1
- package/dist/gateway/static/root/assets/eye-DAfL1U7M.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-config-api-DusckjUX.js +0 -1
- package/dist/gateway/static/root/assets/index-V7MQ7834.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-_HcZ2fgK.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-iezSMjho.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-C9_nYQwM.js +0 -3
- package/dist/gateway/static/root/assets/share-preview-page-DExl7CJy.js +0 -2
- package/dist/gateway/static/root/assets/skills-page-BlgGD93t.js +0 -2
- package/dist/gateway/static/root/assets/url-fxyYANfA.js +0 -3
- package/dist/gateway/static/root/assets/vendor-codemirror-D0yxdRpg.js +0 -58
- package/dist/gateway/static/root/assets/voice-api-key-field-D0viACE2.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-BvMobnJP.js +0 -27
- package/dist/src/cli/commands/mcp.d.ts +0 -4
- package/dist/src/cli/commands/mcp.js +0 -85
- package/dist/src/cli/commands/mcp.js.map +0 -1
- package/dist/src/config/mcp-config.d.ts +0 -34
- package/dist/src/config/mcp-config.js +0 -116
- package/dist/src/config/mcp-config.js.map +0 -1
- package/dist/src/gateway/hono/routes/mcp.d.ts +0 -3
- package/dist/src/gateway/hono/routes/mcp.js +0 -99
- package/dist/src/gateway/hono/routes/mcp.js.map +0 -1
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../utils/logger.js";
|
|
3
|
+
import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
|
|
4
|
+
import { buildNoteIndexMeta, notePlainText } from "./note-index-meta.js";
|
|
5
|
+
import { resolveNoteHistoryDir, resolveNoteItemPath, resolveNoteMediaDir, resolveNotesDir, resolveNotesIndexPath } from "./paths.js";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { randomUUID } from "node:crypto";
|
|
8
|
+
import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
|
|
9
|
+
//#region src/notes/store.ts
|
|
10
|
+
init_write_file_atomic();
|
|
11
|
+
init_logger();
|
|
12
|
+
const log = createLogger("NotesStore");
|
|
13
|
+
const DEFAULT_INDEX = {
|
|
14
|
+
version: 3,
|
|
15
|
+
notes: []
|
|
16
|
+
};
|
|
17
|
+
const INDEX_VERSION = 3;
|
|
18
|
+
const DEBOUNCE_MS = 500;
|
|
19
|
+
function noteToIndexEntry(note) {
|
|
20
|
+
const { snippet, coverAttachmentId, voiceAttachmentId, voiceDurationSec, attachmentNames } = buildNoteIndexMeta(note);
|
|
21
|
+
return {
|
|
22
|
+
id: note.id,
|
|
23
|
+
title: note.title || void 0,
|
|
24
|
+
kind: note.kind,
|
|
25
|
+
status: note.status,
|
|
26
|
+
createdAt: note.createdAt,
|
|
27
|
+
updatedAt: note.updatedAt,
|
|
28
|
+
pinned: note.pinned || void 0,
|
|
29
|
+
tags: note.tags?.length ? note.tags : void 0,
|
|
30
|
+
snippet,
|
|
31
|
+
coverAttachmentId,
|
|
32
|
+
voiceAttachmentId,
|
|
33
|
+
voiceDurationSec,
|
|
34
|
+
attachmentNames,
|
|
35
|
+
groupId: note.groupId || void 0,
|
|
36
|
+
lastOpenedAt: note.lastOpenedAt || void 0,
|
|
37
|
+
taskDone: note.taskMeta?.done,
|
|
38
|
+
taskDueAt: note.taskMeta?.dueAt
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
var NotesStore = class {
|
|
42
|
+
indexCache = null;
|
|
43
|
+
dirty = false;
|
|
44
|
+
saveTimeout = null;
|
|
45
|
+
initialized = false;
|
|
46
|
+
async initialize() {
|
|
47
|
+
if (this.initialized) return;
|
|
48
|
+
const indexPath = resolveNotesIndexPath();
|
|
49
|
+
try {
|
|
50
|
+
await access(indexPath);
|
|
51
|
+
await this.loadIndex();
|
|
52
|
+
if ((this.indexCache?.version ?? 0) < INDEX_VERSION) await this.rebuildIndexFromItems();
|
|
53
|
+
} catch {
|
|
54
|
+
await this.writeIndex(DEFAULT_INDEX);
|
|
55
|
+
this.indexCache = DEFAULT_INDEX;
|
|
56
|
+
}
|
|
57
|
+
this.initialized = true;
|
|
58
|
+
log.debug("NotesStore initialized");
|
|
59
|
+
}
|
|
60
|
+
async addNote(note) {
|
|
61
|
+
const index = await this.loadIndex();
|
|
62
|
+
await this.writeNoteItem(note);
|
|
63
|
+
index.notes.push(noteToIndexEntry(note));
|
|
64
|
+
index.version++;
|
|
65
|
+
this.scheduleIndexSave(index);
|
|
66
|
+
}
|
|
67
|
+
async getNote(id) {
|
|
68
|
+
const itemPath = resolveNoteItemPath(id);
|
|
69
|
+
try {
|
|
70
|
+
const content = await readFile(itemPath, "utf-8");
|
|
71
|
+
return JSON.parse(content);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
if ((err && typeof err === "object" && "code" in err ? err.code : "") !== "ENOENT") log.debug({
|
|
74
|
+
err,
|
|
75
|
+
id
|
|
76
|
+
}, "Failed to read note item");
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async updateNote(id, patch) {
|
|
81
|
+
const existing = await this.getNote(id);
|
|
82
|
+
if (!existing) return null;
|
|
83
|
+
const updated = {
|
|
84
|
+
...existing,
|
|
85
|
+
...patch,
|
|
86
|
+
id: existing.id,
|
|
87
|
+
createdAt: existing.createdAt,
|
|
88
|
+
updatedAt: Date.now()
|
|
89
|
+
};
|
|
90
|
+
await this.writeNoteItem(updated);
|
|
91
|
+
const index = await this.loadIndex();
|
|
92
|
+
const idx = index.notes.findIndex((n) => n.id === id);
|
|
93
|
+
if (idx !== -1) index.notes[idx] = noteToIndexEntry(updated);
|
|
94
|
+
index.version++;
|
|
95
|
+
this.scheduleIndexSave(index);
|
|
96
|
+
return updated;
|
|
97
|
+
}
|
|
98
|
+
async deleteNote(id) {
|
|
99
|
+
if (!await this.getNote(id)) return false;
|
|
100
|
+
await rm(resolveNoteItemPath(id), { force: true }).catch((err) => {
|
|
101
|
+
log.warn({
|
|
102
|
+
err,
|
|
103
|
+
id
|
|
104
|
+
}, "Failed to remove note item file");
|
|
105
|
+
});
|
|
106
|
+
await rm(resolveNoteMediaDir(id), {
|
|
107
|
+
recursive: true,
|
|
108
|
+
force: true
|
|
109
|
+
}).catch(() => void 0);
|
|
110
|
+
const index = await this.loadIndex();
|
|
111
|
+
const before = index.notes.length;
|
|
112
|
+
index.notes = index.notes.filter((n) => n.id !== id);
|
|
113
|
+
if (index.notes.length === before) log.debug({ id }, "Deleted note file but index entry was missing");
|
|
114
|
+
index.version++;
|
|
115
|
+
this.scheduleIndexSave(index);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
async listNotes(query = {}) {
|
|
119
|
+
let results = (await this.loadIndex()).notes;
|
|
120
|
+
if (query.status) results = results.filter((n) => n.status === query.status);
|
|
121
|
+
else results = results.filter((n) => n.status !== "trashed");
|
|
122
|
+
if (query.kind) results = results.filter((n) => n.kind === query.kind);
|
|
123
|
+
if (query.tag) results = results.filter((n) => n.tags?.includes(query.tag));
|
|
124
|
+
if (query.pinned !== void 0) results = results.filter((n) => Boolean(n.pinned) === query.pinned);
|
|
125
|
+
if (query.groupId !== void 0) if (query.groupId === "ungrouped") results = results.filter((n) => !n.groupId);
|
|
126
|
+
else results = results.filter((n) => n.groupId === query.groupId);
|
|
127
|
+
if (query.pendingTasksOnly) results = results.filter((n) => n.kind === "task" && !n.taskDone);
|
|
128
|
+
if (query.search) {
|
|
129
|
+
const term = query.search.toLowerCase();
|
|
130
|
+
const indexMatches = results.filter((n) => this.noteIndexEntryMatchesSearch(n, term));
|
|
131
|
+
const indexMatchedIds = new Set(indexMatches.map((n) => n.id));
|
|
132
|
+
const contentMatches = [];
|
|
133
|
+
const candidates = results.filter((n) => !indexMatchedIds.has(n.id));
|
|
134
|
+
for (const candidate of candidates) {
|
|
135
|
+
const note = await this.getNote(candidate.id);
|
|
136
|
+
if (!note) continue;
|
|
137
|
+
if ([
|
|
138
|
+
note.title,
|
|
139
|
+
notePlainText(note),
|
|
140
|
+
note.attachments?.map((a) => a.transcript).join(" ")
|
|
141
|
+
].filter(Boolean).join(" ").toLowerCase().includes(term)) contentMatches.push(candidate);
|
|
142
|
+
}
|
|
143
|
+
results = [...indexMatches, ...contentMatches];
|
|
144
|
+
}
|
|
145
|
+
const sortField = query.sortBy || "createdAt";
|
|
146
|
+
const sortDir = query.sortOrder === "asc" ? 1 : -1;
|
|
147
|
+
results = [...results].sort((a, b) => {
|
|
148
|
+
return ((a[sortField] ?? 0) - (b[sortField] ?? 0)) * sortDir;
|
|
149
|
+
});
|
|
150
|
+
const total = results.length;
|
|
151
|
+
const offset = query.offset || 0;
|
|
152
|
+
const limit = Math.min(query.limit || 50, 200);
|
|
153
|
+
return {
|
|
154
|
+
items: results.slice(offset, offset + limit),
|
|
155
|
+
total
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
noteIndexEntryMatchesSearch(entry, term) {
|
|
159
|
+
return Boolean(entry.title?.toLowerCase().includes(term) || entry.snippet?.toLowerCase().includes(term) || entry.tags?.some((tag) => tag.toLowerCase().includes(term)) || entry.attachmentNames?.some((name) => name.toLowerCase().includes(term)));
|
|
160
|
+
}
|
|
161
|
+
async saveAttachment(noteId, fileName, buffer) {
|
|
162
|
+
const mediaDir = resolveNoteMediaDir(noteId);
|
|
163
|
+
await mkdir(mediaDir, { recursive: true });
|
|
164
|
+
const safeName = `${randomUUID().slice(0, 8)}_${fileName.replace(/[^a-zA-Z0-9._-]/g, "_")}`;
|
|
165
|
+
await writeFile(join(mediaDir, safeName), buffer);
|
|
166
|
+
return {
|
|
167
|
+
relativePath: safeName,
|
|
168
|
+
size: buffer.length
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
resolveAttachmentPath(noteId, relativePath) {
|
|
172
|
+
return join(resolveNoteMediaDir(noteId), relativePath);
|
|
173
|
+
}
|
|
174
|
+
async deleteAttachmentFile(noteId, relativePath) {
|
|
175
|
+
await rm(this.resolveAttachmentPath(noteId, relativePath), { force: true }).catch((err) => {
|
|
176
|
+
log.warn({
|
|
177
|
+
err,
|
|
178
|
+
noteId,
|
|
179
|
+
relativePath
|
|
180
|
+
}, "Failed to remove note attachment file");
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
async saveSnapshot(note, trigger) {
|
|
184
|
+
const historyDir = resolveNoteHistoryDir(note.id);
|
|
185
|
+
await mkdir(historyDir, { recursive: true });
|
|
186
|
+
const snapshot = {
|
|
187
|
+
noteId: note.id,
|
|
188
|
+
timestamp: Date.now(),
|
|
189
|
+
trigger,
|
|
190
|
+
title: note.title,
|
|
191
|
+
text: note.text,
|
|
192
|
+
blocks: note.blocks,
|
|
193
|
+
tags: note.tags,
|
|
194
|
+
kind: note.kind,
|
|
195
|
+
status: note.status
|
|
196
|
+
};
|
|
197
|
+
await writeTextAtomic(join(historyDir, `${snapshot.timestamp}.json`), JSON.stringify(snapshot, null, 2));
|
|
198
|
+
log.debug({
|
|
199
|
+
noteId: note.id,
|
|
200
|
+
trigger,
|
|
201
|
+
timestamp: snapshot.timestamp
|
|
202
|
+
}, "Snapshot saved");
|
|
203
|
+
}
|
|
204
|
+
async listSnapshots(noteId) {
|
|
205
|
+
const historyDir = resolveNoteHistoryDir(noteId);
|
|
206
|
+
let files;
|
|
207
|
+
try {
|
|
208
|
+
files = await readdir(historyDir);
|
|
209
|
+
} catch {
|
|
210
|
+
return [];
|
|
211
|
+
}
|
|
212
|
+
const entries = [];
|
|
213
|
+
for (const file of files) {
|
|
214
|
+
if (!file.endsWith(".json")) continue;
|
|
215
|
+
const timestamp = parseInt(file.slice(0, -5), 10);
|
|
216
|
+
if (!Number.isFinite(timestamp)) continue;
|
|
217
|
+
try {
|
|
218
|
+
const content = await readFile(join(historyDir, file), "utf-8");
|
|
219
|
+
const snapshot = JSON.parse(content);
|
|
220
|
+
const rawText = snapshot.text ?? "";
|
|
221
|
+
entries.push({
|
|
222
|
+
timestamp: snapshot.timestamp,
|
|
223
|
+
trigger: snapshot.trigger,
|
|
224
|
+
snippet: rawText.slice(0, 80) || void 0
|
|
225
|
+
});
|
|
226
|
+
} catch {
|
|
227
|
+
log.debug({
|
|
228
|
+
noteId,
|
|
229
|
+
file
|
|
230
|
+
}, "Skipped unreadable snapshot");
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
entries.sort((a, b) => b.timestamp - a.timestamp);
|
|
234
|
+
return entries;
|
|
235
|
+
}
|
|
236
|
+
async getSnapshot(noteId, timestamp) {
|
|
237
|
+
const filePath = join(resolveNoteHistoryDir(noteId), `${timestamp}.json`);
|
|
238
|
+
try {
|
|
239
|
+
const content = await readFile(filePath, "utf-8");
|
|
240
|
+
return JSON.parse(content);
|
|
241
|
+
} catch {
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async pruneSnapshots(noteId, maxCount) {
|
|
246
|
+
const historyDir = resolveNoteHistoryDir(noteId);
|
|
247
|
+
let files;
|
|
248
|
+
try {
|
|
249
|
+
files = await readdir(historyDir);
|
|
250
|
+
} catch {
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
const jsonFiles = files.filter((f) => f.endsWith(".json")).sort();
|
|
254
|
+
if (jsonFiles.length <= maxCount) return;
|
|
255
|
+
const toDelete = jsonFiles.slice(0, jsonFiles.length - maxCount);
|
|
256
|
+
for (const file of toDelete) await rm(join(historyDir, file), { force: true }).catch(() => void 0);
|
|
257
|
+
log.debug({
|
|
258
|
+
noteId,
|
|
259
|
+
deleted: toDelete.length
|
|
260
|
+
}, "Pruned old snapshots");
|
|
261
|
+
}
|
|
262
|
+
async deleteAllSnapshots(noteId) {
|
|
263
|
+
await rm(resolveNoteHistoryDir(noteId), {
|
|
264
|
+
recursive: true,
|
|
265
|
+
force: true
|
|
266
|
+
}).catch(() => void 0);
|
|
267
|
+
}
|
|
268
|
+
async flush() {
|
|
269
|
+
if (!this.dirty || !this.indexCache) return;
|
|
270
|
+
if (this.saveTimeout) {
|
|
271
|
+
clearTimeout(this.saveTimeout);
|
|
272
|
+
this.saveTimeout = null;
|
|
273
|
+
}
|
|
274
|
+
await this.writeIndex(this.indexCache);
|
|
275
|
+
this.dirty = false;
|
|
276
|
+
}
|
|
277
|
+
async loadIndex() {
|
|
278
|
+
if (this.indexCache) return this.indexCache;
|
|
279
|
+
const indexPath = resolveNotesIndexPath();
|
|
280
|
+
try {
|
|
281
|
+
const content = await readFile(indexPath, "utf-8");
|
|
282
|
+
const data = JSON.parse(content);
|
|
283
|
+
if (!data.notes || !Array.isArray(data.notes)) {
|
|
284
|
+
log.warn("Notes index invalid, resetting");
|
|
285
|
+
this.indexCache = DEFAULT_INDEX;
|
|
286
|
+
return this.indexCache;
|
|
287
|
+
}
|
|
288
|
+
this.indexCache = data;
|
|
289
|
+
return data;
|
|
290
|
+
} catch {
|
|
291
|
+
this.indexCache = DEFAULT_INDEX;
|
|
292
|
+
return this.indexCache;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
async writeIndex(data) {
|
|
296
|
+
await writeTextAtomic(resolveNotesIndexPath(), JSON.stringify(data, null, 2));
|
|
297
|
+
log.debug({ count: data.notes.length }, "Notes index saved");
|
|
298
|
+
}
|
|
299
|
+
async writeNoteItem(note) {
|
|
300
|
+
await writeTextAtomic(resolveNoteItemPath(note.id), JSON.stringify(note, null, 2));
|
|
301
|
+
}
|
|
302
|
+
scheduleIndexSave(data) {
|
|
303
|
+
this.indexCache = data;
|
|
304
|
+
this.dirty = true;
|
|
305
|
+
if (this.saveTimeout) clearTimeout(this.saveTimeout);
|
|
306
|
+
this.saveTimeout = setTimeout(() => {
|
|
307
|
+
this.flush().catch((err) => {
|
|
308
|
+
log.error({ err }, "Failed to flush notes index");
|
|
309
|
+
});
|
|
310
|
+
}, DEBOUNCE_MS);
|
|
311
|
+
}
|
|
312
|
+
async rebuildIndexFromItems() {
|
|
313
|
+
const itemsDir = join(resolveNotesDir(), "items");
|
|
314
|
+
let files;
|
|
315
|
+
try {
|
|
316
|
+
files = await readdir(itemsDir);
|
|
317
|
+
} catch {
|
|
318
|
+
this.indexCache = DEFAULT_INDEX;
|
|
319
|
+
await this.writeIndex(DEFAULT_INDEX);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const entries = [];
|
|
323
|
+
for (const file of files) {
|
|
324
|
+
if (!file.endsWith(".json")) continue;
|
|
325
|
+
const noteId = file.slice(0, -5);
|
|
326
|
+
const note = await this.getNote(noteId);
|
|
327
|
+
if (note) entries.push(noteToIndexEntry(note));
|
|
328
|
+
}
|
|
329
|
+
entries.sort((a, b) => b.createdAt - a.createdAt);
|
|
330
|
+
const index = {
|
|
331
|
+
version: INDEX_VERSION,
|
|
332
|
+
notes: entries
|
|
333
|
+
};
|
|
334
|
+
this.indexCache = index;
|
|
335
|
+
await this.writeIndex(index);
|
|
336
|
+
log.debug({ count: entries.length }, "Notes index rebuilt");
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
//#endregion
|
|
340
|
+
export { NotesStore };
|
|
341
|
+
|
|
342
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","names":[],"sources":["../../../src/notes/store.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { readFile, access, mkdir, writeFile, rm, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { writeTextAtomic } from '../infra/write-file-atomic.js';\nimport { createLogger } from '../utils/logger.js';\nimport { buildNoteIndexMeta, notePlainText } from './note-index-meta.js';\nimport { resolveNotesDir, resolveNotesIndexPath, resolveNoteItemPath, resolveNoteMediaDir, resolveNoteHistoryDir } from './paths.js';\nimport type {\n Note,\n NoteIndexEntry,\n NoteSnapshot,\n NoteSnapshotEntry,\n NotesIndexFile,\n NotesListQuery,\n SnapshotTrigger,\n} from './types.js';\n\nconst log = createLogger('NotesStore');\n\nconst DEFAULT_INDEX: NotesIndexFile = { version: 3, notes: [] };\nconst INDEX_VERSION = 3;\nconst DEBOUNCE_MS = 500;\n\nfunction noteToIndexEntry(note: Note): NoteIndexEntry {\n const { snippet, coverAttachmentId, voiceAttachmentId, voiceDurationSec, attachmentNames } = buildNoteIndexMeta(note);\n return {\n id: note.id,\n title: note.title || undefined,\n kind: note.kind,\n status: note.status,\n createdAt: note.createdAt,\n updatedAt: note.updatedAt,\n pinned: note.pinned || undefined,\n tags: note.tags?.length ? note.tags : undefined,\n snippet,\n coverAttachmentId,\n voiceAttachmentId,\n voiceDurationSec,\n attachmentNames,\n groupId: note.groupId || undefined,\n lastOpenedAt: note.lastOpenedAt || undefined,\n taskDone: note.taskMeta?.done,\n taskDueAt: note.taskMeta?.dueAt,\n };\n}\n\nexport class NotesStore {\n private indexCache: NotesIndexFile | null = null;\n private dirty = false;\n private saveTimeout: ReturnType<typeof setTimeout> | null = null;\n private initialized = false;\n\n async initialize(): Promise<void> {\n if (this.initialized) return;\n const indexPath = resolveNotesIndexPath();\n try {\n await access(indexPath);\n await this.loadIndex();\n if ((this.indexCache?.version ?? 0) < INDEX_VERSION) {\n await this.rebuildIndexFromItems();\n }\n } catch {\n await this.writeIndex(DEFAULT_INDEX);\n this.indexCache = DEFAULT_INDEX;\n }\n this.initialized = true;\n log.debug('NotesStore initialized');\n }\n\n async addNote(note: Note): Promise<void> {\n const index = await this.loadIndex();\n await this.writeNoteItem(note);\n index.notes.push(noteToIndexEntry(note));\n index.version++;\n this.scheduleIndexSave(index);\n }\n\n async getNote(id: string): Promise<Note | null> {\n const itemPath = resolveNoteItemPath(id);\n try {\n const content = await readFile(itemPath, 'utf-8');\n return JSON.parse(content) as Note;\n } catch (err) {\n const code = err && typeof err === 'object' && 'code' in err\n ? (err as NodeJS.ErrnoException).code : '';\n if (code !== 'ENOENT') {\n log.debug({ err, id }, 'Failed to read note item');\n }\n return null;\n }\n }\n\n async updateNote(id: string, patch: Partial<Note>): Promise<Note | null> {\n const existing = await this.getNote(id);\n if (!existing) return null;\n\n const updated: Note = {\n ...existing,\n ...patch,\n id: existing.id,\n createdAt: existing.createdAt,\n updatedAt: Date.now(),\n };\n\n await this.writeNoteItem(updated);\n\n const index = await this.loadIndex();\n const idx = index.notes.findIndex((n) => n.id === id);\n if (idx !== -1) {\n index.notes[idx] = noteToIndexEntry(updated);\n }\n index.version++;\n this.scheduleIndexSave(index);\n\n return updated;\n }\n\n async deleteNote(id: string): Promise<boolean> {\n const existing = await this.getNote(id);\n if (!existing) return false;\n\n const itemPath = resolveNoteItemPath(id);\n await rm(itemPath, { force: true }).catch((err) => {\n log.warn({ err, id }, 'Failed to remove note item file');\n });\n\n const mediaDir = resolveNoteMediaDir(id);\n await rm(mediaDir, { recursive: true, force: true }).catch(() => undefined);\n\n const index = await this.loadIndex();\n const before = index.notes.length;\n index.notes = index.notes.filter((n) => n.id !== id);\n if (index.notes.length === before) {\n log.debug({ id }, 'Deleted note file but index entry was missing');\n }\n index.version++;\n this.scheduleIndexSave(index);\n\n return true;\n }\n\n async listNotes(query: NotesListQuery = {}): Promise<{ items: NoteIndexEntry[]; total: number }> {\n const index = await this.loadIndex();\n let results = index.notes;\n\n if (query.status) {\n results = results.filter((n) => n.status === query.status);\n } else {\n results = results.filter((n) => n.status !== 'trashed');\n }\n if (query.kind) {\n results = results.filter((n) => n.kind === query.kind);\n }\n if (query.tag) {\n results = results.filter((n) => n.tags?.includes(query.tag!));\n }\n if (query.pinned !== undefined) {\n results = results.filter((n) => Boolean(n.pinned) === query.pinned);\n }\n if (query.groupId !== undefined) {\n if (query.groupId === 'ungrouped') {\n results = results.filter((n) => !n.groupId);\n } else {\n results = results.filter((n) => n.groupId === query.groupId);\n }\n }\n if (query.pendingTasksOnly) {\n results = results.filter((n) => n.kind === 'task' && !n.taskDone);\n }\n if (query.search) {\n const term = query.search.toLowerCase();\n const indexMatches = results.filter((n) => this.noteIndexEntryMatchesSearch(n, term));\n const indexMatchedIds = new Set(indexMatches.map((n) => n.id));\n const contentMatches: NoteIndexEntry[] = [];\n const candidates = results.filter((n) => !indexMatchedIds.has(n.id));\n for (const candidate of candidates) {\n const note = await this.getNote(candidate.id);\n if (!note) continue;\n const content = [note.title, notePlainText(note), note.attachments?.map((a) => a.transcript).join(' ')]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n if (content.includes(term)) {\n contentMatches.push(candidate);\n }\n }\n results = [...indexMatches, ...contentMatches];\n }\n\n const sortField = query.sortBy || 'createdAt';\n const sortDir = query.sortOrder === 'asc' ? 1 : -1;\n results = [...results].sort((a, b) => {\n const aVal = a[sortField] ?? 0;\n const bVal = b[sortField] ?? 0;\n return (aVal - bVal) * sortDir;\n });\n\n const total = results.length;\n const offset = query.offset || 0;\n const limit = Math.min(query.limit || 50, 200);\n const items = results.slice(offset, offset + limit);\n\n return { items, total };\n }\n\n private noteIndexEntryMatchesSearch(entry: NoteIndexEntry, term: string): boolean {\n return Boolean(\n entry.title?.toLowerCase().includes(term) ||\n entry.snippet?.toLowerCase().includes(term) ||\n entry.tags?.some((tag) => tag.toLowerCase().includes(term)) ||\n entry.attachmentNames?.some((name) => name.toLowerCase().includes(term)),\n );\n }\n\n async saveAttachment(\n noteId: string,\n fileName: string,\n buffer: Buffer,\n ): Promise<{ relativePath: string; size: number }> {\n const mediaDir = resolveNoteMediaDir(noteId);\n await mkdir(mediaDir, { recursive: true });\n const safeName = `${randomUUID().slice(0, 8)}_${fileName.replace(/[^a-zA-Z0-9._-]/g, '_')}`;\n const filePath = join(mediaDir, safeName);\n await writeFile(filePath, buffer);\n return { relativePath: safeName, size: buffer.length };\n }\n\n resolveAttachmentPath(noteId: string, relativePath: string): string {\n return join(resolveNoteMediaDir(noteId), relativePath);\n }\n\n async deleteAttachmentFile(noteId: string, relativePath: string): Promise<void> {\n const filePath = this.resolveAttachmentPath(noteId, relativePath);\n await rm(filePath, { force: true }).catch((err) => {\n log.warn({ err, noteId, relativePath }, 'Failed to remove note attachment file');\n });\n }\n\n async saveSnapshot(note: Note, trigger: SnapshotTrigger): Promise<void> {\n const historyDir = resolveNoteHistoryDir(note.id);\n await mkdir(historyDir, { recursive: true });\n const snapshot: NoteSnapshot = {\n noteId: note.id,\n timestamp: Date.now(),\n trigger,\n title: note.title,\n text: note.text,\n blocks: note.blocks,\n tags: note.tags,\n kind: note.kind,\n status: note.status,\n };\n const filePath = join(historyDir, `${snapshot.timestamp}.json`);\n await writeTextAtomic(filePath, JSON.stringify(snapshot, null, 2));\n log.debug({ noteId: note.id, trigger, timestamp: snapshot.timestamp }, 'Snapshot saved');\n }\n\n async listSnapshots(noteId: string): Promise<NoteSnapshotEntry[]> {\n const historyDir = resolveNoteHistoryDir(noteId);\n let files: string[];\n try {\n files = await readdir(historyDir);\n } catch {\n return [];\n }\n const entries: NoteSnapshotEntry[] = [];\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const timestamp = parseInt(file.slice(0, -'.json'.length), 10);\n if (!Number.isFinite(timestamp)) continue;\n try {\n const content = await readFile(join(historyDir, file), 'utf-8');\n const snapshot = JSON.parse(content) as NoteSnapshot;\n const rawText = snapshot.text ?? '';\n entries.push({\n timestamp: snapshot.timestamp,\n trigger: snapshot.trigger,\n snippet: rawText.slice(0, 80) || undefined,\n });\n } catch {\n log.debug({ noteId, file }, 'Skipped unreadable snapshot');\n }\n }\n entries.sort((a, b) => b.timestamp - a.timestamp);\n return entries;\n }\n\n async getSnapshot(noteId: string, timestamp: number): Promise<NoteSnapshot | null> {\n const filePath = join(resolveNoteHistoryDir(noteId), `${timestamp}.json`);\n try {\n const content = await readFile(filePath, 'utf-8');\n return JSON.parse(content) as NoteSnapshot;\n } catch {\n return null;\n }\n }\n\n async pruneSnapshots(noteId: string, maxCount: number): Promise<void> {\n const historyDir = resolveNoteHistoryDir(noteId);\n let files: string[];\n try {\n files = await readdir(historyDir);\n } catch {\n return;\n }\n const jsonFiles = files\n .filter((f) => f.endsWith('.json'))\n .sort();\n if (jsonFiles.length <= maxCount) return;\n const toDelete = jsonFiles.slice(0, jsonFiles.length - maxCount);\n for (const file of toDelete) {\n await rm(join(historyDir, file), { force: true }).catch(() => undefined);\n }\n log.debug({ noteId, deleted: toDelete.length }, 'Pruned old snapshots');\n }\n\n async deleteAllSnapshots(noteId: string): Promise<void> {\n const historyDir = resolveNoteHistoryDir(noteId);\n await rm(historyDir, { recursive: true, force: true }).catch(() => undefined);\n }\n\n async flush(): Promise<void> {\n if (!this.dirty || !this.indexCache) return;\n if (this.saveTimeout) {\n clearTimeout(this.saveTimeout);\n this.saveTimeout = null;\n }\n await this.writeIndex(this.indexCache);\n this.dirty = false;\n }\n\n private async loadIndex(): Promise<NotesIndexFile> {\n if (this.indexCache) return this.indexCache;\n const indexPath = resolveNotesIndexPath();\n try {\n const content = await readFile(indexPath, 'utf-8');\n const data = JSON.parse(content) as NotesIndexFile;\n if (!data.notes || !Array.isArray(data.notes)) {\n log.warn('Notes index invalid, resetting');\n this.indexCache = DEFAULT_INDEX;\n return this.indexCache;\n }\n this.indexCache = data;\n return data;\n } catch {\n this.indexCache = DEFAULT_INDEX;\n return this.indexCache;\n }\n }\n\n private async writeIndex(data: NotesIndexFile): Promise<void> {\n const indexPath = resolveNotesIndexPath();\n await writeTextAtomic(indexPath, JSON.stringify(data, null, 2));\n log.debug({ count: data.notes.length }, 'Notes index saved');\n }\n\n private async writeNoteItem(note: Note): Promise<void> {\n const itemPath = resolveNoteItemPath(note.id);\n await writeTextAtomic(itemPath, JSON.stringify(note, null, 2));\n }\n\n private scheduleIndexSave(data: NotesIndexFile): void {\n this.indexCache = data;\n this.dirty = true;\n if (this.saveTimeout) {\n clearTimeout(this.saveTimeout);\n }\n this.saveTimeout = setTimeout(() => {\n this.flush().catch((err) => {\n log.error({ err }, 'Failed to flush notes index');\n });\n }, DEBOUNCE_MS);\n }\n\n private async rebuildIndexFromItems(): Promise<void> {\n const itemsDir = join(resolveNotesDir(), 'items');\n let files: string[];\n try {\n files = await readdir(itemsDir);\n } catch {\n this.indexCache = DEFAULT_INDEX;\n await this.writeIndex(DEFAULT_INDEX);\n return;\n }\n\n const entries: NoteIndexEntry[] = [];\n for (const file of files) {\n if (!file.endsWith('.json')) continue;\n const noteId = file.slice(0, -'.json'.length);\n const note = await this.getNote(noteId);\n if (note) {\n entries.push(noteToIndexEntry(note));\n }\n }\n\n entries.sort((a, b) => b.createdAt - a.createdAt);\n const index: NotesIndexFile = { version: INDEX_VERSION, notes: entries };\n this.indexCache = index;\n await this.writeIndex(index);\n log.debug({ count: entries.length }, 'Notes index rebuilt');\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
export type NoteKind = 'thought' | 'todo' | 'voice' | 'media' | 'bookmark' | 'mixed' | 'task';
|
|
2
|
+
export type NoteStatus = 'inbox' | 'processed' | 'archived' | 'trashed';
|
|
3
|
+
export type CaptureChannel = 'app' | 'web' | 'electron' | 'tui' | 'telegram' | 'wechat' | 'feishu';
|
|
4
|
+
export type NoteBlockType = 'paragraph' | 'heading' | 'todo' | 'bulletList' | 'numberedList' | 'quote' | 'code' | 'divider' | 'image' | 'aiSuggestion';
|
|
5
|
+
export interface BaseNoteBlock {
|
|
6
|
+
id: string;
|
|
7
|
+
type: NoteBlockType;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
updatedAt: number;
|
|
10
|
+
}
|
|
11
|
+
export interface TextNoteBlock extends BaseNoteBlock {
|
|
12
|
+
type: 'paragraph' | 'heading' | 'bulletList' | 'numberedList' | 'quote' | 'code' | 'aiSuggestion';
|
|
13
|
+
text: string;
|
|
14
|
+
level?: 1 | 2 | 3;
|
|
15
|
+
indent?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface TodoNoteBlock extends BaseNoteBlock {
|
|
18
|
+
type: 'todo';
|
|
19
|
+
text: string;
|
|
20
|
+
checked: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface DividerNoteBlock extends BaseNoteBlock {
|
|
23
|
+
type: 'divider';
|
|
24
|
+
}
|
|
25
|
+
export interface ImageNoteBlock extends BaseNoteBlock {
|
|
26
|
+
type: 'image';
|
|
27
|
+
attachmentId: string;
|
|
28
|
+
alt?: string;
|
|
29
|
+
width?: number;
|
|
30
|
+
}
|
|
31
|
+
export type NoteBlock = TextNoteBlock | TodoNoteBlock | DividerNoteBlock | ImageNoteBlock;
|
|
32
|
+
export type NotePatchOperation = {
|
|
33
|
+
type: 'replaceBlocks';
|
|
34
|
+
blocks: NoteBlock[];
|
|
35
|
+
} | {
|
|
36
|
+
type: 'insertBlocksAfter';
|
|
37
|
+
afterBlockId: string;
|
|
38
|
+
blocks: NoteBlock[];
|
|
39
|
+
} | {
|
|
40
|
+
type: 'updateBlock';
|
|
41
|
+
blockId: string;
|
|
42
|
+
patch: Partial<NoteBlock>;
|
|
43
|
+
} | {
|
|
44
|
+
type: 'updateMetadata';
|
|
45
|
+
title?: string;
|
|
46
|
+
tags?: string[];
|
|
47
|
+
status?: NoteStatus;
|
|
48
|
+
};
|
|
49
|
+
export interface NoteAiPatch {
|
|
50
|
+
id: string;
|
|
51
|
+
summary: string;
|
|
52
|
+
operations: NotePatchOperation[];
|
|
53
|
+
}
|
|
54
|
+
export interface NoteAttachment {
|
|
55
|
+
id: string;
|
|
56
|
+
type: 'image' | 'video' | 'audio' | 'file';
|
|
57
|
+
mimeType: string;
|
|
58
|
+
fileName: string;
|
|
59
|
+
size: number;
|
|
60
|
+
relativePath: string;
|
|
61
|
+
transcript?: string;
|
|
62
|
+
duration?: number;
|
|
63
|
+
}
|
|
64
|
+
export interface NoteAiMeta {
|
|
65
|
+
summary?: string;
|
|
66
|
+
intent?: 'action_item' | 'idea' | 'reference' | 'question' | 'log';
|
|
67
|
+
extractedTodos?: Array<{
|
|
68
|
+
text: string;
|
|
69
|
+
deadline?: string;
|
|
70
|
+
done: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
suggestedTags?: string[];
|
|
73
|
+
}
|
|
74
|
+
export interface NoteAiDeepMeta {
|
|
75
|
+
processedAt: number;
|
|
76
|
+
priority?: 'high' | 'medium' | 'low';
|
|
77
|
+
relatedNoteIds?: string[];
|
|
78
|
+
relatedGoalId?: string;
|
|
79
|
+
insights?: string;
|
|
80
|
+
}
|
|
81
|
+
export interface CaptureSource {
|
|
82
|
+
channel: CaptureChannel;
|
|
83
|
+
platform?: 'ios' | 'android';
|
|
84
|
+
}
|
|
85
|
+
export interface NoteTaskMeta {
|
|
86
|
+
done: boolean;
|
|
87
|
+
dueAt?: number;
|
|
88
|
+
priority?: 'high' | 'medium' | 'low';
|
|
89
|
+
/** Session key of the thread that created this task. */
|
|
90
|
+
sourceSessionKey?: string;
|
|
91
|
+
/** Note id of the page this task was extracted from. */
|
|
92
|
+
sourceNoteId?: string;
|
|
93
|
+
}
|
|
94
|
+
export interface Note {
|
|
95
|
+
id: string;
|
|
96
|
+
title?: string;
|
|
97
|
+
kind: NoteKind;
|
|
98
|
+
status: NoteStatus;
|
|
99
|
+
text?: string;
|
|
100
|
+
blocks?: NoteBlock[];
|
|
101
|
+
attachments?: NoteAttachment[];
|
|
102
|
+
createdAt: number;
|
|
103
|
+
updatedAt: number;
|
|
104
|
+
capturedVia: CaptureSource;
|
|
105
|
+
ai?: NoteAiMeta;
|
|
106
|
+
aiDeep?: NoteAiDeepMeta;
|
|
107
|
+
tags?: string[];
|
|
108
|
+
pinned?: boolean;
|
|
109
|
+
localVersion?: number;
|
|
110
|
+
remoteVersion?: number;
|
|
111
|
+
/** Space grouping — null means ungrouped (appears in root). */
|
|
112
|
+
groupId?: string;
|
|
113
|
+
/** Last time the user explicitly opened this note. */
|
|
114
|
+
lastOpenedAt?: number;
|
|
115
|
+
/** Task lifecycle metadata (only when kind === 'task'). */
|
|
116
|
+
taskMeta?: NoteTaskMeta;
|
|
117
|
+
}
|
|
118
|
+
export interface NoteIndexEntry {
|
|
119
|
+
id: string;
|
|
120
|
+
title?: string;
|
|
121
|
+
kind: NoteKind;
|
|
122
|
+
status: NoteStatus;
|
|
123
|
+
createdAt: number;
|
|
124
|
+
updatedAt: number;
|
|
125
|
+
pinned?: boolean;
|
|
126
|
+
tags?: string[];
|
|
127
|
+
snippet?: string;
|
|
128
|
+
/** First image attachment id for list thumbnails. */
|
|
129
|
+
coverAttachmentId?: string;
|
|
130
|
+
/** First audio attachment id for inline voice playback. */
|
|
131
|
+
voiceAttachmentId?: string;
|
|
132
|
+
/** Duration in seconds of the voice attachment (when available). */
|
|
133
|
+
voiceDurationSec?: number;
|
|
134
|
+
/** Lowercased attachment file names for list search. */
|
|
135
|
+
attachmentNames?: string[];
|
|
136
|
+
/** Space group id. */
|
|
137
|
+
groupId?: string;
|
|
138
|
+
/** Last opened timestamp for "continue" rail. */
|
|
139
|
+
lastOpenedAt?: number;
|
|
140
|
+
/** Task done flag (only when kind === 'task'). */
|
|
141
|
+
taskDone?: boolean;
|
|
142
|
+
/** Task due timestamp (only when kind === 'task'). */
|
|
143
|
+
taskDueAt?: number;
|
|
144
|
+
}
|
|
145
|
+
export interface NotesIndexFile {
|
|
146
|
+
version: number;
|
|
147
|
+
notes: NoteIndexEntry[];
|
|
148
|
+
}
|
|
149
|
+
export type SnapshotTrigger = 'edit' | 'ai_edit' | 'sync' | 'restore';
|
|
150
|
+
export interface NoteSnapshot {
|
|
151
|
+
noteId: string;
|
|
152
|
+
timestamp: number;
|
|
153
|
+
trigger: SnapshotTrigger;
|
|
154
|
+
title?: string;
|
|
155
|
+
text?: string;
|
|
156
|
+
blocks?: NoteBlock[];
|
|
157
|
+
tags?: string[];
|
|
158
|
+
kind: NoteKind;
|
|
159
|
+
status: NoteStatus;
|
|
160
|
+
}
|
|
161
|
+
export interface NoteSnapshotEntry {
|
|
162
|
+
timestamp: number;
|
|
163
|
+
trigger: SnapshotTrigger;
|
|
164
|
+
snippet?: string;
|
|
165
|
+
}
|
|
166
|
+
export interface NotesListQuery {
|
|
167
|
+
status?: NoteStatus;
|
|
168
|
+
kind?: NoteKind;
|
|
169
|
+
tag?: string;
|
|
170
|
+
pinned?: boolean;
|
|
171
|
+
search?: string;
|
|
172
|
+
limit?: number;
|
|
173
|
+
offset?: number;
|
|
174
|
+
sortBy?: 'createdAt' | 'updatedAt' | 'lastOpenedAt';
|
|
175
|
+
sortOrder?: 'asc' | 'desc';
|
|
176
|
+
/** Filter by space group id. Use `'ungrouped'` for root-level notes. */
|
|
177
|
+
groupId?: string;
|
|
178
|
+
/** Filter to only task notes with done === false. */
|
|
179
|
+
pendingTasksOnly?: boolean;
|
|
180
|
+
}
|
|
181
|
+
export interface CreateNoteParams {
|
|
182
|
+
title?: string;
|
|
183
|
+
text?: string;
|
|
184
|
+
blocks?: NoteBlock[];
|
|
185
|
+
kind?: NoteKind;
|
|
186
|
+
tags?: string[];
|
|
187
|
+
capturedVia: CaptureSource;
|
|
188
|
+
pinned?: boolean;
|
|
189
|
+
groupId?: string;
|
|
190
|
+
taskMeta?: NoteTaskMeta;
|
|
191
|
+
}
|
|
192
|
+
/** A lightweight space group (persisted as a note with kind='mixed', used for grouping). */
|
|
193
|
+
export interface NoteGroup {
|
|
194
|
+
id: string;
|
|
195
|
+
name: string;
|
|
196
|
+
icon?: string;
|
|
197
|
+
createdAt: number;
|
|
198
|
+
updatedAt: number;
|
|
199
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
4
3
|
import { dirname, join } from "node:path";
|
|
4
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
5
5
|
//#region src/providers/auth-runtime/auth-profile-store.ts
|
|
6
6
|
/**
|
|
7
7
|
* {@link AuthProfileStore} implementations.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { __esmMin, __exportAll } from "../../_virtual/_rolldown/runtime.js";
|
|
2
|
-
import { PROVIDER_ENV_MAP, getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
|
|
3
|
-
import { CredentialResolver, hasCredentials, init_credentials, resolveApiKey } from "../auth/credentials.js";
|
|
4
2
|
import { hasProviderAuthOnDiskSync, init_sync_provider_auth } from "../auth/sync-provider-auth.js";
|
|
3
|
+
import { PROVIDER_ENV_MAP, getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
|
|
5
4
|
import { ModelRegistry, getModelRegistry, init_model_registry, prewarmModelRegistry, resetModelRegistry } from "./model-registry.js";
|
|
5
|
+
import { CredentialResolver, hasCredentials, init_credentials, resolveApiKey } from "../auth/credentials.js";
|
|
6
6
|
import { getProviderRegistry, init_plugin_registry } from "./plugin-registry.js";
|
|
7
7
|
import { getModel, getModels, getProviders } from "@earendil-works/pi-ai";
|
|
8
8
|
//#region src/providers/index.ts
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
|
|
2
2
|
import { createLogger } from "../utils/logger/index.js";
|
|
3
3
|
import { init_logger } from "../utils/logger.js";
|
|
4
|
-
import { getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
|
|
5
4
|
import { resolveModelsJsonPath } from "../config/paths.js";
|
|
6
5
|
import { init_resolve_config_value, resolveConfigValue, resolveHeaders } from "../config/resolve-config-value.js";
|
|
7
6
|
import { getDefaultModelValues, init_models_json, validateModelsConfig } from "../config/models-json.js";
|
|
7
|
+
import { getApiKeyFromEnv, init_env_keys } from "./env-keys.js";
|
|
8
8
|
import { existsSync, readFileSync } from "fs";
|
|
9
9
|
import { getModels, getProviders } from "@earendil-works/pi-ai";
|
|
10
10
|
//#region src/providers/model-registry.ts
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
|
|
2
1
|
import { createLogger } from "../utils/logger/index.js";
|
|
3
2
|
import { init_logger } from "../utils/logger.js";
|
|
4
|
-
import {
|
|
3
|
+
import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
|
|
5
4
|
import { join } from "path";
|
|
6
5
|
import { existsSync } from "fs";
|
|
6
|
+
import { mkdir, readFile } from "fs/promises";
|
|
7
7
|
//#region src/session/config-store.ts
|
|
8
8
|
/**
|
|
9
9
|
* Session Config Store
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createLogger } from "../utils/logger/index.js";
|
|
2
|
-
import { init_logger } from "../utils/logger.js";
|
|
3
1
|
import { SessionConfigSchema, init_schema } from "../config/schema.js";
|
|
4
2
|
import { init_session_key, parseSessionKey } from "../routing/session-key.js";
|
|
3
|
+
import { createLogger } from "../utils/logger/index.js";
|
|
4
|
+
import { init_logger } from "../utils/logger.js";
|
|
5
5
|
import { evaluateSessionFreshness, resolveSessionResetPolicy } from "./reset-policy.js";
|
|
6
6
|
import { resolveChannelResetConfig, resolveSessionResetType } from "./reset-type.js";
|
|
7
7
|
import { resolveSessionLifecycleTimestamps } from "./lifecycle-timestamps.js";
|
|
@@ -3,9 +3,9 @@ import { loadEntriesFromFile } from "./load-jsonl-entries.js";
|
|
|
3
3
|
import { withTranscriptFileLock } from "./transcript-file-lock.js";
|
|
4
4
|
import { emitSessionTranscriptUpdate } from "../transcript-events.js";
|
|
5
5
|
import { buildSessionContextForLlm, isTranscriptContextEntry } from "../session-context-for-llm.js";
|
|
6
|
-
import { randomUUID } from "node:crypto";
|
|
7
|
-
import { existsSync } from "node:fs";
|
|
8
6
|
import path from "node:path";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { randomUUID } from "node:crypto";
|
|
9
9
|
import { CURRENT_SESSION_VERSION, SessionManager } from "@earendil-works/pi-coding-agent";
|
|
10
10
|
//#region src/session/parity/jsonl-transcript-io.ts
|
|
11
11
|
init_write_file_atomic();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
|
|
2
2
|
import { readSessionsJsonFileRaw } from "./sessions-json-file-read.js";
|
|
3
3
|
import { commitSessionsJsonWrite, getSessionsJsonWriteStats, invalidateSessionsJsonCache, noteSessionsJsonWritten, readSessionsJsonCached, resetSessionsJsonCacheForTest } from "./sessions-json-cache.js";
|
|
4
|
+
import { dirname } from "node:path";
|
|
4
5
|
import { existsSync } from "node:fs";
|
|
5
6
|
import { mkdir } from "node:fs/promises";
|
|
6
|
-
import { dirname } from "node:path";
|
|
7
7
|
import lockfile from "proper-lockfile";
|
|
8
8
|
//#region src/session/parity/sessions-json-file.ts
|
|
9
9
|
init_write_file_atomic();
|