@xenosystem/agent-interface-host 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +67 -0
- package/dist/acp/AcpAgentRegistryService.d.ts +77 -0
- package/dist/acp/AcpAgentRegistryService.d.ts.map +1 -0
- package/dist/acp/AcpAgentRegistryService.js +754 -0
- package/dist/acp/AcpAgentRegistryService.js.map +1 -0
- package/dist/acp/AcpAgentTurnExecutionAdapter.d.ts +56 -0
- package/dist/acp/AcpAgentTurnExecutionAdapter.d.ts.map +1 -0
- package/dist/acp/AcpAgentTurnExecutionAdapter.js +323 -0
- package/dist/acp/AcpAgentTurnExecutionAdapter.js.map +1 -0
- package/dist/acp/AcpApprovalPortAdapter.d.ts +41 -0
- package/dist/acp/AcpApprovalPortAdapter.d.ts.map +1 -0
- package/dist/acp/AcpApprovalPortAdapter.js +82 -0
- package/dist/acp/AcpApprovalPortAdapter.js.map +1 -0
- package/dist/acp/AcpCoordinationBridge.d.ts +13 -0
- package/dist/acp/AcpCoordinationBridge.d.ts.map +1 -0
- package/dist/acp/AcpCoordinationBridge.js +13 -0
- package/dist/acp/AcpCoordinationBridge.js.map +1 -0
- package/dist/acp/AcpDiagnosticsService.d.ts +61 -0
- package/dist/acp/AcpDiagnosticsService.d.ts.map +1 -0
- package/dist/acp/AcpDiagnosticsService.js +203 -0
- package/dist/acp/AcpDiagnosticsService.js.map +1 -0
- package/dist/acp/AcpExternalCertificationHarness.d.ts +47 -0
- package/dist/acp/AcpExternalCertificationHarness.d.ts.map +1 -0
- package/dist/acp/AcpExternalCertificationHarness.js +176 -0
- package/dist/acp/AcpExternalCertificationHarness.js.map +1 -0
- package/dist/acp/AcpHostBridge.d.ts +81 -0
- package/dist/acp/AcpHostBridge.d.ts.map +1 -0
- package/dist/acp/AcpHostBridge.js +101 -0
- package/dist/acp/AcpHostBridge.js.map +1 -0
- package/dist/acp/AcpInteractivePermissionBridge.d.ts +77 -0
- package/dist/acp/AcpInteractivePermissionBridge.d.ts.map +1 -0
- package/dist/acp/AcpInteractivePermissionBridge.js +127 -0
- package/dist/acp/AcpInteractivePermissionBridge.js.map +1 -0
- package/dist/acp/AcpPermissionBridge.d.ts +19 -0
- package/dist/acp/AcpPermissionBridge.d.ts.map +1 -0
- package/dist/acp/AcpPermissionBridge.js +110 -0
- package/dist/acp/AcpPermissionBridge.js.map +1 -0
- package/dist/acp/AcpPermissionPolicy.d.ts +111 -0
- package/dist/acp/AcpPermissionPolicy.d.ts.map +1 -0
- package/dist/acp/AcpPermissionPolicy.js +167 -0
- package/dist/acp/AcpPermissionPolicy.js.map +1 -0
- package/dist/acp/AcpProcessSupervisor.d.ts +134 -0
- package/dist/acp/AcpProcessSupervisor.d.ts.map +1 -0
- package/dist/acp/AcpProcessSupervisor.js +674 -0
- package/dist/acp/AcpProcessSupervisor.js.map +1 -0
- package/dist/acp/AcpProviderApprovalService.d.ts +27 -0
- package/dist/acp/AcpProviderApprovalService.d.ts.map +1 -0
- package/dist/acp/AcpProviderApprovalService.js +128 -0
- package/dist/acp/AcpProviderApprovalService.js.map +1 -0
- package/dist/acp/AcpProviderCatalogService.d.ts +69 -0
- package/dist/acp/AcpProviderCatalogService.d.ts.map +1 -0
- package/dist/acp/AcpProviderCatalogService.js +707 -0
- package/dist/acp/AcpProviderCatalogService.js.map +1 -0
- package/dist/acp/AcpProviderModelService.d.ts +6 -0
- package/dist/acp/AcpProviderModelService.d.ts.map +1 -0
- package/dist/acp/AcpProviderModelService.js +274 -0
- package/dist/acp/AcpProviderModelService.js.map +1 -0
- package/dist/acp/AcpProviderVersionReadiness.d.ts +6 -0
- package/dist/acp/AcpProviderVersionReadiness.d.ts.map +1 -0
- package/dist/acp/AcpProviderVersionReadiness.js +100 -0
- package/dist/acp/AcpProviderVersionReadiness.js.map +1 -0
- package/dist/acp/AcpRuntimeEventMapper.d.ts +16 -0
- package/dist/acp/AcpRuntimeEventMapper.d.ts.map +1 -0
- package/dist/acp/AcpRuntimeEventMapper.js +326 -0
- package/dist/acp/AcpRuntimeEventMapper.js.map +1 -0
- package/dist/acp/AcpSessionService.d.ts +65 -0
- package/dist/acp/AcpSessionService.d.ts.map +1 -0
- package/dist/acp/AcpSessionService.js +931 -0
- package/dist/acp/AcpSessionService.js.map +1 -0
- package/dist/acp/DurableAcpPermissionPolicyStore.d.ts +25 -0
- package/dist/acp/DurableAcpPermissionPolicyStore.d.ts.map +1 -0
- package/dist/acp/DurableAcpPermissionPolicyStore.js +100 -0
- package/dist/acp/DurableAcpPermissionPolicyStore.js.map +1 -0
- package/dist/acp/acpCommandSafety.d.ts +63 -0
- package/dist/acp/acpCommandSafety.d.ts.map +1 -0
- package/dist/acp/acpCommandSafety.js +90 -0
- package/dist/acp/acpCommandSafety.js.map +1 -0
- package/dist/acp/acpErrors.d.ts +47 -0
- package/dist/acp/acpErrors.d.ts.map +1 -0
- package/dist/acp/acpErrors.js +93 -0
- package/dist/acp/acpErrors.js.map +1 -0
- package/dist/acp/acpRedaction.d.ts +9 -0
- package/dist/acp/acpRedaction.d.ts.map +1 -0
- package/dist/acp/acpRedaction.js +69 -0
- package/dist/acp/acpRedaction.js.map +1 -0
- package/dist/acp/acpSessionResume.d.ts +8 -0
- package/dist/acp/acpSessionResume.d.ts.map +1 -0
- package/dist/acp/acpSessionResume.js +31 -0
- package/dist/acp/acpSessionResume.js.map +1 -0
- package/dist/acp/acpTypes.d.ts +467 -0
- package/dist/acp/acpTypes.d.ts.map +1 -0
- package/dist/acp/acpTypes.js +2 -0
- package/dist/acp/acpTypes.js.map +1 -0
- package/dist/agent/chooseDirectoryBridge.d.ts +29 -0
- package/dist/agent/chooseDirectoryBridge.d.ts.map +1 -0
- package/dist/agent/chooseDirectoryBridge.js +116 -0
- package/dist/agent/chooseDirectoryBridge.js.map +1 -0
- package/dist/agent/permissionProfiles.d.ts +29 -0
- package/dist/agent/permissionProfiles.d.ts.map +1 -0
- package/dist/agent/permissionProfiles.js +107 -0
- package/dist/agent/permissionProfiles.js.map +1 -0
- package/dist/agent/runtimeAuthorityPrompt.d.ts +13 -0
- package/dist/agent/runtimeAuthorityPrompt.d.ts.map +1 -0
- package/dist/agent/runtimeAuthorityPrompt.js +45 -0
- package/dist/agent/runtimeAuthorityPrompt.js.map +1 -0
- package/dist/agent/runtimeModeOutputGuard.d.ts +6 -0
- package/dist/agent/runtimeModeOutputGuard.d.ts.map +1 -0
- package/dist/agent/runtimeModeOutputGuard.js +40 -0
- package/dist/agent/runtimeModeOutputGuard.js.map +1 -0
- package/dist/agent/workspacePlacementBridge.d.ts +29 -0
- package/dist/agent/workspacePlacementBridge.d.ts.map +1 -0
- package/dist/agent/workspacePlacementBridge.js +143 -0
- package/dist/agent/workspacePlacementBridge.js.map +1 -0
- package/dist/agentSearch/AgentSearchService.d.ts +81 -0
- package/dist/agentSearch/AgentSearchService.d.ts.map +1 -0
- package/dist/agentSearch/AgentSearchService.js +1038 -0
- package/dist/agentSearch/AgentSearchService.js.map +1 -0
- package/dist/agentSearch/JsonInvertedIndexAdapter.d.ts +44 -0
- package/dist/agentSearch/JsonInvertedIndexAdapter.d.ts.map +1 -0
- package/dist/agentSearch/JsonInvertedIndexAdapter.js +307 -0
- package/dist/agentSearch/JsonInvertedIndexAdapter.js.map +1 -0
- package/dist/agentSearch/SearchIndexAdapter.d.ts +33 -0
- package/dist/agentSearch/SearchIndexAdapter.d.ts.map +1 -0
- package/dist/agentSearch/SearchIndexAdapter.js +2 -0
- package/dist/agentSearch/SearchIndexAdapter.js.map +1 -0
- package/dist/agentSearch/SearchSourceWatcher.d.ts +29 -0
- package/dist/agentSearch/SearchSourceWatcher.d.ts.map +1 -0
- package/dist/agentSearch/SearchSourceWatcher.js +150 -0
- package/dist/agentSearch/SearchSourceWatcher.js.map +1 -0
- package/dist/agentSearch/SqliteFtsIndexAdapter.d.ts +58 -0
- package/dist/agentSearch/SqliteFtsIndexAdapter.d.ts.map +1 -0
- package/dist/agentSearch/SqliteFtsIndexAdapter.js +420 -0
- package/dist/agentSearch/SqliteFtsIndexAdapter.js.map +1 -0
- package/dist/agentSearch/conversationIndexer.d.ts +69 -0
- package/dist/agentSearch/conversationIndexer.d.ts.map +1 -0
- package/dist/agentSearch/conversationIndexer.js +313 -0
- package/dist/agentSearch/conversationIndexer.js.map +1 -0
- package/dist/agentSearch/searchTypes.d.ts +264 -0
- package/dist/agentSearch/searchTypes.d.ts.map +1 -0
- package/dist/agentSearch/searchTypes.js +2 -0
- package/dist/agentSearch/searchTypes.js.map +1 -0
- package/dist/agentSearch/searchUtils.d.ts +12 -0
- package/dist/agentSearch/searchUtils.d.ts.map +1 -0
- package/dist/agentSearch/searchUtils.js +125 -0
- package/dist/agentSearch/searchUtils.js.map +1 -0
- package/dist/agentSearch/workspaceMetadataIndexer.d.ts +3 -0
- package/dist/agentSearch/workspaceMetadataIndexer.d.ts.map +1 -0
- package/dist/agentSearch/workspaceMetadataIndexer.js +125 -0
- package/dist/agentSearch/workspaceMetadataIndexer.js.map +1 -0
- package/dist/cli/CliControlPlaneService.d.ts +269 -0
- package/dist/cli/CliControlPlaneService.d.ts.map +1 -0
- package/dist/cli/CliControlPlaneService.js +1874 -0
- package/dist/cli/CliControlPlaneService.js.map +1 -0
- package/dist/cloud/XenoCloudAgentTurnExecutionAdapter.d.ts +91 -0
- package/dist/cloud/XenoCloudAgentTurnExecutionAdapter.d.ts.map +1 -0
- package/dist/cloud/XenoCloudAgentTurnExecutionAdapter.js +379 -0
- package/dist/cloud/XenoCloudAgentTurnExecutionAdapter.js.map +1 -0
- package/dist/codebase/CodebaseIntelligenceService.d.ts +68 -0
- package/dist/codebase/CodebaseIntelligenceService.d.ts.map +1 -0
- package/dist/codebase/CodebaseIntelligenceService.js +1717 -0
- package/dist/codebase/CodebaseIntelligenceService.js.map +1 -0
- package/dist/codebase/LanguageServerProcessManager.d.ts +85 -0
- package/dist/codebase/LanguageServerProcessManager.d.ts.map +1 -0
- package/dist/codebase/LanguageServerProcessManager.js +607 -0
- package/dist/codebase/LanguageServerProcessManager.js.map +1 -0
- package/dist/codebase/codeTypes.d.ts +485 -0
- package/dist/codebase/codeTypes.d.ts.map +1 -0
- package/dist/codebase/codeTypes.js +2 -0
- package/dist/codebase/codeTypes.js.map +1 -0
- package/dist/codebase/codeUtils.d.ts +24 -0
- package/dist/codebase/codeUtils.d.ts.map +1 -0
- package/dist/codebase/codeUtils.js +177 -0
- package/dist/codebase/codeUtils.js.map +1 -0
- package/dist/codebase/contextPacks.d.ts +18 -0
- package/dist/codebase/contextPacks.d.ts.map +1 -0
- package/dist/codebase/contextPacks.js +180 -0
- package/dist/codebase/contextPacks.js.map +1 -0
- package/dist/codebase/dependencyGraph.d.ts +3 -0
- package/dist/codebase/dependencyGraph.d.ts.map +1 -0
- package/dist/codebase/dependencyGraph.js +209 -0
- package/dist/codebase/dependencyGraph.js.map +1 -0
- package/dist/codebase/fileIndexer.d.ts +27 -0
- package/dist/codebase/fileIndexer.d.ts.map +1 -0
- package/dist/codebase/fileIndexer.js +167 -0
- package/dist/codebase/fileIndexer.js.map +1 -0
- package/dist/codebase/symbolIndexer.d.ts +3 -0
- package/dist/codebase/symbolIndexer.d.ts.map +1 -0
- package/dist/codebase/symbolIndexer.js +184 -0
- package/dist/codebase/symbolIndexer.js.map +1 -0
- package/dist/codebase/whatChanged.d.ts +4 -0
- package/dist/codebase/whatChanged.d.ts.map +1 -0
- package/dist/codebase/whatChanged.js +138 -0
- package/dist/codebase/whatChanged.js.map +1 -0
- package/dist/coordination/CoordinationService.d.ts +166 -0
- package/dist/coordination/CoordinationService.d.ts.map +1 -0
- package/dist/coordination/CoordinationService.js +247 -0
- package/dist/coordination/CoordinationService.js.map +1 -0
- package/dist/coordination/claims.d.ts +122 -0
- package/dist/coordination/claims.d.ts.map +1 -0
- package/dist/coordination/claims.js +196 -0
- package/dist/coordination/claims.js.map +1 -0
- package/dist/coordination/coordinationTools.d.ts +40 -0
- package/dist/coordination/coordinationTools.d.ts.map +1 -0
- package/dist/coordination/coordinationTools.js +92 -0
- package/dist/coordination/coordinationTools.js.map +1 -0
- package/dist/coordination/laneBridge.d.ts +84 -0
- package/dist/coordination/laneBridge.d.ts.map +1 -0
- package/dist/coordination/laneBridge.js +86 -0
- package/dist/coordination/laneBridge.js.map +1 -0
- package/dist/coordination/messages.d.ts +225 -0
- package/dist/coordination/messages.d.ts.map +1 -0
- package/dist/coordination/messages.js +335 -0
- package/dist/coordination/messages.js.map +1 -0
- package/dist/coordination/permissionWaitRegistry.d.ts +32 -0
- package/dist/coordination/permissionWaitRegistry.d.ts.map +1 -0
- package/dist/coordination/permissionWaitRegistry.js +59 -0
- package/dist/coordination/permissionWaitRegistry.js.map +1 -0
- package/dist/coordination/query.d.ts +187 -0
- package/dist/coordination/query.d.ts.map +1 -0
- package/dist/coordination/query.js +138 -0
- package/dist/coordination/query.js.map +1 -0
- package/dist/coordination/renderInbox.d.ts +15 -0
- package/dist/coordination/renderInbox.d.ts.map +1 -0
- package/dist/coordination/renderInbox.js +19 -0
- package/dist/coordination/renderInbox.js.map +1 -0
- package/dist/coordination/runtimeEvents.d.ts +53 -0
- package/dist/coordination/runtimeEvents.d.ts.map +1 -0
- package/dist/coordination/runtimeEvents.js +112 -0
- package/dist/coordination/runtimeEvents.js.map +1 -0
- package/dist/detachedHostService.d.ts +77 -0
- package/dist/detachedHostService.d.ts.map +1 -0
- package/dist/detachedHostService.js +66 -0
- package/dist/detachedHostService.js.map +1 -0
- package/dist/detachedHostSupervisor.d.ts +102 -0
- package/dist/detachedHostSupervisor.d.ts.map +1 -0
- package/dist/detachedHostSupervisor.js +168 -0
- package/dist/detachedHostSupervisor.js.map +1 -0
- package/dist/durableRuntimeEventStore.d.ts +49 -0
- package/dist/durableRuntimeEventStore.d.ts.map +1 -0
- package/dist/durableRuntimeEventStore.js +364 -0
- package/dist/durableRuntimeEventStore.js.map +1 -0
- package/dist/engineering/EngineeringWorkbenchService.d.ts +142 -0
- package/dist/engineering/EngineeringWorkbenchService.d.ts.map +1 -0
- package/dist/engineering/EngineeringWorkbenchService.js +2301 -0
- package/dist/engineering/EngineeringWorkbenchService.js.map +1 -0
- package/dist/engineering/LandingService.d.ts +112 -0
- package/dist/engineering/LandingService.d.ts.map +1 -0
- package/dist/engineering/LandingService.js +239 -0
- package/dist/engineering/LandingService.js.map +1 -0
- package/dist/engineering/engineeringTypes.d.ts +2 -0
- package/dist/engineering/engineeringTypes.d.ts.map +1 -0
- package/dist/engineering/engineeringTypes.js +2 -0
- package/dist/engineering/engineeringTypes.js.map +1 -0
- package/dist/engineering/patchReview.d.ts +11 -0
- package/dist/engineering/patchReview.d.ts.map +1 -0
- package/dist/engineering/patchReview.js +174 -0
- package/dist/engineering/patchReview.js.map +1 -0
- package/dist/index.d.ts +834 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3242 -0
- package/dist/index.js.map +1 -0
- package/dist/intake/IntakeService.d.ts +84 -0
- package/dist/intake/IntakeService.d.ts.map +1 -0
- package/dist/intake/IntakeService.js +117 -0
- package/dist/intake/IntakeService.js.map +1 -0
- package/dist/intake/RepositoryTodoIntakeSource.d.ts +72 -0
- package/dist/intake/RepositoryTodoIntakeSource.d.ts.map +1 -0
- package/dist/intake/RepositoryTodoIntakeSource.js +168 -0
- package/dist/intake/RepositoryTodoIntakeSource.js.map +1 -0
- package/dist/intake/WorkspaceTodoIntakeSource.d.ts +53 -0
- package/dist/intake/WorkspaceTodoIntakeSource.d.ts.map +1 -0
- package/dist/intake/WorkspaceTodoIntakeSource.js +81 -0
- package/dist/intake/WorkspaceTodoIntakeSource.js.map +1 -0
- package/dist/isolation/CommandExecution.d.ts +132 -0
- package/dist/isolation/CommandExecution.d.ts.map +1 -0
- package/dist/isolation/CommandExecution.js +48 -0
- package/dist/isolation/CommandExecution.js.map +1 -0
- package/dist/isolation/LocalCommandExecutor.d.ts +27 -0
- package/dist/isolation/LocalCommandExecutor.d.ts.map +1 -0
- package/dist/isolation/LocalCommandExecutor.js +97 -0
- package/dist/isolation/LocalCommandExecutor.js.map +1 -0
- package/dist/isolation/RunExecutionEnvironment.d.ts +135 -0
- package/dist/isolation/RunExecutionEnvironment.d.ts.map +1 -0
- package/dist/isolation/RunExecutionEnvironment.js +206 -0
- package/dist/isolation/RunExecutionEnvironment.js.map +1 -0
- package/dist/isolation/RunIsolationService.d.ts +90 -0
- package/dist/isolation/RunIsolationService.d.ts.map +1 -0
- package/dist/isolation/RunIsolationService.js +86 -0
- package/dist/isolation/RunIsolationService.js.map +1 -0
- package/dist/isolation/SandboxCommandExecutor.d.ts +93 -0
- package/dist/isolation/SandboxCommandExecutor.d.ts.map +1 -0
- package/dist/isolation/SandboxCommandExecutor.js +189 -0
- package/dist/isolation/SandboxCommandExecutor.js.map +1 -0
- package/dist/knowledge/WorkspaceKnowledgeService.d.ts +71 -0
- package/dist/knowledge/WorkspaceKnowledgeService.d.ts.map +1 -0
- package/dist/knowledge/WorkspaceKnowledgeService.js +103 -0
- package/dist/knowledge/WorkspaceKnowledgeService.js.map +1 -0
- package/dist/localHostAuthority.d.ts +24 -0
- package/dist/localHostAuthority.d.ts.map +1 -0
- package/dist/localHostAuthority.js +87 -0
- package/dist/localHostAuthority.js.map +1 -0
- package/dist/localHostLease.d.ts +51 -0
- package/dist/localHostLease.d.ts.map +1 -0
- package/dist/localHostLease.js +167 -0
- package/dist/localHostLease.js.map +1 -0
- package/dist/localHostPaths.d.ts +30 -0
- package/dist/localHostPaths.d.ts.map +1 -0
- package/dist/localHostPaths.js +60 -0
- package/dist/localHostPaths.js.map +1 -0
- package/dist/localRpcTransport.d.ts +21 -0
- package/dist/localRpcTransport.d.ts.map +1 -0
- package/dist/localRpcTransport.js +423 -0
- package/dist/localRpcTransport.js.map +1 -0
- package/dist/node.d.ts +104 -0
- package/dist/node.d.ts.map +1 -0
- package/dist/node.js +103 -0
- package/dist/node.js.map +1 -0
- package/dist/observation/DirectoryBaselineScanner.d.ts +44 -0
- package/dist/observation/DirectoryBaselineScanner.d.ts.map +1 -0
- package/dist/observation/DirectoryBaselineScanner.js +112 -0
- package/dist/observation/DirectoryBaselineScanner.js.map +1 -0
- package/dist/observation/MountContentReader.d.ts +63 -0
- package/dist/observation/MountContentReader.d.ts.map +1 -0
- package/dist/observation/MountContentReader.js +158 -0
- package/dist/observation/MountContentReader.js.map +1 -0
- package/dist/observation/RunObservationService.d.ts +229 -0
- package/dist/observation/RunObservationService.d.ts.map +1 -0
- package/dist/observation/RunObservationService.js +248 -0
- package/dist/observation/RunObservationService.js.map +1 -0
- package/dist/observation/XenoUseObservationSource.d.ts +42 -0
- package/dist/observation/XenoUseObservationSource.d.ts.map +1 -0
- package/dist/observation/XenoUseObservationSource.js +104 -0
- package/dist/observation/XenoUseObservationSource.js.map +1 -0
- package/dist/observation/XenoUseRunObserver.d.ts +140 -0
- package/dist/observation/XenoUseRunObserver.d.ts.map +1 -0
- package/dist/observation/XenoUseRunObserver.js +256 -0
- package/dist/observation/XenoUseRunObserver.js.map +1 -0
- package/dist/pluginMcp/PluginMcpManagerService.d.ts +141 -0
- package/dist/pluginMcp/PluginMcpManagerService.d.ts.map +1 -0
- package/dist/pluginMcp/PluginMcpManagerService.js +1821 -0
- package/dist/pluginMcp/PluginMcpManagerService.js.map +1 -0
- package/dist/pluginMcp/pluginMcpTypes.d.ts +349 -0
- package/dist/pluginMcp/pluginMcpTypes.d.ts.map +1 -0
- package/dist/pluginMcp/pluginMcpTypes.js +2 -0
- package/dist/pluginMcp/pluginMcpTypes.js.map +1 -0
- package/dist/policy/WorkspacePolicyService.d.ts +83 -0
- package/dist/policy/WorkspacePolicyService.d.ts.map +1 -0
- package/dist/policy/WorkspacePolicyService.js +809 -0
- package/dist/policy/WorkspacePolicyService.js.map +1 -0
- package/dist/policy/policyGuard.d.ts +27 -0
- package/dist/policy/policyGuard.d.ts.map +1 -0
- package/dist/policy/policyGuard.js +143 -0
- package/dist/policy/policyGuard.js.map +1 -0
- package/dist/policy/policyTypes.d.ts +190 -0
- package/dist/policy/policyTypes.d.ts.map +1 -0
- package/dist/policy/policyTypes.js +2 -0
- package/dist/policy/policyTypes.js.map +1 -0
- package/dist/runtime/RuntimeEventStore.d.ts +42 -0
- package/dist/runtime/RuntimeEventStore.d.ts.map +1 -0
- package/dist/runtime/RuntimeEventStore.js +412 -0
- package/dist/runtime/RuntimeEventStore.js.map +1 -0
- package/dist/runtime/RuntimeEventStoreRepositoryAdapter.d.ts +21 -0
- package/dist/runtime/RuntimeEventStoreRepositoryAdapter.d.ts.map +1 -0
- package/dist/runtime/RuntimeEventStoreRepositoryAdapter.js +41 -0
- package/dist/runtime/RuntimeEventStoreRepositoryAdapter.js.map +1 -0
- package/dist/runtime/RuntimeTimelineProjection.d.ts +5 -0
- package/dist/runtime/RuntimeTimelineProjection.d.ts.map +1 -0
- package/dist/runtime/RuntimeTimelineProjection.js +705 -0
- package/dist/runtime/RuntimeTimelineProjection.js.map +1 -0
- package/dist/runtime/runtimeEventTypes.d.ts +73 -0
- package/dist/runtime/runtimeEventTypes.d.ts.map +1 -0
- package/dist/runtime/runtimeEventTypes.js +2 -0
- package/dist/runtime/runtimeEventTypes.js.map +1 -0
- package/dist/sdk/SdkNativeAgentTurnExecutionAdapter.d.ts +117 -0
- package/dist/sdk/SdkNativeAgentTurnExecutionAdapter.d.ts.map +1 -0
- package/dist/sdk/SdkNativeAgentTurnExecutionAdapter.js +214 -0
- package/dist/sdk/SdkNativeAgentTurnExecutionAdapter.js.map +1 -0
- package/dist/session/AgentSessionService.d.ts +285 -0
- package/dist/session/AgentSessionService.d.ts.map +1 -0
- package/dist/session/AgentSessionService.js +444 -0
- package/dist/session/AgentSessionService.js.map +1 -0
- package/dist/session/bufferedSessionPty.d.ts +27 -0
- package/dist/session/bufferedSessionPty.d.ts.map +1 -0
- package/dist/session/bufferedSessionPty.js +49 -0
- package/dist/session/bufferedSessionPty.js.map +1 -0
- package/dist/session/renderSupport.d.ts +53 -0
- package/dist/session/renderSupport.d.ts.map +1 -0
- package/dist/session/renderSupport.js +41 -0
- package/dist/session/renderSupport.js.map +1 -0
- package/dist/session/runtimeEventChannel.d.ts +56 -0
- package/dist/session/runtimeEventChannel.d.ts.map +1 -0
- package/dist/session/runtimeEventChannel.js +53 -0
- package/dist/session/runtimeEventChannel.js.map +1 -0
- package/dist/state/JsonAgentStateRepository.d.ts +29 -0
- package/dist/state/JsonAgentStateRepository.d.ts.map +1 -0
- package/dist/state/JsonAgentStateRepository.js +165 -0
- package/dist/state/JsonAgentStateRepository.js.map +1 -0
- package/dist/state/SqliteAgentStateRepository.d.ts +58 -0
- package/dist/state/SqliteAgentStateRepository.d.ts.map +1 -0
- package/dist/state/SqliteAgentStateRepository.js +777 -0
- package/dist/state/SqliteAgentStateRepository.js.map +1 -0
- package/dist/state/createAgentStateRepository.d.ts +4 -0
- package/dist/state/createAgentStateRepository.d.ts.map +1 -0
- package/dist/state/createAgentStateRepository.js +12 -0
- package/dist/state/createAgentStateRepository.js.map +1 -0
- package/dist/state/stateSanitizers.d.ts +7 -0
- package/dist/state/stateSanitizers.d.ts.map +1 -0
- package/dist/state/stateSanitizers.js +87 -0
- package/dist/state/stateSanitizers.js.map +1 -0
- package/dist/subagents/AcpSubagentExecutionAdapter.d.ts +12 -0
- package/dist/subagents/AcpSubagentExecutionAdapter.d.ts.map +1 -0
- package/dist/subagents/AcpSubagentExecutionAdapter.js +119 -0
- package/dist/subagents/AcpSubagentExecutionAdapter.js.map +1 -0
- package/dist/subagents/CliSubagentExecutionAdapter.d.ts +13 -0
- package/dist/subagents/CliSubagentExecutionAdapter.d.ts.map +1 -0
- package/dist/subagents/CliSubagentExecutionAdapter.js +217 -0
- package/dist/subagents/CliSubagentExecutionAdapter.js.map +1 -0
- package/dist/subagents/HostTurnSubagentExecutionAdapter.d.ts +78 -0
- package/dist/subagents/HostTurnSubagentExecutionAdapter.d.ts.map +1 -0
- package/dist/subagents/HostTurnSubagentExecutionAdapter.js +160 -0
- package/dist/subagents/HostTurnSubagentExecutionAdapter.js.map +1 -0
- package/dist/subagents/SubagentRunService.d.ts +103 -0
- package/dist/subagents/SubagentRunService.d.ts.map +1 -0
- package/dist/subagents/SubagentRunService.js +1183 -0
- package/dist/subagents/SubagentRunService.js.map +1 -0
- package/dist/subagents/SubagentScheduler.d.ts +167 -0
- package/dist/subagents/SubagentScheduler.d.ts.map +1 -0
- package/dist/subagents/SubagentScheduler.js +530 -0
- package/dist/subagents/SubagentScheduler.js.map +1 -0
- package/dist/subagents/TeamAgentRouter.d.ts +104 -0
- package/dist/subagents/TeamAgentRouter.d.ts.map +1 -0
- package/dist/subagents/TeamAgentRouter.js +435 -0
- package/dist/subagents/TeamAgentRouter.js.map +1 -0
- package/dist/subagents/capabilityMatcher.d.ts +3 -0
- package/dist/subagents/capabilityMatcher.d.ts.map +1 -0
- package/dist/subagents/capabilityMatcher.js +127 -0
- package/dist/subagents/capabilityMatcher.js.map +1 -0
- package/dist/subagents/subagentRunPort.d.ts +43 -0
- package/dist/subagents/subagentRunPort.d.ts.map +1 -0
- package/dist/subagents/subagentRunPort.js +24 -0
- package/dist/subagents/subagentRunPort.js.map +1 -0
- package/dist/subagents/subagentTypes.d.ts +330 -0
- package/dist/subagents/subagentTypes.d.ts.map +1 -0
- package/dist/subagents/subagentTypes.js +2 -0
- package/dist/subagents/subagentTypes.js.map +1 -0
- package/dist/subagents/subagentWorkspaceAuthority.d.ts +29 -0
- package/dist/subagents/subagentWorkspaceAuthority.d.ts.map +1 -0
- package/dist/subagents/subagentWorkspaceAuthority.js +173 -0
- package/dist/subagents/subagentWorkspaceAuthority.js.map +1 -0
- package/dist/support/SupportDiagnosticsService.d.ts +87 -0
- package/dist/support/SupportDiagnosticsService.d.ts.map +1 -0
- package/dist/support/SupportDiagnosticsService.js +1199 -0
- package/dist/support/SupportDiagnosticsService.js.map +1 -0
- package/dist/turns/DurableInterruptedTurnStore.d.ts +14 -0
- package/dist/turns/DurableInterruptedTurnStore.d.ts.map +1 -0
- package/dist/turns/DurableInterruptedTurnStore.js +63 -0
- package/dist/turns/DurableInterruptedTurnStore.js.map +1 -0
- package/dist/turns/interruptedTurns.d.ts +50 -0
- package/dist/turns/interruptedTurns.d.ts.map +1 -0
- package/dist/turns/interruptedTurns.js +54 -0
- package/dist/turns/interruptedTurns.js.map +1 -0
- package/dist/turns/turnAdmission.d.ts +113 -0
- package/dist/turns/turnAdmission.d.ts.map +1 -0
- package/dist/turns/turnAdmission.js +136 -0
- package/dist/turns/turnAdmission.js.map +1 -0
- package/dist/workspace/WorkspaceHostService.d.ts +126 -0
- package/dist/workspace/WorkspaceHostService.d.ts.map +1 -0
- package/dist/workspace/WorkspaceHostService.js +841 -0
- package/dist/workspace/WorkspaceHostService.js.map +1 -0
- package/dist/workspace/WorkspaceShellService.d.ts +71 -0
- package/dist/workspace/WorkspaceShellService.d.ts.map +1 -0
- package/dist/workspace/WorkspaceShellService.js +273 -0
- package/dist/workspace/WorkspaceShellService.js.map +1 -0
- package/dist/workspace/fileAssociations.d.ts +12 -0
- package/dist/workspace/fileAssociations.d.ts.map +1 -0
- package/dist/workspace/fileAssociations.js +202 -0
- package/dist/workspace/fileAssociations.js.map +1 -0
- package/dist/workspace/scrollbackBuffer.d.ts +48 -0
- package/dist/workspace/scrollbackBuffer.d.ts.map +1 -0
- package/dist/workspace/scrollbackBuffer.js +94 -0
- package/dist/workspace/scrollbackBuffer.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,777 @@
|
|
|
1
|
+
import { closeSync, copyFileSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { createRequire } from 'node:module';
|
|
4
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
5
|
+
import { safeAgentStateError, sanitizeConversation, sanitizeWorkspaceTree, serializeBoundedAgentState, } from './stateSanitizers.js';
|
|
6
|
+
const SQLITE_SCHEMA_VERSION = 1;
|
|
7
|
+
const MAX_LEGACY_FILES = 100_002;
|
|
8
|
+
const MAX_LEGACY_FILE_BYTES = 128 * 1024 * 1024;
|
|
9
|
+
const MAX_LEGACY_TOTAL_BYTES = 2 * 1024 * 1024 * 1024;
|
|
10
|
+
const APPLICATION_ID = 0x58454e4f;
|
|
11
|
+
/**
|
|
12
|
+
* Transactional state authority for both XENO Agent surfaces. Runtime/audit events remain in the
|
|
13
|
+
* append-only event journal; this database owns mutable workspace and conversation projections.
|
|
14
|
+
*/
|
|
15
|
+
export class SqliteAgentStateRepository {
|
|
16
|
+
databaseFile;
|
|
17
|
+
migrationReport;
|
|
18
|
+
database;
|
|
19
|
+
closed = false;
|
|
20
|
+
constructor(databaseFile, database, migrationReport) {
|
|
21
|
+
this.databaseFile = databaseFile;
|
|
22
|
+
this.database = database;
|
|
23
|
+
this.migrationReport = migrationReport;
|
|
24
|
+
}
|
|
25
|
+
static async open(options) {
|
|
26
|
+
const normalized = normalizeOptions(options);
|
|
27
|
+
ensureDirectory(dirname(normalized.databaseFile));
|
|
28
|
+
ensureDirectory(normalized.backupsDirectory);
|
|
29
|
+
ensureDirectory(normalized.reportsDirectory);
|
|
30
|
+
const releaseMigrationLock = acquireMigrationLock(normalized.migrationLockFile);
|
|
31
|
+
try {
|
|
32
|
+
const driver = await loadSqliteDriver();
|
|
33
|
+
let report;
|
|
34
|
+
if (existsSync(normalized.databaseFile)) {
|
|
35
|
+
report = inspectExistingDatabase(driver, normalized);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
report = activateInitialDatabase(driver, normalized);
|
|
39
|
+
}
|
|
40
|
+
const database = driver.open(normalized.databaseFile);
|
|
41
|
+
configureActiveDatabase(database);
|
|
42
|
+
validateSchema(database);
|
|
43
|
+
return new SqliteAgentStateRepository(normalized.databaseFile, database, report);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
releaseMigrationLock();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async loadWorkspaces() {
|
|
50
|
+
try {
|
|
51
|
+
this.assertOpen();
|
|
52
|
+
const row = asRecord(this.database.prepare('SELECT json FROM workspace_state WHERE singleton = 1').get());
|
|
53
|
+
if (!row || typeof row.json !== 'string')
|
|
54
|
+
return { success: true, workspaces: [] };
|
|
55
|
+
return { success: true, workspaces: sanitizeWorkspaceTree(JSON.parse(row.json)) };
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
return { success: false, workspaces: [], error: safeAgentStateError(error) };
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async saveWorkspaces(input) {
|
|
62
|
+
try {
|
|
63
|
+
this.assertOpen();
|
|
64
|
+
if (!Array.isArray(input.workspaces)) {
|
|
65
|
+
return { success: false, error: 'Invalid workspace state: expected an array.' };
|
|
66
|
+
}
|
|
67
|
+
const json = serializeBoundedAgentState(sanitizeWorkspaceTree(input.workspaces), 'Workspace state');
|
|
68
|
+
inTransaction(this.database, () => {
|
|
69
|
+
this.database.prepare(`
|
|
70
|
+
INSERT INTO workspace_state(singleton, json, updated_at)
|
|
71
|
+
VALUES (1, ?, ?)
|
|
72
|
+
ON CONFLICT(singleton) DO UPDATE SET json = excluded.json, updated_at = excluded.updated_at
|
|
73
|
+
`).run(json, Date.now());
|
|
74
|
+
markPostMigrationWrite(this.database);
|
|
75
|
+
});
|
|
76
|
+
return { success: true };
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
return { success: false, error: safeAgentStateError(error) };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async loadConversations() {
|
|
83
|
+
try {
|
|
84
|
+
this.assertOpen();
|
|
85
|
+
const rows = this.database.prepare('SELECT json FROM conversations ORDER BY id ASC').all();
|
|
86
|
+
const conversations = rows.map((value) => {
|
|
87
|
+
const row = asRecord(value);
|
|
88
|
+
if (!row || typeof row.json !== 'string')
|
|
89
|
+
throw new Error('Conversation row is corrupt.');
|
|
90
|
+
const conversation = sanitizeConversation(JSON.parse(row.json));
|
|
91
|
+
if (!conversation)
|
|
92
|
+
throw new Error('Conversation row has an invalid identity.');
|
|
93
|
+
return conversation;
|
|
94
|
+
});
|
|
95
|
+
return {
|
|
96
|
+
success: true,
|
|
97
|
+
conversations,
|
|
98
|
+
recoveredConversationIds: [],
|
|
99
|
+
corruptConversationFiles: [],
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
return { success: false, conversations: [], error: safeAgentStateError(error) };
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
async saveConversation(input) {
|
|
107
|
+
try {
|
|
108
|
+
this.assertOpen();
|
|
109
|
+
const conversation = sanitizeConversation(input.conversation);
|
|
110
|
+
if (!conversation)
|
|
111
|
+
return { success: false, error: 'Invalid conversation state.' };
|
|
112
|
+
const id = String(conversation.id);
|
|
113
|
+
const json = serializeBoundedAgentState(conversation, `Conversation ${id}`);
|
|
114
|
+
inTransaction(this.database, () => {
|
|
115
|
+
this.database.prepare(`
|
|
116
|
+
INSERT INTO conversations(id, json, updated_at)
|
|
117
|
+
VALUES (?, ?, ?)
|
|
118
|
+
ON CONFLICT(id) DO UPDATE SET json = excluded.json, updated_at = excluded.updated_at
|
|
119
|
+
`).run(id, json, Date.now());
|
|
120
|
+
markPostMigrationWrite(this.database);
|
|
121
|
+
});
|
|
122
|
+
return { success: true };
|
|
123
|
+
}
|
|
124
|
+
catch (error) {
|
|
125
|
+
return { success: false, error: safeAgentStateError(error) };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async deleteConversation(input) {
|
|
129
|
+
try {
|
|
130
|
+
this.assertOpen();
|
|
131
|
+
const id = typeof input.conversationId === 'string' ? input.conversationId.trim().slice(0, 240) : '';
|
|
132
|
+
if (!id)
|
|
133
|
+
return { success: false, error: 'Invalid conversation ID.' };
|
|
134
|
+
inTransaction(this.database, () => {
|
|
135
|
+
this.database.prepare('DELETE FROM conversations WHERE id = ?').run(id);
|
|
136
|
+
markPostMigrationWrite(this.database);
|
|
137
|
+
});
|
|
138
|
+
return { success: true };
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
return { success: false, error: safeAgentStateError(error) };
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
close() {
|
|
145
|
+
if (this.closed)
|
|
146
|
+
return;
|
|
147
|
+
this.closed = true;
|
|
148
|
+
this.database.close();
|
|
149
|
+
}
|
|
150
|
+
assertOpen() {
|
|
151
|
+
if (this.closed)
|
|
152
|
+
throw new Error('Agent state repository is closed.');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
export async function rollbackAgentStateMigration(options) {
|
|
156
|
+
const normalized = normalizeOptions(options);
|
|
157
|
+
if (!existsSync(normalized.databaseFile)) {
|
|
158
|
+
return { success: false, rollbackDirectory: null, error: 'No active Agent state database exists.' };
|
|
159
|
+
}
|
|
160
|
+
ensureDirectory(normalized.backupsDirectory);
|
|
161
|
+
const releaseMigrationLock = acquireMigrationLock(normalized.migrationLockFile);
|
|
162
|
+
try {
|
|
163
|
+
const driver = await loadSqliteDriver();
|
|
164
|
+
const database = driver.open(normalized.databaseFile);
|
|
165
|
+
let migrationId = null;
|
|
166
|
+
let writes = 0;
|
|
167
|
+
try {
|
|
168
|
+
configureActiveDatabase(database);
|
|
169
|
+
validateSchema(database);
|
|
170
|
+
migrationId = readMetadata(database, 'legacy_migration_id');
|
|
171
|
+
writes = Number.parseInt(readMetadata(database, 'post_migration_writes') || '0', 10);
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
database.close();
|
|
175
|
+
}
|
|
176
|
+
if (!migrationId) {
|
|
177
|
+
return { success: false, rollbackDirectory: null, error: 'The active database was not created from legacy state.' };
|
|
178
|
+
}
|
|
179
|
+
if (!Number.isFinite(writes) || writes !== 0) {
|
|
180
|
+
return {
|
|
181
|
+
success: false,
|
|
182
|
+
rollbackDirectory: null,
|
|
183
|
+
error: 'Rollback is no longer safe because the transactional store has accepted post-migration writes.',
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
const rollbackDirectory = join(normalized.backupsDirectory, `rollback-${timestampSlug(new Date())}-${migrationId.slice(0, 12)}`);
|
|
187
|
+
ensureDirectory(rollbackDirectory);
|
|
188
|
+
for (const suffix of ['', '-wal', '-shm']) {
|
|
189
|
+
const source = `${normalized.databaseFile}${suffix}`;
|
|
190
|
+
if (!existsSync(source))
|
|
191
|
+
continue;
|
|
192
|
+
renameSync(source, join(rollbackDirectory, `${basename(normalized.databaseFile)}${suffix}`));
|
|
193
|
+
}
|
|
194
|
+
return { success: true, rollbackDirectory, error: null };
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
return { success: false, rollbackDirectory: null, error: safeAgentStateError(error) };
|
|
198
|
+
}
|
|
199
|
+
finally {
|
|
200
|
+
releaseMigrationLock();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function normalizeOptions(options) {
|
|
204
|
+
const databaseFile = requiredAbsolutePath(options.databaseFile, 'databaseFile');
|
|
205
|
+
const backupsDirectory = requiredAbsolutePath(options.backupsDirectory, 'backupsDirectory');
|
|
206
|
+
const reportsDirectory = requiredAbsolutePath(options.reportsDirectory, 'reportsDirectory');
|
|
207
|
+
const migrationLockFile = requiredAbsolutePath(options.migrationLockFile, 'migrationLockFile');
|
|
208
|
+
const legacyWorkspaceFile = optionalAbsolutePath(options.legacyWorkspaceFile);
|
|
209
|
+
const legacyConversationsDirectory = optionalAbsolutePath(options.legacyConversationsDirectory);
|
|
210
|
+
return {
|
|
211
|
+
databaseFile,
|
|
212
|
+
backupsDirectory,
|
|
213
|
+
reportsDirectory,
|
|
214
|
+
migrationLockFile,
|
|
215
|
+
...(legacyWorkspaceFile ? { legacyWorkspaceFile } : {}),
|
|
216
|
+
...(legacyConversationsDirectory ? { legacyConversationsDirectory } : {}),
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
async function loadSqliteDriver() {
|
|
220
|
+
const major = Number.parseInt(process.versions.node.split('.')[0] || '0', 10);
|
|
221
|
+
if (major >= 22) {
|
|
222
|
+
try {
|
|
223
|
+
const module = await import('node:sqlite');
|
|
224
|
+
return {
|
|
225
|
+
id: 'node:sqlite',
|
|
226
|
+
open: (path) => new module.DatabaseSync(path),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
// Electron 33 embeds Node 20. Native packaged builds use the compatible fallback below.
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
const require = createRequire(import.meta.url);
|
|
235
|
+
const loaded = require('better-sqlite3');
|
|
236
|
+
const Database = asDatabaseConstructor(loaded);
|
|
237
|
+
return { id: 'better-sqlite3', open: (path) => new Database(path) };
|
|
238
|
+
}
|
|
239
|
+
catch (error) {
|
|
240
|
+
throw new Error(`No compatible SQLite driver is available for Node ${process.versions.node}: ${safeAgentStateError(error)}`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function asDatabaseConstructor(value) {
|
|
244
|
+
if (typeof value === 'function')
|
|
245
|
+
return value;
|
|
246
|
+
const record = asRecord(value);
|
|
247
|
+
if (record && typeof record.default === 'function') {
|
|
248
|
+
return record.default;
|
|
249
|
+
}
|
|
250
|
+
throw new Error('better-sqlite3 did not expose a database constructor.');
|
|
251
|
+
}
|
|
252
|
+
function activateInitialDatabase(driver, options) {
|
|
253
|
+
const started = new Date();
|
|
254
|
+
let inventory = emptyLegacyInventory();
|
|
255
|
+
let migrationId = `fresh-${createHash('sha256').update(options.databaseFile).digest('hex')}`;
|
|
256
|
+
const temporaryDatabase = `${options.databaseFile}.migrating-${process.pid}-${Date.now()}`;
|
|
257
|
+
let database = null;
|
|
258
|
+
try {
|
|
259
|
+
inventory = inventoryLegacyState(options, started);
|
|
260
|
+
migrationId = inventory.sourceFiles.length > 0
|
|
261
|
+
? `legacy-${inventory.sourceFingerprint}`
|
|
262
|
+
: migrationId;
|
|
263
|
+
database = driver.open(temporaryDatabase);
|
|
264
|
+
configureMigrationDatabase(database);
|
|
265
|
+
createSchema(database);
|
|
266
|
+
inTransaction(database, () => {
|
|
267
|
+
database?.prepare('INSERT INTO workspace_state(singleton, json, updated_at) VALUES (1, ?, ?)')
|
|
268
|
+
.run(serializeBoundedAgentState(inventory.workspace, 'Migrated workspace state'), Date.now());
|
|
269
|
+
const insertConversation = database?.prepare('INSERT INTO conversations(id, json, updated_at) VALUES (?, ?, ?)');
|
|
270
|
+
for (const conversation of inventory.conversations) {
|
|
271
|
+
const id = String(conversation.id);
|
|
272
|
+
insertConversation?.run(id, serializeBoundedAgentState(conversation, `Migrated conversation ${id}`), Date.now());
|
|
273
|
+
}
|
|
274
|
+
writeMetadata(database, 'created_by_driver', driver.id);
|
|
275
|
+
writeMetadata(database, 'legacy_migration_id', inventory.sourceFiles.length > 0 ? migrationId : '');
|
|
276
|
+
writeMetadata(database, 'post_migration_writes', '0');
|
|
277
|
+
database?.prepare(`
|
|
278
|
+
INSERT INTO migration_ledger(
|
|
279
|
+
id, status, source_fingerprint, backup_directory, counts_json, recovered_sources_json,
|
|
280
|
+
started_at, completed_at, error
|
|
281
|
+
) VALUES (?, 'complete', ?, ?, ?, ?, ?, ?, NULL)
|
|
282
|
+
`).run(migrationId, inventory.sourceFiles.length > 0 ? inventory.sourceFingerprint : null, inventory.backupDirectory, JSON.stringify({ workspaces: inventory.workspace.length, conversations: inventory.conversations.length }), JSON.stringify(inventory.recoveredSources), started.toISOString(), new Date().toISOString());
|
|
283
|
+
});
|
|
284
|
+
validateImportedState(database, inventory);
|
|
285
|
+
database.exec('PRAGMA wal_checkpoint(TRUNCATE)');
|
|
286
|
+
database.close();
|
|
287
|
+
database = null;
|
|
288
|
+
fsyncFile(temporaryDatabase);
|
|
289
|
+
renameSync(temporaryDatabase, options.databaseFile);
|
|
290
|
+
const completed = new Date();
|
|
291
|
+
const report = {
|
|
292
|
+
schemaVersion: 1,
|
|
293
|
+
migrationId,
|
|
294
|
+
status: inventory.sourceFiles.length > 0 ? 'migrated' : 'fresh',
|
|
295
|
+
startedAt: started.toISOString(),
|
|
296
|
+
completedAt: completed.toISOString(),
|
|
297
|
+
databaseFile: options.databaseFile,
|
|
298
|
+
sourceFingerprint: inventory.sourceFiles.length > 0 ? inventory.sourceFingerprint : null,
|
|
299
|
+
backupDirectory: inventory.backupDirectory,
|
|
300
|
+
workspaceCount: inventory.workspace.length,
|
|
301
|
+
conversationCount: inventory.conversations.length,
|
|
302
|
+
recoveredSources: inventory.recoveredSources,
|
|
303
|
+
sourceFiles: inventory.sourceFiles,
|
|
304
|
+
reportFile: null,
|
|
305
|
+
error: null,
|
|
306
|
+
};
|
|
307
|
+
report.reportFile = writeMigrationReport(options.reportsDirectory, report);
|
|
308
|
+
return report;
|
|
309
|
+
}
|
|
310
|
+
catch (error) {
|
|
311
|
+
if (error instanceof LegacyStateInventoryError)
|
|
312
|
+
inventory = error.inventory;
|
|
313
|
+
if (inventory.sourceFiles.length > 0)
|
|
314
|
+
migrationId = `legacy-${inventory.sourceFingerprint}`;
|
|
315
|
+
database?.close();
|
|
316
|
+
if (existsSync(temporaryDatabase))
|
|
317
|
+
rmSync(temporaryDatabase, { force: true });
|
|
318
|
+
const completed = new Date();
|
|
319
|
+
const report = {
|
|
320
|
+
schemaVersion: 1,
|
|
321
|
+
migrationId,
|
|
322
|
+
status: 'failed',
|
|
323
|
+
startedAt: started.toISOString(),
|
|
324
|
+
completedAt: completed.toISOString(),
|
|
325
|
+
databaseFile: options.databaseFile,
|
|
326
|
+
sourceFingerprint: inventory.sourceFiles.length > 0 ? inventory.sourceFingerprint : null,
|
|
327
|
+
backupDirectory: inventory.backupDirectory,
|
|
328
|
+
workspaceCount: inventory.workspace.length,
|
|
329
|
+
conversationCount: inventory.conversations.length,
|
|
330
|
+
recoveredSources: inventory.recoveredSources,
|
|
331
|
+
sourceFiles: inventory.sourceFiles,
|
|
332
|
+
reportFile: null,
|
|
333
|
+
error: safeAgentStateError(error),
|
|
334
|
+
};
|
|
335
|
+
report.reportFile = writeMigrationReport(options.reportsDirectory, report);
|
|
336
|
+
throw new Error(`Agent state migration failed without activation: ${report.error}`);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function inspectExistingDatabase(driver, options) {
|
|
340
|
+
const started = new Date();
|
|
341
|
+
const database = driver.open(options.databaseFile);
|
|
342
|
+
try {
|
|
343
|
+
configureActiveDatabase(database);
|
|
344
|
+
validateSchema(database);
|
|
345
|
+
const workspaceCount = Number(asRecord(database.prepare('SELECT COUNT(*) AS count FROM workspace_state').get())?.count || 0);
|
|
346
|
+
const conversationCount = Number(asRecord(database.prepare('SELECT COUNT(*) AS count FROM conversations').get())?.count || 0);
|
|
347
|
+
const ledger = asRecord(database.prepare(`
|
|
348
|
+
SELECT id, source_fingerprint, backup_directory, recovered_sources_json
|
|
349
|
+
FROM migration_ledger
|
|
350
|
+
WHERE status = 'complete'
|
|
351
|
+
ORDER BY completed_at DESC
|
|
352
|
+
LIMIT 1
|
|
353
|
+
`).get());
|
|
354
|
+
const completed = new Date();
|
|
355
|
+
return {
|
|
356
|
+
schemaVersion: 1,
|
|
357
|
+
migrationId: typeof ledger?.id === 'string' ? ledger.id : 'existing-database',
|
|
358
|
+
status: 'existing',
|
|
359
|
+
startedAt: started.toISOString(),
|
|
360
|
+
completedAt: completed.toISOString(),
|
|
361
|
+
databaseFile: options.databaseFile,
|
|
362
|
+
sourceFingerprint: typeof ledger?.source_fingerprint === 'string' ? ledger.source_fingerprint : null,
|
|
363
|
+
backupDirectory: typeof ledger?.backup_directory === 'string' ? ledger.backup_directory : null,
|
|
364
|
+
workspaceCount,
|
|
365
|
+
conversationCount,
|
|
366
|
+
recoveredSources: parseStringArray(ledger?.recovered_sources_json),
|
|
367
|
+
sourceFiles: [],
|
|
368
|
+
reportFile: null,
|
|
369
|
+
error: null,
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
finally {
|
|
373
|
+
database.close();
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
function inventoryLegacyState(options, started) {
|
|
377
|
+
let inventory = emptyLegacyInventory();
|
|
378
|
+
try {
|
|
379
|
+
const candidates = legacySourceCandidates(options);
|
|
380
|
+
if (candidates.length > MAX_LEGACY_FILES) {
|
|
381
|
+
throw new Error(`Legacy state contains more than ${MAX_LEGACY_FILES} recognized files.`);
|
|
382
|
+
}
|
|
383
|
+
let totalBytes = 0;
|
|
384
|
+
const sourceFiles = candidates.map((candidate) => {
|
|
385
|
+
const info = inspectRegularFile(candidate.source);
|
|
386
|
+
if (info.size > MAX_LEGACY_FILE_BYTES) {
|
|
387
|
+
throw new Error(`Legacy state file ${candidate.source} exceeds the per-file migration limit.`);
|
|
388
|
+
}
|
|
389
|
+
totalBytes += info.size;
|
|
390
|
+
if (totalBytes > MAX_LEGACY_TOTAL_BYTES) {
|
|
391
|
+
throw new Error('Legacy state exceeds the total migration size limit.');
|
|
392
|
+
}
|
|
393
|
+
return {
|
|
394
|
+
source: candidate.source,
|
|
395
|
+
backupRelativePath: candidate.backupRelativePath,
|
|
396
|
+
bytes: info.size,
|
|
397
|
+
sha256: sha256File(candidate.source),
|
|
398
|
+
};
|
|
399
|
+
});
|
|
400
|
+
const sourceFingerprint = createHash('sha256')
|
|
401
|
+
.update(sourceFiles.map((file) => `${file.backupRelativePath}\0${file.bytes}\0${file.sha256}`).join('\n'))
|
|
402
|
+
.digest('hex');
|
|
403
|
+
const backupDirectory = sourceFiles.length > 0
|
|
404
|
+
? join(options.backupsDirectory, `legacy-${timestampSlug(started)}-${sourceFingerprint.slice(0, 12)}`)
|
|
405
|
+
: null;
|
|
406
|
+
inventory = { ...inventory, sourceFiles, sourceFingerprint, backupDirectory };
|
|
407
|
+
if (backupDirectory)
|
|
408
|
+
backupLegacySources(sourceFiles, backupDirectory, sourceFingerprint, started);
|
|
409
|
+
const recoveredSources = [];
|
|
410
|
+
const workspace = readLegacyWorkspace(options.legacyWorkspaceFile, recoveredSources);
|
|
411
|
+
const conversations = readLegacyConversations(options.legacyConversationsDirectory, recoveredSources);
|
|
412
|
+
return { ...inventory, workspace, conversations, recoveredSources };
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
415
|
+
throw new LegacyStateInventoryError(safeAgentStateError(error), inventory);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
class LegacyStateInventoryError extends Error {
|
|
419
|
+
inventory;
|
|
420
|
+
constructor(message, inventory) {
|
|
421
|
+
super(message);
|
|
422
|
+
this.name = 'LegacyStateInventoryError';
|
|
423
|
+
this.inventory = inventory;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
function emptyLegacyInventory() {
|
|
427
|
+
return {
|
|
428
|
+
sourceFiles: [],
|
|
429
|
+
sourceFingerprint: createHash('sha256').update('').digest('hex'),
|
|
430
|
+
workspace: [],
|
|
431
|
+
conversations: [],
|
|
432
|
+
recoveredSources: [],
|
|
433
|
+
backupDirectory: null,
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
function legacySourceCandidates(options) {
|
|
437
|
+
const candidates = [];
|
|
438
|
+
if (options.legacyWorkspaceFile) {
|
|
439
|
+
for (const [path, name] of [
|
|
440
|
+
[options.legacyWorkspaceFile, 'workspaces.json'],
|
|
441
|
+
[`${options.legacyWorkspaceFile}.bak`, 'workspaces.json.bak'],
|
|
442
|
+
]) {
|
|
443
|
+
if (existsSync(path))
|
|
444
|
+
candidates.push({ source: path, backupRelativePath: join('workspace', name) });
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
if (options.legacyConversationsDirectory && existsSync(options.legacyConversationsDirectory)) {
|
|
448
|
+
const directoryInfo = lstatSync(options.legacyConversationsDirectory);
|
|
449
|
+
if (!directoryInfo.isDirectory() || directoryInfo.isSymbolicLink()) {
|
|
450
|
+
throw new Error('Legacy conversations path must be a real directory, not a link.');
|
|
451
|
+
}
|
|
452
|
+
for (const entry of readdirSync(options.legacyConversationsDirectory).sort()) {
|
|
453
|
+
if (!entry.endsWith('.json') && !entry.endsWith('.json.bak'))
|
|
454
|
+
continue;
|
|
455
|
+
candidates.push({
|
|
456
|
+
source: join(options.legacyConversationsDirectory, entry),
|
|
457
|
+
backupRelativePath: join('conversations', entry),
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
return candidates.sort((left, right) => left.backupRelativePath.localeCompare(right.backupRelativePath));
|
|
462
|
+
}
|
|
463
|
+
function backupLegacySources(files, backupDirectory, sourceFingerprint, started) {
|
|
464
|
+
if (existsSync(backupDirectory))
|
|
465
|
+
throw new Error(`Migration backup already exists: ${backupDirectory}`);
|
|
466
|
+
ensureDirectory(backupDirectory);
|
|
467
|
+
for (const file of files) {
|
|
468
|
+
const target = join(backupDirectory, file.backupRelativePath);
|
|
469
|
+
ensureDirectory(dirname(target));
|
|
470
|
+
copyFileSync(file.source, target);
|
|
471
|
+
fsyncFile(target);
|
|
472
|
+
if (sha256File(target) !== file.sha256) {
|
|
473
|
+
throw new Error(`Backup verification failed for ${file.source}.`);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
const manifest = {
|
|
477
|
+
schemaVersion: 1,
|
|
478
|
+
createdAt: started.toISOString(),
|
|
479
|
+
sourceFingerprint,
|
|
480
|
+
files,
|
|
481
|
+
};
|
|
482
|
+
atomicWriteText(join(backupDirectory, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
483
|
+
}
|
|
484
|
+
function readLegacyWorkspace(path, recoveredSources) {
|
|
485
|
+
if (!path || (!existsSync(path) && !existsSync(`${path}.bak`)))
|
|
486
|
+
return [];
|
|
487
|
+
const parsed = readRecoverableJson(path, recoveredSources);
|
|
488
|
+
if (!Array.isArray(parsed))
|
|
489
|
+
throw new Error('Legacy workspace state is not an array.');
|
|
490
|
+
return sanitizeWorkspaceTree(parsed);
|
|
491
|
+
}
|
|
492
|
+
function readLegacyConversations(directory, recoveredSources) {
|
|
493
|
+
if (!directory || !existsSync(directory))
|
|
494
|
+
return [];
|
|
495
|
+
const baseNames = new Set();
|
|
496
|
+
for (const entry of readdirSync(directory)) {
|
|
497
|
+
if (entry.endsWith('.json'))
|
|
498
|
+
baseNames.add(entry);
|
|
499
|
+
else if (entry.endsWith('.json.bak'))
|
|
500
|
+
baseNames.add(entry.slice(0, -4));
|
|
501
|
+
}
|
|
502
|
+
const conversations = [];
|
|
503
|
+
const ids = new Set();
|
|
504
|
+
for (const name of [...baseNames].sort()) {
|
|
505
|
+
const parsed = readRecoverableJson(join(directory, name), recoveredSources);
|
|
506
|
+
const conversation = sanitizeConversation(parsed);
|
|
507
|
+
if (!conversation)
|
|
508
|
+
throw new Error(`Legacy conversation ${name} has an invalid identity.`);
|
|
509
|
+
const id = String(conversation.id);
|
|
510
|
+
if (ids.has(id))
|
|
511
|
+
throw new Error(`Legacy state contains duplicate conversation ID ${id}.`);
|
|
512
|
+
ids.add(id);
|
|
513
|
+
conversations.push(conversation);
|
|
514
|
+
}
|
|
515
|
+
return conversations;
|
|
516
|
+
}
|
|
517
|
+
function readRecoverableJson(primaryPath, recoveredSources) {
|
|
518
|
+
if (existsSync(primaryPath)) {
|
|
519
|
+
try {
|
|
520
|
+
inspectRegularFile(primaryPath);
|
|
521
|
+
return JSON.parse(readFileSync(primaryPath, 'utf8'));
|
|
522
|
+
}
|
|
523
|
+
catch (primaryError) {
|
|
524
|
+
const backupPath = `${primaryPath}.bak`;
|
|
525
|
+
if (!existsSync(backupPath)) {
|
|
526
|
+
throw new Error(`Legacy state ${primaryPath} is corrupt and has no valid backup: ${safeAgentStateError(primaryError)}`);
|
|
527
|
+
}
|
|
528
|
+
try {
|
|
529
|
+
inspectRegularFile(backupPath);
|
|
530
|
+
const value = JSON.parse(readFileSync(backupPath, 'utf8'));
|
|
531
|
+
recoveredSources.push(basename(backupPath));
|
|
532
|
+
return value;
|
|
533
|
+
}
|
|
534
|
+
catch (backupError) {
|
|
535
|
+
throw new Error(`Legacy state ${primaryPath} and its backup are corrupt: ${safeAgentStateError(backupError)}`);
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
const backupPath = `${primaryPath}.bak`;
|
|
540
|
+
inspectRegularFile(backupPath);
|
|
541
|
+
recoveredSources.push(basename(backupPath));
|
|
542
|
+
return JSON.parse(readFileSync(backupPath, 'utf8'));
|
|
543
|
+
}
|
|
544
|
+
function configureMigrationDatabase(database) {
|
|
545
|
+
database.exec(`
|
|
546
|
+
PRAGMA journal_mode = DELETE;
|
|
547
|
+
PRAGMA synchronous = FULL;
|
|
548
|
+
PRAGMA foreign_keys = ON;
|
|
549
|
+
PRAGMA trusted_schema = OFF;
|
|
550
|
+
PRAGMA busy_timeout = 5000;
|
|
551
|
+
PRAGMA application_id = ${APPLICATION_ID};
|
|
552
|
+
`);
|
|
553
|
+
}
|
|
554
|
+
function configureActiveDatabase(database) {
|
|
555
|
+
database.exec(`
|
|
556
|
+
PRAGMA journal_mode = WAL;
|
|
557
|
+
PRAGMA synchronous = FULL;
|
|
558
|
+
PRAGMA foreign_keys = ON;
|
|
559
|
+
PRAGMA trusted_schema = OFF;
|
|
560
|
+
PRAGMA busy_timeout = 5000;
|
|
561
|
+
PRAGMA wal_autocheckpoint = 1000;
|
|
562
|
+
`);
|
|
563
|
+
}
|
|
564
|
+
function createSchema(database) {
|
|
565
|
+
database.exec(`
|
|
566
|
+
CREATE TABLE IF NOT EXISTS metadata (
|
|
567
|
+
key TEXT PRIMARY KEY NOT NULL,
|
|
568
|
+
value TEXT NOT NULL
|
|
569
|
+
) STRICT;
|
|
570
|
+
CREATE TABLE IF NOT EXISTS workspace_state (
|
|
571
|
+
singleton INTEGER PRIMARY KEY NOT NULL CHECK(singleton = 1),
|
|
572
|
+
json TEXT NOT NULL CHECK(json_valid(json)),
|
|
573
|
+
updated_at INTEGER NOT NULL
|
|
574
|
+
) STRICT;
|
|
575
|
+
CREATE TABLE IF NOT EXISTS conversations (
|
|
576
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
577
|
+
json TEXT NOT NULL CHECK(json_valid(json)),
|
|
578
|
+
updated_at INTEGER NOT NULL
|
|
579
|
+
) STRICT;
|
|
580
|
+
CREATE TABLE IF NOT EXISTS migration_ledger (
|
|
581
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
582
|
+
status TEXT NOT NULL CHECK(status IN ('complete', 'failed')),
|
|
583
|
+
source_fingerprint TEXT,
|
|
584
|
+
backup_directory TEXT,
|
|
585
|
+
counts_json TEXT NOT NULL CHECK(json_valid(counts_json)),
|
|
586
|
+
recovered_sources_json TEXT NOT NULL CHECK(json_valid(recovered_sources_json)),
|
|
587
|
+
started_at TEXT NOT NULL,
|
|
588
|
+
completed_at TEXT NOT NULL,
|
|
589
|
+
error TEXT
|
|
590
|
+
) STRICT;
|
|
591
|
+
PRAGMA user_version = ${SQLITE_SCHEMA_VERSION};
|
|
592
|
+
`);
|
|
593
|
+
}
|
|
594
|
+
function validateSchema(database) {
|
|
595
|
+
const version = Number(asRecord(database.prepare('PRAGMA user_version').get())?.user_version);
|
|
596
|
+
if (version !== SQLITE_SCHEMA_VERSION) {
|
|
597
|
+
throw new Error(`Unsupported Agent state schema ${version}; expected ${SQLITE_SCHEMA_VERSION}.`);
|
|
598
|
+
}
|
|
599
|
+
const integrity = asRecord(database.prepare('PRAGMA quick_check').get());
|
|
600
|
+
const status = integrity ? Object.values(integrity)[0] : undefined;
|
|
601
|
+
if (status !== 'ok')
|
|
602
|
+
throw new Error(`Agent state integrity check failed: ${String(status || 'unknown')}.`);
|
|
603
|
+
for (const table of ['metadata', 'workspace_state', 'conversations', 'migration_ledger']) {
|
|
604
|
+
const row = asRecord(database.prepare("SELECT name FROM sqlite_master WHERE type = 'table' AND name = ?").get(table));
|
|
605
|
+
if (row?.name !== table)
|
|
606
|
+
throw new Error(`Agent state database is missing table ${table}.`);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
function validateImportedState(database, inventory) {
|
|
610
|
+
validateSchema(database);
|
|
611
|
+
const workspaceRow = asRecord(database.prepare('SELECT json FROM workspace_state WHERE singleton = 1').get());
|
|
612
|
+
if (typeof workspaceRow?.json !== 'string' || workspaceRow.json !== serializeBoundedAgentState(inventory.workspace, 'Workspace state')) {
|
|
613
|
+
throw new Error('Workspace migration equivalence check failed.');
|
|
614
|
+
}
|
|
615
|
+
const rows = database.prepare('SELECT id, json FROM conversations ORDER BY id ASC').all().map(asRecord);
|
|
616
|
+
if (rows.length !== inventory.conversations.length)
|
|
617
|
+
throw new Error('Conversation migration count check failed.');
|
|
618
|
+
const expected = [...inventory.conversations].sort((left, right) => String(left.id).localeCompare(String(right.id)));
|
|
619
|
+
for (let index = 0; index < expected.length; index += 1) {
|
|
620
|
+
const actual = rows[index];
|
|
621
|
+
const conversation = expected[index];
|
|
622
|
+
if (!actual || !conversation || actual.id !== conversation.id || actual.json !== serializeBoundedAgentState(conversation, `Conversation ${String(conversation.id)}`)) {
|
|
623
|
+
throw new Error(`Conversation migration equivalence check failed at index ${index}.`);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
function inTransaction(database, action) {
|
|
628
|
+
database.exec('BEGIN IMMEDIATE');
|
|
629
|
+
try {
|
|
630
|
+
const result = action();
|
|
631
|
+
database.exec('COMMIT');
|
|
632
|
+
return result;
|
|
633
|
+
}
|
|
634
|
+
catch (error) {
|
|
635
|
+
try {
|
|
636
|
+
database.exec('ROLLBACK');
|
|
637
|
+
}
|
|
638
|
+
catch {
|
|
639
|
+
// Preserve the original transaction error.
|
|
640
|
+
}
|
|
641
|
+
throw error;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
function markPostMigrationWrite(database) {
|
|
645
|
+
const current = Number.parseInt(readMetadata(database, 'post_migration_writes') || '0', 10);
|
|
646
|
+
writeMetadata(database, 'post_migration_writes', String(Number.isFinite(current) ? current + 1 : 1));
|
|
647
|
+
}
|
|
648
|
+
function readMetadata(database, key) {
|
|
649
|
+
const row = asRecord(database.prepare('SELECT value FROM metadata WHERE key = ?').get(key));
|
|
650
|
+
return typeof row?.value === 'string' ? row.value : null;
|
|
651
|
+
}
|
|
652
|
+
function writeMetadata(database, key, value) {
|
|
653
|
+
database.prepare(`
|
|
654
|
+
INSERT INTO metadata(key, value) VALUES (?, ?)
|
|
655
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
656
|
+
`).run(key, value);
|
|
657
|
+
}
|
|
658
|
+
function inspectRegularFile(path) {
|
|
659
|
+
const info = lstatSync(path);
|
|
660
|
+
if (!info.isFile() || info.isSymbolicLink())
|
|
661
|
+
throw new Error(`Legacy state source is not a regular file: ${path}`);
|
|
662
|
+
return { size: info.size };
|
|
663
|
+
}
|
|
664
|
+
function sha256File(path) {
|
|
665
|
+
return createHash('sha256').update(readFileSync(path)).digest('hex');
|
|
666
|
+
}
|
|
667
|
+
function acquireMigrationLock(path) {
|
|
668
|
+
ensureDirectory(dirname(path));
|
|
669
|
+
let handle;
|
|
670
|
+
try {
|
|
671
|
+
handle = openSync(path, 'wx');
|
|
672
|
+
}
|
|
673
|
+
catch {
|
|
674
|
+
throw new Error(`Agent state migration lock is already held: ${path}`);
|
|
675
|
+
}
|
|
676
|
+
try {
|
|
677
|
+
writeFileSync(handle, `${JSON.stringify({ pid: process.pid, startedAt: new Date().toISOString() })}\n`, 'utf8');
|
|
678
|
+
fsyncSync(handle);
|
|
679
|
+
}
|
|
680
|
+
catch (error) {
|
|
681
|
+
closeSync(handle);
|
|
682
|
+
if (existsSync(path))
|
|
683
|
+
unlinkSync(path);
|
|
684
|
+
throw error;
|
|
685
|
+
}
|
|
686
|
+
return () => {
|
|
687
|
+
try {
|
|
688
|
+
closeSync(handle);
|
|
689
|
+
}
|
|
690
|
+
finally {
|
|
691
|
+
if (existsSync(path))
|
|
692
|
+
unlinkSync(path);
|
|
693
|
+
}
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function writeMigrationReport(reportsDirectory, report) {
|
|
697
|
+
ensureDirectory(reportsDirectory);
|
|
698
|
+
const path = join(reportsDirectory, `state-migration-${timestampSlug(new Date(report.completedAt))}-${report.migrationId.slice(0, 12)}.md`);
|
|
699
|
+
const lines = [
|
|
700
|
+
'# XENO Agent State Migration Report',
|
|
701
|
+
'',
|
|
702
|
+
`- Status: ${report.status}`,
|
|
703
|
+
`- Migration ID: ${report.migrationId}`,
|
|
704
|
+
`- Started: ${report.startedAt}`,
|
|
705
|
+
`- Completed: ${report.completedAt}`,
|
|
706
|
+
`- Database: ${report.databaseFile}`,
|
|
707
|
+
`- Source fingerprint: ${report.sourceFingerprint || '(fresh profile)'}`,
|
|
708
|
+
`- Backup: ${report.backupDirectory || '(none)'}`,
|
|
709
|
+
`- Workspaces: ${report.workspaceCount}`,
|
|
710
|
+
`- Conversations: ${report.conversationCount}`,
|
|
711
|
+
`- Recovered sources: ${report.recoveredSources.length}`,
|
|
712
|
+
`- Source files: ${report.sourceFiles.length}`,
|
|
713
|
+
`- Error: ${report.error || '(none)'}`,
|
|
714
|
+
'',
|
|
715
|
+
report.status === 'migrated'
|
|
716
|
+
? 'The legacy files remain byte-for-byte intact. Rollback is permitted only before the new database accepts a post-migration write.'
|
|
717
|
+
: 'No legacy state was modified by this operation.',
|
|
718
|
+
'',
|
|
719
|
+
];
|
|
720
|
+
atomicWriteText(path, lines.join('\n'));
|
|
721
|
+
return path;
|
|
722
|
+
}
|
|
723
|
+
function atomicWriteText(path, contents) {
|
|
724
|
+
ensureDirectory(dirname(path));
|
|
725
|
+
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
726
|
+
try {
|
|
727
|
+
writeFileSync(temporary, contents, 'utf8');
|
|
728
|
+
fsyncFile(temporary);
|
|
729
|
+
renameSync(temporary, path);
|
|
730
|
+
}
|
|
731
|
+
finally {
|
|
732
|
+
if (existsSync(temporary))
|
|
733
|
+
unlinkSync(temporary);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
function fsyncFile(path) {
|
|
737
|
+
const handle = openSync(path, 'r+');
|
|
738
|
+
try {
|
|
739
|
+
fsyncSync(handle);
|
|
740
|
+
}
|
|
741
|
+
finally {
|
|
742
|
+
closeSync(handle);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
function ensureDirectory(path) {
|
|
746
|
+
if (!existsSync(path))
|
|
747
|
+
mkdirSync(path, { recursive: true });
|
|
748
|
+
}
|
|
749
|
+
function timestampSlug(value) {
|
|
750
|
+
return value.toISOString().replace(/[:.]/g, '-').replace('T', '_').replace('Z', '');
|
|
751
|
+
}
|
|
752
|
+
function requiredAbsolutePath(value, field) {
|
|
753
|
+
const normalized = optionalAbsolutePath(value);
|
|
754
|
+
if (!normalized)
|
|
755
|
+
throw new Error(`Agent state ${field} is required.`);
|
|
756
|
+
return normalized;
|
|
757
|
+
}
|
|
758
|
+
function optionalAbsolutePath(value) {
|
|
759
|
+
return typeof value === 'string' && value.trim() ? resolve(value.trim()) : undefined;
|
|
760
|
+
}
|
|
761
|
+
function asRecord(value) {
|
|
762
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
763
|
+
? value
|
|
764
|
+
: null;
|
|
765
|
+
}
|
|
766
|
+
function parseStringArray(value) {
|
|
767
|
+
if (typeof value !== 'string')
|
|
768
|
+
return [];
|
|
769
|
+
try {
|
|
770
|
+
const parsed = JSON.parse(value);
|
|
771
|
+
return Array.isArray(parsed) ? parsed.filter((entry) => typeof entry === 'string') : [];
|
|
772
|
+
}
|
|
773
|
+
catch {
|
|
774
|
+
return [];
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
//# sourceMappingURL=SqliteAgentStateRepository.js.map
|