@xopcai/xopc 0.0.99 → 0.0.101
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/src/account-manager.d.ts +3 -3
- package/dist/extensions/telegram/src/account-manager.js +8 -8
- package/dist/extensions/telegram/src/account-manager.js.map +1 -1
- package/dist/extensions/telegram/src/actions/message-actions.d.ts +4 -0
- package/dist/extensions/telegram/src/actions/message-actions.js +71 -0
- package/dist/extensions/telegram/src/actions/message-actions.js.map +1 -0
- package/dist/extensions/telegram/src/adapters/config-adapter.js +9 -1
- package/dist/extensions/telegram/src/adapters/config-adapter.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/config-surface.js +1 -1
- package/dist/extensions/telegram/src/adapters/config-surface.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/outbound-adapter.d.ts +2 -1
- package/dist/extensions/telegram/src/adapters/outbound-adapter.js +18 -4
- package/dist/extensions/telegram/src/adapters/outbound-adapter.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/security-adapter.js +2 -1
- package/dist/extensions/telegram/src/adapters/security-adapter.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js +90 -6
- package/dist/extensions/telegram/src/adapters/streaming-adapter.js.map +1 -1
- package/dist/extensions/telegram/src/adapters/types.d.ts +9 -1
- package/dist/extensions/telegram/src/api-root.d.ts +4 -0
- package/dist/extensions/telegram/src/api-root.js +42 -0
- package/dist/extensions/telegram/src/api-root.js.map +1 -0
- package/dist/extensions/telegram/src/approval-delivery.d.ts +9 -0
- package/dist/extensions/telegram/src/approval-delivery.js +36 -0
- package/dist/extensions/telegram/src/approval-delivery.js.map +1 -0
- package/dist/extensions/telegram/src/approval-store.d.ts +25 -0
- package/dist/extensions/telegram/src/approval-store.js +61 -0
- package/dist/extensions/telegram/src/approval-store.js.map +1 -0
- package/dist/extensions/telegram/src/config-schema.d.ts +185 -35
- package/dist/extensions/telegram/src/config-schema.js +67 -45
- package/dist/extensions/telegram/src/config-schema.js.map +1 -1
- package/dist/extensions/telegram/src/conversation-id.d.ts +6 -0
- package/dist/extensions/telegram/src/conversation-id.js +18 -0
- package/dist/extensions/telegram/src/conversation-id.js.map +1 -0
- package/dist/extensions/telegram/src/doctor.d.ts +5 -0
- package/dist/extensions/telegram/src/doctor.js +80 -0
- package/dist/extensions/telegram/src/doctor.js.map +1 -0
- package/dist/extensions/telegram/src/exec-approval-handler.d.ts +7 -0
- package/dist/extensions/telegram/src/exec-approval-handler.js +36 -0
- package/dist/extensions/telegram/src/exec-approval-handler.js.map +1 -0
- package/dist/extensions/telegram/src/exec-approvals.d.ts +8 -0
- package/dist/extensions/telegram/src/exec-approvals.js +20 -0
- package/dist/extensions/telegram/src/exec-approvals.js.map +1 -0
- package/dist/extensions/telegram/src/focus-handler.d.ts +12 -0
- package/dist/extensions/telegram/src/focus-handler.js +55 -0
- package/dist/extensions/telegram/src/focus-handler.js.map +1 -0
- package/dist/extensions/telegram/src/group-config-resolver.d.ts +12 -0
- package/dist/extensions/telegram/src/group-config-resolver.js +17 -0
- package/dist/extensions/telegram/src/group-config-resolver.js.map +1 -0
- package/dist/extensions/telegram/src/inbound-coalescer.d.ts +15 -0
- package/dist/extensions/telegram/src/inbound-coalescer.js +107 -0
- package/dist/extensions/telegram/src/inbound-coalescer.js.map +1 -0
- package/dist/extensions/telegram/src/inbound-processor.d.ts +1 -0
- package/dist/extensions/telegram/src/inbound-processor.js +41 -4
- package/dist/extensions/telegram/src/inbound-processor.js.map +1 -1
- package/dist/extensions/telegram/src/network-errors.d.ts +2 -0
- package/dist/extensions/telegram/src/network-errors.js +23 -0
- package/dist/extensions/telegram/src/network-errors.js.map +1 -0
- package/dist/extensions/telegram/src/plugin.d.ts +11 -0
- package/dist/extensions/telegram/src/plugin.js +191 -57
- package/dist/extensions/telegram/src/plugin.js.map +1 -1
- package/dist/extensions/telegram/src/polling-session.d.ts +17 -0
- package/dist/extensions/telegram/src/polling-session.js +112 -0
- package/dist/extensions/telegram/src/polling-session.js.map +1 -0
- package/dist/extensions/telegram/src/proxy-fetch.d.ts +2 -0
- package/dist/extensions/telegram/src/proxy-fetch.js +14 -0
- package/dist/extensions/telegram/src/proxy-fetch.js.map +1 -0
- package/dist/extensions/telegram/src/reactions.d.ts +14 -0
- package/dist/extensions/telegram/src/reactions.js +48 -0
- package/dist/extensions/telegram/src/reactions.js.map +1 -0
- package/dist/extensions/telegram/src/reply-params.d.ts +15 -0
- package/dist/extensions/telegram/src/reply-params.js +28 -0
- package/dist/extensions/telegram/src/reply-params.js.map +1 -0
- package/dist/extensions/telegram/src/startup-errors.d.ts +3 -0
- package/dist/extensions/telegram/src/startup-errors.js +27 -0
- package/dist/extensions/telegram/src/startup-errors.js.map +1 -0
- package/dist/extensions/telegram/src/telegram-actions.d.ts +25 -0
- package/dist/extensions/telegram/src/telegram-actions.js +65 -0
- package/dist/extensions/telegram/src/telegram-actions.js.map +1 -0
- package/dist/extensions/telegram/src/thread-bindings.d.ts +15 -0
- package/dist/extensions/telegram/src/thread-bindings.js +22 -0
- package/dist/extensions/telegram/src/thread-bindings.js.map +1 -0
- package/dist/extensions/telegram/src/token-resolver.d.ts +8 -0
- package/dist/extensions/telegram/src/token-resolver.js +34 -0
- package/dist/extensions/telegram/src/token-resolver.js.map +1 -0
- package/dist/extensions/telegram/src/update-offset-store.d.ts +9 -0
- package/dist/extensions/telegram/src/update-offset-store.js +66 -0
- package/dist/extensions/telegram/src/update-offset-store.js.map +1 -0
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +5 -3
- package/dist/extensions/weixin/src/api/api.js.map +1 -1
- package/dist/gateway/static/root/assets/{agents-4KTK-Ku7.js → agents-u8cmUfGQ.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-DkgInY2w.js → apps-page-DF8m9cUE.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-preview-renderer-DBAxQXb-.js → attachment-preview-renderer-CybMSIoS.js} +2 -2
- package/dist/gateway/static/root/assets/{attachment-process-heavy-Csq3TrrP.js → attachment-process-heavy-RnGYy9bC.js} +2 -2
- package/dist/gateway/static/root/assets/channels-settings-BM3doRvi.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-ah4zWEIP.js +8 -0
- package/dist/gateway/static/root/assets/{cron-api-BRDli2Mm.js → cron-api-DgMuL_2b.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-BzEr5Za8.js → cron-page-COfUPKfq.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-BsHh1vX0.js → dist-Dzy3Q0ZH.js} +1 -1
- package/dist/gateway/static/root/assets/{docx-preview-Dxj1EkCO.js → docx-preview-CajIk2FR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-TWt5q_ef.js → extension-debug-page-kyxxefKh.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-C3kV8ZvZ.js → extension-page-BVbCBHoI.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-Csy9LNC6.js → extension-settings-page-t1lb2A7v.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-BLLOP2CM.js → fetch-drJUxxKP.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-MXbM8HvY.js → field-primitives-6Vo1Yga4.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-CkoyqfRx.js → heartbeat-config-api-BF3psu4O.js} +1 -1
- package/dist/gateway/static/root/assets/index-DjNDHzwG.css +1 -0
- package/dist/gateway/static/root/assets/index-WAyKAilR.js +4840 -0
- package/dist/gateway/static/root/assets/{logs-page-B2vY41ph.js → logs-page-BTVPXcHV.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-page-B7qE5pkO.js → note-detail-page-DqSAg_5Z.js} +1 -1
- package/dist/gateway/static/root/assets/{note-time-NBBReVR4.js → note-time-FSOjchic.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-CsWYaqYM.js → notes-page-DkRX7BE2.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-BPGY3SCT.js → sessions-page-Khdw35Zk.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-advanced-gate-DtA451RM.js → settings-advanced-gate-DspC8oEm.js} +2 -2
- package/dist/gateway/static/root/assets/{settings-form-section-DYR_SPlX.js → settings-form-section-DuxvUuur.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-BJUgZQzN.js → settings-page-DN8JBZ8F.js} +2 -2
- package/dist/gateway/static/root/assets/{share-preview-page-3u8VFmdo.js → share-preview-page-UNAcbiMb.js} +2 -2
- package/dist/gateway/static/root/assets/{skills-page-DuyhcH4U.js → skills-page-ByYT0fXZ.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-e2q2yjs4.js → theme-store-B6KXPHgK.js} +1 -1
- package/dist/gateway/static/root/assets/url-q28QhI7l.js +3 -0
- package/dist/gateway/static/root/assets/{utils-B4Vw3fnc.js → utils-DK_1H47k.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-BFY67Hhp.js → voice-api-key-field-BYN2EIMs.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-yUJ5jexd.js → workflow-page.utils-Bi19YNTr.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-DIMHCpNt.js → workflows-page-DP57FEKW.js} +1 -1
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +4 -0
- package/dist/src/agent/agent-manager.js +84 -4
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +1 -0
- package/dist/src/agent/child-agent-factory.js +13 -10
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/embedded/run-for-session.d.ts +1 -0
- package/dist/src/agent/embedded/run-for-session.js +2 -0
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/embedded/run-turn.js +1 -17
- package/dist/src/agent/embedded/run-turn.js.map +1 -1
- package/dist/src/agent/embedded/session-runner.js +3 -1
- package/dist/src/agent/embedded/session-runner.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.d.ts +1 -0
- package/dist/src/agent/embedded/session-tool-result-guard.js +1 -0
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/inbound/attachment-pipeline.d.ts +37 -0
- package/dist/src/agent/inbound/attachment-pipeline.js +169 -0
- package/dist/src/agent/inbound/attachment-pipeline.js.map +1 -0
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +3 -5
- package/dist/src/agent/inbound/turn-dispatcher.js +1 -2
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/memory/index.d.ts +2 -0
- package/dist/src/agent/memory/index.js +2 -1
- package/dist/src/agent/memory/memory-flush.d.ts +27 -0
- package/dist/src/agent/memory/memory-flush.js +124 -0
- package/dist/src/agent/memory/memory-flush.js.map +1 -0
- package/dist/src/agent/messaging/outbound-coordinator.js +2 -1
- package/dist/src/agent/messaging/outbound-coordinator.js.map +1 -1
- package/dist/src/agent/messaging/stream-manager.d.ts +2 -0
- package/dist/src/agent/messaging/stream-manager.js +3 -0
- package/dist/src/agent/messaging/stream-manager.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.d.ts +0 -4
- package/dist/src/agent/orchestration/agent-orchestrator.js +40 -107
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/prompt/contribution.d.ts +9 -0
- package/dist/src/agent/prompt/contribution.js +1 -0
- package/dist/src/agent/prompt/safety.js +0 -10
- package/dist/src/agent/prompt/safety.js.map +1 -1
- package/dist/src/agent/prompt/sanitize-for-prompt.d.ts +6 -0
- package/dist/src/agent/prompt/sanitize-for-prompt.js +13 -0
- package/dist/src/agent/prompt/sanitize-for-prompt.js.map +1 -0
- package/dist/src/agent/prompt/sections/behavior.d.ts +5 -0
- package/dist/src/agent/prompt/sections/behavior.js +50 -0
- package/dist/src/agent/prompt/sections/behavior.js.map +1 -0
- package/dist/src/agent/prompt/sections/memory-skills.d.ts +9 -0
- package/dist/src/agent/prompt/sections/memory-skills.js +59 -0
- package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -0
- package/dist/src/agent/prompt/sections/messaging-runtime.d.ts +16 -0
- package/dist/src/agent/prompt/sections/messaging-runtime.js +69 -0
- package/dist/src/agent/prompt/sections/messaging-runtime.js.map +1 -0
- package/dist/src/agent/prompt/sections/project-context.d.ts +16 -0
- package/dist/src/agent/prompt/sections/project-context.js +58 -0
- package/dist/src/agent/prompt/sections/project-context.js.map +1 -0
- package/dist/src/agent/prompt/sections/tooling.d.ts +5 -0
- package/dist/src/agent/prompt/sections/tooling.js +119 -0
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -0
- package/dist/src/agent/prompt/sections/workspace-runtime.d.ts +11 -0
- package/dist/src/agent/prompt/sections/workspace-runtime.js +32 -0
- package/dist/src/agent/prompt/sections/workspace-runtime.js.map +1 -0
- package/dist/src/agent/prompt/service-prompt-builder.d.ts +13 -0
- package/dist/src/agent/prompt/service-prompt-builder.js +54 -13
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/prompt/subagent-context.d.ts +15 -0
- package/dist/src/agent/prompt/subagent-context.js +68 -0
- package/dist/src/agent/prompt/subagent-context.js.map +1 -0
- package/dist/src/agent/prompt/system-prompt-params.d.ts +53 -0
- package/dist/src/agent/prompt/system-prompt-params.js +74 -0
- package/dist/src/agent/prompt/system-prompt-params.js.map +1 -0
- package/dist/src/agent/prompt/system-prompt.d.ts +22 -11
- package/dist/src/agent/prompt/system-prompt.js +79 -193
- package/dist/src/agent/prompt/system-prompt.js.map +1 -1
- package/dist/src/agent/prompt/types.d.ts +3 -0
- package/dist/src/agent/service/build-direct-message-content.d.ts +5 -21
- package/dist/src/agent/service/build-direct-message-content.js +11 -64
- package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.d.ts +1 -1
- package/dist/src/agent/service/direct-turn-helpers.js +7 -0
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +3 -3
- package/dist/src/agent/service/process-direct-one-shot.js +22 -17
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +6 -20
- package/dist/src/agent/service/process-direct-streaming.js +39 -40
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/webchat-tts.d.ts +4 -9
- package/dist/src/agent/service/webchat-tts.js +9 -20
- package/dist/src/agent/service/webchat-tts.js.map +1 -1
- package/dist/src/agent/service.d.ts +8 -19
- package/dist/src/agent/service.js +53 -11
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/tools/factory.js +2 -0
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +1 -0
- package/dist/src/agent/tools/index.js +2 -1
- package/dist/src/agent/tools/media-read-tool.d.ts +2 -0
- package/dist/src/agent/tools/media-read-tool.js +89 -0
- package/dist/src/agent/tools/media-read-tool.js.map +1 -0
- package/dist/src/auth/credentials.js +0 -1
- package/dist/src/auth/credentials.js.map +1 -1
- package/dist/src/channels/attachments/attachment-classifiers.d.ts +8 -0
- package/dist/src/channels/attachments/attachment-classifiers.js +11 -0
- package/dist/src/channels/attachments/attachment-classifiers.js.map +1 -0
- package/dist/src/channels/attachments/inbound-persist.d.ts +13 -34
- package/dist/src/channels/attachments/inbound-persist.js +34 -102
- package/dist/src/channels/attachments/inbound-persist.js.map +1 -1
- package/dist/src/channels/attachments/inbound-types.d.ts +13 -0
- package/dist/src/channels/attachments/inbound-types.js +30 -0
- package/dist/src/channels/attachments/inbound-types.js.map +1 -0
- package/dist/src/channels/attachments/outbound-tts-persist.d.ts +3 -12
- package/dist/src/channels/attachments/outbound-tts-persist.js +28 -48
- package/dist/src/channels/attachments/outbound-tts-persist.js.map +1 -1
- package/dist/src/channels/attachments/voice-stt-webchat.d.ts +3 -3
- package/dist/src/channels/attachments/voice-stt-webchat.js +8 -14
- package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
- package/dist/src/channels/channel-domain.d.ts +30 -2
- package/dist/src/channels/exec-approval-runtime.d.ts +29 -0
- package/dist/src/channels/exec-approval-runtime.js +30 -0
- package/dist/src/channels/exec-approval-runtime.js.map +1 -0
- package/dist/src/channels/index.js +1 -1
- package/dist/src/channels/plugin-types.d.ts +1 -0
- package/dist/src/channels/transport-types.d.ts +2 -2
- package/dist/src/cli/bin.d.ts +1 -0
- package/dist/src/cli/bin.js +1 -0
- package/dist/src/cli/bin.js.map +1 -1
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.d.ts +2 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js +62 -0
- package/dist/src/cli/commands/doctor/checks/database-schema.js.map +1 -0
- package/dist/src/cli/commands/doctor/flow.js +2 -0
- package/dist/src/cli/commands/doctor/flow.js.map +1 -1
- package/dist/src/cli/commands/init.js +2 -57
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/onboard/channels/registry.js +1 -1
- package/dist/src/cli/commands/setup.js +6 -5
- package/dist/src/cli/commands/setup.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +1 -2
- package/dist/src/cli/utils/init-workspace-core.js.map +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/paths.d.ts +0 -13
- package/dist/src/config/paths.js +1 -20
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/rules.js +1 -1
- package/dist/src/config/schema.d.ts +24 -0
- package/dist/src/config/schema.js +33 -2
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/oauth-async.js +36 -3
- package/dist/src/gateway/hono/oauth-async.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/channels.js +3 -3
- package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/media.d.ts +3 -0
- package/dist/src/gateway/hono/routes/media.js +50 -0
- package/dist/src/gateway/hono/routes/media.js.map +1 -0
- package/dist/src/gateway/hono/routes/sessions.js +6 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +1 -87
- package/dist/src/gateway/hono/routes/workspace.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.js +3 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/infra/http-proxy-env.d.ts +4 -0
- package/dist/src/infra/http-proxy-env.js +23 -0
- package/dist/src/infra/http-proxy-env.js.map +1 -0
- package/dist/src/media/index.d.ts +5 -0
- package/dist/src/media/index.js +5 -0
- package/dist/src/media/media-reference.d.ts +23 -0
- package/dist/src/media/media-reference.js +34 -0
- package/dist/src/media/media-reference.js.map +1 -0
- package/dist/src/media/paths.d.ts +5 -0
- package/dist/src/media/paths.js +20 -0
- package/dist/src/media/paths.js.map +1 -0
- package/dist/src/media/session-references.d.ts +8 -0
- package/dist/src/media/session-references.js +45 -0
- package/dist/src/media/session-references.js.map +1 -0
- package/dist/src/media/store.d.ts +19 -0
- package/dist/src/media/store.js +131 -0
- package/dist/src/media/store.js.map +1 -0
- package/dist/src/media/types.d.ts +34 -0
- package/dist/src/media/types.js +1 -0
- package/dist/src/media/uri.d.ts +15 -0
- package/dist/src/media/uri.js +51 -0
- package/dist/src/media/uri.js.map +1 -0
- package/dist/src/session/session-title.js +6 -3
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/session/store.js +1 -1
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/types.d.ts +12 -7
- package/dist/src/session/types.js.map +1 -1
- package/dist/src/storage/sqlite/index.d.ts +4 -1
- package/dist/src/storage/sqlite/index.js +6 -2
- package/dist/src/storage/sqlite/migrations/002_add_flush_columns.sql +3 -0
- package/dist/src/storage/sqlite/migrations/discover.d.ts +4 -0
- package/dist/src/storage/sqlite/migrations/discover.js +38 -0
- package/dist/src/storage/sqlite/migrations/discover.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/discover.ts +52 -0
- package/dist/src/storage/sqlite/migrations/errors.d.ts +11 -0
- package/dist/src/storage/sqlite/migrations/errors.js +27 -0
- package/dist/src/storage/sqlite/migrations/errors.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/errors.ts +32 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +22 -0
- package/dist/src/storage/sqlite/migrations/runner.js +97 -0
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -0
- package/dist/src/storage/sqlite/migrations/runner.ts +153 -0
- package/dist/src/storage/sqlite/migrations/types.d.ts +12 -0
- package/dist/src/storage/sqlite/migrations/types.js +1 -0
- package/dist/src/storage/sqlite/migrations/types.ts +13 -0
- package/dist/src/storage/sqlite/row-mappers.d.ts +4 -0
- package/dist/src/storage/sqlite/row-mappers.js +4 -0
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -1
- package/dist/src/storage/sqlite/schema-version.d.ts +6 -0
- package/dist/src/storage/sqlite/schema-version.js +29 -0
- package/dist/src/storage/sqlite/schema-version.js.map +1 -0
- package/dist/src/storage/sqlite/schema.d.ts +5 -3
- package/dist/src/storage/sqlite/schema.js +24 -28
- package/dist/src/storage/sqlite/schema.js.map +1 -1
- package/dist/src/storage/sqlite/schema.sql +2 -0
- package/dist/src/storage/sqlite/session-metadata.js +1 -0
- package/dist/src/storage/sqlite/session-metadata.js.map +1 -1
- package/dist/src/storage/sqlite/session-repository.js +7 -3
- package/dist/src/storage/sqlite/session-repository.js.map +1 -1
- package/package.json +3 -3
- package/dist/gateway/static/root/assets/channels-settings-BxW1Xio4.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-Cxm6AvQO.js +0 -8
- package/dist/gateway/static/root/assets/index-BJDmBCSl.css +0 -1
- package/dist/gateway/static/root/assets/index-Cbg5TS5m.js +0 -4707
- package/dist/gateway/static/root/assets/url-DpFBIyN9.js +0 -3
- package/dist/src/cli/commands/onboard/workspace.d.ts +0 -14
- package/dist/src/cli/commands/onboard/workspace.js +0 -33
- package/dist/src/cli/commands/onboard/workspace.js.map +0 -1
- package/dist/src/cli/utils/workspace.d.ts +0 -35
- package/dist/src/cli/utils/workspace.js +0 -72
- package/dist/src/cli/utils/workspace.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","names":[],"sources":["../../../src/session/store.ts"],"sourcesContent":["import type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../config/schema.js';\nimport { resolveStateDir } from '../config/paths-state.js';\nimport { resolveEffectiveAgentProfileForSession } from '../config/agent-profile.js';\nimport { readPostCompactionContext } from '../agent/reply/post-compaction-context.js';\nimport { createLogger } from '../utils/logger.js';\nimport { SessionCompactor, type CompactionConfig, type CompactionResult } from '../agent/memory/compaction.js';\nimport { SlidingWindow, type WindowConfig } from '../agent/memory/window.js';\nimport {\n requireXopcDatabase,\n appendTranscriptEntry,\n captureCompactionCheckpoint,\n deleteSessionRecord,\n ensureSessionRecord,\n estimateTokensFromMessages,\n getCompactionCheckpointDetail,\n getGlobalSessionStats,\n getSessionMetadata,\n listCompactionCheckpoints,\n listSessionMetadata,\n listSessionsByAgent,\n loadCheckpointRows,\n loadLlmMessagesForSession,\n loadTranscriptRowsForSession,\n patchSessionMetadata,\n replaceTranscriptRows,\n resetSessionRecord,\n restoreCompactionCheckpoint,\n} from '../storage/sqlite/index.js';\nimport type { TranscriptCompactionRecord, XopcSessionTranscriptV1 } from './transcript-format.js';\nimport {\n buildSessionContextForLlm,\n mergeLlmMessagesPreservingContextRows,\n type TranscriptStoredRow,\n type XopcTranscriptContextEntry,\n} from './session-context-for-llm.js';\nimport { normalizeCompactionCheckpointId } from './compaction-checkpoints.js';\nimport type {\n SessionMetadata,\n SessionDetail,\n SessionListQuery,\n PaginatedResult,\n GlobalSessionStats,\n ExportFormat,\n SessionExport,\n SessionTranscriptSummary,\n CompactionCheckpointSummary,\n CompactionCheckpointDetail,\n} from './types.js';\nimport { SessionStatus } from './types.js';\nimport type { Message } from './types.js';\nimport type { SessionTranscriptUpdate } from './transcript-events.js';\nimport { isAppendOnlyLlmTranscriptMessage } from './transcript-stats.js';\n\nconst log = createLogger('SessionStore');\n\nconst INDEX_VERSION = '1.0';\n\nexport interface SessionStoreOptions {\n config: Config;\n}\n\nexport class SessionStore {\n private window: SlidingWindow;\n private compactor: SessionCompactor;\n\n constructor(\n private options: SessionStoreOptions,\n windowConfig?: Partial<WindowConfig>,\n compactionConfig?: Partial<CompactionConfig>,\n ) {\n this.window = new SlidingWindow(windowConfig);\n this.compactor = new SessionCompactor(compactionConfig);\n }\n\n private resolveWorkspaceCwd(sessionKey: string): string {\n return resolveEffectiveAgentProfileForSession(this.options.config, sessionKey).resolvedWorkspacePath;\n }\n\n private async runStoreMutation<T>(fn: () => Promise<T>): Promise<T> {\n return fn();\n }\n\n async initialize(): Promise<void> {\n requireXopcDatabase();\n log.debug('Session store initialized (SQLite)');\n }\n\n getSessionsRoot(): string {\n return resolveStateDir();\n }\n\n async resolveTranscriptPath(\n sessionKey: string,\n ): Promise<{ sessionId: string; sessionKey: string }> {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(sessionKey);\n const meta = ensureSessionRecord(sessionKey, cwd);\n return { sessionId: meta.transcriptId!, sessionKey };\n }\n\n async appendTranscriptMessage(sessionKey: string, message: AgentMessage): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(sessionKey);\n ensureSessionRecord(sessionKey, cwd);\n appendTranscriptEntry(sessionKey, message);\n });\n }\n\n async getByAgent(agentId: string): Promise<SessionMetadata[]> {\n requireXopcDatabase();\n return listSessionsByAgent(agentId);\n }\n\n async getByAccount(accountId: string): Promise<SessionMetadata[]> {\n const { items } = await this.list({ limit: 100_000 });\n return items.filter((m) => m.routing?.accountId === accountId);\n }\n\n async getByPeer(peerKind: string, peerId: string): Promise<SessionMetadata[]> {\n const { items } = await this.list({ limit: 100_000 });\n return items.filter((m) => m.routing?.peerKind === peerKind && m.routing.peerId === peerId);\n }\n\n async getMainSession(channel: string, accountId: string): Promise<SessionMetadata | null> {\n const { items } = await this.list({ limit: 100_000 });\n return (\n items.find(\n (m) =>\n m.routing?.source === channel &&\n m.routing.accountId === accountId &&\n m.routing.peerKind === 'dm' &&\n m.routing.peerId === 'main',\n ) ?? null\n );\n }\n\n async refreshIndex(): Promise<void> {\n /* no-op: SQLite is authoritative */\n }\n\n async list(query: SessionListQuery = {}): Promise<PaginatedResult<SessionMetadata>> {\n requireXopcDatabase();\n return listSessionMetadata(query);\n }\n\n async get(\n key: string,\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ): Promise<SessionDetail | null> {\n const metadata = await this.getMetadata(key);\n if (!metadata) {\n return null;\n }\n const messages = await this.loadDisplayMessages(key);\n return this.buildSessionDetail(key, metadata, messages, options);\n }\n\n async getMessagePage(\n key: string,\n options: {\n offset?: number;\n limit?: number;\n before?: string;\n includeTranscriptSummary?: boolean;\n includeTranscriptRows?: boolean;\n } = {},\n ): Promise<{\n session: SessionDetail;\n pagination: {\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n before?: string;\n nextBeforeCursor?: string;\n };\n } | null> {\n const metadata = await this.getMetadata(key);\n if (!metadata) {\n return null;\n }\n\n const limit = Math.min(200, Math.max(1, Math.trunc(options.limit ?? 50)));\n const offset = Math.max(0, Math.trunc(options.offset ?? 0));\n const parsedBefore = options.before ? Number.parseInt(options.before, 10) : undefined;\n const hasBeforeCursor = parsedBefore !== undefined && Number.isFinite(parsedBefore);\n\n const displayMessages = await this.loadDisplayMessages(key);\n const page = this.paginateDisplayMessages(displayMessages, {\n limit,\n offset: hasBeforeCursor ? undefined : offset,\n beforeEndIndex: hasBeforeCursor ? parsedBefore : undefined,\n });\n\n const session = await this.buildSessionDetail(key, metadata, page.messages, options);\n const nextBeforeCursor = page.startIndex > 0 ? String(page.startIndex) : undefined;\n\n return {\n session,\n pagination: {\n total: page.total,\n limit,\n offset,\n hasMore: hasBeforeCursor ? page.startIndex > 0 : offset + limit < page.total,\n ...(hasBeforeCursor ? { before: String(page.endIndex) } : {}),\n ...(nextBeforeCursor ? { nextBeforeCursor } : {}),\n },\n };\n }\n\n private async buildSessionDetail(\n key: string,\n metadata: SessionMetadata,\n messages: AgentMessage[],\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ): Promise<SessionDetail> {\n let transcriptSummary: SessionTranscriptSummary | undefined;\n if (options?.includeTranscriptSummary) {\n const env = await this.loadTranscriptDocument(key);\n if (env) {\n transcriptSummary = {\n id: env.id,\n version: env.version,\n createdAt: env.createdAt,\n updatedAt: env.updatedAt,\n compactionCount: env.compactions?.length ?? 0,\n };\n }\n }\n let transcriptRows: TranscriptStoredRow[] | undefined;\n if (options?.includeTranscriptRows) {\n transcriptRows = await this.loadTranscriptRows(key);\n }\n return {\n ...metadata,\n messages: this.convertMessages(messages),\n ...(transcriptSummary ? { transcriptSummary } : {}),\n ...(transcriptRows !== undefined ? { transcriptRows } : {}),\n };\n }\n\n async loadTranscriptRows(key: string): Promise<TranscriptStoredRow[]> {\n requireXopcDatabase();\n return loadTranscriptRowsForSession(key);\n }\n\n async getMetadata(key: string): Promise<SessionMetadata | null> {\n requireXopcDatabase();\n return getSessionMetadata(key);\n }\n\n async updateMetadata(key: string, updates: Partial<SessionMetadata>): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n patchSessionMetadata(key, updates);\n log.debug({ key, updates }, 'Session metadata updated');\n });\n }\n\n async reset(key: string): Promise<{ sessionId: string; previousSessionId: string } | null> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(key);\n const outcome = resetSessionRecord(key, cwd);\n if (outcome) {\n log.info({ key, ...outcome }, 'Session reset');\n }\n return outcome;\n });\n }\n\n async delete(key: string): Promise<boolean> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const ok = deleteSessionRecord(key);\n if (ok) {\n log.info({ key }, 'Session deleted');\n }\n return ok;\n });\n }\n\n async deleteMany(keys: string[]): Promise<{ success: string[]; failed: string[] }> {\n const success: string[] = [];\n const failed: string[] = [];\n for (const key of keys) {\n try {\n if (await this.delete(key)) {\n success.push(key);\n } else {\n failed.push(key);\n }\n } catch {\n failed.push(key);\n }\n }\n return { success, failed };\n }\n\n async setStatus(key: string, status: SessionStatus): Promise<void> {\n await this.updateMetadata(key, { status });\n }\n\n async archive(key: string): Promise<void> {\n await this.setStatus(key, SessionStatus.ARCHIVED);\n }\n\n async unarchive(key: string): Promise<void> {\n await this.setStatus(key, SessionStatus.ACTIVE);\n }\n\n async pin(key: string): Promise<void> {\n await this.setStatus(key, SessionStatus.PINNED);\n }\n\n async unpin(key: string): Promise<void> {\n await this.setStatus(key, SessionStatus.ACTIVE);\n }\n\n async loadMessages(_key: string, _options?: { fromArchive?: boolean }): Promise<AgentMessage[]> {\n requireXopcDatabase();\n return loadLlmMessagesForSession(_key);\n }\n\n async loadTranscriptDocument(key: string): Promise<XopcSessionTranscriptV1 | null> {\n const metadata = await this.getMetadata(key);\n if (!metadata?.transcriptId) {\n return null;\n }\n const rows = await this.loadTranscriptRows(key);\n const compactions: TranscriptCompactionRecord[] = [];\n for (const row of rows) {\n if ((row as { type?: string }).type === 'compaction') {\n const c = row as unknown as TranscriptCompactionRecord & { type: 'compaction' };\n compactions.push({\n at: c.at ?? new Date().toISOString(),\n summary: c.summary ?? '',\n firstKeptIndex: Number(c.firstKeptIndex ?? 0),\n tokensBefore: c.tokensBefore ?? 0,\n tokensAfter: (c as { tokensAfter?: number }).tokensAfter ?? 0,\n });\n }\n }\n return {\n type: 'xopc_session_transcript',\n version: 1,\n id: metadata.transcriptId,\n createdAt: metadata.createdAt,\n updatedAt: metadata.updatedAt,\n messages: rows,\n ...(compactions.length > 0 ? { compactions } : {}),\n };\n }\n\n async syncEmbeddedTranscriptUpdate(update: SessionTranscriptUpdate): Promise<void> {\n const sessionKey = update.sessionKey?.trim();\n if (!sessionKey) {\n return;\n }\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(sessionKey);\n ensureSessionRecord(sessionKey, cwd);\n\n if (update.message && isAppendOnlyLlmTranscriptMessage(update.message)) {\n appendTranscriptEntry(sessionKey, update.message as AgentMessage);\n }\n });\n }\n\n async appendTranscriptContextEntry(\n key: string,\n entry: Omit<XopcTranscriptContextEntry, 'kind'> & Partial<Pick<XopcTranscriptContextEntry, 'kind'>>,\n ): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(key);\n ensureSessionRecord(key, cwd);\n const row: XopcTranscriptContextEntry = {\n kind: 'context',\n id: typeof entry.id === 'string' ? entry.id : undefined,\n text: typeof entry.text === 'string' ? entry.text : undefined,\n data: entry.data,\n createdAt: entry.createdAt ?? new Date().toISOString(),\n };\n appendTranscriptEntry(key, row);\n });\n }\n\n async saveMessages(key: string, messages: AgentMessage[]): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(key);\n ensureSessionRecord(key, cwd);\n const prev = await this.loadTranscriptRows(key);\n const merged = mergeLlmMessagesPreservingContextRows(prev, messages);\n replaceTranscriptRows(key, merged);\n });\n }\n\n getWindowStats(messages: AgentMessage[]) {\n return this.window.getStats(messages);\n }\n\n needsCompaction(key: string, messages: AgentMessage[], contextWindow: number) {\n return this.compactor.needsCompaction(messages, contextWindow);\n }\n\n prepareCompaction(key: string, messages: AgentMessage[], contextWindow: number) {\n const result = this.compactor.needsCompaction(messages, contextWindow);\n return { needsCompaction: result.needed, messages, stats: result };\n }\n\n async applyCompaction(\n key: string,\n messages: AgentMessage[],\n result: CompactionResult,\n ): Promise<AgentMessage[]> {\n const compacted = this.compactor.applyCompaction(messages, result);\n return this.runStoreMutation(async () => {\n const prev = await this.loadTranscriptRows(key);\n const merged = mergeLlmMessagesPreservingContextRows(prev, compacted);\n captureCompactionCheckpoint(key);\n replaceTranscriptRows(key, merged, {\n appendCompaction: {\n at: new Date().toISOString(),\n summary: result.summary,\n firstKeptIndex: result.firstKeptIndex,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n },\n });\n const metadata = await this.getMetadata(key);\n if (metadata) {\n await this.updateMetadata(key, { compactedCount: metadata.compactedCount + 1 });\n }\n log.info(\n { key, tokensBefore: result.tokensBefore, tokensAfter: result.tokensAfter, keptMessages: compacted.length },\n 'Session compacted',\n );\n await this.injectPostCompactionContext(key);\n return compacted;\n });\n }\n\n async compact(\n key: string,\n messages: AgentMessage[],\n contextWindow: number,\n instructions?: string,\n force?: boolean,\n ): Promise<CompactionResult> {\n void contextWindow;\n const result = await this.compactor.compact(messages, instructions, force);\n if (result.compacted) {\n await this.applyCompaction(key, messages, result);\n }\n return result;\n }\n\n async getCompactionStats(key: string) {\n const metadata = await this.getMetadata(key);\n if (!metadata) {\n return undefined;\n }\n return {\n compactionCount: metadata.compactedCount,\n totalTokensBefore: 0,\n totalTokensAfter: 0,\n lastCompactionAt: undefined,\n };\n }\n\n async listCompactionCheckpoints(key: string): Promise<CompactionCheckpointSummary[]> {\n requireXopcDatabase();\n return listCompactionCheckpoints(key);\n }\n\n async getCompactionCheckpointDetail(\n key: string,\n checkpointId: string,\n ): Promise<CompactionCheckpointDetail | null> {\n requireXopcDatabase();\n const id = normalizeCompactionCheckpointId(checkpointId);\n if (!id) {\n return null;\n }\n return getCompactionCheckpointDetail(key, id);\n }\n\n async restoreCompactionCheckpoint(key: string, checkpointId: string): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const id = normalizeCompactionCheckpointId(checkpointId);\n if (!id) {\n throw new Error(`Invalid checkpoint id: ${checkpointId}`);\n }\n restoreCompactionCheckpoint(key, id);\n });\n }\n\n async deleteSession(key: string): Promise<boolean> {\n return this.delete(key);\n }\n\n async load(key: string, options?: { fromArchive?: boolean }): Promise<AgentMessage[]> {\n return this.loadMessages(key, options);\n }\n\n async estimateTokenUsage(_key: string, messages: AgentMessage[]): Promise<number> {\n return this.estimateTokens(messages);\n }\n\n async searchInSession(key: string, keyword: string): Promise<Message[]> {\n const messages = await this.loadDisplayMessages(key);\n const q = keyword.toLowerCase();\n return this.convertMessages(\n messages.filter((m) => this.extractTextContent(this.messageContent(m)).toLowerCase().includes(q)),\n );\n }\n\n async exportSession(key: string, format: ExportFormat): Promise<string> {\n const metadata = await this.getMetadata(key);\n if (!metadata) {\n throw new Error(`Session not found: ${key}`);\n }\n const rows = await this.loadTranscriptRows(key);\n const messages = this.convertMessages(buildSessionContextForLlm(rows));\n const payload: SessionExport = {\n version: INDEX_VERSION,\n exportedAt: new Date().toISOString(),\n metadata,\n messages,\n transcriptRows: rows,\n };\n if (format === 'json') {\n return JSON.stringify(payload, null, 2);\n }\n const lines = [`# ${metadata.name ?? metadata.key}`, '', `Exported: ${payload.exportedAt}`, ''];\n for (const msg of messages) {\n lines.push(`## ${msg.role}`, '', typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content), '');\n }\n return lines.join('\\n');\n }\n\n async getStats(): Promise<GlobalSessionStats> {\n requireXopcDatabase();\n return getGlobalSessionStats();\n }\n\n async archiveOld(olderThanDays: number): Promise<number> {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - olderThanDays);\n const list = await this.list({ limit: 100_000 });\n let archived = 0;\n for (const session of list.items) {\n if (session.status !== SessionStatus.ARCHIVED && session.status !== SessionStatus.PINNED) {\n const lastAccess = new Date(session.lastAccessedAt);\n if (lastAccess < cutoff) {\n await this.archive(session.key);\n archived++;\n }\n }\n }\n return archived;\n }\n\n estimateTokens(messages: AgentMessage[]): number {\n return estimateTokensFromMessages(messages);\n }\n\n private async loadDisplayMessages(key: string): Promise<AgentMessage[]> {\n requireXopcDatabase();\n const checkpoints = listCompactionCheckpoints(key);\n const rowSets: TranscriptStoredRow[][] = [];\n for (const checkpoint of [...checkpoints].reverse()) {\n rowSets.push(loadCheckpointRows(key, checkpoint.id));\n }\n rowSets.push(await this.loadTranscriptRows(key));\n\n const messages: AgentMessage[] = [];\n const seen = new Set<string>();\n for (const rows of rowSets) {\n for (const message of buildSessionContextForLlm(rows)) {\n if (this.isCompactionSummaryMessage(message)) {\n continue;\n }\n const identity = this.displayMessageIdentity(message);\n if (seen.has(identity)) {\n continue;\n }\n seen.add(identity);\n messages.push(message);\n }\n }\n return messages;\n }\n\n private paginateDisplayMessages(\n messages: AgentMessage[],\n options: {\n offset?: number;\n limit?: number;\n beforeEndIndex?: number;\n } = {},\n ): { messages: AgentMessage[]; total: number; startIndex: number; endIndex: number } {\n const total = messages.length;\n const limit = Math.min(200, Math.max(1, Math.trunc(options.limit ?? 50)));\n const offset = Math.max(0, Math.trunc(options.offset ?? 0));\n\n let startIndex: number;\n let endIndex: number;\n if (options.beforeEndIndex !== undefined && Number.isFinite(options.beforeEndIndex)) {\n endIndex = Math.min(total, Math.max(0, Math.trunc(options.beforeEndIndex)));\n startIndex = Math.max(0, endIndex - limit);\n } else {\n endIndex = Math.max(0, total - offset);\n startIndex = Math.max(0, endIndex - limit);\n }\n\n return {\n messages: messages.slice(startIndex, endIndex),\n total,\n startIndex,\n endIndex,\n };\n }\n\n private displayMessageIdentity(message: AgentMessage): string {\n const record = message as unknown as Record<string, unknown>;\n return JSON.stringify({\n role: message.role,\n timestamp: record.timestamp,\n toolCallId: record.toolCallId ?? record.tool_call_id,\n toolName: record.toolName,\n content: this.messageContent(message),\n });\n }\n\n private messageContent(msg: AgentMessage): unknown {\n return (msg as { content?: unknown }).content;\n }\n\n private isCompactionSummaryMessage(msg: AgentMessage): boolean {\n if (msg.role !== 'user') {\n return false;\n }\n const text = this.extractTextContent(this.messageContent(msg)).trim();\n return /^\\[Previous conversation summary\\]/i.test(text);\n }\n\n private extractTextContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n const parts: string[] = [];\n for (const item of content) {\n if (typeof item !== 'object' || item === null || !('type' in item)) {\n continue;\n }\n const c = item as { type?: string; text?: string; name?: string };\n if (c.type === 'text' && typeof c.text === 'string') {\n parts.push(c.text);\n } else if (c.type === 'toolCall' || c.type === 'tool_use') {\n parts.push(c.name ? `[${c.name}]` : '');\n }\n }\n return parts.join('');\n }\n return '';\n }\n\n private async injectPostCompactionContext(key: string): Promise<void> {\n const contextText = readPostCompactionContext({\n cfg: this.options.config,\n sessionKey: key,\n });\n if (!contextText?.trim()) {\n return;\n }\n try {\n await this.appendTranscriptContextEntry(key, {\n id: `post-compaction-${Date.now()}`,\n text: contextText,\n createdAt: new Date().toISOString(),\n });\n } catch (err) {\n log.warn({ err, key }, 'Post-compaction context injection failed');\n }\n }\n\n private convertMessages(messages: AgentMessage[]): Message[] {\n return messages.map((m: AgentMessage & Record<string, unknown>) => {\n const c = this.messageContent(m);\n const content: string | unknown[] =\n typeof c === 'string' ? c : Array.isArray(c) ? c : this.extractTextContent(c);\n const row: Message = {\n role: m.role as Message['role'],\n content,\n timestamp: m.timestamp ? new Date(m.timestamp as string | number).toISOString() : undefined,\n tool_call_id: (m.tool_call_id as string | undefined) || (m.toolCallId as string | undefined),\n tool_calls: m.tool_calls as Message['tool_calls'],\n name: m.name as string | undefined,\n };\n if (Array.isArray(m.attachments) && m.attachments.length > 0) {\n row.attachments = m.attachments as Message['attachments'];\n }\n const rawUsage = m.usage as { input?: number; output?: number; totalTokens?: number; total?: number } | undefined;\n if (rawUsage && typeof rawUsage === 'object') {\n const inputTokens = typeof rawUsage.input === 'number' ? rawUsage.input : undefined;\n const outputTokens = typeof rawUsage.output === 'number' ? rawUsage.output : undefined;\n const totalTokens = typeof rawUsage.totalTokens === 'number'\n ? rawUsage.totalTokens\n : typeof rawUsage.total === 'number'\n ? rawUsage.total\n : undefined;\n if (inputTokens !== undefined || outputTokens !== undefined || totalTokens !== undefined) {\n row.usage = { inputTokens, outputTokens, totalTokens };\n }\n }\n return row;\n });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","names":[],"sources":["../../../src/session/store.ts"],"sourcesContent":["import type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { Config } from '../config/schema.js';\nimport { resolveStateDir } from '../config/paths-state.js';\nimport { resolveEffectiveAgentProfileForSession } from '../config/agent-profile.js';\nimport { readPostCompactionContext } from '../agent/reply/post-compaction-context.js';\nimport { createLogger } from '../utils/logger.js';\nimport { SessionCompactor, type CompactionConfig, type CompactionResult } from '../agent/memory/compaction.js';\nimport { SlidingWindow, type WindowConfig } from '../agent/memory/window.js';\nimport {\n requireXopcDatabase,\n appendTranscriptEntry,\n captureCompactionCheckpoint,\n deleteSessionRecord,\n ensureSessionRecord,\n estimateTokensFromMessages,\n getCompactionCheckpointDetail,\n getGlobalSessionStats,\n getSessionMetadata,\n listCompactionCheckpoints,\n listSessionMetadata,\n listSessionsByAgent,\n loadCheckpointRows,\n loadLlmMessagesForSession,\n loadTranscriptRowsForSession,\n patchSessionMetadata,\n replaceTranscriptRows,\n resetSessionRecord,\n restoreCompactionCheckpoint,\n} from '../storage/sqlite/index.js';\nimport type { TranscriptCompactionRecord, XopcSessionTranscriptV1 } from './transcript-format.js';\nimport {\n buildSessionContextForLlm,\n mergeLlmMessagesPreservingContextRows,\n type TranscriptStoredRow,\n type XopcTranscriptContextEntry,\n} from './session-context-for-llm.js';\nimport { normalizeCompactionCheckpointId } from './compaction-checkpoints.js';\nimport type {\n SessionMetadata,\n SessionDetail,\n SessionListQuery,\n PaginatedResult,\n GlobalSessionStats,\n ExportFormat,\n SessionExport,\n SessionTranscriptSummary,\n CompactionCheckpointSummary,\n CompactionCheckpointDetail,\n} from './types.js';\nimport { SessionStatus } from './types.js';\nimport type { Message } from './types.js';\nimport type { SessionTranscriptUpdate } from './transcript-events.js';\nimport { isAppendOnlyLlmTranscriptMessage } from './transcript-stats.js';\n\nconst log = createLogger('SessionStore');\n\nconst INDEX_VERSION = '1.0';\n\nexport interface SessionStoreOptions {\n config: Config;\n}\n\nexport class SessionStore {\n private window: SlidingWindow;\n private compactor: SessionCompactor;\n\n constructor(\n private options: SessionStoreOptions,\n windowConfig?: Partial<WindowConfig>,\n compactionConfig?: Partial<CompactionConfig>,\n ) {\n this.window = new SlidingWindow(windowConfig);\n this.compactor = new SessionCompactor(compactionConfig);\n }\n\n private resolveWorkspaceCwd(sessionKey: string): string {\n return resolveEffectiveAgentProfileForSession(this.options.config, sessionKey).resolvedWorkspacePath;\n }\n\n private async runStoreMutation<T>(fn: () => Promise<T>): Promise<T> {\n return fn();\n }\n\n async initialize(): Promise<void> {\n requireXopcDatabase();\n log.debug('Session store initialized (SQLite)');\n }\n\n getSessionsRoot(): string {\n return resolveStateDir();\n }\n\n async resolveTranscriptPath(\n sessionKey: string,\n ): Promise<{ sessionId: string; sessionKey: string }> {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(sessionKey);\n const meta = ensureSessionRecord(sessionKey, cwd);\n return { sessionId: meta.transcriptId!, sessionKey };\n }\n\n async appendTranscriptMessage(sessionKey: string, message: AgentMessage): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(sessionKey);\n ensureSessionRecord(sessionKey, cwd);\n appendTranscriptEntry(sessionKey, message);\n });\n }\n\n async getByAgent(agentId: string): Promise<SessionMetadata[]> {\n requireXopcDatabase();\n return listSessionsByAgent(agentId);\n }\n\n async getByAccount(accountId: string): Promise<SessionMetadata[]> {\n const { items } = await this.list({ limit: 100_000 });\n return items.filter((m) => m.routing?.accountId === accountId);\n }\n\n async getByPeer(peerKind: string, peerId: string): Promise<SessionMetadata[]> {\n const { items } = await this.list({ limit: 100_000 });\n return items.filter((m) => m.routing?.peerKind === peerKind && m.routing.peerId === peerId);\n }\n\n async getMainSession(channel: string, accountId: string): Promise<SessionMetadata | null> {\n const { items } = await this.list({ limit: 100_000 });\n return (\n items.find(\n (m) =>\n m.routing?.source === channel &&\n m.routing.accountId === accountId &&\n m.routing.peerKind === 'dm' &&\n m.routing.peerId === 'main',\n ) ?? null\n );\n }\n\n async refreshIndex(): Promise<void> {\n /* no-op: SQLite is authoritative */\n }\n\n async list(query: SessionListQuery = {}): Promise<PaginatedResult<SessionMetadata>> {\n requireXopcDatabase();\n return listSessionMetadata(query);\n }\n\n async get(\n key: string,\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ): Promise<SessionDetail | null> {\n const metadata = await this.getMetadata(key);\n if (!metadata) {\n return null;\n }\n const messages = await this.loadDisplayMessages(key);\n return this.buildSessionDetail(key, metadata, messages, options);\n }\n\n async getMessagePage(\n key: string,\n options: {\n offset?: number;\n limit?: number;\n before?: string;\n includeTranscriptSummary?: boolean;\n includeTranscriptRows?: boolean;\n } = {},\n ): Promise<{\n session: SessionDetail;\n pagination: {\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n before?: string;\n nextBeforeCursor?: string;\n };\n } | null> {\n const metadata = await this.getMetadata(key);\n if (!metadata) {\n return null;\n }\n\n const limit = Math.min(200, Math.max(1, Math.trunc(options.limit ?? 50)));\n const offset = Math.max(0, Math.trunc(options.offset ?? 0));\n const parsedBefore = options.before ? Number.parseInt(options.before, 10) : undefined;\n const hasBeforeCursor = parsedBefore !== undefined && Number.isFinite(parsedBefore);\n\n const displayMessages = await this.loadDisplayMessages(key);\n const page = this.paginateDisplayMessages(displayMessages, {\n limit,\n offset: hasBeforeCursor ? undefined : offset,\n beforeEndIndex: hasBeforeCursor ? parsedBefore : undefined,\n });\n\n const session = await this.buildSessionDetail(key, metadata, page.messages, options);\n const nextBeforeCursor = page.startIndex > 0 ? String(page.startIndex) : undefined;\n\n return {\n session,\n pagination: {\n total: page.total,\n limit,\n offset,\n hasMore: hasBeforeCursor ? page.startIndex > 0 : offset + limit < page.total,\n ...(hasBeforeCursor ? { before: String(page.endIndex) } : {}),\n ...(nextBeforeCursor ? { nextBeforeCursor } : {}),\n },\n };\n }\n\n private async buildSessionDetail(\n key: string,\n metadata: SessionMetadata,\n messages: AgentMessage[],\n options?: { includeTranscriptSummary?: boolean; includeTranscriptRows?: boolean },\n ): Promise<SessionDetail> {\n let transcriptSummary: SessionTranscriptSummary | undefined;\n if (options?.includeTranscriptSummary) {\n const env = await this.loadTranscriptDocument(key);\n if (env) {\n transcriptSummary = {\n id: env.id,\n version: env.version,\n createdAt: env.createdAt,\n updatedAt: env.updatedAt,\n compactionCount: env.compactions?.length ?? 0,\n };\n }\n }\n let transcriptRows: TranscriptStoredRow[] | undefined;\n if (options?.includeTranscriptRows) {\n transcriptRows = await this.loadTranscriptRows(key);\n }\n return {\n ...metadata,\n messages: this.convertMessages(messages),\n ...(transcriptSummary ? { transcriptSummary } : {}),\n ...(transcriptRows !== undefined ? { transcriptRows } : {}),\n };\n }\n\n async loadTranscriptRows(key: string): Promise<TranscriptStoredRow[]> {\n requireXopcDatabase();\n return loadTranscriptRowsForSession(key);\n }\n\n async getMetadata(key: string): Promise<SessionMetadata | null> {\n requireXopcDatabase();\n return getSessionMetadata(key);\n }\n\n async updateMetadata(key: string, updates: Partial<SessionMetadata>): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n patchSessionMetadata(key, updates);\n log.debug({ key, updates }, 'Session metadata updated');\n });\n }\n\n async reset(key: string): Promise<{ sessionId: string; previousSessionId: string } | null> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(key);\n const outcome = resetSessionRecord(key, cwd);\n if (outcome) {\n log.info({ key, ...outcome }, 'Session reset');\n }\n return outcome;\n });\n }\n\n async delete(key: string): Promise<boolean> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const ok = deleteSessionRecord(key);\n if (ok) {\n log.info({ key }, 'Session deleted');\n }\n return ok;\n });\n }\n\n async deleteMany(keys: string[]): Promise<{ success: string[]; failed: string[] }> {\n const success: string[] = [];\n const failed: string[] = [];\n for (const key of keys) {\n try {\n if (await this.delete(key)) {\n success.push(key);\n } else {\n failed.push(key);\n }\n } catch {\n failed.push(key);\n }\n }\n return { success, failed };\n }\n\n async setStatus(key: string, status: SessionStatus): Promise<void> {\n await this.updateMetadata(key, { status });\n }\n\n async archive(key: string): Promise<void> {\n await this.setStatus(key, SessionStatus.ARCHIVED);\n }\n\n async unarchive(key: string): Promise<void> {\n await this.setStatus(key, SessionStatus.ACTIVE);\n }\n\n async pin(key: string): Promise<void> {\n await this.setStatus(key, SessionStatus.PINNED);\n }\n\n async unpin(key: string): Promise<void> {\n await this.setStatus(key, SessionStatus.ACTIVE);\n }\n\n async loadMessages(_key: string, _options?: { fromArchive?: boolean }): Promise<AgentMessage[]> {\n requireXopcDatabase();\n return loadLlmMessagesForSession(_key);\n }\n\n async loadTranscriptDocument(key: string): Promise<XopcSessionTranscriptV1 | null> {\n const metadata = await this.getMetadata(key);\n if (!metadata?.transcriptId) {\n return null;\n }\n const rows = await this.loadTranscriptRows(key);\n const compactions: TranscriptCompactionRecord[] = [];\n for (const row of rows) {\n if ((row as { type?: string }).type === 'compaction') {\n const c = row as unknown as TranscriptCompactionRecord & { type: 'compaction' };\n compactions.push({\n at: c.at ?? new Date().toISOString(),\n summary: c.summary ?? '',\n firstKeptIndex: Number(c.firstKeptIndex ?? 0),\n tokensBefore: c.tokensBefore ?? 0,\n tokensAfter: (c as { tokensAfter?: number }).tokensAfter ?? 0,\n });\n }\n }\n return {\n type: 'xopc_session_transcript',\n version: 1,\n id: metadata.transcriptId,\n createdAt: metadata.createdAt,\n updatedAt: metadata.updatedAt,\n messages: rows,\n ...(compactions.length > 0 ? { compactions } : {}),\n };\n }\n\n async syncEmbeddedTranscriptUpdate(update: SessionTranscriptUpdate): Promise<void> {\n const sessionKey = update.sessionKey?.trim();\n if (!sessionKey) {\n return;\n }\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(sessionKey);\n ensureSessionRecord(sessionKey, cwd);\n\n if (update.message && isAppendOnlyLlmTranscriptMessage(update.message)) {\n appendTranscriptEntry(sessionKey, update.message as AgentMessage);\n }\n });\n }\n\n async appendTranscriptContextEntry(\n key: string,\n entry: Omit<XopcTranscriptContextEntry, 'kind'> & Partial<Pick<XopcTranscriptContextEntry, 'kind'>>,\n ): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(key);\n ensureSessionRecord(key, cwd);\n const row: XopcTranscriptContextEntry = {\n kind: 'context',\n id: typeof entry.id === 'string' ? entry.id : undefined,\n text: typeof entry.text === 'string' ? entry.text : undefined,\n data: entry.data,\n createdAt: entry.createdAt ?? new Date().toISOString(),\n };\n appendTranscriptEntry(key, row);\n });\n }\n\n async saveMessages(key: string, messages: AgentMessage[]): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const cwd = this.resolveWorkspaceCwd(key);\n ensureSessionRecord(key, cwd);\n const prev = await this.loadTranscriptRows(key);\n const merged = mergeLlmMessagesPreservingContextRows(prev, messages);\n replaceTranscriptRows(key, merged);\n });\n }\n\n getWindowStats(messages: AgentMessage[]) {\n return this.window.getStats(messages);\n }\n\n needsCompaction(key: string, messages: AgentMessage[], contextWindow: number) {\n return this.compactor.needsCompaction(messages, contextWindow);\n }\n\n prepareCompaction(key: string, messages: AgentMessage[], contextWindow: number) {\n const result = this.compactor.needsCompaction(messages, contextWindow);\n return { needsCompaction: result.needed, messages, stats: result };\n }\n\n async applyCompaction(\n key: string,\n messages: AgentMessage[],\n result: CompactionResult,\n ): Promise<AgentMessage[]> {\n const compacted = this.compactor.applyCompaction(messages, result);\n return this.runStoreMutation(async () => {\n const prev = await this.loadTranscriptRows(key);\n const merged = mergeLlmMessagesPreservingContextRows(prev, compacted);\n captureCompactionCheckpoint(key);\n replaceTranscriptRows(key, merged, {\n appendCompaction: {\n at: new Date().toISOString(),\n summary: result.summary,\n firstKeptIndex: result.firstKeptIndex,\n tokensBefore: result.tokensBefore,\n tokensAfter: result.tokensAfter,\n },\n });\n const metadata = await this.getMetadata(key);\n if (metadata) {\n await this.updateMetadata(key, { compactedCount: metadata.compactedCount + 1 });\n }\n log.info(\n { key, tokensBefore: result.tokensBefore, tokensAfter: result.tokensAfter, keptMessages: compacted.length },\n 'Session compacted',\n );\n await this.injectPostCompactionContext(key);\n return compacted;\n });\n }\n\n async compact(\n key: string,\n messages: AgentMessage[],\n contextWindow: number,\n instructions?: string,\n force?: boolean,\n ): Promise<CompactionResult> {\n void contextWindow;\n const result = await this.compactor.compact(messages, instructions, force);\n if (result.compacted) {\n await this.applyCompaction(key, messages, result);\n }\n return result;\n }\n\n async getCompactionStats(key: string) {\n const metadata = await this.getMetadata(key);\n if (!metadata) {\n return undefined;\n }\n return {\n compactionCount: metadata.compactedCount,\n totalTokensBefore: 0,\n totalTokensAfter: 0,\n lastCompactionAt: undefined,\n };\n }\n\n async listCompactionCheckpoints(key: string): Promise<CompactionCheckpointSummary[]> {\n requireXopcDatabase();\n return listCompactionCheckpoints(key);\n }\n\n async getCompactionCheckpointDetail(\n key: string,\n checkpointId: string,\n ): Promise<CompactionCheckpointDetail | null> {\n requireXopcDatabase();\n const id = normalizeCompactionCheckpointId(checkpointId);\n if (!id) {\n return null;\n }\n return getCompactionCheckpointDetail(key, id);\n }\n\n async restoreCompactionCheckpoint(key: string, checkpointId: string): Promise<void> {\n return this.runStoreMutation(async () => {\n requireXopcDatabase();\n const id = normalizeCompactionCheckpointId(checkpointId);\n if (!id) {\n throw new Error(`Invalid checkpoint id: ${checkpointId}`);\n }\n restoreCompactionCheckpoint(key, id);\n });\n }\n\n async deleteSession(key: string): Promise<boolean> {\n return this.delete(key);\n }\n\n async load(key: string, options?: { fromArchive?: boolean }): Promise<AgentMessage[]> {\n return this.loadMessages(key, options);\n }\n\n async estimateTokenUsage(_key: string, messages: AgentMessage[]): Promise<number> {\n return this.estimateTokens(messages);\n }\n\n async searchInSession(key: string, keyword: string): Promise<Message[]> {\n const messages = await this.loadDisplayMessages(key);\n const q = keyword.toLowerCase();\n return this.convertMessages(\n messages.filter((m) => this.extractTextContent(this.messageContent(m)).toLowerCase().includes(q)),\n );\n }\n\n async exportSession(key: string, format: ExportFormat): Promise<string> {\n const metadata = await this.getMetadata(key);\n if (!metadata) {\n throw new Error(`Session not found: ${key}`);\n }\n const rows = await this.loadTranscriptRows(key);\n const messages = this.convertMessages(buildSessionContextForLlm(rows));\n const payload: SessionExport = {\n version: INDEX_VERSION,\n exportedAt: new Date().toISOString(),\n metadata,\n messages,\n transcriptRows: rows,\n };\n if (format === 'json') {\n return JSON.stringify(payload, null, 2);\n }\n const lines = [`# ${metadata.name ?? metadata.key}`, '', `Exported: ${payload.exportedAt}`, ''];\n for (const msg of messages) {\n lines.push(`## ${msg.role}`, '', typeof msg.content === 'string' ? msg.content : JSON.stringify(msg.content), '');\n }\n return lines.join('\\n');\n }\n\n async getStats(): Promise<GlobalSessionStats> {\n requireXopcDatabase();\n return getGlobalSessionStats();\n }\n\n async archiveOld(olderThanDays: number): Promise<number> {\n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - olderThanDays);\n const list = await this.list({ limit: 100_000 });\n let archived = 0;\n for (const session of list.items) {\n if (session.status !== SessionStatus.ARCHIVED && session.status !== SessionStatus.PINNED) {\n const lastAccess = new Date(session.lastAccessedAt);\n if (lastAccess < cutoff) {\n await this.archive(session.key);\n archived++;\n }\n }\n }\n return archived;\n }\n\n estimateTokens(messages: AgentMessage[]): number {\n return estimateTokensFromMessages(messages);\n }\n\n private async loadDisplayMessages(key: string): Promise<AgentMessage[]> {\n requireXopcDatabase();\n const checkpoints = listCompactionCheckpoints(key);\n const rowSets: TranscriptStoredRow[][] = [];\n for (const checkpoint of [...checkpoints].reverse()) {\n rowSets.push(loadCheckpointRows(key, checkpoint.id));\n }\n rowSets.push(await this.loadTranscriptRows(key));\n\n const messages: AgentMessage[] = [];\n const seen = new Set<string>();\n for (const rows of rowSets) {\n for (const message of buildSessionContextForLlm(rows)) {\n if (this.isCompactionSummaryMessage(message)) {\n continue;\n }\n const identity = this.displayMessageIdentity(message);\n if (seen.has(identity)) {\n continue;\n }\n seen.add(identity);\n messages.push(message);\n }\n }\n return messages;\n }\n\n private paginateDisplayMessages(\n messages: AgentMessage[],\n options: {\n offset?: number;\n limit?: number;\n beforeEndIndex?: number;\n } = {},\n ): { messages: AgentMessage[]; total: number; startIndex: number; endIndex: number } {\n const total = messages.length;\n const limit = Math.min(200, Math.max(1, Math.trunc(options.limit ?? 50)));\n const offset = Math.max(0, Math.trunc(options.offset ?? 0));\n\n let startIndex: number;\n let endIndex: number;\n if (options.beforeEndIndex !== undefined && Number.isFinite(options.beforeEndIndex)) {\n endIndex = Math.min(total, Math.max(0, Math.trunc(options.beforeEndIndex)));\n startIndex = Math.max(0, endIndex - limit);\n } else {\n endIndex = Math.max(0, total - offset);\n startIndex = Math.max(0, endIndex - limit);\n }\n\n return {\n messages: messages.slice(startIndex, endIndex),\n total,\n startIndex,\n endIndex,\n };\n }\n\n private displayMessageIdentity(message: AgentMessage): string {\n const record = message as unknown as Record<string, unknown>;\n return JSON.stringify({\n role: message.role,\n timestamp: record.timestamp,\n toolCallId: record.toolCallId ?? record.tool_call_id,\n toolName: record.toolName,\n content: this.messageContent(message),\n });\n }\n\n private messageContent(msg: AgentMessage): unknown {\n return (msg as { content?: unknown }).content;\n }\n\n private isCompactionSummaryMessage(msg: AgentMessage): boolean {\n if (msg.role !== 'user') {\n return false;\n }\n const text = this.extractTextContent(this.messageContent(msg)).trim();\n return /^\\[Previous conversation summary\\]/i.test(text);\n }\n\n private extractTextContent(content: unknown): string {\n if (typeof content === 'string') {\n return content;\n }\n if (Array.isArray(content)) {\n const parts: string[] = [];\n for (const item of content) {\n if (typeof item !== 'object' || item === null || !('type' in item)) {\n continue;\n }\n const c = item as { type?: string; text?: string; name?: string };\n if (c.type === 'text' && typeof c.text === 'string') {\n parts.push(c.text);\n } else if (c.type === 'toolCall' || c.type === 'tool_use') {\n parts.push(c.name ? `[${c.name}]` : '');\n }\n }\n return parts.join('');\n }\n return '';\n }\n\n private async injectPostCompactionContext(key: string): Promise<void> {\n const contextText = readPostCompactionContext({\n cfg: this.options.config,\n sessionKey: key,\n });\n if (!contextText?.trim()) {\n return;\n }\n try {\n await this.appendTranscriptContextEntry(key, {\n id: `post-compaction-${Date.now()}`,\n text: contextText,\n createdAt: new Date().toISOString(),\n });\n } catch (err) {\n log.warn({ err, key }, 'Post-compaction context injection failed');\n }\n }\n\n private convertMessages(messages: AgentMessage[]): Message[] {\n return messages.map((m: AgentMessage & Record<string, unknown>) => {\n const c = this.messageContent(m);\n const content: string | unknown[] =\n typeof c === 'string' ? c : Array.isArray(c) ? c : this.extractTextContent(c);\n const row: Message = {\n role: m.role as Message['role'],\n content,\n timestamp: m.timestamp ? new Date(m.timestamp as string | number).toISOString() : undefined,\n tool_call_id: (m.tool_call_id as string | undefined) || (m.toolCallId as string | undefined),\n tool_calls: m.tool_calls as Message['tool_calls'],\n name: m.name as string | undefined,\n };\n if (Array.isArray(m.media) && m.media.length > 0) {\n row.media = m.media as Message['media'];\n }\n const rawUsage = m.usage as { input?: number; output?: number; totalTokens?: number; total?: number } | undefined;\n if (rawUsage && typeof rawUsage === 'object') {\n const inputTokens = typeof rawUsage.input === 'number' ? rawUsage.input : undefined;\n const outputTokens = typeof rawUsage.output === 'number' ? rawUsage.output : undefined;\n const totalTokens = typeof rawUsage.totalTokens === 'number'\n ? rawUsage.totalTokens\n : typeof rawUsage.total === 'number'\n ? rawUsage.total\n : undefined;\n if (inputTokens !== undefined || outputTokens !== undefined || totalTokens !== undefined) {\n row.usage = { inputTokens, outputTokens, totalTokens };\n }\n }\n return row;\n });\n }\n}\n"],"mappings":"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"}
|
|
@@ -23,13 +23,16 @@ export interface Message {
|
|
|
23
23
|
outputTokens?: number;
|
|
24
24
|
totalTokens?: number;
|
|
25
25
|
};
|
|
26
|
-
/**
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
/** Inbound attachment metadata (no base64). */
|
|
27
|
+
media?: Array<{
|
|
28
|
+
id: string;
|
|
29
|
+
bucket: string;
|
|
30
|
+
type: string;
|
|
31
|
+
mimeType: string;
|
|
32
|
+
name: string;
|
|
33
|
+
size: number;
|
|
34
|
+
uri: string;
|
|
35
|
+
path: string;
|
|
33
36
|
}>;
|
|
34
37
|
}
|
|
35
38
|
/** Session status enum */
|
|
@@ -82,6 +85,8 @@ export interface SessionMetadata {
|
|
|
82
85
|
messageCount: number;
|
|
83
86
|
estimatedTokens: number;
|
|
84
87
|
compactedCount: number;
|
|
88
|
+
lastFlushedAt?: string;
|
|
89
|
+
flushCount?: number;
|
|
85
90
|
sourceChannel: string;
|
|
86
91
|
sourceChatId: string;
|
|
87
92
|
customData?: Record<string, unknown>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../src/session/types.ts"],"sourcesContent":["// Session management types\n\nimport type { TranscriptStoredRow } from './session-context-for-llm.js';\n\nexport interface Message {\n role: 'system' | 'user' | 'assistant' | 'tool' | 'toolResult';\n /** Plain string or structured content blocks (tool calls, multimodal). */\n content: string | unknown[];\n timestamp?: string;\n tool_call_id?: string;\n tool_calls?: Array<{\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n }>;\n tool_call_id$?: string;\n toolName?: string;\n isError?: boolean;\n name?: string;\n /** Token usage from the LLM response (assistant messages only). */\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n /**
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../src/session/types.ts"],"sourcesContent":["// Session management types\n\nimport type { TranscriptStoredRow } from './session-context-for-llm.js';\n\nexport interface Message {\n role: 'system' | 'user' | 'assistant' | 'tool' | 'toolResult';\n /** Plain string or structured content blocks (tool calls, multimodal). */\n content: string | unknown[];\n timestamp?: string;\n tool_call_id?: string;\n tool_calls?: Array<{\n id: string;\n type: 'function';\n function: {\n name: string;\n arguments: string;\n };\n }>;\n tool_call_id$?: string;\n toolName?: string;\n isError?: boolean;\n name?: string;\n /** Token usage from the LLM response (assistant messages only). */\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n /** Inbound attachment metadata (no base64). */\n media?: Array<{\n id: string;\n bucket: string;\n type: string;\n mimeType: string;\n name: string;\n size: number;\n uri: string;\n path: string;\n }>;\n}\n\n/** Session status enum */\nexport enum SessionStatus {\n ACTIVE = 'active',\n IDLE = 'idle',\n ARCHIVED = 'archived',\n PINNED = 'pinned',\n}\n\n/** Session routing metadata */\nexport interface SessionRoutingMeta {\n agentId: string;\n source: string;\n accountId: string;\n peerKind: string;\n peerId: string;\n threadId?: string;\n scopeId?: string;\n mainSessionKey?: string;\n lastRoutePolicy?: 'main' | 'session';\n}\n\n/** Session-level statistics (per session) */\nexport interface SessionStats {\n messageCount: number;\n tokenCount: number;\n turnCount?: number;\n lastTurnAt?: number;\n}\n\n/** Global session statistics (aggregate) */\nexport interface GlobalSessionStats {\n totalSessions: number;\n activeSessions: number;\n archivedSessions: number;\n pinnedSessions: number;\n totalMessages: number;\n totalTokens: number;\n oldestSession?: string;\n newestSession?: string;\n byChannel: Record<string, number>;\n}\n\n/** Session metadata (stored in index) */\nexport interface SessionMetadata {\n key: string;\n name?: string;\n status: SessionStatus;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n lastAccessedAt: string;\n messageCount: number;\n estimatedTokens: number;\n compactedCount: number;\n lastFlushedAt?: string;\n flushCount?: number;\n sourceChannel: string;\n sourceChatId: string;\n customData?: Record<string, unknown>;\n /** Routing metadata */\n routing?: SessionRoutingMeta;\n /** Session statistics */\n stats?: SessionStats;\n /**\n * High-level origin for filtering/UI (e.g. `cron`, `heartbeat`, `webchat`).\n * Distinct from `sourceChannel` (routing namespace).\n */\n sessionType?: string;\n /**\n * Stable transcript document id (wrapped on-disk format), aligned with OpenClaw `sessionId`.\n */\n transcriptId?: string;\n /** First activity time for this session row (ISO), from transcript header when available. */\n sessionStartedAt?: string;\n /** Last transcript write / interaction (ISO), updated on each persist. */\n lastInteractionAt?: string;\n /**\n * Epoch ms when the last webchat run was aborted (`POST /api/agent/abort`).\n * Used with `clientCreatedAtMs` on the next POST /api/agent to drop stale queued sends.\n */\n abortCutoffTimestamp?: number;\n}\n\n/** Summary of wrapped transcript (no duplicate message bodies). */\nexport interface SessionTranscriptSummary {\n id: string;\n version: number;\n createdAt: string;\n updatedAt: string;\n compactionCount: number;\n}\n\n/** Session detail (metadata + messages) */\nexport interface SessionDetail extends SessionMetadata {\n messages: Message[];\n /** Present when loaded with `includeTranscriptSummary` (gateway `?include=transcript`). */\n transcriptSummary?: SessionTranscriptSummary;\n /** Present when loaded with `include=transcriptRows` (full on-disk rows, LLM + `kind: 'context'`). */\n transcriptRows?: TranscriptStoredRow[];\n}\n\n/** Session list query parameters */\nexport interface SessionListQuery {\n status?: SessionStatus | SessionStatus[];\n /** Single `sourceChannel`, or comma-separated list (e.g. `telegram,weixin`). */\n channel?: string;\n tags?: string[];\n search?: string;\n sortBy?: 'updatedAt' | 'createdAt' | 'messageCount' | 'lastAccessedAt';\n sortOrder?: 'asc' | 'desc';\n limit?: number;\n offset?: number;\n}\n\n/** Paginated result */\nexport interface PaginatedResult<T> {\n items: T[];\n total: number;\n limit: number;\n offset: number;\n hasMore: boolean;\n}\n\n/** Export format */\nexport type ExportFormat = 'json' | 'markdown';\n\n/** Session export data */\nexport interface SessionExport {\n version: string;\n exportedAt: string;\n metadata: SessionMetadata;\n messages: Message[];\n /** Full on-disk rows (LLM + `kind: 'context'`) for audit / round-trip. */\n transcriptRows: TranscriptStoredRow[];\n}\n\n/** On-disk pre-compaction snapshot (OpenClaw-style checkpoint list). */\nexport interface CompactionCheckpointSummary {\n id: string;\n sizeBytes: number;\n modifiedAt: string;\n}\n\nexport interface CompactionCheckpointDetail extends CompactionCheckpointSummary {\n messageCount: number;\n}\n"],"mappings":";;AA0CA,IAAY,gBAAL,yBAAA,eAAA;AACL,eAAA,YAAA;AACA,eAAA,UAAA;AACA,eAAA,cAAA;AACA,eAAA,YAAA;;KACD"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export { resolveXopcDatabasePath, XOPC_DB_FILENAME } from './paths.js';
|
|
2
|
-
export { XOPC_DB_SCHEMA_VERSION, SCHEMA_META_SCHEMA_VERSION_KEY, ensureXopcDatabaseSchema, readSchemaVersionForTest, } from './schema.js';
|
|
2
|
+
export { XOPC_DB_SCHEMA_VERSION, XOPC_DB_BASELINE_SCHEMA_VERSION, SCHEMA_META_SCHEMA_VERSION_KEY, ensureXopcDatabaseSchema, readSchemaVersionForTest, readSchemaVersion, } from './schema.js';
|
|
3
|
+
export { applyPendingMigrations, inspectSchemaMigrationStatus, resolveMigrationsDir, type SchemaMigrationStatus, } from './migrations/runner.js';
|
|
4
|
+
export { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, } from './migrations/errors.js';
|
|
5
|
+
export { discoverSqlMigrations, listRegisteredMigrationTargets } from './migrations/discover.js';
|
|
3
6
|
export { closeXopcDatabase, getXopcDatabase, isXopcDatabaseOpen, openXopcDatabase, requireXopcDatabase, resetXopcDatabaseSingletonForTest, type OpenXopcDatabaseOptions, type XopcDatabase, } from './connection.js';
|
|
4
7
|
export { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';
|
|
5
8
|
export { buildDefaultSessionMetadata, extractRoutingFromSessionKey, parseSessionKeySource, resolveAgentIdFromSessionKey, } from './session-metadata.js';
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { XOPC_DB_FILENAME, resolveXopcDatabasePath } from "../../config/paths-state.js";
|
|
2
|
-
import { SCHEMA_META_SCHEMA_VERSION_KEY,
|
|
2
|
+
import { SCHEMA_META_SCHEMA_VERSION_KEY, readSchemaVersion, readSchemaVersionForTest } from "./schema-version.js";
|
|
3
|
+
import { discoverSqlMigrations, listRegisteredMigrationTargets } from "./migrations/discover.js";
|
|
4
|
+
import { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError } from "./migrations/errors.js";
|
|
5
|
+
import { XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, applyPendingMigrations, inspectSchemaMigrationStatus, resolveMigrationsDir } from "./migrations/runner.js";
|
|
6
|
+
import { ensureXopcDatabaseSchema } from "./schema.js";
|
|
3
7
|
import { closeXopcDatabase, getXopcDatabase, isXopcDatabaseOpen, openXopcDatabase, requireXopcDatabase, resetXopcDatabaseSingletonForTest } from "./connection.js";
|
|
4
8
|
import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
|
|
5
9
|
import { buildDefaultSessionMetadata, extractRoutingFromSessionKey, parseSessionKeySource, resolveAgentIdFromSessionKey } from "./session-metadata.js";
|
|
@@ -10,4 +14,4 @@ import { appendCronRun, deleteCronRunsForJob, readAllCronRuns, readCronJobHistor
|
|
|
10
14
|
import { deleteNoteRecord, getNoteRecord, listNoteRecords, upsertNoteRecord } from "./notes-repository.js";
|
|
11
15
|
import { resolveAgentIdFromMemoriesDir, searchMemoryIndex, syncMemoryIndex } from "./memory-index-repository.js";
|
|
12
16
|
import { deleteSessionConfig, getSessionConfig, hasSessionConfig, setSessionConfig, updateSessionConfig } from "./config-repository.js";
|
|
13
|
-
export { SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, appendCronRun, appendTranscriptEntry, buildDefaultSessionMetadata, buildGlobalSessionStats, captureCompactionCheckpoint, classifyStoredRow, closeXopcDatabase, deleteCronRunsForJob, deleteNoteRecord, deleteSessionConfig, deleteSessionRecord, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, extractRoutingFromSessionKey, findSessionKeyByTranscriptId, getCompactionCheckpointDetail, getCurrentTranscriptId, getGlobalSessionStats, getNoteRecord, getSessionConfig, getSessionMetadata, getSessionPersistedLevels, getSqliteDatabase, getXopcDatabase, hasSessionConfig, incrementSessionStatsOnAppend, isXopcDatabaseOpen, listCompactionCheckpoints, listNoteRecords, listSessionMetadata, listSessionsByAgent, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptRows, loadTranscriptRowsForSession, metadataToSessionInsert, openXopcDatabase, paginateTranscriptMessages, parseSessionKeySource, patchSessionMetadata, readAllCronRuns, readCronJobHistory, readSchemaVersionForTest, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveAgentIdFromMemoriesDir, resolveAgentIdFromSessionKey, resolveSessionAgentId, resolveXopcDatabasePath, restoreCompactionCheckpoint, runSqliteWriteTransaction, searchMemoryIndex, sessionConfigRowToConfig, sessionRowToMetadata, setSessionConfig, syncMemoryIndex, transcriptEntryRowToStoredRow, updateSessionConfig, updateSessionStats, upsertNoteRecord };
|
|
17
|
+
export { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError, SCHEMA_META_SCHEMA_VERSION_KEY, XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_FILENAME, XOPC_DB_SCHEMA_VERSION, appendCronRun, appendTranscriptEntry, applyPendingMigrations, buildDefaultSessionMetadata, buildGlobalSessionStats, captureCompactionCheckpoint, classifyStoredRow, closeXopcDatabase, deleteCronRunsForJob, deleteNoteRecord, deleteSessionConfig, deleteSessionRecord, discoverSqlMigrations, ensureSessionRecord, ensureXopcDatabaseSchema, estimateTokensFromMessages, extractFtsContent, extractRoutingFromSessionKey, findSessionKeyByTranscriptId, getCompactionCheckpointDetail, getCurrentTranscriptId, getGlobalSessionStats, getNoteRecord, getSessionConfig, getSessionMetadata, getSessionPersistedLevels, getSqliteDatabase, getXopcDatabase, hasSessionConfig, incrementSessionStatsOnAppend, inspectSchemaMigrationStatus, isXopcDatabaseOpen, listCompactionCheckpoints, listNoteRecords, listRegisteredMigrationTargets, listSessionMetadata, listSessionsByAgent, loadCheckpointRows, loadLlmMessagesForSession, loadTranscriptRows, loadTranscriptRowsForSession, metadataToSessionInsert, openXopcDatabase, paginateTranscriptMessages, parseSessionKeySource, patchSessionMetadata, readAllCronRuns, readCronJobHistory, readSchemaVersion, readSchemaVersionForTest, replaceTranscriptRows, requireXopcDatabase, resetSessionRecord, resetXopcDatabaseSingletonForTest, resolveAgentIdFromMemoriesDir, resolveAgentIdFromSessionKey, resolveMigrationsDir, resolveSessionAgentId, resolveXopcDatabasePath, restoreCompactionCheckpoint, runSqliteWriteTransaction, searchMemoryIndex, sessionConfigRowToConfig, sessionRowToMetadata, setSessionConfig, syncMemoryIndex, transcriptEntryRowToStoredRow, updateSessionConfig, updateSessionStats, upsertNoteRecord };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { SqlMigration } from './types.js';
|
|
2
|
+
export declare function discoverSqlMigrations(migrationsDir: string): SqlMigration[];
|
|
3
|
+
export declare function validateMigrationSequence(migrations: SqlMigration[]): void;
|
|
4
|
+
export declare function listRegisteredMigrationTargets(migrationsDir: string): number[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
|
+
//#region src/storage/sqlite/migrations/discover.ts
|
|
4
|
+
/** Matches `002_add_notes_index.sql` → target version 2. */
|
|
5
|
+
const MIGRATION_FILENAME = /^(\d{3})_[\w-]+\.sql$/;
|
|
6
|
+
function discoverSqlMigrations(migrationsDir) {
|
|
7
|
+
if (!existsSync(migrationsDir)) return [];
|
|
8
|
+
const migrations = [];
|
|
9
|
+
for (const entry of readdirSync(migrationsDir, { withFileTypes: true })) {
|
|
10
|
+
if (!entry.isFile()) continue;
|
|
11
|
+
const match = MIGRATION_FILENAME.exec(entry.name);
|
|
12
|
+
if (!match) continue;
|
|
13
|
+
const targetVersion = Number.parseInt(match[1], 10);
|
|
14
|
+
if (!Number.isInteger(targetVersion) || targetVersion < 2) throw new Error(`Invalid SQLite migration filename "${entry.name}" (target version must be >= 2)`);
|
|
15
|
+
migrations.push({
|
|
16
|
+
targetVersion,
|
|
17
|
+
filename: entry.name,
|
|
18
|
+
sql: readFileSync(join(migrationsDir, entry.name), "utf8")
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
migrations.sort((a, b) => a.targetVersion - b.targetVersion);
|
|
22
|
+
validateMigrationSequence(migrations);
|
|
23
|
+
return migrations;
|
|
24
|
+
}
|
|
25
|
+
function validateMigrationSequence(migrations) {
|
|
26
|
+
for (let index = 0; index < migrations.length; index++) {
|
|
27
|
+
const expected = index + 2;
|
|
28
|
+
const actual = migrations[index].targetVersion;
|
|
29
|
+
if (actual !== expected) throw new Error(`SQLite migration sequence gap: expected migration to version ${expected}, found ${migrations[index].filename} (v${actual})`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function listRegisteredMigrationTargets(migrationsDir) {
|
|
33
|
+
return discoverSqlMigrations(migrationsDir).map((migration) => migration.targetVersion);
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
export { discoverSqlMigrations, listRegisteredMigrationTargets, validateMigrationSequence };
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=discover.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discover.js","names":[],"sources":["../../../../../src/storage/sqlite/migrations/discover.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport type { SqlMigration } from './types.js';\n\n/** Matches `002_add_notes_index.sql` → target version 2. */\nconst MIGRATION_FILENAME = /^(\\d{3})_[\\w-]+\\.sql$/;\n\nexport function discoverSqlMigrations(migrationsDir: string): SqlMigration[] {\n if (!existsSync(migrationsDir)) {\n return [];\n }\n\n const migrations: SqlMigration[] = [];\n for (const entry of readdirSync(migrationsDir, { withFileTypes: true })) {\n if (!entry.isFile()) continue;\n const match = MIGRATION_FILENAME.exec(entry.name);\n if (!match) continue;\n const targetVersion = Number.parseInt(match[1]!, 10);\n if (!Number.isInteger(targetVersion) || targetVersion < 2) {\n throw new Error(\n `Invalid SQLite migration filename \"${entry.name}\" (target version must be >= 2)`,\n );\n }\n migrations.push({\n targetVersion,\n filename: entry.name,\n sql: readFileSync(join(migrationsDir, entry.name), 'utf8'),\n });\n }\n\n migrations.sort((a, b) => a.targetVersion - b.targetVersion);\n validateMigrationSequence(migrations);\n return migrations;\n}\n\nexport function validateMigrationSequence(migrations: SqlMigration[]): void {\n for (let index = 0; index < migrations.length; index++) {\n const expected = index + 2;\n const actual = migrations[index]!.targetVersion;\n if (actual !== expected) {\n throw new Error(\n `SQLite migration sequence gap: expected migration to version ${expected}, ` +\n `found ${migrations[index]!.filename} (v${actual})`,\n );\n }\n }\n}\n\nexport function listRegisteredMigrationTargets(migrationsDir: string): number[] {\n return discoverSqlMigrations(migrationsDir).map((migration) => migration.targetVersion);\n}\n"],"mappings":";;;;AAMA,MAAM,qBAAqB;AAE3B,SAAgB,sBAAsB,eAAuC;AAC3E,KAAI,CAAC,WAAW,cAAc,CAC5B,QAAO,EAAE;CAGX,MAAM,aAA6B,EAAE;AACrC,MAAK,MAAM,SAAS,YAAY,eAAe,EAAE,eAAe,MAAM,CAAC,EAAE;AACvE,MAAI,CAAC,MAAM,QAAQ,CAAE;EACrB,MAAM,QAAQ,mBAAmB,KAAK,MAAM,KAAK;AACjD,MAAI,CAAC,MAAO;EACZ,MAAM,gBAAgB,OAAO,SAAS,MAAM,IAAK,GAAG;AACpD,MAAI,CAAC,OAAO,UAAU,cAAc,IAAI,gBAAgB,EACtD,OAAM,IAAI,MACR,sCAAsC,MAAM,KAAK,iCAClD;AAEH,aAAW,KAAK;GACd;GACA,UAAU,MAAM;GAChB,KAAK,aAAa,KAAK,eAAe,MAAM,KAAK,EAAE,OAAO;GAC3D,CAAC;;AAGJ,YAAW,MAAM,GAAG,MAAM,EAAE,gBAAgB,EAAE,cAAc;AAC5D,2BAA0B,WAAW;AACrC,QAAO;;AAGT,SAAgB,0BAA0B,YAAkC;AAC1E,MAAK,IAAI,QAAQ,GAAG,QAAQ,WAAW,QAAQ,SAAS;EACtD,MAAM,WAAW,QAAQ;EACzB,MAAM,SAAS,WAAW,OAAQ;AAClC,MAAI,WAAW,SACb,OAAM,IAAI,MACR,gEAAgE,SAAS,UAC9D,WAAW,OAAQ,SAAS,KAAK,OAAO,GACpD;;;AAKP,SAAgB,+BAA+B,eAAiC;AAC9E,QAAO,sBAAsB,cAAc,CAAC,KAAK,cAAc,UAAU,cAAc"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
import type { SqlMigration } from './types.js';
|
|
5
|
+
|
|
6
|
+
/** Matches `002_add_notes_index.sql` → target version 2. */
|
|
7
|
+
const MIGRATION_FILENAME = /^(\d{3})_[\w-]+\.sql$/;
|
|
8
|
+
|
|
9
|
+
export function discoverSqlMigrations(migrationsDir: string): SqlMigration[] {
|
|
10
|
+
if (!existsSync(migrationsDir)) {
|
|
11
|
+
return [];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const migrations: SqlMigration[] = [];
|
|
15
|
+
for (const entry of readdirSync(migrationsDir, { withFileTypes: true })) {
|
|
16
|
+
if (!entry.isFile()) continue;
|
|
17
|
+
const match = MIGRATION_FILENAME.exec(entry.name);
|
|
18
|
+
if (!match) continue;
|
|
19
|
+
const targetVersion = Number.parseInt(match[1]!, 10);
|
|
20
|
+
if (!Number.isInteger(targetVersion) || targetVersion < 2) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Invalid SQLite migration filename "${entry.name}" (target version must be >= 2)`,
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
migrations.push({
|
|
26
|
+
targetVersion,
|
|
27
|
+
filename: entry.name,
|
|
28
|
+
sql: readFileSync(join(migrationsDir, entry.name), 'utf8'),
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
migrations.sort((a, b) => a.targetVersion - b.targetVersion);
|
|
33
|
+
validateMigrationSequence(migrations);
|
|
34
|
+
return migrations;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function validateMigrationSequence(migrations: SqlMigration[]): void {
|
|
38
|
+
for (let index = 0; index < migrations.length; index++) {
|
|
39
|
+
const expected = index + 2;
|
|
40
|
+
const actual = migrations[index]!.targetVersion;
|
|
41
|
+
if (actual !== expected) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`SQLite migration sequence gap: expected migration to version ${expected}, ` +
|
|
44
|
+
`found ${migrations[index]!.filename} (v${actual})`,
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function listRegisteredMigrationTargets(migrationsDir: string): number[] {
|
|
51
|
+
return discoverSqlMigrations(migrationsDir).map((migration) => migration.targetVersion);
|
|
52
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class DatabaseSchemaTooNewError extends Error {
|
|
2
|
+
readonly dbVersion: number;
|
|
3
|
+
readonly appVersion: number;
|
|
4
|
+
constructor(dbVersion: number, appVersion: number);
|
|
5
|
+
}
|
|
6
|
+
export declare class DatabaseSchemaMigrationGapError extends Error {
|
|
7
|
+
readonly dbVersion: number;
|
|
8
|
+
readonly appVersion: number;
|
|
9
|
+
readonly missingVersion: number;
|
|
10
|
+
constructor(dbVersion: number, appVersion: number, missingVersion: number);
|
|
11
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region src/storage/sqlite/migrations/errors.ts
|
|
2
|
+
var DatabaseSchemaTooNewError = class extends Error {
|
|
3
|
+
dbVersion;
|
|
4
|
+
appVersion;
|
|
5
|
+
constructor(dbVersion, appVersion) {
|
|
6
|
+
super(`xopc database schema version ${dbVersion} is newer than this app supports (${appVersion}). Upgrade xopc to a newer release or restore xopc.db from backup.`);
|
|
7
|
+
this.name = "DatabaseSchemaTooNewError";
|
|
8
|
+
this.dbVersion = dbVersion;
|
|
9
|
+
this.appVersion = appVersion;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var DatabaseSchemaMigrationGapError = class extends Error {
|
|
13
|
+
dbVersion;
|
|
14
|
+
appVersion;
|
|
15
|
+
missingVersion;
|
|
16
|
+
constructor(dbVersion, appVersion, missingVersion) {
|
|
17
|
+
super(`xopc database schema version ${dbVersion} requires migration to v${missingVersion}, but no migration file is bundled with this app (supports up to v${appVersion}). Upgrade xopc to a release that includes the missing migration.`);
|
|
18
|
+
this.name = "DatabaseSchemaMigrationGapError";
|
|
19
|
+
this.dbVersion = dbVersion;
|
|
20
|
+
this.appVersion = appVersion;
|
|
21
|
+
this.missingVersion = missingVersion;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
//#endregion
|
|
25
|
+
export { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError };
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../../../../../src/storage/sqlite/migrations/errors.ts"],"sourcesContent":["export class DatabaseSchemaTooNewError extends Error {\n readonly dbVersion: number;\n readonly appVersion: number;\n\n constructor(dbVersion: number, appVersion: number) {\n super(\n `xopc database schema version ${dbVersion} is newer than this app supports (${appVersion}). ` +\n 'Upgrade xopc to a newer release or restore xopc.db from backup.',\n );\n this.name = 'DatabaseSchemaTooNewError';\n this.dbVersion = dbVersion;\n this.appVersion = appVersion;\n }\n}\n\nexport class DatabaseSchemaMigrationGapError extends Error {\n readonly dbVersion: number;\n readonly appVersion: number;\n readonly missingVersion: number;\n\n constructor(dbVersion: number, appVersion: number, missingVersion: number) {\n super(\n `xopc database schema version ${dbVersion} requires migration to v${missingVersion}, ` +\n `but no migration file is bundled with this app (supports up to v${appVersion}). ` +\n 'Upgrade xopc to a release that includes the missing migration.',\n );\n this.name = 'DatabaseSchemaMigrationGapError';\n this.dbVersion = dbVersion;\n this.appVersion = appVersion;\n this.missingVersion = missingVersion;\n }\n}\n"],"mappings":";AAAA,IAAa,4BAAb,cAA+C,MAAM;CACnD;CACA;CAEA,YAAY,WAAmB,YAAoB;AACjD,QACE,gCAAgC,UAAU,oCAAoC,WAAW,oEAE1F;AACD,OAAK,OAAO;AACZ,OAAK,YAAY;AACjB,OAAK,aAAa;;;AAItB,IAAa,kCAAb,cAAqD,MAAM;CACzD;CACA;CACA;CAEA,YAAY,WAAmB,YAAoB,gBAAwB;AACzE,QACE,gCAAgC,UAAU,0BAA0B,eAAe,oEACd,WAAW,mEAEjF;AACD,OAAK,OAAO;AACZ,OAAK,YAAY;AACjB,OAAK,aAAa;AAClB,OAAK,iBAAiB"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export class DatabaseSchemaTooNewError extends Error {
|
|
2
|
+
readonly dbVersion: number;
|
|
3
|
+
readonly appVersion: number;
|
|
4
|
+
|
|
5
|
+
constructor(dbVersion: number, appVersion: number) {
|
|
6
|
+
super(
|
|
7
|
+
`xopc database schema version ${dbVersion} is newer than this app supports (${appVersion}). ` +
|
|
8
|
+
'Upgrade xopc to a newer release or restore xopc.db from backup.',
|
|
9
|
+
);
|
|
10
|
+
this.name = 'DatabaseSchemaTooNewError';
|
|
11
|
+
this.dbVersion = dbVersion;
|
|
12
|
+
this.appVersion = appVersion;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export class DatabaseSchemaMigrationGapError extends Error {
|
|
17
|
+
readonly dbVersion: number;
|
|
18
|
+
readonly appVersion: number;
|
|
19
|
+
readonly missingVersion: number;
|
|
20
|
+
|
|
21
|
+
constructor(dbVersion: number, appVersion: number, missingVersion: number) {
|
|
22
|
+
super(
|
|
23
|
+
`xopc database schema version ${dbVersion} requires migration to v${missingVersion}, ` +
|
|
24
|
+
`but no migration file is bundled with this app (supports up to v${appVersion}). ` +
|
|
25
|
+
'Upgrade xopc to a release that includes the missing migration.',
|
|
26
|
+
);
|
|
27
|
+
this.name = 'DatabaseSchemaMigrationGapError';
|
|
28
|
+
this.dbVersion = dbVersion;
|
|
29
|
+
this.appVersion = appVersion;
|
|
30
|
+
this.missingVersion = missingVersion;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { DatabaseSync } from 'node:sqlite';
|
|
2
|
+
import type { ApplyMigrationsOptions } from './types.js';
|
|
3
|
+
/** Baseline schema version applied from schema.sql on first open. */
|
|
4
|
+
export declare const XOPC_DB_BASELINE_SCHEMA_VERSION = 2;
|
|
5
|
+
/** Latest schema version this release supports (increment when adding migrations). */
|
|
6
|
+
export declare const XOPC_DB_SCHEMA_VERSION = 2;
|
|
7
|
+
export declare function resolveMigrationsDir(override?: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
|
|
10
|
+
* Each step runs in its own transaction and updates schema_meta on success.
|
|
11
|
+
*/
|
|
12
|
+
export declare function applyPendingMigrations(db: DatabaseSync, options?: ApplyMigrationsOptions): number;
|
|
13
|
+
export type SchemaMigrationStatus = {
|
|
14
|
+
dbVersion: number;
|
|
15
|
+
appVersion: number;
|
|
16
|
+
pendingVersions: number[];
|
|
17
|
+
isTooNew: boolean;
|
|
18
|
+
hasMigrationGap: boolean;
|
|
19
|
+
missingVersion: number | null;
|
|
20
|
+
};
|
|
21
|
+
/** Inspect schema version without mutating the database. */
|
|
22
|
+
export declare function inspectSchemaMigrationStatus(db: DatabaseSync, options?: Pick<ApplyMigrationsOptions, 'migrationsDir' | 'targetVersion'>): SchemaMigrationStatus;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { createLogger } from "../../../utils/logger/index.js";
|
|
2
|
+
import { init_logger } from "../../../utils/logger.js";
|
|
3
|
+
import { readSchemaVersion, setSchemaVersion } from "../schema-version.js";
|
|
4
|
+
import { discoverSqlMigrations } from "./discover.js";
|
|
5
|
+
import { DatabaseSchemaMigrationGapError, DatabaseSchemaTooNewError } from "./errors.js";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
//#region src/storage/sqlite/migrations/runner.ts
|
|
10
|
+
init_logger();
|
|
11
|
+
const log = createLogger("Sqlite:Migrations");
|
|
12
|
+
/** Baseline schema version applied from schema.sql on first open. */
|
|
13
|
+
const XOPC_DB_BASELINE_SCHEMA_VERSION = 2;
|
|
14
|
+
/** Latest schema version this release supports (increment when adding migrations). */
|
|
15
|
+
const XOPC_DB_SCHEMA_VERSION = 2;
|
|
16
|
+
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
function resolveMigrationsDir(override) {
|
|
18
|
+
if (override) return override;
|
|
19
|
+
const siblingDir = join(MODULE_DIR, "migrations");
|
|
20
|
+
if (existsSync(siblingDir)) return siblingDir;
|
|
21
|
+
return MODULE_DIR;
|
|
22
|
+
}
|
|
23
|
+
function migrationByTarget(migrations, targetVersion) {
|
|
24
|
+
return migrations.find((migration) => migration.targetVersion === targetVersion);
|
|
25
|
+
}
|
|
26
|
+
function applySingleMigration(db, migration) {
|
|
27
|
+
log.info({
|
|
28
|
+
targetVersion: migration.targetVersion,
|
|
29
|
+
file: migration.filename
|
|
30
|
+
}, "Applying SQLite migration");
|
|
31
|
+
db.exec("BEGIN IMMEDIATE");
|
|
32
|
+
try {
|
|
33
|
+
db.exec(migration.sql);
|
|
34
|
+
setSchemaVersion(db, migration.targetVersion);
|
|
35
|
+
db.exec("COMMIT");
|
|
36
|
+
} catch (error) {
|
|
37
|
+
try {
|
|
38
|
+
db.exec("ROLLBACK");
|
|
39
|
+
} catch {}
|
|
40
|
+
const em = error instanceof Error ? error.message : String(error);
|
|
41
|
+
throw new Error(`SQLite migration to v${migration.targetVersion} (${migration.filename}) failed: ${em}`, { cause: error });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.
|
|
46
|
+
* Each step runs in its own transaction and updates schema_meta on success.
|
|
47
|
+
*/
|
|
48
|
+
function applyPendingMigrations(db, options = {}) {
|
|
49
|
+
const targetVersion = options.targetVersion ?? 2;
|
|
50
|
+
let currentVersion = readSchemaVersion(db);
|
|
51
|
+
if (currentVersion > targetVersion) throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);
|
|
52
|
+
if (currentVersion >= targetVersion) return currentVersion;
|
|
53
|
+
const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));
|
|
54
|
+
while (currentVersion < targetVersion) {
|
|
55
|
+
const nextVersion = currentVersion + 1;
|
|
56
|
+
const migration = migrationByTarget(migrations, nextVersion);
|
|
57
|
+
if (!migration) throw new DatabaseSchemaMigrationGapError(currentVersion, targetVersion, nextVersion);
|
|
58
|
+
applySingleMigration(db, migration);
|
|
59
|
+
currentVersion = nextVersion;
|
|
60
|
+
}
|
|
61
|
+
return currentVersion;
|
|
62
|
+
}
|
|
63
|
+
/** Inspect schema version without mutating the database. */
|
|
64
|
+
function inspectSchemaMigrationStatus(db, options = {}) {
|
|
65
|
+
const appVersion = options.targetVersion ?? 2;
|
|
66
|
+
const dbVersion = readSchemaVersion(db);
|
|
67
|
+
if (dbVersion > appVersion) return {
|
|
68
|
+
dbVersion,
|
|
69
|
+
appVersion,
|
|
70
|
+
pendingVersions: [],
|
|
71
|
+
isTooNew: true,
|
|
72
|
+
hasMigrationGap: false,
|
|
73
|
+
missingVersion: null
|
|
74
|
+
};
|
|
75
|
+
const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));
|
|
76
|
+
const pendingVersions = [];
|
|
77
|
+
let hasMigrationGap = false;
|
|
78
|
+
let missingVersion = null;
|
|
79
|
+
for (let version = dbVersion + 1; version <= appVersion; version++) if (migrationByTarget(migrations, version)) pendingVersions.push(version);
|
|
80
|
+
else {
|
|
81
|
+
hasMigrationGap = true;
|
|
82
|
+
missingVersion = version;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
dbVersion,
|
|
87
|
+
appVersion,
|
|
88
|
+
pendingVersions,
|
|
89
|
+
isTooNew: false,
|
|
90
|
+
hasMigrationGap,
|
|
91
|
+
missingVersion
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { XOPC_DB_BASELINE_SCHEMA_VERSION, XOPC_DB_SCHEMA_VERSION, applyPendingMigrations, inspectSchemaMigrationStatus, resolveMigrationsDir };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","names":[],"sources":["../../../../../src/storage/sqlite/migrations/runner.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport type { DatabaseSync } from 'node:sqlite';\n\nimport { createLogger } from '../../../utils/logger.js';\nimport { readSchemaVersion, setSchemaVersion } from '../schema-version.js';\nimport { discoverSqlMigrations } from './discover.js';\nimport {\n DatabaseSchemaMigrationGapError,\n DatabaseSchemaTooNewError,\n} from './errors.js';\nimport type { ApplyMigrationsOptions, SqlMigration } from './types.js';\n\nconst log = createLogger('Sqlite:Migrations');\n\n/** Baseline schema version applied from schema.sql on first open. */\nexport const XOPC_DB_BASELINE_SCHEMA_VERSION = 2;\n\n/** Latest schema version this release supports (increment when adding migrations). */\nexport const XOPC_DB_SCHEMA_VERSION = 2;\n\nconst MODULE_DIR = dirname(fileURLToPath(import.meta.url));\n\nexport function resolveMigrationsDir(override?: string): string {\n if (override) {\n return override;\n }\n // Packaged Electron gateway bundle: `out/server/index.js` + `out/server/migrations/`.\n const siblingDir = join(MODULE_DIR, 'migrations');\n if (existsSync(siblingDir)) {\n return siblingDir;\n }\n // Dev / dist: SQL files live next to `migrations/runner.js`.\n return MODULE_DIR;\n}\n\nfunction migrationByTarget(\n migrations: SqlMigration[],\n targetVersion: number,\n): SqlMigration | undefined {\n return migrations.find((migration) => migration.targetVersion === targetVersion);\n}\n\nfunction applySingleMigration(db: DatabaseSync, migration: SqlMigration): void {\n log.info({ targetVersion: migration.targetVersion, file: migration.filename }, 'Applying SQLite migration');\n db.exec('BEGIN IMMEDIATE');\n try {\n db.exec(migration.sql);\n setSchemaVersion(db, migration.targetVersion);\n db.exec('COMMIT');\n } catch (error) {\n try {\n db.exec('ROLLBACK');\n } catch {\n /* preserve original error */\n }\n const em = error instanceof Error ? error.message : String(error);\n throw new Error(\n `SQLite migration to v${migration.targetVersion} (${migration.filename}) failed: ${em}`,\n { cause: error },\n );\n }\n}\n\n/**\n * Apply sequential SQL migrations from (currentVersion + 1) through targetVersion.\n * Each step runs in its own transaction and updates schema_meta on success.\n */\nexport function applyPendingMigrations(\n db: DatabaseSync,\n options: ApplyMigrationsOptions = {},\n): number {\n const targetVersion = options.targetVersion ?? XOPC_DB_SCHEMA_VERSION;\n let currentVersion = readSchemaVersion(db);\n\n if (currentVersion > targetVersion) {\n throw new DatabaseSchemaTooNewError(currentVersion, targetVersion);\n }\n\n if (currentVersion >= targetVersion) {\n return currentVersion;\n }\n\n const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));\n\n while (currentVersion < targetVersion) {\n const nextVersion = currentVersion + 1;\n const migration = migrationByTarget(migrations, nextVersion);\n if (!migration) {\n throw new DatabaseSchemaMigrationGapError(currentVersion, targetVersion, nextVersion);\n }\n applySingleMigration(db, migration);\n currentVersion = nextVersion;\n }\n\n return currentVersion;\n}\n\nexport type SchemaMigrationStatus = {\n dbVersion: number;\n appVersion: number;\n pendingVersions: number[];\n isTooNew: boolean;\n hasMigrationGap: boolean;\n missingVersion: number | null;\n};\n\n/** Inspect schema version without mutating the database. */\nexport function inspectSchemaMigrationStatus(\n db: DatabaseSync,\n options: Pick<ApplyMigrationsOptions, 'migrationsDir' | 'targetVersion'> = {},\n): SchemaMigrationStatus {\n const appVersion = options.targetVersion ?? XOPC_DB_SCHEMA_VERSION;\n const dbVersion = readSchemaVersion(db);\n const isTooNew = dbVersion > appVersion;\n\n if (isTooNew) {\n return {\n dbVersion,\n appVersion,\n pendingVersions: [],\n isTooNew: true,\n hasMigrationGap: false,\n missingVersion: null,\n };\n }\n\n const migrations = discoverSqlMigrations(resolveMigrationsDir(options.migrationsDir));\n const pendingVersions: number[] = [];\n let hasMigrationGap = false;\n let missingVersion: number | null = null;\n\n for (let version = dbVersion + 1; version <= appVersion; version++) {\n if (migrationByTarget(migrations, version)) {\n pendingVersions.push(version);\n } else {\n hasMigrationGap = true;\n missingVersion = version;\n break;\n }\n }\n\n return {\n dbVersion,\n appVersion,\n pendingVersions,\n isTooNew: false,\n hasMigrationGap,\n missingVersion,\n };\n}\n"],"mappings":";;;;;;;;;aAMwD;AASxD,MAAM,MAAM,aAAa,oBAAoB;;AAG7C,MAAa,kCAAkC;;AAG/C,MAAa,yBAAyB;AAEtC,MAAM,aAAa,QAAQ,cAAc,OAAO,KAAK,IAAI,CAAC;AAE1D,SAAgB,qBAAqB,UAA2B;AAC9D,KAAI,SACF,QAAO;CAGT,MAAM,aAAa,KAAK,YAAY,aAAa;AACjD,KAAI,WAAW,WAAW,CACxB,QAAO;AAGT,QAAO;;AAGT,SAAS,kBACP,YACA,eAC0B;AAC1B,QAAO,WAAW,MAAM,cAAc,UAAU,kBAAkB,cAAc;;AAGlF,SAAS,qBAAqB,IAAkB,WAA+B;AAC7E,KAAI,KAAK;EAAE,eAAe,UAAU;EAAe,MAAM,UAAU;EAAU,EAAE,4BAA4B;AAC3G,IAAG,KAAK,kBAAkB;AAC1B,KAAI;AACF,KAAG,KAAK,UAAU,IAAI;AACtB,mBAAiB,IAAI,UAAU,cAAc;AAC7C,KAAG,KAAK,SAAS;UACV,OAAO;AACd,MAAI;AACF,MAAG,KAAK,WAAW;UACb;EAGR,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACjE,QAAM,IAAI,MACR,wBAAwB,UAAU,cAAc,IAAI,UAAU,SAAS,YAAY,MACnF,EAAE,OAAO,OAAO,CACjB;;;;;;;AAQL,SAAgB,uBACd,IACA,UAAkC,EAAE,EAC5B;CACR,MAAM,gBAAgB,QAAQ,iBAAA;CAC9B,IAAI,iBAAiB,kBAAkB,GAAG;AAE1C,KAAI,iBAAiB,cACnB,OAAM,IAAI,0BAA0B,gBAAgB,cAAc;AAGpE,KAAI,kBAAkB,cACpB,QAAO;CAGT,MAAM,aAAa,sBAAsB,qBAAqB,QAAQ,cAAc,CAAC;AAErF,QAAO,iBAAiB,eAAe;EACrC,MAAM,cAAc,iBAAiB;EACrC,MAAM,YAAY,kBAAkB,YAAY,YAAY;AAC5D,MAAI,CAAC,UACH,OAAM,IAAI,gCAAgC,gBAAgB,eAAe,YAAY;AAEvF,uBAAqB,IAAI,UAAU;AACnC,mBAAiB;;AAGnB,QAAO;;;AAaT,SAAgB,6BACd,IACA,UAA2E,EAAE,EACtD;CACvB,MAAM,aAAa,QAAQ,iBAAA;CAC3B,MAAM,YAAY,kBAAkB,GAAG;AAGvC,KAFiB,YAAY,WAG3B,QAAO;EACL;EACA;EACA,iBAAiB,EAAE;EACnB,UAAU;EACV,iBAAiB;EACjB,gBAAgB;EACjB;CAGH,MAAM,aAAa,sBAAsB,qBAAqB,QAAQ,cAAc,CAAC;CACrF,MAAM,kBAA4B,EAAE;CACpC,IAAI,kBAAkB;CACtB,IAAI,iBAAgC;AAEpC,MAAK,IAAI,UAAU,YAAY,GAAG,WAAW,YAAY,UACvD,KAAI,kBAAkB,YAAY,QAAQ,CACxC,iBAAgB,KAAK,QAAQ;MACxB;AACL,oBAAkB;AAClB,mBAAiB;AACjB;;AAIJ,QAAO;EACL;EACA;EACA;EACA,UAAU;EACV;EACA;EACD"}
|