@xopcai/xopc 0.0.95 → 0.0.97
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/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +2 -2
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/api/api.js +2 -2
- package/dist/extensions/weixin/src/auth/accounts.js +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/gateway/static/root/assets/{agents-CKe2LMnz.js → agents-B_YUvNi6.js} +2 -2
- package/dist/gateway/static/root/assets/{apps-page-Mi9mMIZ1.js → apps-page-BmwG5aur.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-BrdyC101.js → channels-settings-BiwkeKPb.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-status-swr-D55Bu0nn.js → channels-status-swr-ChyN473C.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-api-CPpx2l-E.js → cron-api-CvSifIfJ.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-Bx2jB0YN.js → cron-page-BDqTDFy6.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-D_AiG_Kg.js → dist-DxsUrjpy.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-6ieHsxRE.js → extension-debug-page-DV_Av5Jq.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-B8nywHRO.js → extension-page-CwZwRhWw.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DrskdEIV.js → extension-settings-page-Bb7TR1Se.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B0aeeY0q.js → fetch-BLLOP2CM.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives--9ooY8Xl.js → field-primitives-CyqVu1QR.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-DUZ_W1w-.js → heartbeat-config-api-Cd4M1eHt.js} +1 -1
- package/dist/gateway/static/root/assets/{index-Dj9FuxCm.js → index-0tS9lV85.js} +74 -74
- package/dist/gateway/static/root/assets/index-BJDmBCSl.css +1 -0
- package/dist/gateway/static/root/assets/{logs-page-CaXqhpKf.js → logs-page-BsAOSowN.js} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-page-B91pLkEI.css → note-detail-page-D4ZIVQbk.css} +1 -1
- package/dist/gateway/static/root/assets/{note-detail-page-DYzym2B0.js → note-detail-page-Dlxoy6Ap.js} +54 -53
- package/dist/gateway/static/root/assets/{note-time-B-vSi2dR.js → note-time-B-r8yTpQ.js} +1 -1
- package/dist/gateway/static/root/assets/{notes-page-BkhWdGiT.js → notes-page-CHFcyqYW.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-53YFokoe.js → sessions-page-Ctu0kgt7.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-advanced-gate-BaZmaklx.js → settings-advanced-gate-Dh0TyOOg.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-DIJPKpTR.js → settings-form-section-DXMCEW1d.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-Dvb230FF.js → settings-page-CIkZ7233.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-CRyjTAG6.js → share-preview-page-7RV65xhJ.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-C5ZJbfAe.js → skills-page-D_Az1SlU.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-Cg_SuBw0.js → theme-store-e2q2yjs4.js} +1 -1
- package/dist/gateway/static/root/assets/url-DpFBIyN9.js +3 -0
- package/dist/gateway/static/root/assets/{utils-lMYoWhqo.js → utils-OA_b1q0Q.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-Dda2pcUU.js → voice-api-key-field-SJml1hAt.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-page.utils-KIladUrU.js → workflow-page.utils-D90VVCzC.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-BTis4Z7Y.js → workflows-page-y7Btji0J.js} +1 -1
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +12 -8
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.d.ts +0 -1
- package/dist/src/agent/agent-scope.js +2 -5
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +2 -0
- package/dist/src/agent/bootstrap/bootstrap-cache.js +10 -1
- package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-files.d.ts +2 -1
- package/dist/src/agent/bootstrap/bootstrap-files.js +34 -12
- package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +1 -2
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +6 -12
- package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/types.d.ts +5 -5
- package/dist/src/agent/context/workspace-seed.js +6 -6
- package/dist/src/agent/context/workspace-seed.js.map +1 -1
- package/dist/src/agent/context/workspace-state.d.ts +20 -0
- package/dist/src/agent/context/workspace-state.js +57 -0
- package/dist/src/agent/context/workspace-state.js.map +1 -0
- package/dist/src/agent/context/workspace-templates/AGENTS.md +0 -4
- package/dist/src/agent/embedded/index.d.ts +2 -2
- package/dist/src/agent/embedded/index.js +3 -3
- package/dist/src/agent/embedded/run-turn.js +0 -3
- package/dist/src/agent/embedded/run-turn.js.map +1 -1
- package/dist/src/agent/embedded/session-manager-init.d.ts +0 -17
- package/dist/src/agent/embedded/session-manager-init.js +1 -36
- package/dist/src/agent/embedded/session-manager-init.js.map +1 -1
- package/dist/src/agent/embedded/session-runner.d.ts +3 -12
- package/dist/src/agent/embedded/session-runner.js +12 -26
- package/dist/src/agent/embedded/session-runner.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js +2 -4
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/embedded/sqlite-hydrating-session-manager.d.ts +10 -0
- package/dist/src/agent/embedded/sqlite-hydrating-session-manager.js +34 -0
- package/dist/src/agent/embedded/sqlite-hydrating-session-manager.js.map +1 -0
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-service.js +8 -15
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -2
- package/dist/src/agent/mcp/mcp-transport-config.js +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/prompt/memory/index.d.ts +1 -0
- package/dist/src/agent/prompt/memory/index.js +34 -80
- package/dist/src/agent/prompt/memory/index.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/prompt/system-prompt.js +0 -1
- package/dist/src/agent/prompt/system-prompt.js.map +1 -1
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/build-direct-message-content.js +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js +8 -17
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +14 -23
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.js +7 -11
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +3 -3
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +1 -1
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/index.d.ts +0 -1
- package/dist/src/agent/tools/index.js +1 -2
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/session-search-tool.d.ts +0 -1
- package/dist/src/agent/tools/session-search-tool.js +11 -6
- package/dist/src/agent/tools/session-search-tool.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/tool-paths.js +1 -3
- package/dist/src/agent/tools/tool-paths.js.map +1 -1
- package/dist/src/agent/tools/workflow-tool.js +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/auth/credentials.js +3 -3
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/providers/browser-ext-install.js +4 -4
- package/dist/src/browser/providers/cloakbrowser.js +4 -4
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +1 -1
- package/dist/src/channels/pairing/pairing-store.js +2 -2
- package/dist/src/chat-commands/agent-edit.js +3 -4
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/context.js +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +32 -95
- package/dist/src/cli/commands/doctor/checks/session-integrity.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/logs.js +1 -1
- package/dist/src/cli/commands/image.js +1 -1
- package/dist/src/cli/commands/init.js +5 -7
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +0 -8
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/templates.d.ts +3 -10
- package/dist/src/cli/templates.js +4 -32
- package/dist/src/cli/templates.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +7 -8
- package/dist/src/config/index.js.map +1 -1
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.d.ts +3 -0
- package/dist/src/config/paths-state.js +7 -3
- package/dist/src/config/paths-state.js.map +1 -1
- package/dist/src/config/paths.d.ts +5 -36
- package/dist/src/config/paths.js +7 -52
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/schema.d.ts +15 -0
- package/dist/src/config/schema.js +11 -0
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/execution-types.d.ts +42 -0
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.d.ts +4 -8
- package/dist/src/cron/run-log-store.js +26 -78
- package/dist/src/cron/run-log-store.js.map +1 -1
- package/dist/src/cron/service.d.ts +3 -3
- package/dist/src/cron/service.js +2 -2
- package/dist/src/cron/service.js.map +1 -1
- package/dist/src/cron/types.d.ts +1 -42
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +2 -2
- package/dist/src/daemon/launchd.js +2 -2
- package/dist/src/daemon/schtasks.js +2 -2
- package/dist/src/daemon/systemd.js +2 -2
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/update.js +1 -1
- package/dist/src/gateway/agents-admin.js +4 -4
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/file-path-classifier.d.ts +0 -1
- package/dist/src/gateway/file-path-classifier.js +2 -8
- package/dist/src/gateway/file-path-classifier.js.map +1 -1
- package/dist/src/gateway/heartbeat/service.js +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +1 -1
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/hono/routes/shares.js +1 -1
- package/dist/src/gateway/hono/routes/workspace.js +2 -2
- package/dist/src/gateway/lock.js +3 -3
- package/dist/src/gateway/ports.js +1 -1
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service.js +5 -1
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/session-reset-service.d.ts +1 -1
- package/dist/src/gateway/session-reset-service.js +1 -1
- package/dist/src/gateway/session-reset-service.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/brew.js +1 -1
- package/dist/src/infra/node-sqlite.d.ts +1 -0
- package/dist/src/infra/node-sqlite.js +17 -0
- package/dist/src/infra/node-sqlite.js.map +1 -0
- package/dist/src/infra/package-json.js +1 -1
- package/dist/src/infra/package-update-steps.js +1 -1
- package/dist/src/infra/path-env.js +2 -2
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/sqlite-errors.d.ts +1 -0
- package/dist/src/infra/sqlite-errors.js +77 -0
- package/dist/src/infra/sqlite-errors.js.map +1 -0
- package/dist/src/infra/stable-node-path.js +1 -1
- package/dist/src/infra/unhandled-rejections.d.ts +1 -0
- package/dist/src/infra/unhandled-rejections.js +25 -0
- package/dist/src/infra/unhandled-rejections.js.map +1 -0
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.js +1 -1
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/warning-filter.d.ts +7 -0
- package/dist/src/infra/warning-filter.js +59 -0
- package/dist/src/infra/warning-filter.js.map +1 -0
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/notes/store.d.ts +3 -9
- package/dist/src/notes/store.js +22 -196
- package/dist/src/notes/store.js.map +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +1 -1
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/session/config-store.d.ts +6 -75
- package/dist/src/session/config-store.js +38 -144
- package/dist/src/session/config-store.js.map +1 -1
- package/dist/src/session/config-types.d.ts +15 -0
- package/dist/src/session/config-types.js +1 -0
- package/dist/src/session/index.d.ts +1 -3
- package/dist/src/session/index.js +3 -5
- package/dist/src/session/init-session-turn.d.ts +0 -6
- package/dist/src/session/init-session-turn.js +18 -18
- package/dist/src/session/init-session-turn.js.map +1 -1
- package/dist/src/session/lifecycle-timestamps.d.ts +5 -2
- package/dist/src/session/lifecycle-timestamps.js.map +1 -1
- package/dist/src/session/{parity/load-jsonl-entries.js → load-jsonl-entries.js} +1 -1
- package/dist/src/session/load-jsonl-entries.js.map +1 -0
- package/dist/src/session/manager.d.ts +5 -3
- package/dist/src/session/manager.js +1 -5
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/resolve-session.d.ts +3 -6
- package/dist/src/session/resolve-session.js +26 -31
- package/dist/src/session/resolve-session.js.map +1 -1
- package/dist/src/session/session-context-for-llm.js +5 -1
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/session/session-id.js +12 -0
- package/dist/src/session/session-id.js.map +1 -0
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/session-workspace.d.ts +1 -1
- package/dist/src/session/session-workspace.js.map +1 -1
- package/dist/src/session/store.d.ts +14 -63
- package/dist/src/session/store.js +172 -847
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/stored-rows-to-file-entries.d.ts +11 -0
- package/dist/src/session/stored-rows-to-file-entries.js +95 -0
- package/dist/src/session/stored-rows-to-file-entries.js.map +1 -0
- package/dist/src/session/transcript-events.d.ts +1 -2
- package/dist/src/session/transcript-events.js +5 -12
- package/dist/src/session/transcript-events.js.map +1 -1
- package/dist/src/session/transcript-format.d.ts +1 -1
- package/dist/src/session/transcript-format.js.map +1 -1
- package/dist/src/session/transcript-stats.d.ts +1 -0
- package/dist/src/session/transcript-stats.js +10 -0
- package/dist/src/session/transcript-stats.js.map +1 -0
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/storage/sqlite/config-repository.d.ts +6 -0
- package/dist/src/storage/sqlite/config-repository.js +56 -0
- package/dist/src/storage/sqlite/config-repository.js.map +1 -0
- package/dist/src/storage/sqlite/connection.d.ts +38 -0
- package/dist/src/storage/sqlite/connection.js +258 -0
- package/dist/src/storage/sqlite/connection.js.map +1 -0
- package/dist/src/storage/sqlite/cron-run-repository.d.ts +5 -0
- package/dist/src/storage/sqlite/cron-run-repository.js +97 -0
- package/dist/src/storage/sqlite/cron-run-repository.js.map +1 -0
- package/dist/src/storage/sqlite/fts.d.ts +2 -0
- package/dist/src/storage/sqlite/fts.js +11 -0
- package/dist/src/storage/sqlite/fts.js.map +1 -0
- package/dist/src/storage/sqlite/index.d.ts +12 -0
- package/dist/src/storage/sqlite/index.js +13 -0
- package/dist/src/storage/sqlite/memory-index-repository.d.ts +18 -0
- package/dist/src/storage/sqlite/memory-index-repository.js +132 -0
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -0
- package/dist/src/storage/sqlite/notes-repository.d.ts +11 -0
- package/dist/src/storage/sqlite/notes-repository.js +191 -0
- package/dist/src/storage/sqlite/notes-repository.js.map +1 -0
- package/dist/src/storage/sqlite/paths.d.ts +1 -0
- package/dist/src/storage/sqlite/paths.js +7 -0
- package/dist/src/storage/sqlite/paths.js.map +1 -0
- package/dist/src/storage/sqlite/row-mappers.d.ts +82 -0
- package/dist/src/storage/sqlite/row-mappers.js +164 -0
- package/dist/src/storage/sqlite/row-mappers.js.map +1 -0
- package/dist/src/storage/sqlite/schema.d.ts +5 -0
- package/dist/src/storage/sqlite/schema.js +43 -0
- package/dist/src/storage/sqlite/schema.js.map +1 -0
- package/dist/src/storage/sqlite/schema.sql +195 -0
- package/dist/src/storage/sqlite/session-metadata.d.ts +8 -0
- package/dist/src/storage/sqlite/session-metadata.js +83 -0
- package/dist/src/storage/sqlite/session-metadata.js.map +1 -0
- package/dist/src/storage/sqlite/session-repository.d.ts +29 -0
- package/dist/src/storage/sqlite/session-repository.js +268 -0
- package/dist/src/storage/sqlite/session-repository.js.map +1 -0
- package/dist/src/storage/sqlite/transaction.d.ts +11 -0
- package/dist/src/storage/sqlite/transaction.js +115 -0
- package/dist/src/storage/sqlite/transaction.js.map +1 -0
- package/dist/src/storage/sqlite/transcript-repository.d.ts +34 -0
- package/dist/src/storage/sqlite/transcript-repository.js +241 -0
- package/dist/src/storage/sqlite/transcript-repository.js.map +1 -0
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/tui-keybindings-file.js +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui.js +3 -3
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/workflows/service/workflow-session-bridge.js +41 -64
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/dist/src/workflows/store/event-store.js +1 -1
- package/dist/src/workflows/store/run-store.js +1 -1
- package/package.json +2 -2
- package/dist/gateway/static/root/assets/index-Bj_l8QDp.css +0 -1
- package/dist/gateway/static/root/assets/url-BHHmdJYc.js +0 -3
- package/dist/src/agent/context/workspace-templates/BOOTSTRAP.md +0 -61
- package/dist/src/agent/embedded/session-manager-cache.d.ts +0 -19
- package/dist/src/agent/embedded/session-manager-cache.js +0 -48
- package/dist/src/agent/embedded/session-manager-cache.js.map +0 -1
- package/dist/src/session/parity/artifacts.d.ts +0 -16
- package/dist/src/session/parity/artifacts.js +0 -80
- package/dist/src/session/parity/artifacts.js.map +0 -1
- package/dist/src/session/parity/jsonl-transcript-io.d.ts +0 -54
- package/dist/src/session/parity/jsonl-transcript-io.js +0 -236
- package/dist/src/session/parity/jsonl-transcript-io.js.map +0 -1
- package/dist/src/session/parity/load-jsonl-entries.js.map +0 -1
- package/dist/src/session/parity/session-id.js +0 -18
- package/dist/src/session/parity/session-id.js.map +0 -1
- package/dist/src/session/parity/sessions-json-cache.d.ts +0 -14
- package/dist/src/session/parity/sessions-json-cache.js +0 -98
- package/dist/src/session/parity/sessions-json-cache.js.map +0 -1
- package/dist/src/session/parity/sessions-json-file-read.d.ts +0 -6
- package/dist/src/session/parity/sessions-json-file-read.js +0 -19
- package/dist/src/session/parity/sessions-json-file-read.js.map +0 -1
- package/dist/src/session/parity/sessions-json-file.d.ts +0 -11
- package/dist/src/session/parity/sessions-json-file.js +0 -52
- package/dist/src/session/parity/sessions-json-file.js.map +0 -1
- package/dist/src/session/parity/sessions-json-patch.d.ts +0 -14
- package/dist/src/session/parity/sessions-json-patch.js +0 -40
- package/dist/src/session/parity/sessions-json-patch.js.map +0 -1
- package/dist/src/session/parity/transcript-file-lock.d.ts +0 -22
- package/dist/src/session/parity/transcript-file-lock.js +0 -142
- package/dist/src/session/parity/transcript-file-lock.js.map +0 -1
- package/dist/src/session/parity/transcript-pagination.d.ts +0 -29
- package/dist/src/session/parity/transcript-pagination.js +0 -132
- package/dist/src/session/parity/transcript-pagination.js.map +0 -1
- package/dist/src/session/parity/transcript-paths.d.ts +0 -13
- package/dist/src/session/parity/transcript-paths.js +0 -64
- package/dist/src/session/parity/transcript-paths.js.map +0 -1
- package/dist/src/session/parity/xopc-session-disk-entry.d.ts +0 -22
- package/dist/src/session/search-index-cache.d.ts +0 -6
- package/dist/src/session/search-index-cache.js +0 -44
- package/dist/src/session/search-index-cache.js.map +0 -1
- package/dist/src/session/search-index.d.ts +0 -20
- package/dist/src/session/search-index.js +0 -124
- package/dist/src/session/search-index.js.map +0 -1
- /package/dist/src/{session/parity/xopc-session-disk-entry.js → cron/execution-types.js} +0 -0
- /package/dist/src/session/{parity/load-jsonl-entries.d.ts → load-jsonl-entries.d.ts} +0 -0
- /package/dist/src/session/{parity/session-id.d.ts → session-id.d.ts} +0 -0
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { readSessionsJsonFileRaw } from "./sessions-json-file-read.js";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { stat } from "node:fs/promises";
|
|
4
|
-
//#region src/session/parity/sessions-json-cache.ts
|
|
5
|
-
const readCache = /* @__PURE__ */ new Map();
|
|
6
|
-
const serializedWriteCache = /* @__PURE__ */ new Map();
|
|
7
|
-
let writeStats = {
|
|
8
|
-
performed: 0,
|
|
9
|
-
skippedUnchanged: 0
|
|
10
|
-
};
|
|
11
|
-
function getSessionsJsonWriteStats() {
|
|
12
|
-
return writeStats;
|
|
13
|
-
}
|
|
14
|
-
function resetSessionsJsonCacheForTest() {
|
|
15
|
-
readCache.clear();
|
|
16
|
-
serializedWriteCache.clear();
|
|
17
|
-
writeStats = {
|
|
18
|
-
performed: 0,
|
|
19
|
-
skippedUnchanged: 0
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function invalidateSessionsJsonCache(storePath) {
|
|
23
|
-
readCache.delete(storePath);
|
|
24
|
-
serializedWriteCache.delete(storePath);
|
|
25
|
-
}
|
|
26
|
-
function serializeSessionsJson(store) {
|
|
27
|
-
return `${JSON.stringify(store, null, 2)}\n`;
|
|
28
|
-
}
|
|
29
|
-
async function readSessionsJsonCached(storePath) {
|
|
30
|
-
if (!existsSync(storePath)) return {
|
|
31
|
-
store: {},
|
|
32
|
-
serialized: "{}\n"
|
|
33
|
-
};
|
|
34
|
-
let mtimeMs = 0;
|
|
35
|
-
let sizeBytes = 0;
|
|
36
|
-
try {
|
|
37
|
-
const st = await stat(storePath);
|
|
38
|
-
mtimeMs = st.mtimeMs;
|
|
39
|
-
sizeBytes = st.size;
|
|
40
|
-
} catch {
|
|
41
|
-
return {
|
|
42
|
-
store: {},
|
|
43
|
-
serialized: "{}\n"
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
const cached = readCache.get(storePath);
|
|
47
|
-
if (cached && cached.mtimeMs === mtimeMs && cached.sizeBytes === sizeBytes) return {
|
|
48
|
-
store: structuredClone(cached.parsed),
|
|
49
|
-
serialized: cached.serialized
|
|
50
|
-
};
|
|
51
|
-
const store = await readSessionsJsonFileRaw(storePath);
|
|
52
|
-
const serialized = serializeSessionsJson(store);
|
|
53
|
-
readCache.set(storePath, {
|
|
54
|
-
mtimeMs,
|
|
55
|
-
sizeBytes,
|
|
56
|
-
parsed: structuredClone(store),
|
|
57
|
-
serialized
|
|
58
|
-
});
|
|
59
|
-
serializedWriteCache.set(storePath, serialized);
|
|
60
|
-
return {
|
|
61
|
-
store: structuredClone(store),
|
|
62
|
-
serialized
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
function commitSessionsJsonWrite(storePath, store, serialized) {
|
|
66
|
-
if (serializedWriteCache.get(storePath) === serialized) {
|
|
67
|
-
writeStats.skippedUnchanged += 1;
|
|
68
|
-
readCache.set(storePath, {
|
|
69
|
-
mtimeMs: readCache.get(storePath)?.mtimeMs ?? Date.now(),
|
|
70
|
-
sizeBytes: serialized.length,
|
|
71
|
-
parsed: structuredClone(store),
|
|
72
|
-
serialized
|
|
73
|
-
});
|
|
74
|
-
return false;
|
|
75
|
-
}
|
|
76
|
-
serializedWriteCache.set(storePath, serialized);
|
|
77
|
-
writeStats.performed += 1;
|
|
78
|
-
readCache.set(storePath, {
|
|
79
|
-
mtimeMs: Date.now(),
|
|
80
|
-
sizeBytes: serialized.length,
|
|
81
|
-
parsed: structuredClone(store),
|
|
82
|
-
serialized
|
|
83
|
-
});
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
function noteSessionsJsonWritten(storePath, serialized, store) {
|
|
87
|
-
serializedWriteCache.set(storePath, serialized);
|
|
88
|
-
readCache.set(storePath, {
|
|
89
|
-
mtimeMs: Date.now(),
|
|
90
|
-
sizeBytes: serialized.length,
|
|
91
|
-
parsed: structuredClone(store),
|
|
92
|
-
serialized
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
//#endregion
|
|
96
|
-
export { commitSessionsJsonWrite, getSessionsJsonWriteStats, invalidateSessionsJsonCache, noteSessionsJsonWritten, readSessionsJsonCached, resetSessionsJsonCacheForTest };
|
|
97
|
-
|
|
98
|
-
//# sourceMappingURL=sessions-json-cache.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessions-json-cache.js","names":[],"sources":["../../../../src/session/parity/sessions-json-cache.ts"],"sourcesContent":["import { stat } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\n\nimport { readSessionsJsonFileRaw } from './sessions-json-file-read.js';\n\ntype ReadCacheEntry = {\n mtimeMs: number;\n sizeBytes: number;\n parsed: Record<string, unknown>;\n serialized: string;\n};\n\nconst readCache = new Map<string, ReadCacheEntry>();\nconst serializedWriteCache = new Map<string, string>();\n\nlet writeStats = {\n performed: 0,\n skippedUnchanged: 0,\n};\n\nexport function getSessionsJsonWriteStats(): Readonly<typeof writeStats> {\n return writeStats;\n}\n\nexport function resetSessionsJsonCacheForTest(): void {\n readCache.clear();\n serializedWriteCache.clear();\n writeStats = { performed: 0, skippedUnchanged: 0 };\n}\n\nexport function invalidateSessionsJsonCache(storePath: string): void {\n readCache.delete(storePath);\n serializedWriteCache.delete(storePath);\n}\n\nfunction serializeSessionsJson(store: Record<string, unknown>): string {\n return `${JSON.stringify(store, null, 2)}\\n`;\n}\n\nexport async function readSessionsJsonCached(\n storePath: string,\n): Promise<{ store: Record<string, unknown>; serialized: string }> {\n if (!existsSync(storePath)) {\n return { store: {}, serialized: '{}\\n' };\n }\n\n let mtimeMs = 0;\n let sizeBytes = 0;\n try {\n const st = await stat(storePath);\n mtimeMs = st.mtimeMs;\n sizeBytes = st.size;\n } catch {\n return { store: {}, serialized: '{}\\n' };\n }\n\n const cached = readCache.get(storePath);\n if (cached && cached.mtimeMs === mtimeMs && cached.sizeBytes === sizeBytes) {\n return { store: structuredClone(cached.parsed), serialized: cached.serialized };\n }\n\n const store = await readSessionsJsonFileRaw(storePath);\n const serialized = serializeSessionsJson(store);\n readCache.set(storePath, { mtimeMs, sizeBytes, parsed: structuredClone(store), serialized });\n serializedWriteCache.set(storePath, serialized);\n return { store: structuredClone(store), serialized };\n}\n\nexport function commitSessionsJsonWrite(\n storePath: string,\n store: Record<string, unknown>,\n serialized: string,\n): boolean {\n const previous = serializedWriteCache.get(storePath);\n if (previous === serialized) {\n writeStats.skippedUnchanged += 1;\n readCache.set(storePath, {\n mtimeMs: readCache.get(storePath)?.mtimeMs ?? Date.now(),\n sizeBytes: serialized.length,\n parsed: structuredClone(store),\n serialized,\n });\n return false;\n }\n\n serializedWriteCache.set(storePath, serialized);\n writeStats.performed += 1;\n readCache.set(storePath, {\n mtimeMs: Date.now(),\n sizeBytes: serialized.length,\n parsed: structuredClone(store),\n serialized,\n });\n return true;\n}\n\nexport function noteSessionsJsonWritten(storePath: string, serialized: string, store: Record<string, unknown>): void {\n serializedWriteCache.set(storePath, serialized);\n readCache.set(storePath, {\n mtimeMs: Date.now(),\n sizeBytes: serialized.length,\n parsed: structuredClone(store),\n serialized,\n });\n}\n"],"mappings":";;;;AAYA,MAAM,4BAAY,IAAI,KAA6B;AACnD,MAAM,uCAAuB,IAAI,KAAqB;AAEtD,IAAI,aAAa;CACf,WAAW;CACX,kBAAkB;CACnB;AAED,SAAgB,4BAAyD;AACvE,QAAO;;AAGT,SAAgB,gCAAsC;AACpD,WAAU,OAAO;AACjB,sBAAqB,OAAO;AAC5B,cAAa;EAAE,WAAW;EAAG,kBAAkB;EAAG;;AAGpD,SAAgB,4BAA4B,WAAyB;AACnE,WAAU,OAAO,UAAU;AAC3B,sBAAqB,OAAO,UAAU;;AAGxC,SAAS,sBAAsB,OAAwC;AACrE,QAAO,GAAG,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;;AAG3C,eAAsB,uBACpB,WACiE;AACjE,KAAI,CAAC,WAAW,UAAU,CACxB,QAAO;EAAE,OAAO,EAAE;EAAE,YAAY;EAAQ;CAG1C,IAAI,UAAU;CACd,IAAI,YAAY;AAChB,KAAI;EACF,MAAM,KAAK,MAAM,KAAK,UAAU;AAChC,YAAU,GAAG;AACb,cAAY,GAAG;SACT;AACN,SAAO;GAAE,OAAO,EAAE;GAAE,YAAY;GAAQ;;CAG1C,MAAM,SAAS,UAAU,IAAI,UAAU;AACvC,KAAI,UAAU,OAAO,YAAY,WAAW,OAAO,cAAc,UAC/D,QAAO;EAAE,OAAO,gBAAgB,OAAO,OAAO;EAAE,YAAY,OAAO;EAAY;CAGjF,MAAM,QAAQ,MAAM,wBAAwB,UAAU;CACtD,MAAM,aAAa,sBAAsB,MAAM;AAC/C,WAAU,IAAI,WAAW;EAAE;EAAS;EAAW,QAAQ,gBAAgB,MAAM;EAAE;EAAY,CAAC;AAC5F,sBAAqB,IAAI,WAAW,WAAW;AAC/C,QAAO;EAAE,OAAO,gBAAgB,MAAM;EAAE;EAAY;;AAGtD,SAAgB,wBACd,WACA,OACA,YACS;AAET,KADiB,qBAAqB,IAAI,UAC9B,KAAK,YAAY;AAC3B,aAAW,oBAAoB;AAC/B,YAAU,IAAI,WAAW;GACvB,SAAS,UAAU,IAAI,UAAU,EAAE,WAAW,KAAK,KAAK;GACxD,WAAW,WAAW;GACtB,QAAQ,gBAAgB,MAAM;GAC9B;GACD,CAAC;AACF,SAAO;;AAGT,sBAAqB,IAAI,WAAW,WAAW;AAC/C,YAAW,aAAa;AACxB,WAAU,IAAI,WAAW;EACvB,SAAS,KAAK,KAAK;EACnB,WAAW,WAAW;EACtB,QAAQ,gBAAgB,MAAM;EAC9B;EACD,CAAC;AACF,QAAO;;AAGT,SAAgB,wBAAwB,WAAmB,YAAoB,OAAsC;AACnH,sBAAqB,IAAI,WAAW,WAAW;AAC/C,WAAU,IAAI,WAAW;EACvB,SAAS,KAAK,KAAK;EACnB,WAAW,WAAW;EACtB,QAAQ,gBAAgB,MAAM;EAC9B;EACD,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises";
|
|
2
|
-
//#region src/session/parity/sessions-json-file-read.ts
|
|
3
|
-
/**
|
|
4
|
-
* Raw disk read for sessions.json (no in-memory cache).
|
|
5
|
-
*/
|
|
6
|
-
async function readSessionsJsonFileRaw(storePath) {
|
|
7
|
-
try {
|
|
8
|
-
const raw = await readFile(storePath, "utf-8");
|
|
9
|
-
const parsed = JSON.parse(raw);
|
|
10
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
11
|
-
return parsed;
|
|
12
|
-
} catch {
|
|
13
|
-
return {};
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
//#endregion
|
|
17
|
-
export { readSessionsJsonFileRaw };
|
|
18
|
-
|
|
19
|
-
//# sourceMappingURL=sessions-json-file-read.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessions-json-file-read.js","names":[],"sources":["../../../../src/session/parity/sessions-json-file-read.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\n\n// Type duplicated inline — `sessions-json-file.ts` imports a value from this\n// file (cache.ts → file-read.ts → file.ts), so re-importing the type back\n// would close the loop. The shape is trivial so we declare it locally.\ntype SessionsJsonMap<T> = Record<string, T>;\n\n/**\n * Raw disk read for sessions.json (no in-memory cache).\n */\nexport async function readSessionsJsonFileRaw<T extends Record<string, unknown>>(\n storePath: string,\n): Promise<SessionsJsonMap<T>> {\n try {\n const raw = await readFile(storePath, 'utf-8');\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n return {};\n }\n return parsed as SessionsJsonMap<T>;\n } catch {\n return {};\n }\n}\n"],"mappings":";;;;;AAUA,eAAsB,wBACpB,WAC6B;AAC7B,KAAI;EACF,MAAM,MAAM,MAAM,SAAS,WAAW,QAAQ;EAC9C,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,CAChE,QAAO,EAAE;AAEX,SAAO;SACD;AACN,SAAO,EAAE"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export type SessionsJsonMap<T> = Record<string, T>;
|
|
2
|
-
/**
|
|
3
|
-
* Read JSON object from `sessions.json`. Missing file → `{}`.
|
|
4
|
-
* Uses mtime/size cache when enabled.
|
|
5
|
-
*/
|
|
6
|
-
export declare function readSessionsJsonFile<T extends Record<string, unknown>>(storePath: string): Promise<SessionsJsonMap<T>>;
|
|
7
|
-
/**
|
|
8
|
-
* Exclusive update: lock → read → mutate → atomic write (skipped when serialized unchanged) → unlock.
|
|
9
|
-
*/
|
|
10
|
-
export declare function withSessionsJsonLock<T>(storePath: string, fn: (store: SessionsJsonMap<Record<string, unknown>>) => Promise<T>): Promise<T>;
|
|
11
|
-
export { invalidateSessionsJsonCache, getSessionsJsonWriteStats, resetSessionsJsonCacheForTest } from './sessions-json-cache.js';
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
|
|
2
|
-
import { readSessionsJsonFileRaw } from "./sessions-json-file-read.js";
|
|
3
|
-
import { commitSessionsJsonWrite, getSessionsJsonWriteStats, invalidateSessionsJsonCache, noteSessionsJsonWritten, readSessionsJsonCached, resetSessionsJsonCacheForTest } from "./sessions-json-cache.js";
|
|
4
|
-
import { dirname } from "node:path";
|
|
5
|
-
import { existsSync } from "node:fs";
|
|
6
|
-
import { mkdir } from "node:fs/promises";
|
|
7
|
-
import lockfile from "proper-lockfile";
|
|
8
|
-
//#region src/session/parity/sessions-json-file.ts
|
|
9
|
-
init_write_file_atomic();
|
|
10
|
-
async function ensureDirForFile(filePath) {
|
|
11
|
-
await mkdir(dirname(filePath), { recursive: true });
|
|
12
|
-
}
|
|
13
|
-
function serializeSessionsJson(store) {
|
|
14
|
-
return `${JSON.stringify(store, null, 2)}\n`;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* Read JSON object from `sessions.json`. Missing file → `{}`.
|
|
18
|
-
* Uses mtime/size cache when enabled.
|
|
19
|
-
*/
|
|
20
|
-
async function readSessionsJsonFile(storePath) {
|
|
21
|
-
if (!existsSync(storePath)) return {};
|
|
22
|
-
const { store } = await readSessionsJsonCached(storePath);
|
|
23
|
-
return store;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Exclusive update: lock → read → mutate → atomic write (skipped when serialized unchanged) → unlock.
|
|
27
|
-
*/
|
|
28
|
-
async function withSessionsJsonLock(storePath, fn) {
|
|
29
|
-
await ensureDirForFile(storePath);
|
|
30
|
-
if (!existsSync(storePath)) {
|
|
31
|
-
await writeTextAtomic(storePath, "{}\n");
|
|
32
|
-
noteSessionsJsonWritten(storePath, "{}\n", {});
|
|
33
|
-
}
|
|
34
|
-
const release = await lockfile.lock(storePath, { retries: {
|
|
35
|
-
retries: 30,
|
|
36
|
-
minTimeout: 50,
|
|
37
|
-
maxTimeout: 500
|
|
38
|
-
} });
|
|
39
|
-
try {
|
|
40
|
-
const data = existsSync(storePath) ? await readSessionsJsonFileRaw(storePath) : {};
|
|
41
|
-
const result = await fn(data);
|
|
42
|
-
const serialized = serializeSessionsJson(data);
|
|
43
|
-
if (commitSessionsJsonWrite(storePath, data, serialized)) await writeTextAtomic(storePath, serialized);
|
|
44
|
-
return result;
|
|
45
|
-
} finally {
|
|
46
|
-
await release();
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
//#endregion
|
|
50
|
-
export { getSessionsJsonWriteStats, invalidateSessionsJsonCache, readSessionsJsonFile, resetSessionsJsonCacheForTest, withSessionsJsonLock };
|
|
51
|
-
|
|
52
|
-
//# sourceMappingURL=sessions-json-file.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessions-json-file.js","names":[],"sources":["../../../../src/session/parity/sessions-json-file.ts"],"sourcesContent":["import { mkdir } from 'node:fs/promises';\nimport { dirname } from 'node:path';\nimport { existsSync } from 'node:fs';\n\nimport lockfile from 'proper-lockfile';\n\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport {\n commitSessionsJsonWrite,\n noteSessionsJsonWritten,\n readSessionsJsonCached,\n} from './sessions-json-cache.js';\nimport { readSessionsJsonFileRaw } from './sessions-json-file-read.js';\n\nexport type SessionsJsonMap<T> = Record<string, T>;\n\nasync function ensureDirForFile(filePath: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true });\n}\n\nfunction serializeSessionsJson(store: Record<string, unknown>): string {\n return `${JSON.stringify(store, null, 2)}\\n`;\n}\n\n/**\n * Read JSON object from `sessions.json`. Missing file → `{}`.\n * Uses mtime/size cache when enabled.\n */\nexport async function readSessionsJsonFile<T extends Record<string, unknown>>(\n storePath: string,\n): Promise<SessionsJsonMap<T>> {\n if (!existsSync(storePath)) {\n return {};\n }\n const { store } = await readSessionsJsonCached(storePath);\n return store as SessionsJsonMap<T>;\n}\n\n/**\n * Exclusive update: lock → read → mutate → atomic write (skipped when serialized unchanged) → unlock.\n */\nexport async function withSessionsJsonLock<T>(\n storePath: string,\n fn: (store: SessionsJsonMap<Record<string, unknown>>) => Promise<T>,\n): Promise<T> {\n await ensureDirForFile(storePath);\n if (!existsSync(storePath)) {\n await writeTextAtomic(storePath, '{}\\n');\n noteSessionsJsonWritten(storePath, '{}\\n', {});\n }\n const release = await lockfile.lock(storePath, {\n retries: {\n retries: 30,\n minTimeout: 50,\n maxTimeout: 500,\n },\n });\n try {\n const data = existsSync(storePath)\n ? await readSessionsJsonFileRaw<Record<string, unknown>>(storePath)\n : {};\n const result = await fn(data);\n const serialized = serializeSessionsJson(data);\n if (commitSessionsJsonWrite(storePath, data, serialized)) {\n await writeTextAtomic(storePath, serialized);\n }\n return result;\n } finally {\n await release();\n }\n}\n\nexport { invalidateSessionsJsonCache, getSessionsJsonWriteStats, resetSessionsJsonCacheForTest } from './sessions-json-cache.js';\n"],"mappings":";;;;;;;;wBAMmE;AAUnE,eAAe,iBAAiB,UAAiC;AAC/D,OAAM,MAAM,QAAQ,SAAS,EAAE,EAAE,WAAW,MAAM,CAAC;;AAGrD,SAAS,sBAAsB,OAAwC;AACrE,QAAO,GAAG,KAAK,UAAU,OAAO,MAAM,EAAE,CAAC;;;;;;AAO3C,eAAsB,qBACpB,WAC6B;AAC7B,KAAI,CAAC,WAAW,UAAU,CACxB,QAAO,EAAE;CAEX,MAAM,EAAE,UAAU,MAAM,uBAAuB,UAAU;AACzD,QAAO;;;;;AAMT,eAAsB,qBACpB,WACA,IACY;AACZ,OAAM,iBAAiB,UAAU;AACjC,KAAI,CAAC,WAAW,UAAU,EAAE;AAC1B,QAAM,gBAAgB,WAAW,OAAO;AACxC,0BAAwB,WAAW,QAAQ,EAAE,CAAC;;CAEhD,MAAM,UAAU,MAAM,SAAS,KAAK,WAAW,EAC7C,SAAS;EACP,SAAS;EACT,YAAY;EACZ,YAAY;EACb,EACF,CAAC;AACF,KAAI;EACF,MAAM,OAAO,WAAW,UAAU,GAC9B,MAAM,wBAAiD,UAAU,GACjE,EAAE;EACN,MAAM,SAAS,MAAM,GAAG,KAAK;EAC7B,MAAM,aAAa,sBAAsB,KAAK;AAC9C,MAAI,wBAAwB,WAAW,MAAM,WAAW,CACtD,OAAM,gBAAgB,WAAW,WAAW;AAE9C,SAAO;WACC;AACR,QAAM,SAAS"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { XopcSessionDiskEntry } from './xopc-session-disk-entry.js';
|
|
2
|
-
export type SessionsJsonStatsPatch = {
|
|
3
|
-
messageCount: number;
|
|
4
|
-
estimatedTokens: number;
|
|
5
|
-
lastTurnAt: number;
|
|
6
|
-
};
|
|
7
|
-
export declare function buildSessionsJsonStatsPatch(messageCount: number, estimatedTokens: number): SessionsJsonStatsPatch;
|
|
8
|
-
/** Apply stats + timestamps to a single sessions.json entry (in-memory patch). */
|
|
9
|
-
export declare function patchSessionsJsonEntryStats(entry: XopcSessionDiskEntry, stats: SessionsJsonStatsPatch): void;
|
|
10
|
-
export declare function isAppendOnlyLlmTranscriptMessage(message: unknown): boolean;
|
|
11
|
-
/** Increment stats for a single appended LLM row (hot path). */
|
|
12
|
-
export declare function incrementSessionsJsonStatsForAppend(entry: XopcSessionDiskEntry, opts?: {
|
|
13
|
-
tokenDelta?: number;
|
|
14
|
-
}): void;
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
//#region src/session/parity/sessions-json-patch.ts
|
|
2
|
-
function buildSessionsJsonStatsPatch(messageCount, estimatedTokens) {
|
|
3
|
-
return {
|
|
4
|
-
messageCount,
|
|
5
|
-
estimatedTokens,
|
|
6
|
-
lastTurnAt: Date.now()
|
|
7
|
-
};
|
|
8
|
-
}
|
|
9
|
-
/** Apply stats + timestamps to a single sessions.json entry (in-memory patch). */
|
|
10
|
-
function patchSessionsJsonEntryStats(entry, stats) {
|
|
11
|
-
if (!entry.pluginExtensions?.xopc?.metadata) return;
|
|
12
|
-
const meta = entry.pluginExtensions.xopc.metadata;
|
|
13
|
-
meta.messageCount = stats.messageCount;
|
|
14
|
-
meta.estimatedTokens = stats.estimatedTokens;
|
|
15
|
-
meta.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
16
|
-
meta.lastAccessedAt = meta.updatedAt;
|
|
17
|
-
meta.stats = {
|
|
18
|
-
messageCount: stats.messageCount,
|
|
19
|
-
tokenCount: stats.estimatedTokens,
|
|
20
|
-
lastTurnAt: stats.lastTurnAt
|
|
21
|
-
};
|
|
22
|
-
entry.updatedAt = stats.lastTurnAt;
|
|
23
|
-
}
|
|
24
|
-
function isAppendOnlyLlmTranscriptMessage(message) {
|
|
25
|
-
if (!message || typeof message !== "object") return false;
|
|
26
|
-
const role = message.role;
|
|
27
|
-
return role === "user" || role === "assistant" || role === "tool" || role === "toolResult";
|
|
28
|
-
}
|
|
29
|
-
/** Increment stats for a single appended LLM row (hot path). */
|
|
30
|
-
function incrementSessionsJsonStatsForAppend(entry, opts) {
|
|
31
|
-
if (!entry.pluginExtensions?.xopc?.metadata) return;
|
|
32
|
-
const meta = entry.pluginExtensions.xopc.metadata;
|
|
33
|
-
const nextCount = (meta.messageCount ?? 0) + 1;
|
|
34
|
-
const tokenDelta = opts?.tokenDelta ?? 0;
|
|
35
|
-
patchSessionsJsonEntryStats(entry, buildSessionsJsonStatsPatch(nextCount, (meta.estimatedTokens ?? 0) + tokenDelta));
|
|
36
|
-
}
|
|
37
|
-
//#endregion
|
|
38
|
-
export { buildSessionsJsonStatsPatch, incrementSessionsJsonStatsForAppend, isAppendOnlyLlmTranscriptMessage, patchSessionsJsonEntryStats };
|
|
39
|
-
|
|
40
|
-
//# sourceMappingURL=sessions-json-patch.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessions-json-patch.js","names":[],"sources":["../../../../src/session/parity/sessions-json-patch.ts"],"sourcesContent":["import type { XopcSessionDiskEntry } from './xopc-session-disk-entry.js';\n\nexport type SessionsJsonStatsPatch = {\n messageCount: number;\n estimatedTokens: number;\n lastTurnAt: number;\n};\n\nexport function buildSessionsJsonStatsPatch(\n messageCount: number,\n estimatedTokens: number,\n): SessionsJsonStatsPatch {\n const now = Date.now();\n return {\n messageCount,\n estimatedTokens,\n lastTurnAt: now,\n };\n}\n\n/** Apply stats + timestamps to a single sessions.json entry (in-memory patch). */\nexport function patchSessionsJsonEntryStats(\n entry: XopcSessionDiskEntry,\n stats: SessionsJsonStatsPatch,\n): void {\n if (!entry.pluginExtensions?.xopc?.metadata) {\n return;\n }\n const meta = entry.pluginExtensions.xopc.metadata;\n meta.messageCount = stats.messageCount;\n meta.estimatedTokens = stats.estimatedTokens;\n meta.updatedAt = new Date().toISOString();\n meta.lastAccessedAt = meta.updatedAt;\n meta.stats = {\n messageCount: stats.messageCount,\n tokenCount: stats.estimatedTokens,\n lastTurnAt: stats.lastTurnAt,\n };\n entry.updatedAt = stats.lastTurnAt;\n}\n\nexport function isAppendOnlyLlmTranscriptMessage(message: unknown): boolean {\n if (!message || typeof message !== 'object') {\n return false;\n }\n const role = (message as { role?: string }).role;\n return role === 'user' || role === 'assistant' || role === 'tool' || role === 'toolResult';\n}\n\n/** Increment stats for a single appended LLM row (hot path). */\nexport function incrementSessionsJsonStatsForAppend(\n entry: XopcSessionDiskEntry,\n opts?: { tokenDelta?: number },\n): void {\n if (!entry.pluginExtensions?.xopc?.metadata) {\n return;\n }\n const meta = entry.pluginExtensions.xopc.metadata;\n const nextCount = (meta.messageCount ?? 0) + 1;\n const tokenDelta = opts?.tokenDelta ?? 0;\n const nextTokens = (meta.estimatedTokens ?? 0) + tokenDelta;\n patchSessionsJsonEntryStats(entry, buildSessionsJsonStatsPatch(nextCount, nextTokens));\n}\n"],"mappings":";AAQA,SAAgB,4BACd,cACA,iBACwB;AAExB,QAAO;EACL;EACA;EACA,YAJU,KAAK,KAIA;EAChB;;;AAIH,SAAgB,4BACd,OACA,OACM;AACN,KAAI,CAAC,MAAM,kBAAkB,MAAM,SACjC;CAEF,MAAM,OAAO,MAAM,iBAAiB,KAAK;AACzC,MAAK,eAAe,MAAM;AAC1B,MAAK,kBAAkB,MAAM;AAC7B,MAAK,6BAAY,IAAI,MAAM,EAAC,aAAa;AACzC,MAAK,iBAAiB,KAAK;AAC3B,MAAK,QAAQ;EACX,cAAc,MAAM;EACpB,YAAY,MAAM;EAClB,YAAY,MAAM;EACnB;AACD,OAAM,YAAY,MAAM;;AAG1B,SAAgB,iCAAiC,SAA2B;AAC1E,KAAI,CAAC,WAAW,OAAO,YAAY,SACjC,QAAO;CAET,MAAM,OAAQ,QAA8B;AAC5C,QAAO,SAAS,UAAU,SAAS,eAAe,SAAS,UAAU,SAAS;;;AAIhF,SAAgB,oCACd,OACA,MACM;AACN,KAAI,CAAC,MAAM,kBAAkB,MAAM,SACjC;CAEF,MAAM,OAAO,MAAM,iBAAiB,KAAK;CACzC,MAAM,aAAa,KAAK,gBAAgB,KAAK;CAC7C,MAAM,aAAa,MAAM,cAAc;AAEvC,6BAA4B,OAAO,4BAA4B,YAD3C,KAAK,mBAAmB,KAAK,WACoC,CAAC"}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Cross-process (and re-entrant same-process) advisory lock for session transcript JSONL.
|
|
3
|
-
* Aligns with the goal of safe concurrent gateway/CLI access; same idea as OpenClaw's
|
|
4
|
-
* session write lock, but scoped to a single transcript path with a smaller surface area.
|
|
5
|
-
*/
|
|
6
|
-
export type TranscriptFileLock = {
|
|
7
|
-
release: () => Promise<void>;
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* Acquire an exclusive lock for mutations to `transcriptAbsPath`.
|
|
11
|
-
* Re-entrant on the same path in the same process (nested `withTranscriptFileLock`).
|
|
12
|
-
*/
|
|
13
|
-
export declare function acquireTranscriptFileLock(transcriptAbsPath: string, opts?: {
|
|
14
|
-
timeoutMs?: number;
|
|
15
|
-
staleMs?: number;
|
|
16
|
-
}): Promise<TranscriptFileLock>;
|
|
17
|
-
export declare function withTranscriptFileLock<T>(transcriptAbsPath: string, fn: () => Promise<T>, opts?: {
|
|
18
|
-
timeoutMs?: number;
|
|
19
|
-
staleMs?: number;
|
|
20
|
-
}): Promise<T>;
|
|
21
|
-
/** Best-effort: remove a stale lock without acquiring (e.g. doctor tooling). */
|
|
22
|
-
export declare function tryRemoveStaleTranscriptLock(transcriptAbsPath: string, staleMs?: number): Promise<boolean>;
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { createHash } from "node:crypto";
|
|
4
|
-
import { mkdir, open, readFile, rm, stat } from "node:fs/promises";
|
|
5
|
-
//#region src/session/parity/transcript-file-lock.ts
|
|
6
|
-
/**
|
|
7
|
-
* Cross-process (and re-entrant same-process) advisory lock for session transcript JSONL.
|
|
8
|
-
* Aligns with the goal of safe concurrent gateway/CLI access; same idea as OpenClaw's
|
|
9
|
-
* session write lock, but scoped to a single transcript path with a smaller surface area.
|
|
10
|
-
*/
|
|
11
|
-
const DEFAULT_TIMEOUT_MS = 6e4;
|
|
12
|
-
const DEFAULT_STALE_MS = 1800 * 1e3;
|
|
13
|
-
const heldLocks = /* @__PURE__ */ new Map();
|
|
14
|
-
/** Same-process serialization for acquire; cross-process exclusion uses the lock file. */
|
|
15
|
-
const acquireChains = /* @__PURE__ */ new Map();
|
|
16
|
-
function chainPerTranscript(normalized, fn) {
|
|
17
|
-
const run = (acquireChains.get(normalized) ?? Promise.resolve()).then(() => fn());
|
|
18
|
-
acquireChains.set(normalized, run.then(() => void 0).catch(() => void 0));
|
|
19
|
-
return run;
|
|
20
|
-
}
|
|
21
|
-
function normalizeTranscriptPath(transcriptAbsPath) {
|
|
22
|
-
return path.resolve(transcriptAbsPath);
|
|
23
|
-
}
|
|
24
|
-
function lockPathFor(transcriptAbsPath) {
|
|
25
|
-
const dir = path.dirname(transcriptAbsPath);
|
|
26
|
-
const base = path.basename(transcriptAbsPath);
|
|
27
|
-
const hash = createHash("sha256").update(transcriptAbsPath).digest("hex").slice(0, 16);
|
|
28
|
-
return path.join(dir, `.${base}.${hash}.xopc-transcript.lock`);
|
|
29
|
-
}
|
|
30
|
-
function isPidAlive(pid) {
|
|
31
|
-
if (!Number.isFinite(pid) || pid <= 0) return false;
|
|
32
|
-
try {
|
|
33
|
-
process.kill(pid, 0);
|
|
34
|
-
return true;
|
|
35
|
-
} catch {
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
async function readPayload(lockFile) {
|
|
40
|
-
try {
|
|
41
|
-
const raw = await readFile(lockFile, "utf8");
|
|
42
|
-
return JSON.parse(raw);
|
|
43
|
-
} catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
async function isStaleLock(lockFile, staleMs) {
|
|
48
|
-
let st;
|
|
49
|
-
try {
|
|
50
|
-
st = await stat(lockFile);
|
|
51
|
-
} catch {
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
if (Date.now() - st.mtimeMs > staleMs) return true;
|
|
55
|
-
const payload = await readPayload(lockFile);
|
|
56
|
-
const pid = typeof payload?.pid === "number" ? payload.pid : void 0;
|
|
57
|
-
if (pid != null && pid !== process.pid && !isPidAlive(pid)) return true;
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
60
|
-
async function releaseHeldLock(normalized, held) {
|
|
61
|
-
held.refcount -= 1;
|
|
62
|
-
if (held.refcount > 0) return;
|
|
63
|
-
heldLocks.delete(normalized);
|
|
64
|
-
try {
|
|
65
|
-
await held.handle.close();
|
|
66
|
-
} catch {}
|
|
67
|
-
try {
|
|
68
|
-
await rm(held.lockFile, { force: true });
|
|
69
|
-
} catch {}
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* Acquire an exclusive lock for mutations to `transcriptAbsPath`.
|
|
73
|
-
* Re-entrant on the same path in the same process (nested `withTranscriptFileLock`).
|
|
74
|
-
*/
|
|
75
|
-
async function acquireTranscriptFileLock(transcriptAbsPath, opts) {
|
|
76
|
-
const normalized = normalizeTranscriptPath(transcriptAbsPath);
|
|
77
|
-
return chainPerTranscript(normalized, () => acquireTranscriptFileLockBody(normalized, opts));
|
|
78
|
-
}
|
|
79
|
-
async function acquireTranscriptFileLockBody(normalized, opts) {
|
|
80
|
-
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
81
|
-
const staleMs = opts?.staleMs ?? DEFAULT_STALE_MS;
|
|
82
|
-
const existing = heldLocks.get(normalized);
|
|
83
|
-
if (existing) {
|
|
84
|
-
existing.refcount += 1;
|
|
85
|
-
return { release: async () => {
|
|
86
|
-
await releaseHeldLock(normalized, existing);
|
|
87
|
-
} };
|
|
88
|
-
}
|
|
89
|
-
const lockFile = lockPathFor(normalized);
|
|
90
|
-
await mkdir(path.dirname(lockFile), { recursive: true });
|
|
91
|
-
const started = Date.now();
|
|
92
|
-
let handle = null;
|
|
93
|
-
while (Date.now() - started < timeoutMs) try {
|
|
94
|
-
handle = await open(lockFile, "wx", 384);
|
|
95
|
-
break;
|
|
96
|
-
} catch (err) {
|
|
97
|
-
if (err.code === "EEXIST") {
|
|
98
|
-
if (await isStaleLock(lockFile, staleMs)) {
|
|
99
|
-
await rm(lockFile, { force: true });
|
|
100
|
-
continue;
|
|
101
|
-
}
|
|
102
|
-
await new Promise((r) => setTimeout(r, 50 + Math.floor(Math.random() * 40)));
|
|
103
|
-
continue;
|
|
104
|
-
}
|
|
105
|
-
throw err;
|
|
106
|
-
}
|
|
107
|
-
if (!handle) throw new Error(`timeout acquiring transcript lock: ${lockFile}`);
|
|
108
|
-
const payload = {
|
|
109
|
-
pid: process.pid,
|
|
110
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
111
|
-
};
|
|
112
|
-
await handle.writeFile(JSON.stringify(payload, null, 2), "utf8");
|
|
113
|
-
const held = {
|
|
114
|
-
refcount: 1,
|
|
115
|
-
handle,
|
|
116
|
-
lockFile
|
|
117
|
-
};
|
|
118
|
-
heldLocks.set(normalized, held);
|
|
119
|
-
return { release: async () => {
|
|
120
|
-
await releaseHeldLock(normalized, held);
|
|
121
|
-
} };
|
|
122
|
-
}
|
|
123
|
-
async function withTranscriptFileLock(transcriptAbsPath, fn, opts) {
|
|
124
|
-
const lock = await acquireTranscriptFileLock(transcriptAbsPath, opts);
|
|
125
|
-
try {
|
|
126
|
-
return await fn();
|
|
127
|
-
} finally {
|
|
128
|
-
await lock.release();
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
/** Best-effort: remove a stale lock without acquiring (e.g. doctor tooling). */
|
|
132
|
-
async function tryRemoveStaleTranscriptLock(transcriptAbsPath, staleMs = DEFAULT_STALE_MS) {
|
|
133
|
-
const lockFile = lockPathFor(normalizeTranscriptPath(transcriptAbsPath));
|
|
134
|
-
if (!existsSync(lockFile)) return false;
|
|
135
|
-
if (!await isStaleLock(lockFile, staleMs)) return false;
|
|
136
|
-
await rm(lockFile, { force: true });
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
//#endregion
|
|
140
|
-
export { acquireTranscriptFileLock, tryRemoveStaleTranscriptLock, withTranscriptFileLock };
|
|
141
|
-
|
|
142
|
-
//# sourceMappingURL=transcript-file-lock.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transcript-file-lock.js","names":[],"sources":["../../../../src/session/parity/transcript-file-lock.ts"],"sourcesContent":["/**\n * Cross-process (and re-entrant same-process) advisory lock for session transcript JSONL.\n * Aligns with the goal of safe concurrent gateway/CLI access; same idea as OpenClaw's\n * session write lock, but scoped to a single transcript path with a smaller surface area.\n */\n\nimport { createHash } from 'node:crypto';\nimport type { FileHandle } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\nimport { mkdir, open, readFile, rm, stat } from 'node:fs/promises';\nimport path from 'node:path';\n\nconst DEFAULT_TIMEOUT_MS = 60_000;\nconst DEFAULT_STALE_MS = 30 * 60 * 1000;\n\ntype LockPayload = { pid?: number; createdAt?: string };\n\ntype HeldTranscriptLock = {\n refcount: number;\n handle: FileHandle;\n lockFile: string;\n};\n\nconst heldLocks = new Map<string, HeldTranscriptLock>();\n\n/** Same-process serialization for acquire; cross-process exclusion uses the lock file. */\nconst acquireChains = new Map<string, Promise<void>>();\n\nfunction chainPerTranscript<T>(normalized: string, fn: () => Promise<T>): Promise<T> {\n const prev = acquireChains.get(normalized) ?? Promise.resolve();\n const run = prev.then(() => fn());\n acquireChains.set(\n normalized,\n run.then(() => undefined).catch(() => undefined),\n );\n return run;\n}\n\nfunction normalizeTranscriptPath(transcriptAbsPath: string): string {\n return path.resolve(transcriptAbsPath);\n}\n\nfunction lockPathFor(transcriptAbsPath: string): string {\n const dir = path.dirname(transcriptAbsPath);\n const base = path.basename(transcriptAbsPath);\n const hash = createHash('sha256').update(transcriptAbsPath).digest('hex').slice(0, 16);\n return path.join(dir, `.${base}.${hash}.xopc-transcript.lock`);\n}\n\nfunction isPidAlive(pid: number): boolean {\n if (!Number.isFinite(pid) || pid <= 0) {\n return false;\n }\n try {\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\nasync function readPayload(lockFile: string): Promise<LockPayload | null> {\n try {\n const raw = await readFile(lockFile, 'utf8');\n return JSON.parse(raw) as LockPayload;\n } catch {\n return null;\n }\n}\n\nasync function isStaleLock(lockFile: string, staleMs: number): Promise<boolean> {\n let st;\n try {\n st = await stat(lockFile);\n } catch {\n return true;\n }\n const age = Date.now() - st.mtimeMs;\n if (age > staleMs) {\n return true;\n }\n const payload = await readPayload(lockFile);\n const pid = typeof payload?.pid === 'number' ? payload.pid : undefined;\n if (pid != null && pid !== process.pid && !isPidAlive(pid)) {\n return true;\n }\n return false;\n}\n\nasync function releaseHeldLock(normalized: string, held: HeldTranscriptLock): Promise<void> {\n held.refcount -= 1;\n if (held.refcount > 0) {\n return;\n }\n heldLocks.delete(normalized);\n try {\n await held.handle.close();\n } catch {\n /* ignore */\n }\n try {\n await rm(held.lockFile, { force: true });\n } catch {\n /* ignore */\n }\n}\n\nexport type TranscriptFileLock = { release: () => Promise<void> };\n\n/**\n * Acquire an exclusive lock for mutations to `transcriptAbsPath`.\n * Re-entrant on the same path in the same process (nested `withTranscriptFileLock`).\n */\nexport async function acquireTranscriptFileLock(\n transcriptAbsPath: string,\n opts?: { timeoutMs?: number; staleMs?: number },\n): Promise<TranscriptFileLock> {\n const normalized = normalizeTranscriptPath(transcriptAbsPath);\n return chainPerTranscript(normalized, () => acquireTranscriptFileLockBody(normalized, opts));\n}\n\nasync function acquireTranscriptFileLockBody(\n normalized: string,\n opts?: { timeoutMs?: number; staleMs?: number },\n): Promise<TranscriptFileLock> {\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const staleMs = opts?.staleMs ?? DEFAULT_STALE_MS;\n\n const existing = heldLocks.get(normalized);\n if (existing) {\n existing.refcount += 1;\n return {\n release: async () => {\n await releaseHeldLock(normalized, existing);\n },\n };\n }\n\n const lockFile = lockPathFor(normalized);\n await mkdir(path.dirname(lockFile), { recursive: true });\n\n const started = Date.now();\n let handle: FileHandle | null = null;\n\n while (Date.now() - started < timeoutMs) {\n try {\n handle = await open(lockFile, 'wx', 0o600);\n break;\n } catch (err) {\n const code = (err as NodeJS.ErrnoException).code;\n if (code === 'EEXIST') {\n if (await isStaleLock(lockFile, staleMs)) {\n await rm(lockFile, { force: true });\n continue;\n }\n await new Promise((r) => setTimeout(r, 50 + Math.floor(Math.random() * 40)));\n continue;\n }\n throw err;\n }\n }\n\n if (!handle) {\n throw new Error(`timeout acquiring transcript lock: ${lockFile}`);\n }\n\n const payload: LockPayload = { pid: process.pid, createdAt: new Date().toISOString() };\n await handle.writeFile(JSON.stringify(payload, null, 2), 'utf8');\n\n const held: HeldTranscriptLock = { refcount: 1, handle, lockFile };\n heldLocks.set(normalized, held);\n\n return {\n release: async () => {\n await releaseHeldLock(normalized, held);\n },\n };\n}\n\nexport async function withTranscriptFileLock<T>(\n transcriptAbsPath: string,\n fn: () => Promise<T>,\n opts?: { timeoutMs?: number; staleMs?: number },\n): Promise<T> {\n const lock = await acquireTranscriptFileLock(transcriptAbsPath, opts);\n try {\n return await fn();\n } finally {\n await lock.release();\n }\n}\n\n/** Best-effort: remove a stale lock without acquiring (e.g. doctor tooling). */\nexport async function tryRemoveStaleTranscriptLock(\n transcriptAbsPath: string,\n staleMs: number = DEFAULT_STALE_MS,\n): Promise<boolean> {\n const lockFile = lockPathFor(normalizeTranscriptPath(transcriptAbsPath));\n if (!existsSync(lockFile)) {\n return false;\n }\n if (!(await isStaleLock(lockFile, staleMs))) {\n return false;\n }\n await rm(lockFile, { force: true });\n return true;\n}\n"],"mappings":"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"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { AgentMessage } from '@earendil-works/pi-agent-core';
|
|
2
|
-
import type { TranscriptStoredRow } from '../session-context-for-llm.js';
|
|
3
|
-
export type TranscriptPageOptions = {
|
|
4
|
-
limit: number;
|
|
5
|
-
/** Exclusive end index into display message rows (default: total). */
|
|
6
|
-
beforeIndex?: number;
|
|
7
|
-
/** Tail offset (used when `beforeIndex` is omitted). */
|
|
8
|
-
offset?: number;
|
|
9
|
-
};
|
|
10
|
-
export type TranscriptPageResult = {
|
|
11
|
-
rows: TranscriptStoredRow[];
|
|
12
|
-
total: number;
|
|
13
|
-
startIndex: number;
|
|
14
|
-
endIndex: number;
|
|
15
|
-
};
|
|
16
|
-
/**
|
|
17
|
-
* Count persisted pi `type: message` rows (excludes context custom rows).
|
|
18
|
-
*/
|
|
19
|
-
export declare function countTranscriptMessageRows(absPath: string): Promise<number>;
|
|
20
|
-
/**
|
|
21
|
-
* Read a page of display messages from transcript tail (newest page when cursors omitted).
|
|
22
|
-
*/
|
|
23
|
-
export declare function readDisplayMessagePageFromTranscriptFile(absPath: string, options: TranscriptPageOptions): Promise<TranscriptPageResult & {
|
|
24
|
-
messages: AgentMessage[];
|
|
25
|
-
}>;
|
|
26
|
-
/**
|
|
27
|
-
* Read a page of transcript rows from the tail (newest page when `beforeIndex` omitted).
|
|
28
|
-
*/
|
|
29
|
-
export declare function readTranscriptRowsPageFromFile(absPath: string, options: TranscriptPageOptions): Promise<TranscriptPageResult>;
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import "./jsonl-transcript-io.js";
|
|
2
|
-
import { existsSync } from "node:fs";
|
|
3
|
-
import { readFile } from "node:fs/promises";
|
|
4
|
-
//#region src/session/parity/transcript-pagination.ts
|
|
5
|
-
function classifyLine(line) {
|
|
6
|
-
const trimmed = line.trim();
|
|
7
|
-
if (!trimmed) return "other";
|
|
8
|
-
if (trimmed.includes("\"type\":\"session\"") || trimmed.includes("\"type\": \"session\"")) return "session";
|
|
9
|
-
if (trimmed.includes("\"type\":\"message\"") || trimmed.includes("\"type\": \"message\"")) return "message";
|
|
10
|
-
if (trimmed.includes(`"xopc:transcript-row"`) || trimmed.includes("\"type\":\"custom\"")) return "context";
|
|
11
|
-
return "other";
|
|
12
|
-
}
|
|
13
|
-
function parseStoredRow(line, kind) {
|
|
14
|
-
try {
|
|
15
|
-
const parsed = JSON.parse(line);
|
|
16
|
-
if (kind === "message" && parsed.message) return parsed.message;
|
|
17
|
-
if (kind === "context" && parsed.type === "custom") {
|
|
18
|
-
const data = parsed.data;
|
|
19
|
-
if (!data || data.kind !== "context") return null;
|
|
20
|
-
return {
|
|
21
|
-
kind: "context",
|
|
22
|
-
id: typeof data.id === "string" ? data.id : void 0,
|
|
23
|
-
text: typeof data.text === "string" ? data.text : void 0,
|
|
24
|
-
data: data.data,
|
|
25
|
-
createdAt: typeof data.createdAt === "string" ? data.createdAt : void 0
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
} catch {
|
|
29
|
-
return null;
|
|
30
|
-
}
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Count persisted pi `type: message` rows (excludes context custom rows).
|
|
35
|
-
*/
|
|
36
|
-
async function countTranscriptMessageRows(absPath) {
|
|
37
|
-
if (!existsSync(absPath)) return 0;
|
|
38
|
-
const content = await readFile(absPath, "utf8");
|
|
39
|
-
let count = 0;
|
|
40
|
-
for (const line of content.split("\n")) if (classifyLine(line) === "message") count += 1;
|
|
41
|
-
return count;
|
|
42
|
-
}
|
|
43
|
-
function isCompactionSummaryLine(line) {
|
|
44
|
-
return line.includes("[Previous conversation summary]");
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Read a page of display messages from transcript tail (newest page when cursors omitted).
|
|
48
|
-
*/
|
|
49
|
-
async function readDisplayMessagePageFromTranscriptFile(absPath, options) {
|
|
50
|
-
if (!existsSync(absPath)) return {
|
|
51
|
-
rows: [],
|
|
52
|
-
messages: [],
|
|
53
|
-
total: 0,
|
|
54
|
-
startIndex: 0,
|
|
55
|
-
endIndex: 0
|
|
56
|
-
};
|
|
57
|
-
const limit = Math.max(1, Math.trunc(options.limit));
|
|
58
|
-
const content = await readFile(absPath, "utf8");
|
|
59
|
-
const displayLines = [];
|
|
60
|
-
for (const line of content.split("\n")) {
|
|
61
|
-
const kind = classifyLine(line);
|
|
62
|
-
if (kind !== "message") continue;
|
|
63
|
-
if (isCompactionSummaryLine(line)) continue;
|
|
64
|
-
displayLines.push({
|
|
65
|
-
line,
|
|
66
|
-
kind
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
const total = displayLines.length;
|
|
70
|
-
const offset = Math.max(0, Math.trunc(options.offset ?? 0));
|
|
71
|
-
const endExclusive = options.beforeIndex !== void 0 ? Math.min(total, Math.max(0, Math.trunc(options.beforeIndex))) : Math.max(0, total - offset);
|
|
72
|
-
const startInclusive = Math.max(0, endExclusive - limit);
|
|
73
|
-
const slice = displayLines.slice(startInclusive, endExclusive);
|
|
74
|
-
const rows = [];
|
|
75
|
-
const messages = [];
|
|
76
|
-
for (const item of slice) {
|
|
77
|
-
const row = parseStoredRow(item.line, item.kind);
|
|
78
|
-
if (row && typeof row.role === "string") {
|
|
79
|
-
rows.push(row);
|
|
80
|
-
messages.push(row);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return {
|
|
84
|
-
rows,
|
|
85
|
-
messages,
|
|
86
|
-
total,
|
|
87
|
-
startIndex: startInclusive,
|
|
88
|
-
endIndex: endExclusive
|
|
89
|
-
};
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Read a page of transcript rows from the tail (newest page when `beforeIndex` omitted).
|
|
93
|
-
*/
|
|
94
|
-
async function readTranscriptRowsPageFromFile(absPath, options) {
|
|
95
|
-
if (!existsSync(absPath)) return {
|
|
96
|
-
rows: [],
|
|
97
|
-
total: 0,
|
|
98
|
-
startIndex: 0,
|
|
99
|
-
endIndex: 0
|
|
100
|
-
};
|
|
101
|
-
const limit = Math.max(1, Math.trunc(options.limit));
|
|
102
|
-
const content = await readFile(absPath, "utf8");
|
|
103
|
-
const parsedLines = [];
|
|
104
|
-
for (const line of content.split("\n")) {
|
|
105
|
-
const kind = classifyLine(line);
|
|
106
|
-
if (kind === "session" || kind === "other") continue;
|
|
107
|
-
parsedLines.push({
|
|
108
|
-
line,
|
|
109
|
-
kind
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
const total = parsedLines.length;
|
|
113
|
-
const offset = Math.max(0, Math.trunc(options.offset ?? 0));
|
|
114
|
-
const endExclusive = options.beforeIndex !== void 0 ? Math.min(total, Math.max(0, Math.trunc(options.beforeIndex))) : Math.max(0, total - offset);
|
|
115
|
-
const startInclusive = Math.max(0, endExclusive - limit);
|
|
116
|
-
const slice = parsedLines.slice(startInclusive, endExclusive);
|
|
117
|
-
const rows = [];
|
|
118
|
-
for (const item of slice) {
|
|
119
|
-
const row = parseStoredRow(item.line, item.kind);
|
|
120
|
-
if (row) rows.push(row);
|
|
121
|
-
}
|
|
122
|
-
return {
|
|
123
|
-
rows,
|
|
124
|
-
total,
|
|
125
|
-
startIndex: startInclusive,
|
|
126
|
-
endIndex: endExclusive
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
//#endregion
|
|
130
|
-
export { countTranscriptMessageRows, readDisplayMessagePageFromTranscriptFile, readTranscriptRowsPageFromFile };
|
|
131
|
-
|
|
132
|
-
//# sourceMappingURL=transcript-pagination.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"transcript-pagination.js","names":[],"sources":["../../../../src/session/parity/transcript-pagination.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises';\nimport { existsSync } from 'node:fs';\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport type { TranscriptStoredRow, XopcTranscriptContextEntry } from '../session-context-for-llm.js';\nimport { XOPC_CONTEXT_CUSTOM_TYPE } from './jsonl-transcript-io.js';\n\nexport type TranscriptPageOptions = {\n limit: number;\n /** Exclusive end index into display message rows (default: total). */\n beforeIndex?: number;\n /** Tail offset (used when `beforeIndex` is omitted). */\n offset?: number;\n};\n\nexport type TranscriptPageResult = {\n rows: TranscriptStoredRow[];\n total: number;\n startIndex: number;\n endIndex: number;\n};\n\ntype ParsedLine = {\n line: string;\n kind: 'session' | 'message' | 'context' | 'other';\n};\n\nfunction classifyLine(line: string): ParsedLine['kind'] {\n const trimmed = line.trim();\n if (!trimmed) {\n return 'other';\n }\n if (trimmed.includes('\"type\":\"session\"') || trimmed.includes('\"type\": \"session\"')) {\n return 'session';\n }\n if (trimmed.includes('\"type\":\"message\"') || trimmed.includes('\"type\": \"message\"')) {\n return 'message';\n }\n if (trimmed.includes(`\"${XOPC_CONTEXT_CUSTOM_TYPE}\"`) || trimmed.includes('\"type\":\"custom\"')) {\n return 'context';\n }\n return 'other';\n}\n\nfunction parseStoredRow(line: string, kind: ParsedLine['kind']): TranscriptStoredRow | null {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (kind === 'message' && parsed.message) {\n return parsed.message as AgentMessage;\n }\n if (kind === 'context' && parsed.type === 'custom') {\n const data = parsed.data as Record<string, unknown> | undefined;\n if (!data || data.kind !== 'context') {\n return null;\n }\n return {\n kind: 'context',\n id: typeof data.id === 'string' ? data.id : undefined,\n text: typeof data.text === 'string' ? data.text : undefined,\n data: data.data as Record<string, unknown> | undefined,\n createdAt: typeof data.createdAt === 'string' ? data.createdAt : undefined,\n } satisfies XopcTranscriptContextEntry;\n }\n } catch {\n return null;\n }\n return null;\n}\n\n/**\n * Count persisted pi `type: message` rows (excludes context custom rows).\n */\nexport async function countTranscriptMessageRows(absPath: string): Promise<number> {\n if (!existsSync(absPath)) {\n return 0;\n }\n const content = await readFile(absPath, 'utf8');\n let count = 0;\n for (const line of content.split('\\n')) {\n const kind = classifyLine(line);\n if (kind === 'message') {\n count += 1;\n }\n }\n return count;\n}\n\nfunction isCompactionSummaryLine(line: string): boolean {\n return line.includes('[Previous conversation summary]');\n}\n\n/**\n * Read a page of display messages from transcript tail (newest page when cursors omitted).\n */\nexport async function readDisplayMessagePageFromTranscriptFile(\n absPath: string,\n options: TranscriptPageOptions,\n): Promise<TranscriptPageResult & { messages: AgentMessage[] }> {\n if (!existsSync(absPath)) {\n return { rows: [], messages: [], total: 0, startIndex: 0, endIndex: 0 };\n }\n\n const limit = Math.max(1, Math.trunc(options.limit));\n const content = await readFile(absPath, 'utf8');\n const displayLines: ParsedLine[] = [];\n for (const line of content.split('\\n')) {\n const kind = classifyLine(line);\n if (kind !== 'message') {\n continue;\n }\n if (isCompactionSummaryLine(line)) {\n continue;\n }\n displayLines.push({ line, kind });\n }\n\n const total = displayLines.length;\n const offset = Math.max(0, Math.trunc(options.offset ?? 0));\n const endExclusive =\n options.beforeIndex !== undefined\n ? Math.min(total, Math.max(0, Math.trunc(options.beforeIndex)))\n : Math.max(0, total - offset);\n const startInclusive = Math.max(0, endExclusive - limit);\n const slice = displayLines.slice(startInclusive, endExclusive);\n const rows: TranscriptStoredRow[] = [];\n const messages: AgentMessage[] = [];\n for (const item of slice) {\n const row = parseStoredRow(item.line, item.kind);\n if (row && typeof (row as AgentMessage).role === 'string') {\n rows.push(row);\n messages.push(row as AgentMessage);\n }\n }\n\n return {\n rows,\n messages,\n total,\n startIndex: startInclusive,\n endIndex: endExclusive,\n };\n}\n\n/**\n * Read a page of transcript rows from the tail (newest page when `beforeIndex` omitted).\n */\nexport async function readTranscriptRowsPageFromFile(\n absPath: string,\n options: TranscriptPageOptions,\n): Promise<TranscriptPageResult> {\n if (!existsSync(absPath)) {\n return { rows: [], total: 0, startIndex: 0, endIndex: 0 };\n }\n\n const limit = Math.max(1, Math.trunc(options.limit));\n const content = await readFile(absPath, 'utf8');\n const parsedLines: ParsedLine[] = [];\n for (const line of content.split('\\n')) {\n const kind = classifyLine(line);\n if (kind === 'session' || kind === 'other') {\n continue;\n }\n parsedLines.push({ line, kind });\n }\n\n const total = parsedLines.length;\n const offset = Math.max(0, Math.trunc(options.offset ?? 0));\n const endExclusive =\n options.beforeIndex !== undefined\n ? Math.min(total, Math.max(0, Math.trunc(options.beforeIndex)))\n : Math.max(0, total - offset);\n const startInclusive = Math.max(0, endExclusive - limit);\n const slice = parsedLines.slice(startInclusive, endExclusive);\n const rows: TranscriptStoredRow[] = [];\n for (const item of slice) {\n const row = parseStoredRow(item.line, item.kind);\n if (row) {\n rows.push(row);\n }\n }\n\n return {\n rows,\n total,\n startIndex: startInclusive,\n endIndex: endExclusive,\n };\n}\n"],"mappings":"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"}
|