spawnfile 0.1.14 → 0.1.17
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 +60 -159
- package/dist/audit/checksShared.d.ts +1 -1
- package/dist/auth/importers.d.ts +10 -0
- package/dist/auth/importers.js +29 -4
- package/dist/auth/index.d.ts +2 -0
- package/dist/auth/index.js +1 -0
- package/dist/auth/paths.d.ts +1 -1
- package/dist/auth/profileStore.js +9 -9
- package/dist/auth/targetSecretSourceFsIdentity.d.ts +40 -0
- package/dist/auth/targetSecretSourceFsIdentity.js +42 -0
- package/dist/auth/targetSecretSourceFsPublish.d.ts +2 -0
- package/dist/auth/targetSecretSourceFsPublish.js +3 -1
- package/dist/auth/targetSecretSourceFsPublishImmutable.d.ts +2 -1
- package/dist/auth/targetSecretSourceFsPublishImmutable.js +104 -71
- package/dist/auth/targetSecretSourceFsRead.js +5 -14
- package/dist/auth/trainingAuth.d.ts +21 -0
- package/dist/auth/trainingAuth.js +86 -0
- package/dist/auth/types.d.ts +1 -1
- package/dist/cli/authCommands.d.ts +1 -1
- package/dist/cli/authCommands.js +9 -0
- package/dist/cli/canaryCutoverCommand.d.ts +2 -0
- package/dist/cli/canaryCutoverCommand.js +30 -0
- package/dist/cli/capabilitiesCommand.d.ts +3 -0
- package/dist/cli/capabilitiesCommand.js +12 -0
- package/dist/cli/capabilitiesReceipt.d.ts +56 -0
- package/dist/cli/capabilitiesReceipt.js +56 -0
- package/dist/cli/compileBuildCommands.js +13 -0
- package/dist/cli/composedLifecycleContractSet.d.ts +21 -0
- package/dist/cli/composedLifecycleContractSet.js +204 -0
- package/dist/cli/devCommands.js +2 -0
- package/dist/cli/downCommand.js +19 -8
- package/dist/cli/evidenceExportHelperCommand.d.ts +13 -0
- package/dist/cli/evidenceExportHelperCommand.js +51 -0
- package/dist/cli/index.js +12 -3
- package/dist/cli/lifecycleMachine.d.ts +7 -1
- package/dist/cli/lifecycleMachine.js +2 -2
- package/dist/cli/paideiaDelegation.d.ts +17 -0
- package/dist/cli/paideiaDelegation.js +210 -0
- package/dist/cli/paideiaSupervisor.d.ts +17 -0
- package/dist/cli/paideiaSupervisor.js +48 -0
- package/dist/cli/productStateCloneCommand.d.ts +2 -0
- package/dist/cli/productStateCloneCommand.js +34 -0
- package/dist/cli/runCli.d.ts +13 -3
- package/dist/cli/runCli.js +37 -9
- package/dist/cli/targetCommands.d.ts +4 -7
- package/dist/cli/targetCommands.js +16 -46
- package/dist/cli/targetConfigPreparedPlan.d.ts +3 -0
- package/dist/cli/targetConfigPreparedPlan.js +74 -0
- package/dist/cli/targetConfigResolver.d.ts +3 -0
- package/dist/cli/targetConfigResolver.js +111 -0
- package/dist/cli/targetConfigResolverCommand.d.ts +6 -0
- package/dist/cli/targetConfigResolverCommand.js +43 -0
- package/dist/cli/targetConfigResolverContracts.d.ts +56 -0
- package/dist/cli/targetConfigResolverContracts.js +30 -0
- package/dist/cli/targetConfigResolverDocker.d.ts +4 -0
- package/dist/cli/targetConfigResolverDocker.js +47 -0
- package/dist/cli/targetConfigResolverValidation.d.ts +10 -0
- package/dist/cli/targetConfigResolverValidation.js +94 -0
- package/dist/cli/targetDefaultAuthorities.d.ts +2 -0
- package/dist/cli/targetDefaultAuthorities.js +3 -0
- package/dist/cli/targetDefaultConfig.d.ts +7 -0
- package/dist/cli/targetDefaultConfig.js +22 -5
- package/dist/cli/targetDefaultConfigStdin.js +7 -1
- package/dist/cli/targetDefaultHandlerFactory.js +23 -2
- package/dist/cli/targetDefaultHandlers.d.ts +2 -2
- package/dist/cli/targetProductionCommands.d.ts +5 -0
- package/dist/cli/targetProductionCommands.js +45 -0
- package/dist/cli/trainCommand.d.ts +3 -0
- package/dist/cli/trainCommand.js +61 -0
- package/dist/cli/upCommand.js +35 -6
- package/dist/cli/upLifecycleRecovery.d.ts +2 -2
- package/dist/cli/upLifecycleRecovery.js +188 -44
- package/dist/cli/usageCommand.d.ts +40 -0
- package/dist/cli/usageCommand.js +284 -0
- package/dist/cli/usageCommandLive.d.ts +84 -0
- package/dist/cli/usageCommandLive.js +95 -0
- package/dist/cli/usageDeploymentSource.d.ts +9 -0
- package/dist/cli/usageDeploymentSource.js +22 -0
- package/dist/cli/workspaceResourceMigrationCommand.d.ts +8 -0
- package/dist/cli/workspaceResourceMigrationCommand.js +36 -0
- package/dist/compiler/buildCompilePlanTeams.d.ts +1 -1
- package/dist/compiler/buildCompilePlanTeams.js +6 -1
- package/dist/compiler/compilePlanHelpers.js +3 -0
- package/dist/compiler/compileProject.d.ts +2 -0
- package/dist/compiler/compileProject.js +5 -1
- package/dist/compiler/compileProjectSupport.js +9 -0
- package/dist/compiler/containerArtifacts.d.ts +3 -1
- package/dist/compiler/containerArtifacts.js +92 -40
- package/dist/compiler/containerArtifactsPlans.d.ts +1 -1
- package/dist/compiler/containerArtifactsPlans.js +24 -7
- package/dist/compiler/containerArtifactsRender.d.ts +2 -1
- package/dist/compiler/containerArtifactsRender.js +91 -58
- package/dist/compiler/containerArtifactsTypes.d.ts +8 -0
- package/dist/compiler/containerBackedMountRender.d.ts +56 -0
- package/dist/compiler/containerBackedMountRender.js +101 -0
- package/dist/compiler/containerDaimonBrokerRender.d.ts +112 -0
- package/dist/compiler/containerDaimonBrokerRender.js +191 -0
- package/dist/compiler/containerDaimonGrokWorkerProvisioning.d.ts +38 -0
- package/dist/compiler/containerDaimonGrokWorkerProvisioning.js +108 -0
- package/dist/compiler/containerDaimonGrokWorkerRender.d.ts +172 -0
- package/dist/compiler/containerDaimonGrokWorkerRender.js +268 -0
- package/dist/compiler/containerDaimonOwnershipGuardRender.d.ts +12 -0
- package/dist/compiler/containerDaimonOwnershipGuardRender.js +191 -0
- package/dist/compiler/containerDaimonUidEntrypointRender.d.ts +24 -0
- package/dist/compiler/containerDaimonUidEntrypointRender.js +297 -0
- package/dist/compiler/containerEntrypointRender.d.ts +7 -0
- package/dist/compiler/containerEntrypointRender.js +28 -22
- package/dist/compiler/containerPersistentMounts.d.ts +30 -0
- package/dist/compiler/containerPersistentMounts.js +66 -0
- package/dist/compiler/containerReadinessPaths.d.ts +1 -0
- package/dist/compiler/containerReadinessPaths.js +1 -0
- package/dist/compiler/containerRuntimeLinkMaterializer.d.ts +2 -0
- package/dist/compiler/containerRuntimeLinkMaterializer.js +12 -0
- package/dist/compiler/containerRuntimeReadinessRender.d.ts +7 -0
- package/dist/compiler/containerRuntimeReadinessRender.js +40 -0
- package/dist/compiler/containerStateOwnershipRender.d.ts +4 -0
- package/dist/compiler/containerStateOwnershipRender.js +75 -0
- package/dist/compiler/containerTargetResources.d.ts +22 -1
- package/dist/compiler/containerTargetResources.js +94 -2
- package/dist/compiler/containerVolumeBootstrap.d.ts +3 -0
- package/dist/compiler/containerVolumeBootstrap.js +3 -0
- package/dist/compiler/containerWorkspaceResourceRender.js +49 -1
- package/dist/compiler/daimonTelemetryArtifacts.d.ts +2 -2
- package/dist/compiler/daimonTelemetryArtifacts.js +5 -10
- package/dist/compiler/deploymentLineage.d.ts +40 -0
- package/dist/compiler/deploymentLineage.js +50 -0
- package/dist/compiler/index.d.ts +3 -0
- package/dist/compiler/index.js +3 -0
- package/dist/compiler/initProject.d.ts +2 -0
- package/dist/compiler/initProject.js +39 -1
- package/dist/compiler/localMoltnetAuthority.d.ts +64 -0
- package/dist/compiler/localMoltnetAuthority.js +177 -0
- package/dist/compiler/memoryArtifacts.d.ts +1 -1
- package/dist/compiler/memoryArtifacts.js +108 -32
- package/dist/compiler/modelEnv.d.ts +5 -0
- package/dist/compiler/modelEnv.js +8 -2
- package/dist/compiler/moltnetArtifactPaths.d.ts +17 -12
- package/dist/compiler/moltnetArtifactPaths.js +17 -15
- package/dist/compiler/moltnetArtifactTypes.d.ts +10 -0
- package/dist/compiler/moltnetArtifacts.d.ts +1 -1
- package/dist/compiler/moltnetArtifacts.js +52 -12
- package/dist/compiler/moltnetBinaries.d.ts +16 -4
- package/dist/compiler/moltnetBinaries.js +46 -6
- package/dist/compiler/moltnetClientConfig.js +1 -1
- package/dist/compiler/moltnetConfigLowering.d.ts +3 -1
- package/dist/compiler/moltnetConfigLowering.js +30 -6
- package/dist/compiler/moltnetNodeConfig.js +1 -1
- package/dist/compiler/moltnetReleaseAuthority.d.ts +24 -1
- package/dist/compiler/moltnetReleaseAuthority.js +33 -4
- package/dist/compiler/moltnetRepresentativeResolution.d.ts +1 -1
- package/dist/compiler/moltnetRepresentativeResolution.js +2 -2
- package/dist/compiler/moltnetResolution.js +9 -15
- package/dist/compiler/moltnetRoomMemberships.js +20 -5
- package/dist/compiler/moltnetRoomPolicyCompatibility.d.ts +1 -1
- package/dist/compiler/moltnetRoomPolicyCompatibility.js +3 -1
- package/dist/compiler/moltnetRuntimeConfig.d.ts +1 -1
- package/dist/compiler/moltnetRuntimeConfig.js +22 -2
- package/dist/compiler/moltnetServerPlans.js +19 -0
- package/dist/compiler/organizationExternalParticipants.d.ts +3 -0
- package/dist/compiler/organizationExternalParticipants.js +176 -0
- package/dist/compiler/organizationIdentity.d.ts +3 -9
- package/dist/compiler/organizationIdentity.js +37 -270
- package/dist/compiler/organizationIdentityGraph.d.ts +15 -0
- package/dist/compiler/organizationIdentityGraph.js +115 -0
- package/dist/compiler/organizationReadyEvidence.d.ts +8 -0
- package/dist/compiler/organizationReadyEvidence.js +23 -3
- package/dist/compiler/runProject.d.ts +4 -2
- package/dist/compiler/runProject.js +32 -6
- package/dist/compiler/runProjectAuth.d.ts +3 -1
- package/dist/compiler/runProjectAuth.js +19 -3
- package/dist/compiler/runProjectDaimonCodexDocker.d.ts +3 -0
- package/dist/compiler/runProjectDaimonCodexDocker.js +36 -0
- package/dist/compiler/runProjectDocker.d.ts +8 -4
- package/dist/compiler/runProjectDocker.js +43 -18
- package/dist/compiler/runProjectDockerDaimonGuards.d.ts +15 -0
- package/dist/compiler/runProjectDockerDaimonGuards.js +122 -0
- package/dist/compiler/runProjectDockerReservation.d.ts +3 -0
- package/dist/compiler/runProjectDockerReservation.js +118 -0
- package/dist/compiler/runProjectLifecycle.js +1 -1
- package/dist/compiler/training/broker/declaration.d.ts +45 -0
- package/dist/compiler/training/broker/declaration.js +55 -0
- package/dist/compiler/training/broker/entrypoint.d.ts +39 -0
- package/dist/compiler/training/broker/entrypoint.js +111 -0
- package/dist/compiler/training/broker/index.d.ts +10 -0
- package/dist/compiler/training/broker/index.js +10 -0
- package/dist/compiler/training/broker/main.d.ts +2 -0
- package/dist/compiler/training/broker/main.js +14 -0
- package/dist/compiler/training/broker/paths.d.ts +196 -0
- package/dist/compiler/training/broker/paths.js +241 -0
- package/dist/compiler/training/broker/processes.d.ts +42 -0
- package/dist/compiler/training/broker/processes.js +99 -0
- package/dist/compiler/training/broker/projection.d.ts +51 -0
- package/dist/compiler/training/broker/projection.js +76 -0
- package/dist/compiler/training/broker/provisioning.d.ts +87 -0
- package/dist/compiler/training/broker/provisioning.js +213 -0
- package/dist/compiler/training/broker/receipt.d.ts +77 -0
- package/dist/compiler/training/broker/receipt.js +110 -0
- package/dist/compiler/training/broker/registration.d.ts +41 -0
- package/dist/compiler/training/broker/registration.js +102 -0
- package/dist/compiler/training/broker/runtime.d.ts +25 -0
- package/dist/compiler/training/broker/runtime.js +173 -0
- package/dist/compiler/training/broker/seccompRoutes.d.ts +31 -0
- package/dist/compiler/training/broker/seccompRoutes.js +36 -0
- package/dist/compiler/training/broker/supervisor.d.ts +109 -0
- package/dist/compiler/training/broker/supervisor.js +173 -0
- package/dist/compiler/training/container/contract.d.ts +31 -0
- package/dist/compiler/training/container/contract.js +33 -0
- package/dist/compiler/training/container/index.d.ts +4 -0
- package/dist/compiler/training/container/index.js +2 -0
- package/dist/compiler/training/container/launch.d.ts +18 -0
- package/dist/compiler/training/container/launch.js +173 -0
- package/dist/compiler/training/container/prepare.d.ts +8 -0
- package/dist/compiler/training/container/prepare.js +80 -0
- package/dist/compiler/training/container/process.d.ts +14 -0
- package/dist/compiler/training/container/process.js +70 -0
- package/dist/compiler/training/container/security.d.ts +36 -0
- package/dist/compiler/training/container/security.js +58 -0
- package/dist/compiler/training/context.d.ts +7 -0
- package/dist/compiler/training/context.js +93 -0
- package/dist/compiler/training/contract.d.ts +142 -0
- package/dist/compiler/training/contract.js +34 -0
- package/dist/compiler/training/index.d.ts +4 -0
- package/dist/compiler/training/index.js +3 -0
- package/dist/compiler/training/preparation/assets/Dockerfile +98 -0
- package/dist/compiler/training/preparation/assets/package-lock.json +3787 -0
- package/dist/compiler/training/preparation/broker.d.ts +21 -0
- package/dist/compiler/training/preparation/broker.js +43 -0
- package/dist/compiler/training/preparation/contextModes.d.ts +12 -0
- package/dist/compiler/training/preparation/contextModes.js +38 -0
- package/dist/compiler/training/preparation/contract.d.ts +182 -0
- package/dist/compiler/training/preparation/contract.js +94 -0
- package/dist/compiler/training/preparation/copyAssets.d.ts +1 -0
- package/dist/compiler/training/preparation/copyAssets.js +8 -0
- package/dist/compiler/training/preparation/daimonParent.d.ts +42 -0
- package/dist/compiler/training/preparation/daimonParent.js +114 -0
- package/dist/compiler/training/preparation/files.d.ts +25 -0
- package/dist/compiler/training/preparation/files.js +85 -0
- package/dist/compiler/training/preparation/image.d.ts +28 -0
- package/dist/compiler/training/preparation/image.js +102 -0
- package/dist/compiler/training/preparation/index.d.ts +3 -0
- package/dist/compiler/training/preparation/index.js +2 -0
- package/dist/compiler/training/preparation/inputs.d.ts +23 -0
- package/dist/compiler/training/preparation/inputs.js +93 -0
- package/dist/compiler/training/preparation/prepare.d.ts +33 -0
- package/dist/compiler/training/preparation/prepare.js +186 -0
- package/dist/compiler/training/preparation/scratch.d.ts +19 -0
- package/dist/compiler/training/preparation/scratch.js +48 -0
- package/dist/compiler/training/repair/compatibility.d.ts +11 -0
- package/dist/compiler/training/repair/compatibility.js +34 -0
- package/dist/compiler/training/repair/contract.d.ts +506 -0
- package/dist/compiler/training/repair/contract.js +31 -0
- package/dist/compiler/training/repair/index.d.ts +3 -0
- package/dist/compiler/training/repair/index.js +3 -0
- package/dist/compiler/training/repair/prepare.d.ts +230 -0
- package/dist/compiler/training/repair/prepare.js +74 -0
- package/dist/compiler/training/repair/witness.d.ts +203 -0
- package/dist/compiler/training/repair/witness.js +42 -0
- package/dist/compiler/types.d.ts +2 -0
- package/dist/compiler/upProject.d.ts +26 -1
- package/dist/compiler/upProject.js +117 -178
- package/dist/compiler/upProjectHandoff.d.ts +62 -0
- package/dist/compiler/upProjectHandoff.js +204 -0
- package/dist/compiler/upReceipt.js +49 -4
- package/dist/compiler/updateProjectModels.js +1 -0
- package/dist/compiler/view/types.d.ts +1 -1
- package/dist/compiler/workspaceBundleArtifacts.d.ts +3 -0
- package/dist/compiler/workspaceBundleArtifacts.js +106 -0
- package/dist/compiler/workspaceResources.d.ts +4 -1
- package/dist/compiler/workspaceResources.js +12 -7
- package/dist/deployment/artifactsExportPlan.js +51 -1
- package/dist/deployment/canaryCutover.d.ts +42 -0
- package/dist/deployment/canaryCutover.js +140 -0
- package/dist/deployment/candidateDiagnostics.d.ts +15 -0
- package/dist/deployment/candidateDiagnostics.js +90 -0
- package/dist/deployment/dockerLogs.js +4 -1
- package/dist/deployment/dockerManager.js +9 -3
- package/dist/deployment/dockerProbeGateway.d.ts +17 -0
- package/dist/deployment/dockerProbeGateway.js +17 -2
- package/dist/deployment/downDeployment.d.ts +5 -0
- package/dist/deployment/downDeployment.js +109 -8
- package/dist/deployment/downReceiptTypes.d.ts +17 -2
- package/dist/deployment/downReceiptTypes.js +17 -2
- package/dist/deployment/index.d.ts +4 -0
- package/dist/deployment/index.js +4 -0
- package/dist/deployment/lifecycleCompletionContracts.d.ts +66 -0
- package/dist/deployment/lifecycleCompletionContracts.js +34 -0
- package/dist/deployment/lifecycleCompletionPaths.d.ts +4 -1
- package/dist/deployment/lifecycleCompletionPaths.js +3 -0
- package/dist/deployment/lifecycleCompletionPublication.d.ts +2 -0
- package/dist/deployment/lifecycleCompletionPublication.js +18 -4
- package/dist/deployment/lifecycleCompletionStore.d.ts +1 -1
- package/dist/deployment/lifecycleCompletionStore.js +7 -7
- package/dist/deployment/lifecycleUpRecords.d.ts +11 -0
- package/dist/deployment/lifecycleUpRecords.js +127 -0
- package/dist/deployment/native/AGENTS.md +11 -0
- package/dist/deployment/native/rename-noreplace-arm64 +0 -0
- package/dist/deployment/native/rename-noreplace-arm64.provenance.json +1 -0
- package/dist/deployment/native/rename-noreplace-x64 +0 -0
- package/dist/deployment/native/rename-noreplace-x64.provenance.json +1 -0
- package/dist/deployment/noReplaceActivation.d.ts +17 -0
- package/dist/deployment/noReplaceActivation.js +50 -0
- package/dist/deployment/organizationHandoffAuthorityFsBudget.d.ts +110 -0
- package/dist/deployment/organizationHandoffAuthorityFsBudget.js +156 -0
- package/dist/deployment/organizationHandoffAuthorityFsClient.js +82 -27
- package/dist/deployment/organizationHandoffAuthorityFsElection.d.ts +21 -0
- package/dist/deployment/organizationHandoffAuthorityFsElection.js +57 -0
- package/dist/deployment/organizationHandoffAuthorityFsWorker.js +254 -108
- package/dist/deployment/organizationHandoffAuthorityFsWorkerStall.fixture.d.ts +1 -0
- package/dist/deployment/organizationHandoffAuthorityFsWorkerStall.fixture.js +16 -0
- package/dist/deployment/organizationHandoffAuthorityStore.js +14 -7
- package/dist/deployment/organizationHandoffAuthorityTypes.d.ts +2 -2
- package/dist/deployment/organizationHandoffAuthorityTypes.js +2 -1
- package/dist/deployment/organizationReady.d.ts +2 -0
- package/dist/deployment/organizationReady.js +36 -4
- package/dist/deployment/productStateClone.d.ts +43 -0
- package/dist/deployment/productStateClone.js +319 -0
- package/dist/deployment/upLifecycleRecoveryState.d.ts +23 -0
- package/dist/deployment/upLifecycleRecoveryState.js +12 -0
- package/dist/deployment/upReceiptTypes.d.ts +32 -6
- package/dist/deployment/upReceiptTypes.js +29 -2
- package/dist/deployment/workspaceResourceMigration.d.ts +55 -0
- package/dist/deployment/workspaceResourceMigration.js +315 -0
- package/dist/dev/project.d.ts +7 -0
- package/dist/dev/project.js +9 -0
- package/dist/distribution/consumeImage.d.ts +2 -0
- package/dist/distribution/consumeImage.js +98 -73
- package/dist/distribution/consumeImageDaimonDocker.d.ts +3 -0
- package/dist/distribution/consumeImageDaimonDocker.js +45 -0
- package/dist/distribution/consumeImageLifecycle.d.ts +17 -0
- package/dist/distribution/consumeImageLifecycle.js +231 -0
- package/dist/distribution/consumeImageSupport.d.ts +12 -0
- package/dist/distribution/consumeImageSupport.js +15 -0
- package/dist/distribution/distributionReportSchema.d.ts +11 -1
- package/dist/distribution/distributionReportSchema.js +15 -2
- package/dist/distribution/dockerRunner.d.ts +6 -1
- package/dist/distribution/dockerRunner.js +31 -4
- package/dist/distribution/imageRuntimeAuth.d.ts +9 -1
- package/dist/distribution/imageRuntimeAuth.js +70 -1
- package/dist/distribution/index.d.ts +1 -1
- package/dist/distribution/index.js +1 -1
- package/dist/distribution/preflight.js +5 -1
- package/dist/distribution/types.d.ts +14 -1
- package/dist/distribution/types.js +3 -0
- package/dist/evidenceExportHelper/boundedExecutor.d.ts +3 -0
- package/dist/evidenceExportHelper/boundedExecutor.js +33 -0
- package/dist/evidenceExportHelper/helperProgram.mjs +156 -0
- package/dist/evidenceExportHelper/index.d.ts +4 -0
- package/dist/evidenceExportHelper/index.js +4 -0
- package/dist/evidenceExportHelper/preparedAuthority.d.ts +64 -0
- package/dist/evidenceExportHelper/preparedAuthority.js +228 -0
- package/dist/evidenceExportHelper/preparedBuilder.d.ts +10 -0
- package/dist/evidenceExportHelper/preparedBuilder.js +183 -0
- package/dist/evidenceExportHelper/preparedBuilderTypes.d.ts +19 -0
- package/dist/evidenceExportHelper/preparedBuilderTypes.js +1 -0
- package/dist/evidenceExportHelper/recipe.d.ts +7 -0
- package/dist/evidenceExportHelper/recipe.js +83 -0
- package/dist/filesystem/io.d.ts +2 -0
- package/dist/filesystem/io.js +16 -1
- package/dist/manifest/executionSchemas.d.ts +27 -0
- package/dist/manifest/executionSchemas.js +21 -2
- package/dist/manifest/mcpSchemas.d.ts +1 -0
- package/dist/manifest/mcpSchemas.js +3 -0
- package/dist/manifest/renderSpawnfileNetworks.js +11 -0
- package/dist/manifest/renderSpawnfileWorkspace.js +5 -0
- package/dist/manifest/scheduleSchemas.d.ts +3 -1
- package/dist/manifest/scheduleSchemas.js +91 -5
- package/dist/manifest/schemas.d.ts +237 -12
- package/dist/manifest/schemas.js +5 -2
- package/dist/manifest/teamNetworkAccessSchemas.d.ts +5 -1
- package/dist/manifest/teamNetworkAccessSchemas.js +11 -0
- package/dist/manifest/teamNetworkAuthSchemas.d.ts +1 -1
- package/dist/manifest/teamNetworkSchemas.d.ts +17 -3
- package/dist/manifest/teamNetworkSchemas.js +19 -1
- package/dist/manifest/teamNetworkServerSchemas.d.ts +8 -3
- package/dist/manifest/teamNetworkServerSchemas.js +18 -2
- package/dist/manifest/workspaceSchemas.d.ts +16 -0
- package/dist/manifest/workspaceSchemas.js +11 -0
- package/dist/report/types.d.ts +34 -4
- package/dist/runtime/common.d.ts +28 -1
- package/dist/runtime/common.js +33 -3
- package/dist/runtime/container.js +49 -33
- package/dist/runtime/daimon/adapter.d.ts +14 -0
- package/dist/runtime/daimon/adapter.js +243 -0
- package/dist/runtime/daimon/attention.d.ts +8 -0
- package/dist/runtime/daimon/attention.js +32 -0
- package/dist/runtime/daimon/config.d.ts +25 -0
- package/dist/runtime/daimon/config.js +272 -0
- package/dist/runtime/daimon/contractManifest.d.ts +295 -0
- package/dist/runtime/daimon/contractManifest.js +319 -0
- package/dist/runtime/daimon/grokModel.d.ts +19 -0
- package/dist/runtime/daimon/grokModel.js +33 -0
- package/dist/runtime/daimon/grokWorkerConfigBytes.d.ts +26 -0
- package/dist/runtime/daimon/grokWorkerConfigBytes.js +36 -0
- package/dist/runtime/daimon/grokWorkerContract.d.ts +22 -0
- package/dist/runtime/daimon/grokWorkerContract.js +48 -0
- package/dist/runtime/daimon/memory.d.ts +57 -0
- package/dist/runtime/daimon/memory.js +125 -0
- package/dist/runtime/daimon/runAuth.d.ts +51 -0
- package/dist/runtime/daimon/runAuth.js +279 -0
- package/dist/runtime/daimon/runtimeIdentity.d.ts +22 -0
- package/dist/runtime/daimon/runtimeIdentity.js +22 -0
- package/dist/runtime/daimon/scheduleAuthority.d.ts +3 -0
- package/dist/runtime/daimon/scheduleAuthority.js +17 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.js +4 -0
- package/dist/runtime/install.d.ts +3 -0
- package/dist/runtime/install.js +3 -0
- package/dist/runtime/localDaimonAuthority.d.ts +11 -0
- package/dist/runtime/localDaimonAuthority.js +77 -0
- package/dist/runtime/mnemeMcp.d.ts +13 -0
- package/dist/runtime/mnemeMcp.js +26 -0
- package/dist/runtime/openclaw/adapter.js +2 -2
- package/dist/runtime/pi/adapter.d.ts +0 -1
- package/dist/runtime/pi/adapter.js +2 -6
- package/dist/runtime/pi/appCliSource.js +1 -1
- package/dist/runtime/pi/appScheduleSource.js +6 -2
- package/dist/runtime/pi/appTemplateTypes.d.ts +1 -1
- package/dist/runtime/picoclaw/adapter.js +2 -2
- package/dist/runtime/registry.d.ts +3 -0
- package/dist/runtime/registry.js +19 -2
- package/dist/runtime/scheduleUtils.d.ts +1 -0
- package/dist/runtime/scheduleUtils.js +5 -1
- package/dist/runtime/types.d.ts +25 -0
- package/dist/runtime/usageLedger.d.ts +158 -0
- package/dist/runtime/usageLedger.js +269 -0
- package/dist/runtime/usageLedgerRead.d.ts +48 -0
- package/dist/runtime/usageLedgerRead.js +102 -0
- package/dist/runtime/usageRequestLedger.d.ts +42 -0
- package/dist/runtime/usageRequestLedger.js +72 -0
- package/dist/shared/daimonCodexDocker.d.ts +32 -0
- package/dist/shared/daimonCodexDocker.js +120 -0
- package/dist/shared/daimonGrokSeccompProfile.d.ts +10 -0
- package/dist/shared/daimonGrokSeccompProfile.js +11 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +2 -0
- package/dist/shared/types.d.ts +1 -1
- package/dist/shared/volumeNames.d.ts +6 -0
- package/dist/shared/volumeNames.js +14 -0
- package/dist/target/dockerArtifactsProvider.js +34 -7
- package/dist/target/dockerBaseImage.d.ts +2 -0
- package/dist/target/dockerBaseImage.js +11 -0
- package/dist/target/dockerCommandExecutor.d.ts +11 -0
- package/dist/target/dockerCommandExecutor.js +53 -2
- package/dist/target/dockerCommandExecutorCore.d.ts +2 -1
- package/dist/target/dockerCommandExecutorCore.js +4 -2
- package/dist/target/dockerPublicArtifactSnapshot.d.ts +3 -3
- package/dist/target/dockerPublicArtifactSnapshot.js +17 -33
- package/dist/target/dockerTarget.d.ts +1 -0
- package/dist/target/dockerTargetBinding.d.ts +1 -2
- package/dist/target/dockerTargetBinding.js +2 -3
- package/dist/target/dockerTargetExecFile.d.ts +19 -0
- package/dist/target/dockerTargetExecFile.js +194 -0
- package/dist/target/dockerWorldServiceProvider.d.ts +4 -0
- package/dist/target/dockerWorldServiceProvider.js +13 -1
- package/dist/target/evidenceExport.d.ts +3 -1
- package/dist/target/evidenceExport.js +12 -3
- package/dist/target/evidenceExportOperationsTestKit.js +3 -3
- package/dist/target/evidenceExportProvider.d.ts +2 -0
- package/dist/target/evidenceExportProvider.js +15 -5
- package/dist/target/publicArtifactSnapshot.d.ts +31 -0
- package/dist/target/publicArtifactSnapshot.js +37 -3
- package/examples/README.md +45 -0
- package/examples/agent-with-subagents/AGENTS.md +3 -0
- package/examples/agent-with-subagents/Spawnfile +30 -0
- package/examples/agent-with-subagents/subagents/critic/AGENTS.md +3 -0
- package/examples/agent-with-subagents/subagents/critic/Spawnfile +15 -0
- package/examples/agent-with-subagents/subagents/researcher/AGENTS.md +3 -0
- package/examples/agent-with-subagents/subagents/researcher/Spawnfile +17 -0
- package/examples/daimon-org/Spawnfile +68 -0
- package/examples/daimon-org/TEAM.md +4 -0
- package/examples/daimon-org/agents/mapper/AGENTS.md +4 -0
- package/examples/daimon-org/agents/mapper/Spawnfile +37 -0
- package/examples/daimon-org/shared/skills/file-note/SKILL.md +9 -0
- package/examples/daimon-org/teams/review/Spawnfile +53 -0
- package/examples/daimon-org/teams/review/agents/reviewer/AGENTS.md +4 -0
- package/examples/daimon-org/teams/review/agents/reviewer/Spawnfile +37 -0
- package/examples/daimon-public-host/AGENTS.md +3 -0
- package/examples/daimon-public-host/Spawnfile +21 -0
- package/examples/distribution-org/Spawnfile +43 -0
- package/examples/distribution-org/TEAM.md +4 -0
- package/examples/distribution-org/agents/coordinator/AGENTS.md +1 -0
- package/examples/distribution-org/agents/coordinator/Spawnfile +20 -0
- package/examples/distribution-org/agents/researcher/AGENTS.md +1 -0
- package/examples/distribution-org/agents/researcher/Spawnfile +20 -0
- package/examples/jungian-daimon-org/Spawnfile +41 -0
- package/examples/jungian-daimon-org/TEAM.md +21 -0
- package/examples/jungian-daimon-org/teams/luna/Spawnfile +47 -0
- package/examples/jungian-daimon-org/teams/luna/TEAM.md +4 -0
- package/examples/jungian-daimon-org/teams/luna/agents/animus/AGENTS.md +10 -0
- package/examples/jungian-daimon-org/teams/luna/agents/animus/Spawnfile +33 -0
- package/examples/jungian-daimon-org/teams/luna/agents/representative/AGENTS.md +21 -0
- package/examples/jungian-daimon-org/teams/luna/agents/representative/Spawnfile +30 -0
- package/examples/jungian-daimon-org/teams/luna/agents/shadow/AGENTS.md +10 -0
- package/examples/jungian-daimon-org/teams/luna/agents/shadow/Spawnfile +33 -0
- package/examples/jungian-daimon-org/teams/selene/Spawnfile +47 -0
- package/examples/jungian-daimon-org/teams/selene/TEAM.md +4 -0
- package/examples/jungian-daimon-org/teams/selene/agents/animus/AGENTS.md +10 -0
- package/examples/jungian-daimon-org/teams/selene/agents/animus/Spawnfile +33 -0
- package/examples/jungian-daimon-org/teams/selene/agents/representative/AGENTS.md +19 -0
- package/examples/jungian-daimon-org/teams/selene/agents/representative/Spawnfile +33 -0
- package/examples/jungian-daimon-org/teams/selene/agents/shadow/AGENTS.md +10 -0
- package/examples/jungian-daimon-org/teams/selene/agents/shadow/Spawnfile +30 -0
- package/examples/mixed-runtime-org/Spawnfile +71 -0
- package/examples/mixed-runtime-org/TEAM.md +8 -0
- package/examples/mixed-runtime-org/agents/analyst/AGENTS.md +8 -0
- package/examples/mixed-runtime-org/agents/analyst/Spawnfile +27 -0
- package/examples/mixed-runtime-org/agents/conductor/AGENTS.md +8 -0
- package/examples/mixed-runtime-org/agents/conductor/Spawnfile +27 -0
- package/examples/mixed-runtime-org/agents/localist/AGENTS.md +7 -0
- package/examples/mixed-runtime-org/agents/localist/Spawnfile +50 -0
- package/examples/moltnet-team-chat/Spawnfile +43 -0
- package/examples/moltnet-team-chat/TEAM.md +5 -0
- package/examples/moltnet-team-chat/agents/coordinator/AGENTS.md +9 -0
- package/examples/moltnet-team-chat/agents/coordinator/Spawnfile +26 -0
- package/examples/moltnet-team-chat/teams/analysis/Spawnfile +23 -0
- package/examples/moltnet-team-chat/teams/analysis/TEAM.md +3 -0
- package/examples/moltnet-team-chat/teams/analysis/agents/observer/AGENTS.md +5 -0
- package/examples/moltnet-team-chat/teams/analysis/agents/observer/Spawnfile +19 -0
- package/examples/moltnet-team-chat/teams/analysis/agents/representative/AGENTS.md +5 -0
- package/examples/moltnet-team-chat/teams/analysis/agents/representative/Spawnfile +19 -0
- package/examples/moltnet-team-chat/teams/field/Spawnfile +41 -0
- package/examples/moltnet-team-chat/teams/field/TEAM.md +3 -0
- package/examples/moltnet-team-chat/teams/field/agents/observer/AGENTS.md +5 -0
- package/examples/moltnet-team-chat/teams/field/agents/observer/Spawnfile +26 -0
- package/examples/moltnet-team-chat/teams/field/agents/representative/AGENTS.md +11 -0
- package/examples/moltnet-team-chat/teams/field/agents/representative/Spawnfile +26 -0
- package/examples/single-agent/AGENTS.md +3 -0
- package/examples/single-agent/HEARTBEAT.md +3 -0
- package/examples/single-agent/IDENTITY.md +3 -0
- package/examples/single-agent/MEMORY.md +3 -0
- package/examples/single-agent/SOUL.md +3 -0
- package/examples/single-agent/Spawnfile +41 -0
- package/examples/single-agent/skills/web_search/SKILL.md +6 -0
- package/moltnet-releases.json +5 -4
- package/package.json +36 -9
- package/runtimes.yaml +5 -2
- package/dist/cli/targetWorldClockCrossProcess.test-helper.d.ts +0 -13
- package/dist/cli/targetWorldClockCrossProcess.test-helper.js +0 -109
- package/dist/deployment/providerRuntimeBoundaryScanner.test-helper.d.ts +0 -8
- package/dist/deployment/providerRuntimeBoundaryScanner.test-helper.js +0 -60
- package/dist/deployment/simfileFixtureBoundary.test-helper.d.ts +0 -8
- package/dist/deployment/simfileFixtureBoundary.test-helper.js +0 -103
- package/dist/ownership/simfileRunOperatorInputs.d.ts +0 -103
- package/dist/ownership/simfileRunOperatorInputs.js +0 -139
- package/dist/target/cleanupRunDocker.test-helper.d.ts +0 -67
- package/dist/target/cleanupRunDocker.test-helper.js +0 -238
|
@@ -52,8 +52,8 @@ const organizationReadinessObjectSchema = z.object({
|
|
|
52
52
|
if (!validStateCode(result.state, result.code)) {
|
|
53
53
|
context.addIssue({ code: z.ZodIssueCode.custom, path: ["state"], message: "invalid state/code combination" });
|
|
54
54
|
}
|
|
55
|
-
if (result.state === "ready" &&
|
|
56
|
-
context.addIssue({ code: z.ZodIssueCode.custom, path: ["state"], message: "ready requires run_id
|
|
55
|
+
if (result.state === "ready" && result.run_id === null) {
|
|
56
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["state"], message: "ready requires run_id" });
|
|
57
57
|
}
|
|
58
58
|
});
|
|
59
59
|
export const organizationReadinessSchema = z.preprocess((value) => isPlainRecord(value) ? value : null, organizationReadinessObjectSchema);
|
|
@@ -126,6 +126,8 @@ const validNodeConfig = (content, expectedDigest) => {
|
|
|
126
126
|
}
|
|
127
127
|
};
|
|
128
128
|
const validBindings = (evidence, content) => {
|
|
129
|
+
if (evidence.worldBindings === null)
|
|
130
|
+
return content === null;
|
|
129
131
|
if (!content || !evidence.worldBindings || hash(content) !== evidence.worldBindings.digest)
|
|
130
132
|
return false;
|
|
131
133
|
try {
|
|
@@ -148,11 +150,41 @@ const validBindings = (evidence, content) => {
|
|
|
148
150
|
return false;
|
|
149
151
|
}
|
|
150
152
|
};
|
|
153
|
+
const validDaimon = (evidence, content) => {
|
|
154
|
+
if (evidence.daimon == null)
|
|
155
|
+
return content == null;
|
|
156
|
+
try {
|
|
157
|
+
const value = exact(JSON.parse(content ?? ""), ["version", "agents"]);
|
|
158
|
+
if (value?.version !== "noopolis.daimon.readiness-receipt.v1" || !Array.isArray(value.agents))
|
|
159
|
+
return false;
|
|
160
|
+
const agents = value.agents.map((entry) => { const item = exact(entry, ["agent_id", "engine"]); return item && typeof item.agent_id === "string" && typeof item.engine === "string" ? [item.agent_id, item.engine] : null; });
|
|
161
|
+
return agents.every(Boolean) && JSON.stringify(agents) === JSON.stringify(evidence.daimon.agents.map((agent) => [agent.agentId, agent.engine]));
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
};
|
|
167
|
+
const validAttachmentReceipts = (evidence, receipts) => {
|
|
168
|
+
const expected = evidence.networks.flatMap((network) => network.nodes.map((node) => ({ networkId: network.id, memberId: node.memberId, path: node.receiptPath })));
|
|
169
|
+
if (!receipts || receipts.size !== expected.length)
|
|
170
|
+
return expected.length === 0;
|
|
171
|
+
return expected.every((entry) => {
|
|
172
|
+
try {
|
|
173
|
+
const body = exact(JSON.parse(receipts.get(entry.path) ?? ""), ["version", "attachments"]);
|
|
174
|
+
if (body?.version !== "moltnet.node-readiness.v1" || !Array.isArray(body.attachments))
|
|
175
|
+
return false;
|
|
176
|
+
return body.attachments.length === 1 && body.attachments.every((value) => { const attachment = exact(value, ["network_id", "agent_id"]); return attachment?.network_id === entry.networkId && attachment.agent_id === entry.memberId; });
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
};
|
|
151
183
|
export const reconcileOrganizationReadiness = (input) => {
|
|
152
184
|
const { evidence, inspection, record } = input;
|
|
153
185
|
if (evidence.hasExternalMoltnet)
|
|
154
186
|
return correlation(evidence, record, "pending", "external_moltnet");
|
|
155
|
-
if (!
|
|
187
|
+
if (!record.runId)
|
|
156
188
|
return correlation(evidence, record, "pending", "compiled_evidence_missing");
|
|
157
189
|
if (record.unitCount !== 1 || !inspection || inspection.running !== true || inspection.exists !== true) {
|
|
158
190
|
return correlation(evidence, record, "pending", "unit_unavailable");
|
|
@@ -168,7 +200,7 @@ export const reconcileOrganizationReadiness = (input) => {
|
|
|
168
200
|
|| identity.unit !== record.unitId || identity.version !== evidence.compileVersion) {
|
|
169
201
|
return correlation(evidence, record, "failed", "identity_mismatch");
|
|
170
202
|
}
|
|
171
|
-
if (!input.probe || input.probe.networks.length !== evidence.networks.length
|
|
203
|
+
if (!input.probe || !validDaimon(evidence, input.probe.daimonReceipt) || !validAttachmentReceipts(evidence, input.probe.attachmentReceipts) || input.probe.networks.length !== evidence.networks.length
|
|
172
204
|
|| !evidence.networks.every((network) => {
|
|
173
205
|
const live = input.probe?.networks.find((candidate) => candidate.id === network.id);
|
|
174
206
|
return live?.healthOk === true;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
type DockerExec = (command: string, args: string[]) => Promise<{
|
|
2
|
+
stdout: string;
|
|
3
|
+
}>;
|
|
4
|
+
export declare const issueProductStateSourceAuthority: (input: {
|
|
5
|
+
dockerCommand: string;
|
|
6
|
+
container: string;
|
|
7
|
+
sourceRunId: string;
|
|
8
|
+
mountPath: string;
|
|
9
|
+
candidateVolumeName: string;
|
|
10
|
+
candidateResourceIdentity: string;
|
|
11
|
+
}, docker?: DockerExec) => Promise<Record<string, unknown>>;
|
|
12
|
+
export declare const createProductStateProof: (source: string, sourceRunId: string) => Promise<Record<string, unknown>>;
|
|
13
|
+
export declare const issueProductStateSourceSnapshot: (input: {
|
|
14
|
+
dockerCommand: string;
|
|
15
|
+
container: string;
|
|
16
|
+
sourceRunId: string;
|
|
17
|
+
mountPath: string;
|
|
18
|
+
candidateVolumeName: string;
|
|
19
|
+
candidateResourceIdentity: string;
|
|
20
|
+
}, docker?: DockerExec) => Promise<{
|
|
21
|
+
authority: Record<string, unknown>;
|
|
22
|
+
proof: Record<string, unknown>;
|
|
23
|
+
}>;
|
|
24
|
+
export declare const cloneQuiescedProductState: (input: {
|
|
25
|
+
source: string;
|
|
26
|
+
destination: string;
|
|
27
|
+
proof: unknown;
|
|
28
|
+
candidateRunId: string;
|
|
29
|
+
activationIdentity?: string;
|
|
30
|
+
}) => Promise<{
|
|
31
|
+
files: number;
|
|
32
|
+
source_run_id: string;
|
|
33
|
+
candidate_run_id: string;
|
|
34
|
+
}>;
|
|
35
|
+
export declare const runProductStateCloneWorkflow: (input: {
|
|
36
|
+
authorityReceiptPath: string;
|
|
37
|
+
dockerCommand: string;
|
|
38
|
+
destination: string;
|
|
39
|
+
proofPath: string;
|
|
40
|
+
receiptPath: string;
|
|
41
|
+
candidateRunId: string;
|
|
42
|
+
}, docker?: DockerExec) => Promise<Record<string, unknown>>;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { chmod, copyFile, link, mkdir, open, readFile, readdir, rename, rm, stat } from "node:fs/promises";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { execFile as execFileCallback } from "node:child_process";
|
|
5
|
+
import { promisify } from "node:util";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { SpawnfileError } from "../shared/index.js";
|
|
9
|
+
const digest = z.string().regex(/^sha256:[a-f0-9]{64}$/u);
|
|
10
|
+
const relative = z.string().min(1).max(255).refine((value) => !path.isAbsolute(value) && !value.split(/[\\/]/u).includes(".."));
|
|
11
|
+
const proofSchema = z.object({ version: z.literal("spawnfile.product-state-quiescence.v1"), state: z.literal("quiesced"), source_run_id: z.string().regex(/^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/u), files: z.array(z.object({ path: relative, sha256: digest }).strict()).min(1).max(4096) }).strict();
|
|
12
|
+
const forbidden = /(?:^|[._/-])(?:auth|credential|token|secret|session|wake)(?:[._/-]|$)|\.(?:db|sqlite|sqlite3)(?:-|$)/iu;
|
|
13
|
+
const execFile = promisify(execFileCallback);
|
|
14
|
+
const authoritySchema = z.object({ version: z.literal("spawnfile.product-state-source-authority.v1"), source_run_id: z.string(), container_id: z.string().regex(/^[a-f0-9]{64}$/u), image_id: z.string().regex(/^sha256:[a-f0-9]{64}$/u), started_at: z.string().min(1), was_paused: z.boolean(), source: z.string().min(1), mount_path: z.string().min(1), volume_name: z.string().min(1), candidate_volume_name: z.string().min(1), candidate_resource_identity: digest }).strict();
|
|
15
|
+
const defaultDockerExec = async (command, args) => await execFile(command, args, { encoding: "utf8", maxBuffer: 1_048_576, timeout: 10_000 });
|
|
16
|
+
const inspectContainer = async (docker, command, container) => { const value = JSON.parse((await docker(command, ["inspect", container])).stdout); if (!Array.isArray(value) || value.length !== 1 || typeof value[0] !== "object")
|
|
17
|
+
throw new SpawnfileError("validation_error", "Managed source container inspection failed"); return value[0]; };
|
|
18
|
+
const restoreRunningState = async (docker, command, authority) => {
|
|
19
|
+
await docker(command, ["unpause", authority.container_id]);
|
|
20
|
+
const restored = await inspectContainer(docker, command, authority.container_id);
|
|
21
|
+
if (restored.Id !== authority.container_id || restored.Image !== authority.image_id || restored.State?.StartedAt !== authority.started_at || restored.State?.Running !== true || restored.State?.Paused !== false)
|
|
22
|
+
throw new SpawnfileError("validation_error", "Managed source state restoration could not be proven");
|
|
23
|
+
};
|
|
24
|
+
export const issueProductStateSourceAuthority = async (input, docker = defaultDockerExec) => {
|
|
25
|
+
const inspected = await inspectContainer(docker, input.dockerCommand, input.container), labels = inspected.Config?.Labels, state = inspected.State;
|
|
26
|
+
const mounts = Array.isArray(inspected.Mounts) ? inspected.Mounts.filter((mount) => mount.Type === "volume" && mount.Destination === input.mountPath && mount.RW === true) : [];
|
|
27
|
+
if (inspected.Id?.length !== 64 || !/^sha256:[a-f0-9]{64}$/u.test(inspected.Image) || labels?.["com.spawnfile.run_id"] !== input.sourceRunId || state?.Running !== true || typeof state.StartedAt !== "string" || mounts.length !== 1 || typeof mounts[0].Source !== "string" || typeof mounts[0].Name !== "string")
|
|
28
|
+
throw new SpawnfileError("validation_error", "Source run does not own one exact managed writable state root");
|
|
29
|
+
const volume = JSON.parse((await docker(input.dockerCommand, ["volume", "inspect", input.candidateVolumeName])).stdout);
|
|
30
|
+
if (!Array.isArray(volume) || volume.length !== 1 || typeof volume[0]?.Mountpoint !== "string")
|
|
31
|
+
throw new SpawnfileError("validation_error", "Candidate volume is unavailable");
|
|
32
|
+
return authoritySchema.parse({ version: "spawnfile.product-state-source-authority.v1", source_run_id: input.sourceRunId, container_id: inspected.Id, image_id: inspected.Image, started_at: state.StartedAt, was_paused: state.Paused === true, source: mounts[0].Source, mount_path: input.mountPath, volume_name: mounts[0].Name, candidate_volume_name: input.candidateVolumeName, candidate_resource_identity: input.candidateResourceIdentity });
|
|
33
|
+
};
|
|
34
|
+
const hashFile = async (file) => {
|
|
35
|
+
const handle = await open(file, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
36
|
+
try {
|
|
37
|
+
const info = await handle.stat();
|
|
38
|
+
if (!info.isFile() || info.size > 67_108_864)
|
|
39
|
+
throw new SpawnfileError("validation_error", "Product state file is unsafe or oversized");
|
|
40
|
+
return `sha256:${createHash("sha256").update(await handle.readFile()).digest("hex")}`;
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await handle.close();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const syncDirectory = async (directory) => { const handle = await open(directory, constants.O_RDONLY); try {
|
|
47
|
+
await handle.sync();
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
await handle.close();
|
|
51
|
+
} };
|
|
52
|
+
const syncTreeDirectories = async (directory) => { for (const entry of await readdir(directory, { withFileTypes: true }))
|
|
53
|
+
if (entry.isDirectory())
|
|
54
|
+
await syncTreeDirectories(path.join(directory, entry.name)); await syncDirectory(directory); };
|
|
55
|
+
const wholeSourceManifest = async (root) => {
|
|
56
|
+
const result = new Map();
|
|
57
|
+
const visit = async (directory, prefix) => {
|
|
58
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
59
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
60
|
+
if ([".spawnfile-product-state-write-fence", ".spawnfile-product-state-preseed-journal", ".spawnfile-resource-identity"].includes(relativePath))
|
|
61
|
+
continue;
|
|
62
|
+
const absolutePath = path.join(directory, entry.name);
|
|
63
|
+
if (entry.isDirectory()) {
|
|
64
|
+
await visit(absolutePath, relativePath);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (!entry.isFile() || result.size >= 4096)
|
|
68
|
+
throw new SpawnfileError("validation_error", "Product-state source contains an unsafe or excessive entry");
|
|
69
|
+
result.set(relativePath, await hashFile(absolutePath));
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
await visit(root, "");
|
|
73
|
+
return result;
|
|
74
|
+
};
|
|
75
|
+
const verifyWholeSourceManifest = async (root, proof) => {
|
|
76
|
+
const actual = await wholeSourceManifest(root), expected = new Map(proof.files.map((entry) => [entry.path, entry.sha256]));
|
|
77
|
+
if (actual.size !== expected.size || [...actual].some(([name, checksum]) => expected.get(name) !== checksum))
|
|
78
|
+
throw new SpawnfileError("validation_error", "Whole product-state source manifest drifted or is incomplete");
|
|
79
|
+
};
|
|
80
|
+
export const createProductStateProof = async (source, sourceRunId) => {
|
|
81
|
+
const manifest = await wholeSourceManifest(source);
|
|
82
|
+
const files = [...manifest].sort(([left], [right]) => left.localeCompare(right)).map(([filePath, sha256]) => { if (forbidden.test(filePath))
|
|
83
|
+
throw new SpawnfileError("validation_error", "Product-state source includes prohibited state"); return { path: filePath, sha256 }; });
|
|
84
|
+
return proofSchema.parse({ version: "spawnfile.product-state-quiescence.v1", state: "quiesced", source_run_id: sourceRunId, files });
|
|
85
|
+
};
|
|
86
|
+
export const issueProductStateSourceSnapshot = async (input, docker = defaultDockerExec) => {
|
|
87
|
+
const authority = authoritySchema.parse(await issueProductStateSourceAuthority(input, docker));
|
|
88
|
+
let pausedByUs = false;
|
|
89
|
+
try {
|
|
90
|
+
if (!authority.was_paused) {
|
|
91
|
+
await docker(input.dockerCommand, ["pause", authority.container_id]);
|
|
92
|
+
pausedByUs = true;
|
|
93
|
+
}
|
|
94
|
+
const frozen = await inspectContainer(docker, input.dockerCommand, authority.container_id);
|
|
95
|
+
if (frozen.Id !== authority.container_id || frozen.Image !== authority.image_id || frozen.State?.StartedAt !== authority.started_at || frozen.State?.Paused !== true)
|
|
96
|
+
throw new SpawnfileError("validation_error", "Source changed before authoritative snapshot");
|
|
97
|
+
return { authority, proof: await createProductStateProof(authority.source, authority.source_run_id) };
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
if (pausedByUs)
|
|
101
|
+
await restoreRunningState(docker, input.dockerCommand, authority);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
export const cloneQuiescedProductState = async (input) => {
|
|
105
|
+
const proof = proofSchema.parse(input.proof);
|
|
106
|
+
if (proof.source_run_id === input.candidateRunId)
|
|
107
|
+
throw new SpawnfileError("validation_error", "Candidate state namespace must differ from source");
|
|
108
|
+
const destinationExists = await stat(input.destination).then((info) => { if (!info.isDirectory())
|
|
109
|
+
throw new SpawnfileError("validation_error", "Candidate state destination is not a directory"); return true; }, (error) => error.code === "ENOENT" ? false : Promise.reject(error));
|
|
110
|
+
const journalPath = path.join(input.destination, ".spawnfile-product-state-preseed-journal");
|
|
111
|
+
if (destinationExists && await stat(journalPath).then(() => true, () => false)) {
|
|
112
|
+
const journal = z.object({ version: z.literal("spawnfile.product-state-preseed-journal.v1"), candidate_run_id: z.string(), entries: z.array(relative), staging: relative }).strict().parse(JSON.parse(await readFile(journalPath, "utf8")));
|
|
113
|
+
if (journal.candidate_run_id !== input.candidateRunId)
|
|
114
|
+
throw new SpawnfileError("validation_error", "Candidate preseed journal belongs to another run");
|
|
115
|
+
const identityPath = path.join(input.destination, ".spawnfile-resource-identity"), activated = input.activationIdentity && await readFile(identityPath, "utf8").then((value) => value === `${input.activationIdentity}\n`, () => false);
|
|
116
|
+
if (activated) {
|
|
117
|
+
await verifyWholeSourceManifest(input.destination, proof);
|
|
118
|
+
await rm(journalPath);
|
|
119
|
+
await syncDirectory(input.destination);
|
|
120
|
+
return { files: proof.files.length, source_run_id: proof.source_run_id, candidate_run_id: input.candidateRunId };
|
|
121
|
+
}
|
|
122
|
+
for (const entry of [...journal.entries, journal.staging])
|
|
123
|
+
await rm(path.join(input.destination, entry), { recursive: true, force: true });
|
|
124
|
+
await rm(journalPath);
|
|
125
|
+
await syncDirectory(input.destination);
|
|
126
|
+
}
|
|
127
|
+
if (destinationExists && (await readdir(input.destination)).length !== 0)
|
|
128
|
+
throw new SpawnfileError("validation_error", "Candidate state destination is not empty");
|
|
129
|
+
const names = new Set();
|
|
130
|
+
for (const entry of proof.files) {
|
|
131
|
+
if (forbidden.test(entry.path) || names.has(entry.path))
|
|
132
|
+
throw new SpawnfileError("validation_error", "Product-state classification contains a prohibited or duplicate path");
|
|
133
|
+
names.add(entry.path);
|
|
134
|
+
if (await hashFile(path.join(input.source, entry.path)) !== entry.sha256)
|
|
135
|
+
throw new SpawnfileError("validation_error", "Quiesced product-state checksum mismatch");
|
|
136
|
+
}
|
|
137
|
+
const temporary = destinationExists ? path.join(input.destination, `.spawnfile-preseed-${process.pid}`) : `${input.destination}.candidate-${process.pid}`;
|
|
138
|
+
await mkdir(temporary, { recursive: false, mode: 0o700 });
|
|
139
|
+
const activated = [];
|
|
140
|
+
try {
|
|
141
|
+
for (const entry of proof.files) {
|
|
142
|
+
const target = path.join(temporary, entry.path);
|
|
143
|
+
await mkdir(path.dirname(target), { recursive: true, mode: 0o700 });
|
|
144
|
+
await copyFile(path.join(input.source, entry.path), target, constants.COPYFILE_EXCL);
|
|
145
|
+
const copied = await open(target, constants.O_RDONLY);
|
|
146
|
+
try {
|
|
147
|
+
await copied.sync();
|
|
148
|
+
}
|
|
149
|
+
finally {
|
|
150
|
+
await copied.close();
|
|
151
|
+
}
|
|
152
|
+
if (await hashFile(target) !== entry.sha256 || await hashFile(path.join(input.source, entry.path)) !== entry.sha256)
|
|
153
|
+
throw new SpawnfileError("validation_error", "Product state changed during clone");
|
|
154
|
+
}
|
|
155
|
+
await syncTreeDirectories(temporary);
|
|
156
|
+
if (destinationExists) {
|
|
157
|
+
const entries = await readdir(temporary), journal = await open(journalPath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
|
|
158
|
+
try {
|
|
159
|
+
await journal.writeFile(`${JSON.stringify({ version: "spawnfile.product-state-preseed-journal.v1", candidate_run_id: input.candidateRunId, entries, staging: path.basename(temporary) })}\n`);
|
|
160
|
+
await journal.sync();
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
await journal.close();
|
|
164
|
+
}
|
|
165
|
+
await syncDirectory(input.destination);
|
|
166
|
+
for (const entry of entries) {
|
|
167
|
+
await rename(path.join(temporary, entry), path.join(input.destination, entry));
|
|
168
|
+
activated.push(path.join(input.destination, entry));
|
|
169
|
+
await syncDirectory(input.destination);
|
|
170
|
+
}
|
|
171
|
+
await rm(temporary, { recursive: true });
|
|
172
|
+
await syncDirectory(input.destination);
|
|
173
|
+
await verifyWholeSourceManifest(input.destination, proof);
|
|
174
|
+
if (input.activationIdentity) {
|
|
175
|
+
const identity = await open(path.join(input.destination, ".spawnfile-resource-identity"), constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
|
|
176
|
+
try {
|
|
177
|
+
await identity.writeFile(`${input.activationIdentity}\n`);
|
|
178
|
+
await identity.sync();
|
|
179
|
+
}
|
|
180
|
+
finally {
|
|
181
|
+
await identity.close();
|
|
182
|
+
}
|
|
183
|
+
await syncDirectory(input.destination);
|
|
184
|
+
}
|
|
185
|
+
await rm(journalPath);
|
|
186
|
+
await syncDirectory(input.destination);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
await rename(temporary, input.destination);
|
|
190
|
+
await syncDirectory(path.dirname(input.destination));
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
if (input.activationIdentity) {
|
|
195
|
+
await rm(path.join(input.destination, ".spawnfile-resource-identity"), { force: true });
|
|
196
|
+
if (destinationExists)
|
|
197
|
+
await syncDirectory(input.destination);
|
|
198
|
+
}
|
|
199
|
+
for (const entry of activated.reverse()) {
|
|
200
|
+
await rm(entry, { recursive: true, force: true });
|
|
201
|
+
if (destinationExists)
|
|
202
|
+
await syncDirectory(input.destination);
|
|
203
|
+
}
|
|
204
|
+
await rm(temporary, { recursive: true, force: true });
|
|
205
|
+
await syncDirectory(destinationExists ? input.destination : path.dirname(input.destination));
|
|
206
|
+
await rm(journalPath, { force: true });
|
|
207
|
+
if (destinationExists)
|
|
208
|
+
await syncDirectory(input.destination);
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
return { files: proof.files.length, source_run_id: proof.source_run_id, candidate_run_id: input.candidateRunId };
|
|
212
|
+
};
|
|
213
|
+
export const runProductStateCloneWorkflow = async (input, docker = defaultDockerExec) => {
|
|
214
|
+
const authority = authoritySchema.parse(JSON.parse(await readFile(input.authorityReceiptPath, "utf8")));
|
|
215
|
+
const candidateVolume = JSON.parse((await docker(input.dockerCommand, ["volume", "inspect", authority.candidate_volume_name])).stdout);
|
|
216
|
+
if (!Array.isArray(candidateVolume) || candidateVolume.length !== 1 || candidateVolume[0]?.Mountpoint !== path.resolve(input.destination))
|
|
217
|
+
throw new SpawnfileError("validation_error", "Clone destination is not the attested candidate volume");
|
|
218
|
+
const current = await inspectContainer(docker, input.dockerCommand, authority.container_id), currentMounts = Array.isArray(current.Mounts) ? current.Mounts : [];
|
|
219
|
+
if (current.Id !== authority.container_id || current.Image !== authority.image_id || current.State?.StartedAt !== authority.started_at || current.Config?.Labels?.["com.spawnfile.run_id"] !== authority.source_run_id || current.State?.Running !== true || current.State?.Paused !== authority.was_paused || !currentMounts.some((mount) => mount.Type === "volume" && mount.Name === authority.volume_name && mount.Source === authority.source && mount.Destination === authority.mount_path && mount.RW === true))
|
|
220
|
+
throw new SpawnfileError("validation_error", "Source run authority is stale or rebound");
|
|
221
|
+
const proofBytes = await readFile(input.proofPath);
|
|
222
|
+
if (proofBytes.length > 1_048_576)
|
|
223
|
+
throw new SpawnfileError("validation_error", "Product-state proof is oversized");
|
|
224
|
+
const proof = proofSchema.parse(JSON.parse(proofBytes.toString("utf8")));
|
|
225
|
+
if (proof.source_run_id !== authority.source_run_id)
|
|
226
|
+
throw new SpawnfileError("validation_error", "Proof source run does not match managed authority");
|
|
227
|
+
const fencePath = path.join(authority.source, ".spawnfile-product-state-write-fence");
|
|
228
|
+
const fence = await open(fencePath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY | constants.O_NOFOLLOW, 0o400);
|
|
229
|
+
const modes = [];
|
|
230
|
+
let pausedByUs = false;
|
|
231
|
+
try {
|
|
232
|
+
await fence.writeFile(`${proof.source_run_id}\n`);
|
|
233
|
+
await fence.sync();
|
|
234
|
+
if (!authority.was_paused) {
|
|
235
|
+
await docker(input.dockerCommand, ["pause", authority.container_id]);
|
|
236
|
+
pausedByUs = true;
|
|
237
|
+
}
|
|
238
|
+
const frozen = await inspectContainer(docker, input.dockerCommand, authority.container_id);
|
|
239
|
+
if (frozen.State?.Paused !== true || frozen.State?.StartedAt !== authority.started_at || frozen.Id !== authority.container_id)
|
|
240
|
+
throw new SpawnfileError("validation_error", "Managed source cgroup did not freeze exactly");
|
|
241
|
+
await verifyWholeSourceManifest(authority.source, proof);
|
|
242
|
+
for (const entry of proof.files) {
|
|
243
|
+
if (forbidden.test(entry.path))
|
|
244
|
+
throw new SpawnfileError("validation_error", "Product-state classification contains a prohibited path");
|
|
245
|
+
const file = path.join(authority.source, entry.path), info = await stat(file);
|
|
246
|
+
modes.push({ file, mode: info.mode & 0o777 });
|
|
247
|
+
await chmod(file, info.mode & ~0o222);
|
|
248
|
+
}
|
|
249
|
+
const cloned = await cloneQuiescedProductState({ source: authority.source, destination: input.destination, proof, candidateRunId: input.candidateRunId, activationIdentity: authority.candidate_resource_identity });
|
|
250
|
+
await verifyWholeSourceManifest(authority.source, proof);
|
|
251
|
+
await verifyWholeSourceManifest(input.destination, proof);
|
|
252
|
+
const receipt = { version: "spawnfile.product-state-clone-receipt.v1", ...cloned, proof_sha256: `sha256:${createHash("sha256").update(proofBytes).digest("hex")}`, destination: path.resolve(input.destination), candidate_volume_name: authority.candidate_volume_name, source_container_id: authority.container_id };
|
|
253
|
+
const temporaryReceipt = `${input.receiptPath}.tmp-${process.pid}`;
|
|
254
|
+
await mkdir(path.dirname(input.receiptPath), { recursive: true, mode: 0o700 });
|
|
255
|
+
let published = false;
|
|
256
|
+
try {
|
|
257
|
+
const receiptFile = await open(temporaryReceipt, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
|
|
258
|
+
try {
|
|
259
|
+
await receiptFile.writeFile(`${JSON.stringify(receipt)}\n`);
|
|
260
|
+
await receiptFile.sync();
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
await receiptFile.close();
|
|
264
|
+
}
|
|
265
|
+
await link(temporaryReceipt, input.receiptPath);
|
|
266
|
+
published = true;
|
|
267
|
+
const receiptDirectory = await open(path.dirname(input.receiptPath), constants.O_RDONLY);
|
|
268
|
+
try {
|
|
269
|
+
await receiptDirectory.sync();
|
|
270
|
+
}
|
|
271
|
+
finally {
|
|
272
|
+
await receiptDirectory.close();
|
|
273
|
+
}
|
|
274
|
+
await rm(temporaryReceipt);
|
|
275
|
+
await syncDirectory(path.dirname(input.receiptPath));
|
|
276
|
+
}
|
|
277
|
+
catch (error) {
|
|
278
|
+
await rm(temporaryReceipt, { force: true });
|
|
279
|
+
await syncDirectory(path.dirname(input.receiptPath));
|
|
280
|
+
if (published) {
|
|
281
|
+
await rm(input.receiptPath, { force: true });
|
|
282
|
+
await syncDirectory(path.dirname(input.receiptPath));
|
|
283
|
+
}
|
|
284
|
+
for (const entry of await readdir(input.destination)) {
|
|
285
|
+
await rm(path.join(input.destination, entry), { recursive: true, force: true });
|
|
286
|
+
await syncDirectory(input.destination);
|
|
287
|
+
}
|
|
288
|
+
throw error;
|
|
289
|
+
}
|
|
290
|
+
return receipt;
|
|
291
|
+
}
|
|
292
|
+
finally {
|
|
293
|
+
let restorationError;
|
|
294
|
+
for (const item of modes.reverse())
|
|
295
|
+
try {
|
|
296
|
+
await chmod(item.file, item.mode);
|
|
297
|
+
}
|
|
298
|
+
catch (error) {
|
|
299
|
+
restorationError ??= error;
|
|
300
|
+
}
|
|
301
|
+
try {
|
|
302
|
+
await fence.close();
|
|
303
|
+
await rm(fencePath, { force: true });
|
|
304
|
+
await syncDirectory(authority.source);
|
|
305
|
+
}
|
|
306
|
+
catch (error) {
|
|
307
|
+
restorationError ??= error;
|
|
308
|
+
}
|
|
309
|
+
try {
|
|
310
|
+
if (pausedByUs)
|
|
311
|
+
await restoreRunningState(docker, input.dockerCommand, authority);
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
restorationError ??= error;
|
|
315
|
+
}
|
|
316
|
+
if (restorationError)
|
|
317
|
+
throw new SpawnfileError("validation_error", "Product-state source restoration failed", { cause: restorationError });
|
|
318
|
+
}
|
|
319
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ephemeral grants issued only by the durable up reconciler. They are kept
|
|
3
|
+
* process-local: a restart reconstructs them by re-reading and re-verifying
|
|
4
|
+
* the lifecycle records, never by trusting caller-supplied recovery data.
|
|
5
|
+
*/
|
|
6
|
+
export interface NoDockerMutationRecovery {
|
|
7
|
+
readonly kind: "no_docker_mutation";
|
|
8
|
+
}
|
|
9
|
+
export interface DeploymentRecordRecovery {
|
|
10
|
+
readonly kind: "deployment_record";
|
|
11
|
+
}
|
|
12
|
+
export interface DetachedContainerRecovery {
|
|
13
|
+
readonly containerId: string;
|
|
14
|
+
readonly containerName: string;
|
|
15
|
+
readonly deploymentLabels: Readonly<Record<string, string>>;
|
|
16
|
+
readonly imageId: string;
|
|
17
|
+
readonly kind: "detached_container";
|
|
18
|
+
}
|
|
19
|
+
export type UpLifecycleRecovery = NoDockerMutationRecovery | DeploymentRecordRecovery | DetachedContainerRecovery;
|
|
20
|
+
export declare const noDockerMutationRecovery: () => NoDockerMutationRecovery;
|
|
21
|
+
export declare const deploymentRecordRecovery: () => DeploymentRecordRecovery;
|
|
22
|
+
export declare const detachedContainerRecovery: (value: Omit<DetachedContainerRecovery, "kind">) => DetachedContainerRecovery;
|
|
23
|
+
export declare const isTrustedUpLifecycleRecovery: (value: unknown) => value is UpLifecycleRecovery;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
const grants = new WeakSet();
|
|
2
|
+
const grant = (value) => {
|
|
3
|
+
const result = Object.freeze(value);
|
|
4
|
+
grants.add(result);
|
|
5
|
+
return result;
|
|
6
|
+
};
|
|
7
|
+
export const noDockerMutationRecovery = () => grant({ kind: "no_docker_mutation" });
|
|
8
|
+
export const deploymentRecordRecovery = () => grant({ kind: "deployment_record" });
|
|
9
|
+
export const detachedContainerRecovery = (value) => grant({ ...value, kind: "detached_container" });
|
|
10
|
+
export const isTrustedUpLifecycleRecovery = (value) => value !== null
|
|
11
|
+
&& typeof value === "object"
|
|
12
|
+
&& grants.has(value);
|
|
@@ -38,15 +38,28 @@ declare const compiledEngineEntrySchema: z.ZodObject<{
|
|
|
38
38
|
engine: z.ZodString;
|
|
39
39
|
}, z.core.$strict>;
|
|
40
40
|
export type CompiledEngineEntry = z.infer<typeof compiledEngineEntrySchema>;
|
|
41
|
-
declare const moltnetReleaseIdentitySchema: z.ZodObject<{
|
|
41
|
+
declare const moltnetReleaseIdentitySchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
42
42
|
architecture: z.ZodUnion<readonly [z.ZodLiteral<"amd64">, z.ZodLiteral<"arm64">]>;
|
|
43
43
|
asset: z.ZodString;
|
|
44
44
|
asset_sha256: z.ZodString;
|
|
45
|
-
capabilities: z.ZodTuple<[z.ZodLiteral<"pi-bridge">], null>;
|
|
45
|
+
capabilities: z.ZodUnion<readonly [z.ZodTuple<[z.ZodLiteral<"pi-bridge">], null>, z.ZodTuple<[z.ZodLiteral<"daimon-bridge">, z.ZodLiteral<"pi-bridge">], null>]>;
|
|
46
46
|
release_version: z.ZodString;
|
|
47
47
|
source_revision: z.ZodString;
|
|
48
48
|
version: z.ZodLiteral<"spawnfile.moltnet-release-identity.v1">;
|
|
49
|
-
}, z.core.$strict
|
|
49
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
50
|
+
architecture: z.ZodUnion<readonly [z.ZodLiteral<"amd64">, z.ZodLiteral<"arm64">]>;
|
|
51
|
+
asset: z.ZodString;
|
|
52
|
+
asset_sha256: z.ZodString;
|
|
53
|
+
capabilities: z.ZodTuple<[z.ZodLiteral<"daimon-bridge">, z.ZodLiteral<"pi-bridge">], null>;
|
|
54
|
+
development: z.ZodObject<{
|
|
55
|
+
mode: z.ZodLiteral<"local-development">;
|
|
56
|
+
non_production: z.ZodLiteral<true>;
|
|
57
|
+
unsigned: z.ZodLiteral<true>;
|
|
58
|
+
unpublished: z.ZodLiteral<true>;
|
|
59
|
+
}, z.core.$strict>;
|
|
60
|
+
source_sha256: z.ZodString;
|
|
61
|
+
version: z.ZodLiteral<"spawnfile.moltnet-release-identity.v1">;
|
|
62
|
+
}, z.core.$strict>]>;
|
|
50
63
|
export type MoltnetReleaseReceiptIdentity = z.infer<typeof moltnetReleaseIdentitySchema>;
|
|
51
64
|
export declare const upReceiptSchema: z.ZodPreprocess<z.ZodObject<{
|
|
52
65
|
version: z.ZodLiteral<"spawnfile.up-receipt.v1">;
|
|
@@ -68,15 +81,28 @@ export declare const upReceiptSchema: z.ZodPreprocess<z.ZodObject<{
|
|
|
68
81
|
agent: z.ZodString;
|
|
69
82
|
engine: z.ZodString;
|
|
70
83
|
}, z.core.$strict>>>;
|
|
71
|
-
moltnet_release: z.ZodOptional<z.ZodObject<{
|
|
84
|
+
moltnet_release: z.ZodOptional<z.ZodUnion<readonly [z.ZodObject<{
|
|
72
85
|
architecture: z.ZodUnion<readonly [z.ZodLiteral<"amd64">, z.ZodLiteral<"arm64">]>;
|
|
73
86
|
asset: z.ZodString;
|
|
74
87
|
asset_sha256: z.ZodString;
|
|
75
|
-
capabilities: z.ZodTuple<[z.ZodLiteral<"pi-bridge">], null>;
|
|
88
|
+
capabilities: z.ZodUnion<readonly [z.ZodTuple<[z.ZodLiteral<"pi-bridge">], null>, z.ZodTuple<[z.ZodLiteral<"daimon-bridge">, z.ZodLiteral<"pi-bridge">], null>]>;
|
|
76
89
|
release_version: z.ZodString;
|
|
77
90
|
source_revision: z.ZodString;
|
|
78
91
|
version: z.ZodLiteral<"spawnfile.moltnet-release-identity.v1">;
|
|
79
|
-
}, z.core.$strict
|
|
92
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
93
|
+
architecture: z.ZodUnion<readonly [z.ZodLiteral<"amd64">, z.ZodLiteral<"arm64">]>;
|
|
94
|
+
asset: z.ZodString;
|
|
95
|
+
asset_sha256: z.ZodString;
|
|
96
|
+
capabilities: z.ZodTuple<[z.ZodLiteral<"daimon-bridge">, z.ZodLiteral<"pi-bridge">], null>;
|
|
97
|
+
development: z.ZodObject<{
|
|
98
|
+
mode: z.ZodLiteral<"local-development">;
|
|
99
|
+
non_production: z.ZodLiteral<true>;
|
|
100
|
+
unsigned: z.ZodLiteral<true>;
|
|
101
|
+
unpublished: z.ZodLiteral<true>;
|
|
102
|
+
}, z.core.$strict>;
|
|
103
|
+
source_sha256: z.ZodString;
|
|
104
|
+
version: z.ZodLiteral<"spawnfile.moltnet-release-identity.v1">;
|
|
105
|
+
}, z.core.$strict>]>>;
|
|
80
106
|
organization_handoff: z.ZodOptional<z.ZodObject<{
|
|
81
107
|
binding_digest: z.ZodString;
|
|
82
108
|
deployment_handle: z.ZodString;
|
|
@@ -43,11 +43,16 @@ const compiledEngineEntrySchema = z
|
|
|
43
43
|
engine: z.string().min(1)
|
|
44
44
|
})
|
|
45
45
|
.strict();
|
|
46
|
-
const
|
|
46
|
+
const publishedMoltnetReleaseIdentitySchema = z.object({
|
|
47
47
|
architecture: z.union([z.literal("amd64"), z.literal("arm64")]),
|
|
48
48
|
asset: z.string().regex(/^moltnet_linux_(amd64|arm64)\.tar\.gz$/u),
|
|
49
49
|
asset_sha256: z.string().regex(/^sha256:[a-f0-9]{64}$/u),
|
|
50
|
-
|
|
50
|
+
// Union, not replacement: moltnet v0.1.18 publishes both bridges, and every
|
|
51
|
+
// older pi-only release must still validate.
|
|
52
|
+
capabilities: z.union([
|
|
53
|
+
z.tuple([z.literal("pi-bridge")]),
|
|
54
|
+
z.tuple([z.literal("daimon-bridge"), z.literal("pi-bridge")])
|
|
55
|
+
]),
|
|
51
56
|
release_version: z.string().regex(/^v?\d+\.\d+\.\d+(?:-\d+-g[a-f0-9]{7,40})?$/u),
|
|
52
57
|
source_revision: z.string().regex(/^[a-f0-9]{40}$/u),
|
|
53
58
|
version: z.literal("spawnfile.moltnet-release-identity.v1")
|
|
@@ -68,6 +73,28 @@ const moltnetReleaseIdentitySchema = z.object({
|
|
|
68
73
|
});
|
|
69
74
|
}
|
|
70
75
|
});
|
|
76
|
+
const localMoltnetReleaseIdentitySchema = z.object({
|
|
77
|
+
architecture: z.union([z.literal("amd64"), z.literal("arm64")]),
|
|
78
|
+
asset: z.string().regex(/^moltnet_linux_(amd64|arm64)\.tar\.gz$/u),
|
|
79
|
+
asset_sha256: z.string().regex(/^sha256:[a-f0-9]{64}$/u),
|
|
80
|
+
capabilities: z.tuple([z.literal("daimon-bridge"), z.literal("pi-bridge")]),
|
|
81
|
+
development: z.object({
|
|
82
|
+
mode: z.literal("local-development"),
|
|
83
|
+
non_production: z.literal(true),
|
|
84
|
+
unsigned: z.literal(true),
|
|
85
|
+
unpublished: z.literal(true)
|
|
86
|
+
}).strict(),
|
|
87
|
+
source_sha256: z.string().regex(/^sha256:[a-f0-9]{64}$/u),
|
|
88
|
+
version: z.literal("spawnfile.moltnet-release-identity.v1")
|
|
89
|
+
}).strict().superRefine((value, context) => {
|
|
90
|
+
if (!value.asset.includes(`_${value.architecture}.`)) {
|
|
91
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["asset"], message: "Moltnet asset architecture must match identity architecture" });
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
const moltnetReleaseIdentitySchema = z.union([
|
|
95
|
+
publishedMoltnetReleaseIdentitySchema,
|
|
96
|
+
localMoltnetReleaseIdentitySchema
|
|
97
|
+
]);
|
|
71
98
|
const organizationHandoffReceiptSchema = z.object({
|
|
72
99
|
binding_digest: z.string().regex(/^sha256:[a-f0-9]{64}$/u),
|
|
73
100
|
deployment_handle: z.string().regex(/^sf-oh1-[a-f0-9]{64}$/u),
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
export declare const WORKSPACE_RESOURCE_MANIFEST_VERSION: "spawnfile.workspace-resource-manifest.v1";
|
|
2
|
+
export declare const WORKSPACE_RESOURCE_MIGRATION_VERSION: "spawnfile.workspace-resource-migration.v1";
|
|
3
|
+
export interface WorkspaceResourceManifestFile {
|
|
4
|
+
gid: number;
|
|
5
|
+
mode: number;
|
|
6
|
+
path: string;
|
|
7
|
+
sha256: `sha256:${string}`;
|
|
8
|
+
size: number;
|
|
9
|
+
uid: number;
|
|
10
|
+
}
|
|
11
|
+
export interface WorkspaceResourceManifestDirectory {
|
|
12
|
+
gid: number;
|
|
13
|
+
mode: number;
|
|
14
|
+
path: string;
|
|
15
|
+
uid: number;
|
|
16
|
+
}
|
|
17
|
+
export interface WorkspaceResourceManifest {
|
|
18
|
+
version: typeof WORKSPACE_RESOURCE_MANIFEST_VERSION;
|
|
19
|
+
root: {
|
|
20
|
+
gid: number;
|
|
21
|
+
mode: number;
|
|
22
|
+
uid: number;
|
|
23
|
+
};
|
|
24
|
+
directories: WorkspaceResourceManifestDirectory[];
|
|
25
|
+
files: WorkspaceResourceManifestFile[];
|
|
26
|
+
}
|
|
27
|
+
export interface WorkspaceResourceMigrationReceipt {
|
|
28
|
+
version: typeof WORKSPACE_RESOURCE_MIGRATION_VERSION;
|
|
29
|
+
active_path: string;
|
|
30
|
+
destination_path: string;
|
|
31
|
+
manifest_sha256: `sha256:${string}`;
|
|
32
|
+
rollback: boolean;
|
|
33
|
+
source_path: string;
|
|
34
|
+
source_retained: true;
|
|
35
|
+
status: "activated" | "rolled_back";
|
|
36
|
+
}
|
|
37
|
+
export interface WorkspaceResourceMigrationHooks {
|
|
38
|
+
beforeActivation?: (destinationPath: string) => Promise<void>;
|
|
39
|
+
afterActivation?: (destinationPath: string) => Promise<void>;
|
|
40
|
+
afterCopy?: (temporaryPath: string) => Promise<void>;
|
|
41
|
+
activate?: (temporaryPath: string, destinationPath: string) => Promise<void>;
|
|
42
|
+
copy?: (sourcePath: string, temporaryPath: string) => Promise<void>;
|
|
43
|
+
freeBytes?: (parentPath: string) => Promise<bigint>;
|
|
44
|
+
withSourceWriteFence?: <T>(operation: () => Promise<T>) => Promise<T>;
|
|
45
|
+
}
|
|
46
|
+
export interface WorkspaceResourceMigrationOptions {
|
|
47
|
+
destinationPath: string;
|
|
48
|
+
hooks?: WorkspaceResourceMigrationHooks;
|
|
49
|
+
manifestPath: string;
|
|
50
|
+
resolvedIdentity: string;
|
|
51
|
+
sourceQuiesced?: boolean;
|
|
52
|
+
sourcePath: string;
|
|
53
|
+
}
|
|
54
|
+
export declare const migrateWorkspaceResource: (options: WorkspaceResourceMigrationOptions) => Promise<WorkspaceResourceMigrationReceipt>;
|
|
55
|
+
export declare const buildWorkspaceResourceManifest: (sourcePath: string) => Promise<WorkspaceResourceManifest>;
|