@abot-ai/runtime 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/src/bridge/request-steering.js +60 -15
- package/dist/src/capabilities/normal-invocation/contracts.d.ts +3 -0
- package/dist/src/capabilities/normal-invocation/output-channels.d.ts +10 -0
- package/dist/src/capabilities/normal-invocation/output-channels.js +29 -0
- package/dist/src/capabilities/normal-invocation/validator.js +4 -2
- package/dist/src/capabilities/tool-types.d.ts +1 -1
- package/dist/src/cli/host-companion-bundle.mjs +7570 -6781
- package/dist/src/cli/host-companion-entry.js +5 -22
- package/dist/src/cli/host-companion-input.d.ts +3 -0
- package/dist/src/cli/host-companion-input.js +21 -0
- package/dist/src/cli/host-companion-lifecycle.d.ts +11 -0
- package/dist/src/cli/host-companion-lifecycle.js +32 -0
- package/dist/src/cli/host-companion-setup-target.d.ts +4 -0
- package/dist/src/cli/host-companion-setup-target.js +17 -0
- package/dist/src/cli/host-companion-startup.d.ts +2 -0
- package/dist/src/cli/host-companion-startup.js +7 -2
- package/dist/src/cli/host-companion.d.ts +6 -0
- package/dist/src/cli/host-companion.js +30 -27
- package/dist/src/cli/windows-companion-store-entry.d.ts +9 -0
- package/dist/src/cli/windows-companion-store-entry.js +67 -0
- package/dist/src/computer-access/command-output-capture.d.ts +37 -0
- package/dist/src/computer-access/command-output-capture.js +136 -0
- package/dist/src/computer-access/command-output-retention.d.ts +5 -0
- package/dist/src/computer-access/command-output-retention.js +90 -0
- package/dist/src/computer-access/command-output.d.ts +7 -0
- package/dist/src/computer-access/command-output.js +1 -0
- package/dist/src/computer-access/commands.d.ts +1 -0
- package/dist/src/computer-access/commands.js +1 -1
- package/dist/src/computer-access/companion/command-output-protocol.d.ts +12 -0
- package/dist/src/computer-access/companion/command-output-protocol.js +28 -0
- package/dist/src/computer-access/companion/command-output.d.ts +13 -0
- package/dist/src/computer-access/companion/command-output.js +110 -0
- package/dist/src/computer-access/companion/install-link-macos.d.ts +7 -0
- package/dist/src/computer-access/companion/install-link-macos.js +48 -0
- package/dist/src/computer-access/companion/install-link-registration.d.ts +4 -0
- package/dist/src/computer-access/companion/install-link-registration.js +184 -0
- package/dist/src/computer-access/companion/install-link-windows.d.ts +4 -0
- package/dist/src/computer-access/companion/install-link-windows.js +65 -0
- package/dist/src/computer-access/companion/install-link.d.ts +9 -0
- package/dist/src/computer-access/companion/install-link.js +54 -0
- package/dist/src/computer-access/companion/native-messages.js +3 -0
- package/dist/src/computer-access/companion/native-session.d.ts +1 -0
- package/dist/src/computer-access/companion/native-session.js +14 -2
- package/dist/src/computer-access/companion/native-supervisor.js +1 -0
- package/dist/src/computer-access/companion/notification-windows.d.ts +1 -1
- package/dist/src/computer-access/companion/notification-windows.js +8 -3
- package/dist/src/computer-access/companion/protocol.d.ts +1 -1
- package/dist/src/computer-access/companion/protocol.js +6 -0
- package/dist/src/computer-access/companion/release-version.d.ts +1 -1
- package/dist/src/computer-access/companion/release-version.js +1 -1
- package/dist/src/computer-access/companion/windows-store/connection-error.d.ts +7 -0
- package/dist/src/computer-access/companion/windows-store/connection-error.js +19 -0
- package/dist/src/computer-access/companion/windows-store/connection-link.d.ts +13 -0
- package/dist/src/computer-access/companion/windows-store/connection-link.js +109 -0
- package/dist/src/computer-access/companion/windows-store/identity.d.ts +13 -0
- package/dist/src/computer-access/companion/windows-store/identity.js +13 -0
- package/dist/src/computer-access/companion/windows-store/lifecycle.d.ts +5 -0
- package/dist/src/computer-access/companion/windows-store/lifecycle.js +90 -0
- package/dist/src/computer-access/contracts.d.ts +1 -1
- package/dist/src/computer-access/handlers.d.ts +2 -1
- package/dist/src/computer-access/handlers.js +5 -1
- package/dist/src/computer-access/process-capture.d.ts +6 -0
- package/dist/src/computer-access/process-capture.js +1 -0
- package/dist/src/computer-access/process-result.d.ts +2 -0
- package/dist/src/computer-access/process-result.js +14 -6
- package/dist/src/computer-access/process-runner.d.ts +2 -1
- package/dist/src/computer-access/process-runner.js +21 -13
- package/dist/src/model-gateway/server/configuration.d.ts +2 -0
- package/dist/src/model-gateway/server/configuration.js +73 -21
- package/dist/src/plugin-contract/install-source.d.ts +13 -0
- package/dist/src/plugin-contract/install-source.js +99 -0
- package/dist/src/plugin-contract/manifest.d.ts +2 -1
- package/dist/src/plugin-sdk/computer-access.d.ts +8 -0
- package/dist/src/plugin-sdk/computer-access.js +5 -0
- package/dist/src/runtime/adapters/in-memory-session-store.js +6 -16
- package/dist/src/runtime/admin/config-control.js +2 -1
- package/dist/src/runtime/automations/catalog.d.ts +3 -0
- package/dist/src/runtime/automations/catalog.js +1 -0
- package/dist/src/runtime/automations/model-dependency-projection.d.ts +2 -0
- package/dist/src/runtime/automations/service.d.ts +2 -0
- package/dist/src/runtime/capabilities/automation-builder/authoring-reference.d.ts +10 -5
- package/dist/src/runtime/capabilities/automation-builder/authoring-reference.js +8 -7
- package/dist/src/runtime/capabilities/automation-builder/payload-instructions.d.ts +2 -2
- package/dist/src/runtime/capabilities/automation-builder/payload-instructions.js +2 -2
- package/dist/src/runtime/capabilities/automation-builder/tool-contract.d.ts +2 -2
- package/dist/src/runtime/capabilities/automations/authoring-catalog.js +1 -1
- package/dist/src/runtime/capabilities/automations/authoring-preparation.d.ts +11 -5
- package/dist/src/runtime/capabilities/automations/tool-module.js +1 -1
- package/dist/src/runtime/capabilities/request-permission-catalog.d.ts +3 -1
- package/dist/src/runtime/capabilities/request-permission-catalog.js +21 -2
- package/dist/src/runtime/capabilities/request-permission-tool-registry.d.ts +2 -1
- package/dist/src/runtime/capabilities/request-permission-tool-registry.js +18 -10
- package/dist/src/runtime/capabilities/request-runtime-tool-registry.d.ts +2 -0
- package/dist/src/runtime/capabilities/request-runtime-tool-registry.js +1 -1
- package/dist/src/runtime/capabilities/scheduling/create-operations.d.ts +6 -0
- package/dist/src/runtime/config/builders.js +6 -5
- package/dist/src/runtime/config/effective-model-config-validation.js +4 -35
- package/dist/src/runtime/config/fields.js +15 -0
- package/dist/src/runtime/config/model-context-capacity.d.ts +20 -0
- package/dist/src/runtime/config/model-context-capacity.js +55 -0
- package/dist/src/runtime/config/model-execution-policy.d.ts +5 -1
- package/dist/src/runtime/config/model-execution-policy.js +16 -0
- package/dist/src/runtime/config/model-plugin-config.d.ts +8 -0
- package/dist/src/runtime/config/model-plugin-config.js +40 -0
- package/dist/src/runtime/config/schema.js +5 -1
- package/dist/src/runtime/config/validation/model-profile-validation.js +2 -0
- package/dist/src/runtime/config/validation/runtime-config-validation-contract.d.ts +3 -1
- package/dist/src/runtime/config/validation/runtime-config-validation-contract.js +3 -1
- package/dist/src/runtime/config/validation/runtime-root-section-validation.js +11 -4
- package/dist/src/runtime/config/validation/web-ui-config-validation.js +3 -2
- package/dist/src/runtime/config/web-ui.d.ts +5 -0
- package/dist/src/runtime/config/web-ui.js +5 -0
- package/dist/src/runtime/config.js +2 -0
- package/dist/src/runtime/local-application.d.ts +2 -0
- package/dist/src/runtime/local-host/app-owner.js +50 -6
- package/dist/src/runtime/local-host/app-request-control.d.ts +3 -1
- package/dist/src/runtime/local-host/app-request-control.js +91 -11
- package/dist/src/runtime/local-host/client-requests.js +32 -5
- package/dist/src/runtime/local-host/client-services.d.ts +2 -0
- package/dist/src/runtime/local-host/local-request-diagnostics.d.ts +9 -0
- package/dist/src/runtime/local-host/local-request-diagnostics.js +47 -0
- package/dist/src/runtime/local-host/saved-approvals.js +23 -2
- package/dist/src/runtime/model/model-selection.js +4 -1
- package/dist/src/runtime/observability/request-control-diagnostics.d.ts +6 -0
- package/dist/src/runtime/observability/request-control-diagnostics.js +52 -0
- package/dist/src/runtime/plugins/configuration-context.d.ts +9 -0
- package/dist/src/runtime/plugins/configuration-context.js +42 -0
- package/dist/src/runtime/plugins/configuration-settings.d.ts +2 -0
- package/dist/src/runtime/plugins/configuration-settings.js +26 -0
- package/dist/src/runtime/plugins/configuration-store.d.ts +23 -0
- package/dist/src/runtime/plugins/configuration-store.js +100 -0
- package/dist/src/runtime/plugins/configuration-write.d.ts +5 -0
- package/dist/src/runtime/plugins/configuration-write.js +58 -0
- package/dist/src/runtime/plugins/installation/archive.d.ts +2 -0
- package/dist/src/runtime/plugins/installation/archive.js +107 -0
- package/dist/src/runtime/plugins/installation/github-download.d.ts +9 -0
- package/dist/src/runtime/plugins/installation/github-download.js +72 -0
- package/dist/src/runtime/plugins/installation/installed-package.d.ts +9 -0
- package/dist/src/runtime/plugins/installation/installed-package.js +66 -0
- package/dist/src/runtime/plugins/installation/package.d.ts +45 -0
- package/dist/src/runtime/plugins/installation/package.js +79 -0
- package/dist/src/runtime/plugins/installation/portable-path.d.ts +2 -0
- package/dist/src/runtime/plugins/installation/portable-path.js +10 -0
- package/dist/src/runtime/plugins/installation/publication.d.ts +10 -0
- package/dist/src/runtime/plugins/installation/publication.js +17 -0
- package/dist/src/runtime/plugins/installation/service.d.ts +41 -0
- package/dist/src/runtime/plugins/installation/service.js +80 -0
- package/dist/src/runtime/plugins/loader.js +15 -29
- package/dist/src/runtime/plugins/manifest-projection.js +1 -0
- package/dist/src/runtime/plugins/manifest-validator.js +3 -0
- package/dist/src/runtime/plugins/module-cache.d.ts +2 -0
- package/dist/src/runtime/plugins/module-cache.js +19 -0
- package/dist/src/runtime/plugins/selection.d.ts +2 -0
- package/dist/src/runtime/plugins/selection.js +16 -11
- package/dist/src/runtime/ports.d.ts +6 -4
- package/dist/src/runtime/request/dependencies.d.ts +2 -1
- package/dist/src/runtime/request/execution-payload-compacted-evidence.d.ts +1 -1
- package/dist/src/runtime/request/handler.js +8 -0
- package/dist/src/runtime/request/prepared-execution.js +6 -1
- package/dist/src/runtime/request/request-steering.d.ts +4 -0
- package/dist/src/runtime/request/request-steering.js +37 -12
- package/dist/src/runtime/request/worker-capability-composition.d.ts +2 -0
- package/dist/src/runtime/request/worker-capability-composition.js +4 -1
- package/dist/src/runtime/scheduler/journal-index-state.d.ts +1 -1
- package/dist/src/sessions/assistant-initiative-message.d.ts +3 -0
- package/dist/src/sessions/assistant-initiative-message.js +12 -0
- package/dist/src/sessions/assistant-initiative.d.ts +2 -2
- package/dist/src/sessions/assistant-initiative.js +1 -7
- package/dist/src/sessions/durable-session-commit.d.ts +2 -1
- package/dist/src/sessions/durable-session-commit.js +6 -1
- package/dist/src/sessions/metadata/projection.d.ts +15 -0
- package/dist/src/sessions/metadata/projection.js +55 -0
- package/dist/src/sessions/metadata/publication.d.ts +12 -0
- package/dist/src/sessions/metadata/publication.js +78 -0
- package/dist/src/sessions/metadata/source-receipt.d.ts +5 -0
- package/dist/src/sessions/metadata/source-receipt.js +42 -0
- package/dist/src/sessions/metadata/store.d.ts +7 -0
- package/dist/src/sessions/metadata/store.js +119 -0
- package/dist/src/sessions/record/projection.d.ts +3 -1
- package/dist/src/sessions/record/projection.js +26 -18
- package/dist/src/sessions/request-lifecycle/service.js +3 -3
- package/dist/src/sessions/session-service.d.ts +2 -4
- package/dist/src/sessions/session-service.js +4 -16
- package/dist/src/sessions/session-store.d.ts +2 -1
- package/dist/src/sessions/session-store.js +9 -3
- package/dist/src/sessions/snapshot.d.ts +17 -0
- package/dist/src/sessions/snapshot.js +105 -0
- package/dist/src/sessions/types.d.ts +2 -0
- package/dist/src/shared/tool-selection.d.ts +2 -0
- package/dist/src/shared/tool-selection.js +7 -0
- package/dist/src/web-ui/app/ARCHITECTURE.md +14 -0
- package/dist/src/web-ui/app/app.js +6 -3
- package/dist/src/web-ui/app/components/config-workspace/config-model.js +2 -0
- package/dist/src/web-ui/app/components/config-workspace/model-plugin-permissions.js +130 -0
- package/dist/src/web-ui/app/components/config-workspace/model-plugin-selection.js +180 -0
- package/dist/src/web-ui/app/components/config-workspace/model-plugin-view-state.js +114 -0
- package/dist/src/web-ui/app/components/config-workspace/model-rendering.js +3 -0
- package/dist/src/web-ui/app/components/config-workspace/model-summary.js +39 -0
- package/dist/src/web-ui/app/components/config-workspace/summary-rendering.js +30 -0
- package/dist/src/web-ui/app/components/config-workspace/workspace-events.js +37 -0
- package/dist/src/web-ui/app/components/config-workspace/workspace-mutations.js +2 -0
- package/dist/src/web-ui/app/components/config-workspace/workspace-persistence.js +9 -1
- package/dist/src/web-ui/app/components/config-workspace/workspace-view.js +23 -67
- package/dist/src/web-ui/app/components/config-workspace.js +11 -2
- package/dist/src/web-ui/app/components/conversation-view.js +36 -5
- package/dist/src/web-ui/app/components/dashboard/recent-conversations.js +2 -1
- package/dist/src/web-ui/app/components/dashboard/workspace.js +2 -1
- package/dist/src/web-ui/app/components/operations-summary.js +105 -0
- package/dist/src/web-ui/app/components/passive-learning/home.js +1 -9
- package/dist/src/web-ui/app/components/plugins/configuration-draft.js +34 -0
- package/dist/src/web-ui/app/components/plugins/configuration-editor.js +147 -0
- package/dist/src/web-ui/app/components/plugins/configuration-fields.js +103 -0
- package/dist/src/web-ui/app/components/plugins/configuration-retained-secrets.js +20 -0
- package/dist/src/web-ui/app/components/plugins/configuration-settings.js +108 -0
- package/dist/src/web-ui/app/components/plugins/discovery-rendering.js +37 -0
- package/dist/src/web-ui/app/components/plugins/installation.js +212 -0
- package/dist/src/web-ui/app/components/plugins/manager.js +160 -6
- package/dist/src/web-ui/app/components/plugins/removal.js +130 -0
- package/dist/src/web-ui/app/components/plugins/rendering.js +14 -2
- package/dist/src/web-ui/app/components/plugins/summary.js +54 -0
- package/dist/src/web-ui/app/components/plugins/tabs.js +31 -0
- package/dist/src/web-ui/app/components/plugins/view-state.js +3 -1
- package/dist/src/web-ui/app/components/runtime-setup/connection-form.js +5 -2
- package/dist/src/web-ui/app/components/runtime-setup/connection-state.js +9 -1
- package/dist/src/web-ui/app/components/runtime-setup/context-window-feedback.js +71 -0
- package/dist/src/web-ui/app/components/runtime-setup/optional-steps.js +2 -0
- package/dist/src/web-ui/app/components/runtime-setup-guide.js +15 -3
- package/dist/src/web-ui/app/components/spark-chat/empty-state.js +1 -0
- package/dist/src/web-ui/app/components/spark-chat/panel.js +1 -0
- package/dist/src/web-ui/app/components/system-host/connection-card.js +35 -0
- package/dist/src/web-ui/app/components/system-host/macos-setup.js +1 -1
- package/dist/src/web-ui/app/components/system-host/manager.js +45 -12
- package/dist/src/web-ui/app/components/system-host/rendering.js +111 -106
- package/dist/src/web-ui/app/components/system-host/windows-store-setup.js +293 -0
- package/dist/src/web-ui/app/components/workspace-shell.js +6 -0
- package/dist/src/web-ui/app/computer-access-feature.js +22 -5
- package/dist/src/web-ui/app/configuration-feature.js +35 -2
- package/dist/src/web-ui/app/controllers/app-event-bindings.js +4 -1
- package/dist/src/web-ui/app/controllers/conversation-read-state-controller.d.ts +1 -0
- package/dist/src/web-ui/app/controllers/conversation-read-state-controller.js +7 -3
- package/dist/src/web-ui/app/controllers/conversation-request-hydration.js +88 -0
- package/dist/src/web-ui/app/controllers/conversation-session-controller.d.ts +9 -3
- package/dist/src/web-ui/app/controllers/conversation-session-controller.js +52 -144
- package/dist/src/web-ui/app/controllers/history-pagination.js +111 -0
- package/dist/src/web-ui/app/controllers/operations-controller.d.ts +12 -0
- package/dist/src/web-ui/app/controllers/operations-controller.js +28 -21
- package/dist/src/web-ui/app/controllers/runtime-onboarding-controller.d.ts +1 -0
- package/dist/src/web-ui/app/controllers/runtime-onboarding-controller.js +11 -0
- package/dist/src/web-ui/app/controllers/session-controller.js +10 -2
- package/dist/src/web-ui/app/controllers/session-list-pagination.js +71 -0
- package/dist/src/web-ui/app/controllers/session-sidebar-controller.js +6 -4
- package/dist/src/web-ui/app/controllers/spark-chat-reading.js +1 -0
- package/dist/src/web-ui/app/controllers/spark-chat-sync.js +24 -5
- package/dist/src/web-ui/app/controllers/workspace-route-controller.js +21 -19
- package/dist/src/web-ui/app/dashboard-feature.js +2 -2
- package/dist/src/web-ui/app/index.html +6 -2
- package/dist/src/web-ui/app/lib/history-page-messages.js +49 -0
- package/dist/src/web-ui/app/lib/request-lifecycle-view.js +8 -0
- package/dist/src/web-ui/app/lib/workspace-route.d.ts +3 -0
- package/dist/src/web-ui/app/lib/workspace-route.js +4 -0
- package/dist/src/web-ui/app/passive-learning-feature.js +0 -1
- package/dist/src/web-ui/app/runtime-onboarding-feature.js +3 -0
- package/dist/src/web-ui/app/schedules-feature.js +1 -1
- package/dist/src/web-ui/app/services/runtime-web-client/configuration.js +20 -0
- package/dist/src/web-ui/app/services/runtime-web-client/plugin-configuration.js +19 -0
- package/dist/src/web-ui/app/services/runtime-web-client/spark-chat.js +4 -4
- package/dist/src/web-ui/app/services/runtime-web-client/system-host.js +2 -0
- package/dist/src/web-ui/app/services/runtime-web-client.d.ts +6 -1
- package/dist/src/web-ui/app/services/runtime-web-client.js +12 -3
- package/dist/src/web-ui/app/spark-chat-feature.js +76 -19
- package/dist/src/web-ui/app/styles/11-product-links.css +30 -0
- package/dist/src/web-ui/app/styles/41-plugin-configuration.css +79 -0
- package/dist/src/web-ui/app/styles/41-plugin-discovery.css +132 -0
- package/dist/src/web-ui/app/styles/41-plugin-management.css +6 -0
- package/dist/src/web-ui/app/styles/42-model-plugin-permissions.css +173 -0
- package/dist/src/web-ui/app/styles/46-system-host.css +61 -107
- package/dist/src/web-ui/app/styles/47-config-controls.css +13 -1
- package/dist/src/web-ui/app/styles/54-spark-chat.css +33 -1
- package/dist/src/web-ui/app/styles.css +4 -0
- package/dist/src/web-ui/local-runtime/api-router.js +11 -6
- package/dist/src/web-ui/local-runtime/approval-request-attachment.js +14 -5
- package/dist/src/web-ui/local-runtime/configuration-activation-source.d.ts +1 -1
- package/dist/src/web-ui/local-runtime/configuration-activation-source.js +9 -3
- package/dist/src/web-ui/local-runtime/contracts.d.ts +4 -3
- package/dist/src/web-ui/local-runtime/environment-registry.d.ts +5 -1
- package/dist/src/web-ui/local-runtime/environment-registry.js +53 -11
- package/dist/src/web-ui/local-runtime/history-pagination.d.ts +16 -0
- package/dist/src/web-ui/local-runtime/history-pagination.js +20 -0
- package/dist/src/web-ui/local-runtime/plugin-configuration-routes.d.ts +16 -0
- package/dist/src/web-ui/local-runtime/plugin-configuration-routes.js +68 -0
- package/dist/src/web-ui/local-runtime/plugin-installation-routes.d.ts +16 -0
- package/dist/src/web-ui/local-runtime/plugin-installation-routes.js +96 -0
- package/dist/src/web-ui/local-runtime/plugin-management-routes.d.ts +8 -1
- package/dist/src/web-ui/local-runtime/plugin-management-routes.js +17 -0
- package/dist/src/web-ui/local-runtime/plugin-mutation-admission.d.ts +7 -0
- package/dist/src/web-ui/local-runtime/plugin-mutation-admission.js +17 -0
- package/dist/src/web-ui/local-runtime/plugin-removal-routes.d.ts +18 -0
- package/dist/src/web-ui/local-runtime/plugin-removal-routes.js +60 -0
- package/dist/src/web-ui/local-runtime/realtime-controller.js +41 -2
- package/dist/src/web-ui/local-runtime/request-cancellation-route.js +28 -1
- package/dist/src/web-ui/local-runtime/request-control-observation.d.ts +19 -0
- package/dist/src/web-ui/local-runtime/request-control-observation.js +80 -0
- package/dist/src/web-ui/local-runtime/request-execution.js +69 -37
- package/dist/src/web-ui/local-runtime/runtime-setup-context-window.d.ts +20 -0
- package/dist/src/web-ui/local-runtime/runtime-setup-context-window.js +44 -0
- package/dist/src/web-ui/local-runtime/runtime-setup-routes.js +2 -0
- package/dist/src/web-ui/local-runtime/runtime-setup-validation.js +9 -2
- package/dist/src/web-ui/local-runtime/session-routes.d.ts +1 -0
- package/dist/src/web-ui/local-runtime/session-routes.js +16 -4
- package/dist/src/web-ui/local-runtime/spark-chat-routes.js +4 -3
- package/dist/src/web-ui/plugin-capability-selection.js +4 -1
- package/dist/src/web-ui/plugin-configuration-input.d.ts +12 -0
- package/dist/src/web-ui/plugin-configuration-input.js +68 -0
- package/dist/src/web-ui/plugin-configuration-retained-secrets.d.ts +9 -0
- package/dist/src/web-ui/plugin-configuration-retained-secrets.js +48 -0
- package/dist/src/web-ui/plugin-configuration-service.d.ts +52 -0
- package/dist/src/web-ui/plugin-configuration-service.js +66 -0
- package/dist/src/web-ui/plugin-configuration-view.d.ts +25 -0
- package/dist/src/web-ui/plugin-configuration-view.js +45 -0
- package/dist/src/web-ui/plugin-disabled-selection.d.ts +7 -0
- package/dist/src/web-ui/plugin-disabled-selection.js +17 -0
- package/dist/src/web-ui/plugin-management-catalog.d.ts +3 -1
- package/dist/src/web-ui/plugin-management-catalog.js +11 -1
- package/dist/src/web-ui/plugin-management-selection.js +22 -9
- package/dist/src/web-ui/plugin-management-service.d.ts +5 -1
- package/dist/src/web-ui/plugin-management-service.js +11 -7
- package/dist/src/web-ui/plugin-removal-error.d.ts +7 -0
- package/dist/src/web-ui/plugin-removal-error.js +16 -0
- package/dist/src/web-ui/plugin-removal-service.d.ts +30 -0
- package/dist/src/web-ui/plugin-removal-service.js +109 -0
- package/dist/src/web-ui/runtime-setup-gateway.d.ts +6 -2
- package/dist/src/web-ui/runtime-setup-gateway.js +30 -10
- package/dist/src/web-ui/server.js +6 -2
- package/dist/src/web-ui/session-read-state/overview.d.ts +42 -0
- package/dist/src/web-ui/session-read-state/overview.js +16 -0
- package/dist/src/web-ui/session-read-state/pagination.d.ts +15 -0
- package/dist/src/web-ui/session-read-state/pagination.js +42 -0
- package/dist/src/web-ui/session-read-state/projection.d.ts +4 -3
- package/dist/src/web-ui/session-read-state/service.d.ts +213 -20
- package/dist/src/web-ui/session-read-state/service.js +25 -23
- package/dist/src/web-ui/session-read-state/visible-messages.d.ts +3 -3
- package/dist/src/web-ui/system-host-setup/companion-linux.js +1 -1
- package/dist/src/web-ui/system-host-setup/installer-contract.d.ts +1 -1
- package/dist/src/web-ui/system-host-setup/installer-contract.js +2 -2
- package/dist/src/web-ui/system-host-setup/installers.js +0 -7
- package/dist/src/web-ui/system-host-setup/local-connection.d.ts +4 -1
- package/dist/src/web-ui/system-host-setup/local-connection.js +10 -17
- package/dist/src/web-ui/system-host-setup/routes.d.ts +2 -0
- package/dist/src/web-ui/system-host-setup/routes.js +32 -9
- package/dist/src/web-ui/system-host-setup/setup-mutation.d.ts +9 -0
- package/dist/src/web-ui/system-host-setup/setup-mutation.js +27 -0
- package/dist/src/web-ui/system-host-setup/windows-store-route.d.ts +13 -0
- package/dist/src/web-ui/system-host-setup/windows-store-route.js +68 -0
- package/docs/configuration.md +46 -0
- package/docs/installation.md +45 -24
- package/docs/plugins.md +165 -2
- package/docs/projects-and-full-plus.md +2 -6
- package/docs/runtime-library.md +0 -1
- package/docs/windows-companion-store.md +127 -0
- package/package.json +3 -3
- package/plugins/document-reader/plugin.json +1 -0
- package/plugins/exec/plugin.json +3 -0
- package/plugins/filesystem/plugin.json +2 -0
- package/plugins/local-search/plugin.json +1 -0
- package/plugins/system/README.md +43 -3
- package/plugins/system/plugin.json +5 -0
- package/plugins/system/source/companion-command-output.ts +82 -0
- package/plugins/system/source/host-dispatch.ts +4 -0
- package/plugins/system/source/index.ts +11 -5
- package/plugins/system/source/local-command-output.ts +61 -0
- package/plugins/system/source/request-system-modules.ts +2 -0
- package/plugins/system/src/index.cjs +474 -39
- package/plugins/web/README.md +2 -2
- package/plugins/web/plugin.json +4 -0
- package/runtime.config.schema.json +25 -1
- package/src/runtime/README.md +12 -2
- package/dist/src/web-ui/system-host-setup/companion-windows.d.ts +0 -2
- package/dist/src/web-ui/system-host-setup/companion-windows.js +0 -108
- package/docs/publishing.md +0 -167
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createRequestControlDiagnosticId, traceRequestControl, } from "../observability/request-control-diagnostics.js";
|
|
2
2
|
export const REQUEST_STEERING_FEATURE = "request_steering_v1";
|
|
3
3
|
export const REQUEST_STEERING_MESSAGE_KIND = "runtime_active_request_updates_v1";
|
|
4
4
|
const LOG_SCOPE = "runtime.request_steering";
|
|
@@ -30,6 +30,10 @@ export function projectRequestSteeringSnapshot(inbox, version) {
|
|
|
30
30
|
});
|
|
31
31
|
}
|
|
32
32
|
export function createRequestSteeringInbox(params) {
|
|
33
|
+
const diagnosticIdentity = {
|
|
34
|
+
inboxId: params.diagnostics?.inboxId ?? createRequestControlDiagnosticId("inbox"),
|
|
35
|
+
inboxOrigin: params.diagnostics?.origin ?? "request",
|
|
36
|
+
};
|
|
33
37
|
const updates = [];
|
|
34
38
|
const bySteerId = new Map();
|
|
35
39
|
let closed = false;
|
|
@@ -37,6 +41,10 @@ export function createRequestSteeringInbox(params) {
|
|
|
37
41
|
let persistenceBound = false;
|
|
38
42
|
let persistUpdate;
|
|
39
43
|
let persistenceTail = Promise.resolve();
|
|
44
|
+
traceRequestControl(LOG_SCOPE, "inbox.opened", {
|
|
45
|
+
...diagnosticIdentity,
|
|
46
|
+
requestId: params.requestId,
|
|
47
|
+
});
|
|
40
48
|
function schedulePersistence(update) {
|
|
41
49
|
if (!persistUpdate)
|
|
42
50
|
return;
|
|
@@ -44,7 +52,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
44
52
|
persistenceTail = persistenceTail.then(async () => {
|
|
45
53
|
try {
|
|
46
54
|
await persist(update);
|
|
47
|
-
|
|
55
|
+
traceRequestControl(LOG_SCOPE, "update.persisted", {
|
|
56
|
+
...diagnosticIdentity,
|
|
48
57
|
requestId: params.requestId,
|
|
49
58
|
steerId: update.steerId,
|
|
50
59
|
sequence: update.sequence,
|
|
@@ -52,7 +61,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
52
61
|
});
|
|
53
62
|
}
|
|
54
63
|
catch (error) {
|
|
55
|
-
|
|
64
|
+
traceRequestControl(LOG_SCOPE, "update.persistence_failed", {
|
|
65
|
+
...diagnosticIdentity,
|
|
56
66
|
requestId: params.requestId,
|
|
57
67
|
steerId: update.steerId,
|
|
58
68
|
sequence: update.sequence,
|
|
@@ -66,8 +76,10 @@ export function createRequestSteeringInbox(params) {
|
|
|
66
76
|
const steerId = input.steerId.trim();
|
|
67
77
|
const text = input.text.trim();
|
|
68
78
|
if (!steerId || !text) {
|
|
69
|
-
|
|
79
|
+
traceRequestControl(LOG_SCOPE, "update.rejected", {
|
|
80
|
+
...diagnosticIdentity,
|
|
70
81
|
requestId: params.requestId,
|
|
82
|
+
steerId,
|
|
71
83
|
reason: "invalid_steer_request",
|
|
72
84
|
steerIdLength: steerId.length,
|
|
73
85
|
textLength: text.length,
|
|
@@ -80,7 +92,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
80
92
|
const existing = bySteerId.get(steerId);
|
|
81
93
|
if (existing) {
|
|
82
94
|
if (existing.text !== text) {
|
|
83
|
-
|
|
95
|
+
traceRequestControl(LOG_SCOPE, "update.rejected", {
|
|
96
|
+
...diagnosticIdentity,
|
|
84
97
|
requestId: params.requestId,
|
|
85
98
|
steerId,
|
|
86
99
|
reason: "steer_id_conflict",
|
|
@@ -90,7 +103,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
90
103
|
reason: "steer_id_conflict",
|
|
91
104
|
});
|
|
92
105
|
}
|
|
93
|
-
|
|
106
|
+
traceRequestControl(LOG_SCOPE, "update.duplicate", {
|
|
107
|
+
...diagnosticIdentity,
|
|
94
108
|
requestId: params.requestId,
|
|
95
109
|
steerId,
|
|
96
110
|
sequence: existing.sequence,
|
|
@@ -102,7 +116,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
102
116
|
});
|
|
103
117
|
}
|
|
104
118
|
if (closed || sealed) {
|
|
105
|
-
|
|
119
|
+
traceRequestControl(LOG_SCOPE, "update.rejected", {
|
|
120
|
+
...diagnosticIdentity,
|
|
106
121
|
requestId: params.requestId,
|
|
107
122
|
steerId,
|
|
108
123
|
reason: "request_not_active",
|
|
@@ -122,7 +137,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
122
137
|
updates.push(update);
|
|
123
138
|
bySteerId.set(steerId, update);
|
|
124
139
|
schedulePersistence(update);
|
|
125
|
-
|
|
140
|
+
traceRequestControl(LOG_SCOPE, "update.accepted", {
|
|
141
|
+
...diagnosticIdentity,
|
|
126
142
|
requestId: params.requestId,
|
|
127
143
|
steerId,
|
|
128
144
|
sequence: update.sequence,
|
|
@@ -144,7 +160,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
144
160
|
for (const update of updates) {
|
|
145
161
|
schedulePersistence(update);
|
|
146
162
|
}
|
|
147
|
-
|
|
163
|
+
traceRequestControl(LOG_SCOPE, "persistence.bound", {
|
|
164
|
+
...diagnosticIdentity,
|
|
148
165
|
requestId: params.requestId,
|
|
149
166
|
queuedUpdateCount: updates.length,
|
|
150
167
|
});
|
|
@@ -156,8 +173,14 @@ export function createRequestSteeringInbox(params) {
|
|
|
156
173
|
}
|
|
157
174
|
closed = true;
|
|
158
175
|
sealed = true;
|
|
176
|
+
traceRequestControl(LOG_SCOPE, "inbox.closing", {
|
|
177
|
+
...diagnosticIdentity,
|
|
178
|
+
requestId: params.requestId,
|
|
179
|
+
updateCount: updates.length,
|
|
180
|
+
});
|
|
159
181
|
await persistenceTail;
|
|
160
|
-
|
|
182
|
+
traceRequestControl(LOG_SCOPE, "inbox.closed", {
|
|
183
|
+
...diagnosticIdentity,
|
|
161
184
|
requestId: params.requestId,
|
|
162
185
|
updateCount: updates.length,
|
|
163
186
|
});
|
|
@@ -167,7 +190,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
167
190
|
},
|
|
168
191
|
seal(version) {
|
|
169
192
|
if (closed || sealed || updates.length !== version) {
|
|
170
|
-
|
|
193
|
+
traceRequestControl(LOG_SCOPE, "finalization.rejected", {
|
|
194
|
+
...diagnosticIdentity,
|
|
171
195
|
requestId: params.requestId,
|
|
172
196
|
expectedVersion: version,
|
|
173
197
|
currentVersion: updates.length,
|
|
@@ -177,7 +201,8 @@ export function createRequestSteeringInbox(params) {
|
|
|
177
201
|
return false;
|
|
178
202
|
}
|
|
179
203
|
sealed = true;
|
|
180
|
-
|
|
204
|
+
traceRequestControl(LOG_SCOPE, "finalization.sealed", {
|
|
205
|
+
...diagnosticIdentity,
|
|
181
206
|
requestId: params.requestId,
|
|
182
207
|
version,
|
|
183
208
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { RuntimeModelPluginConfig } from "../config/model-plugin-config.js";
|
|
1
2
|
import type { RuntimeFilesystemScope } from "../context/runtime-filesystem-scope.js";
|
|
2
3
|
import type { RuntimeConfig, ToolRegistry } from "../ports.js";
|
|
3
4
|
import type { ToolRequestAttachment } from "../../capabilities/tool-types.js";
|
|
@@ -10,6 +11,7 @@ type RequestWorkerCapabilityProviderParams<TRequest> = Readonly<{
|
|
|
10
11
|
requestWorkingDirectory?: string;
|
|
11
12
|
filesystemScope?: RuntimeFilesystemScope;
|
|
12
13
|
executionPolicyAuthority?: ExecutionPolicyAuthoritySnapshot;
|
|
14
|
+
modelPlugins?: RuntimeModelPluginConfig;
|
|
13
15
|
requestAttachments?: readonly ToolRequestAttachment[];
|
|
14
16
|
runtimeConfig?: RuntimeConfig;
|
|
15
17
|
toolRegistryOverride?: ToolRegistry;
|
|
@@ -16,6 +16,7 @@ export function createRequestWorkerCapabilityProvider(params) {
|
|
|
16
16
|
request: params.request,
|
|
17
17
|
requestWorkingDirectory: params.requestWorkingDirectory,
|
|
18
18
|
toolPermissionMode: params.request.toolPermissionMode,
|
|
19
|
+
...(params.modelPlugins ? { modelPlugins: params.modelPlugins } : {}),
|
|
19
20
|
...(params.requestAttachments
|
|
20
21
|
? { requestAttachments: params.requestAttachments }
|
|
21
22
|
: {}),
|
|
@@ -41,7 +42,9 @@ export function createRequestWorkerCapabilityProvider(params) {
|
|
|
41
42
|
const provider = createRegisteredToolWorkerCapabilityProvider({
|
|
42
43
|
getRequestToolRegistry,
|
|
43
44
|
requestId: params.request.requestId,
|
|
44
|
-
...(params.request.toolResources
|
|
45
|
+
...(params.request.toolResources
|
|
46
|
+
? { toolResources: params.request.toolResources }
|
|
47
|
+
: {}),
|
|
45
48
|
sessionId: params.request.sessionId,
|
|
46
49
|
requestContext: Object.freeze({
|
|
47
50
|
agentMode: params.request.agentMode,
|
|
@@ -23,10 +23,10 @@ export declare function encodeJournalIndexState(state: JournalIndexState, genera
|
|
|
23
23
|
runs: {
|
|
24
24
|
file: string;
|
|
25
25
|
id: string;
|
|
26
|
-
environmentId: string;
|
|
27
26
|
status: import("./contracts.js").SchedulerRunStatus | "stopping" | "completed_with_skips";
|
|
28
27
|
jobId: string;
|
|
29
28
|
scheduledAt: string;
|
|
29
|
+
environmentId: string;
|
|
30
30
|
jobRevision: number;
|
|
31
31
|
target?: SchedulerStoredRun["target"];
|
|
32
32
|
sessionId?: string;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Classification shared by persisted projections and model history. */
|
|
2
|
+
export function isAssistantInitiativeMessage(message) {
|
|
3
|
+
if (message.role !== "assistant")
|
|
4
|
+
return false;
|
|
5
|
+
if (message.source !== "co_worker")
|
|
6
|
+
return false;
|
|
7
|
+
if (message.initiative?.kind !== "proactive_proposal_v1")
|
|
8
|
+
return false;
|
|
9
|
+
if (typeof message.initiative.proposalId !== "string")
|
|
10
|
+
return false;
|
|
11
|
+
return message.initiative.proposalId.length > 0;
|
|
12
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { SessionRecord } from "./types.js";
|
|
2
|
+
export { isAssistantInitiativeMessage } from "./assistant-initiative-message.js";
|
|
2
3
|
export type AssistantInitiative = Readonly<{
|
|
3
4
|
kind: "proactive_proposal_v1";
|
|
4
5
|
proposalId: string;
|
|
@@ -26,5 +27,4 @@ export declare function createAssistantConversationRecord(options: {
|
|
|
26
27
|
input: CreateAssistantConversationInput;
|
|
27
28
|
now: Date;
|
|
28
29
|
}): Promise<SessionRecord>;
|
|
29
|
-
export declare function isAssistantInitiativeMessage(message: SessionMessage): boolean;
|
|
30
30
|
export declare function assertAssistantInitiative(input: CreateAssistantConversationInput): void;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { assertValidSessionId } from "./record/rules.js";
|
|
2
2
|
import { deleteSessionFile, ensureSessionsDir, loadSessionFile, saveSessionFile } from "./session-store.js";
|
|
3
3
|
import { isSparkHandoffBrief } from "./spark-handoff-brief.js";
|
|
4
|
+
export { isAssistantInitiativeMessage } from "./assistant-initiative-message.js";
|
|
4
5
|
/** Called under the same per-session mutation queue as edits and deletion. */
|
|
5
6
|
export async function createAssistantConversationRecord(options) {
|
|
6
7
|
const { sessionId, input } = options;
|
|
@@ -34,13 +35,6 @@ export async function createAssistantConversationRecord(options) {
|
|
|
34
35
|
}
|
|
35
36
|
return record;
|
|
36
37
|
}
|
|
37
|
-
export function isAssistantInitiativeMessage(message) {
|
|
38
|
-
if (message.role !== "assistant" || message.source !== "co_worker")
|
|
39
|
-
return false;
|
|
40
|
-
if (message.initiative?.kind !== "proactive_proposal_v1")
|
|
41
|
-
return false;
|
|
42
|
-
return typeof message.initiative.proposalId === "string" && message.initiative.proposalId.length > 0;
|
|
43
|
-
}
|
|
44
38
|
export function assertAssistantInitiative(input) {
|
|
45
39
|
if (!input.title.trim() || input.title.length > 160)
|
|
46
40
|
throw new Error("assistant_initiative_title_invalid");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SessionRecord } from "./types.js";
|
|
2
|
+
import type { SessionMetadataChange } from "./metadata/source-receipt.js";
|
|
2
3
|
export declare class SessionCommitOutcomeUnknownError extends Error {
|
|
3
4
|
readonly sessionId: string;
|
|
4
5
|
readonly code = "session_commit_outcome_unknown";
|
|
@@ -6,4 +7,4 @@ export declare class SessionCommitOutcomeUnknownError extends Error {
|
|
|
6
7
|
}
|
|
7
8
|
export declare function syncSessionDirectory(directory: string): Promise<void>;
|
|
8
9
|
/** Same session file and replacement boundary, with explicit durable-commit errors. */
|
|
9
|
-
export declare function saveDurableSessionFile(sessionsDir: string, session: SessionRecord, assertCurrent?: () => void): Promise<void>;
|
|
10
|
+
export declare function saveDurableSessionFile(sessionsDir: string, session: SessionRecord, assertCurrent?: () => void, metadataChange?: SessionMetadataChange): Promise<void>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import { open, rename, rm } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { currentSourceStamp, sessionSourceStamp, updateSessionMetadata } from "./metadata/store.js";
|
|
4
5
|
export class SessionCommitOutcomeUnknownError extends Error {
|
|
5
6
|
sessionId;
|
|
6
7
|
code = "session_commit_outcome_unknown";
|
|
@@ -24,15 +25,18 @@ export async function syncSessionDirectory(directory) {
|
|
|
24
25
|
}
|
|
25
26
|
}
|
|
26
27
|
/** Same session file and replacement boundary, with explicit durable-commit errors. */
|
|
27
|
-
export async function saveDurableSessionFile(sessionsDir, session, assertCurrent) {
|
|
28
|
+
export async function saveDurableSessionFile(sessionsDir, session, assertCurrent, metadataChange = "projection") {
|
|
28
29
|
const target = join(sessionsDir, `${session.id}.json`);
|
|
30
|
+
const previousSource = metadataChange === "request-only" ? await currentSourceStamp(target) : undefined;
|
|
29
31
|
const temporary = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
30
32
|
let replaced = false;
|
|
33
|
+
let source;
|
|
31
34
|
try {
|
|
32
35
|
const handle = await open(temporary, "wx", 0o600);
|
|
33
36
|
try {
|
|
34
37
|
await handle.writeFile(JSON.stringify(session, null, 2), "utf8");
|
|
35
38
|
await handle.sync();
|
|
39
|
+
source = sessionSourceStamp(await handle.stat({ bigint: true }));
|
|
36
40
|
}
|
|
37
41
|
finally {
|
|
38
42
|
await handle.close();
|
|
@@ -48,4 +52,5 @@ export async function saveDurableSessionFile(sessionsDir, session, assertCurrent
|
|
|
48
52
|
throw new SessionCommitOutcomeUnknownError(session.id, { cause: error });
|
|
49
53
|
throw error;
|
|
50
54
|
}
|
|
55
|
+
await updateSessionMetadata(sessionsDir, session, source, previousSource);
|
|
51
56
|
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SessionListItem, SessionRecord, SessionSnapshotMessage } from "../types.js";
|
|
2
|
+
export type SessionMessageMetadata = Pick<SessionSnapshotMessage, "id" | "role" | "createdAt">;
|
|
3
|
+
/** Derived data only. User read cursors stay in the Web UI's existing store. */
|
|
4
|
+
export type SessionMetadata = {
|
|
5
|
+
version: 1;
|
|
6
|
+
source: string;
|
|
7
|
+
interactive: boolean;
|
|
8
|
+
updatedAt: string;
|
|
9
|
+
summary: SessionListItem;
|
|
10
|
+
messages: SessionMessageMetadata[];
|
|
11
|
+
};
|
|
12
|
+
export declare function projectSessionMetadata(session: SessionRecord, source: string): SessionMetadata;
|
|
13
|
+
export declare function isCurrentSessionMetadata(value: unknown, sessionId: string, source: string): value is SessionMetadata;
|
|
14
|
+
/** Stable ordering is owned here so future paging need not change callers' storage knowledge. */
|
|
15
|
+
export declare function compareSessionMetadata(left: SessionMetadata, right: SessionMetadata): number;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { hasAutomationSessionOrigin } from "../automation-session-origin.js";
|
|
2
|
+
import { clientVisibleMessages, toEpochMs, toMessageIdForUi, toSessionListItem, } from "../record/projection.js";
|
|
3
|
+
export function projectSessionMetadata(session, source) {
|
|
4
|
+
return {
|
|
5
|
+
version: 1,
|
|
6
|
+
source,
|
|
7
|
+
interactive: !hasAutomationSessionOrigin(session),
|
|
8
|
+
updatedAt: session.updatedAt,
|
|
9
|
+
summary: toSessionListItem(session),
|
|
10
|
+
messages: clientVisibleMessages(session.messages).map((message) => ({
|
|
11
|
+
id: toMessageIdForUi(message.id),
|
|
12
|
+
role: message.role,
|
|
13
|
+
createdAt: toEpochMs(message.createdAt),
|
|
14
|
+
})),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
function isMessageMetadata(value) {
|
|
18
|
+
if (!value)
|
|
19
|
+
return false;
|
|
20
|
+
if (typeof value.id !== "string" && typeof value.id !== "number")
|
|
21
|
+
return false;
|
|
22
|
+
if (value.role !== "user" && value.role !== "assistant")
|
|
23
|
+
return false;
|
|
24
|
+
return Number.isFinite(value.createdAt);
|
|
25
|
+
}
|
|
26
|
+
export function isCurrentSessionMetadata(value, sessionId, source) {
|
|
27
|
+
if (!value || typeof value !== "object")
|
|
28
|
+
return false;
|
|
29
|
+
const record = value;
|
|
30
|
+
if (record.version !== 1)
|
|
31
|
+
return false;
|
|
32
|
+
if (record.source !== source)
|
|
33
|
+
return false;
|
|
34
|
+
if (typeof record.interactive !== "boolean")
|
|
35
|
+
return false;
|
|
36
|
+
if (typeof record.updatedAt !== "string")
|
|
37
|
+
return false;
|
|
38
|
+
if (record.summary?.id !== sessionId)
|
|
39
|
+
return false;
|
|
40
|
+
if (typeof record.summary.title !== "string")
|
|
41
|
+
return false;
|
|
42
|
+
if (typeof record.summary.lastMessagePreview !== "string")
|
|
43
|
+
return false;
|
|
44
|
+
if (!Number.isFinite(record.summary.createdAt))
|
|
45
|
+
return false;
|
|
46
|
+
if (!Number.isFinite(record.summary.updatedAt))
|
|
47
|
+
return false;
|
|
48
|
+
if (!Array.isArray(record.messages))
|
|
49
|
+
return false;
|
|
50
|
+
return record.messages.every(isMessageMetadata);
|
|
51
|
+
}
|
|
52
|
+
/** Stable ordering is owned here so future paging need not change callers' storage knowledge. */
|
|
53
|
+
export function compareSessionMetadata(left, right) {
|
|
54
|
+
return right.updatedAt.localeCompare(left.updatedAt) || left.summary.id.localeCompare(right.summary.id);
|
|
55
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BigIntStats } from "node:fs";
|
|
2
|
+
export declare function isMissingSessionFile(error: unknown): boolean;
|
|
3
|
+
export declare function sessionSourceStamp(source: BigIntStats): string;
|
|
4
|
+
export declare function currentSourceStamp(path: string): Promise<string | null>;
|
|
5
|
+
export declare function reportMetadataFailure(sessionId: string, error: unknown): void;
|
|
6
|
+
/** Only the derived index is expendable; canonical session read failures still propagate. */
|
|
7
|
+
export declare function readMetadataJson(path: string): Promise<unknown>;
|
|
8
|
+
/** Serialize index publication/deletion by session, never across unrelated sessions. */
|
|
9
|
+
export declare function publishSessionMetadata(path: string, operation: () => Promise<void>): Promise<void>;
|
|
10
|
+
/** List backfills and the Runtime owner may run in different processes. */
|
|
11
|
+
export declare function publishSessionProjection(path: string, operation: () => Promise<void>): Promise<void>;
|
|
12
|
+
export declare function writeMetadataJson(target: string, value: unknown, sourcePath: string, source: string): Promise<boolean>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { withFileLock } from "../../runtime/adapters/long-term-memory/file-lock.js";
|
|
5
|
+
const pendingPublications = new Map();
|
|
6
|
+
export function isMissingSessionFile(error) {
|
|
7
|
+
return error?.code === "ENOENT";
|
|
8
|
+
}
|
|
9
|
+
export function sessionSourceStamp(source) {
|
|
10
|
+
return `${source.dev}:${source.ino}:${source.size}:${source.mtimeNs}`;
|
|
11
|
+
}
|
|
12
|
+
export async function currentSourceStamp(path) {
|
|
13
|
+
try {
|
|
14
|
+
return sessionSourceStamp(await stat(path, { bigint: true }));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (isMissingSessionFile(error))
|
|
18
|
+
return null;
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function reportMetadataFailure(sessionId, error) {
|
|
23
|
+
process.emitWarning(`Session metadata update failed for ${sessionId}: ${String(error)}`, {
|
|
24
|
+
code: "SESSION_METADATA_WRITE_FAILED",
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
/** Only the derived index is expendable; canonical session read failures still propagate. */
|
|
28
|
+
export async function readMetadataJson(path) {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (isMissingSessionFile(error))
|
|
34
|
+
return null;
|
|
35
|
+
if (error instanceof SyntaxError)
|
|
36
|
+
return null;
|
|
37
|
+
reportMetadataFailure(path, error);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Serialize index publication/deletion by session, never across unrelated sessions. */
|
|
42
|
+
export async function publishSessionMetadata(path, operation) {
|
|
43
|
+
const key = resolve(path);
|
|
44
|
+
const previous = pendingPublications.get(key) ?? Promise.resolve();
|
|
45
|
+
const pending = previous.then(operation).catch((error) => reportMetadataFailure(path, error));
|
|
46
|
+
pendingPublications.set(key, pending);
|
|
47
|
+
try {
|
|
48
|
+
await pending;
|
|
49
|
+
}
|
|
50
|
+
finally {
|
|
51
|
+
if (pendingPublications.get(key) === pending)
|
|
52
|
+
pendingPublications.delete(key);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** List backfills and the Runtime owner may run in different processes. */
|
|
56
|
+
export async function publishSessionProjection(path, operation) {
|
|
57
|
+
return publishSessionMetadata(path, async () => {
|
|
58
|
+
await mkdir(dirname(path), { recursive: true });
|
|
59
|
+
await withFileLock(`${path}.lock`, operation);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
export async function writeMetadataJson(target, value, sourcePath, source) {
|
|
63
|
+
if (await currentSourceStamp(sourcePath) !== source)
|
|
64
|
+
return false;
|
|
65
|
+
await mkdir(dirname(target), { recursive: true });
|
|
66
|
+
const temporary = `${target}.${process.pid}.${randomUUID()}.tmp`;
|
|
67
|
+
try {
|
|
68
|
+
await writeFile(temporary, JSON.stringify(value), { encoding: "utf8", mode: 0o600 });
|
|
69
|
+
// Validate at publication too: the canonical file may change while writing the temporary.
|
|
70
|
+
if (await currentSourceStamp(sourcePath) !== source)
|
|
71
|
+
return false;
|
|
72
|
+
await rename(temporary, target);
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
finally {
|
|
76
|
+
await rm(temporary, { force: true });
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { SessionMetadata } from "./projection.js";
|
|
2
|
+
export type SessionMetadataChange = "projection" | "request-only";
|
|
3
|
+
export declare function writeSourceReceipt(path: string, sourcePath: string, source: string, updatedAt: string, previousSource?: string): Promise<void>;
|
|
4
|
+
/** Bind request-only changes to the exact projection they left unchanged. */
|
|
5
|
+
export declare function applySourceReceipt(path: string, record: SessionMetadata, source: string): Promise<SessionMetadata | null>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { toEpochMs } from "../record/projection.js";
|
|
2
|
+
import { readMetadataJson, writeMetadataJson } from "./publication.js";
|
|
3
|
+
function isSourceReceipt(value) {
|
|
4
|
+
if (!value || typeof value !== "object")
|
|
5
|
+
return false;
|
|
6
|
+
const receipt = value;
|
|
7
|
+
if (receipt.version !== 1)
|
|
8
|
+
return false;
|
|
9
|
+
if (typeof receipt.source !== "string")
|
|
10
|
+
return false;
|
|
11
|
+
if (typeof receipt.projectionSource !== "string")
|
|
12
|
+
return false;
|
|
13
|
+
return typeof receipt.updatedAt === "string";
|
|
14
|
+
}
|
|
15
|
+
async function receiptProjectionSource(path, source, previousSource) {
|
|
16
|
+
if (previousSource === undefined)
|
|
17
|
+
return source;
|
|
18
|
+
const previous = await readMetadataJson(path);
|
|
19
|
+
if (!isSourceReceipt(previous))
|
|
20
|
+
return previousSource;
|
|
21
|
+
if (previous.source !== previousSource)
|
|
22
|
+
return previousSource;
|
|
23
|
+
return previous.projectionSource;
|
|
24
|
+
}
|
|
25
|
+
export async function writeSourceReceipt(path, sourcePath, source, updatedAt, previousSource) {
|
|
26
|
+
const projectionSource = await receiptProjectionSource(path, source, previousSource);
|
|
27
|
+
await writeMetadataJson(path, { version: 1, source, projectionSource, updatedAt }, sourcePath, source);
|
|
28
|
+
}
|
|
29
|
+
/** Bind request-only changes to the exact projection they left unchanged. */
|
|
30
|
+
export async function applySourceReceipt(path, record, source) {
|
|
31
|
+
const receipt = await readMetadataJson(path);
|
|
32
|
+
if (!isSourceReceipt(receipt))
|
|
33
|
+
return null;
|
|
34
|
+
if (receipt.source !== source)
|
|
35
|
+
return null;
|
|
36
|
+
if (receipt.projectionSource !== record.source)
|
|
37
|
+
return null;
|
|
38
|
+
return {
|
|
39
|
+
...record, source, updatedAt: receipt.updatedAt,
|
|
40
|
+
summary: { ...record.summary, updatedAt: toEpochMs(receipt.updatedAt) },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SessionRecord } from "../types.js";
|
|
2
|
+
import { type SessionMetadata } from "./projection.js";
|
|
3
|
+
export { currentSourceStamp, sessionSourceStamp } from "./publication.js";
|
|
4
|
+
/** The canonical session has already committed. A derived-index failure cannot undo it. */
|
|
5
|
+
export declare function updateSessionMetadata(sessionsDir: string, session: SessionRecord, source: string, previousSource?: string | null): Promise<void>;
|
|
6
|
+
export declare function deleteSessionMetadata(sessionsDir: string, sessionId: string): Promise<void>;
|
|
7
|
+
export declare function listSessionMetadata(sessionsDir: string): Promise<SessionMetadata[]>;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { mkdir, open, readdir, rm } from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { compareSessionMetadata, isCurrentSessionMetadata, projectSessionMetadata, } from "./projection.js";
|
|
4
|
+
import { currentSourceStamp, isMissingSessionFile, publishSessionMetadata, publishSessionProjection, readMetadataJson, reportMetadataFailure, sessionSourceStamp, writeMetadataJson, } from "./publication.js";
|
|
5
|
+
import { applySourceReceipt, writeSourceReceipt } from "./source-receipt.js";
|
|
6
|
+
export { currentSourceStamp, sessionSourceStamp } from "./publication.js";
|
|
7
|
+
const pendingLists = new Map();
|
|
8
|
+
const concurrentMetadataReads = 4;
|
|
9
|
+
function metadataPath(sessionsDir, sessionId) {
|
|
10
|
+
return join(sessionsDir, ".metadata", `${sessionId}.json`);
|
|
11
|
+
}
|
|
12
|
+
async function writeMetadata(sessionsDir, record) {
|
|
13
|
+
const target = metadataPath(sessionsDir, record.summary.id);
|
|
14
|
+
const sourcePath = join(sessionsDir, `${record.summary.id}.json`);
|
|
15
|
+
await publishSessionProjection(target, async () => {
|
|
16
|
+
if (!await writeMetadataJson(target, record, sourcePath, record.source))
|
|
17
|
+
return;
|
|
18
|
+
// The full projection already carries its source; only request-only changes need a receipt.
|
|
19
|
+
await rm(`${target}.source`, { force: true });
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/** The canonical session has already committed. A derived-index failure cannot undo it. */
|
|
23
|
+
export async function updateSessionMetadata(sessionsDir, session, source, previousSource) {
|
|
24
|
+
if (previousSource) {
|
|
25
|
+
const target = metadataPath(sessionsDir, session.id);
|
|
26
|
+
return publishSessionMetadata(target, () => writeSourceReceipt(`${target}.source`, join(sessionsDir, `${session.id}.json`), source, session.updatedAt, previousSource));
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
await writeMetadata(sessionsDir, projectSessionMetadata(session, source));
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
reportMetadataFailure(session.id, error);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function deleteSessionMetadata(sessionsDir, sessionId) {
|
|
36
|
+
const target = metadataPath(sessionsDir, sessionId);
|
|
37
|
+
await publishSessionProjection(target, async () => {
|
|
38
|
+
await rm(target, { force: true });
|
|
39
|
+
await rm(`${target}.source`, { force: true });
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async function readSourceMetadata(path) {
|
|
43
|
+
const handle = await open(path, "r").catch((error) => {
|
|
44
|
+
if (isMissingSessionFile(error))
|
|
45
|
+
return null;
|
|
46
|
+
throw error;
|
|
47
|
+
});
|
|
48
|
+
if (!handle)
|
|
49
|
+
return null;
|
|
50
|
+
try {
|
|
51
|
+
const source = sessionSourceStamp(await handle.stat({ bigint: true }));
|
|
52
|
+
const session = JSON.parse(await handle.readFile("utf8"));
|
|
53
|
+
return projectSessionMetadata(session, source);
|
|
54
|
+
}
|
|
55
|
+
finally {
|
|
56
|
+
await handle.close();
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function readCurrentMetadata(target, sessionId, source) {
|
|
60
|
+
const stored = await readMetadataJson(target);
|
|
61
|
+
if (isCurrentSessionMetadata(stored, sessionId, source))
|
|
62
|
+
return stored;
|
|
63
|
+
const projectionSource = stored?.source;
|
|
64
|
+
if (typeof projectionSource !== "string")
|
|
65
|
+
return null;
|
|
66
|
+
if (!isCurrentSessionMetadata(stored, sessionId, projectionSource))
|
|
67
|
+
return null;
|
|
68
|
+
return applySourceReceipt(`${target}.source`, stored, source);
|
|
69
|
+
}
|
|
70
|
+
async function loadMetadata(sessionsDir, sessionId) {
|
|
71
|
+
const path = join(sessionsDir, `${sessionId}.json`);
|
|
72
|
+
const source = await currentSourceStamp(path);
|
|
73
|
+
if (source === null)
|
|
74
|
+
return null;
|
|
75
|
+
const current = await readCurrentMetadata(metadataPath(sessionsDir, sessionId), sessionId, source);
|
|
76
|
+
if (current)
|
|
77
|
+
return current;
|
|
78
|
+
const rebuilt = await readSourceMetadata(path);
|
|
79
|
+
if (!rebuilt)
|
|
80
|
+
return null;
|
|
81
|
+
await writeMetadata(sessionsDir, rebuilt);
|
|
82
|
+
return rebuilt;
|
|
83
|
+
}
|
|
84
|
+
function settledMetadata(result) {
|
|
85
|
+
if (result.status === "rejected")
|
|
86
|
+
throw result.reason;
|
|
87
|
+
return result.value;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Each atomically published record completes its own backfill. Restarts reuse
|
|
91
|
+
* those records; interrupted backfills only rebuild missing/stale entries.
|
|
92
|
+
* Source stamps also detect older writers and a crash between the two commits.
|
|
93
|
+
*/
|
|
94
|
+
async function readMetadataList(sessionsDir) {
|
|
95
|
+
await mkdir(sessionsDir, { recursive: true });
|
|
96
|
+
const names = (await readdir(sessionsDir)).filter((name) => name.endsWith(".json"));
|
|
97
|
+
const records = [];
|
|
98
|
+
for (let offset = 0; offset < names.length; offset += concurrentMetadataReads) {
|
|
99
|
+
// Bound disk fan-out and drain the batch before propagating a canonical read failure.
|
|
100
|
+
const batch = await Promise.allSettled(names.slice(offset, offset + concurrentMetadataReads)
|
|
101
|
+
.map((name) => loadMetadata(sessionsDir, name.slice(0, -5))));
|
|
102
|
+
records.push(...batch.map(settledMetadata).filter((record) => record !== null));
|
|
103
|
+
}
|
|
104
|
+
return records.sort(compareSessionMetadata);
|
|
105
|
+
}
|
|
106
|
+
export async function listSessionMetadata(sessionsDir) {
|
|
107
|
+
const directory = resolve(sessionsDir);
|
|
108
|
+
const existing = pendingLists.get(directory);
|
|
109
|
+
if (existing)
|
|
110
|
+
return existing;
|
|
111
|
+
const pending = readMetadataList(directory);
|
|
112
|
+
pendingLists.set(directory, pending);
|
|
113
|
+
try {
|
|
114
|
+
return await pending;
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
pendingLists.delete(directory);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -7,10 +7,12 @@ export declare function normalizeAfterSeq(afterSeq: number): number;
|
|
|
7
7
|
export declare function toEpochMs(timestamp: string): number;
|
|
8
8
|
export declare function toClientReplayEvent(event: SessionRuntimeEvent): Record<string, unknown>;
|
|
9
9
|
export declare function getRequestFinalState(request: SessionRequestRecord): SessionRequestReplay["finalState"];
|
|
10
|
+
export declare function toMessageIdForUi(id: string): string | number;
|
|
10
11
|
export declare function isSameMessageId(messageId: string, requestedId: string): boolean;
|
|
11
12
|
export declare function filterMessagesAfter(messages: SessionRecord["messages"], afterMessageId: string | number | null | undefined): SessionRecord["messages"];
|
|
12
13
|
export declare function clientVisibleMessages(messages: SessionRecord["messages"]): SessionRecord["messages"];
|
|
13
|
-
export declare function toSnapshotMessage(sessionId: string, message: SessionRecord["messages"][number], requests: SessionRequestRecord[]): SessionSnapshotMessage;
|
|
14
|
+
export declare function toSnapshotMessage(sessionId: string, message: SessionRecord["messages"][number], requests: SessionRequestRecord[], resolveRequestId?: (message: SessionRecord["messages"][number]) => string | null): SessionSnapshotMessage;
|
|
15
|
+
export declare function createMessageRequestIdResolver(requests: SessionRequestRecord[]): (message: SessionRecord["messages"][number]) => string | null;
|
|
14
16
|
export declare function toSnapshotRequest(request: SessionRequestRecord): SessionSnapshotRequest;
|
|
15
17
|
export declare function normalizeSessionTitle(title: string): string;
|
|
16
18
|
export declare function toSessionListItem(session: SessionRecord): {
|