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.
Files changed (546) hide show
  1. package/README.md +60 -159
  2. package/dist/audit/checksShared.d.ts +1 -1
  3. package/dist/auth/importers.d.ts +10 -0
  4. package/dist/auth/importers.js +29 -4
  5. package/dist/auth/index.d.ts +2 -0
  6. package/dist/auth/index.js +1 -0
  7. package/dist/auth/paths.d.ts +1 -1
  8. package/dist/auth/profileStore.js +9 -9
  9. package/dist/auth/targetSecretSourceFsIdentity.d.ts +40 -0
  10. package/dist/auth/targetSecretSourceFsIdentity.js +42 -0
  11. package/dist/auth/targetSecretSourceFsPublish.d.ts +2 -0
  12. package/dist/auth/targetSecretSourceFsPublish.js +3 -1
  13. package/dist/auth/targetSecretSourceFsPublishImmutable.d.ts +2 -1
  14. package/dist/auth/targetSecretSourceFsPublishImmutable.js +104 -71
  15. package/dist/auth/targetSecretSourceFsRead.js +5 -14
  16. package/dist/auth/trainingAuth.d.ts +21 -0
  17. package/dist/auth/trainingAuth.js +86 -0
  18. package/dist/auth/types.d.ts +1 -1
  19. package/dist/cli/authCommands.d.ts +1 -1
  20. package/dist/cli/authCommands.js +9 -0
  21. package/dist/cli/canaryCutoverCommand.d.ts +2 -0
  22. package/dist/cli/canaryCutoverCommand.js +30 -0
  23. package/dist/cli/capabilitiesCommand.d.ts +3 -0
  24. package/dist/cli/capabilitiesCommand.js +12 -0
  25. package/dist/cli/capabilitiesReceipt.d.ts +56 -0
  26. package/dist/cli/capabilitiesReceipt.js +56 -0
  27. package/dist/cli/compileBuildCommands.js +13 -0
  28. package/dist/cli/composedLifecycleContractSet.d.ts +21 -0
  29. package/dist/cli/composedLifecycleContractSet.js +204 -0
  30. package/dist/cli/devCommands.js +2 -0
  31. package/dist/cli/downCommand.js +19 -8
  32. package/dist/cli/evidenceExportHelperCommand.d.ts +13 -0
  33. package/dist/cli/evidenceExportHelperCommand.js +51 -0
  34. package/dist/cli/index.js +12 -3
  35. package/dist/cli/lifecycleMachine.d.ts +7 -1
  36. package/dist/cli/lifecycleMachine.js +2 -2
  37. package/dist/cli/paideiaDelegation.d.ts +17 -0
  38. package/dist/cli/paideiaDelegation.js +210 -0
  39. package/dist/cli/paideiaSupervisor.d.ts +17 -0
  40. package/dist/cli/paideiaSupervisor.js +48 -0
  41. package/dist/cli/productStateCloneCommand.d.ts +2 -0
  42. package/dist/cli/productStateCloneCommand.js +34 -0
  43. package/dist/cli/runCli.d.ts +13 -3
  44. package/dist/cli/runCli.js +37 -9
  45. package/dist/cli/targetCommands.d.ts +4 -7
  46. package/dist/cli/targetCommands.js +16 -46
  47. package/dist/cli/targetConfigPreparedPlan.d.ts +3 -0
  48. package/dist/cli/targetConfigPreparedPlan.js +74 -0
  49. package/dist/cli/targetConfigResolver.d.ts +3 -0
  50. package/dist/cli/targetConfigResolver.js +111 -0
  51. package/dist/cli/targetConfigResolverCommand.d.ts +6 -0
  52. package/dist/cli/targetConfigResolverCommand.js +43 -0
  53. package/dist/cli/targetConfigResolverContracts.d.ts +56 -0
  54. package/dist/cli/targetConfigResolverContracts.js +30 -0
  55. package/dist/cli/targetConfigResolverDocker.d.ts +4 -0
  56. package/dist/cli/targetConfigResolverDocker.js +47 -0
  57. package/dist/cli/targetConfigResolverValidation.d.ts +10 -0
  58. package/dist/cli/targetConfigResolverValidation.js +94 -0
  59. package/dist/cli/targetDefaultAuthorities.d.ts +2 -0
  60. package/dist/cli/targetDefaultAuthorities.js +3 -0
  61. package/dist/cli/targetDefaultConfig.d.ts +7 -0
  62. package/dist/cli/targetDefaultConfig.js +22 -5
  63. package/dist/cli/targetDefaultConfigStdin.js +7 -1
  64. package/dist/cli/targetDefaultHandlerFactory.js +23 -2
  65. package/dist/cli/targetDefaultHandlers.d.ts +2 -2
  66. package/dist/cli/targetProductionCommands.d.ts +5 -0
  67. package/dist/cli/targetProductionCommands.js +45 -0
  68. package/dist/cli/trainCommand.d.ts +3 -0
  69. package/dist/cli/trainCommand.js +61 -0
  70. package/dist/cli/upCommand.js +35 -6
  71. package/dist/cli/upLifecycleRecovery.d.ts +2 -2
  72. package/dist/cli/upLifecycleRecovery.js +188 -44
  73. package/dist/cli/usageCommand.d.ts +40 -0
  74. package/dist/cli/usageCommand.js +284 -0
  75. package/dist/cli/usageCommandLive.d.ts +84 -0
  76. package/dist/cli/usageCommandLive.js +95 -0
  77. package/dist/cli/usageDeploymentSource.d.ts +9 -0
  78. package/dist/cli/usageDeploymentSource.js +22 -0
  79. package/dist/cli/workspaceResourceMigrationCommand.d.ts +8 -0
  80. package/dist/cli/workspaceResourceMigrationCommand.js +36 -0
  81. package/dist/compiler/buildCompilePlanTeams.d.ts +1 -1
  82. package/dist/compiler/buildCompilePlanTeams.js +6 -1
  83. package/dist/compiler/compilePlanHelpers.js +3 -0
  84. package/dist/compiler/compileProject.d.ts +2 -0
  85. package/dist/compiler/compileProject.js +5 -1
  86. package/dist/compiler/compileProjectSupport.js +9 -0
  87. package/dist/compiler/containerArtifacts.d.ts +3 -1
  88. package/dist/compiler/containerArtifacts.js +92 -40
  89. package/dist/compiler/containerArtifactsPlans.d.ts +1 -1
  90. package/dist/compiler/containerArtifactsPlans.js +24 -7
  91. package/dist/compiler/containerArtifactsRender.d.ts +2 -1
  92. package/dist/compiler/containerArtifactsRender.js +91 -58
  93. package/dist/compiler/containerArtifactsTypes.d.ts +8 -0
  94. package/dist/compiler/containerBackedMountRender.d.ts +56 -0
  95. package/dist/compiler/containerBackedMountRender.js +101 -0
  96. package/dist/compiler/containerDaimonBrokerRender.d.ts +112 -0
  97. package/dist/compiler/containerDaimonBrokerRender.js +191 -0
  98. package/dist/compiler/containerDaimonGrokWorkerProvisioning.d.ts +38 -0
  99. package/dist/compiler/containerDaimonGrokWorkerProvisioning.js +108 -0
  100. package/dist/compiler/containerDaimonGrokWorkerRender.d.ts +172 -0
  101. package/dist/compiler/containerDaimonGrokWorkerRender.js +268 -0
  102. package/dist/compiler/containerDaimonOwnershipGuardRender.d.ts +12 -0
  103. package/dist/compiler/containerDaimonOwnershipGuardRender.js +191 -0
  104. package/dist/compiler/containerDaimonUidEntrypointRender.d.ts +24 -0
  105. package/dist/compiler/containerDaimonUidEntrypointRender.js +297 -0
  106. package/dist/compiler/containerEntrypointRender.d.ts +7 -0
  107. package/dist/compiler/containerEntrypointRender.js +28 -22
  108. package/dist/compiler/containerPersistentMounts.d.ts +30 -0
  109. package/dist/compiler/containerPersistentMounts.js +66 -0
  110. package/dist/compiler/containerReadinessPaths.d.ts +1 -0
  111. package/dist/compiler/containerReadinessPaths.js +1 -0
  112. package/dist/compiler/containerRuntimeLinkMaterializer.d.ts +2 -0
  113. package/dist/compiler/containerRuntimeLinkMaterializer.js +12 -0
  114. package/dist/compiler/containerRuntimeReadinessRender.d.ts +7 -0
  115. package/dist/compiler/containerRuntimeReadinessRender.js +40 -0
  116. package/dist/compiler/containerStateOwnershipRender.d.ts +4 -0
  117. package/dist/compiler/containerStateOwnershipRender.js +75 -0
  118. package/dist/compiler/containerTargetResources.d.ts +22 -1
  119. package/dist/compiler/containerTargetResources.js +94 -2
  120. package/dist/compiler/containerVolumeBootstrap.d.ts +3 -0
  121. package/dist/compiler/containerVolumeBootstrap.js +3 -0
  122. package/dist/compiler/containerWorkspaceResourceRender.js +49 -1
  123. package/dist/compiler/daimonTelemetryArtifacts.d.ts +2 -2
  124. package/dist/compiler/daimonTelemetryArtifacts.js +5 -10
  125. package/dist/compiler/deploymentLineage.d.ts +40 -0
  126. package/dist/compiler/deploymentLineage.js +50 -0
  127. package/dist/compiler/index.d.ts +3 -0
  128. package/dist/compiler/index.js +3 -0
  129. package/dist/compiler/initProject.d.ts +2 -0
  130. package/dist/compiler/initProject.js +39 -1
  131. package/dist/compiler/localMoltnetAuthority.d.ts +64 -0
  132. package/dist/compiler/localMoltnetAuthority.js +177 -0
  133. package/dist/compiler/memoryArtifacts.d.ts +1 -1
  134. package/dist/compiler/memoryArtifacts.js +108 -32
  135. package/dist/compiler/modelEnv.d.ts +5 -0
  136. package/dist/compiler/modelEnv.js +8 -2
  137. package/dist/compiler/moltnetArtifactPaths.d.ts +17 -12
  138. package/dist/compiler/moltnetArtifactPaths.js +17 -15
  139. package/dist/compiler/moltnetArtifactTypes.d.ts +10 -0
  140. package/dist/compiler/moltnetArtifacts.d.ts +1 -1
  141. package/dist/compiler/moltnetArtifacts.js +52 -12
  142. package/dist/compiler/moltnetBinaries.d.ts +16 -4
  143. package/dist/compiler/moltnetBinaries.js +46 -6
  144. package/dist/compiler/moltnetClientConfig.js +1 -1
  145. package/dist/compiler/moltnetConfigLowering.d.ts +3 -1
  146. package/dist/compiler/moltnetConfigLowering.js +30 -6
  147. package/dist/compiler/moltnetNodeConfig.js +1 -1
  148. package/dist/compiler/moltnetReleaseAuthority.d.ts +24 -1
  149. package/dist/compiler/moltnetReleaseAuthority.js +33 -4
  150. package/dist/compiler/moltnetRepresentativeResolution.d.ts +1 -1
  151. package/dist/compiler/moltnetRepresentativeResolution.js +2 -2
  152. package/dist/compiler/moltnetResolution.js +9 -15
  153. package/dist/compiler/moltnetRoomMemberships.js +20 -5
  154. package/dist/compiler/moltnetRoomPolicyCompatibility.d.ts +1 -1
  155. package/dist/compiler/moltnetRoomPolicyCompatibility.js +3 -1
  156. package/dist/compiler/moltnetRuntimeConfig.d.ts +1 -1
  157. package/dist/compiler/moltnetRuntimeConfig.js +22 -2
  158. package/dist/compiler/moltnetServerPlans.js +19 -0
  159. package/dist/compiler/organizationExternalParticipants.d.ts +3 -0
  160. package/dist/compiler/organizationExternalParticipants.js +176 -0
  161. package/dist/compiler/organizationIdentity.d.ts +3 -9
  162. package/dist/compiler/organizationIdentity.js +37 -270
  163. package/dist/compiler/organizationIdentityGraph.d.ts +15 -0
  164. package/dist/compiler/organizationIdentityGraph.js +115 -0
  165. package/dist/compiler/organizationReadyEvidence.d.ts +8 -0
  166. package/dist/compiler/organizationReadyEvidence.js +23 -3
  167. package/dist/compiler/runProject.d.ts +4 -2
  168. package/dist/compiler/runProject.js +32 -6
  169. package/dist/compiler/runProjectAuth.d.ts +3 -1
  170. package/dist/compiler/runProjectAuth.js +19 -3
  171. package/dist/compiler/runProjectDaimonCodexDocker.d.ts +3 -0
  172. package/dist/compiler/runProjectDaimonCodexDocker.js +36 -0
  173. package/dist/compiler/runProjectDocker.d.ts +8 -4
  174. package/dist/compiler/runProjectDocker.js +43 -18
  175. package/dist/compiler/runProjectDockerDaimonGuards.d.ts +15 -0
  176. package/dist/compiler/runProjectDockerDaimonGuards.js +122 -0
  177. package/dist/compiler/runProjectDockerReservation.d.ts +3 -0
  178. package/dist/compiler/runProjectDockerReservation.js +118 -0
  179. package/dist/compiler/runProjectLifecycle.js +1 -1
  180. package/dist/compiler/training/broker/declaration.d.ts +45 -0
  181. package/dist/compiler/training/broker/declaration.js +55 -0
  182. package/dist/compiler/training/broker/entrypoint.d.ts +39 -0
  183. package/dist/compiler/training/broker/entrypoint.js +111 -0
  184. package/dist/compiler/training/broker/index.d.ts +10 -0
  185. package/dist/compiler/training/broker/index.js +10 -0
  186. package/dist/compiler/training/broker/main.d.ts +2 -0
  187. package/dist/compiler/training/broker/main.js +14 -0
  188. package/dist/compiler/training/broker/paths.d.ts +196 -0
  189. package/dist/compiler/training/broker/paths.js +241 -0
  190. package/dist/compiler/training/broker/processes.d.ts +42 -0
  191. package/dist/compiler/training/broker/processes.js +99 -0
  192. package/dist/compiler/training/broker/projection.d.ts +51 -0
  193. package/dist/compiler/training/broker/projection.js +76 -0
  194. package/dist/compiler/training/broker/provisioning.d.ts +87 -0
  195. package/dist/compiler/training/broker/provisioning.js +213 -0
  196. package/dist/compiler/training/broker/receipt.d.ts +77 -0
  197. package/dist/compiler/training/broker/receipt.js +110 -0
  198. package/dist/compiler/training/broker/registration.d.ts +41 -0
  199. package/dist/compiler/training/broker/registration.js +102 -0
  200. package/dist/compiler/training/broker/runtime.d.ts +25 -0
  201. package/dist/compiler/training/broker/runtime.js +173 -0
  202. package/dist/compiler/training/broker/seccompRoutes.d.ts +31 -0
  203. package/dist/compiler/training/broker/seccompRoutes.js +36 -0
  204. package/dist/compiler/training/broker/supervisor.d.ts +109 -0
  205. package/dist/compiler/training/broker/supervisor.js +173 -0
  206. package/dist/compiler/training/container/contract.d.ts +31 -0
  207. package/dist/compiler/training/container/contract.js +33 -0
  208. package/dist/compiler/training/container/index.d.ts +4 -0
  209. package/dist/compiler/training/container/index.js +2 -0
  210. package/dist/compiler/training/container/launch.d.ts +18 -0
  211. package/dist/compiler/training/container/launch.js +173 -0
  212. package/dist/compiler/training/container/prepare.d.ts +8 -0
  213. package/dist/compiler/training/container/prepare.js +80 -0
  214. package/dist/compiler/training/container/process.d.ts +14 -0
  215. package/dist/compiler/training/container/process.js +70 -0
  216. package/dist/compiler/training/container/security.d.ts +36 -0
  217. package/dist/compiler/training/container/security.js +58 -0
  218. package/dist/compiler/training/context.d.ts +7 -0
  219. package/dist/compiler/training/context.js +93 -0
  220. package/dist/compiler/training/contract.d.ts +142 -0
  221. package/dist/compiler/training/contract.js +34 -0
  222. package/dist/compiler/training/index.d.ts +4 -0
  223. package/dist/compiler/training/index.js +3 -0
  224. package/dist/compiler/training/preparation/assets/Dockerfile +98 -0
  225. package/dist/compiler/training/preparation/assets/package-lock.json +3787 -0
  226. package/dist/compiler/training/preparation/broker.d.ts +21 -0
  227. package/dist/compiler/training/preparation/broker.js +43 -0
  228. package/dist/compiler/training/preparation/contextModes.d.ts +12 -0
  229. package/dist/compiler/training/preparation/contextModes.js +38 -0
  230. package/dist/compiler/training/preparation/contract.d.ts +182 -0
  231. package/dist/compiler/training/preparation/contract.js +94 -0
  232. package/dist/compiler/training/preparation/copyAssets.d.ts +1 -0
  233. package/dist/compiler/training/preparation/copyAssets.js +8 -0
  234. package/dist/compiler/training/preparation/daimonParent.d.ts +42 -0
  235. package/dist/compiler/training/preparation/daimonParent.js +114 -0
  236. package/dist/compiler/training/preparation/files.d.ts +25 -0
  237. package/dist/compiler/training/preparation/files.js +85 -0
  238. package/dist/compiler/training/preparation/image.d.ts +28 -0
  239. package/dist/compiler/training/preparation/image.js +102 -0
  240. package/dist/compiler/training/preparation/index.d.ts +3 -0
  241. package/dist/compiler/training/preparation/index.js +2 -0
  242. package/dist/compiler/training/preparation/inputs.d.ts +23 -0
  243. package/dist/compiler/training/preparation/inputs.js +93 -0
  244. package/dist/compiler/training/preparation/prepare.d.ts +33 -0
  245. package/dist/compiler/training/preparation/prepare.js +186 -0
  246. package/dist/compiler/training/preparation/scratch.d.ts +19 -0
  247. package/dist/compiler/training/preparation/scratch.js +48 -0
  248. package/dist/compiler/training/repair/compatibility.d.ts +11 -0
  249. package/dist/compiler/training/repair/compatibility.js +34 -0
  250. package/dist/compiler/training/repair/contract.d.ts +506 -0
  251. package/dist/compiler/training/repair/contract.js +31 -0
  252. package/dist/compiler/training/repair/index.d.ts +3 -0
  253. package/dist/compiler/training/repair/index.js +3 -0
  254. package/dist/compiler/training/repair/prepare.d.ts +230 -0
  255. package/dist/compiler/training/repair/prepare.js +74 -0
  256. package/dist/compiler/training/repair/witness.d.ts +203 -0
  257. package/dist/compiler/training/repair/witness.js +42 -0
  258. package/dist/compiler/types.d.ts +2 -0
  259. package/dist/compiler/upProject.d.ts +26 -1
  260. package/dist/compiler/upProject.js +117 -178
  261. package/dist/compiler/upProjectHandoff.d.ts +62 -0
  262. package/dist/compiler/upProjectHandoff.js +204 -0
  263. package/dist/compiler/upReceipt.js +49 -4
  264. package/dist/compiler/updateProjectModels.js +1 -0
  265. package/dist/compiler/view/types.d.ts +1 -1
  266. package/dist/compiler/workspaceBundleArtifacts.d.ts +3 -0
  267. package/dist/compiler/workspaceBundleArtifacts.js +106 -0
  268. package/dist/compiler/workspaceResources.d.ts +4 -1
  269. package/dist/compiler/workspaceResources.js +12 -7
  270. package/dist/deployment/artifactsExportPlan.js +51 -1
  271. package/dist/deployment/canaryCutover.d.ts +42 -0
  272. package/dist/deployment/canaryCutover.js +140 -0
  273. package/dist/deployment/candidateDiagnostics.d.ts +15 -0
  274. package/dist/deployment/candidateDiagnostics.js +90 -0
  275. package/dist/deployment/dockerLogs.js +4 -1
  276. package/dist/deployment/dockerManager.js +9 -3
  277. package/dist/deployment/dockerProbeGateway.d.ts +17 -0
  278. package/dist/deployment/dockerProbeGateway.js +17 -2
  279. package/dist/deployment/downDeployment.d.ts +5 -0
  280. package/dist/deployment/downDeployment.js +109 -8
  281. package/dist/deployment/downReceiptTypes.d.ts +17 -2
  282. package/dist/deployment/downReceiptTypes.js +17 -2
  283. package/dist/deployment/index.d.ts +4 -0
  284. package/dist/deployment/index.js +4 -0
  285. package/dist/deployment/lifecycleCompletionContracts.d.ts +66 -0
  286. package/dist/deployment/lifecycleCompletionContracts.js +34 -0
  287. package/dist/deployment/lifecycleCompletionPaths.d.ts +4 -1
  288. package/dist/deployment/lifecycleCompletionPaths.js +3 -0
  289. package/dist/deployment/lifecycleCompletionPublication.d.ts +2 -0
  290. package/dist/deployment/lifecycleCompletionPublication.js +18 -4
  291. package/dist/deployment/lifecycleCompletionStore.d.ts +1 -1
  292. package/dist/deployment/lifecycleCompletionStore.js +7 -7
  293. package/dist/deployment/lifecycleUpRecords.d.ts +11 -0
  294. package/dist/deployment/lifecycleUpRecords.js +127 -0
  295. package/dist/deployment/native/AGENTS.md +11 -0
  296. package/dist/deployment/native/rename-noreplace-arm64 +0 -0
  297. package/dist/deployment/native/rename-noreplace-arm64.provenance.json +1 -0
  298. package/dist/deployment/native/rename-noreplace-x64 +0 -0
  299. package/dist/deployment/native/rename-noreplace-x64.provenance.json +1 -0
  300. package/dist/deployment/noReplaceActivation.d.ts +17 -0
  301. package/dist/deployment/noReplaceActivation.js +50 -0
  302. package/dist/deployment/organizationHandoffAuthorityFsBudget.d.ts +110 -0
  303. package/dist/deployment/organizationHandoffAuthorityFsBudget.js +156 -0
  304. package/dist/deployment/organizationHandoffAuthorityFsClient.js +82 -27
  305. package/dist/deployment/organizationHandoffAuthorityFsElection.d.ts +21 -0
  306. package/dist/deployment/organizationHandoffAuthorityFsElection.js +57 -0
  307. package/dist/deployment/organizationHandoffAuthorityFsWorker.js +254 -108
  308. package/dist/deployment/organizationHandoffAuthorityFsWorkerStall.fixture.d.ts +1 -0
  309. package/dist/deployment/organizationHandoffAuthorityFsWorkerStall.fixture.js +16 -0
  310. package/dist/deployment/organizationHandoffAuthorityStore.js +14 -7
  311. package/dist/deployment/organizationHandoffAuthorityTypes.d.ts +2 -2
  312. package/dist/deployment/organizationHandoffAuthorityTypes.js +2 -1
  313. package/dist/deployment/organizationReady.d.ts +2 -0
  314. package/dist/deployment/organizationReady.js +36 -4
  315. package/dist/deployment/productStateClone.d.ts +43 -0
  316. package/dist/deployment/productStateClone.js +319 -0
  317. package/dist/deployment/upLifecycleRecoveryState.d.ts +23 -0
  318. package/dist/deployment/upLifecycleRecoveryState.js +12 -0
  319. package/dist/deployment/upReceiptTypes.d.ts +32 -6
  320. package/dist/deployment/upReceiptTypes.js +29 -2
  321. package/dist/deployment/workspaceResourceMigration.d.ts +55 -0
  322. package/dist/deployment/workspaceResourceMigration.js +315 -0
  323. package/dist/dev/project.d.ts +7 -0
  324. package/dist/dev/project.js +9 -0
  325. package/dist/distribution/consumeImage.d.ts +2 -0
  326. package/dist/distribution/consumeImage.js +98 -73
  327. package/dist/distribution/consumeImageDaimonDocker.d.ts +3 -0
  328. package/dist/distribution/consumeImageDaimonDocker.js +45 -0
  329. package/dist/distribution/consumeImageLifecycle.d.ts +17 -0
  330. package/dist/distribution/consumeImageLifecycle.js +231 -0
  331. package/dist/distribution/consumeImageSupport.d.ts +12 -0
  332. package/dist/distribution/consumeImageSupport.js +15 -0
  333. package/dist/distribution/distributionReportSchema.d.ts +11 -1
  334. package/dist/distribution/distributionReportSchema.js +15 -2
  335. package/dist/distribution/dockerRunner.d.ts +6 -1
  336. package/dist/distribution/dockerRunner.js +31 -4
  337. package/dist/distribution/imageRuntimeAuth.d.ts +9 -1
  338. package/dist/distribution/imageRuntimeAuth.js +70 -1
  339. package/dist/distribution/index.d.ts +1 -1
  340. package/dist/distribution/index.js +1 -1
  341. package/dist/distribution/preflight.js +5 -1
  342. package/dist/distribution/types.d.ts +14 -1
  343. package/dist/distribution/types.js +3 -0
  344. package/dist/evidenceExportHelper/boundedExecutor.d.ts +3 -0
  345. package/dist/evidenceExportHelper/boundedExecutor.js +33 -0
  346. package/dist/evidenceExportHelper/helperProgram.mjs +156 -0
  347. package/dist/evidenceExportHelper/index.d.ts +4 -0
  348. package/dist/evidenceExportHelper/index.js +4 -0
  349. package/dist/evidenceExportHelper/preparedAuthority.d.ts +64 -0
  350. package/dist/evidenceExportHelper/preparedAuthority.js +228 -0
  351. package/dist/evidenceExportHelper/preparedBuilder.d.ts +10 -0
  352. package/dist/evidenceExportHelper/preparedBuilder.js +183 -0
  353. package/dist/evidenceExportHelper/preparedBuilderTypes.d.ts +19 -0
  354. package/dist/evidenceExportHelper/preparedBuilderTypes.js +1 -0
  355. package/dist/evidenceExportHelper/recipe.d.ts +7 -0
  356. package/dist/evidenceExportHelper/recipe.js +83 -0
  357. package/dist/filesystem/io.d.ts +2 -0
  358. package/dist/filesystem/io.js +16 -1
  359. package/dist/manifest/executionSchemas.d.ts +27 -0
  360. package/dist/manifest/executionSchemas.js +21 -2
  361. package/dist/manifest/mcpSchemas.d.ts +1 -0
  362. package/dist/manifest/mcpSchemas.js +3 -0
  363. package/dist/manifest/renderSpawnfileNetworks.js +11 -0
  364. package/dist/manifest/renderSpawnfileWorkspace.js +5 -0
  365. package/dist/manifest/scheduleSchemas.d.ts +3 -1
  366. package/dist/manifest/scheduleSchemas.js +91 -5
  367. package/dist/manifest/schemas.d.ts +237 -12
  368. package/dist/manifest/schemas.js +5 -2
  369. package/dist/manifest/teamNetworkAccessSchemas.d.ts +5 -1
  370. package/dist/manifest/teamNetworkAccessSchemas.js +11 -0
  371. package/dist/manifest/teamNetworkAuthSchemas.d.ts +1 -1
  372. package/dist/manifest/teamNetworkSchemas.d.ts +17 -3
  373. package/dist/manifest/teamNetworkSchemas.js +19 -1
  374. package/dist/manifest/teamNetworkServerSchemas.d.ts +8 -3
  375. package/dist/manifest/teamNetworkServerSchemas.js +18 -2
  376. package/dist/manifest/workspaceSchemas.d.ts +16 -0
  377. package/dist/manifest/workspaceSchemas.js +11 -0
  378. package/dist/report/types.d.ts +34 -4
  379. package/dist/runtime/common.d.ts +28 -1
  380. package/dist/runtime/common.js +33 -3
  381. package/dist/runtime/container.js +49 -33
  382. package/dist/runtime/daimon/adapter.d.ts +14 -0
  383. package/dist/runtime/daimon/adapter.js +243 -0
  384. package/dist/runtime/daimon/attention.d.ts +8 -0
  385. package/dist/runtime/daimon/attention.js +32 -0
  386. package/dist/runtime/daimon/config.d.ts +25 -0
  387. package/dist/runtime/daimon/config.js +272 -0
  388. package/dist/runtime/daimon/contractManifest.d.ts +295 -0
  389. package/dist/runtime/daimon/contractManifest.js +319 -0
  390. package/dist/runtime/daimon/grokModel.d.ts +19 -0
  391. package/dist/runtime/daimon/grokModel.js +33 -0
  392. package/dist/runtime/daimon/grokWorkerConfigBytes.d.ts +26 -0
  393. package/dist/runtime/daimon/grokWorkerConfigBytes.js +36 -0
  394. package/dist/runtime/daimon/grokWorkerContract.d.ts +22 -0
  395. package/dist/runtime/daimon/grokWorkerContract.js +48 -0
  396. package/dist/runtime/daimon/memory.d.ts +57 -0
  397. package/dist/runtime/daimon/memory.js +125 -0
  398. package/dist/runtime/daimon/runAuth.d.ts +51 -0
  399. package/dist/runtime/daimon/runAuth.js +279 -0
  400. package/dist/runtime/daimon/runtimeIdentity.d.ts +22 -0
  401. package/dist/runtime/daimon/runtimeIdentity.js +22 -0
  402. package/dist/runtime/daimon/scheduleAuthority.d.ts +3 -0
  403. package/dist/runtime/daimon/scheduleAuthority.js +17 -0
  404. package/dist/runtime/index.d.ts +4 -0
  405. package/dist/runtime/index.js +4 -0
  406. package/dist/runtime/install.d.ts +3 -0
  407. package/dist/runtime/install.js +3 -0
  408. package/dist/runtime/localDaimonAuthority.d.ts +11 -0
  409. package/dist/runtime/localDaimonAuthority.js +77 -0
  410. package/dist/runtime/mnemeMcp.d.ts +13 -0
  411. package/dist/runtime/mnemeMcp.js +26 -0
  412. package/dist/runtime/openclaw/adapter.js +2 -2
  413. package/dist/runtime/pi/adapter.d.ts +0 -1
  414. package/dist/runtime/pi/adapter.js +2 -6
  415. package/dist/runtime/pi/appCliSource.js +1 -1
  416. package/dist/runtime/pi/appScheduleSource.js +6 -2
  417. package/dist/runtime/pi/appTemplateTypes.d.ts +1 -1
  418. package/dist/runtime/picoclaw/adapter.js +2 -2
  419. package/dist/runtime/registry.d.ts +3 -0
  420. package/dist/runtime/registry.js +19 -2
  421. package/dist/runtime/scheduleUtils.d.ts +1 -0
  422. package/dist/runtime/scheduleUtils.js +5 -1
  423. package/dist/runtime/types.d.ts +25 -0
  424. package/dist/runtime/usageLedger.d.ts +158 -0
  425. package/dist/runtime/usageLedger.js +269 -0
  426. package/dist/runtime/usageLedgerRead.d.ts +48 -0
  427. package/dist/runtime/usageLedgerRead.js +102 -0
  428. package/dist/runtime/usageRequestLedger.d.ts +42 -0
  429. package/dist/runtime/usageRequestLedger.js +72 -0
  430. package/dist/shared/daimonCodexDocker.d.ts +32 -0
  431. package/dist/shared/daimonCodexDocker.js +120 -0
  432. package/dist/shared/daimonGrokSeccompProfile.d.ts +10 -0
  433. package/dist/shared/daimonGrokSeccompProfile.js +11 -0
  434. package/dist/shared/index.d.ts +2 -0
  435. package/dist/shared/index.js +2 -0
  436. package/dist/shared/types.d.ts +1 -1
  437. package/dist/shared/volumeNames.d.ts +6 -0
  438. package/dist/shared/volumeNames.js +14 -0
  439. package/dist/target/dockerArtifactsProvider.js +34 -7
  440. package/dist/target/dockerBaseImage.d.ts +2 -0
  441. package/dist/target/dockerBaseImage.js +11 -0
  442. package/dist/target/dockerCommandExecutor.d.ts +11 -0
  443. package/dist/target/dockerCommandExecutor.js +53 -2
  444. package/dist/target/dockerCommandExecutorCore.d.ts +2 -1
  445. package/dist/target/dockerCommandExecutorCore.js +4 -2
  446. package/dist/target/dockerPublicArtifactSnapshot.d.ts +3 -3
  447. package/dist/target/dockerPublicArtifactSnapshot.js +17 -33
  448. package/dist/target/dockerTarget.d.ts +1 -0
  449. package/dist/target/dockerTargetBinding.d.ts +1 -2
  450. package/dist/target/dockerTargetBinding.js +2 -3
  451. package/dist/target/dockerTargetExecFile.d.ts +19 -0
  452. package/dist/target/dockerTargetExecFile.js +194 -0
  453. package/dist/target/dockerWorldServiceProvider.d.ts +4 -0
  454. package/dist/target/dockerWorldServiceProvider.js +13 -1
  455. package/dist/target/evidenceExport.d.ts +3 -1
  456. package/dist/target/evidenceExport.js +12 -3
  457. package/dist/target/evidenceExportOperationsTestKit.js +3 -3
  458. package/dist/target/evidenceExportProvider.d.ts +2 -0
  459. package/dist/target/evidenceExportProvider.js +15 -5
  460. package/dist/target/publicArtifactSnapshot.d.ts +31 -0
  461. package/dist/target/publicArtifactSnapshot.js +37 -3
  462. package/examples/README.md +45 -0
  463. package/examples/agent-with-subagents/AGENTS.md +3 -0
  464. package/examples/agent-with-subagents/Spawnfile +30 -0
  465. package/examples/agent-with-subagents/subagents/critic/AGENTS.md +3 -0
  466. package/examples/agent-with-subagents/subagents/critic/Spawnfile +15 -0
  467. package/examples/agent-with-subagents/subagents/researcher/AGENTS.md +3 -0
  468. package/examples/agent-with-subagents/subagents/researcher/Spawnfile +17 -0
  469. package/examples/daimon-org/Spawnfile +68 -0
  470. package/examples/daimon-org/TEAM.md +4 -0
  471. package/examples/daimon-org/agents/mapper/AGENTS.md +4 -0
  472. package/examples/daimon-org/agents/mapper/Spawnfile +37 -0
  473. package/examples/daimon-org/shared/skills/file-note/SKILL.md +9 -0
  474. package/examples/daimon-org/teams/review/Spawnfile +53 -0
  475. package/examples/daimon-org/teams/review/agents/reviewer/AGENTS.md +4 -0
  476. package/examples/daimon-org/teams/review/agents/reviewer/Spawnfile +37 -0
  477. package/examples/daimon-public-host/AGENTS.md +3 -0
  478. package/examples/daimon-public-host/Spawnfile +21 -0
  479. package/examples/distribution-org/Spawnfile +43 -0
  480. package/examples/distribution-org/TEAM.md +4 -0
  481. package/examples/distribution-org/agents/coordinator/AGENTS.md +1 -0
  482. package/examples/distribution-org/agents/coordinator/Spawnfile +20 -0
  483. package/examples/distribution-org/agents/researcher/AGENTS.md +1 -0
  484. package/examples/distribution-org/agents/researcher/Spawnfile +20 -0
  485. package/examples/jungian-daimon-org/Spawnfile +41 -0
  486. package/examples/jungian-daimon-org/TEAM.md +21 -0
  487. package/examples/jungian-daimon-org/teams/luna/Spawnfile +47 -0
  488. package/examples/jungian-daimon-org/teams/luna/TEAM.md +4 -0
  489. package/examples/jungian-daimon-org/teams/luna/agents/animus/AGENTS.md +10 -0
  490. package/examples/jungian-daimon-org/teams/luna/agents/animus/Spawnfile +33 -0
  491. package/examples/jungian-daimon-org/teams/luna/agents/representative/AGENTS.md +21 -0
  492. package/examples/jungian-daimon-org/teams/luna/agents/representative/Spawnfile +30 -0
  493. package/examples/jungian-daimon-org/teams/luna/agents/shadow/AGENTS.md +10 -0
  494. package/examples/jungian-daimon-org/teams/luna/agents/shadow/Spawnfile +33 -0
  495. package/examples/jungian-daimon-org/teams/selene/Spawnfile +47 -0
  496. package/examples/jungian-daimon-org/teams/selene/TEAM.md +4 -0
  497. package/examples/jungian-daimon-org/teams/selene/agents/animus/AGENTS.md +10 -0
  498. package/examples/jungian-daimon-org/teams/selene/agents/animus/Spawnfile +33 -0
  499. package/examples/jungian-daimon-org/teams/selene/agents/representative/AGENTS.md +19 -0
  500. package/examples/jungian-daimon-org/teams/selene/agents/representative/Spawnfile +33 -0
  501. package/examples/jungian-daimon-org/teams/selene/agents/shadow/AGENTS.md +10 -0
  502. package/examples/jungian-daimon-org/teams/selene/agents/shadow/Spawnfile +30 -0
  503. package/examples/mixed-runtime-org/Spawnfile +71 -0
  504. package/examples/mixed-runtime-org/TEAM.md +8 -0
  505. package/examples/mixed-runtime-org/agents/analyst/AGENTS.md +8 -0
  506. package/examples/mixed-runtime-org/agents/analyst/Spawnfile +27 -0
  507. package/examples/mixed-runtime-org/agents/conductor/AGENTS.md +8 -0
  508. package/examples/mixed-runtime-org/agents/conductor/Spawnfile +27 -0
  509. package/examples/mixed-runtime-org/agents/localist/AGENTS.md +7 -0
  510. package/examples/mixed-runtime-org/agents/localist/Spawnfile +50 -0
  511. package/examples/moltnet-team-chat/Spawnfile +43 -0
  512. package/examples/moltnet-team-chat/TEAM.md +5 -0
  513. package/examples/moltnet-team-chat/agents/coordinator/AGENTS.md +9 -0
  514. package/examples/moltnet-team-chat/agents/coordinator/Spawnfile +26 -0
  515. package/examples/moltnet-team-chat/teams/analysis/Spawnfile +23 -0
  516. package/examples/moltnet-team-chat/teams/analysis/TEAM.md +3 -0
  517. package/examples/moltnet-team-chat/teams/analysis/agents/observer/AGENTS.md +5 -0
  518. package/examples/moltnet-team-chat/teams/analysis/agents/observer/Spawnfile +19 -0
  519. package/examples/moltnet-team-chat/teams/analysis/agents/representative/AGENTS.md +5 -0
  520. package/examples/moltnet-team-chat/teams/analysis/agents/representative/Spawnfile +19 -0
  521. package/examples/moltnet-team-chat/teams/field/Spawnfile +41 -0
  522. package/examples/moltnet-team-chat/teams/field/TEAM.md +3 -0
  523. package/examples/moltnet-team-chat/teams/field/agents/observer/AGENTS.md +5 -0
  524. package/examples/moltnet-team-chat/teams/field/agents/observer/Spawnfile +26 -0
  525. package/examples/moltnet-team-chat/teams/field/agents/representative/AGENTS.md +11 -0
  526. package/examples/moltnet-team-chat/teams/field/agents/representative/Spawnfile +26 -0
  527. package/examples/single-agent/AGENTS.md +3 -0
  528. package/examples/single-agent/HEARTBEAT.md +3 -0
  529. package/examples/single-agent/IDENTITY.md +3 -0
  530. package/examples/single-agent/MEMORY.md +3 -0
  531. package/examples/single-agent/SOUL.md +3 -0
  532. package/examples/single-agent/Spawnfile +41 -0
  533. package/examples/single-agent/skills/web_search/SKILL.md +6 -0
  534. package/moltnet-releases.json +5 -4
  535. package/package.json +36 -9
  536. package/runtimes.yaml +5 -2
  537. package/dist/cli/targetWorldClockCrossProcess.test-helper.d.ts +0 -13
  538. package/dist/cli/targetWorldClockCrossProcess.test-helper.js +0 -109
  539. package/dist/deployment/providerRuntimeBoundaryScanner.test-helper.d.ts +0 -8
  540. package/dist/deployment/providerRuntimeBoundaryScanner.test-helper.js +0 -60
  541. package/dist/deployment/simfileFixtureBoundary.test-helper.d.ts +0 -8
  542. package/dist/deployment/simfileFixtureBoundary.test-helper.js +0 -103
  543. package/dist/ownership/simfileRunOperatorInputs.d.ts +0 -103
  544. package/dist/ownership/simfileRunOperatorInputs.js +0 -139
  545. package/dist/target/cleanupRunDocker.test-helper.d.ts +0 -67
  546. package/dist/target/cleanupRunDocker.test-helper.js +0 -238
@@ -5,6 +5,9 @@ import { createWorkspaceResourceCommands, createWorkspaceResourceShellFunctions
5
5
  import { createConfigEnvMaterializationFunction, createConfigEnvWrites } from "./containerConfigEnvRender.js";
6
6
  import { CLI_CREDENTIAL_SECRET_NAME, modelAuthMethodNeedsCliCredential } from "./modelEnv.js";
7
7
  import { createCliCredentialMaterialization, createRecipeEnvAssignments, mergeRecipeEnv, shellQuote } from "./containerEntrypointShell.js";
8
+ import { MOLTNET_READINESS_DIRECTORY } from "./containerReadinessPaths.js";
9
+ import { createRuntimeReadinessWait } from "./containerRuntimeReadinessRender.js";
10
+ import { createBackedMountGuard } from "./containerBackedMountRender.js";
8
11
  const MOLTNET_SERVER_DATA_DIRECTORY = "/var/lib/spawnfile/moltnet/servers";
9
12
  // moltnet reads this path from MOLTNET_CAUSAL_EVENTS_PATH
10
13
  // (internal/app/config_load.go's mergeEnvConfig) and, when set, stamps
@@ -59,28 +62,13 @@ const resolveStartCommand = (plan) => plan.meta.startCommand
59
62
  .map((token) => token
60
63
  .replaceAll("<config-path>", plan.instancePaths.configPath)
61
64
  .replaceAll("<home-path>", plan.instancePaths.homePath ?? "")
65
+ .replaceAll("<instance-root>", plan.instancePaths.instanceRoot ?? "")
62
66
  .replaceAll("<runtime-root>", plan.runtimeRoot)
63
67
  .replaceAll("<workspace-path>", plan.instancePaths.workspacePath)
64
68
  .replaceAll("<port>", plan.port ? String(plan.port) : ""))
65
69
  .filter((token) => token.length > 0);
66
- const createRuntimeReadinessWait = (plan) => {
67
- if (!["openclaw", "pi"].includes(plan.runtimeName) || !plan.port) {
68
- return [];
69
- }
70
- return [
71
- "attempts=0",
72
- `until curl -sf ${shellQuote(`http://127.0.0.1:${plan.port}/healthz`)} >/dev/null; do`,
73
- " attempts=$((attempts + 1))",
74
- ' if [ "$attempts" -ge 180 ]; then',
75
- ` echo ${shellQuote(`Timed out waiting for ${plan.runtimeName} on port ${plan.port}`)} >&2`,
76
- " exit 1",
77
- " fi",
78
- " sleep 1",
79
- "done",
80
- ""
81
- ];
82
- };
83
70
  export const renderEntrypoint = (runtimePlans, requiredSecrets, options = {}) => {
71
+ const usesDaimonRuntime = runtimePlans.some((plan) => plan.runtimeName === "daimon");
84
72
  const cliCredentialMaterialization = createCliCredentialMaterialization(runtimePlans);
85
73
  const renderedRequiredSecrets = [
86
74
  ...new Set([
@@ -91,7 +79,19 @@ export const renderEntrypoint = (runtimePlans, requiredSecrets, options = {}) =>
91
79
  const lines = [
92
80
  "#!/usr/bin/env bash",
93
81
  "set -euo pipefail",
82
+ ...(usesDaimonRuntime ? [
83
+ 'if [ "$#" -ne 3 ] || [ "$1" != "--spawnfile-runtime-identity" ]; then echo "Missing trusted Daimon runtime identity" >&2; exit 1; fi',
84
+ 'volume_bootstrap_uid="$2"',
85
+ 'volume_bootstrap_gid="$3"',
86
+ 'if ! [[ "$volume_bootstrap_uid" =~ ^[1-9][0-9]{0,9}$ ]] || [ "$volume_bootstrap_uid" -gt 2147483647 ]; then echo "Invalid trusted Daimon runtime UID" >&2; exit 1; fi',
87
+ 'if ! [[ "$volume_bootstrap_gid" =~ ^[1-9][0-9]{0,9}$ ]] || [ "$volume_bootstrap_gid" -gt 2147483647 ]; then echo "Invalid trusted Daimon runtime GID" >&2; exit 1; fi',
88
+ "shift 3"
89
+ ] : [
90
+ "volume_bootstrap_uid=1001",
91
+ "volume_bootstrap_gid=1001"
92
+ ]),
94
93
  "",
94
+ ...createBackedMountGuard(options.persistentMounts ?? []),
95
95
  "require_env() {",
96
96
  ' local name=\"$1\"',
97
97
  ' if [ -z \"${!name:-}\" ]; then',
@@ -143,6 +143,11 @@ export const renderEntrypoint = (runtimePlans, requiredSecrets, options = {}) =>
143
143
  return `${lines.join("\n").trimEnd()}\n`;
144
144
  }
145
145
  lines.push("PIDS=()", "", "terminate_children() {", ' for pid in "${PIDS[@]:-}"; do', ' kill "$pid" 2>/dev/null || true', " done", "}", "", "trap terminate_children INT TERM EXIT", "");
146
+ for (const receiptDirectory of [...new Set(moltnetNodePlans.flatMap((plan) => plan.receiptStorePath ? [path.posix.dirname(plan.receiptStorePath)] : []))].sort()) {
147
+ lines.push(`install -d -m 700 ${shellQuote(receiptDirectory)}`);
148
+ }
149
+ if (moltnetNodePlans.some((plan) => plan.receiptStorePath))
150
+ lines.push("");
146
151
  const recipeEnvAssignments = createRecipeEnvAssignments(mergeRecipeEnv(runtimePlans));
147
152
  const recipeEnvPrefix = recipeEnvAssignments.length > 0 ? `${recipeEnvAssignments.join(" ")} ` : "";
148
153
  const managedMoltnetServerPlans = moltnetServerPlans.filter((serverPlan) => serverPlan.mode === "managed");
@@ -159,9 +164,9 @@ export const renderEntrypoint = (runtimePlans, requiredSecrets, options = {}) =>
159
164
  serverLines.push(`apply_json_env_value ${shellQuote(serverPlan.configPath)} ${shellQuote(patch.envName)} ${shellQuote(patch.jsonPath)}`);
160
165
  }
161
166
  const causalEventsPath = moltnetCausalEventsPath(serverPlan.configPath);
162
- serverLines.push(...createMoltnetStorePrepareCommands(serverPlan), `MOLTNET_CONFIG=${shellQuote(serverPlan.configPath)} MOLTNET_CAUSAL_EVENTS_PATH=${shellQuote(causalEventsPath)} ${recipeEnvPrefix}/usr/local/bin/moltnet &`, 'PIDS+=("$!")');
167
+ serverLines.push(...createMoltnetStorePrepareCommands(serverPlan), `MOLTNET_CONFIG=${shellQuote(serverPlan.configPath)} MOLTNET_CAUSAL_EVENTS_PATH=${shellQuote(causalEventsPath)} ${recipeEnvPrefix}/usr/local/bin/moltnet start --config ${shellQuote(serverPlan.configPath)} &`, 'moltnet_server_pid="$!"', 'PIDS+=("$moltnet_server_pid")');
163
168
  if (serverPlan.port) {
164
- serverLines.push(`until curl -sf ${shellQuote(`http://127.0.0.1:${serverPlan.port}/healthz`)} >/dev/null; do sleep 1; done`);
169
+ serverLines.push(`until curl -sf ${shellQuote(`http://127.0.0.1:${serverPlan.port}/healthz`)} >/dev/null; do if ! kill -0 "$moltnet_server_pid" 2>/dev/null; then wait "$moltnet_server_pid" || true; echo ${shellQuote(`Moltnet exited before readiness on port ${serverPlan.port}`)} >&2; exit 1; fi; sleep 1; done`);
165
170
  }
166
171
  const externalParticipants = moltnetExternalParticipants.filter((artifact) => artifact.network.id === serverPlan.networkId);
167
172
  if (externalParticipants.length > 0) {
@@ -189,14 +194,15 @@ export const renderEntrypoint = (runtimePlans, requiredSecrets, options = {}) =>
189
194
  for (const plan of runtimePlans) {
190
195
  const commandTokens = resolveStartCommand(plan);
191
196
  const envAssignments = createEnvironmentAssignments(plan);
192
- lines.push(`mkdir -p ${shellQuote(plan.instancePaths.workspacePath)}`, ...createWorkspaceResourceCommands(plan), `require_file ${shellQuote(plan.instancePaths.configPath)}`, ...createEnvFileWrites(plan), ...createConfigEnvWrites(plan), `${envAssignments.join(" ")} ${commandTokens.map(shellQuote).join(" ")} &`, 'PIDS+=("$!")', "", ...createRuntimeReadinessWait(plan));
197
+ lines.push(`mkdir -p ${shellQuote(plan.instancePaths.workspacePath)}`, ...createWorkspaceResourceCommands(plan), `require_file ${shellQuote(plan.instancePaths.configPath)}`, ...createEnvFileWrites(plan), ...createConfigEnvWrites(plan), `${envAssignments.join(" ")} ${commandTokens.map(shellQuote).join(" ")} &`, 'runtime_pid="$!"', 'PIDS+=("$runtime_pid")', "", ...createRuntimeReadinessWait(plan, "runtime_pid"));
193
198
  }
194
199
  for (const nodePlan of moltnetNodePlans) {
195
200
  const urlEnv = networkUrlEnvName(nodePlan.networkId);
201
+ const receiptPath = `${MOLTNET_READINESS_DIRECTORY}/${nodePlan.networkId}-${nodePlan.memberId}.json`;
196
202
  lines.push(
197
203
  // Rebind the bridge endpoint when an external network URL is provided.
198
- `if [ -n "\${${urlEnv}:-}" ]; then`, ` apply_json_env_value ${shellQuote(nodePlan.configPath)} ${shellQuote(urlEnv)} ${shellQuote("moltnet.base_url")}`, "fi", `${recipeEnvPrefix}/usr/local/bin/moltnet node ${shellQuote(nodePlan.configPath)} &`, 'PIDS+=("$!")', "");
204
+ `if [ -n "\${${urlEnv}:-}" ]; then`, ` apply_json_env_value ${shellQuote(nodePlan.configPath)} ${shellQuote(urlEnv)} ${shellQuote("moltnet.base_url")}`, "fi", `install -d -m 700 ${shellQuote(path.posix.dirname(receiptPath))}`, `rm -f ${shellQuote(receiptPath)}`, `MOLTNET_NODE_READINESS_RECEIPT=${shellQuote(receiptPath)} ${recipeEnvPrefix}/usr/local/bin/moltnet node ${shellQuote(nodePlan.configPath)} &`, 'PIDS+=("$!")', "");
199
205
  }
200
- lines.push('if [ "${#PIDS[@]}" -eq 0 ]; then', ' echo "No runtime targets were generated for this compile output" >&2', " exit 1", "fi", "", "status=0", 'for pid in "${PIDS[@]}"; do', ' if ! wait "$pid"; then', " status=1", " fi", "done", "", 'exit "$status"');
206
+ lines.push('if [ "${#PIDS[@]}" -eq 0 ]; then', ' echo "No runtime targets were generated for this compile output" >&2', " exit 1", "fi", "", "# Every child is critical. Exit on the first child termination so Docker", "# can restart the complete, mutually consistent organization unit.", "set +e", 'wait -n "${PIDS[@]}"', "status=$?", "set -e", "terminate_children", 'for pid in "${PIDS[@]}"; do wait "$pid" 2>/dev/null || true; done', 'if [ "$status" -eq 0 ]; then status=1; fi', 'exit "$status"');
201
207
  return `${lines.join("\n").trimEnd()}\n`;
202
208
  };
@@ -0,0 +1,30 @@
1
+ import type { ContainerPersistentMountReport } from "../report/types.js";
2
+ /**
3
+ * Merges every durable-mount source into one report list.
4
+ *
5
+ * Sources are independent (memory banks, workspace `kind: volume` resources,
6
+ * Daimon telemetry, runtime-declared mounts, Moltnet stores and token
7
+ * directories) and may legitimately name the same mount twice; two sources
8
+ * describing one id DIFFERENTLY is a compile error, as is two ids claiming one
9
+ * host volume name.
10
+ */
11
+ export declare const mergePersistentMounts: (candidates: readonly ContainerPersistentMountReport[]) => ContainerPersistentMountReport[];
12
+ /**
13
+ * Durable mount names come from four independent sources — memory banks
14
+ * (`memoryArtifacts.ts`), workspace `kind: volume` resources
15
+ * (`containerTargetResources.ts`), Moltnet stores and token directories
16
+ * (`moltnetArtifacts.ts`), and runtime-declared mounts (`runtimePlans`) —
17
+ * and each source only ever checked itself.
18
+ *
19
+ * Author-declared names cross those boundaries. A resource with
20
+ * `name: X` and a managed Moltnet store with `persistence.name: X` used to
21
+ * compile to two mounts at two different paths carrying one `volume_name`, so
22
+ * `spawnfile run` mounted a single host volume at both. A sqlite store and a
23
+ * team's edition state then shared one directory, where their bootstrap-marker
24
+ * and replacement-sentinel protocols contradict each other.
25
+ *
26
+ * There is no safe interpretation of that declaration, so it fails at compile
27
+ * naming both sides. (Two mounts legitimately SHARE a name only when they are
28
+ * the same mount, which the id-keyed merge upstream has already collapsed.)
29
+ */
30
+ export declare const assertPersistentMountVolumeNamesAreUnique: (mounts: readonly ContainerPersistentMountReport[]) => void;
@@ -0,0 +1,66 @@
1
+ import { SpawnfileError } from "../shared/index.js";
2
+ /**
3
+ * Merges every durable-mount source into one report list.
4
+ *
5
+ * Sources are independent (memory banks, workspace `kind: volume` resources,
6
+ * Daimon telemetry, runtime-declared mounts, Moltnet stores and token
7
+ * directories) and may legitimately name the same mount twice; two sources
8
+ * describing one id DIFFERENTLY is a compile error, as is two ids claiming one
9
+ * host volume name.
10
+ */
11
+ export const mergePersistentMounts = (candidates) => {
12
+ const byId = new Map();
13
+ const merged = [...candidates]
14
+ .sort((left, right) => left.id.localeCompare(right.id))
15
+ .filter((mount) => {
16
+ const existing = byId.get(mount.id);
17
+ if (!existing) {
18
+ byId.set(mount.id, mount);
19
+ return true;
20
+ }
21
+ if (existing.mount_path !== mount.mount_path ||
22
+ existing.volume_name !== mount.volume_name ||
23
+ existing.reason !== mount.reason ||
24
+ existing.lifecycle !== mount.lifecycle) {
25
+ throw new SpawnfileError("validation_error", `Container persistent mount ${mount.id} resolves to conflicting targets`);
26
+ }
27
+ // Deliberately kept, not deduplicated: two sources describing one mount
28
+ // identically was already reported twice before this merge was extracted,
29
+ // and silently changing that is not this fix's business.
30
+ return true;
31
+ });
32
+ assertPersistentMountVolumeNamesAreUnique(merged);
33
+ return merged;
34
+ };
35
+ /**
36
+ * Durable mount names come from four independent sources — memory banks
37
+ * (`memoryArtifacts.ts`), workspace `kind: volume` resources
38
+ * (`containerTargetResources.ts`), Moltnet stores and token directories
39
+ * (`moltnetArtifacts.ts`), and runtime-declared mounts (`runtimePlans`) —
40
+ * and each source only ever checked itself.
41
+ *
42
+ * Author-declared names cross those boundaries. A resource with
43
+ * `name: X` and a managed Moltnet store with `persistence.name: X` used to
44
+ * compile to two mounts at two different paths carrying one `volume_name`, so
45
+ * `spawnfile run` mounted a single host volume at both. A sqlite store and a
46
+ * team's edition state then shared one directory, where their bootstrap-marker
47
+ * and replacement-sentinel protocols contradict each other.
48
+ *
49
+ * There is no safe interpretation of that declaration, so it fails at compile
50
+ * naming both sides. (Two mounts legitimately SHARE a name only when they are
51
+ * the same mount, which the id-keyed merge upstream has already collapsed.)
52
+ */
53
+ export const assertPersistentMountVolumeNamesAreUnique = (mounts) => {
54
+ const byVolumeName = new Map();
55
+ for (const mount of mounts) {
56
+ const existing = byVolumeName.get(mount.volume_name);
57
+ if (existing && existing.mount_path !== mount.mount_path) {
58
+ throw new SpawnfileError("validation_error", `Durable volume name "${mount.volume_name}" is claimed by two different mounts: `
59
+ + `${existing.id} (${existing.reason}) at ${existing.mount_path}, and `
60
+ + `${mount.id} (${mount.reason}) at ${mount.mount_path}. `
61
+ + "One host volume cannot back two container paths; give each declaration its own name.");
62
+ }
63
+ if (!existing)
64
+ byVolumeName.set(mount.volume_name, mount);
65
+ }
66
+ };
@@ -0,0 +1 @@
1
+ export declare const MOLTNET_READINESS_DIRECTORY = "/run/spawnfile/moltnet-readiness";
@@ -0,0 +1 @@
1
+ export const MOLTNET_READINESS_DIRECTORY = "/run/spawnfile/moltnet-readiness";
@@ -0,0 +1,2 @@
1
+ export declare const RUNTIME_LINK_MATERIALIZER_PATH = "/opt/spawnfile/materialize-runtime-links.cjs";
2
+ export declare const renderRuntimeLinkMaterializer: () => string;
@@ -0,0 +1,12 @@
1
+ export const RUNTIME_LINK_MATERIALIZER_PATH = "/opt/spawnfile/materialize-runtime-links.cjs";
2
+ export const renderRuntimeLinkMaterializer = () => `"use strict";
3
+ const fs=require("node:fs"),path=require("node:path"),root=path.resolve(process.argv[2]||"");
4
+ if(!root.startsWith("/opt/spawnfile/runtime-installs/"))throw Error("unsafe root");
5
+ const rootInfo=fs.lstatSync(root),links=[];
6
+ if(!rootInfo.isDirectory()||rootInfo.isSymbolicLink()||rootInfo.uid||rootInfo.gid)throw Error("unsafe root identity");
7
+ const walk=d=>{for(const n of fs.readdirSync(d).sort()){const p=path.join(d,n),s=fs.lstatSync(p);if(s.isSymbolicLink())links.push(p);else if(s.isDirectory())walk(p);else if(!s.isFile())throw Error("unsupported entry");}};
8
+ const inside=p=>p.startsWith(root+path.sep);
9
+ const resolve=p=>{let hops=0;for(;;){const rel=path.relative(root,p);if(!rel||rel.startsWith("..")||path.isAbsolute(rel))throw Error("link escape");const parts=rel.split(path.sep);let q=root,again=false;for(let i=0;i<parts.length;i++){q=path.join(q,parts[i]);const s=fs.lstatSync(q);if(!s.isSymbolicLink())continue;if(++hops>16||s.uid||s.gid)throw Error("unsafe link chain");const l=fs.readlinkSync(q);if(path.isAbsolute(l))throw Error("absolute link");p=path.resolve(path.dirname(q),l,...parts.slice(i+1));if(!inside(p))throw Error("link escape");again=true;break;}if(!again)return p;}};
10
+ walk(root);
11
+ for(const link of links){const s=fs.lstatSync(link);if(!s.isSymbolicLink()||s.uid||s.gid)throw Error("link changed");const target=resolve(link),t=fs.lstatSync(target);if(!t.isFile()||t.isSymbolicLink()||t.uid||t.gid||t.dev!==rootInfo.dev||t.nlink<1)throw Error("unsafe target");const b=fs.readFileSync(target);if(b.length>67108864)throw Error("target too large");const tmp=link+".spawnfile-materialize",fd=fs.openSync(tmp,fs.constants.O_CREAT|fs.constants.O_EXCL|fs.constants.O_WRONLY|fs.constants.O_NOFOLLOW,t.mode&0o111?0o555:0o444);try{fs.writeFileSync(fd,b);fs.fsyncSync(fd);}finally{fs.closeSync(fd);}fs.renameSync(tmp,link);}
12
+ `;
@@ -0,0 +1,7 @@
1
+ import type { RuntimeTargetPlan } from "./containerArtifactsTypes.js";
2
+ /**
3
+ * Blocks until a runtime with an HTTP port answers /healthz, failing fast if
4
+ * the child dies first. Split out of containerEntrypointRender.ts to keep that
5
+ * module under the repository's 400-line ceiling.
6
+ */
7
+ export declare const createRuntimeReadinessWait: (plan: RuntimeTargetPlan, pidVariable: string) => string[];
@@ -0,0 +1,40 @@
1
+ import { shellQuote } from "./containerEntrypointShell.js";
2
+ /**
3
+ * Blocks until a runtime with an HTTP port answers /healthz, failing fast if
4
+ * the child dies first. Split out of containerEntrypointRender.ts to keep that
5
+ * module under the repository's 400-line ceiling.
6
+ */
7
+ export const createRuntimeReadinessWait = (plan, pidVariable) => {
8
+ if (!plan.port)
9
+ return [];
10
+ if (plan.runtimeName === "daimon") {
11
+ return [
12
+ "attempts=0",
13
+ `until curl -sf ${shellQuote(`http://127.0.0.1:${plan.port}/healthz`)} >/dev/null; do`,
14
+ ` if ! kill -0 "$${pidVariable}" 2>/dev/null; then wait "$${pidVariable}" || true; echo ${shellQuote(`Daimon exited before readiness on port ${plan.port}`)} >&2; exit 1; fi`,
15
+ " attempts=$((attempts + 1))",
16
+ ' if [ "$attempts" -ge 180 ]; then',
17
+ ` echo ${shellQuote(`Timed out waiting for daimon on port ${plan.port}`)} >&2`,
18
+ " exit 1",
19
+ " fi",
20
+ " sleep 1",
21
+ "done",
22
+ ""
23
+ ];
24
+ }
25
+ if (!["openclaw", "pi"].includes(plan.runtimeName))
26
+ return [];
27
+ return [
28
+ "attempts=0",
29
+ `until curl -sf ${shellQuote(`http://127.0.0.1:${plan.port}/healthz`)} >/dev/null; do`,
30
+ ` if ! kill -0 "$${pidVariable}" 2>/dev/null; then wait "$${pidVariable}" || true; echo ${shellQuote(`${plan.runtimeName} exited before readiness on port ${plan.port}`)} >&2; exit 1; fi`,
31
+ " attempts=$((attempts + 1))",
32
+ ' if [ "$attempts" -ge 180 ]; then',
33
+ ` echo ${shellQuote(`Timed out waiting for ${plan.runtimeName} on port ${plan.port}`)} >&2`,
34
+ " exit 1",
35
+ " fi",
36
+ " sleep 1",
37
+ "done",
38
+ ""
39
+ ];
40
+ };
@@ -0,0 +1,4 @@
1
+ import type { RuntimeTargetPlan } from "./containerArtifactsTypes.js";
2
+ import type { EntrypointOptions } from "./containerEntrypointRender.js";
3
+ export { VOLUME_BOOTSTRAP_MARKER, VOLUME_BOOTSTRAP_MARKER_CONTENT } from "./containerVolumeBootstrap.js";
4
+ export declare const createStateOwnershipCommand: (runtimePlans: RuntimeTargetPlan[], persistentMountPaths?: string[], moltnet?: EntrypointOptions["moltnet"]) => string;
@@ -0,0 +1,75 @@
1
+ import path from "node:path";
2
+ import { SpawnfileError } from "../shared/index.js";
3
+ import { DAIMON_RUNTIME_UID, resolveDaimonUidEntrypointStateRoots } from "./containerDaimonUidEntrypointRender.js";
4
+ import { VOLUME_BOOTSTRAP_MARKER, VOLUME_BOOTSTRAP_MARKER_CONTENT } from "./containerVolumeBootstrap.js";
5
+ export { VOLUME_BOOTSTRAP_MARKER, VOLUME_BOOTSTRAP_MARKER_CONTENT } from "./containerVolumeBootstrap.js";
6
+ const SPAWNFILE_STATE_ROOT = "/var/lib/spawnfile";
7
+ const MOLTNET_STATE_ROOT = `${SPAWNFILE_STATE_ROOT}/moltnet`;
8
+ const shellQuote = (value) => `'${value.replace(/'/g, `'\"'\"'`)}'`;
9
+ const privateDirectoriesThrough = (target) => {
10
+ const relative = path.posix.relative(SPAWNFILE_STATE_ROOT, target);
11
+ if (relative.startsWith("../") || path.posix.isAbsolute(relative)) {
12
+ throw new SpawnfileError("compile_error", `Generated Moltnet state path escapes ${SPAWNFILE_STATE_ROOT}: ${target}`);
13
+ }
14
+ const segments = relative === "" ? [] : relative.split("/");
15
+ return [
16
+ SPAWNFILE_STATE_ROOT,
17
+ ...segments.map((_, index) => path.posix.join(SPAWNFILE_STATE_ROOT, ...segments.slice(0, index + 1)))
18
+ ];
19
+ };
20
+ const createMoltnetPrivacyCommands = (runtimePlans, persistentMountPaths, moltnet) => {
21
+ if (!runtimePlans.some((plan) => plan.runtimeName === "daimon") || !moltnet)
22
+ return [];
23
+ const configPaths = [
24
+ ...moltnet.serverPlans.flatMap((plan) => plan.mode === "managed" && plan.configPath ? [plan.configPath] : []),
25
+ ...moltnet.nodePlans.map((plan) => plan.configPath)
26
+ ].sort();
27
+ const receiptDirectories = moltnet.nodePlans.flatMap((plan) => plan.receiptStorePath ? [path.posix.dirname(plan.receiptStorePath)] : []);
28
+ if (configPaths.length === 0)
29
+ return [];
30
+ if (configPaths.some((configPath) => !configPath.startsWith(`${MOLTNET_STATE_ROOT}/`))) {
31
+ throw new SpawnfileError("compile_error", "Generated Moltnet config paths must stay beneath the private Moltnet state root");
32
+ }
33
+ const moltnetMountPaths = persistentMountPaths
34
+ .filter((mountPath) => mountPath.startsWith(`${MOLTNET_STATE_ROOT}/`));
35
+ const privateDirectories = [
36
+ ...new Set([
37
+ ...configPaths.flatMap((configPath) => privateDirectoriesThrough(path.posix.dirname(configPath))),
38
+ ...receiptDirectories.flatMap(privateDirectoriesThrough),
39
+ ...moltnetMountPaths.flatMap(privateDirectoriesThrough)
40
+ ])
41
+ ].filter((directory) => directory !== SPAWNFILE_STATE_ROOT).sort();
42
+ const ownership = `${DAIMON_RUNTIME_UID}:${DAIMON_RUNTIME_UID}`;
43
+ return [
44
+ `install -d -o ${DAIMON_RUNTIME_UID} -g ${DAIMON_RUNTIME_UID} -m 700 ${privateDirectories.map(shellQuote).join(" ")}`,
45
+ `chown root:root ${configPaths.map(shellQuote).join(" ")}`,
46
+ `chmod 600 ${configPaths.map(shellQuote).join(" ")}`,
47
+ `chown ${ownership} ${configPaths.map(shellQuote).join(" ")}`
48
+ ];
49
+ };
50
+ export const createStateOwnershipCommand = (runtimePlans, persistentMountPaths = [], moltnet) => {
51
+ const mountPaths = [...new Set(persistentMountPaths)].sort();
52
+ const wrapperStateRoots = runtimePlans.some((plan) => plan.runtimeName === "daimon")
53
+ ? resolveDaimonUidEntrypointStateRoots(runtimePlans)
54
+ : [];
55
+ const mkdirPaths = [...new Set([SPAWNFILE_STATE_ROOT, ...mountPaths])].sort();
56
+ const markerCommands = mountPaths.map((mountPath) => `printf '%s\\n' ${shellQuote(VOLUME_BOOTSTRAP_MARKER_CONTENT)} > ${shellQuote(path.posix.join(mountPath, VOLUME_BOOTSTRAP_MARKER))} && chmod 600 ${shellQuote(path.posix.join(mountPath, VOLUME_BOOTSTRAP_MARKER))}`);
57
+ const chownPaths = [
58
+ ...new Set([
59
+ ...(runtimePlans.some((plan) => plan.runtimeName === "daimon") ? [] : [SPAWNFILE_STATE_ROOT]),
60
+ ...mountPaths.filter((mountPath) => !mountPath.startsWith(`${SPAWNFILE_STATE_ROOT}/`))
61
+ ])
62
+ ].sort();
63
+ return [
64
+ `mkdir -p ${mkdirPaths.map(shellQuote).join(" ")}`,
65
+ ...markerCommands,
66
+ ...(chownPaths.length > 0
67
+ ? [`chown -R spawnfile:spawnfile ${chownPaths.map(shellQuote).join(" ")}`]
68
+ : []),
69
+ ...(runtimePlans.some((plan) => plan.runtimeName === "daimon")
70
+ ? [`chown root:root ${shellQuote(SPAWNFILE_STATE_ROOT)} && chmod 711 ${shellQuote(SPAWNFILE_STATE_ROOT)}`]
71
+ : []),
72
+ ...wrapperStateRoots.map((stateRoot) => `install -d -o root -g root -m 700 ${shellQuote(stateRoot)}`),
73
+ ...createMoltnetPrivacyCommands(runtimePlans, mountPaths, moltnet)
74
+ ].join(" && ");
75
+ };
@@ -1,4 +1,25 @@
1
1
  import type { ContainerTarget, ContainerTargetInput, RuntimeContainerMeta } from "../runtime/index.js";
2
2
  import type { RuntimeTargetPlan } from "./containerArtifactsTypes.js";
3
3
  import { type WorkspaceResourcePlan } from "./workspaceResources.js";
4
- export declare const resolveTargetResources: (target: ContainerTarget, inputs: ContainerTargetInput[], instancePaths: RuntimeTargetPlan["instancePaths"], meta: RuntimeContainerMeta) => WorkspaceResourcePlan[];
4
+ export interface ResolvedTargetResourcePlan extends WorkspaceResourcePlan {
5
+ canonicalBackingPath: string;
6
+ ownerId: string;
7
+ persistentMountId?: string;
8
+ replacementSentinel?: string;
9
+ resolvedIdentity: string;
10
+ volumeName?: string;
11
+ }
12
+ export interface WorkspaceResourcePersistentMount {
13
+ /** The author's `name`, when declared on the resource. */
14
+ declared_volume_name?: string;
15
+ id: string;
16
+ lifecycle: "exclusive-reattach";
17
+ mount_path: string;
18
+ reason: string;
19
+ volume_name: string;
20
+ }
21
+ export declare const resolveWorkspaceResourceVolumes: (runtimePlans: readonly RuntimeTargetPlan[]) => {
22
+ resources: ResolvedTargetResourcePlan[];
23
+ mounts: WorkspaceResourcePersistentMount[];
24
+ };
25
+ export declare const resolveTargetResources: (target: ContainerTarget, inputs: ContainerTargetInput[], instancePaths: RuntimeTargetPlan["instancePaths"], meta: RuntimeContainerMeta, planRoot: string, deploymentLineage?: string) => ResolvedTargetResourcePlan[];
@@ -1,10 +1,48 @@
1
1
  import path from "node:path";
2
+ import { createHash } from "node:crypto";
2
3
  import { SpawnfileError } from "../shared/index.js";
4
+ import { createExclusiveReattachVolumeName } from "../shared/index.js";
3
5
  import { mergeWorkspaceResourcePlans } from "./workspaceResources.js";
4
6
  const CONFIG_FILE_PLACEHOLDER = "<config-file>";
5
7
  const INSTANCE_ROOT_PLACEHOLDER = "<instance-root>";
6
8
  const SOURCE_AGENT_PLACEHOLDER = "<agent-name>";
7
9
  const SOURCE_SLUG_PLACEHOLDER = "<source-slug>";
10
+ const digest = (value) => createHash("sha256").update(value).digest("hex");
11
+ export const resolveWorkspaceResourceVolumes = (runtimePlans) => {
12
+ const resources = runtimePlans.flatMap((runtimePlan) => (runtimePlan.resources ?? []));
13
+ const byBackingPath = new Map();
14
+ const backingPathByVolumeName = new Map();
15
+ for (const resource of resources.filter((candidate) => candidate.kind === "volume")) {
16
+ const existing = byBackingPath.get(resource.canonicalBackingPath);
17
+ // Two DIFFERENT declared resources landing on one backing path is always a
18
+ // mistake: the path segment derives from an explicit `name` when one is
19
+ // given, so `id: a`/`id: b` both declaring `name: X` in one scope used to
20
+ // collapse into a single directory and volume, silently, with both
21
+ // workspace symlinks pointing at it. The same id across runtime plans is
22
+ // the legitimate `sharing: team` case and still merges.
23
+ if (existing && existing.id !== resource.id) {
24
+ throw new SpawnfileError("validation_error", `Workspace resources ${existing.id} and ${resource.id} resolve to the same backing volume ${resource.canonicalBackingPath}; a declared volume name must be unique within its scope`);
25
+ }
26
+ if (existing && (existing.mode !== resource.mode || existing.sharing !== resource.sharing || existing.volumeName !== resource.volumeName || (resource.sharing === "per_agent" && existing.ownerId !== resource.ownerId))) {
27
+ throw new SpawnfileError("validation_error", `Workspace volume ${resource.canonicalBackingPath} has incompatible mode, sharing, or owner declarations`);
28
+ }
29
+ const conflictingPath = backingPathByVolumeName.get(resource.volumeName);
30
+ if (conflictingPath && conflictingPath !== resource.canonicalBackingPath)
31
+ throw new SpawnfileError("validation_error", "Workspace volume name collision");
32
+ byBackingPath.set(resource.canonicalBackingPath, resource);
33
+ backingPathByVolumeName.set(resource.volumeName, resource.canonicalBackingPath);
34
+ }
35
+ // Workspace `kind: volume` resources are durable product state: an author
36
+ // declares one precisely so it outlives the container. They are therefore
37
+ // `exclusive-reattach` — deployment-stable name, reattached rather than
38
+ // recreated, one live holder at a time.
39
+ return { resources, mounts: [...byBackingPath.values()].map((resource) => ({
40
+ ...(resource.name?.trim() ? { declared_volume_name: resource.name.trim() } : {}),
41
+ id: resource.persistentMountId, lifecycle: "exclusive-reattach",
42
+ mount_path: resource.canonicalBackingPath,
43
+ reason: `Workspace ${resource.sharing} resource ${resource.id}`, volume_name: resource.volumeName
44
+ })) };
45
+ };
8
46
  const replaceSourceWorkspacePathTemplate = (template, input, instancePaths, meta) => {
9
47
  const agentName = input.value.kind === "agent" ? input.value.name : input.slug;
10
48
  const instanceRoot = instancePaths.instanceRoot ?? path.posix.dirname(instancePaths.workspacePath);
@@ -21,10 +59,12 @@ const sourceTargetId = (target, input, isMergedTarget) => isMergedTarget ? `${ta
21
59
  const pathsOverlap = (left, right) => left === right || left.startsWith(`${right}/`) || right.startsWith(`${left}/`);
22
60
  const dedupeAndAssertResourcePlans = (target, resources) => {
23
61
  const byLinkPath = new Map();
62
+ const volumesByBackingPath = new Map();
63
+ const backingPathByVolumeName = new Map();
24
64
  for (const resource of resources) {
25
65
  const existing = byLinkPath.get(resource.linkPath);
26
66
  if (existing) {
27
- if (existing.backingPath !== resource.backingPath || existing.id !== resource.id) {
67
+ if (existing.resolvedIdentity !== resource.resolvedIdentity) {
28
68
  throw new SpawnfileError("validation_error", `Container target ${target.id} declares conflicting workspace resources at ${resource.linkPath}`);
29
69
  }
30
70
  continue;
@@ -34,10 +74,33 @@ const dedupeAndAssertResourcePlans = (target, resources) => {
34
74
  throw new SpawnfileError("validation_error", `Container target ${target.id} declares overlapping workspace resource links ${overlapping.linkPath} and ${resource.linkPath}`);
35
75
  }
36
76
  byLinkPath.set(resource.linkPath, resource);
77
+ if (resource.kind !== "volume")
78
+ continue;
79
+ const existingVolume = volumesByBackingPath.get(resource.canonicalBackingPath);
80
+ if (existingVolume && existingVolume.id !== resource.id) {
81
+ throw new SpawnfileError("validation_error", `Container target ${target.id} declares workspace resources ${existingVolume.id} and ${resource.id} that resolve to the same backing volume ${resource.canonicalBackingPath}; a declared volume name must be unique within its scope`);
82
+ }
83
+ if (existingVolume) {
84
+ const incompatible = existingVolume.mode !== resource.mode ||
85
+ existingVolume.sharing !== resource.sharing ||
86
+ existingVolume.volumeName !== resource.volumeName ||
87
+ (resource.sharing === "per_agent" && existingVolume.ownerId !== resource.ownerId);
88
+ if (incompatible) {
89
+ throw new SpawnfileError("validation_error", `Container target ${target.id} declares incompatible workspace volume owners or modes at ${resource.canonicalBackingPath}`);
90
+ }
91
+ }
92
+ else {
93
+ volumesByBackingPath.set(resource.canonicalBackingPath, resource);
94
+ }
95
+ const conflictingBackingPath = backingPathByVolumeName.get(resource.volumeName);
96
+ if (conflictingBackingPath && conflictingBackingPath !== resource.canonicalBackingPath) {
97
+ throw new SpawnfileError("validation_error", `Container target ${target.id} workspace volume identity collision`);
98
+ }
99
+ backingPathByVolumeName.set(resource.volumeName, resource.canonicalBackingPath);
37
100
  }
38
101
  return [...byLinkPath.values()].sort((left, right) => left.linkPath.localeCompare(right.linkPath) || left.id.localeCompare(right.id));
39
102
  };
40
- export const resolveTargetResources = (target, inputs, instancePaths, meta) => {
103
+ export const resolveTargetResources = (target, inputs, instancePaths, meta, planRoot, deploymentLineage = "compile") => {
41
104
  const sourceIds = new Set(target.sourceIds ?? []);
42
105
  if (sourceIds.size === 0) {
43
106
  return [];
@@ -50,6 +113,35 @@ export const resolveTargetResources = (target, inputs, instancePaths, meta) => {
50
113
  return mergeWorkspaceResourcePlans(input.value.workspaceResources ?? [], `${target.id}/${input.id}`, {
51
114
  targetId: sourceTargetId(target, input, isMergedTarget),
52
115
  workspacePath: resolveSourceWorkspacePath(input, instancePaths, meta)
116
+ }).map((resource) => {
117
+ const canonicalBackingPath = path.posix.normalize(resource.backingPath);
118
+ const ownerId = resource.sharing === "per_agent" ? input.id : canonicalBackingPath;
119
+ const resolvedIdentity = `sha256:${digest(JSON.stringify({
120
+ backingPath: canonicalBackingPath,
121
+ kind: resource.kind,
122
+ mode: resource.mode,
123
+ ownerId,
124
+ ...(resource.kind === "bundle" ? { archivePath: resource.archivePath, sha256: resource.sha256 } : {}),
125
+ sharing: resource.sharing
126
+ }))}`;
127
+ if (resource.kind !== "volume")
128
+ return { ...resource, backingPath: canonicalBackingPath, canonicalBackingPath, ownerId, resolvedIdentity };
129
+ const pathDigest = digest(canonicalBackingPath);
130
+ return {
131
+ ...resource,
132
+ backingPath: canonicalBackingPath,
133
+ canonicalBackingPath,
134
+ ownerId,
135
+ persistentMountId: `workspace-resource-${pathDigest.slice(0, 24)}`,
136
+ replacementSentinel: path.posix.join(canonicalBackingPath, ".spawnfile-resource-identity"),
137
+ resolvedIdentity,
138
+ // Author-declared `name` verbatim (an operator can pre-create or
139
+ // migrate the host volume under exactly that name); otherwise a
140
+ // deployment-stable derived name. Never run-scoped: a fresh
141
+ // NOOPOLIS_RUN_ID must not strand the previous run's state.
142
+ volumeName: resource.name?.trim()
143
+ || createExclusiveReattachVolumeName(`${planRoot}\0${deploymentLineage}`, `workspace-resource-${pathDigest.slice(0, 24)}`)
144
+ };
53
145
  });
54
146
  });
55
147
  return dedupeAndAssertResourcePlans(target, resources);
@@ -0,0 +1,3 @@
1
+ export declare const VOLUME_BOOTSTRAP_MARKER = ".spawnfile-volume-init";
2
+ export declare const VOLUME_BOOTSTRAP_CLAIM = ".spawnfile-volume-init.claim";
3
+ export declare const VOLUME_BOOTSTRAP_MARKER_CONTENT = "spawnfile.volume-bootstrap.v1";
@@ -0,0 +1,3 @@
1
+ export const VOLUME_BOOTSTRAP_MARKER = ".spawnfile-volume-init";
2
+ export const VOLUME_BOOTSTRAP_CLAIM = `${VOLUME_BOOTSTRAP_MARKER}.claim`;
3
+ export const VOLUME_BOOTSTRAP_MARKER_CONTENT = "spawnfile.volume-bootstrap.v1";
@@ -1,11 +1,17 @@
1
+ import { VOLUME_BOOTSTRAP_MARKER, VOLUME_BOOTSTRAP_MARKER_CONTENT } from "./containerVolumeBootstrap.js";
1
2
  const shellQuote = (value) => `'${value.replace(/'/g, `'\"'\"'`)}'`;
2
3
  export const createWorkspaceResourceCommands = (plan) => (plan.resources ?? []).flatMap((resource) => {
3
4
  const readonlyFlag = resource.mode === "readonly" ? "readonly" : "mutable";
4
5
  if (resource.kind === "volume") {
6
+ const resolved = resource;
5
7
  return [
6
- `prepare_volume_resource ${shellQuote(resource.id)} ${shellQuote(resource.linkPath)} ${shellQuote(resource.backingPath)} ${shellQuote(readonlyFlag)}`
8
+ `prepare_volume_resource ${shellQuote(resource.id)} ${shellQuote(resource.linkPath)} ${shellQuote(resource.backingPath)} ${shellQuote(readonlyFlag)} ${shellQuote(resolved.resolvedIdentity ?? "")}`
7
9
  ];
8
10
  }
11
+ if (resource.kind === "bundle")
12
+ return [
13
+ `prepare_bundle_resource ${shellQuote(resource.id)} ${shellQuote(resource.linkPath)} ${shellQuote(resource.backingPath)} ${shellQuote(resource.archivePath ?? "")} ${shellQuote(resource.sha256 ?? "")}`
14
+ ];
9
15
  const selectorKind = resource.branch
10
16
  ? "branch"
11
17
  : resource.tag
@@ -58,15 +64,57 @@ export const createWorkspaceResourceShellFunctions = () => [
58
64
  ' local link_path="$2"',
59
65
  ' local backing_path="$3"',
60
66
  ' local mode="$4"',
67
+ ' local identity="$5"',
61
68
  ' mkdir -p "$backing_path"',
62
69
  ' if [ ! -d "$backing_path" ]; then',
63
70
  ' echo "Workspace volume resource $id backing path is not a directory: $backing_path" >&2',
64
71
  " exit 1",
65
72
  " fi",
73
+ ' local sentinel="$backing_path/.spawnfile-resource-identity"',
74
+ ' if [ -f "$sentinel" ]; then',
75
+ ' if [ "$(cat "$sentinel")" != "$identity" ]; then',
76
+ ' echo "Workspace volume resource $id replacement sentinel mismatch" >&2',
77
+ " exit 1",
78
+ " fi",
79
+ " else",
80
+ ` local bootstrap="$backing_path/${VOLUME_BOOTSTRAP_MARKER}"`,
81
+ ` local bootstrap_claim="$backing_path/${VOLUME_BOOTSTRAP_MARKER}.claim"`,
82
+ ' local first_entry',
83
+ ' first_entry="$(find "$backing_path" -mindepth 1 -maxdepth 1 -print -quit)"',
84
+ ' if [ -n "$first_entry" ]; then',
85
+ ' if [ "$first_entry" = "$bootstrap" ]; then',
86
+ ' mv -T --no-clobber -- "$bootstrap" "$bootstrap_claim"',
87
+ ' elif [ "$first_entry" != "$bootstrap_claim" ]; then',
88
+ ' echo "Workspace volume resource $id is nonempty without an authenticated replacement sentinel" >&2',
89
+ " exit 1",
90
+ " fi",
91
+ ' if [ "$(find "$backing_path" -mindepth 1 -maxdepth 1 ! -name ' + `'${VOLUME_BOOTSTRAP_MARKER}.claim'` + ' -print -quit)" != "" ] || [ -L "$bootstrap_claim" ] || [ ! -f "$bootstrap_claim" ] || [ "$(stat -c "%u:%g:%a:%h" "$bootstrap_claim")" != "${volume_bootstrap_uid}:${volume_bootstrap_gid}:600:1" ] || [ "$(cat "$bootstrap_claim")" != "' + VOLUME_BOOTSTRAP_MARKER_CONTENT + '" ]; then',
92
+ ' echo "Workspace volume resource $id bootstrap marker mismatch" >&2',
93
+ " exit 1",
94
+ " fi",
95
+ ' rm -- "$bootstrap_claim"',
96
+ " fi",
97
+ ' printf "%s\\n" "$identity" > "$sentinel"',
98
+ " fi",
66
99
  ' mark_readonly_resource "$backing_path" "$mode"',
67
100
  ' prepare_resource_link "$id" "$link_path" "$backing_path"',
68
101
  "}",
69
102
  "",
103
+ "prepare_bundle_resource() {",
104
+ ' local id="$1" link_path="$2" backing_path="$3" archive="$4" identity="$5"',
105
+ ' [ -f "$archive" ] || { echo "Workspace bundle $id archive missing" >&2; exit 1; }',
106
+ ' local sentinel="$backing_path/.spawnfile-bundle-identity"',
107
+ ' if [ -e "$backing_path" ]; then',
108
+ ' [ -f "$sentinel" ] && [ "$(cat "$sentinel")" = "$identity" ] || { echo "Workspace bundle $id identity mismatch" >&2; exit 1; }',
109
+ " else",
110
+ ' mkdir -p "$backing_path"',
111
+ ' tar --no-same-owner --no-same-permissions -xf "$archive" -C "$backing_path"',
112
+ ' printf %s "$identity" > "$sentinel"',
113
+ " fi",
114
+ ' mark_readonly_resource "$backing_path" readonly',
115
+ ' prepare_resource_link "$id" "$link_path" "$backing_path"',
116
+ "}",
117
+ "",
70
118
  "prepare_git_resource() {",
71
119
  ' local id="$1"',
72
120
  ' local link_path="$2"',
@@ -2,7 +2,7 @@ import type { ContainerPersistentMountReport } from "../report/index.js";
2
2
  import type { CompiledNodeArtifact, RuntimeTargetPlan } from "./containerArtifactsTypes.js";
3
3
  import type { CompilePlan } from "./types.js";
4
4
  export interface DaimonTelemetryArtifactBundle {
5
- /** One durable volume per pi/daimon agent, mounted onto its telemetry directory. */
5
+ /** One durable volume per legacy Pi agent, mounted onto its telemetry directory. */
6
6
  mounts: ContainerPersistentMountReport[];
7
7
  /** Runtime target plan id (e.g. "pi-app") -> { node id -> telemetry persistent mount id
8
8
  * }, so `containerArtifacts.ts` can stamp `runtime_instances[].telemetry_mount_ids` and
@@ -11,7 +11,7 @@ export interface DaimonTelemetryArtifactBundle {
11
11
  telemetryMountIdsByInstance: Map<string, Record<string, string>>;
12
12
  }
13
13
  /**
14
- * Registers one run-scoped durable volume per pi/daimon agent for its daimon turn/wake
14
+ * Registers one run-scoped durable volume per legacy Pi agent for its daimon turn/wake
15
15
  * causal telemetry directory (`<instanceRoot>/runtime/agents/<slug>/telemetry` — the parent
16
16
  * of `causal.jsonl`, see `appCoreSource.ts`'s `runtimeHomePath`/`instanceRoot`), mirroring
17
17
  * exactly how `moltnetArtifacts.ts` mounts the Moltnet causal directory (Piece 4b,