spawnfile 0.1.17 → 0.1.19
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 +1 -1
- package/dist/auth/importers.js +21 -5
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.js +1 -0
- package/dist/auth/profileStore.js +4 -1
- package/dist/auth/trainingGrokWriteback.d.ts +4 -0
- package/dist/auth/trainingGrokWriteback.js +119 -0
- package/dist/auth/trainingGrokWritebackLock.d.ts +5 -0
- package/dist/auth/trainingGrokWritebackLock.js +56 -0
- package/dist/cli/authCommands.js +9 -5
- package/dist/cli/compileBuildCommands.js +4 -0
- package/dist/cli/devCommands.js +4 -2
- package/dist/cli/downCommand.d.ts +2 -0
- package/dist/cli/downCommand.js +3 -0
- package/dist/cli/envFileOption.d.ts +18 -0
- package/dist/cli/envFileOption.js +20 -0
- package/dist/cli/lifecycleCommands.d.ts +1 -1
- package/dist/cli/lifecycleCommands.js +3 -1
- package/dist/cli/lifecyclePlan.d.ts +1 -0
- package/dist/cli/lifecyclePlan.js +2 -0
- package/dist/cli/paideiaDelegation.d.ts +2 -1
- package/dist/cli/paideiaDelegation.js +5 -4
- package/dist/cli/recordCommands.d.ts +17 -0
- package/dist/cli/recordCommands.js +43 -0
- package/dist/cli/releaseCommand.d.ts +6 -0
- package/dist/cli/releaseCommand.js +91 -0
- package/dist/cli/runCli.d.ts +7 -1
- package/dist/cli/runCli.js +11 -6
- package/dist/cli/runPublishCommands.js +5 -3
- package/dist/cli/trainCommand.js +73 -20
- package/dist/cli/upCommand.js +5 -1
- package/dist/cli/volumeCommands.d.ts +8 -0
- package/dist/cli/volumeCommands.js +53 -0
- package/dist/compiler/agentNodeMerge.js +3 -2
- package/dist/compiler/buildCompilePlan.js +4 -0
- package/dist/compiler/buildCompilePlanAgent.js +3 -1
- package/dist/compiler/buildCompilePlanTraversal.js +2 -0
- package/dist/compiler/buildCompilePlanTraversalHelpers.d.ts +2 -2
- package/dist/compiler/buildCompilePlanTraversalHelpers.js +4 -3
- package/dist/compiler/buildProject.d.ts +10 -0
- package/dist/compiler/buildProject.js +14 -2
- package/dist/compiler/cleanCompileOutput.d.ts +2 -0
- package/dist/compiler/cleanCompileOutput.js +14 -0
- package/dist/compiler/compilePlanHelpers.js +2 -0
- package/dist/compiler/compileProject.d.ts +10 -0
- package/dist/compiler/compileProject.js +29 -3
- package/dist/compiler/containerArtifactSummaries.js +1 -0
- package/dist/compiler/containerArtifacts.d.ts +4 -4
- package/dist/compiler/containerArtifacts.js +18 -34
- package/dist/compiler/containerArtifactsPlans.js +7 -0
- package/dist/compiler/containerArtifactsTypes.d.ts +7 -0
- package/dist/compiler/containerDaimonBrokerRender.d.ts +3 -1
- package/dist/compiler/containerDaimonBrokerRender.js +6 -3
- package/dist/compiler/containerDaimonGrokTaskClock.d.ts +5 -0
- package/dist/compiler/containerDaimonGrokTaskClock.js +29 -0
- package/dist/compiler/containerDaimonGrokWorkerProvisioning.d.ts +1 -1
- package/dist/compiler/containerDaimonGrokWorkerProvisioning.js +38 -16
- package/dist/compiler/containerDaimonGrokWorkerRender.d.ts +33 -8
- package/dist/compiler/containerDaimonGrokWorkerRender.js +18 -5
- package/dist/compiler/containerDaimonOwnershipGuardRender.d.ts +14 -1
- package/dist/compiler/containerDaimonOwnershipGuardRender.js +15 -2
- package/dist/compiler/containerDaimonUidEntrypointRender.js +6 -12
- package/dist/compiler/containerTargetResources.d.ts +10 -0
- package/dist/compiler/containerTargetResources.js +21 -13
- package/dist/compiler/containerWorkspaceResourceRender.js +4 -1
- package/dist/compiler/index.d.ts +2 -0
- package/dist/compiler/index.js +2 -0
- package/dist/compiler/mcpPlaceholders.d.ts +11 -0
- package/dist/compiler/mcpPlaceholders.js +58 -0
- package/dist/compiler/mcpServerInheritance.d.ts +18 -0
- package/dist/compiler/mcpServerInheritance.js +43 -0
- package/dist/compiler/moltnetArtifactTypes.d.ts +1 -0
- package/dist/compiler/moltnetArtifacts.js +1 -0
- package/dist/compiler/preflightCompilePlan.d.ts +9 -0
- package/dist/compiler/preflightCompilePlan.js +38 -0
- package/dist/compiler/recordingAgentFacts.d.ts +4 -0
- package/dist/compiler/recordingAgentFacts.js +35 -0
- package/dist/compiler/recordingCapability.d.ts +4 -0
- package/dist/compiler/recordingCapability.js +22 -0
- package/dist/compiler/recordingReport.d.ts +4 -0
- package/dist/compiler/recordingReport.js +18 -0
- package/dist/compiler/runProject.d.ts +2 -1
- package/dist/compiler/runProject.js +2 -0
- package/dist/compiler/surfaces.d.ts +1 -2
- package/dist/compiler/surfaces.js +0 -1
- package/dist/compiler/syncProjectAuth.js +2 -1
- package/dist/compiler/training/broker/clockProbe.d.ts +6 -0
- package/dist/compiler/training/broker/clockProbe.js +27 -0
- package/dist/compiler/training/broker/declaration.d.ts +4 -2
- package/dist/compiler/training/broker/declaration.js +4 -2
- package/dist/compiler/training/broker/entrypoint.js +33 -18
- package/dist/compiler/training/broker/evaluatorSecrets.d.ts +2 -0
- package/dist/compiler/training/broker/evaluatorSecrets.js +60 -0
- package/dist/compiler/training/broker/index.d.ts +3 -2
- package/dist/compiler/training/broker/index.js +3 -2
- package/dist/compiler/training/broker/main.js +1 -1
- package/dist/compiler/training/broker/paths.d.ts +96 -56
- package/dist/compiler/training/broker/paths.js +97 -89
- package/dist/compiler/training/broker/processes.d.ts +9 -0
- package/dist/compiler/training/broker/processes.js +4 -1
- package/dist/compiler/training/broker/projection.d.ts +3 -2
- package/dist/compiler/training/broker/projection.js +21 -9
- package/dist/compiler/training/broker/provisioning.d.ts +6 -15
- package/dist/compiler/training/broker/provisioning.js +71 -53
- package/dist/compiler/training/broker/registration.d.ts +3 -1
- package/dist/compiler/training/broker/registration.js +29 -21
- package/dist/compiler/training/broker/reset.d.ts +9 -0
- package/dist/compiler/training/broker/reset.js +71 -0
- package/dist/compiler/training/broker/runtime.d.ts +10 -13
- package/dist/compiler/training/broker/runtime.js +69 -115
- package/dist/compiler/training/broker/supervisor.d.ts +10 -11
- package/dist/compiler/training/broker/supervisor.js +22 -23
- package/dist/compiler/training/broker/taskClock.d.ts +5 -0
- package/dist/compiler/training/broker/taskClock.js +41 -0
- package/dist/compiler/training/compiledAgent.d.ts +21 -0
- package/dist/compiler/training/compiledAgent.js +62 -0
- package/dist/compiler/training/container/contract.d.ts +23 -0
- package/dist/compiler/training/container/contract.js +23 -5
- package/dist/compiler/training/container/evaluators.d.ts +48 -0
- package/dist/compiler/training/container/evaluators.js +50 -0
- package/dist/compiler/training/container/grokWriteback.d.ts +8 -0
- package/dist/compiler/training/container/grokWriteback.js +26 -0
- package/dist/compiler/training/container/index.d.ts +2 -1
- package/dist/compiler/training/container/index.js +2 -1
- package/dist/compiler/training/container/launch.d.ts +3 -0
- package/dist/compiler/training/container/launch.js +119 -28
- package/dist/compiler/training/container/nativeSlots.d.ts +14 -0
- package/dist/compiler/training/container/nativeSlots.js +13 -0
- package/dist/compiler/training/container/outputCopy.d.ts +2 -0
- package/dist/compiler/training/container/outputCopy.js +72 -0
- package/dist/compiler/training/container/outputVolume.d.ts +27 -0
- package/dist/compiler/training/container/outputVolume.js +161 -0
- package/dist/compiler/training/container/prepare.d.ts +3 -1
- package/dist/compiler/training/container/prepare.js +57 -12
- package/dist/compiler/training/container/security.d.ts +5 -3
- package/dist/compiler/training/container/security.js +15 -5
- package/dist/compiler/training/container/subjectIsolation.d.ts +5 -0
- package/dist/compiler/training/container/subjectIsolation.js +15 -0
- package/dist/compiler/training/context.d.ts +8 -0
- package/dist/compiler/training/context.js +12 -12
- package/dist/compiler/training/contract.d.ts +2 -0
- package/dist/compiler/training/contract.js +2 -0
- package/dist/compiler/training/execution.d.ts +417 -0
- package/dist/compiler/training/execution.js +160 -0
- package/dist/compiler/training/index.d.ts +8 -0
- package/dist/compiler/training/index.js +7 -0
- package/dist/compiler/training/moments.d.ts +80 -0
- package/dist/compiler/training/moments.js +118 -0
- package/dist/compiler/training/output.d.ts +2 -0
- package/dist/compiler/training/output.js +20 -0
- package/dist/compiler/training/plan/contract.d.ts +287 -0
- package/dist/compiler/training/plan/contract.js +49 -0
- package/dist/compiler/training/plan/index.d.ts +5 -0
- package/dist/compiler/training/plan/index.js +4 -0
- package/dist/compiler/training/plan/load.d.ts +9 -0
- package/dist/compiler/training/plan/load.js +153 -0
- package/dist/compiler/training/plan/references.d.ts +19 -0
- package/dist/compiler/training/plan/references.js +57 -0
- package/dist/compiler/training/plan/resolve.d.ts +4 -0
- package/dist/compiler/training/plan/resolve.js +73 -0
- package/dist/compiler/training/plan/targets.d.ts +11 -0
- package/dist/compiler/training/plan/targets.js +71 -0
- package/dist/compiler/training/plan/types.d.ts +36 -0
- package/dist/compiler/training/plan/types.js +1 -0
- package/dist/compiler/training/preparation/assets/Dockerfile +13 -2
- package/dist/compiler/training/preparation/assets/package-lock.json +2 -2
- package/dist/compiler/training/preparation/broker.d.ts +3 -3
- package/dist/compiler/training/preparation/broker.js +6 -4
- package/dist/compiler/training/preparation/contract.d.ts +27 -2
- package/dist/compiler/training/preparation/contract.js +23 -4
- package/dist/compiler/training/preparation/files.d.ts +5 -1
- package/dist/compiler/training/preparation/files.js +76 -15
- package/dist/compiler/training/preparation/image.js +9 -4
- package/dist/compiler/training/preparation/inputs.d.ts +1 -0
- package/dist/compiler/training/preparation/inputs.js +18 -10
- package/dist/compiler/training/preparation/prepare.d.ts +5 -0
- package/dist/compiler/training/preparation/prepare.js +66 -29
- package/dist/compiler/training/preparation/scratch.d.ts +6 -17
- package/dist/compiler/training/preparation/scratch.js +89 -23
- package/dist/compiler/training/repair/contract.d.ts +338 -4
- package/dist/compiler/training/repair/contract.js +2 -0
- package/dist/compiler/training/repair/index.d.ts +1 -1
- package/dist/compiler/training/repair/index.js +1 -1
- package/dist/compiler/training/repair/prepare.d.ts +155 -3
- package/dist/compiler/training/repair/prepare.js +6 -2
- package/dist/compiler/training/repair/witness.d.ts +152 -3
- package/dist/compiler/training/repair/witness.js +8 -2
- package/dist/compiler/training/resolution.d.ts +25 -0
- package/dist/compiler/training/resolution.js +69 -0
- package/dist/compiler/training/rewind/contract.d.ts +321 -0
- package/dist/compiler/training/rewind/contract.js +39 -0
- package/dist/compiler/training/rewind/deployedResource.d.ts +22 -0
- package/dist/compiler/training/rewind/deployedResource.js +19 -0
- package/dist/compiler/training/rewind/feed.d.ts +12 -0
- package/dist/compiler/training/rewind/feed.js +182 -0
- package/dist/compiler/training/rewind/feedContent.d.ts +6 -0
- package/dist/compiler/training/rewind/feedContent.js +38 -0
- package/dist/compiler/training/rewind/git.d.ts +8 -0
- package/dist/compiler/training/rewind/git.js +159 -0
- package/dist/compiler/training/rewind/gitArchive.d.ts +2 -0
- package/dist/compiler/training/rewind/gitArchive.js +7 -0
- package/dist/compiler/training/rewind/gitHistory.d.ts +3 -0
- package/dist/compiler/training/rewind/gitHistory.js +55 -0
- package/dist/compiler/training/rewind/gitProcess.d.ts +19 -0
- package/dist/compiler/training/rewind/gitProcess.js +81 -0
- package/dist/compiler/training/rewind/gitTree.d.ts +14 -0
- package/dist/compiler/training/rewind/gitTree.js +90 -0
- package/dist/compiler/training/rewind/history.d.ts +28 -0
- package/dist/compiler/training/rewind/history.js +239 -0
- package/dist/compiler/training/rewind/index.d.ts +18 -0
- package/dist/compiler/training/rewind/index.js +15 -0
- package/dist/compiler/training/rewind/inputs.d.ts +9 -0
- package/dist/compiler/training/rewind/inputs.js +67 -0
- package/dist/compiler/training/rewind/instant.d.ts +4 -0
- package/dist/compiler/training/rewind/instant.js +24 -0
- package/dist/compiler/training/rewind/leakCheck.d.ts +10 -0
- package/dist/compiler/training/rewind/leakCheck.js +56 -0
- package/dist/compiler/training/rewind/leakFeed.d.ts +5 -0
- package/dist/compiler/training/rewind/leakFeed.js +25 -0
- package/dist/compiler/training/rewind/leakFiles.d.ts +10 -0
- package/dist/compiler/training/rewind/leakFiles.js +106 -0
- package/dist/compiler/training/rewind/leakGit.d.ts +3 -0
- package/dist/compiler/training/rewind/leakGit.js +78 -0
- package/dist/compiler/training/rewind/leakGitPayload.d.ts +4 -0
- package/dist/compiler/training/rewind/leakGitPayload.js +57 -0
- package/dist/compiler/training/rewind/leakInputs.d.ts +7 -0
- package/dist/compiler/training/rewind/leakInputs.js +135 -0
- package/dist/compiler/training/rewind/leakLayout.d.ts +2 -0
- package/dist/compiler/training/rewind/leakLayout.js +17 -0
- package/dist/compiler/training/rewind/leakProvenance.d.ts +3 -0
- package/dist/compiler/training/rewind/leakProvenance.js +88 -0
- package/dist/compiler/training/rewind/materialize.d.ts +136 -0
- package/dist/compiler/training/rewind/materialize.js +212 -0
- package/dist/compiler/training/rewind/memory.d.ts +10 -0
- package/dist/compiler/training/rewind/memory.js +84 -0
- package/dist/compiler/training/rewind/memorySchemas.d.ts +87 -0
- package/dist/compiler/training/rewind/memorySchemas.js +50 -0
- package/dist/compiler/training/rewind/moltnet.d.ts +2 -0
- package/dist/compiler/training/rewind/moltnet.js +54 -0
- package/dist/compiler/training/rewind/moltnetJson.d.ts +13 -0
- package/dist/compiler/training/rewind/moltnetJson.js +180 -0
- package/dist/compiler/training/rewind/moltnetSchemas.d.ts +1226 -0
- package/dist/compiler/training/rewind/moltnetSchemas.js +75 -0
- package/dist/compiler/training/rewind/moltnetSqlite.d.ts +31 -0
- package/dist/compiler/training/rewind/moltnetSqlite.js +192 -0
- package/dist/compiler/training/rewind/moltnetSqliteData.d.ts +10 -0
- package/dist/compiler/training/rewind/moltnetSqliteData.js +113 -0
- package/dist/compiler/training/rewind/recordInput.d.ts +40 -0
- package/dist/compiler/training/rewind/recordInput.js +49 -0
- package/dist/compiler/training/rewind/recordedBundle.d.ts +4 -0
- package/dist/compiler/training/rewind/recordedBundle.js +58 -0
- package/dist/compiler/training/rewind/recordedCommit.d.ts +2 -0
- package/dist/compiler/training/rewind/recordedCommit.js +10 -0
- package/dist/compiler/training/rewind/select.d.ts +18 -0
- package/dist/compiler/training/rewind/select.js +64 -0
- package/dist/compiler/training/rewind/snapshotManifest.d.ts +42 -0
- package/dist/compiler/training/rewind/snapshotManifest.js +134 -0
- package/dist/compiler/training/rewind/taskClock.d.ts +12 -0
- package/dist/compiler/training/rewind/taskClock.js +40 -0
- package/dist/compiler/training/rewind/timestamps.d.ts +4 -0
- package/dist/compiler/training/rewind/timestamps.js +26 -0
- package/dist/compiler/training/rewind/types.d.ts +43 -0
- package/dist/compiler/training/rewind/types.js +1 -0
- package/dist/compiler/training/rewind/volumes.d.ts +12 -0
- package/dist/compiler/training/rewind/volumes.js +58 -0
- package/dist/compiler/training/selection.d.ts +7 -0
- package/dist/compiler/training/selection.js +15 -0
- package/dist/compiler/types.d.ts +6 -3
- package/dist/compiler/upProject.d.ts +1 -0
- package/dist/compiler/upProject.js +21 -5
- package/dist/compiler/workspaceBundleArtifacts.d.ts +16 -1
- package/dist/compiler/workspaceBundleArtifacts.js +69 -20
- package/dist/compiler/workspaceBundleCache.d.ts +23 -0
- package/dist/compiler/workspaceBundleCache.js +79 -0
- package/dist/compiler/workspaceBundleDependencies.d.ts +21 -0
- package/dist/compiler/workspaceBundleDependencies.js +122 -0
- package/dist/compiler/workspaceBundleFiles.d.ts +51 -0
- package/dist/compiler/workspaceBundleFiles.js +251 -0
- package/dist/compiler/workspaceBundleGenerated.d.ts +25 -0
- package/dist/compiler/workspaceBundleGenerated.js +103 -0
- package/dist/compiler/workspaceBundleGit.d.ts +64 -0
- package/dist/compiler/workspaceBundleGit.js +154 -0
- package/dist/compiler/workspaceBundleKey.d.ts +34 -0
- package/dist/compiler/workspaceBundleKey.js +17 -0
- package/dist/compiler/workspaceBundleResolve.d.ts +56 -0
- package/dist/compiler/workspaceBundleResolve.js +144 -0
- package/dist/compiler/workspaceBundleRun.d.ts +41 -0
- package/dist/compiler/workspaceBundleRun.js +79 -0
- package/dist/compiler/workspaceBundleTar.d.ts +47 -0
- package/dist/compiler/workspaceBundleTar.js +140 -0
- package/dist/compiler/workspaceBundleTree.d.ts +15 -0
- package/dist/compiler/workspaceBundleTree.js +58 -0
- package/dist/compiler/workspaceGitFetch.d.ts +41 -0
- package/dist/compiler/workspaceGitFetch.js +155 -0
- package/dist/compiler/workspaceGitPins.d.ts +33 -0
- package/dist/compiler/workspaceGitPins.js +127 -0
- package/dist/compiler/workspaceResources.d.ts +5 -1
- package/dist/compiler/workspaceResources.js +32 -5
- package/dist/deployment/activation.d.ts +3 -0
- package/dist/deployment/activation.js +12 -0
- package/dist/deployment/canaryCutover.d.ts +1 -1
- package/dist/deployment/candidateRecording.d.ts +8 -0
- package/dist/deployment/candidateRecording.js +22 -0
- package/dist/deployment/dockerManager.d.ts +5 -3
- package/dist/deployment/dockerManager.js +12 -2
- package/dist/deployment/downDeployment.d.ts +2 -0
- package/dist/deployment/downDeployment.js +6 -2
- package/dist/deployment/homeStore.d.ts +9 -1
- package/dist/deployment/homeStore.js +16 -53
- package/dist/deployment/index.d.ts +6 -0
- package/dist/deployment/index.js +6 -0
- package/dist/deployment/pidLock.d.ts +25 -0
- package/dist/deployment/pidLock.js +81 -0
- package/dist/deployment/record.d.ts +85 -1
- package/dist/deployment/record.js +11 -5
- package/dist/deployment/recordPublication.d.ts +15 -0
- package/dist/deployment/recordPublication.js +76 -0
- package/dist/deployment/recordedMemoryRetention.d.ts +18 -0
- package/dist/deployment/recordedMemoryRetention.js +27 -0
- package/dist/deployment/resourceLog.d.ts +140 -0
- package/dist/deployment/resourceLog.js +78 -0
- package/dist/distribution/buildDistributionReport.d.ts +3 -0
- package/dist/distribution/buildDistributionReport.js +5 -0
- package/dist/distribution/consumeImage.d.ts +3 -0
- package/dist/distribution/consumeImage.js +23 -31
- package/dist/distribution/consumeImageLifecycle.d.ts +4 -1
- package/dist/distribution/consumeImageLifecycle.js +14 -3
- package/dist/distribution/consumeImageSupport.d.ts +7 -0
- package/dist/distribution/consumeImageSupport.js +25 -0
- package/dist/distribution/distributionReportSchema.d.ts +47 -0
- package/dist/distribution/distributionReportSchema.js +20 -0
- package/dist/distribution/renderImageInterface.js +1 -1
- package/dist/distribution/types.d.ts +15 -0
- package/dist/filesystem/durableWrite.d.ts +10 -0
- package/dist/filesystem/durableWrite.js +87 -0
- package/dist/filesystem/index.d.ts +2 -0
- package/dist/filesystem/index.js +2 -0
- package/dist/filesystem/retainedJsonl.d.ts +23 -0
- package/dist/filesystem/retainedJsonl.js +123 -0
- package/dist/manifest/commandSchemas.d.ts +5 -0
- package/dist/manifest/commandSchemas.js +5 -0
- package/dist/manifest/executionSchemas.d.ts +20 -0
- package/dist/manifest/executionSchemas.js +13 -3
- package/dist/manifest/index.d.ts +2 -0
- package/dist/manifest/index.js +2 -0
- package/dist/manifest/loadManifest.js +3 -26
- package/dist/manifest/mcpSchemas.d.ts +61 -0
- package/dist/manifest/mcpSchemas.js +57 -11
- package/dist/manifest/memorySchemas.d.ts +1 -1
- package/dist/manifest/memorySchemas.js +1 -1
- package/dist/manifest/parseManifest.d.ts +7 -0
- package/dist/manifest/parseManifest.js +65 -0
- package/dist/manifest/renderSpawnfile.js +4 -1
- package/dist/manifest/renderSpawnfileWorkspace.js +6 -2
- package/dist/manifest/schemas.d.ts +1206 -132
- package/dist/manifest/schemas.js +14 -4
- package/dist/manifest/teamNetworkSchemas.d.ts +1 -1
- package/dist/manifest/trainingDataSchemas.d.ts +357 -0
- package/dist/manifest/trainingDataSchemas.js +31 -0
- package/dist/manifest/trainingSchemas.d.ts +49 -0
- package/dist/manifest/trainingSchemas.js +44 -0
- package/dist/manifest/volumeFeedSchemas.d.ts +52 -0
- package/dist/manifest/volumeFeedSchemas.js +104 -0
- package/dist/manifest/workspaceSchemas.d.ts +182 -5
- package/dist/manifest/workspaceSchemas.js +111 -7
- package/dist/recording/compose.d.ts +3 -0
- package/dist/recording/compose.js +93 -0
- package/dist/recording/deployment.d.ts +15 -0
- package/dist/recording/deployment.js +38 -0
- package/dist/recording/history.d.ts +16 -0
- package/dist/recording/history.js +47 -0
- package/dist/recording/index.d.ts +9 -0
- package/dist/recording/index.js +9 -0
- package/dist/recording/moment.d.ts +61 -0
- package/dist/recording/moment.js +36 -0
- package/dist/recording/parse.d.ts +15 -0
- package/dist/recording/parse.js +74 -0
- package/dist/recording/read.d.ts +8 -0
- package/dist/recording/read.js +61 -0
- package/dist/recording/store.d.ts +10 -0
- package/dist/recording/store.js +94 -0
- package/dist/recording/sync.d.ts +24 -0
- package/dist/recording/sync.js +126 -0
- package/dist/recording/types.d.ts +45 -0
- package/dist/recording/types.js +2 -0
- package/dist/release/drainControl.d.ts +54 -0
- package/dist/release/drainControl.js +137 -0
- package/dist/release/drainPhase.d.ts +37 -0
- package/dist/release/drainPhase.js +161 -0
- package/dist/release/index.d.ts +11 -0
- package/dist/release/index.js +11 -0
- package/dist/release/ledger.d.ts +75 -0
- package/dist/release/ledger.js +111 -0
- package/dist/release/notify.d.ts +58 -0
- package/dist/release/notify.js +126 -0
- package/dist/release/pending.d.ts +35 -0
- package/dist/release/pending.js +60 -0
- package/dist/release/postDeploy.d.ts +32 -0
- package/dist/release/postDeploy.js +62 -0
- package/dist/release/releaseDefaults.d.ts +9 -0
- package/dist/release/releaseDefaults.js +115 -0
- package/dist/release/releaseDocker.d.ts +38 -0
- package/dist/release/releaseDocker.js +94 -0
- package/dist/release/releaseTypes.d.ts +94 -0
- package/dist/release/releaseTypes.js +1 -0
- package/dist/release/runRelease.d.ts +9 -0
- package/dist/release/runRelease.js +218 -0
- package/dist/release/swap.d.ts +23 -0
- package/dist/release/swap.js +55 -0
- package/dist/release/types.d.ts +50 -0
- package/dist/release/types.js +29 -0
- package/dist/report/index.d.ts +1 -0
- package/dist/report/index.js +1 -0
- package/dist/report/recording.d.ts +57 -0
- package/dist/report/recording.js +26 -0
- package/dist/report/types.d.ts +58 -0
- package/dist/runtime/container.js +8 -13
- package/dist/runtime/daimon/adapter.js +15 -4
- package/dist/runtime/daimon/config.d.ts +4 -0
- package/dist/runtime/daimon/config.js +53 -4
- package/dist/runtime/daimon/contract-manifest.json +1 -0
- package/dist/runtime/daimon/contract-manifest.sha256 +1 -0
- package/dist/runtime/daimon/contractManifest.d.ts +59 -8
- package/dist/runtime/daimon/contractManifest.js +26 -10
- package/dist/runtime/daimon/grokTurnLimits.d.ts +25 -0
- package/dist/runtime/daimon/grokTurnLimits.js +51 -0
- package/dist/runtime/daimon/grokWorkerConfigBytes.d.ts +17 -0
- package/dist/runtime/daimon/grokWorkerConfigBytes.js +17 -0
- package/dist/runtime/daimon/grokWorkerContract.d.ts +5 -0
- package/dist/runtime/daimon/grokWorkerContract.js +13 -1
- package/dist/runtime/daimon/recording.d.ts +19 -0
- package/dist/runtime/daimon/recording.js +50 -0
- package/dist/runtime/daimon/scheduleAuthority.d.ts +8 -0
- package/dist/runtime/daimon/scheduleAuthority.js +19 -5
- package/dist/runtime/daimon/wakeMoments.d.ts +15 -0
- package/dist/runtime/daimon/wakeMoments.js +17 -0
- package/dist/runtime/daimonInstall.d.ts +3 -0
- package/dist/runtime/daimonInstall.js +25 -0
- package/dist/runtime/index.d.ts +1 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/install.d.ts +2 -0
- package/dist/runtime/install.js +1 -0
- package/dist/runtime/openclaw/adapter.js +3 -0
- package/dist/runtime/pi/adapter.js +3 -0
- package/dist/runtime/pi/containerTargets.js +6 -0
- package/dist/runtime/picoclaw/adapter.js +3 -0
- package/dist/runtime/registry.d.ts +3 -0
- package/dist/runtime/registry.js +13 -1
- package/dist/runtime/types.d.ts +15 -0
- package/dist/runtime/usageLedgerRead.d.ts +6 -0
- package/dist/runtime/usageLedgerRead.js +3 -3
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/recording.d.ts +8 -0
- package/dist/shared/recording.js +25 -0
- package/dist/target/dockerCommandExecutorCore.js +1 -1
- package/dist/target/dockerTargetBinding.js +2 -1
- package/dist/volume/feedLand.d.ts +31 -0
- package/dist/volume/feedLand.js +174 -0
- package/dist/volume/feedLandings.d.ts +45 -0
- package/dist/volume/feedLandings.js +111 -0
- package/dist/volume/feedLayout.d.ts +61 -0
- package/dist/volume/feedLayout.js +234 -0
- package/dist/volume/feedLock.d.ts +7 -0
- package/dist/volume/feedLock.js +131 -0
- package/dist/volume/feedManifest.d.ts +27 -0
- package/dist/volume/feedManifest.js +123 -0
- package/dist/volume/feedPrepare.d.ts +16 -0
- package/dist/volume/feedPrepare.js +228 -0
- package/dist/volume/feedProject.d.ts +39 -0
- package/dist/volume/feedProject.js +92 -0
- package/dist/volume/feedRecord.d.ts +55 -0
- package/dist/volume/feedRecord.js +148 -0
- package/dist/volume/feedRef.d.ts +43 -0
- package/dist/volume/feedRef.js +117 -0
- package/dist/volume/feedRefresh.d.ts +15 -0
- package/dist/volume/feedRefresh.js +187 -0
- package/dist/volume/feedSource.d.ts +66 -0
- package/dist/volume/feedSource.js +104 -0
- package/dist/volume/feedTarget.d.ts +70 -0
- package/dist/volume/feedTarget.js +9 -0
- package/dist/volume/feedTestKit.d.ts +11 -0
- package/dist/volume/feedTestKit.js +45 -0
- package/dist/volume/feedVerify.d.ts +18 -0
- package/dist/volume/feedVerify.js +104 -0
- package/dist/volume/index.d.ts +13 -0
- package/dist/volume/index.js +13 -0
- package/moltnet-releases.json +4 -4
- package/package.json +3 -3
- package/runtimes.yaml +8 -6
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { instantNanos } from "./instant.js";
|
|
3
|
+
const text = z.string();
|
|
4
|
+
const id = text.min(1);
|
|
5
|
+
export const moltnetInstantSchema = text.refine((value) => {
|
|
6
|
+
try {
|
|
7
|
+
instantNanos(value);
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}, "Expected an RFC3339 instant with at most nanosecond precision");
|
|
14
|
+
const instant = moltnetInstantSchema;
|
|
15
|
+
const strings = z.array(text);
|
|
16
|
+
// Moltnet validates Actor.ID and Part.Kind, but Actor.Type is an unvalidated Go string.
|
|
17
|
+
// Accept its zero value as stored; never fill or normalize native payload fields.
|
|
18
|
+
const actor = z.object({ type: text, id, name: text.optional(), network_id: text.optional(),
|
|
19
|
+
fqid: text.optional(), credential_bound: z.boolean().optional() }).strict();
|
|
20
|
+
const target = z.object({ kind: z.enum(["room", "thread", "dm"]), room_id: text.optional(),
|
|
21
|
+
thread_id: text.optional(), parent_message_id: text.optional(), dm_id: text.optional(),
|
|
22
|
+
participant_ids: strings.optional() }).strict();
|
|
23
|
+
const part = z.object({ kind: id, text: text.optional(), media_type: text.optional(),
|
|
24
|
+
url: text.optional(), filename: text.optional(), data: z.record(text, z.unknown()).optional() }).strict();
|
|
25
|
+
export const moltnetMessageSchema = z.object({
|
|
26
|
+
id, network_id: text, origin: z.object({ network_id: text, message_id: text,
|
|
27
|
+
received_via: text.optional() }).strict().optional(), target, from: actor,
|
|
28
|
+
parts: z.array(part).nullable(), mentions: strings.nullable().optional(), created_at: instant
|
|
29
|
+
}).strict();
|
|
30
|
+
export const moltnetRoomSchema = z.object({
|
|
31
|
+
id, network_id: text.optional(), fqid: text.optional(), name: text,
|
|
32
|
+
members: strings.nullable().optional(), visibility: text.optional(), write_policy: text.optional(),
|
|
33
|
+
federation: z.union([z.enum(["all", "none"]), strings]).nullable().optional(),
|
|
34
|
+
access: z.object({ can_read: z.boolean(), can_write: z.boolean(), reason: text.optional() }).strict().optional(),
|
|
35
|
+
created_at: instant
|
|
36
|
+
}).strict();
|
|
37
|
+
export const moltnetThreadSchema = z.object({
|
|
38
|
+
id, network_id: text.optional(), fqid: text.optional(), room_id: id,
|
|
39
|
+
parent_message_id: text.optional(), message_count: z.number().int().nonnegative(),
|
|
40
|
+
last_message_at: instant.optional()
|
|
41
|
+
}).strict();
|
|
42
|
+
const direct = z.object({ id, network_id: text.optional(), fqid: text.optional(),
|
|
43
|
+
participant_ids: strings.optional(), message_count: z.number().int().nonnegative(),
|
|
44
|
+
last_message_at: instant.optional() }).strict();
|
|
45
|
+
const agentEvent = z.object({ agent_id: id, network_id: text.optional(), fqid: text.optional(),
|
|
46
|
+
name: text.optional(), message_id: text.optional(), reason: text.optional(), target: target.optional(),
|
|
47
|
+
error: text.optional(), attempts: z.number().int().optional(), classification: text.optional() }).strict();
|
|
48
|
+
const pairing = z.object({ id, remote_network_id: text, remote_network_name: text.optional(),
|
|
49
|
+
remote_base_url: text.optional(), status: text.optional(), token: text.optional(),
|
|
50
|
+
relay: z.object({ url: text, room: text.optional(), token: text.optional() }).strict().optional(),
|
|
51
|
+
diagnostics: z.object({ checked_at: instant.optional(), remote_version: text.optional(),
|
|
52
|
+
remote_network_id: text.optional(), remote_protocols: z.object({
|
|
53
|
+
http: strings.optional(), attach: strings.optional(), pair: strings.optional()
|
|
54
|
+
}).strict().optional(), reason: text.optional(), message: text.optional() }).strict().optional()
|
|
55
|
+
}).strict();
|
|
56
|
+
// The delivery store persists Event.Type without validation as well.
|
|
57
|
+
export const moltnetEventSchema = z.object({ id, type: text, network_id: text,
|
|
58
|
+
agent: agentEvent.optional(), message: moltnetMessageSchema.optional(), room: moltnetRoomSchema.optional(),
|
|
59
|
+
thread: moltnetThreadSchema.optional(), dm: direct.optional(), pairing: pairing.optional(),
|
|
60
|
+
replay_gap: z.object({ requested_event_id: text.optional(), oldest_event_id: text.optional(),
|
|
61
|
+
newest_event_id: text.optional() }).strict().optional(), created_at: instant
|
|
62
|
+
}).strict();
|
|
63
|
+
const registration = z.object({ network_id: text, agent_id: id, actor_uid: text, actor_uri: text,
|
|
64
|
+
display_name: text.optional(), credential_key: text.optional(), created_at: instant.optional(),
|
|
65
|
+
updated_at: instant.optional() }).strict();
|
|
66
|
+
const map = (value) => z.record(text, value).nullable().transform((v) => v ?? {});
|
|
67
|
+
const messages = map(z.array(moltnetMessageSchema).nullable().transform((v) => v ?? []));
|
|
68
|
+
export const moltnetSnapshotSchema = z.object({
|
|
69
|
+
rooms: map(moltnetRoomSchema), removed_rooms: map(instant).optional().default({}),
|
|
70
|
+
room_messages: messages, threads: map(moltnetThreadSchema), thread_messages: messages,
|
|
71
|
+
direct_messages: messages, direct_members: map(map(z.object({}).strict())),
|
|
72
|
+
agents: map(registration).optional().default({}),
|
|
73
|
+
attachment_delivery_events: z.array(moltnetEventSchema).nullable().optional().transform((v) => v ?? []),
|
|
74
|
+
attachment_delivery_cursors: map(z.number().int().nonnegative()).optional().default({})
|
|
75
|
+
}).strict();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type MoltnetInspection, type MoltnetMessage } from "./moltnetSchemas.js";
|
|
2
|
+
/** Mutates only a caller-created COPY. secure_delete and VACUUM remove future content from free pages. */
|
|
3
|
+
export declare const rewindMoltnetSqlite: (file: string, at: string) => Promise<MoltnetMessage[]>;
|
|
4
|
+
/** Reopens on-disk SQLite read-only; no materializer state or cut helper supplies the verdict. */
|
|
5
|
+
export interface MoltnetMessageFilter {
|
|
6
|
+
/** Room id, including messages addressed to threads in that room. */
|
|
7
|
+
room?: string;
|
|
8
|
+
sender?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface MoltnetSqliteInspection extends MoltnetInspection {
|
|
11
|
+
/** Filtered messages ordered by stored created_at TEXT, then id, like Moltnet room history. */
|
|
12
|
+
orderedMessages: Array<MoltnetMessage & {
|
|
13
|
+
/** Store-local SQLite rowid (append order), before filtering; may contain gaps. */
|
|
14
|
+
appendIndex: number;
|
|
15
|
+
}>;
|
|
16
|
+
/** All stored registrations, independent of message filters; no credential material. */
|
|
17
|
+
registrations: Array<{
|
|
18
|
+
agentId: string;
|
|
19
|
+
networkId: string;
|
|
20
|
+
actorUid: string;
|
|
21
|
+
}>;
|
|
22
|
+
/** Active rooms only, with sorted member IDs. Labels and policies remain caller-owned. */
|
|
23
|
+
rooms: Array<{
|
|
24
|
+
id: string;
|
|
25
|
+
networkId: string | undefined;
|
|
26
|
+
memberIds: string[];
|
|
27
|
+
}>;
|
|
28
|
+
/** IDs whose stored credential is not the stable token:<agent-id> placeholder. Not secret values. */
|
|
29
|
+
nonCanonicalCredentialAgentIds: string[];
|
|
30
|
+
}
|
|
31
|
+
export declare const inspectMoltnetSqlite: (file: string, at: string, filter?: MoltnetMessageFilter) => Promise<MoltnetSqliteInspection>;
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { lstat, rm } from "node:fs/promises";
|
|
2
|
+
import { compareInstants } from "./instant.js";
|
|
3
|
+
import { inspectMoltnetEvent, latestMoltnetMessage, moltnetMessages, rewindMoltnetJson } from "./moltnetJson.js";
|
|
4
|
+
import { readMoltnetSqlite, readMoltnetSqliteMigrations, sqliteInteger, sqliteText, sqliteJson } from "./moltnetSqliteData.js";
|
|
5
|
+
import { moltnetEventSchema } from "./moltnetSchemas.js";
|
|
6
|
+
const openSqlite = async (file, readOnly = false) => {
|
|
7
|
+
let sqlite;
|
|
8
|
+
try {
|
|
9
|
+
sqlite = await import("node:sqlite");
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
throw new Error("Moltnet SQLite rewind requires node:sqlite (supported Node >=22.19); this Node runtime does not expose it");
|
|
13
|
+
}
|
|
14
|
+
return new sqlite.DatabaseSync(file, { readOnly, enableForeignKeyConstraints: false, allowExtension: false });
|
|
15
|
+
};
|
|
16
|
+
/** Mutates only a caller-created COPY. secure_delete and VACUUM remove future content from free pages. */
|
|
17
|
+
export const rewindMoltnetSqlite = async (file, at) => {
|
|
18
|
+
const database = await openSqlite(file);
|
|
19
|
+
try {
|
|
20
|
+
const source = readMoltnetSqlite(database), cut = rewindMoltnetJson(source, at);
|
|
21
|
+
const messages = moltnetMessages(cut), keepMessages = new Set(messages.map((message) => message.id));
|
|
22
|
+
const eventRows = database.prepare("SELECT * FROM attachment_delivery_events ORDER BY seq").all();
|
|
23
|
+
const keepEvents = new Set(cut.attachment_delivery_events.map((event) => event.id));
|
|
24
|
+
// The database column and the embedded event each carry an instant; both must pass the cut.
|
|
25
|
+
const remainingEvents = eventRows.filter((row) => keepEvents.has(sqliteText(row, "event_id"))
|
|
26
|
+
&& compareInstants(sqliteText(row, "created_at"), at) <= 0);
|
|
27
|
+
const remainingSeq = new Set(remainingEvents.map((row) => sqliteInteger(row, "seq")));
|
|
28
|
+
database.exec("PRAGMA secure_delete=ON; PRAGMA foreign_keys=OFF; BEGIN IMMEDIATE");
|
|
29
|
+
try {
|
|
30
|
+
for (const [id, agent] of Object.entries(source.agents)) {
|
|
31
|
+
if (!cut.agents[id]) {
|
|
32
|
+
database.prepare("DELETE FROM agents WHERE agent_id = ?").run(id);
|
|
33
|
+
database.prepare("DELETE FROM room_members WHERE member_id = ?").run(id);
|
|
34
|
+
database.prepare("DELETE FROM dm_participants WHERE participant_id = ?").run(id);
|
|
35
|
+
database.prepare("DELETE FROM attachment_delivery_cursors WHERE agent_id = ?").run(id);
|
|
36
|
+
}
|
|
37
|
+
else if (agent.updated_at !== cut.agents[id].updated_at) {
|
|
38
|
+
database.prepare("UPDATE agents SET updated_at = ? WHERE agent_id = ?").run(cut.agents[id].updated_at, id);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
for (const row of readMoltnetSqliteMigrations(database)) {
|
|
42
|
+
if (compareInstants(sqliteText(row, "applied_at"), at) > 0) {
|
|
43
|
+
database.prepare("UPDATE schema_migrations SET applied_at = ? WHERE version = ?").run(at, row.version);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const dropMessage = database.prepare("DELETE FROM messages WHERE id = ?");
|
|
47
|
+
for (const message of moltnetMessages(source))
|
|
48
|
+
if (!keepMessages.has(message.id))
|
|
49
|
+
dropMessage.run(message.id);
|
|
50
|
+
const dropRoom = database.prepare("DELETE FROM rooms WHERE id = ?"), restoreRoom = database.prepare("UPDATE rooms SET deleted_at = NULL WHERE id = ?");
|
|
51
|
+
for (const id of Object.keys(source.rooms)) {
|
|
52
|
+
if (!cut.rooms[id])
|
|
53
|
+
dropRoom.run(id);
|
|
54
|
+
else if (source.removed_rooms[id] && !cut.removed_rooms[id])
|
|
55
|
+
restoreRoom.run(id);
|
|
56
|
+
}
|
|
57
|
+
database.exec("DELETE FROM room_members WHERE room_id NOT IN (SELECT id FROM rooms)");
|
|
58
|
+
const dropThread = database.prepare("DELETE FROM threads WHERE id = ?");
|
|
59
|
+
const updateThread = database.prepare("UPDATE threads SET message_count = ?, last_message_at = ? WHERE id = ?");
|
|
60
|
+
for (const id of Object.keys(source.threads)) {
|
|
61
|
+
const thread = cut.threads[id];
|
|
62
|
+
if (!thread)
|
|
63
|
+
dropThread.run(id);
|
|
64
|
+
else
|
|
65
|
+
updateThread.run(thread.message_count, thread.last_message_at, id);
|
|
66
|
+
}
|
|
67
|
+
const dropDm = database.prepare("DELETE FROM dm_conversations WHERE dm_id = ?");
|
|
68
|
+
const updateDm = database.prepare("UPDATE dm_conversations SET message_count = ?, last_message_at = ? WHERE dm_id = ?");
|
|
69
|
+
for (const row of database.prepare("SELECT dm_id FROM dm_conversations").all()) {
|
|
70
|
+
const id = sqliteText(row, "dm_id"), retained = cut.direct_messages[id] ?? [];
|
|
71
|
+
if (!retained.length)
|
|
72
|
+
dropDm.run(id);
|
|
73
|
+
else
|
|
74
|
+
updateDm.run(retained.length, latestMoltnetMessage(retained).created_at, id);
|
|
75
|
+
}
|
|
76
|
+
database.exec("DELETE FROM dm_participants WHERE dm_id NOT IN (SELECT dm_id FROM dm_conversations)");
|
|
77
|
+
database.exec("DELETE FROM artifacts WHERE message_id NOT IN (SELECT id FROM messages)");
|
|
78
|
+
const dropArtifact = database.prepare("DELETE FROM artifacts WHERE id = ?");
|
|
79
|
+
for (const row of database.prepare("SELECT id, created_at FROM artifacts").all()) {
|
|
80
|
+
if (compareInstants(sqliteText(row, "created_at"), at) > 0)
|
|
81
|
+
dropArtifact.run(sqliteText(row, "id"));
|
|
82
|
+
}
|
|
83
|
+
const dropEvent = database.prepare("DELETE FROM attachment_delivery_events WHERE seq = ?");
|
|
84
|
+
for (const row of eventRows)
|
|
85
|
+
if (!remainingSeq.has(sqliteInteger(row, "seq")))
|
|
86
|
+
dropEvent.run(sqliteInteger(row, "seq"));
|
|
87
|
+
const updateCursor = database.prepare("UPDATE attachment_delivery_cursors SET event_seq = ?, updated_at = ? WHERE agent_id = ?");
|
|
88
|
+
for (const row of database.prepare("SELECT * FROM attachment_delivery_cursors").all()) {
|
|
89
|
+
const cursor = sqliteInteger(row, "event_seq");
|
|
90
|
+
const clamped = remainingEvents.reduce((value, event) => {
|
|
91
|
+
const seq = sqliteInteger(event, "seq");
|
|
92
|
+
return seq <= cursor ? Math.max(value, seq) : value;
|
|
93
|
+
}, 0);
|
|
94
|
+
const updated = sqliteText(row, "updated_at");
|
|
95
|
+
updateCursor.run(clamped, compareInstants(updated, at) > 0 ? at : updated, sqliteText(row, "agent_id"));
|
|
96
|
+
}
|
|
97
|
+
const hasSequence = database.prepare("SELECT name FROM sqlite_schema WHERE name = 'sqlite_sequence'").get();
|
|
98
|
+
if (hasSequence)
|
|
99
|
+
database.prepare("UPDATE sqlite_sequence SET seq = ? WHERE name = 'attachment_delivery_events'")
|
|
100
|
+
.run(remainingEvents.reduce((value, row) => Math.max(value, sqliteInteger(row, "seq")), 0));
|
|
101
|
+
database.exec("COMMIT");
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
database.exec("ROLLBACK");
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
database.exec("PRAGMA wal_checkpoint(TRUNCATE); PRAGMA journal_mode=DELETE; VACUUM");
|
|
108
|
+
if (database.prepare("PRAGMA integrity_check").get()?.integrity_check !== "ok")
|
|
109
|
+
throw new Error("Rewound Moltnet SQLite integrity check failed");
|
|
110
|
+
return messages;
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
database.close();
|
|
114
|
+
for (const suffix of ["-wal", "-shm", "-journal"])
|
|
115
|
+
await rm(`${file}${suffix}`, { force: true });
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
export const inspectMoltnetSqlite = async (file, at, filter = {}) => {
|
|
119
|
+
// Validate even empty stores; findings always audit the entire store, independent of filters.
|
|
120
|
+
compareInstants(at, at);
|
|
121
|
+
for (const suffix of ["-wal", "-shm", "-journal"]) {
|
|
122
|
+
const entry = await lstat(`${file}${suffix}`).catch((error) => {
|
|
123
|
+
if (error.code === "ENOENT")
|
|
124
|
+
return null;
|
|
125
|
+
throw error;
|
|
126
|
+
});
|
|
127
|
+
// The materialized database is checkpointed. Refuse sidecars before SQLite can recover or touch them.
|
|
128
|
+
if (entry)
|
|
129
|
+
return { messages: 0, events: 0, orderedMessages: [], registrations: [], rooms: [], nonCanonicalCredentialAgentIds: [], findings: [{ class: "moltnet-event", path: `${file}${suffix}`,
|
|
130
|
+
detail: "Materialized Moltnet SQLite has an uninspected journal/WAL sidecar" }] };
|
|
131
|
+
}
|
|
132
|
+
const database = await openSqlite(file, true);
|
|
133
|
+
try {
|
|
134
|
+
const snapshot = readMoltnetSqlite(database), messages = moltnetMessages(snapshot);
|
|
135
|
+
const findings = [];
|
|
136
|
+
const check = (instant, kind, detail) => {
|
|
137
|
+
if (compareInstants(instant, at) > 0)
|
|
138
|
+
findings.push({ class: kind, path: file, detail });
|
|
139
|
+
};
|
|
140
|
+
for (const agent of Object.values(snapshot.agents)) {
|
|
141
|
+
for (const field of ["created_at", "updated_at"]) {
|
|
142
|
+
if (agent[field])
|
|
143
|
+
check(agent[field], "moltnet-event", `Agent ${agent.agent_id} has a future ${field}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
for (const row of readMoltnetSqliteMigrations(database)) {
|
|
147
|
+
check(sqliteText(row, "applied_at"), "moltnet-event", `Schema migration ${row.version} has a future applied_at`);
|
|
148
|
+
}
|
|
149
|
+
for (const message of messages)
|
|
150
|
+
check(message.created_at, "moltnet-message", `Message ${message.id} is later than the moment`);
|
|
151
|
+
for (const room of Object.values(snapshot.rooms))
|
|
152
|
+
check(room.created_at, "moltnet-room", `Room ${room.id} is later than the moment`);
|
|
153
|
+
for (const [id, instant] of Object.entries(snapshot.removed_rooms))
|
|
154
|
+
check(instant, "moltnet-room", `Room ${id} has a future removal marker`);
|
|
155
|
+
for (const row of database.prepare("SELECT id, created_at FROM artifacts").all()) {
|
|
156
|
+
check(sqliteText(row, "created_at"), "moltnet-message", `Artifact ${row.id} is later than the moment`);
|
|
157
|
+
}
|
|
158
|
+
for (const [table, id] of [["threads", "id"], ["dm_conversations", "dm_id"]]) {
|
|
159
|
+
for (const row of database.prepare(`SELECT ${id}, last_message_at FROM ${table}`).all()) {
|
|
160
|
+
check(sqliteText(row, "last_message_at"), "moltnet-message", `${table} ${row[id]} has a future counter`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
const events = database.prepare("SELECT * FROM attachment_delivery_events").all();
|
|
164
|
+
for (const row of events) {
|
|
165
|
+
check(sqliteText(row, "created_at"), "moltnet-event", `Attachment event ${row.event_id} is later than the moment`);
|
|
166
|
+
findings.push(...inspectMoltnetEvent(moltnetEventSchema.parse(sqliteJson(row, "event_json")), at, file));
|
|
167
|
+
}
|
|
168
|
+
for (const row of database.prepare("SELECT agent_id, updated_at FROM attachment_delivery_cursors").all()) {
|
|
169
|
+
check(sqliteText(row, "updated_at"), "moltnet-event", `Attachment cursor ${row.agent_id} has a future updated_at`);
|
|
170
|
+
}
|
|
171
|
+
const appendPositions = new Map(database.prepare("SELECT id, rowid AS append_index FROM messages").all()
|
|
172
|
+
.map(row => [sqliteText(row, "id"), sqliteInteger(row, "append_index")]));
|
|
173
|
+
const orderedMessages = messages.filter((message) => (filter.room === undefined || message.target.room_id === filter.room)
|
|
174
|
+
&& (filter.sender === undefined || message.from.id === filter.sender))
|
|
175
|
+
.map(message => ({ ...message, appendIndex: appendPositions.get(message.id) }))
|
|
176
|
+
.sort((a, b) => a.created_at < b.created_at ? -1 : a.created_at > b.created_at ? 1
|
|
177
|
+
: a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
178
|
+
const registrations = Object.values(snapshot.agents).map(agent => ({
|
|
179
|
+
agentId: agent.agent_id, networkId: agent.network_id, actorUid: agent.actor_uid
|
|
180
|
+
})).sort((a, b) => a.agentId < b.agentId ? -1 : a.agentId > b.agentId ? 1 : 0);
|
|
181
|
+
const rooms = Object.values(snapshot.rooms).filter(room => !Object.hasOwn(snapshot.removed_rooms, room.id))
|
|
182
|
+
.map(room => ({ id: room.id, networkId: room.network_id, memberIds: [...(room.members ?? [])].sort() }))
|
|
183
|
+
.sort((a, b) => a.id < b.id ? -1 : a.id > b.id ? 1 : 0);
|
|
184
|
+
// Compare inside SQLite so this audit projection never reads credential values into its rows.
|
|
185
|
+
const nonCanonicalCredentialAgentIds = database.prepare("SELECT agent_id FROM agents WHERE credential_key IS NULL OR credential_key != 'token:' || agent_id ORDER BY agent_id").all().map(row => sqliteText(row, "agent_id"));
|
|
186
|
+
return { messages: messages.length, events: events.length, findings, orderedMessages,
|
|
187
|
+
registrations, rooms, nonCanonicalCredentialAgentIds };
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
database.close();
|
|
191
|
+
}
|
|
192
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { DatabaseSync, SQLOutputValue } from "node:sqlite";
|
|
2
|
+
import { type MoltnetSnapshot } from "./moltnetSchemas.js";
|
|
3
|
+
export type SqliteRow = Record<string, SQLOutputValue>;
|
|
4
|
+
export declare const sqliteText: (row: SqliteRow, key: string) => string;
|
|
5
|
+
export declare const sqliteInteger: (row: SqliteRow, key: string) => number;
|
|
6
|
+
export declare const sqliteJson: (row: SqliteRow, key: string) => unknown;
|
|
7
|
+
export declare const readMoltnetSqliteMigrations: (database: DatabaseSync) => SqliteRow[];
|
|
8
|
+
/** A snapshot is an offline store: unknown tables, views or triggers cannot be safely rewound. */
|
|
9
|
+
export declare const validateSqliteLayout: (database: DatabaseSync) => void;
|
|
10
|
+
export declare const readMoltnetSqlite: (database: DatabaseSync) => MoltnetSnapshot;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { parseMoltnetSnapshot } from "./moltnetJson.js";
|
|
2
|
+
import { moltnetEventSchema } from "./moltnetSchemas.js";
|
|
3
|
+
export const sqliteText = (row, key) => {
|
|
4
|
+
if (typeof row[key] !== "string")
|
|
5
|
+
throw new Error(`Invalid Moltnet SQLite ${key}: expected text`);
|
|
6
|
+
return row[key];
|
|
7
|
+
};
|
|
8
|
+
export const sqliteInteger = (row, key) => {
|
|
9
|
+
const value = row[key];
|
|
10
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
11
|
+
throw new Error(`Invalid Moltnet SQLite ${key}: expected nonnegative safe integer`);
|
|
12
|
+
}
|
|
13
|
+
return value;
|
|
14
|
+
};
|
|
15
|
+
export const sqliteJson = (row, key) => {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(sqliteText(row, key));
|
|
18
|
+
}
|
|
19
|
+
catch (error) {
|
|
20
|
+
throw new Error(`Invalid Moltnet SQLite ${key}: ${error.message}`);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
export const readMoltnetSqliteMigrations = (database) => database.prepare("SELECT name FROM sqlite_schema WHERE name = 'schema_migrations'").get()
|
|
24
|
+
? database.prepare("SELECT version, applied_at FROM schema_migrations").all() : [];
|
|
25
|
+
const allowedColumns = {
|
|
26
|
+
rooms: ["id", "network_id", "fqid", "name", "created_at", "deleted_at", "visibility", "write_policy", "federation"],
|
|
27
|
+
room_members: ["room_id", "member_id"],
|
|
28
|
+
threads: ["id", "network_id", "fqid", "room_id", "parent_message_id", "message_count", "last_message_at"],
|
|
29
|
+
messages: ["id", "network_id", "target_kind", "room_id", "thread_id", "parent_message_id", "dm_id", "target_json",
|
|
30
|
+
"from_json", "parts_json", "mentions_json", "created_at", "origin_json"],
|
|
31
|
+
dm_conversations: ["dm_id", "network_id", "fqid", "message_count", "last_message_at"],
|
|
32
|
+
dm_participants: ["dm_id", "participant_id"],
|
|
33
|
+
artifacts: ["id", "network_id", "fqid", "message_id", "target_kind", "room_id", "thread_id", "dm_id", "target_json",
|
|
34
|
+
"part_index", "kind", "media_type", "filename", "url", "created_at"],
|
|
35
|
+
agents: ["agent_id", "network_id", "actor_uid", "actor_uri", "display_name", "credential_key", "created_at", "updated_at"],
|
|
36
|
+
attachment_delivery_events: ["seq", "event_id", "event_json", "created_at"],
|
|
37
|
+
attachment_delivery_cursors: ["agent_id", "event_seq", "updated_at"],
|
|
38
|
+
schema_migrations: ["version", "name", "applied_at"], sqlite_sequence: ["name", "seq"]
|
|
39
|
+
};
|
|
40
|
+
/** A snapshot is an offline store: unknown tables, views or triggers cannot be safely rewound. */
|
|
41
|
+
export const validateSqliteLayout = (database) => {
|
|
42
|
+
for (const row of database.prepare("SELECT type, name FROM sqlite_schema WHERE type IN ('table', 'view', 'trigger')").all()) {
|
|
43
|
+
const table = sqliteText(row, "name");
|
|
44
|
+
if (row.type !== "table" || !Object.hasOwn(allowedColumns, table)) {
|
|
45
|
+
throw new Error(`Unsupported Moltnet SQLite ${row.type} ${row.name}; cannot establish its historical contents`);
|
|
46
|
+
}
|
|
47
|
+
for (const column of database.prepare(`PRAGMA table_info(${table})`).all()) {
|
|
48
|
+
if (!allowedColumns[table].includes(sqliteText(column, "name"))) {
|
|
49
|
+
throw new Error(`Unsupported Moltnet SQLite column ${table}.${column.name}; cannot establish its historical contents`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
export const readMoltnetSqlite = (database) => {
|
|
55
|
+
validateSqliteLayout(database);
|
|
56
|
+
const rooms = {}, removed = {}, threads = {};
|
|
57
|
+
const roomMessages = {}, threadMessages = {}, directMessages = {};
|
|
58
|
+
const directMembers = {}, agents = {};
|
|
59
|
+
const roomMembers = database.prepare("SELECT room_id, member_id FROM room_members").all();
|
|
60
|
+
for (const row of database.prepare("SELECT * FROM rooms").all()) {
|
|
61
|
+
const id = sqliteText(row, "id");
|
|
62
|
+
rooms[id] = { id, network_id: row.network_id, fqid: row.fqid, name: row.name, created_at: row.created_at,
|
|
63
|
+
members: roomMembers.filter((member) => member.room_id === id).map((member) => member.member_id),
|
|
64
|
+
...(row.visibility !== undefined ? { visibility: row.visibility } : {}),
|
|
65
|
+
...(row.write_policy !== undefined ? { write_policy: row.write_policy } : {}),
|
|
66
|
+
...(row.federation !== undefined ? { federation: sqliteJson(row, "federation") } : {}) };
|
|
67
|
+
if (row.deleted_at !== null && row.deleted_at !== undefined && row.deleted_at !== "")
|
|
68
|
+
removed[id] = row.deleted_at;
|
|
69
|
+
}
|
|
70
|
+
for (const row of database.prepare("SELECT * FROM threads").all())
|
|
71
|
+
threads[sqliteText(row, "id")] = {
|
|
72
|
+
id: row.id, network_id: row.network_id, fqid: row.fqid, room_id: row.room_id,
|
|
73
|
+
parent_message_id: row.parent_message_id, message_count: row.message_count, last_message_at: row.last_message_at
|
|
74
|
+
};
|
|
75
|
+
// rowid preserves append order for a DM's first/root message; random message IDs do not.
|
|
76
|
+
for (const row of database.prepare("SELECT * FROM messages ORDER BY rowid").all()) {
|
|
77
|
+
const target = sqliteJson(row, "target_json");
|
|
78
|
+
for (const [column, key] of [["target_kind", "kind"], ["room_id", "room_id"], ["thread_id", "thread_id"],
|
|
79
|
+
["parent_message_id", "parent_message_id"], ["dm_id", "dm_id"]]) {
|
|
80
|
+
if ((row[column] ?? "") !== (target?.[key] ?? ""))
|
|
81
|
+
throw new Error(`Moltnet SQLite message ${row.id}: ${column} disagrees with target_json`);
|
|
82
|
+
}
|
|
83
|
+
const message = { id: row.id, network_id: row.network_id, target,
|
|
84
|
+
from: sqliteJson(row, "from_json"), parts: sqliteJson(row, "parts_json"), mentions: sqliteJson(row, "mentions_json"),
|
|
85
|
+
created_at: row.created_at, ...(row.origin_json !== undefined && row.origin_json !== "{}"
|
|
86
|
+
? { origin: sqliteJson(row, "origin_json") } : {}) };
|
|
87
|
+
const group = row.target_kind === "room" ? roomMessages : row.target_kind === "thread" ? threadMessages
|
|
88
|
+
: row.target_kind === "dm" ? directMessages : undefined;
|
|
89
|
+
if (!group)
|
|
90
|
+
throw new Error(`Unknown Moltnet SQLite message target kind ${row.target_kind}`);
|
|
91
|
+
const key = sqliteText(row, row.target_kind === "room" ? "room_id" : row.target_kind === "thread" ? "thread_id" : "dm_id");
|
|
92
|
+
(group[key] ??= []).push(message);
|
|
93
|
+
}
|
|
94
|
+
for (const row of database.prepare("SELECT dm_id, participant_id FROM dm_participants").all()) {
|
|
95
|
+
(directMembers[sqliteText(row, "dm_id")] ??= {})[sqliteText(row, "participant_id")] = {};
|
|
96
|
+
}
|
|
97
|
+
for (const row of database.prepare("SELECT * FROM agents").all())
|
|
98
|
+
agents[sqliteText(row, "agent_id")] = {
|
|
99
|
+
...row, ...(row.display_name === null ? { display_name: "" } : {})
|
|
100
|
+
};
|
|
101
|
+
const eventRows = database.prepare("SELECT * FROM attachment_delivery_events ORDER BY seq").all();
|
|
102
|
+
const events = eventRows.map((row) => {
|
|
103
|
+
const event = moltnetEventSchema.parse(sqliteJson(row, "event_json"));
|
|
104
|
+
if (event.id !== row.event_id)
|
|
105
|
+
throw new Error(`Moltnet SQLite event ${row.event_id} disagrees with event_json`);
|
|
106
|
+
return event;
|
|
107
|
+
});
|
|
108
|
+
const cursors = Object.fromEntries(database.prepare("SELECT * FROM attachment_delivery_cursors").all()
|
|
109
|
+
.map((row) => [sqliteText(row, "agent_id"), eventRows.filter((event) => sqliteInteger(event, "seq") <= sqliteInteger(row, "event_seq")).length]));
|
|
110
|
+
return parseMoltnetSnapshot({ rooms, removed_rooms: removed, threads, room_messages: roomMessages,
|
|
111
|
+
thread_messages: threadMessages, direct_messages: directMessages, direct_members: directMembers,
|
|
112
|
+
agents, attachment_delivery_events: events, attachment_delivery_cursors: cursors });
|
|
113
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { MomentRecord } from "../../../recording/index.js";
|
|
2
|
+
import type { InputIdentity, RewindInput } from "./types.js";
|
|
3
|
+
/** Merged recording keeps deployment uncertainty at record level, rather than naming each pin. */
|
|
4
|
+
export declare const recordActivationErrors: (record: MomentRecord | null) => string[];
|
|
5
|
+
/** Errors are free text in P3: honor explicit qualifications; otherwise conservatively match the whole ID. */
|
|
6
|
+
export declare const recordInputErrors: (record: MomentRecord, input: InputIdentity) => string[];
|
|
7
|
+
/** Do not discard healthy pins just because another input made the whole record inexact. */
|
|
8
|
+
export declare const recordForInput: (record: MomentRecord | null, input: InputIdentity) => MomentRecord | null;
|
|
9
|
+
export declare const recordPins: (record: MomentRecord | null, input: InputIdentity | RewindInput) => {
|
|
10
|
+
id: string;
|
|
11
|
+
declaredBy: string;
|
|
12
|
+
seq: number;
|
|
13
|
+
generation?: number | undefined;
|
|
14
|
+
}[] | {
|
|
15
|
+
network: string;
|
|
16
|
+
cursor: string;
|
|
17
|
+
messageIds?: string[] | undefined;
|
|
18
|
+
}[] | ({
|
|
19
|
+
id: string;
|
|
20
|
+
kind: "git";
|
|
21
|
+
commit: string;
|
|
22
|
+
sha256?: string | undefined;
|
|
23
|
+
} | {
|
|
24
|
+
id: string;
|
|
25
|
+
kind: "bundle";
|
|
26
|
+
sha256: string;
|
|
27
|
+
} | {
|
|
28
|
+
id: string;
|
|
29
|
+
revision: string;
|
|
30
|
+
tree: string;
|
|
31
|
+
landedAt: string;
|
|
32
|
+
commit?: string | undefined;
|
|
33
|
+
ref?: string | undefined;
|
|
34
|
+
paths?: string[] | undefined;
|
|
35
|
+
period?: string | undefined;
|
|
36
|
+
} | {
|
|
37
|
+
id: string;
|
|
38
|
+
snapshot: string;
|
|
39
|
+
})[];
|
|
40
|
+
export declare const hasRecordPin: (record: MomentRecord | null, input: InputIdentity | RewindInput) => boolean;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const sections = {
|
|
2
|
+
resource: "resources", resources: "resources", git: "resources", bundle: "resources", bundles: "resources",
|
|
3
|
+
feed: "resources", feeds: "resources", volume: "resources", volumes: "resources",
|
|
4
|
+
memory: "memory", bank: "memory", banks: "memory", moltnet: "networks", network: "networks", networks: "networks"
|
|
5
|
+
};
|
|
6
|
+
const ownerPattern = "(?:agent|team|org|organization):[A-Za-z0-9_.:/-]+?";
|
|
7
|
+
const qualifiedPrefix = new RegExp(`(?:^|[^A-Za-z0-9_.-])(${Object.keys(sections).join("|")})`
|
|
8
|
+
+ `(?:[\\s/]+(${ownerPattern}))?[\\s/:]+$`, "iu");
|
|
9
|
+
const ownerPrefix = new RegExp(`(?:^|[^A-Za-z0-9_.-])(${ownerPattern})[\\s/]+$`, "u");
|
|
10
|
+
const ownerSuffix = new RegExp(`^\\s*(?:\\(\\s*|declaredBy\\s*[=:]\\s*|@\\s*)(${ownerPattern})(?=[\\s):,;]|$)`, "u");
|
|
11
|
+
/** Merged recording keeps deployment uncertainty at record level, rather than naming each pin. */
|
|
12
|
+
export const recordActivationErrors = (record) => (record?.errors ?? []).filter((error) => error.includes("Deployment activation is non-exact"));
|
|
13
|
+
/** Errors are free text in P3: honor explicit qualifications; otherwise conservatively match the whole ID. */
|
|
14
|
+
export const recordInputErrors = (record, input) => {
|
|
15
|
+
const escaped = input.id.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
16
|
+
const namesInput = new RegExp(`(?<![A-Za-z0-9_.-])${escaped}(?![A-Za-z0-9_.-])`, "gu");
|
|
17
|
+
return (record.errors ?? []).filter((error) => {
|
|
18
|
+
if (recordActivationErrors(record).includes(error))
|
|
19
|
+
return false;
|
|
20
|
+
let decoded = error;
|
|
21
|
+
try {
|
|
22
|
+
decoded = decodeURIComponent(error);
|
|
23
|
+
}
|
|
24
|
+
catch { /* A literal percent is valid free text. */ }
|
|
25
|
+
return [...decoded.matchAll(namesInput)].some((match) => {
|
|
26
|
+
const prefix = decoded.slice(0, match.index);
|
|
27
|
+
const qualification = qualifiedPrefix.exec(prefix);
|
|
28
|
+
if (qualification && sections[qualification[1].toLowerCase()] !== input.section)
|
|
29
|
+
return false;
|
|
30
|
+
const owner = qualification?.[2] ?? ownerPrefix.exec(prefix)?.[1]
|
|
31
|
+
?? ownerSuffix.exec(decoded.slice(match.index + match[0].length))?.[1];
|
|
32
|
+
return !owner || owner === input.declaredBy;
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
/** Do not discard healthy pins just because another input made the whole record inexact. */
|
|
37
|
+
export const recordForInput = (record, input) => record && !recordInputErrors(record, input).length ? record : null;
|
|
38
|
+
export const recordPins = (record, input) => {
|
|
39
|
+
if (!record)
|
|
40
|
+
return [];
|
|
41
|
+
if (input.section === "memory")
|
|
42
|
+
return record.memory.filter((entry) => entry.id === input.id && entry.declaredBy === input.declaredBy);
|
|
43
|
+
if (input.section === "networks")
|
|
44
|
+
return record.moltnet.filter((entry) => entry.network === input.id);
|
|
45
|
+
const pins = !("declaration" in input) ? [...record.resources, ...record.feeds, ...record.volumes]
|
|
46
|
+
: input.declaration.kind !== "volume" ? record.resources : input.declaration.feed ? record.feeds : record.volumes;
|
|
47
|
+
return pins.filter((entry) => entry.id === input.id);
|
|
48
|
+
};
|
|
49
|
+
export const hasRecordPin = (record, input) => recordPins(record, input).length > 0;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { History } from "./history.js";
|
|
2
|
+
export declare const materializeRecordedBundle: (history: History | undefined, sha256: string, destination: string) => Promise<boolean>;
|
|
3
|
+
/** Acceptance reopens the digest-pinned archive and compares disk bytes, without trusting producer metadata. */
|
|
4
|
+
export declare const verifyRecordedBundle: (history: History | undefined, sha256: string, directory: string) => Promise<void>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { lstat, readFile, readdir } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { validateWorkspaceBundleTar } from "../../workspaceBundleArtifacts.js";
|
|
5
|
+
import { recordedSha256Schema } from "../../../recording/index.js";
|
|
6
|
+
import { extractBundleBytes } from "./gitTree.js";
|
|
7
|
+
const recordedBytes = async (history, sha256) => {
|
|
8
|
+
recordedSha256Schema.parse(sha256);
|
|
9
|
+
const bytes = await history?.bytes(`bundles/${sha256.slice(7)}.tar`);
|
|
10
|
+
if (!bytes || bytes.length > 536_870_912 || `sha256:${createHash("sha256").update(bytes).digest("hex")}` !== sha256)
|
|
11
|
+
return null;
|
|
12
|
+
return bytes;
|
|
13
|
+
};
|
|
14
|
+
export const materializeRecordedBundle = async (history, sha256, destination) => {
|
|
15
|
+
const bytes = await recordedBytes(history, sha256);
|
|
16
|
+
if (!bytes)
|
|
17
|
+
return false;
|
|
18
|
+
await extractBundleBytes(bytes, destination);
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
/** Acceptance reopens the digest-pinned archive and compares disk bytes, without trusting producer metadata. */
|
|
22
|
+
export const verifyRecordedBundle = async (history, sha256, directory) => {
|
|
23
|
+
const bytes = await recordedBytes(history, sha256);
|
|
24
|
+
if (!bytes)
|
|
25
|
+
throw new Error(`Recorded bundle ${sha256} could not be reproduced`);
|
|
26
|
+
validateWorkspaceBundleTar(bytes);
|
|
27
|
+
const text = (field) => field.toString("utf8").replace(/\0.*$/su, "");
|
|
28
|
+
const files = new Map(), directories = new Set();
|
|
29
|
+
for (let offset = 0; offset < bytes.length && !bytes.subarray(offset, offset + 512).every((byte) => byte === 0);) {
|
|
30
|
+
const header = bytes.subarray(offset, offset + 512), prefix = text(header.subarray(345, 500));
|
|
31
|
+
const name = `${prefix ? `${prefix}/` : ""}${text(header.subarray(0, 100))}`.replace(/\/$/u, "");
|
|
32
|
+
const size = Number.parseInt(text(header.subarray(124, 136)).trim(), 8);
|
|
33
|
+
for (let parent = path.posix.dirname(name); parent !== "."; parent = path.posix.dirname(parent))
|
|
34
|
+
directories.add(parent);
|
|
35
|
+
if (header[156] === 53)
|
|
36
|
+
directories.add(name);
|
|
37
|
+
else
|
|
38
|
+
files.set(name, { bytes: bytes.subarray(offset + 512, offset + 512 + size), executable: Boolean(Number.parseInt(text(header.subarray(100, 108)).trim(), 8) & 0o111) });
|
|
39
|
+
offset += 512 + Math.ceil(size / 512) * 512;
|
|
40
|
+
}
|
|
41
|
+
const walk = async (folder, prefix = "") => {
|
|
42
|
+
for (const name of await readdir(folder)) {
|
|
43
|
+
const relative = prefix ? `${prefix}/${name}` : name, full = path.join(folder, name), stats = await lstat(full);
|
|
44
|
+
if (stats.isDirectory() && directories.delete(relative))
|
|
45
|
+
await walk(full, relative);
|
|
46
|
+
else {
|
|
47
|
+
const expected = files.get(relative);
|
|
48
|
+
if (!stats.isFile() || !expected || Boolean(stats.mode & 0o111) !== expected.executable || !(await readFile(full)).equals(expected.bytes)) {
|
|
49
|
+
throw new Error(`Recorded bundle entry mismatch: ${relative}`);
|
|
50
|
+
}
|
|
51
|
+
files.delete(relative);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
await walk(directory);
|
|
56
|
+
if (files.size || directories.size)
|
|
57
|
+
throw new Error(`Missing recorded bundle entries: ${[...files.keys(), ...directories].join(", ")}`);
|
|
58
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { recordedCommitSchema } from "../../../recording/index.js";
|
|
2
|
+
import { rewindGit } from "./gitProcess.js";
|
|
3
|
+
/** Recorded identity names the commit object itself, never a selector or a peeled tag. */
|
|
4
|
+
export const resolveRecordedCommit = async (repository, value) => {
|
|
5
|
+
const commit = recordedCommitSchema.parse(value);
|
|
6
|
+
const type = (await rewindGit(repository, ["cat-file", "-t", commit])).toString().trim();
|
|
7
|
+
if (type !== "commit")
|
|
8
|
+
throw new Error(`Recorded object ${commit} must be a commit object; found ${type}`);
|
|
9
|
+
return commit;
|
|
10
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TrainingPlan } from "../plan/index.js";
|
|
2
|
+
import type { MomentRecord } from "../../../recording/index.js";
|
|
3
|
+
import type { InputIdentity, RewindInput } from "./types.js";
|
|
4
|
+
export type DatasetRole = "train" | "validation" | "test";
|
|
5
|
+
export interface SelectedExample {
|
|
6
|
+
id: string;
|
|
7
|
+
role: DatasetRole;
|
|
8
|
+
dataset: string;
|
|
9
|
+
sourcePath: string;
|
|
10
|
+
example: TrainingPlan["targets"][number]["datasets"]["train"]["examples"][number];
|
|
11
|
+
}
|
|
12
|
+
/** Shared targets referencing the same role/dataset/example are one trial. */
|
|
13
|
+
export declare const selectTrainingExample: (plan: TrainingPlan, selector: string) => SelectedExample;
|
|
14
|
+
export declare const matchingMomentRecords: (records: readonly MomentRecord[], agent: string, at: string) => MomentRecord[];
|
|
15
|
+
/** Replays can share executionId AND startedAt. Keep every earliest tie for per-input agreement. */
|
|
16
|
+
export declare const originalMomentRecords: (records: readonly MomentRecord[]) => MomentRecord[];
|
|
17
|
+
/** Capture time and wake payload are not used to materialize data. Normalize actual used instants. */
|
|
18
|
+
export declare const selectMomentRecord: (records: MomentRecord[], agent: string, at: string, inputs?: Array<InputIdentity | RewindInput>) => MomentRecord | null;
|