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,14 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { readdir, rm } from "node:fs/promises";
|
|
3
|
+
/** Deployment records and histories are host state, not replaceable compile output. */
|
|
4
|
+
export const cleanCompileOutput = async (directory) => {
|
|
5
|
+
const entries = await readdir(directory).catch((error) => {
|
|
6
|
+
if (error.code === "ENOENT")
|
|
7
|
+
return [];
|
|
8
|
+
throw error;
|
|
9
|
+
});
|
|
10
|
+
for (const entry of entries)
|
|
11
|
+
if (entry !== "deployments") {
|
|
12
|
+
await rm(path.join(directory, entry), { recursive: true, force: true });
|
|
13
|
+
}
|
|
14
|
+
};
|
|
@@ -26,6 +26,7 @@ export const getAgentFingerprint = (node) => stableStringify({
|
|
|
26
26
|
requiresMcp: skill.requiresMcp
|
|
27
27
|
})),
|
|
28
28
|
surfaces: node.surfaces,
|
|
29
|
+
training: node.training,
|
|
29
30
|
workspaceResources: node.workspaceResources
|
|
30
31
|
});
|
|
31
32
|
export const getTeamFingerprint = (node) => stableStringify({
|
|
@@ -35,6 +36,7 @@ export const getTeamFingerprint = (node) => stableStringify({
|
|
|
35
36
|
lead: node.lead,
|
|
36
37
|
external: node.external,
|
|
37
38
|
networks: node.networks ?? [],
|
|
39
|
+
training: node.training,
|
|
38
40
|
workspaceResources: node.workspaceResources,
|
|
39
41
|
shared: {
|
|
40
42
|
env: node.shared.env,
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
+
import type { DaimonContractManifest } from "../runtime/daimon/contractManifest.js";
|
|
1
2
|
import { CompileReport } from "../report/index.js";
|
|
2
3
|
import { type RuntimePackageOverrideRequest } from "./containerPackageOverrides.js";
|
|
4
|
+
import type { BundleIdentityMode } from "./workspaceBundleFiles.js";
|
|
3
5
|
import { type MoltnetTargetArchitecture } from "./moltnetBinaries.js";
|
|
4
6
|
import { type OrganizationReadinessEvidence } from "./organizationReadyEvidence.js";
|
|
5
7
|
export { createOrganizationReadinessEvidence, ORGANIZATION_READINESS_EVIDENCE_VERSION } from "./organizationReadyEvidence.js";
|
|
6
8
|
export type { CreateOrganizationReadinessEvidenceInput, OrganizationReadinessEvidence } from "./organizationReadyEvidence.js";
|
|
7
9
|
export interface CompileProjectOptions {
|
|
10
|
+
/** Test seam for the receipt-bound manifest; normal compilation uses the verified vendored bytes. */
|
|
11
|
+
daimonContractManifest?: DaimonContractManifest;
|
|
12
|
+
/** Docker CLI for dependency installs and image-run generated bundle steps; defaults to `docker`. */
|
|
13
|
+
bundleDockerCommand?: string;
|
|
14
|
+
/** Cache for built workspace bundles; defaults to `$SPAWNFILE_HOME/cache/workspace-bundles`. */
|
|
15
|
+
bundleCacheDirectory?: string;
|
|
16
|
+
/** `release` builds bundles only from clean committed inputs; `dev` (default) includes uncommitted edits. */
|
|
17
|
+
bundleIdentity?: BundleIdentityMode;
|
|
8
18
|
clean?: boolean;
|
|
9
19
|
containerArchitecture?: MoltnetTargetArchitecture;
|
|
10
20
|
/** Stable deployment identity for exclusive credential-realm reattachment. */
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { cleanCompileOutput } from "./cleanCompileOutput.js";
|
|
2
|
+
import { assertRecordingCapability } from "./recordingCapability.js";
|
|
1
3
|
import path from "node:path";
|
|
2
4
|
import { chmod } from "node:fs/promises";
|
|
3
|
-
import { ensureDirectory
|
|
5
|
+
import { ensureDirectory } from "../filesystem/index.js";
|
|
4
6
|
import { createCompileReport, createDiagnostic, writeCompileReport } from "../report/index.js";
|
|
5
7
|
import { DEFAULT_OUTPUT_DIRECTORY } from "../shared/index.js";
|
|
6
8
|
import { assertRuntimeCanCompile, createRuntimeLifecycleDiagnostics, getRuntimeAdapter, resolveNoopolisRunId } from "../runtime/index.js";
|
|
@@ -8,6 +10,8 @@ import { buildCompilePlan } from "./buildCompilePlan.js";
|
|
|
8
10
|
import { createContainerArtifacts } from "./containerArtifacts.js";
|
|
9
11
|
import { stageRuntimePackageOverrides } from "./containerPackageOverrides.js";
|
|
10
12
|
import { stageWorkspaceBundles } from "./workspaceBundleArtifacts.js";
|
|
13
|
+
import { resolveWorkspaceBundles } from "./workspaceBundleResolve.js";
|
|
14
|
+
import { resolveWorkspaceGitPins } from "./workspaceGitPins.js";
|
|
11
15
|
import { augmentNodeReports } from "./compileProjectReports.js";
|
|
12
16
|
import { enforcePolicy } from "./compileProjectPolicy.js";
|
|
13
17
|
import { injectMoltnetWorkspaceFiles, injectTeamCompileSupportFiles, prepareTeamCompileSupport, writeEmittedFiles } from "./compileProjectSupport.js";
|
|
@@ -141,6 +145,7 @@ const compileTeamNode = async (baseDirectory, node) => {
|
|
|
141
145
|
};
|
|
142
146
|
export const compileProject = async (inputPath, options = {}) => {
|
|
143
147
|
const plan = await buildCompilePlan(inputPath);
|
|
148
|
+
await assertRecordingCapability(plan, options.daimonContractManifest);
|
|
144
149
|
const worldBindings = options.worldBindingsPath === undefined
|
|
145
150
|
? undefined
|
|
146
151
|
: await loadWorldBindingsForCompile(plan, options.worldBindingsPath, resolveNoopolisRunId(process.env));
|
|
@@ -150,9 +155,22 @@ export const compileProject = async (inputPath, options = {}) => {
|
|
|
150
155
|
? path.resolve(options.outputDirectory)
|
|
151
156
|
: path.join(path.dirname(plan.root), DEFAULT_OUTPUT_DIRECTORY);
|
|
152
157
|
if (options.clean ?? true) {
|
|
153
|
-
await
|
|
158
|
+
await cleanCompileOutput(outputDirectory);
|
|
154
159
|
}
|
|
155
160
|
await ensureDirectory(outputDirectory);
|
|
161
|
+
const workspaceBundles = await resolveWorkspaceBundles(plan, {
|
|
162
|
+
architecture: options.containerArchitecture,
|
|
163
|
+
cacheDirectory: options.bundleCacheDirectory,
|
|
164
|
+
...(options.bundleDockerCommand !== undefined ? { dockerCommand: options.bundleDockerCommand } : {}),
|
|
165
|
+
identity: options.bundleIdentity,
|
|
166
|
+
outputDirectory
|
|
167
|
+
});
|
|
168
|
+
const workspaceGitPins = await resolveWorkspaceGitPins(plan, {
|
|
169
|
+
architecture: options.containerArchitecture,
|
|
170
|
+
bundleCacheDirectory: options.bundleCacheDirectory,
|
|
171
|
+
identity: options.bundleIdentity,
|
|
172
|
+
outputDirectory
|
|
173
|
+
});
|
|
156
174
|
const teamCompileSupport = await prepareTeamCompileSupport(plan);
|
|
157
175
|
const nodeReports = [];
|
|
158
176
|
const compiledNodes = [];
|
|
@@ -180,7 +198,7 @@ export const compileProject = async (inputPath, options = {}) => {
|
|
|
180
198
|
: undefined;
|
|
181
199
|
await injectMoltnetWorkspaceFiles(outputDirectory, compiledNodes, moltnetArtifacts);
|
|
182
200
|
const resolvedRuntimePackageOverrides = await stageRuntimePackageOverrides(outputDirectory, options.runtimePackageOverrides);
|
|
183
|
-
const hasWorkspaceBundles = await stageWorkspaceBundles(outputDirectory, plan);
|
|
201
|
+
const hasWorkspaceBundles = await stageWorkspaceBundles(outputDirectory, plan, new Map([...workspaceBundles.built, ...workspaceGitPins.built]));
|
|
184
202
|
const generatedAt = new Date().toISOString();
|
|
185
203
|
const containerArtifacts = await createContainerArtifacts(plan, compiledNodes, {
|
|
186
204
|
deploymentLineage: options.deploymentLineage,
|
|
@@ -190,6 +208,8 @@ export const compileProject = async (inputPath, options = {}) => {
|
|
|
190
208
|
moltnet: moltnetArtifacts,
|
|
191
209
|
moltnetRelease,
|
|
192
210
|
runtimePackageOverrides: resolvedRuntimePackageOverrides,
|
|
211
|
+
workspaceGitResources: workspaceGitPins.report,
|
|
212
|
+
workspaceBundles: workspaceBundles.report,
|
|
193
213
|
...(worldBindings ? { worldBindings } : {})
|
|
194
214
|
});
|
|
195
215
|
await writeEmittedFiles(outputDirectory, containerArtifacts.files);
|
|
@@ -200,6 +220,12 @@ export const compileProject = async (inputPath, options = {}) => {
|
|
|
200
220
|
outputDirectory,
|
|
201
221
|
projectName: containerArtifacts.distribution.report.organization.project
|
|
202
222
|
});
|
|
223
|
+
if (workspaceBundles.report.length > 0)
|
|
224
|
+
report.workspace_bundles = workspaceBundles.report;
|
|
225
|
+
if (workspaceGitPins.report.length > 0)
|
|
226
|
+
report.workspace_git_resources = workspaceGitPins.report;
|
|
227
|
+
if (containerArtifacts.distribution.report.recording)
|
|
228
|
+
report.recording = containerArtifacts.distribution.report.recording;
|
|
203
229
|
const reportPath = await writeCompileReport(outputDirectory, report);
|
|
204
230
|
const organizationReadinessEvidence = createOrganizationReadinessEvidence({
|
|
205
231
|
compileVersion: report.spawnfile_version,
|
|
@@ -71,6 +71,7 @@ export const createMoltnetSummary = (moltnet, release) => {
|
|
|
71
71
|
}
|
|
72
72
|
return {
|
|
73
73
|
node_plans: moltnet.nodePlans.map((plan) => ({
|
|
74
|
+
...(plan.sourceNodeId ? { node_id: plan.sourceNodeId } : {}),
|
|
74
75
|
config_path: plan.configPath,
|
|
75
76
|
...(plan.credentialAgentId ? { credential_agent_id: plan.credentialAgentId } : {}),
|
|
76
77
|
...(plan.credentialId ? { credential_id: plan.credentialId } : {}),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { CompileReport } from "../report/index.js";
|
|
1
2
|
import { type RuntimeContainerPackageOverrides } from "../runtime/index.js";
|
|
2
3
|
import type { MoltnetArtifacts } from "./moltnetArtifacts.js";
|
|
3
4
|
import type { MoltnetReleaseIdentity } from "./moltnetBinaries.js";
|
|
@@ -13,10 +14,9 @@ export interface ContainerArtifactOptions {
|
|
|
13
14
|
moltnet?: MoltnetArtifacts | null;
|
|
14
15
|
moltnetRelease?: MoltnetReleaseIdentity;
|
|
15
16
|
worldBindings?: ResolvedWorldBindings;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
* standard compile. */
|
|
17
|
+
workspaceGitResources?: CompileReport["workspace_git_resources"];
|
|
18
|
+
workspaceBundles?: CompileReport["workspace_bundles"];
|
|
19
|
+
/** Opt-in install overrides resolved by stageRuntimePackageOverrides. */
|
|
20
20
|
runtimePackageOverrides?: RuntimeContainerPackageOverrides;
|
|
21
21
|
}
|
|
22
22
|
export declare const createContainerArtifacts: (plan: CompilePlan, compiledNodes: CompiledNodeArtifact[], options?: ContainerArtifactOptions) => Promise<GeneratedContainerArtifacts>;
|
|
@@ -8,35 +8,15 @@ import { createDockerIgnoreContent } from "./dockerBuildContext.js";
|
|
|
8
8
|
import { createDaimonTelemetryArtifacts } from "./daimonTelemetryArtifacts.js";
|
|
9
9
|
import { createRootfsFiles, renderDockerfile, renderEntrypoint, renderEnvExample } from "./containerArtifactsRender.js";
|
|
10
10
|
import { createMemoryArtifactBundle } from "./memoryArtifacts.js";
|
|
11
|
+
import { resolveRecordingReport } from "./recordingReport.js";
|
|
11
12
|
import { resolveWorkspaceResourceVolumes } from "./containerTargetResources.js";
|
|
12
13
|
import { mergePersistentMounts } from "./containerPersistentMounts.js";
|
|
13
14
|
import { SIMFILE_WORLD_BINDINGS_VERSION, WORLD_BINDINGS_OUTPUT_FILE } from "./worldBindings.js";
|
|
14
15
|
/**
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* A daimon Moltnet attachment lowers a node runtime config of
|
|
20
|
-
* `kind: "daimon"` carrying `agent_id`, `token_env`, and `receipt_store_path`
|
|
21
|
-
* (`./moltnetRuntimeConfig.ts`). No published Moltnet release implements that
|
|
22
|
-
* kind -- `pkg/bridgeconfig` has no `RuntimeDaimon` through the latest tag, and
|
|
23
|
-
* `pkg/nodeconfig` decodes with `DisallowUnknownFields()`, so the node exits on
|
|
24
|
-
* `agent_id` at strict decode, before `Validate()` is even reached. The
|
|
25
|
-
* entrypoint launches `moltnet node <config> &` and then `wait -n`
|
|
26
|
-
* (`./containerEntrypointRender.ts`), so that exit tears the whole container
|
|
27
|
-
* down. Both a locally built Moltnet (`./localMoltnetAuthority.ts`) and, since
|
|
28
|
-
* the v0.1.18 pin, the published authority (`./moltnetReleaseAuthority.ts`) can
|
|
29
|
-
* advertise `daimon-bridge`; anything older, including every release through
|
|
30
|
-
* v0.1.17, advertises only `pi-bridge` and is still rejected here.
|
|
31
|
-
*
|
|
32
|
-
* This throws rather than warning, which is the opposite call from the other
|
|
33
|
-
* unlowerable-declaration diagnostics in this compiler. Those keep working
|
|
34
|
-
* projects compiling; here every affected project is already broken, and the
|
|
35
|
-
* failure it replaces is an opaque JSON decode error at container boot.
|
|
36
|
-
*
|
|
37
|
-
* `receiptStorePath` is set on a node plan if and only if the attached agent's
|
|
38
|
-
* runtime is daimon (`./moltnetArtifacts.ts`), so it is the exact daimon
|
|
39
|
-
* signal on an already-resolved plan.
|
|
16
|
+
* Refuse a Daimon attachment unless the pinned Moltnet release advertises
|
|
17
|
+
* daimon-bridge (specs/SURFACES.md). Older pi-only releases reject its config
|
|
18
|
+
* and tear down the container at boot. receiptStorePath identifies resolved
|
|
19
|
+
* Daimon attachments; unsupported configs are errors, never degradations.
|
|
40
20
|
*/
|
|
41
21
|
const assertMoltnetDaimonBridgeCapability = (moltnet, release) => {
|
|
42
22
|
const daimonNetworks = [...new Set((moltnet?.nodePlans ?? [])
|
|
@@ -95,6 +75,7 @@ export const createContainerArtifacts = async (plan, compiledNodes, options = {}
|
|
|
95
75
|
.map((variable) => variable.name)
|
|
96
76
|
.sort();
|
|
97
77
|
const memoryArtifacts = createMemoryArtifactBundle(plan, options.deploymentLineage);
|
|
78
|
+
const recording = resolveRecordingReport(plan, memoryArtifacts.memories, options.workspaceGitResources);
|
|
98
79
|
const { resources: resolvedWorkspaceResources, mounts: workspaceResourceMounts } = resolveWorkspaceResourceVolumes(runtimePlans);
|
|
99
80
|
const persistentMountCandidates = [
|
|
100
81
|
...memoryArtifacts.mounts,
|
|
@@ -130,6 +111,9 @@ export const createContainerArtifacts = async (plan, compiledNodes, options = {}
|
|
|
130
111
|
.map((plan) => {
|
|
131
112
|
const telemetryMountIds = daimonTelemetryArtifacts.telemetryMountIdsByInstance.get(plan.id);
|
|
132
113
|
return {
|
|
114
|
+
...(plan.agentPathsByNodeId ? { agent_paths: Object.fromEntries(Object.entries(plan.agentPathsByNodeId).map(([id, paths]) => [id, {
|
|
115
|
+
workspace_path: paths.workspacePath, home_path: paths.homePath, skill_roots: paths.skillRoots
|
|
116
|
+
}])) } : {}),
|
|
133
117
|
config_path: plan.instancePaths.configPath,
|
|
134
118
|
home_path: plan.instancePaths.homePath ?? null,
|
|
135
119
|
id: plan.id,
|
|
@@ -202,15 +186,10 @@ export const createContainerArtifacts = async (plan, compiledNodes, options = {}
|
|
|
202
186
|
modelAuthMethods: mergedModelAuthMethods,
|
|
203
187
|
moltnetNetworks,
|
|
204
188
|
organization,
|
|
205
|
-
//
|
|
206
|
-
//
|
|
207
|
-
// that host. An author-DECLARED name is different — it is part of the
|
|
208
|
-
// declaration the image publishes, so a consumer must honour it verbatim
|
|
209
|
-
// or an operator who pre-created that volume silently gets an empty one.
|
|
189
|
+
// Derived volume names encode private host paths. Only author-declared
|
|
190
|
+
// names are portable; image consumers must honor them verbatim.
|
|
210
191
|
persistentMounts: persistentMounts.map((mount) => ({
|
|
211
|
-
...(mount.declared_volume_name
|
|
212
|
-
? { declared_volume_name: mount.declared_volume_name }
|
|
213
|
-
: {}),
|
|
192
|
+
...(mount.declared_volume_name ? { declared_volume_name: mount.declared_volume_name } : {}),
|
|
214
193
|
durability: "persistent",
|
|
215
194
|
id: mount.id,
|
|
216
195
|
kind: "volume",
|
|
@@ -219,6 +198,11 @@ export const createContainerArtifacts = async (plan, compiledNodes, options = {}
|
|
|
219
198
|
})),
|
|
220
199
|
portMappings,
|
|
221
200
|
publishedPorts,
|
|
201
|
+
...(recording ? {
|
|
202
|
+
recording,
|
|
203
|
+
workspaceGitResources: options.workspaceGitResources?.map(({ id, commit, sha256, agent_node_ids, declared_by }) => ({ id, commit, sha256, agent_node_ids: agent_node_ids, ...(declared_by ? { declared_by } : {}) })),
|
|
204
|
+
workspaceBundles: options.workspaceBundles?.map(({ id, sha256, origin, agent_node_ids, declared_by }) => ({ id, sha256, origin, agent_node_ids: agent_node_ids, ...(declared_by ? { declared_by } : {}) }))
|
|
205
|
+
} : {}),
|
|
222
206
|
resources: workspaceResources.map((resource) => ({
|
|
223
207
|
id: resource.id,
|
|
224
208
|
kind: resource.kind,
|
|
@@ -227,7 +211,7 @@ export const createContainerArtifacts = async (plan, compiledNodes, options = {}
|
|
|
227
211
|
mount: resource.mount,
|
|
228
212
|
sharing: resource.sharing
|
|
229
213
|
})),
|
|
230
|
-
runtimeInstances,
|
|
214
|
+
runtimeInstances: runtimeInstances.map(({ agent_paths: _paths, ...instance }) => instance),
|
|
231
215
|
...(worldBindingsEvidence ? { worldBindings: worldBindingsEvidence } : {})
|
|
232
216
|
});
|
|
233
217
|
const distributionLabels = createDistributionImageLabels(projectSlug, distributionReport.compile_fingerprint);
|
|
@@ -93,9 +93,16 @@ export const createRuntimeTargetPlans = async (plan, compiledNodes, worldBinding
|
|
|
93
93
|
const instancePaths = resolveInstancePaths(runtimeName, target.id, adapter.container);
|
|
94
94
|
const portStride = adapter.container.portStride ?? 1;
|
|
95
95
|
runtimePlans.push({
|
|
96
|
+
...(target.agentPathsByNodeId ? { agentPathsByNodeId: Object.fromEntries(Object.entries(target.agentPathsByNodeId).map(([id, paths]) => {
|
|
97
|
+
const expand = (value) => value.replaceAll("<instance-root>", instancePaths.instanceRoot)
|
|
98
|
+
.replaceAll("<workspace-path>", instancePaths.workspacePath);
|
|
99
|
+
return [id, { workspacePath: expand(paths.workspacePath),
|
|
100
|
+
homePath: paths.homePath === null ? null : expand(paths.homePath), skillRoots: paths.skillRoots.map(expand) }];
|
|
101
|
+
})) } : {}),
|
|
96
102
|
configEnvBindings: resolveTargetConfigEnvBindings(adapter.container, target) ?? [],
|
|
97
103
|
...(target.engineByNodeId ? { engineByNodeId: target.engineByNodeId } : {}),
|
|
98
104
|
...(target.grokModelByNodeId ? { grokModelByNodeId: target.grokModelByNodeId } : {}),
|
|
105
|
+
...(target.grokTurnLimitsByNodeId ? { grokTurnLimitsByNodeId: target.grokTurnLimitsByNodeId } : {}),
|
|
99
106
|
envFiles: resolveTargetEnvFiles(instancePaths.configPath, target),
|
|
100
107
|
packages: resolveTargetPackages(target, targetInputs),
|
|
101
108
|
id: target.id,
|
|
@@ -14,6 +14,7 @@ export interface ContainerEnvVariable {
|
|
|
14
14
|
required: boolean;
|
|
15
15
|
}
|
|
16
16
|
export interface RuntimeTargetPlan {
|
|
17
|
+
agentPathsByNodeId?: import("../runtime/types.js").ContainerTarget["agentPathsByNodeId"];
|
|
17
18
|
configEnvBindings?: RuntimeContainerConfigEnvBinding[];
|
|
18
19
|
/** Passthrough of `ContainerTarget.engineByNodeId` (see `runtime/types.ts`), for
|
|
19
20
|
* `containerArtifacts.ts` to stamp onto `ContainerRuntimeInstanceReport.engine_by_node_id`. */
|
|
@@ -23,6 +24,12 @@ export interface RuntimeTargetPlan {
|
|
|
23
24
|
model: string;
|
|
24
25
|
reasoningEffort: string;
|
|
25
26
|
}>;
|
|
27
|
+
/** Passthrough of `ContainerTarget.grokTurnLimitsByNodeId` for the Daimon broker worker render. */
|
|
28
|
+
grokTurnLimitsByNodeId?: Record<string, {
|
|
29
|
+
maxRequests?: number;
|
|
30
|
+
maxTokens?: number;
|
|
31
|
+
timeoutMs?: number;
|
|
32
|
+
}>;
|
|
26
33
|
packages?: ResolvedPackage[];
|
|
27
34
|
envFiles: Array<{
|
|
28
35
|
envName: string;
|
|
@@ -109,4 +109,6 @@ optionalDenyPaths?: readonly string[],
|
|
|
109
109
|
* pass a path outside it: a `tmp/` inside a cleared root is a mount point in
|
|
110
110
|
* the training launch, and clearing a mount point fails `EBUSY`.
|
|
111
111
|
*/
|
|
112
|
-
brokerTmpdir?: string
|
|
112
|
+
brokerTmpdir?: string,
|
|
113
|
+
/** Root-owned training deny targets, created after root reset and before worker attestation. */
|
|
114
|
+
beforeWorkerProvisioning?: readonly string[]) => string[];
|
|
@@ -146,7 +146,9 @@ optionalDenyPaths,
|
|
|
146
146
|
* pass a path outside it: a `tmp/` inside a cleared root is a mount point in
|
|
147
147
|
* the training launch, and clearing a mount point fails `EBUSY`.
|
|
148
148
|
*/
|
|
149
|
-
brokerTmpdir = DAIMON_BROKER_TMPDIR
|
|
149
|
+
brokerTmpdir = DAIMON_BROKER_TMPDIR,
|
|
150
|
+
/** Root-owned training deny targets, created after root reset and before worker attestation. */
|
|
151
|
+
beforeWorkerProvisioning = []) => {
|
|
150
152
|
const program = [
|
|
151
153
|
"const crypto = require('node:crypto'); const fs = require('node:fs');",
|
|
152
154
|
`const registrations = ${JSON.stringify(registrations.map(({ agentId, home, slot, uid, workspace }) => ({ agentId, home, slot, uid, workspace })))};`,
|
|
@@ -169,8 +171,8 @@ brokerTmpdir = DAIMON_BROKER_TMPDIR) => {
|
|
|
169
171
|
`const atomicOwned = (target, bytes) => { const temporary = \`${"${target}"}.\${process.pid}.\${crypto.randomUUID()}.tmp\`; try { const output = fs.openSync(temporary, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_NOFOLLOW, 0o600); try { let written = 0; while (written < bytes.length) written += fs.writeSync(output, bytes, written, bytes.length - written, written); fs.fchmodSync(output, 0o600); fs.fchownSync(output, 2100, 2100); fs.fsyncSync(output); } finally { fs.closeSync(output); } fs.renameSync(temporary, target); const directory = fs.openSync(require('node:path').dirname(target), fs.constants.O_RDONLY | fs.constants.O_DIRECTORY); try { fs.fsyncSync(directory); } finally { fs.closeSync(directory); } } catch (error) { try { fs.unlinkSync(temporary); } catch {} throw error; } };`,
|
|
170
172
|
"let existing; try { existing = fs.lstatSync(authority); } catch (error) { if (error.code !== 'ENOENT') throw error; } const bootstrapBytes = readSecure(bootstrap, undefined, 'bootstrap'); let bootstrapRecord; try { const root = JSON.parse(bootstrapBytes.toString('utf8')), rows = root && typeof root === 'object' && !Array.isArray(root) ? Object.entries(root).filter(([key, value]) => /^https:\\/\\/auth\\.x\\.ai::/.test(key) && value && typeof value === 'object' && !Array.isArray(value)).map(([, value]) => value) : []; if (rows.length !== 1 || typeof rows[0].key !== 'string' || !rows[0].key.trim() || typeof rows[0].refresh_token !== 'string' || !rows[0].refresh_token.trim() || typeof rows[0].expires_at !== 'string' || !Number.isFinite(Date.parse(rows[0].expires_at))) throw new Error(); bootstrapRecord = true; } catch { bootstrapBytes.fill(0); throw new Error('invalid broker credential bootstrap'); } if (!bootstrapRecord) throw new Error('invalid broker credential bootstrap'); const bootstrapDigest = crypto.createHash('sha256').update(bootstrapBytes).digest('hex');",
|
|
171
173
|
`const journalRoot = '${DAIMON_BROKER_REALM}/.daimon-broker'; let journalRootExists = false; try { const info = fs.lstatSync(journalRoot); if (!info.isDirectory() || info.isSymbolicLink() || info.uid !== 2100 || info.gid !== 2100 || (info.mode & 0o777) !== 0o700) throw new Error('unsafe broker credential journal directory'); fs.chownSync(journalRoot, 0, 0); fs.chmodSync(journalRoot, 0o700); journalRootExists = true; } catch (error) { if (error.code !== 'ENOENT') throw error; }`,
|
|
172
|
-
|
|
173
|
-
"if (journalRootExists) { fs.chownSync(journalRoot, 0, 0); fs.chmodSync(journalRoot, 0o700); fs.chownSync(journalRoot, 2100, 2100); }
|
|
174
|
+
"const credentialExpiry = (bytes) => { try { const rows = Object.entries(JSON.parse(bytes.toString('utf8'))).filter(([key]) => /^https:\\/\\/auth\\.x\\.ai::/.test(key)).map(([, value]) => value); const expiry = rows.length === 1 && typeof rows[0]?.expires_at === 'string' ? Date.parse(rows[0].expires_at) : NaN; if (!Number.isFinite(expiry)) throw new Error(); return expiry; } catch { throw new Error('invalid broker credential expiry'); } };",
|
|
175
|
+
`try { const journalPath = '${DAIMON_BROKER_REALM}/.daimon-broker/credential-journal.json'; let journal; try { const raw = readSecure(journalPath, 2100, 'recovery journal'); journal = JSON.parse(raw.toString('utf8')); raw.fill(0); } catch (error) { if (error.code !== 'ENOENT') throw error; } const stale = journal?.version === 'noopolis.daimon.broker-credential-journal.v1' && journal.state === 'stale'; const recover = () => { if (!stale || !Number.isSafeInteger(journal.generation) || journal.generation < 0 || !/^[a-f0-9]{64}$/.test(journal.sourceDigest) || journal.sourceDigest !== journal.promotedDigest || bootstrapDigest === journal.sourceDigest) throw new Error('unsafe broker credential recovery'); atomicOwned(authority, bootstrapBytes); const recovered = Buffer.from(\`${"${JSON.stringify({ version: 'noopolis.daimon.broker-credential-journal.v1', state: 'promoted', generation: journal.generation + 1, sourceDigest: journal.sourceDigest, promotedDigest: bootstrapDigest })}"}\\n\`); try { atomicOwned(journalPath, recovered); } finally { recovered.fill(0); } }; if (!existing) { if (journal) throw new Error('broker credential authority missing; refusing bootstrap rollback'); else atomicOwned(authority, bootstrapBytes); } else { const authorityBytes = readSecure(authority, 2100, 'authority'); try { const authorityDigest = crypto.createHash('sha256').update(authorityBytes).digest('hex'); if (stale) { if (authorityDigest !== journal.sourceDigest && authorityDigest !== bootstrapDigest) throw new Error('unsafe broker credential recovery'); if (authorityDigest === bootstrapDigest && bootstrapDigest === journal.sourceDigest) throw new Error('unsafe broker credential recovery'); if (authorityDigest !== bootstrapDigest && credentialExpiry(bootstrapBytes) <= credentialExpiry(authorityBytes)) throw new Error('older broker bootstrap cannot recover newer realm'); if (authorityDigest === bootstrapDigest) { const recovered = Buffer.from(\`${"${JSON.stringify({ version: 'noopolis.daimon.broker-credential-journal.v1', state: 'promoted', generation: journal.generation + 1, sourceDigest: journal.sourceDigest, promotedDigest: bootstrapDigest })}"}\\n\`); try { atomicOwned(journalPath, recovered); } finally { recovered.fill(0); } } else recover(); } } finally { authorityBytes.fill(0); } } } finally { bootstrapBytes.fill(0); if (journalRootExists) { fs.chownSync(journalRoot, 0, 0); fs.chmodSync(journalRoot, 0o700); fs.chownSync(journalRoot, 2100, 2100); } fs.chownSync('${DAIMON_BROKER_REALM}', 0, 0); fs.chmodSync('${DAIMON_BROKER_REALM}', 0o700); fs.chownSync('${DAIMON_BROKER_REALM}', 2100, 2100); }`,
|
|
174
176
|
...renderDaimonWorkspaceResourceSecurity(workspaceResources),
|
|
175
177
|
...renderDaimonGrokWorkerProvisioning(registrations, serviceOptions, ...(optionalDenyPaths ? [optionalDenyPaths] : [])),
|
|
176
178
|
`fs.chownSync('${DAIMON_BROKER_REALM}', 0, 0); fs.chmodSync('${DAIMON_BROKER_REALM}', 0o700); fs.chownSync('${DAIMON_BROKER_REALM}', 2100, 2100);`,
|
|
@@ -184,6 +186,7 @@ brokerTmpdir = DAIMON_BROKER_TMPDIR) => {
|
|
|
184
186
|
: [...MOUNT_AWARE_CLEAR_HELPER, "for broker_root in /etc/daimon-engine-broker /run/daimon-engine-broker; do spawnfile_clear_tree \"$broker_root\"; done"]),
|
|
185
187
|
`install -d -o root -g ${DAIMON_BROKER_UID} -m 0731 /run/daimon-engine-broker`,
|
|
186
188
|
`install -d -o ${DAIMON_BROKER_UID} -g ${DAIMON_BROKER_UID} -m 0700 ${brokerTmpdir}`,
|
|
189
|
+
...beforeWorkerProvisioning,
|
|
187
190
|
"node <<'SPAWNFILE_DAIMON_BROKER_PROVISION'",
|
|
188
191
|
program,
|
|
189
192
|
"SPAWNFILE_DAIMON_BROKER_PROVISION"
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DaimonGrokRegistration } from "./containerDaimonGrokWorkerRender.js";
|
|
2
|
+
/** Exit without closing/unlinking the listener: the next process needs a socket inode, not a live peer. */
|
|
3
|
+
export declare const GROK_SOCKET_PLACEHOLDER_PROGRAM: string;
|
|
4
|
+
/** Lines inside the shared root program, after its canonical-path and ownership helpers. */
|
|
5
|
+
export declare const renderDaimonGrokTaskClockProvisioning: (registrations: readonly DaimonGrokRegistration[]) => string[];
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { DAIMON_GROK_ENGINE_BROKER } from "../runtime/daimon/contractManifest.js";
|
|
2
|
+
const broker = DAIMON_GROK_ENGINE_BROKER;
|
|
3
|
+
const clock = broker.worker.taskClock;
|
|
4
|
+
/** Exit without closing/unlinking the listener: the next process needs a socket inode, not a live peer. */
|
|
5
|
+
export const GROK_SOCKET_PLACEHOLDER_PROGRAM = [
|
|
6
|
+
"const fs = require('node:fs'), net = require('node:net');",
|
|
7
|
+
"const [file, uid, gid] = process.argv.slice(1);",
|
|
8
|
+
"const server = net.createServer(); server.on('error', (error) => { console.error(error.message); process.exit(1); });",
|
|
9
|
+
"server.listen(file, () => { fs.chmodSync(file, 0o600); fs.chownSync(file, Number(uid), Number(gid)); process.exit(0); });"
|
|
10
|
+
].join("\n");
|
|
11
|
+
/** Lines inside the shared root program, after its canonical-path and ownership helpers. */
|
|
12
|
+
export const renderDaimonGrokTaskClockProvisioning = (registrations) => {
|
|
13
|
+
if (!registrations.some((entry) => entry.configVariant === "clocked"))
|
|
14
|
+
return [];
|
|
15
|
+
return [
|
|
16
|
+
`const taskClock = ${JSON.stringify(clock)};`,
|
|
17
|
+
`const clocks = ${JSON.stringify(registrations.filter(entry => entry.configVariant === "clocked").map(entry => ({ directoryPath: clock.slotDirectoryPattern.replace("{slot}", String(entry.slot)), timestampFilePath: clock.slotFilePattern.replace("{slot}", String(entry.slot)) })))};`,
|
|
18
|
+
// All ancestors must stay searchable and non-writable by the worker, including the control root.
|
|
19
|
+
"for (const entry of grokWorkers) { for (let at = require('node:path').dirname(taskClock.rootDirectoryPath);; at = require('node:path').dirname(at)) { const info = assertCanonical(at, 'task clock ancestor'); const access = info.uid === entry.uid ? (info.mode >> 6) & 7 : info.gid === entry.uid ? (info.mode >> 3) & 7 : info.mode & 7; if (!info.isDirectory() || !(access & 1) || (access & 2)) throw new Error(`unsafe task clock ancestor: ${at}`); if (at === '/') break; } }",
|
|
20
|
+
"ensureDirectory(taskClock.rootDirectoryPath, 0, 0, taskClock.directoryMode); assertCanonical(taskClock.rootDirectoryPath, 'task clock root');",
|
|
21
|
+
"for (const current of clocks) { ensureDirectory(current.directoryPath, 0, 0, taskClock.directoryMode); assertCanonical(current.directoryPath, 'task clock');",
|
|
22
|
+
"ensureExactFile(current.timestampFilePath, '+0\\n', taskClock.fileMode); fs.chownSync(current.timestampFilePath, taskClock.ownerUid, taskClock.ownerUid);",
|
|
23
|
+
"withMode(current.directoryPath, taskClock.directoryMode, taskClock.ownerUid, taskClock.ownerUid); }",
|
|
24
|
+
// Startup attestation runs BEFORE the backend listens. All deny targets must already exist,
|
|
25
|
+
// and the backend only replaces a socket owned by its uid. Listeners unlink these real socket
|
|
26
|
+
// nodes in turn; readiness must prove replacement, never certify a placeholder as a listener.
|
|
27
|
+
`for (const socket of ${JSON.stringify([broker.controlSocketPath, broker.backendSocketPath, broker.launcherSocketPath])}) { require('node:child_process').execFileSync(process.execPath, ['-e', ${JSON.stringify(GROK_SOCKET_PLACEHOLDER_PROGRAM)}, socket, '${clock.ownerUid}', '${clock.ownerUid}'], { timeout: 5000, stdio: 'pipe' }); const info = fs.lstatSync(socket); if (!info.isSocket() || info.uid !== ${clock.ownerUid} || info.gid !== ${clock.ownerUid} || (info.mode & 0o7777) !== 0o600) throw new Error('unsafe broker socket placeholder'); }`
|
|
28
|
+
];
|
|
29
|
+
};
|
|
@@ -26,7 +26,7 @@ export declare const renderDaimonGrokWorkerProvisioning: (registrations: readonl
|
|
|
26
26
|
* are tmpfs mounts and `/run/secrets` and the shared state roots do not
|
|
27
27
|
* exist there at all.
|
|
28
28
|
*/
|
|
29
|
-
optionalDenyPaths?: readonly string[]) => string[];
|
|
29
|
+
optionalDenyPaths?: readonly string[], scope?: "container" | "slot") => string[];
|
|
30
30
|
/**
|
|
31
31
|
* Grok 1.0.34 runs every sandbox profile inside bubblewrap, which needs
|
|
32
32
|
* unprivileged user namespaces. Ubuntu 24.04+ hosts (and Colima's default VM)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { renderDaimonGrokTaskClockProvisioning } from "./containerDaimonGrokTaskClock.js";
|
|
1
2
|
import { DAIMON_GROK_ENGINE_BROKER } from "../runtime/daimon/contractManifest.js";
|
|
3
|
+
import { resolveDaimonGrokClockedWorkerConfig, resolveDaimonGrokWorkerConfig } from "../runtime/daimon/grokWorkerContract.js";
|
|
2
4
|
import { DAIMON_BROKER_UID, DAIMON_ORGANIZATION_UID } from "../runtime/daimon/runtimeIdentity.js";
|
|
3
5
|
import { DAIMON_GROK_DENIED_STATE_ROOTS, DAIMON_GROK_OPTIONAL_DENY_PATHS, DAIMON_GROK_WORKER_READ_ONLY_FILES, DAIMON_WORKER_ROOT, renderDaimonGrokServiceConfig } from "./containerDaimonGrokWorkerRender.js";
|
|
4
6
|
/** Only the bytes the program writes; everything else it needs is recomputed or checked in place. */
|
|
@@ -51,47 +53,67 @@ export const renderDaimonGrokWorkerProvisioning = (registrations, serviceOptions
|
|
|
51
53
|
* are tmpfs mounts and `/run/secrets` and the shared state roots do not
|
|
52
54
|
* exist there at all.
|
|
53
55
|
*/
|
|
54
|
-
optionalDenyPaths = [...DAIMON_GROK_OPTIONAL_DENY_PATHS, ...DAIMON_GROK_DENIED_STATE_ROOTS]) => [
|
|
56
|
+
optionalDenyPaths = [...DAIMON_GROK_OPTIONAL_DENY_PATHS, ...DAIMON_GROK_DENIED_STATE_ROOTS], scope = "container") => [
|
|
55
57
|
`const grokWorkers = ${JSON.stringify(registrations.map(programRegistration))};`,
|
|
56
58
|
`const optionalDenyPaths = new Set(${JSON.stringify([...optionalDenyPaths])});`,
|
|
57
|
-
|
|
59
|
+
// Derive each expected hash from manifest-validated bytes, never from the registration's digest.
|
|
60
|
+
// Clocked templates are pinned at slot zero, then specialized by the contract resolver.
|
|
61
|
+
`const pinnedConfigSha256 = ${JSON.stringify(registrations.map(entry => (entry.configVariant === "clocked"
|
|
62
|
+
? resolveDaimonGrokClockedWorkerConfig(entry.model, entry.reasoningEffort, entry.slot)
|
|
63
|
+
: resolveDaimonGrokWorkerConfig(entry.model, entry.reasoningEffort)).sha256))};`,
|
|
58
64
|
"const sha256Hex = (value) => crypto.createHash('sha256').update(value).digest('hex');",
|
|
59
|
-
"for (const entry of grokWorkers) { if (sha256Hex(entry.config) !== entry.configSha256 ||
|
|
65
|
+
"for (const [index, entry] of grokWorkers.entries()) { if (sha256Hex(entry.config) !== entry.configSha256 || pinnedConfigSha256[index] !== entry.configSha256 || sha256Hex(entry.profile) !== entry.profileSha256 || entry.denyPaths.length === 0) throw new Error(`Grok worker contract bytes for ${entry.agentId} do not match their pins`); }",
|
|
60
66
|
// Root holds no CAP_FOWNER: every mode change reclaims the inode, sets the mode, then restores or hands over ownership.
|
|
61
67
|
"const withMode = (target, mode, uid, gid) => { const info = fs.lstatSync(target); if (!info.isDirectory() || info.isSymbolicLink()) throw new Error(`unsafe Grok worker directory: ${target}`); fs.chownSync(target, 0, 0); fs.chmodSync(target, mode); fs.chownSync(target, uid, gid); };",
|
|
68
|
+
// Root holds no CAP_DAC_OVERRIDE either: before it may create inside a directory the ownership pass
|
|
69
|
+
// already handed to another uid, it takes the inode back. The caller sets the final owner and mode.
|
|
70
|
+
"const reclaimForRoot = (target) => { const info = fs.lstatSync(target); if (!info.isDirectory() || info.isSymbolicLink()) throw new Error(`unsafe Grok worker directory: ${target}`); fs.chownSync(target, 0, 0); fs.chmodSync(target, 0o700); };",
|
|
62
71
|
"const traversable = (target) => { for (let ancestor = require('node:path').dirname(target); ancestor.startsWith('/var/lib/spawnfile/') && ancestor.length > '/var/lib/spawnfile'.length; ancestor = require('node:path').dirname(ancestor)) { const info = fs.lstatSync(ancestor); if ((info.mode & 0o011) !== 0o011) withMode(ancestor, (info.mode & 0o7777) | 0o011, info.uid, info.gid); } };",
|
|
63
72
|
"const assertCanonical = (target, label) => { const info = fs.lstatSync(target); if (info.isSymbolicLink() || fs.realpathSync(target) !== target) throw new Error(`Grok worker ${label} is not a canonical non-symlink path: ${target}`); return info; };",
|
|
64
73
|
"const ensureDirectory = (target, uid, gid, mode) => { fs.mkdirSync(target, { recursive: true, mode: 0o700 }); const info = fs.lstatSync(target); if (!info.isDirectory() || info.isSymbolicLink()) throw new Error('unsafe worker runtime directory'); fs.chownSync(target, 0, 0); fs.chmodSync(target, mode); fs.chownSync(target, uid, gid); };",
|
|
65
74
|
"const ensureExactFile = (target, content, mode) => { let info; try { info = fs.lstatSync(target); } catch (error) { if (error.code !== 'ENOENT') throw error; fs.writeFileSync(target, content, { mode, flag: 'wx' }); info = fs.lstatSync(target); } if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1) throw new Error('unsafe worker runtime file'); if (fs.readFileSync(target, 'utf8') !== content) throw new Error(`worker runtime file identity mismatch: ${target}`); fs.chownSync(target, 0, 0); fs.chmodSync(target, mode); };",
|
|
66
75
|
`const ensureEventsFile = (target, uid) => { let info; try { info = fs.lstatSync(target); } catch (error) { if (error.code !== 'ENOENT') throw error; fs.writeFileSync(target, '', { mode: 0o640, flag: 'wx' }); info = fs.lstatSync(target); } if (!info.isFile() || info.isSymbolicLink() || info.nlink !== 1 || (info.uid !== uid && info.uid !== 0) || ![0, uid, ${DAIMON_BROKER_UID}].includes(info.gid) || ![0o600, 0o640, 0o644].includes(info.mode & 0o777)) throw new Error('unsafe worker attestation events'); fs.chownSync(target, 0, 0); fs.chmodSync(target, 0o640); fs.chownSync(target, uid, ${DAIMON_BROKER_UID}); };`,
|
|
67
|
-
|
|
76
|
+
...(scope === "slot" ? [] : renderDaimonGrokTaskClockProvisioning(registrations)),
|
|
77
|
+
...(scope === "slot" ? [] : [`fs.mkdirSync('${DAIMON_WORKER_ROOT}', { recursive: true, mode: 0o711 }); fs.chownSync('${DAIMON_WORKER_ROOT}', 0, 0); fs.chmodSync('${DAIMON_WORKER_ROOT}', 0o711); assertCanonical('${DAIMON_WORKER_ROOT}', 'worker root');`]),
|
|
68
78
|
// Pass 1: every workspace and home exists, root-held, before any deny list is checked.
|
|
69
|
-
`for (const entry of grokWorkers) { traversable(entry.workspace); secureWorkspace(entry.workspace, entry.uid); assertCanonical(entry.workspace, 'workspace'); ensureDirectory(entry.home, 0, 0, 0o700); ensureDirectory(entry.grokHome, 0, 0, 0o700); ensureDirectory(\`\${entry.grokHome}/sessions\`, 0, 0, 0o700); for (const target of [entry.home, entry.grokHome]) assertCanonical(target, 'home'); }`,
|
|
79
|
+
`for (const entry of grokWorkers) { traversable(entry.workspace); secureWorkspace(entry.workspace, entry.uid); assertCanonical(entry.workspace, 'workspace'); ${scope === "container" ? "ensureDirectory(entry.home, 0, 0, 0o700);" : ""} ensureDirectory(entry.grokHome, 0, 0, 0o700); ensureDirectory(\`\${entry.grokHome}/sessions\`, 0, 0, 0o700); for (const target of [entry.home, entry.grokHome]) assertCanonical(target, 'home'); }`,
|
|
70
80
|
"for (const denied of optionalDenyPaths) { try { fs.lstatSync(denied); } catch (error) { if (error.code !== 'ENOENT') throw error; fs.mkdirSync(denied, { mode: 0o700 }); fs.chownSync(denied, 0, 0); fs.chmodSync(denied, 0o700); } }",
|
|
71
81
|
"for (const entry of grokWorkers) for (const denied of entry.denyPaths) { try { assertCanonical(denied, 'deny path'); } catch (error) { if (error.code === 'ENOENT' && entry.deferredDenyPaths.includes(denied)) continue; if (error.code === 'ENOENT') throw new Error(`Grok worker deny path is missing: ${denied}`); throw error; } }",
|
|
72
82
|
// Pass 2: exact root-owned read-only files, the events file, then the final sticky modes.
|
|
73
|
-
`for (const entry of grokWorkers) { ensureExactFile(\`\${entry.grokHome}/config.toml\`, entry.config, 0o444); ensureExactFile(entry.profilePath, entry.profile, 0o444); for (const name of ${JSON.stringify(DAIMON_GROK_WORKER_READ_ONLY_FILES.filter((name) => name !== "config.toml" && name !== "sandbox.toml"))}) ensureExactFile(\`\${entry.grokHome}/\${name}\`, '', 0o444); ensureEventsFile(entry.eventsPath, entry.uid); ensureDirectory(\`\${entry.grokHome}/sessions\`, 0, entry.uid, 0o1771); ensureDirectory(entry.grokHome, 0, entry.uid, 0o1771); ensureDirectory(entry.privateTmp, entry.uid, entry.uid, 0o700); ensureDirectory(entry.home, entry.uid, ${DAIMON_BROKER_UID}, 0o710)
|
|
83
|
+
`for (const entry of grokWorkers) { ensureExactFile(\`\${entry.grokHome}/config.toml\`, entry.config, 0o444); ensureExactFile(entry.profilePath, entry.profile, 0o444); for (const name of ${JSON.stringify(DAIMON_GROK_WORKER_READ_ONLY_FILES.filter((name) => name !== "config.toml" && name !== "sandbox.toml"))}) ensureExactFile(\`\${entry.grokHome}/\${name}\`, '', 0o444); ensureEventsFile(entry.eventsPath, entry.uid); ensureDirectory(\`\${entry.grokHome}/sessions\`, 0, entry.uid, 0o1771); ensureDirectory(entry.grokHome, 0, entry.uid, 0o1771); ${scope === "container" ? `ensureDirectory(entry.privateTmp, entry.uid, entry.uid, 0o700); ensureDirectory(entry.home, entry.uid, ${DAIMON_BROKER_UID}, 0o710);` : ""} for (const target of [entry.profilePath, entry.eventsPath, \`\${entry.grokHome}/config.toml\`]) assertCanonical(target, 'home file'); }`,
|
|
74
84
|
// Worker-private temp: the launcher compiles TMPDIR=<home>/tmp, the only temp the worker may write. It is
|
|
75
85
|
// created in the pass above, while the home is still root-owned: root here holds no CAP_DAC_OVERRIDE, so
|
|
76
86
|
// once the home is `<worker>:<broker> 0710` root can no longer create anything inside it.
|
|
77
|
-
|
|
87
|
+
`for (const entry of grokWorkers) { ${scope === "container" ? "ensureDirectory(entry.privateTmp, entry.uid, entry.uid, 0o700);" : ""} assertCanonical(entry.privateTmp, 'private temp'); }`,
|
|
78
88
|
// Spills: <runtimeHome>/tool-output 2000:<worker> 2750 (setgid) under a runtime home the worker's group can
|
|
79
|
-
// traverse.
|
|
80
|
-
//
|
|
81
|
-
|
|
89
|
+
// traverse. Root reclaims the runtime home before creating the spill directory: the compiler lists every
|
|
90
|
+
// organization runtime home as a private directory, so the container's ownership pass has already handed
|
|
91
|
+
// it to the organization uid by the time this runs, and root here holds no CAP_DAC_OVERRIDE — a bare
|
|
92
|
+
// `mkdir` inside a home root no longer owns fails EACCES and the container exits 1 at start. The trailing
|
|
93
|
+
// `withMode` still narrows the home to its final `2000:<worker> 0710`, so the end state is unchanged.
|
|
94
|
+
`for (const entry of grokWorkers) { traversable(entry.runtimeHome); fs.mkdirSync(entry.runtimeHome, { recursive: true, mode: 0o700 }); assertCanonical(entry.runtimeHome, 'runtime home'); reclaimForRoot(entry.runtimeHome); try { fs.mkdirSync(entry.spillDirectory, { mode: 0o700 }); } catch (error) { if (error.code !== 'EEXIST') throw error; } assertCanonical(entry.spillDirectory, 'spill directory'); withMode(entry.spillDirectory, 0o2750, ${DAIMON_ORGANIZATION_UID}, entry.uid); for (const mounted of entry.runtimeHomeMounts) { assertCanonical(mounted, 'runtime home mount'); withMode(mounted, 0o700, ${DAIMON_ORGANIZATION_UID}, ${DAIMON_ORGANIZATION_UID}); } withMode(entry.runtimeHome, 0o710, ${DAIMON_ORGANIZATION_UID}, entry.uid); }`,
|
|
82
95
|
// Shared temp: Grok refuses a profile denying /tmp or /var/tmp, so modes close them: root:<org group> 1774 lets workers list names only.
|
|
83
|
-
`for (const shared of ${JSON.stringify(DAIMON_GROK_ENGINE_BROKER.worker.home.sharedTmp.paths)}) { fs.mkdirSync(shared, { recursive: true, mode: 0o1777 }); assertCanonical(shared, 'shared temp'); withMode(shared, 0o${DAIMON_GROK_ENGINE_BROKER.worker.home.sharedTmp.mode.toString(8)}, 0, ${DAIMON_ORGANIZATION_UID}); }
|
|
84
|
-
// Deny-path placement, asserted once every mode above is final.
|
|
96
|
+
...(scope === "slot" ? [] : [`for (const shared of ${JSON.stringify(DAIMON_GROK_ENGINE_BROKER.worker.home.sharedTmp.paths)}) { fs.mkdirSync(shared, { recursive: true, mode: 0o1777 }); assertCanonical(shared, 'shared temp'); withMode(shared, 0o${DAIMON_GROK_ENGINE_BROKER.worker.home.sharedTmp.mode.toString(8)}, 0, ${DAIMON_ORGANIZATION_UID}); }`]),
|
|
97
|
+
// Deny-path placement, asserted once every mode above is final. A resource backing the organization
|
|
98
|
+
// entrypoint only materializes later is created here, empty and root-owned, rather than skipped: the
|
|
99
|
+
// engine broker starts before that entrypoint runs and its own placement preflight refuses a deny target
|
|
100
|
+
// that does not exist, which exits the container 1 before any agent attaches. `prepare_bundle_resource`
|
|
101
|
+
// and `prepare_git_resource` both treat an empty backing as unmaterialized, so the content still lands.
|
|
102
|
+
// Grok 1.0.34 materializes each deny
|
|
85
103
|
// target inside bubblewrap AS THE WORKER UID, so the worker must be able to search every ancestor and
|
|
86
104
|
// the target must already exist; one unplaceable entry makes Grok refuse the whole profile and every
|
|
87
105
|
// turn of that worker fails with a bare `bwrap: Can't create file at ...: Permission denied`. Root here
|
|
88
106
|
// holds CAP_DAC_READ_SEARCH, so it can read every mode the worker cannot, and decides for it.
|
|
107
|
+
// A deferred backing usually sits under a resource instance directory the ownership pass has already
|
|
108
|
+
// handed to the organization uid, so root has to borrow each missing ancestor to create inside it and
|
|
109
|
+
// hand it straight back: the entrypoint that materializes the resource depends on those modes.
|
|
110
|
+
`const createDeferredDenyTarget = (target) => { const parent = require('node:path').dirname(target); let info; try { info = fs.lstatSync(parent); } catch (error) { if (error.code !== 'ENOENT') throw error; createDeferredDenyTarget(parent); info = fs.lstatSync(parent); } if (!info.isDirectory() || info.isSymbolicLink()) throw new Error(\`unsafe deferred deny parent: \${parent}\`); const mode = info.mode & 0o7777, borrowed = info.uid !== 0 || (mode & 0o300) !== 0o300; if (borrowed) { fs.chownSync(parent, 0, 0); fs.chmodSync(parent, 0o700); } try { fs.mkdirSync(target, { mode: 0o755 }); fs.chmodSync(target, 0o755); fs.chownSync(target, ${DAIMON_ORGANIZATION_UID}, ${DAIMON_ORGANIZATION_UID}); } finally { if (borrowed) { fs.chmodSync(parent, mode); fs.chownSync(parent, info.uid, info.gid); } } };`,
|
|
89
111
|
"const searches = (info, uid, gid) => info.uid === uid ? (info.mode & 0o100) !== 0 : info.gid === gid ? (info.mode & 0o010) !== 0 : (info.mode & 0o001) !== 0;",
|
|
90
112
|
"const assertPlaceable = (denied, uid, gid) => { const parts = denied.split('/').slice(1); let at = ''; for (const part of parts.slice(0, -1)) { at += `/${part}`; let info; try { info = fs.lstatSync(at); } catch (error) { throw new Error(`Grok worker deny path ${denied} is not placeable: ${at} could not be read (${error.code})`); } if (!info.isDirectory() || info.isSymbolicLink()) throw new Error(`Grok worker deny path ${denied} is not placeable: ${at} is not a directory`); if (!searches(info, uid, gid)) throw new Error(`Grok worker deny path ${denied} is not placeable: worker uid ${uid} cannot search ${at} (${(info.mode & 0o7777).toString(8)} ${info.uid}:${info.gid}); deny that directory itself instead`); } };",
|
|
91
|
-
"for (const entry of grokWorkers) for (const denied of entry.denyPaths) { if (entry.deferredDenyPaths.includes(denied)) { try { fs.lstatSync(denied); } catch (error) { if (error.code
|
|
92
|
-
`const service = ${JSON.stringify(renderDaimonGrokServiceConfig(registrations, serviceOptions))};`,
|
|
93
|
-
|
|
94
|
-
|
|
113
|
+
"for (const entry of grokWorkers) for (const denied of entry.denyPaths) { if (entry.deferredDenyPaths.includes(denied)) { try { fs.lstatSync(denied); } catch (error) { if (error.code !== 'ENOENT') throw error; createDeferredDenyTarget(denied); } } assertPlaceable(denied, entry.uid, entry.uid); }",
|
|
114
|
+
...(scope === "slot" ? [] : [`const service = ${JSON.stringify(renderDaimonGrokServiceConfig(registrations, serviceOptions))};`,
|
|
115
|
+
"for (const registration of service.registrations) { const entry = grokWorkers.find((worker) => worker.slot === registration.slot); if (!entry || registration.profileSha256 !== sha256Hex(fs.readFileSync(entry.profilePath, 'utf8'))) throw new Error('Grok broker service registration does not match its provisioned profile'); }",
|
|
116
|
+
`fs.writeFileSync('${DAIMON_GROK_ENGINE_BROKER.serviceConfigPath}', \`\${JSON.stringify(service)}\\n\`, { mode: 0o440, flag: 'wx' }); fs.chownSync('${DAIMON_GROK_ENGINE_BROKER.serviceConfigPath}', 0, ${DAIMON_BROKER_UID}); fs.chmodSync('${DAIMON_GROK_ENGINE_BROKER.serviceConfigPath}', 0o440);`])
|
|
95
117
|
];
|
|
96
118
|
const shellQuote = (value) => `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
97
119
|
/**
|
|
@@ -48,6 +48,8 @@ export interface DaimonGrokRegistration {
|
|
|
48
48
|
agentId: string;
|
|
49
49
|
config: string;
|
|
50
50
|
configSha256: string;
|
|
51
|
+
/** Selects trusted config bytes; production retains the unclocked default. */
|
|
52
|
+
configVariant?: "unclocked" | "clocked";
|
|
51
53
|
denyPaths: string[];
|
|
52
54
|
/** Deny entries the main entrypoint materializes after root provisioning (workspace resource backings); absent is allowed there, a symlink never. */
|
|
53
55
|
deferredDenyPaths: string[];
|
|
@@ -130,6 +132,10 @@ export declare const DAIMON_GROK_DENIED_STATE_ROOTS: readonly ["/var/lib/spawnfi
|
|
|
130
132
|
export declare const resolveDaimonGrokWorkerDenyPaths: (plans: readonly RuntimeTargetPlan[], plan: RuntimeTargetPlan, agentId: string, workerHomes: readonly string[], ownHome: string) => string[];
|
|
131
133
|
export declare const resolveDaimonGrokRegistrations: (plans: RuntimeTargetPlan[]) => DaimonGrokRegistration[];
|
|
132
134
|
export interface DaimonGrokServiceConfigOptions {
|
|
135
|
+
/** Repeated agent IDs use v3 slot policies; production retains v2 by default. */
|
|
136
|
+
version?: "v3";
|
|
137
|
+
maxRunRequests?: number;
|
|
138
|
+
runRequestStore?: string;
|
|
133
139
|
/**
|
|
134
140
|
* Where the broker keeps its durable turn registry. Production keeps it on
|
|
135
141
|
* the realm volume beside the credential; training overrides it to per-slot
|
|
@@ -142,14 +148,8 @@ export interface DaimonGrokServiceConfigOptions {
|
|
|
142
148
|
}
|
|
143
149
|
/** `service.json` v2, exactly the shape Daimon's strict `parseEngineBrokerServiceConfig` accepts. */
|
|
144
150
|
export declare const renderDaimonGrokServiceConfig: (registrations: readonly DaimonGrokRegistration[], options?: DaimonGrokServiceConfigOptions) => {
|
|
145
|
-
|
|
146
|
-
agentId: string;
|
|
151
|
+
slotPolicies?: {
|
|
147
152
|
slot: number;
|
|
148
|
-
workerUid: number;
|
|
149
|
-
workspace: string;
|
|
150
|
-
profilePath: string;
|
|
151
|
-
eventsPath: string;
|
|
152
|
-
profileSha256: string;
|
|
153
153
|
usageLedgerPath: string;
|
|
154
154
|
limits: {
|
|
155
155
|
maxRequests: 32;
|
|
@@ -164,9 +164,34 @@ export declare const renderDaimonGrokServiceConfig: (registrations: readonly Dai
|
|
|
164
164
|
id: "grok-4.6" | "grok-4.5" | "grok-build";
|
|
165
165
|
reasoningEffort: "high" | "medium" | "low";
|
|
166
166
|
};
|
|
167
|
+
}[] | undefined;
|
|
168
|
+
registrations: {
|
|
169
|
+
usageLedgerPath?: string | undefined;
|
|
170
|
+
limits?: {
|
|
171
|
+
maxRequests: 32;
|
|
172
|
+
maxTokens: 300000;
|
|
173
|
+
timeoutMs: 240000;
|
|
174
|
+
} | {
|
|
175
|
+
maxRequests: number;
|
|
176
|
+
maxTokens: number;
|
|
177
|
+
timeoutMs: number;
|
|
178
|
+
} | undefined;
|
|
179
|
+
model?: {
|
|
180
|
+
id: "grok-4.6" | "grok-4.5" | "grok-build";
|
|
181
|
+
reasoningEffort: "high" | "medium" | "low";
|
|
182
|
+
} | undefined;
|
|
183
|
+
agentId: string;
|
|
184
|
+
slot: number;
|
|
185
|
+
workerUid: number;
|
|
186
|
+
workspace: string;
|
|
187
|
+
profilePath: string;
|
|
188
|
+
eventsPath: string;
|
|
189
|
+
profileSha256: string;
|
|
167
190
|
}[];
|
|
168
191
|
inferenceLedgerPath?: string | undefined;
|
|
169
|
-
|
|
192
|
+
runRequestStore?: string | undefined;
|
|
193
|
+
maxRunRequests?: number | undefined;
|
|
194
|
+
version: "noopolis.daimon.engine-broker-service.v2" | "noopolis.daimon.engine-broker-service.v3";
|
|
170
195
|
credentialHome: "/var/lib/spawnfile/daimon/grok-subscription-realm";
|
|
171
196
|
turnStore: string;
|
|
172
197
|
};
|