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
@@ -0,0 +1,315 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { createReadStream } from "node:fs";
3
+ import { cp, lstat, mkdir, open, readFile, readdir, realpath, rename, rm, stat, statfs, writeFile } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import { pipeline } from "node:stream/promises";
6
+ import { activateNoReplace } from "./noReplaceActivation.js";
7
+ export const WORKSPACE_RESOURCE_MANIFEST_VERSION = "spawnfile.workspace-resource-manifest.v1";
8
+ export const WORKSPACE_RESOURCE_MIGRATION_VERSION = "spawnfile.workspace-resource-migration.v1";
9
+ const METADATA_MANIFEST = ".spawnfile-resource-migration-manifest.json";
10
+ const ACTIVATION_PROVENANCE = ".spawnfile-resource-activation-provenance";
11
+ const RESOURCE_IDENTITY = ".spawnfile-resource-identity";
12
+ const MAX_MANIFEST_BYTES = 16 * 1024 * 1024;
13
+ const MAX_JOURNAL_BYTES = 16 * 1024;
14
+ const digestBytes = (bytes) => `sha256:${createHash("sha256").update(bytes).digest("hex")}`;
15
+ const fileDigest = async (file) => {
16
+ const hash = createHash("sha256");
17
+ await pipeline(createReadStream(file), hash);
18
+ return `sha256:${hash.digest("hex")}`;
19
+ };
20
+ const safeRelativePath = (value) => {
21
+ if (typeof value !== "string" || !value || path.isAbsolute(value) || value.includes("\\"))
22
+ throw new Error("Workspace resource manifest contains an unsafe path");
23
+ const normalized = path.posix.normalize(value);
24
+ if (normalized === "." || normalized === ".." || normalized.startsWith("../") || normalized !== value)
25
+ throw new Error("Workspace resource manifest contains an unsafe path");
26
+ return normalized;
27
+ };
28
+ const integer = (value, label) => {
29
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0)
30
+ throw new Error(`Workspace resource manifest ${label} is invalid`);
31
+ return value;
32
+ };
33
+ const exact = (value, keys) => Object.keys(value).sort().join("\0") === [...keys].sort().join("\0");
34
+ const parseManifest = (value) => {
35
+ if (!value || typeof value !== "object" || Array.isArray(value))
36
+ throw new Error("Workspace resource manifest is invalid");
37
+ const root = value;
38
+ if (!exact(root, ["version", "root", "directories", "files"]) || root.version !== WORKSPACE_RESOURCE_MANIFEST_VERSION || !Array.isArray(root.directories) || !Array.isArray(root.files) || !root.root || typeof root.root !== "object" || Array.isArray(root.root))
39
+ throw new Error("Workspace resource manifest is invalid");
40
+ const rootMetadata = root.root;
41
+ if (!exact(rootMetadata, ["gid", "mode", "uid"]))
42
+ throw new Error("Workspace resource manifest root metadata is invalid");
43
+ const files = root.files.map((raw) => {
44
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
45
+ throw new Error("Workspace resource manifest file is invalid");
46
+ const file = raw;
47
+ if (!exact(file, ["gid", "mode", "path", "sha256", "size", "uid"]) || typeof file.sha256 !== "string" || !/^sha256:[a-f0-9]{64}$/u.test(file.sha256))
48
+ throw new Error("Workspace resource manifest file is invalid");
49
+ return { gid: integer(file.gid, "file gid"), mode: integer(file.mode, "file mode"), path: safeRelativePath(file.path), sha256: file.sha256, size: integer(file.size, "file size"), uid: integer(file.uid, "file uid") };
50
+ }).sort((left, right) => left.path.localeCompare(right.path));
51
+ const directories = root.directories.map((raw) => {
52
+ if (!raw || typeof raw !== "object" || Array.isArray(raw))
53
+ throw new Error("Workspace resource manifest directory is invalid");
54
+ const directory = raw;
55
+ if (!exact(directory, ["gid", "mode", "path", "uid"]))
56
+ throw new Error("Workspace resource manifest directory is invalid");
57
+ return { gid: integer(directory.gid, "directory gid"), mode: integer(directory.mode, "directory mode"), path: safeRelativePath(directory.path), uid: integer(directory.uid, "directory uid") };
58
+ }).sort((left, right) => left.path.localeCompare(right.path));
59
+ const allPaths = [...directories.map((entry) => entry.path), ...files.map((entry) => entry.path)];
60
+ if (new Set(allPaths).size !== allPaths.length || allPaths.some((entry) => entry === METADATA_MANIFEST || entry === ACTIVATION_PROVENANCE || entry === RESOURCE_IDENTITY))
61
+ throw new Error("Workspace resource manifest contains duplicate or reserved paths");
62
+ return { version: WORKSPACE_RESOURCE_MANIFEST_VERSION, root: { gid: integer(rootMetadata.gid, "root gid"), mode: integer(rootMetadata.mode, "root mode"), uid: integer(rootMetadata.uid, "root uid") }, directories, files };
63
+ };
64
+ const inventory = async (root, relative = "") => {
65
+ const directories = [];
66
+ const files = [];
67
+ for (const entry of await readdir(path.join(root, relative), { withFileTypes: true })) {
68
+ const child = relative ? path.posix.join(relative, entry.name) : entry.name;
69
+ if (entry.isSymbolicLink())
70
+ throw new Error(`Workspace resource contains a symlink: ${child}`);
71
+ if (entry.isDirectory()) {
72
+ directories.push(child);
73
+ const nested = await inventory(root, child);
74
+ directories.push(...nested.directories);
75
+ files.push(...nested.files);
76
+ }
77
+ else if (entry.isFile())
78
+ files.push(child);
79
+ else
80
+ throw new Error(`Workspace resource contains an unsupported entry: ${child}`);
81
+ }
82
+ return { directories: directories.sort(), files: files.sort() };
83
+ };
84
+ const verifyTree = async (root, manifest, metadataDigest, internal) => {
85
+ const rootEntry = await lstat(root);
86
+ if (!rootEntry.isDirectory() || rootEntry.isSymbolicLink() || rootEntry.uid !== manifest.root.uid || rootEntry.gid !== manifest.root.gid || (rootEntry.mode & 0o7777) !== manifest.root.mode)
87
+ throw new Error("Workspace resource root metadata mismatch");
88
+ const actual = await inventory(root);
89
+ const internalFiles = new Set([METADATA_MANIFEST, ACTIVATION_PROVENANCE, RESOURCE_IDENTITY]);
90
+ const actualFiles = actual.files.filter((entry) => !internalFiles.has(entry));
91
+ if (actualFiles.join("\0") !== manifest.files.map((file) => file.path).join("\0") || actual.directories.join("\0") !== manifest.directories.map((directory) => directory.path).join("\0"))
92
+ throw new Error("Workspace resource inventory does not match its manifest");
93
+ for (const expected of manifest.directories) {
94
+ const entry = await lstat(path.join(root, expected.path));
95
+ if (!entry.isDirectory() || entry.isSymbolicLink() || entry.uid !== expected.uid || entry.gid !== expected.gid || (entry.mode & 0o7777) !== expected.mode)
96
+ throw new Error(`Workspace resource directory metadata mismatch: ${expected.path}`);
97
+ }
98
+ for (const expected of manifest.files) {
99
+ const entry = await stat(path.join(root, expected.path));
100
+ if (!entry.isFile() || entry.size !== expected.size || entry.uid !== expected.uid || entry.gid !== expected.gid || (entry.mode & 0o7777) !== expected.mode || await fileDigest(path.join(root, expected.path)) !== expected.sha256)
101
+ throw new Error(`Workspace resource checksum or metadata mismatch: ${expected.path}`);
102
+ }
103
+ if (metadataDigest !== undefined && await fileDigest(path.join(root, METADATA_MANIFEST)) !== metadataDigest)
104
+ throw new Error("Workspace resource metadata manifest checksum mismatch");
105
+ if (internal && ((await readFile(path.join(root, ACTIVATION_PROVENANCE), "utf8")) !== `${internal.activationToken}\n` || (await readFile(path.join(root, RESOURCE_IDENTITY), "utf8")) !== `${internal.resolvedIdentity}\n`))
106
+ throw new Error("Workspace resource authenticated migration identity mismatch");
107
+ };
108
+ const canonicalDestination = async (destinationPath) => {
109
+ if (!path.isAbsolute(destinationPath))
110
+ throw new Error("Workspace resource destination path must be absolute");
111
+ const resolved = path.resolve(destinationPath);
112
+ const parent = await realpath(path.dirname(resolved));
113
+ const destination = path.join(parent, path.basename(resolved));
114
+ return { destination, parent };
115
+ };
116
+ const directoryIdentity = (entry) => ({ dev: Number(entry.dev), ino: Number(entry.ino) });
117
+ const ownedDestinationIdentity = async (destination, token, expected) => {
118
+ try {
119
+ const entry = await lstat(destination);
120
+ const marker = path.join(destination, ACTIVATION_PROVENANCE);
121
+ const markerEntry = await lstat(marker);
122
+ if (!entry.isDirectory() || entry.isSymbolicLink() || !markerEntry.isFile() || markerEntry.isSymbolicLink() || (await readFile(marker, "utf8")) !== `${token}\n`)
123
+ return undefined;
124
+ const actual = directoryIdentity(entry);
125
+ return expected && (expected.dev !== actual.dev || expected.ino !== actual.ino) ? undefined : actual;
126
+ }
127
+ catch (error) {
128
+ if (error.code === "ENOENT")
129
+ return undefined;
130
+ throw error;
131
+ }
132
+ };
133
+ const writeJournal = async (journalPath, journal) => {
134
+ const bytes = `${JSON.stringify(journal)}\n`;
135
+ if (Buffer.byteLength(bytes) > MAX_JOURNAL_BYTES)
136
+ throw new Error("Workspace resource migration journal is too large");
137
+ const temporary = `${journalPath}.write-${randomUUID()}`;
138
+ const handle = await open(temporary, "wx", 0o600);
139
+ try {
140
+ await handle.writeFile(bytes);
141
+ await handle.sync();
142
+ }
143
+ finally {
144
+ await handle.close();
145
+ }
146
+ await rename(temporary, journalPath);
147
+ const parentHandle = await open(path.dirname(journalPath), "r");
148
+ try {
149
+ await parentHandle.sync();
150
+ }
151
+ finally {
152
+ await parentHandle.close();
153
+ }
154
+ };
155
+ const syncDirectory = async (directory) => { const handle = await open(directory, "r"); try {
156
+ await handle.sync();
157
+ }
158
+ finally {
159
+ await handle.close();
160
+ } };
161
+ const readJournal = async (journalPath) => {
162
+ try {
163
+ const entry = await lstat(journalPath);
164
+ if (!entry.isFile() || entry.isSymbolicLink() || entry.size < 1 || entry.size > MAX_JOURNAL_BYTES)
165
+ throw new Error("Workspace resource migration journal is invalid");
166
+ const value = JSON.parse(await readFile(journalPath, "utf8"));
167
+ const keys = ["version", "status", "migration_id", "parent", "source_basename", "destination_basename", "source_path", "destination_path", "temporary_path", "temporary_dev", "temporary_ino", "activation_token", "manifest_sha256", "resolved_identity"];
168
+ if (!value || !exact(value, keys) || value.version !== "spawnfile.workspace-resource-migration-journal.v1" || !["prepared", "activated"].includes(String(value.status)) || typeof value.migration_id !== "string" || typeof value.parent !== "string" || typeof value.source_basename !== "string" || typeof value.destination_basename !== "string" || typeof value.source_path !== "string" || typeof value.destination_path !== "string" || typeof value.temporary_path !== "string" || !Number.isSafeInteger(value.temporary_dev) || !Number.isSafeInteger(value.temporary_ino) || typeof value.activation_token !== "string" || typeof value.manifest_sha256 !== "string" || typeof value.resolved_identity !== "string")
169
+ throw new Error("Workspace resource migration journal is invalid");
170
+ return value;
171
+ }
172
+ catch (error) {
173
+ if (error.code === "ENOENT")
174
+ return undefined;
175
+ throw error;
176
+ }
177
+ };
178
+ export const migrateWorkspaceResource = async (options) => {
179
+ if (!path.isAbsolute(options.sourcePath) || !path.isAbsolute(options.manifestPath))
180
+ throw new Error("Workspace resource source and manifest paths must be absolute");
181
+ if (!/^sha256:[a-f0-9]{64}$/u.test(options.resolvedIdentity))
182
+ throw new Error("Workspace resource resolved identity is invalid");
183
+ if (options.sourceQuiesced !== true && options.hooks?.withSourceWriteFence === undefined)
184
+ throw new Error("Workspace resource migration requires explicit source quiescence or a write-fence authority");
185
+ const sourceEntry = await lstat(options.sourcePath);
186
+ const source = await realpath(options.sourcePath);
187
+ if (!sourceEntry.isDirectory() || sourceEntry.isSymbolicLink())
188
+ throw new Error("Workspace resource source must be one canonical directory");
189
+ const { destination, parent } = await canonicalDestination(options.destinationPath);
190
+ if (destination === source || destination.startsWith(`${source}${path.sep}`) || source.startsWith(`${destination}${path.sep}`))
191
+ throw new Error("Workspace resource source and destination must not overlap");
192
+ const manifestEntry = await lstat(options.manifestPath);
193
+ if (!manifestEntry.isFile() || manifestEntry.isSymbolicLink() || manifestEntry.size < 1 || manifestEntry.size > MAX_MANIFEST_BYTES)
194
+ throw new Error("Workspace resource manifest must be a bounded regular file");
195
+ const manifestBytes = await readFile(options.manifestPath);
196
+ const manifest = parseManifest(JSON.parse(manifestBytes.toString("utf8")));
197
+ if (sourceEntry.uid !== manifest.root.uid || sourceEntry.gid !== manifest.root.gid || (sourceEntry.mode & 0o7777) !== manifest.root.mode)
198
+ throw new Error("Workspace resource source owner or mode does not match its manifest");
199
+ await verifyTree(source, manifest);
200
+ const requiredBytes = BigInt(manifest.files.reduce((total, file) => total + file.size, manifestBytes.length));
201
+ const freeBytes = options.hooks?.freeBytes ?? (async (target) => { const value = await statfs(target, { bigint: true }); return value.bavail * value.bsize; });
202
+ if (await freeBytes(parent) < requiredBytes)
203
+ throw new Error("Workspace resource destination has insufficient free space");
204
+ if (options.hooks?.activate === undefined && process.platform === "linux") {
205
+ const filesystem = await statfs(parent, { bigint: true });
206
+ const localTypes = new Set([0xef53n, 0x58465342n, 0x9123683en, 0x01021994n, 0x794c7630n]);
207
+ if (!localTypes.has(filesystem.type))
208
+ throw new Error("Workspace resource migration requires unambiguous local filesystem authority");
209
+ }
210
+ const copy = options.hooks?.copy ?? (async (from, to) => await cp(from, to, { errorOnExist: true, force: false, preserveTimestamps: true, recursive: true }));
211
+ const activate = options.hooks?.activate ?? activateNoReplace;
212
+ const withSourceWriteFence = options.hooks?.withSourceWriteFence ?? (async (operation) => await operation());
213
+ const manifestSha256 = digestBytes(manifestBytes);
214
+ const journalPath = `${destination}.migration-journal.json`;
215
+ const recovered = await readJournal(journalPath);
216
+ if (recovered && (recovered.parent !== parent || recovered.source_basename !== path.basename(source) || recovered.destination_basename !== path.basename(destination) || recovered.source_path !== source || recovered.destination_path !== destination || path.dirname(recovered.temporary_path) !== parent || !path.basename(recovered.temporary_path).startsWith(`${path.basename(destination)}.migration-`) || recovered.manifest_sha256 !== manifestSha256 || recovered.resolved_identity !== options.resolvedIdentity))
217
+ throw new Error("Workspace resource migration journal does not match this migration");
218
+ let temporary = recovered?.temporary_path ?? `${destination}.migration-${randomUUID()}`;
219
+ let activationToken = recovered?.activation_token ?? randomUUID();
220
+ let migrationId = recovered?.migration_id ?? randomUUID();
221
+ let activatedIdentity = recovered ? { dev: recovered.temporary_dev, ino: recovered.temporary_ino } : undefined;
222
+ let resume = false;
223
+ if (recovered) {
224
+ const destinationOwned = await ownedDestinationIdentity(destination, activationToken, activatedIdentity);
225
+ const destinationExact = await (async () => { try {
226
+ const entry = await lstat(destination);
227
+ const actual = directoryIdentity(entry);
228
+ return actual.dev === activatedIdentity?.dev && actual.ino === activatedIdentity?.ino;
229
+ }
230
+ catch (error) {
231
+ if (error.code === "ENOENT")
232
+ return false;
233
+ throw error;
234
+ } })();
235
+ if (destinationOwned || (recovered.status === "activated" && destinationExact && await readFile(path.join(destination, RESOURCE_IDENTITY), "utf8") === `${options.resolvedIdentity}\n`)) {
236
+ await verifyTree(destination, manifest, manifestSha256, destinationOwned ? { activationToken, resolvedIdentity: options.resolvedIdentity } : undefined);
237
+ await writeJournal(journalPath, { ...recovered, status: "activated" });
238
+ await rm(path.join(destination, ACTIVATION_PROVENANCE), { force: true });
239
+ return { version: WORKSPACE_RESOURCE_MIGRATION_VERSION, active_path: destination, destination_path: destination, manifest_sha256: manifestSha256, rollback: false, source_path: source, source_retained: true, status: "activated" };
240
+ }
241
+ if (await ownedDestinationIdentity(temporary, activationToken, activatedIdentity)) {
242
+ await verifyTree(temporary, manifest, manifestSha256, { activationToken, resolvedIdentity: options.resolvedIdentity });
243
+ resume = true;
244
+ }
245
+ else
246
+ throw new Error("Workspace resource migration journal has no recoverable owned state");
247
+ }
248
+ else {
249
+ try {
250
+ await lstat(destination);
251
+ throw new Error("Workspace resource destination already exists");
252
+ }
253
+ catch (error) {
254
+ if (error.code !== "ENOENT")
255
+ throw error;
256
+ }
257
+ }
258
+ try {
259
+ if (!resume) {
260
+ await copy(source, temporary);
261
+ await mkdir(temporary, { recursive: true });
262
+ await writeFile(path.join(temporary, METADATA_MANIFEST), manifestBytes, { flag: "wx", mode: 0o600 });
263
+ await writeFile(path.join(temporary, ACTIVATION_PROVENANCE), `${activationToken}\n`, { flag: "wx", mode: 0o600 });
264
+ await writeFile(path.join(temporary, RESOURCE_IDENTITY), `${options.resolvedIdentity}\n`, { flag: "wx", mode: 0o600 });
265
+ await options.hooks?.afterCopy?.(temporary);
266
+ await verifyTree(temporary, manifest, manifestSha256, { activationToken, resolvedIdentity: options.resolvedIdentity });
267
+ activatedIdentity = directoryIdentity(await lstat(temporary));
268
+ }
269
+ if (!activatedIdentity)
270
+ throw new Error("Workspace resource temporary identity is unavailable");
271
+ const journal = { version: "spawnfile.workspace-resource-migration-journal.v1", status: "prepared", migration_id: migrationId, parent, source_basename: path.basename(source), destination_basename: path.basename(destination), source_path: source, destination_path: destination, temporary_path: temporary, temporary_dev: activatedIdentity.dev, temporary_ino: activatedIdentity.ino, activation_token: activationToken, manifest_sha256: manifestSha256, resolved_identity: options.resolvedIdentity };
272
+ await writeJournal(journalPath, journal);
273
+ await withSourceWriteFence(async () => {
274
+ const currentSource = await lstat(source);
275
+ if (currentSource.dev !== sourceEntry.dev || currentSource.ino !== sourceEntry.ino)
276
+ throw new Error("Workspace resource source identity changed before activation");
277
+ await verifyTree(source, manifest);
278
+ await options.hooks?.beforeActivation?.(destination);
279
+ await activate(temporary, destination);
280
+ await syncDirectory(parent);
281
+ });
282
+ if (await ownedDestinationIdentity(destination, activationToken, activatedIdentity) === undefined)
283
+ throw new Error("Workspace resource activation provenance is unavailable");
284
+ await verifyTree(destination, manifest, manifestSha256, { activationToken, resolvedIdentity: options.resolvedIdentity });
285
+ await writeJournal(journalPath, { ...journal, status: "activated" });
286
+ await options.hooks?.afterActivation?.(destination);
287
+ await rm(path.join(destination, ACTIVATION_PROVENANCE));
288
+ return { version: WORKSPACE_RESOURCE_MIGRATION_VERSION, active_path: destination, destination_path: destination, manifest_sha256: manifestSha256, rollback: false, source_path: source, source_retained: true, status: "activated" };
289
+ }
290
+ catch (error) {
291
+ const owned = await ownedDestinationIdentity(destination, activationToken, activatedIdentity);
292
+ if (owned === undefined) {
293
+ await rm(temporary, { force: true, recursive: true });
294
+ await rm(journalPath, { force: true });
295
+ throw error;
296
+ }
297
+ await rm(destination, { force: true, recursive: true });
298
+ await rm(journalPath, { force: true });
299
+ return { version: WORKSPACE_RESOURCE_MIGRATION_VERSION, active_path: source, destination_path: destination, manifest_sha256: manifestSha256, rollback: true, source_path: source, source_retained: true, status: "rolled_back" };
300
+ }
301
+ };
302
+ export const buildWorkspaceResourceManifest = async (sourcePath) => {
303
+ const source = await realpath(sourcePath);
304
+ const root = await stat(source);
305
+ const entries = await inventory(source);
306
+ const directories = await Promise.all(entries.directories.map(async (relative) => {
307
+ const entry = await lstat(path.join(source, relative));
308
+ return { gid: entry.gid, mode: entry.mode & 0o7777, path: relative, uid: entry.uid };
309
+ }));
310
+ const files = await Promise.all(entries.files.map(async (relative) => {
311
+ const entry = await stat(path.join(source, relative));
312
+ return { gid: entry.gid, mode: entry.mode & 0o7777, path: relative, sha256: await fileDigest(path.join(source, relative)), size: entry.size, uid: entry.uid };
313
+ }));
314
+ return { version: WORKSPACE_RESOURCE_MANIFEST_VERSION, root: { gid: root.gid, mode: root.mode & 0o7777, uid: root.uid }, directories, files };
315
+ };
@@ -26,6 +26,13 @@ export interface DevStopProjectResult {
26
26
  outputDirectory: string;
27
27
  }
28
28
  export declare const resolveDevOutputDirectory: (inputPath: string, outputDirectory?: string) => Promise<string>;
29
+ /**
30
+ * A dev deployment gets its own lineage namespace so it can never resolve to
31
+ * the derived volumes of a production `spawnfile up` of the same project —
32
+ * before this, both defaulted to the lineage `default` and dev wrote into
33
+ * production's state whenever production was stopped. The deployment NAME is
34
+ * untouched, so dev records, labels, and `dev stop --deployment` are unchanged.
35
+ */
29
36
  export declare const devUpProject: (inputPath: string, options?: UpProjectOptions) => Promise<UpProjectResult>;
30
37
  export declare const selectDeploymentRecord: (outputDirectory: string, deploymentName?: string) => Promise<DeploymentRecord>;
31
38
  export declare const devApplyProject: (inputPath: string, options: DevApplyProjectOptions) => Promise<DevApplyProjectResult>;
@@ -3,6 +3,7 @@ import { readFile } from "node:fs/promises";
3
3
  import { buildCompilePlan, upProject } from "../compiler/index.js";
4
4
  import { listDeploymentRecords, normalizeDeploymentName } from "../deployment/index.js";
5
5
  import { SpawnfileError } from "../shared/index.js";
6
+ import { DEV_DEPLOYMENT_LINEAGE_NAMESPACE } from "../compiler/deploymentLineage.js";
6
7
  import { chownContainerPaths, compileForDevApply, copyIntoContainer, defaultExecFile, dockerArgsForRecord, ensureContainerDirectories, firstContainerName, runDocker } from "./docker.js";
7
8
  const DEV_OUTPUT_DIRECTORY = ".spawn-dev";
8
9
  export const PI_CONTROL_URL = "http://127.0.0.1:19690";
@@ -13,8 +14,16 @@ export const resolveDevOutputDirectory = async (inputPath, outputDirectory) => {
13
14
  const plan = await buildCompilePlan(inputPath);
14
15
  return path.join(path.dirname(plan.root), DEV_OUTPUT_DIRECTORY);
15
16
  };
17
+ /**
18
+ * A dev deployment gets its own lineage namespace so it can never resolve to
19
+ * the derived volumes of a production `spawnfile up` of the same project —
20
+ * before this, both defaulted to the lineage `default` and dev wrote into
21
+ * production's state whenever production was stopped. The deployment NAME is
22
+ * untouched, so dev records, labels, and `dev stop --deployment` are unchanged.
23
+ */
16
24
  export const devUpProject = async (inputPath, options = {}) => upProject(inputPath, {
17
25
  ...options,
26
+ deploymentLineageNamespace: DEV_DEPLOYMENT_LINEAGE_NAMESPACE,
18
27
  detach: true,
19
28
  outputDirectory: await resolveDevOutputDirectory(inputPath, options.outputDirectory)
20
29
  });
@@ -4,6 +4,8 @@ import type { ResolvedAuthProfile } from "../auth/index.js";
4
4
  export interface ConsumeImageUpOptions {
5
5
  authProfile?: ResolvedAuthProfile | null;
6
6
  authValues?: Record<string, string>;
7
+ /** See `ImageRuntimeAuthInput.daimonContainerCredentialUid`. */
8
+ daimonContainerCredentialUid?: number;
7
9
  authProfileName?: string | null;
8
10
  deploymentName?: string;
9
11
  dockerCommand?: string;
@@ -1,10 +1,12 @@
1
1
  import os from "node:os";
2
2
  import path from "node:path";
3
3
  import { mkdtemp, rm, writeFile } from "node:fs/promises";
4
- import { acquireHomeDeploymentLock, createDockerDeploymentLabels, homeDeploymentExists, normalizeDeploymentName, readHomeDeploymentRecord, resolveDockerDeploymentTarget, verifyDockerDeploymentTarget, writeHomeDeployment } from "../deployment/index.js";
4
+ import { acquireHomeDeploymentLock, captureCandidateDiagnostics, createDockerDeploymentLabels, homeDeploymentExists, normalizeDeploymentName, readHomeDeploymentRecord, resolveDockerDeploymentTarget, sanitizeCandidateDiagnostic, verifyDockerDeploymentTarget, writeHomeDeployment } from "../deployment/index.js";
5
5
  import { SpawnfileError } from "../shared/index.js";
6
- import { deriveDeploymentName, deriveVolumeName, renderEnvFileContent, resolveImageEnvironment } from "./consumeImageSupport.js";
6
+ import { deriveDeploymentName, derivePersistentMountVolumeName, renderEnvFileContent, resolveImageEnvironment } from "./consumeImageSupport.js";
7
+ import { acquireExclusiveVolumeReservations, assertCandidateContainerReady, assertContainerStopped, inspectContainerSnapshot, restorePreviousContainer, rollbackCandidateContainer } from "./consumeImageLifecycle.js";
7
8
  import { createConsumerDockerRunner } from "./dockerRunner.js";
9
+ import { resolveDaimonDockerSecurityArgsForImage } from "./consumeImageDaimonDocker.js";
8
10
  import { extractImageReport, resolveDockerBaseArgs } from "./extractImage.js";
9
11
  import { parseImageReference } from "./imageRef.js";
10
12
  import { prepareImageRuntimeAuthMounts } from "./imageRuntimeAuth.js";
@@ -35,15 +37,6 @@ const resolveRegistryDigest = async (imageRef, runDocker) => {
35
37
  return null;
36
38
  }
37
39
  };
38
- const containerExists = async (runDocker, containerName) => {
39
- try {
40
- await runDocker(["container", "inspect", containerName]);
41
- return true;
42
- }
43
- catch {
44
- return false;
45
- }
46
- };
47
40
  const resolveLocalImageId = async (imageRef, runDocker) => {
48
41
  try {
49
42
  const raw = (await runDocker([
@@ -131,6 +124,7 @@ const consumeImageUpLocked = async (imageRef, parsedRef, deploymentName, isExpli
131
124
  // port for two containers at once. There is a brief restart gap, unavoidable
132
125
  // when reusing host ports without a proxy.
133
126
  const backupName = `${containerName}-previous-${Date.now().toString(36)}`;
127
+ let volumeReservation;
134
128
  try {
135
129
  await writeFile(envFilePath, renderEnvFileContent(env), "utf8");
136
130
  // Prepare import-based model auth (the consumer's Claude/Codex login) and
@@ -138,24 +132,41 @@ const consumeImageUpLocked = async (imageRef, parsedRef, deploymentName, isExpli
138
132
  // config is already baked into the image; this only resolves the credential
139
133
  // mounts. Doing it first guarantees an unusable import fails while the live
140
134
  // container is still untouched, never mid-swap.
141
- const authMountArgs = options.authProfile && availableImports.length > 0
142
- ? (await prepareImageRuntimeAuthMounts({
143
- authProfile: options.authProfile,
144
- report,
145
- tempRoot: workDir
146
- })).mountArgs
147
- : [];
148
- const liveExists = await containerExists(runDocker, containerName);
149
- if (liveExists) {
135
+ const authMountArgs = (await prepareImageRuntimeAuthMounts({
136
+ authProfile: options.authProfile ?? null,
137
+ ...(options.daimonContainerCredentialUid === undefined
138
+ ? {}
139
+ : { daimonContainerCredentialUid: options.daimonContainerCredentialUid }),
140
+ report,
141
+ tempRoot: workDir
142
+ })).mountArgs;
143
+ const daimonDockerSecurityArgs = await resolveDaimonDockerSecurityArgsForImage(imageRef, report, runDocker, workDir);
144
+ volumeReservation = await acquireExclusiveVolumeReservations(report, deploymentName, containerName, imageRef, runDocker);
145
+ const previousContainer = await inspectContainerSnapshot(runDocker, containerName);
146
+ if (previousContainer !== null) {
150
147
  await runDocker(["rename", containerName, backupName]);
151
- await runDocker(["stop", backupName]).catch(() => undefined);
148
+ try {
149
+ await runDocker(["stop", backupName]);
150
+ await assertContainerStopped(runDocker, backupName, previousContainer.id);
151
+ }
152
+ catch (error) {
153
+ try {
154
+ await restorePreviousContainer(runDocker, previousContainer, backupName, containerName);
155
+ }
156
+ catch {
157
+ throw new SpawnfileError("runtime_error", "Prior deployment stop failed and its original state could not be restored");
158
+ }
159
+ throw error;
160
+ }
152
161
  }
153
- const runArgs = ["run", "-d", "--name", containerName, "--env-file", envFilePath];
162
+ const runArgs = [
163
+ "run", "-d", "--name", containerName, ...daimonDockerSecurityArgs, "--env-file", envFilePath
164
+ ];
154
165
  for (const port of report.ports) {
155
166
  runArgs.push("-p", `${port}:${port}`);
156
167
  }
157
168
  for (const mount of report.persistent_mounts) {
158
- runArgs.push("-v", `${deriveVolumeName(deploymentName, mount.id)}:${mount.target}`);
169
+ runArgs.push("-v", `${derivePersistentMountVolumeName(deploymentName, mount)}:${mount.target}`);
159
170
  }
160
171
  runArgs.push(...authMountArgs);
161
172
  const labels = createDockerDeploymentLabels({
@@ -169,63 +180,77 @@ const consumeImageUpLocked = async (imageRef, parsedRef, deploymentName, isExpli
169
180
  runArgs.push("--label", `${name}=${value}`);
170
181
  }
171
182
  runArgs.push(imageRef);
172
- let runOutput;
183
+ let candidateId;
173
184
  try {
174
- runOutput = (await runDocker(runArgs)).toString("utf8").trim();
185
+ const runOutput = (await runDocker(runArgs)).toString("utf8").trim();
186
+ const observedId = runOutput.split("\n").pop()?.trim();
187
+ if (!observedId || !/^[a-f0-9]{64}$/u.test(observedId)) {
188
+ throw new SpawnfileError("runtime_error", "Candidate container returned invalid identity");
189
+ }
190
+ candidateId = observedId;
191
+ await assertCandidateContainerReady(runDocker, candidateId, containerName);
192
+ const imageId = await resolveLocalImageId(imageRef, runDocker);
193
+ const digest = await resolveRegistryDigest(imageRef, runDocker);
194
+ const record = {
195
+ auth_profile: options.authProfileName ?? null,
196
+ compile_fingerprint: inspection.compileFingerprint,
197
+ created_at: new Date().toISOString(),
198
+ ...(options.envFilePath ? { env_file: path.resolve(options.envFilePath) } : {}),
199
+ manager: "docker",
200
+ name: deploymentName,
201
+ output_directory: null,
202
+ source: { digest, kind: "image", ref: imageRef },
203
+ target,
204
+ units: [
205
+ {
206
+ container_id: candidateId,
207
+ container_name: containerName,
208
+ contains: buildContainsEntries(report),
209
+ id: unitIdFor(deploymentName),
210
+ image_id: imageId,
211
+ image_tag: imageRef,
212
+ kind: "container",
213
+ runtime_instances: report.runtime_instances.map((instance) => instance.id).sort()
214
+ }
215
+ ],
216
+ version: "spawnfile.deployment.v2"
217
+ };
218
+ const written = await writeHomeDeployment(record, report);
219
+ if (previousContainer !== null) {
220
+ await runDocker(["rm", "-f", previousContainer.id]).catch(() => undefined);
221
+ }
222
+ return {
223
+ containerName,
224
+ deploymentName,
225
+ imageRef,
226
+ previous,
227
+ record,
228
+ recordPath: written.recordPath
229
+ };
175
230
  }
176
231
  catch (error) {
177
- // The new container failed to start; remove the failed attempt and restore
178
- // the previous deployment so a failed redeploy never loses the live one.
179
- await runDocker(["rm", "-f", containerName]).catch(() => undefined);
180
- if (liveExists) {
181
- await runDocker(["rename", backupName, containerName]).catch(() => undefined);
182
- await runDocker(["start", containerName]).catch(() => undefined);
232
+ const diagnostics = candidateId ? await captureCandidateDiagnostics({
233
+ candidateId, deploymentName, runDocker, secretValues: Object.values(env)
234
+ }) : null;
235
+ const detail = diagnostics ? ` (${diagnostics.summary}); ${diagnostics.path
236
+ ? `private diagnostics: ${diagnostics.path}` : "private diagnostics unavailable"}` : "";
237
+ const failure = (cause) => new SpawnfileError("runtime_error", sanitizeCandidateDiagnostic(cause instanceof Error ? cause.message : String(cause), Object.values(env)) + detail);
238
+ try {
239
+ await rollbackCandidateContainer(runDocker, candidateId, containerName, previousContainer, backupName);
183
240
  }
184
- throw error;
185
- }
186
- // The new container is up — discard the previous one.
187
- if (liveExists) {
188
- await runDocker(["rm", "-f", backupName]).catch(() => undefined);
241
+ catch (rollbackError) {
242
+ throw failure(rollbackError);
243
+ }
244
+ throw failure(error);
189
245
  }
190
- const containerId = runOutput.split("\n").pop()?.trim() || null;
191
- const imageId = await resolveLocalImageId(imageRef, runDocker);
192
- const digest = await resolveRegistryDigest(imageRef, runDocker);
193
- const record = {
194
- auth_profile: options.authProfileName ?? null,
195
- compile_fingerprint: inspection.compileFingerprint,
196
- created_at: new Date().toISOString(),
197
- ...(options.envFilePath ? { env_file: path.resolve(options.envFilePath) } : {}),
198
- manager: "docker",
199
- name: deploymentName,
200
- output_directory: null,
201
- source: { digest, kind: "image", ref: imageRef },
202
- target,
203
- units: [
204
- {
205
- container_id: containerId,
206
- container_name: containerName,
207
- contains: buildContainsEntries(report),
208
- id: unitIdFor(deploymentName),
209
- image_id: imageId,
210
- image_tag: imageRef,
211
- kind: "container",
212
- runtime_instances: report.runtime_instances.map((instance) => instance.id).sort()
213
- }
214
- ],
215
- version: "spawnfile.deployment.v2"
216
- };
217
- const written = await writeHomeDeployment(record, report);
218
- return {
219
- containerName,
220
- deploymentName,
221
- imageRef,
222
- previous,
223
- record,
224
- recordPath: written.recordPath
225
- };
226
246
  }
227
247
  finally {
228
- await rm(workDir, { force: true, recursive: true }).catch(() => undefined);
248
+ try {
249
+ await volumeReservation?.release();
250
+ }
251
+ finally {
252
+ await rm(workDir, { force: true, recursive: true }).catch(() => undefined);
253
+ }
229
254
  }
230
255
  };
231
256
  const readPreviousSource = async (deploymentName) => {
@@ -0,0 +1,3 @@
1
+ import type { DockerCommandRunner } from "./dockerRunner.js";
2
+ import type { DistributionReport } from "./types.js";
3
+ export declare const resolveDaimonDockerSecurityArgsForImage: (imageRef: string, report: DistributionReport, runDocker: DockerCommandRunner, securityDirectory: string) => Promise<string[]>;
@@ -0,0 +1,45 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { SpawnfileError } from "../shared/errors.js";
3
+ import { DAIMON_DOCKER_RUNTIME_SECURITY_ARGS, daimonEngineDockerSecurityArgsForConfigs, materializeDaimonGrokSeccompProfile } from "../shared/daimonCodexDocker.js";
4
+ import { extractSingleFileFromTar } from "./tarReader.js";
5
+ const DAIMON_CONFIG_SIZE_CAP_BYTES = 4 * 1024 * 1024;
6
+ const daimonInstancesFrom = (report) => report.runtime_instances.filter((instance) => instance.runtime === "daimon");
7
+ const assertAbsoluteConfigPath = (instance) => {
8
+ if (!instance.config_path.startsWith("/")) {
9
+ throw new SpawnfileError("validation_error", "Daimon runtime instance has a non-absolute generated config path");
10
+ }
11
+ return instance.config_path;
12
+ };
13
+ const readDaimonConfigSourcesFromImage = async (imageRef, instances, runDocker) => {
14
+ const helperName = `spawnfile-daimon-config-${randomUUID()}`;
15
+ await runDocker(["create", "--name", helperName, imageRef]);
16
+ try {
17
+ const sources = [];
18
+ for (const instance of instances) {
19
+ let tar;
20
+ try {
21
+ tar = await runDocker(["cp", `${helperName}:${assertAbsoluteConfigPath(instance)}`, "-"]);
22
+ }
23
+ catch (error) {
24
+ if (error instanceof SpawnfileError)
25
+ throw error;
26
+ throw new SpawnfileError("validation_error", "Could not read Daimon's generated organization config before Docker launch");
27
+ }
28
+ sources.push(extractSingleFileFromTar(tar, { maxBytes: DAIMON_CONFIG_SIZE_CAP_BYTES }).toString("utf8"));
29
+ }
30
+ return sources;
31
+ }
32
+ finally {
33
+ await runDocker(["rm", "-f", helperName]).catch(() => undefined);
34
+ }
35
+ };
36
+ export const resolveDaimonDockerSecurityArgsForImage = async (imageRef, report, runDocker, securityDirectory) => {
37
+ const daimonInstances = daimonInstancesFrom(report);
38
+ if (daimonInstances.length === 0)
39
+ return [];
40
+ const sources = await readDaimonConfigSourcesFromImage(imageRef, daimonInstances, runDocker);
41
+ return [
42
+ ...DAIMON_DOCKER_RUNTIME_SECURITY_ARGS,
43
+ ...(await daimonEngineDockerSecurityArgsForConfigs(sources, () => materializeDaimonGrokSeccompProfile(securityDirectory)))
44
+ ];
45
+ };