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,94 @@
|
|
|
1
|
+
import type { ResolvedAuthProfile } from "../auth/index.js";
|
|
2
|
+
import type { CompileProjectResult } from "../compiler/compileProject.js";
|
|
3
|
+
import type { DockerDeploymentTarget } from "../deployment/index.js";
|
|
4
|
+
import type { Availability, DrainWait, RuntimeControlTarget, WaitForDrainedOptions } from "./drainControl.js";
|
|
5
|
+
import type { NotifierConfig, NotifyResult, ReleaseNotification } from "./notify.js";
|
|
6
|
+
import type { PostDeployContext, PostDeployHook, PostDeployResult } from "./postDeploy.js";
|
|
7
|
+
import type { PruneResult, RunningUnit, SettleOptions } from "./releaseDocker.js";
|
|
8
|
+
export declare const DAIMON_CONTROL_TOKEN_ENV = "SPAWNFILE_DAIMON_CONTROL_TOKEN";
|
|
9
|
+
export interface ReleaseRequest {
|
|
10
|
+
authProfile?: ResolvedAuthProfile | null;
|
|
11
|
+
authProfileName?: string | null;
|
|
12
|
+
/** `release` (default) builds workspace bundles only from clean committed inputs. */
|
|
13
|
+
bundleIdentity: "dev" | "release";
|
|
14
|
+
deployment: string;
|
|
15
|
+
dockerCommand: string;
|
|
16
|
+
dockerContext?: string;
|
|
17
|
+
/** Set from the pinned target when it is a `DOCKER_HOST` daemon. */
|
|
18
|
+
dockerHost?: string;
|
|
19
|
+
/** False only when the operator explicitly accepts killing in-flight turns. */
|
|
20
|
+
drain: boolean;
|
|
21
|
+
drainPollMs: number;
|
|
22
|
+
drainTimeoutMs: number;
|
|
23
|
+
envFileEnv: Record<string, string>;
|
|
24
|
+
envFilePath?: string;
|
|
25
|
+
force: boolean;
|
|
26
|
+
imageRepository?: string;
|
|
27
|
+
inputPath: string;
|
|
28
|
+
log: (line: string) => void;
|
|
29
|
+
notifier: NotifierConfig;
|
|
30
|
+
notifyDeferredAfterMs: number;
|
|
31
|
+
now?: () => Date;
|
|
32
|
+
outputDirectory?: string;
|
|
33
|
+
/** Runs once the new container settled and admits; must exit 0 before the release is recorded. */
|
|
34
|
+
postDeploy?: PostDeployHook | null;
|
|
35
|
+
/** Overrides `<SPAWNFILE_HOME>/releases`. */
|
|
36
|
+
releaseRoot?: string;
|
|
37
|
+
settle: SettleOptions;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
/** The Docker daemon every step of this release talks to, pinned once at the start. */
|
|
40
|
+
target?: DockerDeploymentTarget;
|
|
41
|
+
}
|
|
42
|
+
export interface CompiledRelease {
|
|
43
|
+
compileMs: number;
|
|
44
|
+
compileResult: CompileProjectResult;
|
|
45
|
+
identity: string;
|
|
46
|
+
repository: string;
|
|
47
|
+
}
|
|
48
|
+
export interface BuiltRelease {
|
|
49
|
+
buildMs: number | null;
|
|
50
|
+
imageId: string;
|
|
51
|
+
imageTag: string;
|
|
52
|
+
skipped: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface DeployedRelease {
|
|
55
|
+
containerName: string;
|
|
56
|
+
deployMs: number;
|
|
57
|
+
}
|
|
58
|
+
export interface PreparedInputs {
|
|
59
|
+
authProfile: ResolvedAuthProfile | null;
|
|
60
|
+
envFileEnv: Record<string, string>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Every effect a release has, injectable so the ORDER (drain before deploy,
|
|
64
|
+
* resume on abort, never deploy on a drain timeout) is asserted by tests
|
|
65
|
+
* rather than by a comment.
|
|
66
|
+
*/
|
|
67
|
+
export interface ReleaseDependencies {
|
|
68
|
+
build(request: ReleaseRequest, compiled: CompiledRelease, imageTag: string): Promise<BuiltRelease>;
|
|
69
|
+
compile(request: ReleaseRequest): Promise<CompiledRelease>;
|
|
70
|
+
/** Deploys while the caller holds the deployment lock (see `lockDeployment`). */
|
|
71
|
+
deploy(request: ReleaseRequest, imageTag: string): Promise<DeployedRelease>;
|
|
72
|
+
inspectUnit(request: ReleaseRequest, containerRef: string): Promise<RunningUnit | null>;
|
|
73
|
+
/** The same home lock `up` takes, held from the drain through the swap. */
|
|
74
|
+
lockDeployment(deployment: string): Promise<() => Promise<void>>;
|
|
75
|
+
notify(config: NotifierConfig, notification: ReleaseNotification): Promise<NotifyResult>;
|
|
76
|
+
/** Reads the env file and auth profile inside the release, so their failures are reported like any other. */
|
|
77
|
+
prepare(request: ReleaseRequest): Promise<PreparedInputs>;
|
|
78
|
+
prune(request: ReleaseRequest, repository: string, keep: readonly (string | null)[]): Promise<PruneResult>;
|
|
79
|
+
/** Runtime kinds inside the running image, from its embedded distribution report. */
|
|
80
|
+
runtimesOf(request: ReleaseRequest, imageId: string): Promise<string[]>;
|
|
81
|
+
requestDrain(target: RuntimeControlTarget): Promise<Availability>;
|
|
82
|
+
/**
|
|
83
|
+
* The Docker daemon this release talks to, with its endpoint fingerprint:
|
|
84
|
+
* an explicit `--context`, else what the Docker CLI would use
|
|
85
|
+
* (`DOCKER_HOST`, `DOCKER_CONTEXT` or the selected context).
|
|
86
|
+
*/
|
|
87
|
+
pinTarget(request: ReleaseRequest): Promise<DockerDeploymentTarget>;
|
|
88
|
+
/** Throws when a recorded target's endpoint is no longer the one its name resolves to. */
|
|
89
|
+
verifyTarget(request: ReleaseRequest, target: DockerDeploymentTarget): Promise<void>;
|
|
90
|
+
requestResume(target: RuntimeControlTarget): Promise<Availability>;
|
|
91
|
+
runPostDeploy(request: ReleaseRequest, hook: PostDeployHook, context: PostDeployContext): Promise<PostDeployResult>;
|
|
92
|
+
settle(request: ReleaseRequest, containerRef: string): Promise<RunningUnit>;
|
|
93
|
+
waitForDrained(target: RuntimeControlTarget, options: WaitForDrainedOptions): Promise<DrainWait>;
|
|
94
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DAIMON_CONTROL_TOKEN_ENV = "SPAWNFILE_DAIMON_CONTROL_TOKEN";
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ReleaseDependencies, type ReleaseRequest } from "./releaseTypes.js";
|
|
2
|
+
import { type ReleaseOutcome } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* compile → identity → (unchanged? stop) → build → drain → deploy → settle →
|
|
5
|
+
* resume → post-deploy → record → prune. The ledger is written last because it claims
|
|
6
|
+
* "this identity is RUNNING"; written earlier it would claim a container that
|
|
7
|
+
* never came up, and the next run would see nothing to do.
|
|
8
|
+
*/
|
|
9
|
+
export declare const runRelease: (request: ReleaseRequest, deps: ReleaseDependencies) => Promise<ReleaseOutcome>;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { rm } from "node:fs/promises";
|
|
2
|
+
import { normalizeDeploymentName } from "../deployment/index.js";
|
|
3
|
+
import { controlTargetFor, recoverInterruptedDrain, requestForTarget, resolveControlToken } from "./drainPhase.js";
|
|
4
|
+
import { acquireReleaseLock, appendReleaseLog, postDeployPending, ensureReleaseDirectory, readReleaseLedger, resolveReleasePaths, writeJsonAtomic, writeReleaseLedger } from "./ledger.js";
|
|
5
|
+
import { createNotification } from "./notify.js";
|
|
6
|
+
import { clearDeferral, markDeferralNotified, recordDeferral } from "./pending.js";
|
|
7
|
+
import { releaseImageTag } from "./releaseDocker.js";
|
|
8
|
+
import { DAIMON_CONTROL_TOKEN_ENV } from "./releaseTypes.js";
|
|
9
|
+
import { drainAndSwap, releaseContainerName } from "./swap.js";
|
|
10
|
+
import { ReleaseError, isReleaseError } from "./types.js";
|
|
11
|
+
/**
|
|
12
|
+
* compile → identity → (unchanged? stop) → build → drain → deploy → settle →
|
|
13
|
+
* resume → post-deploy → record → prune. The ledger is written last because it claims
|
|
14
|
+
* "this identity is RUNNING"; written earlier it would claim a container that
|
|
15
|
+
* never came up, and the next run would see nothing to do.
|
|
16
|
+
*/
|
|
17
|
+
export const runRelease = async (request, deps) => {
|
|
18
|
+
// One spelling everywhere: storage, the container name, the lock and `up` all normalize it.
|
|
19
|
+
request.deployment = normalizeDeploymentName(request.deployment);
|
|
20
|
+
const paths = resolveReleasePaths(request.deployment, request.releaseRoot);
|
|
21
|
+
const progress = { identity: null, stage: "lock" };
|
|
22
|
+
let unlock = null;
|
|
23
|
+
try {
|
|
24
|
+
await ensureReleaseDirectory(paths);
|
|
25
|
+
unlock = await acquireReleaseLock(paths);
|
|
26
|
+
progress.stage = "prepare";
|
|
27
|
+
Object.assign(request, await deps.prepare(request));
|
|
28
|
+
progress.stage = "recover";
|
|
29
|
+
await recoverInterruptedDrain(request, deps, paths);
|
|
30
|
+
progress.stage = "target";
|
|
31
|
+
const pinned = requestForTarget(request, await deps.pinTarget(request));
|
|
32
|
+
return await releaseLocked(pinned, deps, paths, progress);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
return fail(request, deps, paths, progress, error);
|
|
36
|
+
}
|
|
37
|
+
finally {
|
|
38
|
+
await unlock?.().catch(() => undefined);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
const releaseLocked = async (request, deps, paths, progress) => {
|
|
42
|
+
const started = Date.now();
|
|
43
|
+
progress.stage = "compile";
|
|
44
|
+
const compiled = await deps.compile(request).catch((error) => {
|
|
45
|
+
throw new ReleaseError("build-failed", `compile failed: ${error.message}`, { cause: error });
|
|
46
|
+
});
|
|
47
|
+
progress.identity = compiled.identity;
|
|
48
|
+
const imageTag = releaseImageTag(compiled.repository, compiled.identity);
|
|
49
|
+
progress.stage = "inspect";
|
|
50
|
+
const ledger = await readReleaseLedger(paths.ledger);
|
|
51
|
+
const running = await deps.inspectUnit(request, releaseContainerName(request.deployment));
|
|
52
|
+
// A post-deploy command that failed (or never finished) leaves its marker: the
|
|
53
|
+
// running container may be the recorded image, but the release is not done.
|
|
54
|
+
const hookPending = await postDeployPending(paths.postDeploy);
|
|
55
|
+
if (!hookPending && isUnchanged(request, ledger, compiled.identity, running)) {
|
|
56
|
+
await clearDeferral(paths.pending);
|
|
57
|
+
request.log(`release: ${compiled.identity.slice(0, 19)} is already running as ${ledger.image_tag}; nothing to do`);
|
|
58
|
+
return { identity: compiled.identity, imageTag: ledger.image_tag, kind: "unchanged" };
|
|
59
|
+
}
|
|
60
|
+
if (request.drain && running?.running && resolveControlToken(request) === null) {
|
|
61
|
+
throw new ReleaseError("blocked", `${DAIMON_CONTROL_TOKEN_ENV} is not set in the env file or environment; a drained release needs the running deployment's control token`);
|
|
62
|
+
}
|
|
63
|
+
request.log(ledger
|
|
64
|
+
? `release: ${compiled.identity.slice(0, 19)} differs from the released ${ledger.identity.slice(0, 19)} (${ledger.image_tag}); releasing`
|
|
65
|
+
: `release: nothing recorded as released for ${request.deployment}; releasing ${compiled.identity.slice(0, 19)}`);
|
|
66
|
+
// The tag about to be built is kept too: a retry after a failed deploy reuses it instead of rebuilding.
|
|
67
|
+
await pruneQuietly(request, deps, compiled.repository, [imageTag, ledger?.image_tag ?? null, ledger?.previous_image_tag ?? null]);
|
|
68
|
+
progress.stage = "build";
|
|
69
|
+
const built = await deps.build(request, compiled, imageTag).catch((error) => {
|
|
70
|
+
throw new ReleaseError("build-failed", `image build failed: ${error.message}`, { cause: error });
|
|
71
|
+
});
|
|
72
|
+
request.log(built.skipped ? `release: ${imageTag} already built; build skipped` : `release: built ${imageTag} in ${Math.round((built.buildMs ?? 0) / 1000)}s`);
|
|
73
|
+
progress.stage = "deploy";
|
|
74
|
+
if (request.signal?.aborted)
|
|
75
|
+
throw new ReleaseError("interrupted", "the release was interrupted before draining; nothing was paused or deployed");
|
|
76
|
+
// The same home lock `up` takes, held from before the drain until the ledger
|
|
77
|
+
// names what is running: no concurrent `up` can replace the drained
|
|
78
|
+
// container, or the candidate before it is recorded.
|
|
79
|
+
const unlockDeployment = await deps.lockDeployment(request.deployment).catch((error) => {
|
|
80
|
+
throw new ReleaseError("blocked", `cannot lock the deployment: ${error.message}`);
|
|
81
|
+
});
|
|
82
|
+
try {
|
|
83
|
+
return await swapAndRecord(request, deps, paths, progress, { built, compiled, imageTag, ledger, started });
|
|
84
|
+
}
|
|
85
|
+
finally {
|
|
86
|
+
await unlockDeployment().catch(() => undefined);
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const swapAndRecord = async (request, deps, paths, progress, { built, compiled, imageTag, ledger, started }) => {
|
|
90
|
+
const swap = await drainAndSwap(request, deps, paths, imageTag);
|
|
91
|
+
if (swap.kind === "deferred")
|
|
92
|
+
return defer(request, deps, paths, compiled.identity);
|
|
93
|
+
const { deployed, drained } = swap;
|
|
94
|
+
progress.stage = "settle";
|
|
95
|
+
const settled = await deps.settle(request, deployed.containerName);
|
|
96
|
+
if (settled.imageId !== built.imageId) {
|
|
97
|
+
throw new ReleaseError("deploy-failed", `the settled container runs ${settled.imageId}, not the built ${built.imageId}`);
|
|
98
|
+
}
|
|
99
|
+
if (request.drain) {
|
|
100
|
+
progress.stage = "resume";
|
|
101
|
+
try {
|
|
102
|
+
await deps.requestResume(controlTargetFor(request, settled.id, settled.imageId));
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
throw new ReleaseError("resume-failed", `the new container did not confirm admission: ${error.message}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (request.postDeploy) {
|
|
109
|
+
progress.stage = "post-deploy";
|
|
110
|
+
await writeJsonAtomic(paths.postDeploy, { at: (request.now?.() ?? new Date()).toISOString(), identity: compiled.identity }).catch((error) => {
|
|
111
|
+
throw new ReleaseError("post-deploy-failed", `cannot record that a post-deploy command is pending, so it was not run: ${error.message}`);
|
|
112
|
+
});
|
|
113
|
+
await runPostDeployStep(request, deps, request.postDeploy, {
|
|
114
|
+
containerName: deployed.containerName, deployment: request.deployment, identity: compiled.identity, imageId: settled.imageId, imageTag
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
progress.stage = "record";
|
|
118
|
+
const timings = {
|
|
119
|
+
build_ms: built.buildMs,
|
|
120
|
+
compile_ms: compiled.compileMs,
|
|
121
|
+
deploy_ms: deployed.deployMs,
|
|
122
|
+
drain_ms: drained.drainMs,
|
|
123
|
+
total_ms: Date.now() - started
|
|
124
|
+
};
|
|
125
|
+
const next = {
|
|
126
|
+
compile_fingerprint: compiled.compileResult.report.compile_fingerprint ?? "unknown",
|
|
127
|
+
deployment: request.deployment,
|
|
128
|
+
identity: compiled.identity,
|
|
129
|
+
image_id: settled.imageId,
|
|
130
|
+
image_tag: imageTag,
|
|
131
|
+
previous_image_tag: ledger && ledger.image_tag !== imageTag ? ledger.image_tag : ledger?.previous_image_tag ?? null,
|
|
132
|
+
released_at: (request.now?.() ?? new Date()).toISOString(),
|
|
133
|
+
timings,
|
|
134
|
+
version: "spawnfile.release-ledger.v1"
|
|
135
|
+
};
|
|
136
|
+
await writeReleaseLedger(paths.ledger, next).catch((error) => {
|
|
137
|
+
throw new ReleaseError("ledger-failed", `the deployment is running but the release ledger could not be written (every later run will redeploy until it can): ${error.message}`);
|
|
138
|
+
});
|
|
139
|
+
await rm(paths.postDeploy, { force: true }).catch((error) => {
|
|
140
|
+
request.log(`release: cannot clear the post-deploy marker, so the next run releases again: ${error.message}`);
|
|
141
|
+
});
|
|
142
|
+
await appendReleaseLog(paths.log, { at: next.released_at, deployment: request.deployment, identity: compiled.identity, image_tag: imageTag, outcome: "released", timings }).catch(() => undefined);
|
|
143
|
+
await clearDeferral(paths.pending).catch(() => undefined);
|
|
144
|
+
await pruneQuietly(request, deps, compiled.repository, [imageTag, next.previous_image_tag]);
|
|
145
|
+
request.log(`release: ${imageTag} deployed, settled and recorded (build ${timings.build_ms === null ? "skipped" : `${Math.round(timings.build_ms / 1000)}s`}, drain ${Math.round((timings.drain_ms ?? 0) / 1000)}s, total ${Math.round(timings.total_ms / 1000)}s)`);
|
|
146
|
+
return { identity: compiled.identity, imageId: settled.imageId, imageTag, kind: "released", timings };
|
|
147
|
+
};
|
|
148
|
+
/** A failed hook leaves the release unrecorded: the next run deploys again and reruns it. */
|
|
149
|
+
const runPostDeployStep = async (request, deps, hook, context) => {
|
|
150
|
+
if (request.signal?.aborted)
|
|
151
|
+
throw new ReleaseError("interrupted", "the release was interrupted after deploying; the post-deploy command did not run and nothing was recorded");
|
|
152
|
+
let result;
|
|
153
|
+
try {
|
|
154
|
+
result = await deps.runPostDeploy(request, hook, context);
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
throw new ReleaseError("post-deploy-failed", `the post-deploy command could not run: ${error.message}`);
|
|
158
|
+
}
|
|
159
|
+
const output = result.output.trim();
|
|
160
|
+
if (output)
|
|
161
|
+
request.log(`release: post-deploy output:\n${output}`);
|
|
162
|
+
if (request.signal?.aborted)
|
|
163
|
+
throw new ReleaseError("interrupted", "the release was interrupted while the post-deploy command ran; nothing was recorded");
|
|
164
|
+
if (result.timedOut)
|
|
165
|
+
throw new ReleaseError("post-deploy-failed", `the post-deploy command did not finish within ${Math.round(hook.timeoutMs / 1000)}s`);
|
|
166
|
+
if (result.exitCode !== 0)
|
|
167
|
+
throw new ReleaseError("post-deploy-failed", `the post-deploy command exited ${result.exitCode ?? "by signal"}${output ? `: ${output.slice(-300)}` : ""}`);
|
|
168
|
+
request.log("release: post-deploy command succeeded");
|
|
169
|
+
};
|
|
170
|
+
/** Unchanged means the recorded identity is the one the container is actually running, not merely the one last built. */
|
|
171
|
+
const isUnchanged = (request, ledger, identity, running) => !request.force && ledger !== null && ledger.identity === identity && running !== null && running.running && running.imageId === ledger.image_id;
|
|
172
|
+
const pruneQuietly = async (request, deps, repository, keep) => {
|
|
173
|
+
try {
|
|
174
|
+
const pruned = await deps.prune(request, repository, keep);
|
|
175
|
+
for (const tag of pruned.removed)
|
|
176
|
+
request.log(`release: removed old image ${tag}`);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
request.log(`release: image prune skipped (${error.message.slice(0, 160)})`);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const defer = async (request, deps, paths, identity) => {
|
|
183
|
+
const decision = await recordDeferral(paths.pending, identity, { notifyAfterMs: request.notifyDeferredAfterMs, ...(request.now ? { now: request.now() } : {}) });
|
|
184
|
+
const hours = Math.floor(decision.ageMs / 3_600_000);
|
|
185
|
+
const message = decision.trackingBroken
|
|
186
|
+
? `release deferred (running turns did not finish within the drain bound) and ${decision.trackingBroken}`
|
|
187
|
+
: `release deferred: running turns did not finish within the drain bound; pending ${hours}h`;
|
|
188
|
+
request.log(`release: ${message}; admission resumed, nothing deployed, retry on the next run`);
|
|
189
|
+
const at = (request.now?.() ?? new Date()).toISOString();
|
|
190
|
+
await appendReleaseLog(paths.log, { at, deployment: request.deployment, identity, message, outcome: "deferred", reason: "release-deferred" }).catch(() => undefined);
|
|
191
|
+
const notified = decision.notify ? await notifyAndLog(request, deps, paths, "release-deferred", message, identity) : false;
|
|
192
|
+
if (notified && !decision.trackingBroken)
|
|
193
|
+
await markDeferralNotified(paths.pending, decision.pending).catch(() => undefined);
|
|
194
|
+
return { identity, kind: "deferred", message, notified };
|
|
195
|
+
};
|
|
196
|
+
const fail = async (request, deps, paths, progress, error) => {
|
|
197
|
+
const reason = isReleaseError(error) ? error.reason : "blocked";
|
|
198
|
+
const message = `${reason} at ${progress.stage}: ${error instanceof Error ? error.message : String(error)}`;
|
|
199
|
+
request.log(`release FAILED: ${message}`);
|
|
200
|
+
const at = (request.now?.() ?? new Date()).toISOString();
|
|
201
|
+
await appendReleaseLog(paths.log, { at, deployment: request.deployment, identity: progress.identity, message, outcome: "failed", reason }).catch(() => undefined);
|
|
202
|
+
const notified = await notifyAndLog(request, deps, paths, reason, message, progress.identity);
|
|
203
|
+
return { identity: progress.identity, kind: "failed", message, notified, reason };
|
|
204
|
+
};
|
|
205
|
+
const notifyAndLog = async (request, deps, paths, reason, message, identity) => {
|
|
206
|
+
if (request.notifier.kind === "none")
|
|
207
|
+
return false;
|
|
208
|
+
const notification = createNotification({ deployment: request.deployment, identity, message, reason, ...(request.now ? { now: request.now() } : {}) });
|
|
209
|
+
const result = await deps.notify(request.notifier, notification).catch((error) => ({ channel: request.notifier.kind, delivered: false, error: error.message }));
|
|
210
|
+
if (!result.delivered)
|
|
211
|
+
request.log(`release: notifier did not deliver (${result.error ?? "unknown"}); the message is in ${paths.log}`);
|
|
212
|
+
await appendReleaseLog(paths.log, {
|
|
213
|
+
at: notification.at, deployment: request.deployment, identity, message: notification.message,
|
|
214
|
+
notified: { channel: result.channel, delivered: result.delivered, ...(result.error ? { error: result.error } : {}) },
|
|
215
|
+
outcome: "notified", reason
|
|
216
|
+
}).catch(() => undefined);
|
|
217
|
+
return result.delivered;
|
|
218
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type DrainOutcome } from "./drainPhase.js";
|
|
2
|
+
import type { ReleasePaths } from "./ledger.js";
|
|
3
|
+
import type { DeployedRelease, ReleaseDependencies, ReleaseRequest } from "./releaseTypes.js";
|
|
4
|
+
/** Runtimes whose admission a release can pause through a published control contract. */
|
|
5
|
+
export declare const DRAINABLE_RUNTIMES: ReadonlySet<string>;
|
|
6
|
+
/** `up --image` names the deployment's container this way; a release replaces exactly that container. */
|
|
7
|
+
export declare const releaseContainerName: (deployment: string) => string;
|
|
8
|
+
export type SwapOutcome = {
|
|
9
|
+
deployed: DeployedRelease;
|
|
10
|
+
drained: DrainOutcome;
|
|
11
|
+
kind: "deployed";
|
|
12
|
+
} | {
|
|
13
|
+
drained: DrainOutcome;
|
|
14
|
+
kind: "deferred";
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Drain and swap. The caller holds the deployment's home lock, so no
|
|
18
|
+
* concurrent `up` can replace the drained container between the drain and
|
|
19
|
+
* the deploy. The container is inspected again under the lock (a long build may have outlived
|
|
20
|
+
* the first inspection) and once more after the drain: a different container,
|
|
21
|
+
* or one that restarted and therefore admits again, aborts the release.
|
|
22
|
+
*/
|
|
23
|
+
export declare const drainAndSwap: (request: ReleaseRequest, deps: ReleaseDependencies, paths: ReleasePaths, imageTag: string) => Promise<SwapOutcome>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { clearDrainMarker, drainForRelease, resumeAfterFailedDeploy, resumeDrained } from "./drainPhase.js";
|
|
2
|
+
import { ReleaseError } from "./types.js";
|
|
3
|
+
/** Runtimes whose admission a release can pause through a published control contract. */
|
|
4
|
+
export const DRAINABLE_RUNTIMES = new Set(["daimon"]);
|
|
5
|
+
/** `up --image` names the deployment's container this way; a release replaces exactly that container. */
|
|
6
|
+
export const releaseContainerName = (deployment) => `spawnfile-${deployment}`;
|
|
7
|
+
/**
|
|
8
|
+
* Drain and swap. The caller holds the deployment's home lock, so no
|
|
9
|
+
* concurrent `up` can replace the drained container between the drain and
|
|
10
|
+
* the deploy. The container is inspected again under the lock (a long build may have outlived
|
|
11
|
+
* the first inspection) and once more after the drain: a different container,
|
|
12
|
+
* or one that restarted and therefore admits again, aborts the release.
|
|
13
|
+
*/
|
|
14
|
+
export const drainAndSwap = async (request, deps, paths, imageTag) => {
|
|
15
|
+
const containerName = releaseContainerName(request.deployment);
|
|
16
|
+
const target = await deps.inspectUnit(request, containerName);
|
|
17
|
+
if (request.drain && target?.running) {
|
|
18
|
+
const runtimes = await deps.runtimesOf(request, target.imageId).catch((error) => {
|
|
19
|
+
throw new ReleaseError("blocked", `cannot read which runtimes the running image holds, so it cannot be shown drainable: ${error.message}`);
|
|
20
|
+
});
|
|
21
|
+
const undrainable = [...new Set(runtimes)].filter((runtime) => !DRAINABLE_RUNTIMES.has(runtime));
|
|
22
|
+
if (runtimes.length === 0 || undrainable.length > 0) {
|
|
23
|
+
throw new ReleaseError("blocked", `the running container holds runtimes without a drain contract (${undrainable.join(", ") || "none listed"}); draining it could not stop their turns. Use --no-drain to deploy over them deliberately`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
const drained = await drainForRelease(request, deps, paths, target);
|
|
27
|
+
if (drained.kind === "timeout")
|
|
28
|
+
return { drained, kind: "deferred" };
|
|
29
|
+
if (drained.kind === "drained" && target) {
|
|
30
|
+
// Anything that stops the release between the drain and the deploy resumes the drained container.
|
|
31
|
+
try {
|
|
32
|
+
const now = await deps.inspectUnit(request, containerName);
|
|
33
|
+
if (now === null || now.id !== target.id || now.restartCount !== target.restartCount || !now.running) {
|
|
34
|
+
throw new ReleaseError("drain-failed", "the drained container was replaced or restarted before the deploy; a restarted runtime admits again, so nothing was deployed");
|
|
35
|
+
}
|
|
36
|
+
if (request.signal?.aborted)
|
|
37
|
+
throw new ReleaseError("interrupted", "the release was interrupted after draining; admission resumed, nothing deployed");
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
await resumeDrained(request, deps, paths, target);
|
|
41
|
+
throw error instanceof ReleaseError ? error : new ReleaseError("drain-failed", `cannot confirm the drained container before deploying: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
let deployed;
|
|
45
|
+
try {
|
|
46
|
+
deployed = await deps.deploy(request, imageTag);
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
await resumeAfterFailedDeploy(request, deps, paths, containerName);
|
|
50
|
+
throw new ReleaseError("deploy-failed", `deploy failed: ${error.message}`, { cause: error });
|
|
51
|
+
}
|
|
52
|
+
// The drained container was replaced; its drain ended with its process.
|
|
53
|
+
await clearDrainMarker(paths);
|
|
54
|
+
return { deployed, drained, kind: "deployed" };
|
|
55
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixed vocabulary a release failure is reported in. A notifier receives
|
|
3
|
+
* exactly one of these words, so whoever reads the notification learns a small
|
|
4
|
+
* closed set rather than free text; the detail travels separately.
|
|
5
|
+
*/
|
|
6
|
+
export declare const RELEASE_FAILURE_REASONS: readonly ["blocked", "build-failed", "drain-failed", "deploy-failed", "health-failed", "resume-failed", "post-deploy-failed", "ledger-failed", "interrupted", "release-deferred"];
|
|
7
|
+
export type ReleaseFailureReason = (typeof RELEASE_FAILURE_REASONS)[number];
|
|
8
|
+
/** Carries the reason word with the error so the orchestrator never guesses it. */
|
|
9
|
+
export declare class ReleaseError extends Error {
|
|
10
|
+
readonly reason: ReleaseFailureReason;
|
|
11
|
+
constructor(reason: ReleaseFailureReason, message: string, options?: ErrorOptions);
|
|
12
|
+
}
|
|
13
|
+
export declare const isReleaseError: (value: unknown) => value is ReleaseError;
|
|
14
|
+
export interface ReleaseTimings {
|
|
15
|
+
build_ms: number | null;
|
|
16
|
+
compile_ms: number;
|
|
17
|
+
deploy_ms: number | null;
|
|
18
|
+
drain_ms: number | null;
|
|
19
|
+
total_ms: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* `released`: a new image is running and recorded. `unchanged`: the recorded
|
|
23
|
+
* identity is the one running, nothing was built or touched. `deferred`: the
|
|
24
|
+
* running organization did not drain within the bound, the release was
|
|
25
|
+
* abandoned before deploying and admission resumed. `failed`: see `reason`.
|
|
26
|
+
*/
|
|
27
|
+
export type ReleaseOutcome = {
|
|
28
|
+
identity: string;
|
|
29
|
+
imageTag: string;
|
|
30
|
+
kind: "unchanged";
|
|
31
|
+
} | {
|
|
32
|
+
identity: string;
|
|
33
|
+
imageId: string;
|
|
34
|
+
imageTag: string;
|
|
35
|
+
kind: "released";
|
|
36
|
+
timings: ReleaseTimings;
|
|
37
|
+
} | {
|
|
38
|
+
identity: string;
|
|
39
|
+
kind: "deferred";
|
|
40
|
+
message: string;
|
|
41
|
+
notified: boolean;
|
|
42
|
+
} | {
|
|
43
|
+
identity: string | null;
|
|
44
|
+
kind: "failed";
|
|
45
|
+
message: string;
|
|
46
|
+
notified: boolean;
|
|
47
|
+
reason: ReleaseFailureReason;
|
|
48
|
+
};
|
|
49
|
+
/** Exit codes: 0 released/unchanged, 75 (EX_TEMPFAIL) deferred, 1 failed. */
|
|
50
|
+
export declare const releaseExitCode: (outcome: ReleaseOutcome) => number;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fixed vocabulary a release failure is reported in. A notifier receives
|
|
3
|
+
* exactly one of these words, so whoever reads the notification learns a small
|
|
4
|
+
* closed set rather than free text; the detail travels separately.
|
|
5
|
+
*/
|
|
6
|
+
export const RELEASE_FAILURE_REASONS = Object.freeze([
|
|
7
|
+
"blocked",
|
|
8
|
+
"build-failed",
|
|
9
|
+
"drain-failed",
|
|
10
|
+
"deploy-failed",
|
|
11
|
+
"health-failed",
|
|
12
|
+
"resume-failed",
|
|
13
|
+
"post-deploy-failed",
|
|
14
|
+
"ledger-failed",
|
|
15
|
+
"interrupted",
|
|
16
|
+
"release-deferred"
|
|
17
|
+
]);
|
|
18
|
+
/** Carries the reason word with the error so the orchestrator never guesses it. */
|
|
19
|
+
export class ReleaseError extends Error {
|
|
20
|
+
reason;
|
|
21
|
+
constructor(reason, message, options) {
|
|
22
|
+
super(message, options);
|
|
23
|
+
this.reason = reason;
|
|
24
|
+
this.name = "ReleaseError";
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export const isReleaseError = (value) => value instanceof ReleaseError;
|
|
28
|
+
/** Exit codes: 0 released/unchanged, 75 (EX_TEMPFAIL) deferred, 1 failed. */
|
|
29
|
+
export const releaseExitCode = (outcome) => outcome.kind === "failed" ? 1 : outcome.kind === "deferred" ? 75 : 0;
|
package/dist/report/index.d.ts
CHANGED
package/dist/report/index.js
CHANGED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Portable compiled facts, persisted with the deployment so sync never recompiles. */
|
|
3
|
+
export declare const recordingAgentSchema: z.ZodObject<{
|
|
4
|
+
node_id: z.ZodString;
|
|
5
|
+
slug: z.ZodString;
|
|
6
|
+
directory: z.ZodString;
|
|
7
|
+
keep_ms: z.ZodNumber;
|
|
8
|
+
networks: z.ZodArray<z.ZodString>;
|
|
9
|
+
memory: z.ZodArray<z.ZodObject<{
|
|
10
|
+
id: z.ZodString;
|
|
11
|
+
declared_by: z.ZodString;
|
|
12
|
+
ledger_path: z.ZodNullable<z.ZodString>;
|
|
13
|
+
}, z.core.$strict>>;
|
|
14
|
+
feeds: z.ZodArray<z.ZodObject<{
|
|
15
|
+
id: z.ZodString;
|
|
16
|
+
volume_name: z.ZodString;
|
|
17
|
+
}, z.core.$strict>>;
|
|
18
|
+
resources: z.ZodArray<z.ZodObject<{
|
|
19
|
+
id: z.ZodString;
|
|
20
|
+
kind: z.ZodEnum<{
|
|
21
|
+
git: "git";
|
|
22
|
+
bundle: "bundle";
|
|
23
|
+
}>;
|
|
24
|
+
}, z.core.$strict>>;
|
|
25
|
+
snapshots: z.ZodArray<z.ZodString>;
|
|
26
|
+
}, z.core.$strict>;
|
|
27
|
+
export type RecordingAgentReport = z.infer<typeof recordingAgentSchema>;
|
|
28
|
+
/** Optional members preserve S1 records; sync requires the compiled agents member. */
|
|
29
|
+
export declare const recordingReportSchema: z.ZodObject<{
|
|
30
|
+
keep_ms: z.ZodNumber;
|
|
31
|
+
memory_mount_ids: z.ZodArray<z.ZodString>;
|
|
32
|
+
recording_mount_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
33
|
+
agents: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
34
|
+
node_id: z.ZodString;
|
|
35
|
+
slug: z.ZodString;
|
|
36
|
+
directory: z.ZodString;
|
|
37
|
+
keep_ms: z.ZodNumber;
|
|
38
|
+
networks: z.ZodArray<z.ZodString>;
|
|
39
|
+
memory: z.ZodArray<z.ZodObject<{
|
|
40
|
+
id: z.ZodString;
|
|
41
|
+
declared_by: z.ZodString;
|
|
42
|
+
ledger_path: z.ZodNullable<z.ZodString>;
|
|
43
|
+
}, z.core.$strict>>;
|
|
44
|
+
feeds: z.ZodArray<z.ZodObject<{
|
|
45
|
+
id: z.ZodString;
|
|
46
|
+
volume_name: z.ZodString;
|
|
47
|
+
}, z.core.$strict>>;
|
|
48
|
+
resources: z.ZodArray<z.ZodObject<{
|
|
49
|
+
id: z.ZodString;
|
|
50
|
+
kind: z.ZodEnum<{
|
|
51
|
+
git: "git";
|
|
52
|
+
bundle: "bundle";
|
|
53
|
+
}>;
|
|
54
|
+
}, z.core.$strict>>;
|
|
55
|
+
snapshots: z.ZodArray<z.ZodString>;
|
|
56
|
+
}, z.core.$strict>>>;
|
|
57
|
+
}, z.core.$strict>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const text = z.string().min(1);
|
|
3
|
+
const mountId = text.regex(/^[A-Za-z0-9][A-Za-z0-9_.-]*$/u).refine((value) => !value.includes(".."));
|
|
4
|
+
const containerPath = text.startsWith("/").refine((value) => !value.includes("\0"));
|
|
5
|
+
const keepMs = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
|
|
6
|
+
/** Portable compiled facts, persisted with the deployment so sync never recompiles. */
|
|
7
|
+
export const recordingAgentSchema = z.object({
|
|
8
|
+
node_id: text,
|
|
9
|
+
slug: text.regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/u),
|
|
10
|
+
directory: containerPath,
|
|
11
|
+
keep_ms: keepMs,
|
|
12
|
+
networks: z.array(text),
|
|
13
|
+
memory: z.array(z.object({ id: text, declared_by: text, ledger_path: containerPath.nullable() }).strict()),
|
|
14
|
+
feeds: z.array(z.object({ id: text, volume_name: text }).strict()),
|
|
15
|
+
resources: z.array(z.object({ id: text, kind: z.enum(["git", "bundle"]) }).strict()),
|
|
16
|
+
snapshots: z.array(text)
|
|
17
|
+
}).strict().refine((value) => value.directory === `/var/lib/spawnfile/recording/${value.slug}`, {
|
|
18
|
+
message: "Recording directory must match the compiled agent slug"
|
|
19
|
+
});
|
|
20
|
+
/** Optional members preserve S1 records; sync requires the compiled agents member. */
|
|
21
|
+
export const recordingReportSchema = z.object({
|
|
22
|
+
keep_ms: keepMs,
|
|
23
|
+
memory_mount_ids: z.array(mountId),
|
|
24
|
+
recording_mount_ids: z.array(mountId).optional(),
|
|
25
|
+
agents: z.array(recordingAgentSchema).optional()
|
|
26
|
+
}).strict();
|