spawnfile 0.1.17 → 0.1.18

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 (489) hide show
  1. package/README.md +1 -1
  2. package/dist/auth/importers.js +21 -5
  3. package/dist/auth/index.d.ts +1 -0
  4. package/dist/auth/index.js +1 -0
  5. package/dist/auth/profileStore.js +4 -1
  6. package/dist/auth/trainingGrokWriteback.d.ts +4 -0
  7. package/dist/auth/trainingGrokWriteback.js +119 -0
  8. package/dist/auth/trainingGrokWritebackLock.d.ts +5 -0
  9. package/dist/auth/trainingGrokWritebackLock.js +56 -0
  10. package/dist/cli/authCommands.js +9 -5
  11. package/dist/cli/compileBuildCommands.js +4 -0
  12. package/dist/cli/devCommands.js +4 -2
  13. package/dist/cli/downCommand.d.ts +2 -0
  14. package/dist/cli/downCommand.js +3 -0
  15. package/dist/cli/envFileOption.d.ts +18 -0
  16. package/dist/cli/envFileOption.js +20 -0
  17. package/dist/cli/lifecycleCommands.d.ts +1 -1
  18. package/dist/cli/lifecycleCommands.js +3 -1
  19. package/dist/cli/lifecyclePlan.d.ts +1 -0
  20. package/dist/cli/lifecyclePlan.js +2 -0
  21. package/dist/cli/paideiaDelegation.d.ts +2 -1
  22. package/dist/cli/paideiaDelegation.js +5 -4
  23. package/dist/cli/recordCommands.d.ts +17 -0
  24. package/dist/cli/recordCommands.js +43 -0
  25. package/dist/cli/releaseCommand.d.ts +6 -0
  26. package/dist/cli/releaseCommand.js +91 -0
  27. package/dist/cli/runCli.d.ts +7 -1
  28. package/dist/cli/runCli.js +11 -6
  29. package/dist/cli/runPublishCommands.js +5 -3
  30. package/dist/cli/trainCommand.js +73 -20
  31. package/dist/cli/upCommand.js +5 -1
  32. package/dist/cli/volumeCommands.d.ts +8 -0
  33. package/dist/cli/volumeCommands.js +53 -0
  34. package/dist/compiler/agentNodeMerge.js +3 -2
  35. package/dist/compiler/buildCompilePlan.js +4 -0
  36. package/dist/compiler/buildCompilePlanAgent.js +3 -1
  37. package/dist/compiler/buildCompilePlanTraversal.js +2 -0
  38. package/dist/compiler/buildCompilePlanTraversalHelpers.d.ts +2 -2
  39. package/dist/compiler/buildCompilePlanTraversalHelpers.js +4 -3
  40. package/dist/compiler/buildProject.d.ts +10 -0
  41. package/dist/compiler/buildProject.js +14 -2
  42. package/dist/compiler/cleanCompileOutput.d.ts +2 -0
  43. package/dist/compiler/cleanCompileOutput.js +14 -0
  44. package/dist/compiler/compilePlanHelpers.js +2 -0
  45. package/dist/compiler/compileProject.d.ts +10 -0
  46. package/dist/compiler/compileProject.js +29 -3
  47. package/dist/compiler/containerArtifactSummaries.js +1 -0
  48. package/dist/compiler/containerArtifacts.d.ts +4 -4
  49. package/dist/compiler/containerArtifacts.js +18 -34
  50. package/dist/compiler/containerArtifactsPlans.js +7 -0
  51. package/dist/compiler/containerArtifactsTypes.d.ts +7 -0
  52. package/dist/compiler/containerDaimonBrokerRender.d.ts +3 -1
  53. package/dist/compiler/containerDaimonBrokerRender.js +6 -3
  54. package/dist/compiler/containerDaimonGrokTaskClock.d.ts +5 -0
  55. package/dist/compiler/containerDaimonGrokTaskClock.js +29 -0
  56. package/dist/compiler/containerDaimonGrokWorkerProvisioning.d.ts +1 -1
  57. package/dist/compiler/containerDaimonGrokWorkerProvisioning.js +38 -16
  58. package/dist/compiler/containerDaimonGrokWorkerRender.d.ts +33 -8
  59. package/dist/compiler/containerDaimonGrokWorkerRender.js +18 -5
  60. package/dist/compiler/containerDaimonOwnershipGuardRender.d.ts +14 -1
  61. package/dist/compiler/containerDaimonOwnershipGuardRender.js +15 -2
  62. package/dist/compiler/containerDaimonUidEntrypointRender.js +6 -12
  63. package/dist/compiler/containerTargetResources.d.ts +10 -0
  64. package/dist/compiler/containerTargetResources.js +21 -13
  65. package/dist/compiler/containerWorkspaceResourceRender.js +4 -1
  66. package/dist/compiler/index.d.ts +2 -0
  67. package/dist/compiler/index.js +2 -0
  68. package/dist/compiler/mcpPlaceholders.d.ts +11 -0
  69. package/dist/compiler/mcpPlaceholders.js +58 -0
  70. package/dist/compiler/mcpServerInheritance.d.ts +18 -0
  71. package/dist/compiler/mcpServerInheritance.js +43 -0
  72. package/dist/compiler/moltnetArtifactTypes.d.ts +1 -0
  73. package/dist/compiler/moltnetArtifacts.js +1 -0
  74. package/dist/compiler/preflightCompilePlan.d.ts +9 -0
  75. package/dist/compiler/preflightCompilePlan.js +38 -0
  76. package/dist/compiler/recordingAgentFacts.d.ts +4 -0
  77. package/dist/compiler/recordingAgentFacts.js +35 -0
  78. package/dist/compiler/recordingCapability.d.ts +4 -0
  79. package/dist/compiler/recordingCapability.js +22 -0
  80. package/dist/compiler/recordingReport.d.ts +4 -0
  81. package/dist/compiler/recordingReport.js +18 -0
  82. package/dist/compiler/runProject.d.ts +2 -1
  83. package/dist/compiler/runProject.js +2 -0
  84. package/dist/compiler/surfaces.d.ts +1 -2
  85. package/dist/compiler/surfaces.js +0 -1
  86. package/dist/compiler/syncProjectAuth.js +2 -1
  87. package/dist/compiler/training/broker/clockProbe.d.ts +6 -0
  88. package/dist/compiler/training/broker/clockProbe.js +27 -0
  89. package/dist/compiler/training/broker/declaration.d.ts +4 -2
  90. package/dist/compiler/training/broker/declaration.js +4 -2
  91. package/dist/compiler/training/broker/entrypoint.js +33 -18
  92. package/dist/compiler/training/broker/evaluatorSecrets.d.ts +2 -0
  93. package/dist/compiler/training/broker/evaluatorSecrets.js +60 -0
  94. package/dist/compiler/training/broker/index.d.ts +3 -2
  95. package/dist/compiler/training/broker/index.js +3 -2
  96. package/dist/compiler/training/broker/main.js +1 -1
  97. package/dist/compiler/training/broker/paths.d.ts +96 -56
  98. package/dist/compiler/training/broker/paths.js +97 -89
  99. package/dist/compiler/training/broker/processes.d.ts +9 -0
  100. package/dist/compiler/training/broker/processes.js +4 -1
  101. package/dist/compiler/training/broker/projection.d.ts +3 -2
  102. package/dist/compiler/training/broker/projection.js +21 -9
  103. package/dist/compiler/training/broker/provisioning.d.ts +6 -15
  104. package/dist/compiler/training/broker/provisioning.js +71 -53
  105. package/dist/compiler/training/broker/registration.d.ts +3 -1
  106. package/dist/compiler/training/broker/registration.js +29 -21
  107. package/dist/compiler/training/broker/reset.d.ts +9 -0
  108. package/dist/compiler/training/broker/reset.js +71 -0
  109. package/dist/compiler/training/broker/runtime.d.ts +10 -13
  110. package/dist/compiler/training/broker/runtime.js +69 -115
  111. package/dist/compiler/training/broker/supervisor.d.ts +10 -11
  112. package/dist/compiler/training/broker/supervisor.js +22 -23
  113. package/dist/compiler/training/broker/taskClock.d.ts +5 -0
  114. package/dist/compiler/training/broker/taskClock.js +41 -0
  115. package/dist/compiler/training/compiledAgent.d.ts +21 -0
  116. package/dist/compiler/training/compiledAgent.js +62 -0
  117. package/dist/compiler/training/container/contract.d.ts +23 -0
  118. package/dist/compiler/training/container/contract.js +23 -5
  119. package/dist/compiler/training/container/evaluators.d.ts +48 -0
  120. package/dist/compiler/training/container/evaluators.js +50 -0
  121. package/dist/compiler/training/container/grokWriteback.d.ts +8 -0
  122. package/dist/compiler/training/container/grokWriteback.js +26 -0
  123. package/dist/compiler/training/container/index.d.ts +2 -1
  124. package/dist/compiler/training/container/index.js +2 -1
  125. package/dist/compiler/training/container/launch.d.ts +3 -0
  126. package/dist/compiler/training/container/launch.js +119 -28
  127. package/dist/compiler/training/container/nativeSlots.d.ts +14 -0
  128. package/dist/compiler/training/container/nativeSlots.js +13 -0
  129. package/dist/compiler/training/container/outputCopy.d.ts +2 -0
  130. package/dist/compiler/training/container/outputCopy.js +72 -0
  131. package/dist/compiler/training/container/outputVolume.d.ts +27 -0
  132. package/dist/compiler/training/container/outputVolume.js +161 -0
  133. package/dist/compiler/training/container/prepare.d.ts +3 -1
  134. package/dist/compiler/training/container/prepare.js +57 -12
  135. package/dist/compiler/training/container/security.d.ts +5 -3
  136. package/dist/compiler/training/container/security.js +15 -5
  137. package/dist/compiler/training/container/subjectIsolation.d.ts +5 -0
  138. package/dist/compiler/training/container/subjectIsolation.js +15 -0
  139. package/dist/compiler/training/context.d.ts +8 -0
  140. package/dist/compiler/training/context.js +12 -12
  141. package/dist/compiler/training/contract.d.ts +2 -0
  142. package/dist/compiler/training/contract.js +2 -0
  143. package/dist/compiler/training/execution.d.ts +417 -0
  144. package/dist/compiler/training/execution.js +160 -0
  145. package/dist/compiler/training/index.d.ts +8 -0
  146. package/dist/compiler/training/index.js +7 -0
  147. package/dist/compiler/training/moments.d.ts +80 -0
  148. package/dist/compiler/training/moments.js +118 -0
  149. package/dist/compiler/training/output.d.ts +2 -0
  150. package/dist/compiler/training/output.js +20 -0
  151. package/dist/compiler/training/plan/contract.d.ts +287 -0
  152. package/dist/compiler/training/plan/contract.js +49 -0
  153. package/dist/compiler/training/plan/index.d.ts +5 -0
  154. package/dist/compiler/training/plan/index.js +4 -0
  155. package/dist/compiler/training/plan/load.d.ts +9 -0
  156. package/dist/compiler/training/plan/load.js +153 -0
  157. package/dist/compiler/training/plan/references.d.ts +19 -0
  158. package/dist/compiler/training/plan/references.js +57 -0
  159. package/dist/compiler/training/plan/resolve.d.ts +4 -0
  160. package/dist/compiler/training/plan/resolve.js +73 -0
  161. package/dist/compiler/training/plan/targets.d.ts +11 -0
  162. package/dist/compiler/training/plan/targets.js +71 -0
  163. package/dist/compiler/training/plan/types.d.ts +36 -0
  164. package/dist/compiler/training/plan/types.js +1 -0
  165. package/dist/compiler/training/preparation/assets/Dockerfile +13 -2
  166. package/dist/compiler/training/preparation/assets/package-lock.json +2 -2
  167. package/dist/compiler/training/preparation/broker.d.ts +3 -3
  168. package/dist/compiler/training/preparation/broker.js +6 -4
  169. package/dist/compiler/training/preparation/contract.d.ts +27 -2
  170. package/dist/compiler/training/preparation/contract.js +23 -4
  171. package/dist/compiler/training/preparation/files.d.ts +5 -1
  172. package/dist/compiler/training/preparation/files.js +76 -15
  173. package/dist/compiler/training/preparation/image.js +9 -4
  174. package/dist/compiler/training/preparation/inputs.d.ts +1 -0
  175. package/dist/compiler/training/preparation/inputs.js +18 -10
  176. package/dist/compiler/training/preparation/prepare.d.ts +5 -0
  177. package/dist/compiler/training/preparation/prepare.js +66 -29
  178. package/dist/compiler/training/preparation/scratch.d.ts +6 -17
  179. package/dist/compiler/training/preparation/scratch.js +89 -23
  180. package/dist/compiler/training/repair/contract.d.ts +338 -4
  181. package/dist/compiler/training/repair/contract.js +2 -0
  182. package/dist/compiler/training/repair/index.d.ts +1 -1
  183. package/dist/compiler/training/repair/index.js +1 -1
  184. package/dist/compiler/training/repair/prepare.d.ts +155 -3
  185. package/dist/compiler/training/repair/prepare.js +6 -2
  186. package/dist/compiler/training/repair/witness.d.ts +152 -3
  187. package/dist/compiler/training/repair/witness.js +8 -2
  188. package/dist/compiler/training/resolution.d.ts +25 -0
  189. package/dist/compiler/training/resolution.js +69 -0
  190. package/dist/compiler/training/rewind/contract.d.ts +321 -0
  191. package/dist/compiler/training/rewind/contract.js +39 -0
  192. package/dist/compiler/training/rewind/deployedResource.d.ts +22 -0
  193. package/dist/compiler/training/rewind/deployedResource.js +19 -0
  194. package/dist/compiler/training/rewind/feed.d.ts +12 -0
  195. package/dist/compiler/training/rewind/feed.js +182 -0
  196. package/dist/compiler/training/rewind/feedContent.d.ts +6 -0
  197. package/dist/compiler/training/rewind/feedContent.js +38 -0
  198. package/dist/compiler/training/rewind/git.d.ts +8 -0
  199. package/dist/compiler/training/rewind/git.js +159 -0
  200. package/dist/compiler/training/rewind/gitArchive.d.ts +2 -0
  201. package/dist/compiler/training/rewind/gitArchive.js +7 -0
  202. package/dist/compiler/training/rewind/gitHistory.d.ts +3 -0
  203. package/dist/compiler/training/rewind/gitHistory.js +55 -0
  204. package/dist/compiler/training/rewind/gitProcess.d.ts +19 -0
  205. package/dist/compiler/training/rewind/gitProcess.js +81 -0
  206. package/dist/compiler/training/rewind/gitTree.d.ts +14 -0
  207. package/dist/compiler/training/rewind/gitTree.js +90 -0
  208. package/dist/compiler/training/rewind/history.d.ts +28 -0
  209. package/dist/compiler/training/rewind/history.js +239 -0
  210. package/dist/compiler/training/rewind/index.d.ts +18 -0
  211. package/dist/compiler/training/rewind/index.js +15 -0
  212. package/dist/compiler/training/rewind/inputs.d.ts +9 -0
  213. package/dist/compiler/training/rewind/inputs.js +67 -0
  214. package/dist/compiler/training/rewind/instant.d.ts +4 -0
  215. package/dist/compiler/training/rewind/instant.js +24 -0
  216. package/dist/compiler/training/rewind/leakCheck.d.ts +10 -0
  217. package/dist/compiler/training/rewind/leakCheck.js +56 -0
  218. package/dist/compiler/training/rewind/leakFeed.d.ts +5 -0
  219. package/dist/compiler/training/rewind/leakFeed.js +25 -0
  220. package/dist/compiler/training/rewind/leakFiles.d.ts +10 -0
  221. package/dist/compiler/training/rewind/leakFiles.js +106 -0
  222. package/dist/compiler/training/rewind/leakGit.d.ts +3 -0
  223. package/dist/compiler/training/rewind/leakGit.js +78 -0
  224. package/dist/compiler/training/rewind/leakGitPayload.d.ts +4 -0
  225. package/dist/compiler/training/rewind/leakGitPayload.js +57 -0
  226. package/dist/compiler/training/rewind/leakInputs.d.ts +7 -0
  227. package/dist/compiler/training/rewind/leakInputs.js +135 -0
  228. package/dist/compiler/training/rewind/leakLayout.d.ts +2 -0
  229. package/dist/compiler/training/rewind/leakLayout.js +17 -0
  230. package/dist/compiler/training/rewind/leakProvenance.d.ts +3 -0
  231. package/dist/compiler/training/rewind/leakProvenance.js +88 -0
  232. package/dist/compiler/training/rewind/materialize.d.ts +136 -0
  233. package/dist/compiler/training/rewind/materialize.js +212 -0
  234. package/dist/compiler/training/rewind/memory.d.ts +10 -0
  235. package/dist/compiler/training/rewind/memory.js +84 -0
  236. package/dist/compiler/training/rewind/memorySchemas.d.ts +87 -0
  237. package/dist/compiler/training/rewind/memorySchemas.js +50 -0
  238. package/dist/compiler/training/rewind/moltnet.d.ts +2 -0
  239. package/dist/compiler/training/rewind/moltnet.js +54 -0
  240. package/dist/compiler/training/rewind/moltnetJson.d.ts +13 -0
  241. package/dist/compiler/training/rewind/moltnetJson.js +180 -0
  242. package/dist/compiler/training/rewind/moltnetSchemas.d.ts +1226 -0
  243. package/dist/compiler/training/rewind/moltnetSchemas.js +75 -0
  244. package/dist/compiler/training/rewind/moltnetSqlite.d.ts +31 -0
  245. package/dist/compiler/training/rewind/moltnetSqlite.js +192 -0
  246. package/dist/compiler/training/rewind/moltnetSqliteData.d.ts +10 -0
  247. package/dist/compiler/training/rewind/moltnetSqliteData.js +113 -0
  248. package/dist/compiler/training/rewind/recordInput.d.ts +40 -0
  249. package/dist/compiler/training/rewind/recordInput.js +49 -0
  250. package/dist/compiler/training/rewind/recordedBundle.d.ts +4 -0
  251. package/dist/compiler/training/rewind/recordedBundle.js +58 -0
  252. package/dist/compiler/training/rewind/recordedCommit.d.ts +2 -0
  253. package/dist/compiler/training/rewind/recordedCommit.js +10 -0
  254. package/dist/compiler/training/rewind/select.d.ts +18 -0
  255. package/dist/compiler/training/rewind/select.js +64 -0
  256. package/dist/compiler/training/rewind/snapshotManifest.d.ts +42 -0
  257. package/dist/compiler/training/rewind/snapshotManifest.js +134 -0
  258. package/dist/compiler/training/rewind/taskClock.d.ts +12 -0
  259. package/dist/compiler/training/rewind/taskClock.js +40 -0
  260. package/dist/compiler/training/rewind/timestamps.d.ts +4 -0
  261. package/dist/compiler/training/rewind/timestamps.js +26 -0
  262. package/dist/compiler/training/rewind/types.d.ts +43 -0
  263. package/dist/compiler/training/rewind/types.js +1 -0
  264. package/dist/compiler/training/rewind/volumes.d.ts +12 -0
  265. package/dist/compiler/training/rewind/volumes.js +58 -0
  266. package/dist/compiler/training/selection.d.ts +7 -0
  267. package/dist/compiler/training/selection.js +15 -0
  268. package/dist/compiler/types.d.ts +6 -3
  269. package/dist/compiler/upProject.d.ts +1 -0
  270. package/dist/compiler/upProject.js +21 -5
  271. package/dist/compiler/workspaceBundleArtifacts.d.ts +16 -1
  272. package/dist/compiler/workspaceBundleArtifacts.js +69 -20
  273. package/dist/compiler/workspaceBundleCache.d.ts +23 -0
  274. package/dist/compiler/workspaceBundleCache.js +79 -0
  275. package/dist/compiler/workspaceBundleDependencies.d.ts +21 -0
  276. package/dist/compiler/workspaceBundleDependencies.js +122 -0
  277. package/dist/compiler/workspaceBundleFiles.d.ts +51 -0
  278. package/dist/compiler/workspaceBundleFiles.js +251 -0
  279. package/dist/compiler/workspaceBundleGenerated.d.ts +25 -0
  280. package/dist/compiler/workspaceBundleGenerated.js +103 -0
  281. package/dist/compiler/workspaceBundleGit.d.ts +64 -0
  282. package/dist/compiler/workspaceBundleGit.js +154 -0
  283. package/dist/compiler/workspaceBundleKey.d.ts +34 -0
  284. package/dist/compiler/workspaceBundleKey.js +17 -0
  285. package/dist/compiler/workspaceBundleResolve.d.ts +56 -0
  286. package/dist/compiler/workspaceBundleResolve.js +144 -0
  287. package/dist/compiler/workspaceBundleRun.d.ts +41 -0
  288. package/dist/compiler/workspaceBundleRun.js +79 -0
  289. package/dist/compiler/workspaceBundleTar.d.ts +47 -0
  290. package/dist/compiler/workspaceBundleTar.js +140 -0
  291. package/dist/compiler/workspaceBundleTree.d.ts +15 -0
  292. package/dist/compiler/workspaceBundleTree.js +58 -0
  293. package/dist/compiler/workspaceGitFetch.d.ts +41 -0
  294. package/dist/compiler/workspaceGitFetch.js +155 -0
  295. package/dist/compiler/workspaceGitPins.d.ts +33 -0
  296. package/dist/compiler/workspaceGitPins.js +127 -0
  297. package/dist/compiler/workspaceResources.d.ts +5 -1
  298. package/dist/compiler/workspaceResources.js +32 -5
  299. package/dist/deployment/activation.d.ts +3 -0
  300. package/dist/deployment/activation.js +12 -0
  301. package/dist/deployment/canaryCutover.d.ts +1 -1
  302. package/dist/deployment/candidateRecording.d.ts +8 -0
  303. package/dist/deployment/candidateRecording.js +22 -0
  304. package/dist/deployment/dockerManager.d.ts +5 -3
  305. package/dist/deployment/dockerManager.js +12 -2
  306. package/dist/deployment/downDeployment.d.ts +2 -0
  307. package/dist/deployment/downDeployment.js +6 -2
  308. package/dist/deployment/homeStore.d.ts +9 -1
  309. package/dist/deployment/homeStore.js +16 -53
  310. package/dist/deployment/index.d.ts +6 -0
  311. package/dist/deployment/index.js +6 -0
  312. package/dist/deployment/pidLock.d.ts +25 -0
  313. package/dist/deployment/pidLock.js +81 -0
  314. package/dist/deployment/record.d.ts +85 -1
  315. package/dist/deployment/record.js +11 -5
  316. package/dist/deployment/recordPublication.d.ts +15 -0
  317. package/dist/deployment/recordPublication.js +76 -0
  318. package/dist/deployment/recordedMemoryRetention.d.ts +18 -0
  319. package/dist/deployment/recordedMemoryRetention.js +27 -0
  320. package/dist/deployment/resourceLog.d.ts +140 -0
  321. package/dist/deployment/resourceLog.js +78 -0
  322. package/dist/distribution/buildDistributionReport.d.ts +3 -0
  323. package/dist/distribution/buildDistributionReport.js +5 -0
  324. package/dist/distribution/consumeImage.d.ts +3 -0
  325. package/dist/distribution/consumeImage.js +23 -31
  326. package/dist/distribution/consumeImageLifecycle.d.ts +4 -1
  327. package/dist/distribution/consumeImageLifecycle.js +14 -3
  328. package/dist/distribution/consumeImageSupport.d.ts +7 -0
  329. package/dist/distribution/consumeImageSupport.js +25 -0
  330. package/dist/distribution/distributionReportSchema.d.ts +47 -0
  331. package/dist/distribution/distributionReportSchema.js +20 -0
  332. package/dist/distribution/renderImageInterface.js +1 -1
  333. package/dist/distribution/types.d.ts +15 -0
  334. package/dist/filesystem/durableWrite.d.ts +10 -0
  335. package/dist/filesystem/durableWrite.js +87 -0
  336. package/dist/filesystem/index.d.ts +2 -0
  337. package/dist/filesystem/index.js +2 -0
  338. package/dist/filesystem/retainedJsonl.d.ts +23 -0
  339. package/dist/filesystem/retainedJsonl.js +123 -0
  340. package/dist/manifest/commandSchemas.d.ts +5 -0
  341. package/dist/manifest/commandSchemas.js +5 -0
  342. package/dist/manifest/executionSchemas.d.ts +20 -0
  343. package/dist/manifest/executionSchemas.js +13 -3
  344. package/dist/manifest/index.d.ts +2 -0
  345. package/dist/manifest/index.js +2 -0
  346. package/dist/manifest/loadManifest.js +3 -26
  347. package/dist/manifest/mcpSchemas.d.ts +61 -0
  348. package/dist/manifest/mcpSchemas.js +57 -11
  349. package/dist/manifest/memorySchemas.d.ts +1 -1
  350. package/dist/manifest/memorySchemas.js +1 -1
  351. package/dist/manifest/parseManifest.d.ts +7 -0
  352. package/dist/manifest/parseManifest.js +65 -0
  353. package/dist/manifest/renderSpawnfile.js +4 -1
  354. package/dist/manifest/renderSpawnfileWorkspace.js +6 -2
  355. package/dist/manifest/schemas.d.ts +1206 -132
  356. package/dist/manifest/schemas.js +14 -4
  357. package/dist/manifest/teamNetworkSchemas.d.ts +1 -1
  358. package/dist/manifest/trainingDataSchemas.d.ts +357 -0
  359. package/dist/manifest/trainingDataSchemas.js +31 -0
  360. package/dist/manifest/trainingSchemas.d.ts +49 -0
  361. package/dist/manifest/trainingSchemas.js +44 -0
  362. package/dist/manifest/volumeFeedSchemas.d.ts +52 -0
  363. package/dist/manifest/volumeFeedSchemas.js +104 -0
  364. package/dist/manifest/workspaceSchemas.d.ts +182 -5
  365. package/dist/manifest/workspaceSchemas.js +111 -7
  366. package/dist/recording/compose.d.ts +3 -0
  367. package/dist/recording/compose.js +93 -0
  368. package/dist/recording/deployment.d.ts +15 -0
  369. package/dist/recording/deployment.js +38 -0
  370. package/dist/recording/history.d.ts +16 -0
  371. package/dist/recording/history.js +47 -0
  372. package/dist/recording/index.d.ts +9 -0
  373. package/dist/recording/index.js +9 -0
  374. package/dist/recording/moment.d.ts +61 -0
  375. package/dist/recording/moment.js +36 -0
  376. package/dist/recording/parse.d.ts +15 -0
  377. package/dist/recording/parse.js +74 -0
  378. package/dist/recording/read.d.ts +8 -0
  379. package/dist/recording/read.js +61 -0
  380. package/dist/recording/store.d.ts +10 -0
  381. package/dist/recording/store.js +94 -0
  382. package/dist/recording/sync.d.ts +24 -0
  383. package/dist/recording/sync.js +126 -0
  384. package/dist/recording/types.d.ts +45 -0
  385. package/dist/recording/types.js +2 -0
  386. package/dist/release/drainControl.d.ts +54 -0
  387. package/dist/release/drainControl.js +137 -0
  388. package/dist/release/drainPhase.d.ts +37 -0
  389. package/dist/release/drainPhase.js +161 -0
  390. package/dist/release/index.d.ts +11 -0
  391. package/dist/release/index.js +11 -0
  392. package/dist/release/ledger.d.ts +75 -0
  393. package/dist/release/ledger.js +111 -0
  394. package/dist/release/notify.d.ts +58 -0
  395. package/dist/release/notify.js +126 -0
  396. package/dist/release/pending.d.ts +35 -0
  397. package/dist/release/pending.js +60 -0
  398. package/dist/release/postDeploy.d.ts +32 -0
  399. package/dist/release/postDeploy.js +62 -0
  400. package/dist/release/releaseDefaults.d.ts +9 -0
  401. package/dist/release/releaseDefaults.js +115 -0
  402. package/dist/release/releaseDocker.d.ts +38 -0
  403. package/dist/release/releaseDocker.js +94 -0
  404. package/dist/release/releaseTypes.d.ts +94 -0
  405. package/dist/release/releaseTypes.js +1 -0
  406. package/dist/release/runRelease.d.ts +9 -0
  407. package/dist/release/runRelease.js +218 -0
  408. package/dist/release/swap.d.ts +23 -0
  409. package/dist/release/swap.js +55 -0
  410. package/dist/release/types.d.ts +50 -0
  411. package/dist/release/types.js +29 -0
  412. package/dist/report/index.d.ts +1 -0
  413. package/dist/report/index.js +1 -0
  414. package/dist/report/recording.d.ts +57 -0
  415. package/dist/report/recording.js +26 -0
  416. package/dist/report/types.d.ts +58 -0
  417. package/dist/runtime/container.js +8 -13
  418. package/dist/runtime/daimon/adapter.js +15 -4
  419. package/dist/runtime/daimon/config.d.ts +4 -0
  420. package/dist/runtime/daimon/config.js +53 -4
  421. package/dist/runtime/daimon/contract-manifest.json +1 -0
  422. package/dist/runtime/daimon/contract-manifest.sha256 +1 -0
  423. package/dist/runtime/daimon/contractManifest.d.ts +59 -8
  424. package/dist/runtime/daimon/contractManifest.js +26 -10
  425. package/dist/runtime/daimon/grokTurnLimits.d.ts +25 -0
  426. package/dist/runtime/daimon/grokTurnLimits.js +51 -0
  427. package/dist/runtime/daimon/grokWorkerConfigBytes.d.ts +17 -0
  428. package/dist/runtime/daimon/grokWorkerConfigBytes.js +17 -0
  429. package/dist/runtime/daimon/grokWorkerContract.d.ts +5 -0
  430. package/dist/runtime/daimon/grokWorkerContract.js +13 -1
  431. package/dist/runtime/daimon/recording.d.ts +19 -0
  432. package/dist/runtime/daimon/recording.js +50 -0
  433. package/dist/runtime/daimon/scheduleAuthority.d.ts +8 -0
  434. package/dist/runtime/daimon/scheduleAuthority.js +19 -5
  435. package/dist/runtime/daimon/wakeMoments.d.ts +15 -0
  436. package/dist/runtime/daimon/wakeMoments.js +17 -0
  437. package/dist/runtime/daimonInstall.d.ts +3 -0
  438. package/dist/runtime/daimonInstall.js +25 -0
  439. package/dist/runtime/index.d.ts +1 -0
  440. package/dist/runtime/index.js +1 -0
  441. package/dist/runtime/install.d.ts +2 -0
  442. package/dist/runtime/install.js +1 -0
  443. package/dist/runtime/openclaw/adapter.js +3 -0
  444. package/dist/runtime/pi/adapter.js +3 -0
  445. package/dist/runtime/pi/containerTargets.js +6 -0
  446. package/dist/runtime/picoclaw/adapter.js +3 -0
  447. package/dist/runtime/registry.d.ts +3 -0
  448. package/dist/runtime/registry.js +13 -1
  449. package/dist/runtime/types.d.ts +15 -0
  450. package/dist/runtime/usageLedgerRead.d.ts +6 -0
  451. package/dist/runtime/usageLedgerRead.js +3 -3
  452. package/dist/shared/index.d.ts +1 -0
  453. package/dist/shared/index.js +1 -0
  454. package/dist/shared/recording.d.ts +8 -0
  455. package/dist/shared/recording.js +25 -0
  456. package/dist/target/dockerCommandExecutorCore.js +1 -1
  457. package/dist/target/dockerTargetBinding.js +2 -1
  458. package/dist/volume/feedLand.d.ts +31 -0
  459. package/dist/volume/feedLand.js +174 -0
  460. package/dist/volume/feedLandings.d.ts +45 -0
  461. package/dist/volume/feedLandings.js +111 -0
  462. package/dist/volume/feedLayout.d.ts +61 -0
  463. package/dist/volume/feedLayout.js +234 -0
  464. package/dist/volume/feedLock.d.ts +7 -0
  465. package/dist/volume/feedLock.js +131 -0
  466. package/dist/volume/feedManifest.d.ts +27 -0
  467. package/dist/volume/feedManifest.js +123 -0
  468. package/dist/volume/feedPrepare.d.ts +16 -0
  469. package/dist/volume/feedPrepare.js +228 -0
  470. package/dist/volume/feedProject.d.ts +39 -0
  471. package/dist/volume/feedProject.js +92 -0
  472. package/dist/volume/feedRecord.d.ts +55 -0
  473. package/dist/volume/feedRecord.js +148 -0
  474. package/dist/volume/feedRef.d.ts +43 -0
  475. package/dist/volume/feedRef.js +117 -0
  476. package/dist/volume/feedRefresh.d.ts +15 -0
  477. package/dist/volume/feedRefresh.js +187 -0
  478. package/dist/volume/feedSource.d.ts +66 -0
  479. package/dist/volume/feedSource.js +104 -0
  480. package/dist/volume/feedTarget.d.ts +70 -0
  481. package/dist/volume/feedTarget.js +9 -0
  482. package/dist/volume/feedTestKit.d.ts +11 -0
  483. package/dist/volume/feedTestKit.js +45 -0
  484. package/dist/volume/feedVerify.d.ts +18 -0
  485. package/dist/volume/feedVerify.js +104 -0
  486. package/dist/volume/index.d.ts +13 -0
  487. package/dist/volume/index.js +13 -0
  488. package/package.json +3 -3
  489. package/runtimes.yaml +8 -6
@@ -1,31 +1,59 @@
1
1
  import { randomUUID } from "node:crypto";
2
- import { chmod, mkdtemp, readFile, realpath, rm, stat, writeFile } from "node:fs/promises";
2
+ import { chmod, mkdtemp, readFile, realpath, stat, writeFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { DAIMON_CODEX_NATIVE_SANDBOX_DOCKER_SECURITY_OPTS } from "../../../shared/index.js";
5
+ import { parseTrainingBrokerDeclaration } from "../broker/declaration.js";
6
+ import { trainingSlotsDocument, TRAINING_SLOTS_FILE } from "../broker/paths.js";
5
7
  import { assertNotDesktopGrokAuth } from "../broker/entrypoint.js";
6
- import { TRAINING_BROKER_ENTRYPOINT, trainingBrokerMounts, trainingBrokerSecurityArgs, trainingBrokerTmpfsTargets } from "./security.js";
8
+ import { TRAINING_BROKER_ENTRYPOINT, trainingBrokerMounts, trainingBrokerSecurityArgs, trainingBrokerTmpfsTargets, trainingRunRequestMount } from "./security.js";
7
9
  import { parseDetachedContainerInspect } from "../../runProjectDocker.js";
10
+ import { mapTrainingExecution, trainingExecutionSchema, TRAINING_EXECUTION_FILE, TRAINING_EXECUTION_CAPABILITY_LABEL, TRAINING_EXECUTION_VERSION } from "../execution.js";
11
+ import { verifyCanonicalPins } from "../preparation/inputs.js";
12
+ import { removeTrainingPreparationScratch } from "../preparation/scratch.js";
8
13
  import { trainingImageSchema } from "./contract.js";
14
+ import { prepareTrainingEvaluators } from "./evaluators.js";
9
15
  import { prepareTrainingContainer } from "./prepare.js";
10
16
  import { runTrainingDocker } from "./process.js";
11
17
  import { repairEnvelopeSchema } from "../repair/contract.js";
12
18
  import { hashJson } from "../preparation/files.js";
13
19
  import { parseTrainingMappedPreparation } from "../preparation/contract.js";
20
+ import { persistTrainingGrokCredential } from "./grokWriteback.js";
21
+ import { nativeTrainingSlotsDocument } from "./nativeSlots.js";
22
+ import { createTrainingOutputVolume, trainingOutputVolumeEnabled } from "./outputVolume.js";
23
+ // The image bakes /run/training/inputs as 0:2000 0750 for brokered worker isolation; the
24
+ // non-brokered host-uid evaluator joins that group so it can still traverse its own inputs.
25
+ export const TRAINING_INPUTS_GID = 2_000;
14
26
  const inspectFormat = "{{json .Id}}\n{{json .Name}}\n{{json .Image}}\n{{json .Config.Labels}}";
15
27
  export const launchTrainingContainer = async (options) => {
16
28
  if (options.signal?.aborted)
17
29
  return 130;
18
30
  const image = trainingImageSchema.parse(options.image);
31
+ const volumeEnabled = trainingOutputVolumeEnabled();
19
32
  const uid = process.getuid?.(), gid = process.getgid?.();
20
33
  if (uid === undefined || gid === undefined || uid === 0)
21
34
  throw Error("Training requires an explicit non-root local user");
22
35
  const configBytes = await readFile(options.configPath, "utf8");
23
36
  if (Buffer.byteLength(configBytes) > 1024 * 1024)
24
37
  throw Error("Training launch config exceeds 1 MiB");
25
- const prepared = await prepareTrainingContainer(JSON.parse(configBytes), options.context, options.args);
38
+ const raw = JSON.parse(configBytes);
39
+ const prepared = await prepareTrainingContainer(options.execution
40
+ ? { ...raw, output: { ...raw.output, source: options.execution.output } } : raw, options.context, options.args, { createOutput: options.execution !== undefined && !options.args.includes("--resume") });
41
+ const execution = options.execution ? mapTrainingExecution(options.execution, file => {
42
+ const absolute = path.resolve(file);
43
+ const binding = [...prepared.config.inputs, prepared.config.output].find(entry => absolute === entry.source || absolute.startsWith(entry.source + path.sep));
44
+ if (!binding)
45
+ throw Error(`Training execution path is not covered by a declared mount: ${file}`);
46
+ return path.posix.join(binding.destination, path.relative(binding.source, absolute).split(path.sep).join("/"));
47
+ }) : undefined;
48
+ if (options.execution)
49
+ await verifyCanonicalPins(prepared.config.inputs.map((input, index) => ({ ...input, id: String(index), digest: "" })), options.execution.datasetPins, prepared.config.inputs.map(input => input.source));
26
50
  // D2: the training Grok login is a dedicated one. Refuse the developer's desktop leaf before Docker ever sees it.
27
- if (prepared.config.broker)
51
+ if (prepared.config.broker) {
28
52
  assertNotDesktopGrokAuth(prepared.config.broker.bootstrap);
53
+ const declaration = parseTrainingBrokerDeclaration(JSON.parse(await readFile(prepared.config.broker.declaration, "utf8")));
54
+ if (declaration.slots !== prepared.config.slots)
55
+ throw Error("Training launch and broker declaration slots differ");
56
+ }
29
57
  if (options.preparationPath) {
30
58
  if (await realpath(options.preparationPath) !== options.preparationPath)
31
59
  throw Error("Preparation receipt path must be canonical");
@@ -46,23 +74,24 @@ export const launchTrainingContainer = async (options) => {
46
74
  const interrupt = () => { interrupted = true; controller.abort(); };
47
75
  const timer = setTimeout(() => { timedOut = true; controller.abort(); }, options.timeoutMs);
48
76
  options.signal?.addEventListener("abort", interrupt, { once: true });
49
- process.once("SIGINT", interrupt);
50
- process.once("SIGTERM", interrupt);
77
+ process.on("SIGINT", interrupt);
78
+ process.on("SIGTERM", interrupt);
51
79
  if (options.signal?.aborted)
52
80
  interrupt();
53
81
  const prefix = ["--context", prepared.config.dockerContext];
54
- const call = async (args, cleanup = false, stream = false) => {
82
+ const call = async (args, cleanup = false, stream = false, cleanupTimeoutMs = 10_000) => {
55
83
  if (!cleanup && controller.signal.aborted)
56
84
  throw Error("Container operation cancelled");
57
85
  return execute([...prefix, ...args], {
58
- timeoutMs: cleanup ? 10_000 : Math.max(1, deadline - Date.now()),
86
+ timeoutMs: cleanup ? cleanupTimeoutMs : Math.max(1, deadline - Date.now()),
59
87
  ...(cleanup ? {} : { signal: controller.signal }), ...(stream ? options.streams : {})
60
88
  });
61
89
  };
62
90
  const name = `spawnfile-training-${randomUUID()}`;
63
91
  const labels = { "com.spawnfile.training.owner": name };
64
- let privateRoot, containerId, creationAttempted = false;
92
+ let privateRoot, containerId, creationAttempted = false, startAttempted = false;
65
93
  let expectedImage, lastLine = "", closureVerified = false;
94
+ let outputVolume;
66
95
  try {
67
96
  const endpoint = await execute(["context", "inspect", prepared.config.dockerContext, "--format", "{{json .Endpoints.docker.Host}}"], { timeoutMs: 10_000, signal: controller.signal });
68
97
  if (endpoint.code !== 0 || !/^unix:\/\//u.test(JSON.parse(endpoint.stdout)))
@@ -71,38 +100,69 @@ export const launchTrainingContainer = async (options) => {
71
100
  expectedImage = inspected.stdout.trim();
72
101
  if (inspected.code !== 0 || !/^sha256:[a-f0-9]{64}$/u.test(expectedImage) || (image.startsWith("sha256:") && image !== expectedImage))
73
102
  throw Error("Training image must be locally available with an immutable identity");
103
+ if (execution) {
104
+ const capability = await call(["image", "inspect", expectedImage, "--format", `{{json (index .Config.Labels "${TRAINING_EXECUTION_CAPABILITY_LABEL}")}}`]);
105
+ if (capability.code !== 0 || capability.stdout.trim() !== JSON.stringify(TRAINING_EXECUTION_VERSION)) {
106
+ throw Error(`Authored training requires an image implementing --spawnfile-execution ${TRAINING_EXECUTION_FILE} and labelled ${TRAINING_EXECUTION_CAPABILITY_LABEL}=${TRAINING_EXECUTION_VERSION}; legacy Paideia datasets are incompatible`);
107
+ }
108
+ }
74
109
  privateRoot = await realpath(await mkdtemp(path.join(path.dirname(prepared.config.output.source), ".spawnfile-training-container-")));
75
110
  await chmod(privateRoot, 0o700);
76
111
  const contextFile = path.join(privateRoot, "context.json");
77
112
  await writeFile(contextFile, JSON.stringify(prepared.context), { mode: 0o444, flag: "wx" });
78
- const mounts = [...prepared.config.inputs.map((entry) => `type=bind,src=${entry.source},dst=${entry.destination},readonly`),
79
- `type=bind,src=${prepared.config.output.source},dst=/run/training/output`,
113
+ const executionFile = path.join(privateRoot, "execution.json");
114
+ if (execution)
115
+ await writeFile(executionFile, JSON.stringify(trainingExecutionSchema.parse(execution)), { mode: 0o444, flag: "wx" });
116
+ const evaluators = await prepareTrainingEvaluators(privateRoot, prepared.config, prepared.args);
117
+ if (volumeEnabled) {
118
+ outputVolume = createTrainingOutputVolume({ name, image: expectedImage, host: prepared.config.output.source, scratch: privateRoot,
119
+ uid, gid, runtimeUid: prepared.config.broker ? 2000 : uid, runtimeGid: prepared.config.broker ? 2000 : gid,
120
+ context: prepared.config.dockerContext, call: (args, cleanup) => call(args, cleanup, false, 120_000), stderr: options.streams.stderr });
121
+ await outputVolume.seed();
122
+ }
123
+ const mounts = [...evaluators.mounts, ...prepared.config.inputs.map((entry) => `type=bind,src=${entry.source},dst=${entry.destination},readonly`),
124
+ outputVolume?.mount ?? `type=bind,src=${prepared.config.output.source},dst=/run/training/output`,
80
125
  `type=bind,src=${contextFile},dst=/run/paideia/context.json,readonly`,
126
+ ...execution ? [`type=bind,src=${executionFile},dst=${TRAINING_EXECUTION_FILE},readonly`] : [],
81
127
  ...options.preparationPath ? [`type=bind,src=${options.preparationPath},dst=/run/paideia/preparation.json,readonly`] : [],
82
128
  ...options.repairPath ? [`type=bind,src=${options.repairPath},dst=/run/paideia/repair.json,readonly`] : [],
83
129
  ...prepared.config.auth.map((entry) => `type=bind,src=${entry.source},dst=/run/paideia-auth/${entry.provider},readonly`)];
84
130
  const broker = prepared.config.broker;
131
+ if (broker) {
132
+ mounts.push(trainingRunRequestMount(prepared.config.output.source, prepared.args));
133
+ const slotsFile = path.join(privateRoot, "slots.json");
134
+ await writeFile(slotsFile, `${JSON.stringify(trainingSlotsDocument(prepared.config.slots))}\n`, { mode: 0o444, flag: "wx" });
135
+ mounts.push(`type=bind,src=${slotsFile},dst=${TRAINING_SLOTS_FILE},readonly`);
136
+ }
137
+ else {
138
+ const slotsFile = path.join(privateRoot, "slots.json");
139
+ await writeFile(slotsFile, `${JSON.stringify(nativeTrainingSlotsDocument(prepared.config.slots, uid))}\n`, { mode: 0o444, flag: "wx" });
140
+ mounts.push(`type=bind,src=${slotsFile},dst=${TRAINING_SLOTS_FILE},readonly`);
141
+ }
85
142
  // A brokered Grok slot runs the launcher, the broker and the model's own worker uid inside this container, so it
86
143
  // starts as root with the production Daimon capability set instead of the host user with no capabilities at all.
87
144
  const privilege = broker
88
145
  ? [...await trainingBrokerSecurityArgs(privateRoot), "--pids-limit", "2048",
89
- ...trainingBrokerTmpfsTargets().flatMap((entry) => ["--tmpfs", `${entry.path}:rw,nosuid,nodev,size=${entry.size},mode=${entry.mode}`])]
90
- : ["--user", `${uid}:${gid}`, "--cap-drop", "ALL", "--security-opt", "no-new-privileges",
91
- ...DAIMON_CODEX_NATIVE_SANDBOX_DOCKER_SECURITY_OPTS, "--pids-limit", "512",
92
- "--tmpfs", `/tmp:rw,nosuid,nodev,size=1g,uid=${uid},gid=${gid},mode=1777`, "--tmpfs", `/work:rw,nosuid,nodev,size=4g,uid=${uid},gid=${gid},mode=700`,
93
- "--tmpfs", `/home/training:rw,nosuid,nodev,size=1g,uid=${uid},gid=${gid},mode=700`];
146
+ ...trainingBrokerTmpfsTargets(prepared.config.slots).flatMap((entry) => ["--tmpfs", `${entry.path}:rw,nosuid,nodev,size=${entry.size},mode=${entry.mode}`])]
147
+ : ["--user", `${uid}:${gid}`, "--group-add", String(TRAINING_INPUTS_GID), "--cap-drop", "ALL", "--security-opt", "no-new-privileges",
148
+ ...DAIMON_CODEX_NATIVE_SANDBOX_DOCKER_SECURITY_OPTS, "--pids-limit", String(512 * prepared.config.slots),
149
+ "--tmpfs", `/tmp:rw,nosuid,nodev,size=${prepared.config.slots}g,uid=${uid},gid=${gid},mode=1777`, "--tmpfs", `/work:rw,nosuid,nodev,size=${4 * prepared.config.slots}g,uid=${uid},gid=${gid},mode=700`,
150
+ "--tmpfs", `/home/training:rw,nosuid,nodev,size=${prepared.config.slots}g,uid=${uid},gid=${gid},mode=700`];
94
151
  const args = ["create", "--name", name, "--label", `com.spawnfile.training.owner=${name}`,
95
152
  "--init", "--read-only", ...privilege,
96
153
  "--env", "HOME=/home/training", "--workdir", "/work", "--entrypoint", broker ? TRAINING_BROKER_ENTRYPOINT : "/opt/training/bin/train",
154
+ ...(broker ? ["--env", "PAIDEIA_MODEL_REQUEST_CAP=broker"] : []),
155
+ ...evaluators.env.flatMap(value => ["--env", value]),
97
156
  ...[...mounts, ...(broker ? trainingBrokerMounts(broker) : [])].flatMap((mount) => ["--mount", mount]),
98
157
  ...(prepared.viewerPort === undefined ? [] : ["--publish", `127.0.0.1:${prepared.viewerPort}:${prepared.viewerPort}`]), expectedImage,
99
- "train", "--spawnfile-context", "/run/paideia/context.json", ...prepared.args];
158
+ "train", "--spawnfile-context", "/run/paideia/context.json",
159
+ ...(execution ? ["--spawnfile-execution", TRAINING_EXECUTION_FILE] : []), ...prepared.args];
100
160
  creationAttempted = true;
101
161
  const created = await call(args);
102
162
  containerId = created.stdout.trim();
103
163
  if (created.code !== 0 || !/^[a-f0-9]{64}$/u.test(containerId)) {
104
164
  let diagnostic = created.stderr;
105
- for (const auth of prepared.config.auth)
165
+ for (const auth of [...prepared.config.auth, ...prepared.config.evaluatorSecrets ?? []])
106
166
  diagnostic = diagnostic.replaceAll(auth.source, "[auth source]");
107
167
  diagnostic = diagnostic.replace(/\p{Cc}/gu, " ").trim().slice(0, 2048);
108
168
  throw Error(`Docker did not return a valid training container identity${diagnostic ? `: ${diagnostic}` : ""}`);
@@ -112,6 +172,7 @@ export const launchTrainingContainer = async (options) => {
112
172
  throw Error("Training container identity mismatch");
113
173
  if (controller.signal.aborted)
114
174
  throw Error("Container operation cancelled");
175
+ startAttempted = true;
115
176
  const result = await execute([...prefix, "start", "--attach", containerId], {
116
177
  timeoutMs: Math.max(1, deadline - Date.now()), signal: controller.signal,
117
178
  stdout: (line) => { if (line.trim())
@@ -121,6 +182,7 @@ export const launchTrainingContainer = async (options) => {
121
182
  const state = JSON.parse(terminal.stdout);
122
183
  if (terminal.code !== 0 || state.Running !== false || !Number.isInteger(state.ExitCode) || result.code !== state.ExitCode)
123
184
  throw Error("Training container final state is unverified");
185
+ await outputVolume?.export();
124
186
  if (state.ExitCode !== 0 && state.ExitCode !== 1)
125
187
  return state.ExitCode;
126
188
  const receipt = JSON.parse(lastLine);
@@ -140,9 +202,6 @@ export const launchTrainingContainer = async (options) => {
140
202
  }
141
203
  finally {
142
204
  clearTimeout(timer);
143
- options.signal?.removeEventListener("abort", interrupt);
144
- process.removeListener("SIGINT", interrupt);
145
- process.removeListener("SIGTERM", interrupt);
146
205
  try {
147
206
  if (creationAttempted) {
148
207
  // A timed-out create may still have created our uniquely labelled container.
@@ -151,11 +210,28 @@ export const launchTrainingContainer = async (options) => {
151
210
  const id = JSON.parse(found.stdout.split("\n")[0]);
152
211
  if (typeof id !== "string" || parseDetachedContainerInspect(found.stdout, id, labels, name).imageId !== expectedImage || (containerId && /^[a-f0-9]{64}$/u.test(containerId) && id !== containerId))
153
212
  throw Error("Refusing cleanup of unverified training container");
154
- const removed = await call(["rm", "--force", id], true);
155
- const remaining = await call(["container", "ls", "--all", "--no-trunc", "--filter", `id=${id}`, "--format", "{{.ID}}"], true);
156
- if (removed.code !== 0 || remaining.code !== 0 || remaining.stdout.trim())
157
- throw Error("Training container cleanup is unverified");
158
- closureVerified = true;
213
+ try {
214
+ if (startAttempted) {
215
+ const current = await call(["inspect", "--format", "{{json .State}}", id], true);
216
+ if (current.code !== 0)
217
+ throw Error("Cannot verify training writer state");
218
+ if (JSON.parse(current.stdout).Running === true) {
219
+ const stopped = await call(["stop", "--time", "5", id], true);
220
+ if (stopped.code !== 0)
221
+ throw Error("Cannot stop training output writer");
222
+ }
223
+ }
224
+ if (startAttempted && prepared.config.broker && privateRoot) {
225
+ await persistTrainingGrokCredential(id, prepared.config.broker.bootstrap, privateRoot, call);
226
+ }
227
+ }
228
+ finally {
229
+ const removed = await call(["rm", "--force", id], true);
230
+ const remaining = await call(["container", "ls", "--all", "--no-trunc", "--filter", `id=${id}`, "--format", "{{.ID}}"], true);
231
+ if (removed.code !== 0 || remaining.code !== 0 || remaining.stdout.trim())
232
+ throw Error("Training container cleanup is unverified");
233
+ closureVerified = true;
234
+ }
159
235
  }
160
236
  else {
161
237
  const remaining = await call(["container", "ls", "--all", "--filter", `name=^/${name}$`, "--format", "{{.ID}}"], true);
@@ -166,8 +242,23 @@ export const launchTrainingContainer = async (options) => {
166
242
  }
167
243
  }
168
244
  finally {
169
- if (privateRoot && (!creationAttempted || closureVerified))
170
- await rm(privateRoot, { recursive: true, force: true });
245
+ try {
246
+ const closed = !creationAttempted || closureVerified;
247
+ try {
248
+ if (closed)
249
+ await outputVolume?.export();
250
+ }
251
+ finally {
252
+ await outputVolume?.dispose(closed);
253
+ }
254
+ }
255
+ finally {
256
+ options.signal?.removeEventListener("abort", interrupt);
257
+ process.removeListener("SIGINT", interrupt);
258
+ process.removeListener("SIGTERM", interrupt);
259
+ if (privateRoot && (!creationAttempted || closureVerified) && (!outputVolume || outputVolume.safeToCleanup()))
260
+ await removeTrainingPreparationScratch(privateRoot);
261
+ }
171
262
  }
172
263
  }
173
264
  };
@@ -0,0 +1,14 @@
1
+ /** Native trials keep fresh per-trial roots; only their port blocks are provisioned. */
2
+ export declare const nativeTrainingSlotsDocument: (slots: number, workerUid: number) => {
3
+ schema: "spawnfile.training-slots.v2";
4
+ slots: {
5
+ index: number;
6
+ workerUid: number;
7
+ isolation: "shared-uid";
8
+ roots: {};
9
+ ports: {
10
+ base: number;
11
+ count: number;
12
+ };
13
+ }[];
14
+ };
@@ -0,0 +1,13 @@
1
+ import { assertTrainingSlotCount, TRAINING_PORT_BASE, TRAINING_PORT_STRIDE } from "../broker/paths.js";
2
+ /** Native trials keep fresh per-trial roots; only their port blocks are provisioned. */
3
+ export const nativeTrainingSlotsDocument = (slots, workerUid) => {
4
+ if (!Number.isInteger(workerUid) || workerUid <= 0 || workerUid > 4_294_967_294)
5
+ throw Error("Native slots require a non-root worker uid");
6
+ return {
7
+ schema: "spawnfile.training-slots.v2",
8
+ slots: Array.from({ length: assertTrainingSlotCount(slots) }, (_, index) => ({
9
+ index, workerUid, isolation: "shared-uid", roots: {},
10
+ ports: { base: TRAINING_PORT_BASE + index * TRAINING_PORT_STRIDE, count: TRAINING_PORT_STRIDE }
11
+ }))
12
+ };
13
+ };
@@ -0,0 +1,2 @@
1
+ /** Runs only in the verified Linux training image. No project code is imported. */
2
+ export declare const trainingOutputCopyProgram: string;
@@ -0,0 +1,72 @@
1
+ /** Runs only in the verified Linux training image. No project code is imported. */
2
+ export const trainingOutputCopyProgram = String.raw `
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const [source, destination, owner, group] = process.argv.slice(1);
6
+ const uid = Number(owner), gid = Number(group);
7
+ const limits = { entries: 1_000_000, bytes: 64 * 1024 ** 3, depth: 64 };
8
+ let entries = 0, bytes = 0;
9
+ const links = new Map();
10
+ const buffer = Buffer.alloc(1024 * 1024);
11
+ // Linux fd-relative traversal keeps renamed directories and symlink swaps from
12
+ // redirecting reads/writes outside the two mounts. The fallback permits local QA.
13
+ const fdPath = (fd, file) => process.platform === 'linux' ? '/proc/self/fd/' + fd : file;
14
+ const directory = fs.constants.O_RDONLY | fs.constants.O_DIRECTORY | fs.constants.O_NOFOLLOW;
15
+ function copy(src, dst, depth) {
16
+ if (++entries > limits.entries || depth > limits.depth) throw Error('Output tree exceeds entry/depth limit');
17
+ const info = fs.lstatSync(src);
18
+ if (info.isSymbolicLink()) {
19
+ const target = fs.readlinkSync(src);
20
+ bytes += Buffer.byteLength(target);
21
+ if (bytes > limits.bytes) throw Error('Output exceeds 64 GiB');
22
+ fs.symlinkSync(target, dst); fs.lchownSync(dst, uid, gid);
23
+ fs.lutimesSync(dst, info.atime, info.mtime);
24
+ return;
25
+ }
26
+ if (info.isDirectory()) {
27
+ const input = fs.openSync(src, directory);
28
+ let output;
29
+ try {
30
+ if (depth !== 0) fs.mkdirSync(dst, { mode: 0o700 });
31
+ output = fs.openSync(dst, directory);
32
+ fs.fchownSync(output, uid, gid);
33
+ const from = fdPath(input, src), to = fdPath(output, dst);
34
+ if (depth === 0 && fs.readdirSync(to).length) throw Error('Output copy destination must be empty');
35
+ for (const name of fs.readdirSync(from)) copy(path.join(from, name), path.join(to, name), depth + 1);
36
+ fs.fchownSync(output, uid, gid); fs.fchmodSync(output, info.mode & 0o7777);
37
+ fs.futimesSync(output, info.atime, info.mtime); fs.fsyncSync(output);
38
+ } finally { if (output !== undefined) fs.closeSync(output); fs.closeSync(input); }
39
+ return;
40
+ }
41
+ if (!info.isFile()) throw Error('Output contains a special file');
42
+ const input = fs.openSync(src, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
43
+ let output;
44
+ try {
45
+ const opened = fs.fstatSync(input);
46
+ if (!opened.isFile() || opened.dev !== info.dev || opened.ino !== info.ino) throw Error('Output changed during copy');
47
+ const key = info.dev + ':' + info.ino;
48
+ // Store a path rooted at the destination mount, not an fd that closes after recursion.
49
+ const previous = links.get(key);
50
+ if (previous) { fs.linkSync(previous, dst); return; }
51
+ bytes += info.size;
52
+ if (bytes > limits.bytes) throw Error('Output exceeds 64 GiB');
53
+ output = fs.openSync(dst, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | fs.constants.O_NOFOLLOW, 0o600);
54
+ fs.fchownSync(output, uid, gid);
55
+ let position = 0;
56
+ while (position < info.size) {
57
+ const count = fs.readSync(input, buffer, 0, Math.min(buffer.length, info.size - position), position);
58
+ if (!count) throw Error('Output truncated during copy');
59
+ let written = 0;
60
+ while (written < count) written += fs.writeSync(output, buffer, written, count - written);
61
+ position += count;
62
+ }
63
+ const after = fs.fstatSync(input);
64
+ if (after.size !== info.size || after.mtimeMs !== info.mtimeMs) throw Error('Output changed during copy');
65
+ fs.fchownSync(output, uid, gid); fs.fchmodSync(output, info.mode & 0o7777);
66
+ fs.futimesSync(output, info.atime, info.mtime); fs.fsyncSync(output);
67
+ links.set(key, fs.realpathSync(dst));
68
+ } finally { if (output !== undefined) fs.closeSync(output); fs.closeSync(input); }
69
+ }
70
+ copy(source, destination, 0);
71
+ console.log('spawnfile-output-copy-complete');
72
+ `;
@@ -0,0 +1,27 @@
1
+ type DockerCall = (args: string[], cleanup?: boolean) => Promise<{
2
+ code: number;
3
+ stdout: string;
4
+ stderr: string;
5
+ }>;
6
+ export declare const trainingOutputVolumeEnabled: () => boolean;
7
+ /** One launch owns this volume; budgets and auth volumes are never touched. */
8
+ export declare const createTrainingOutputVolume: (options: {
9
+ name: string;
10
+ image: string;
11
+ host: string;
12
+ scratch: string;
13
+ uid: number;
14
+ gid: number;
15
+ runtimeUid: number;
16
+ runtimeGid: number;
17
+ context: string;
18
+ call: DockerCall;
19
+ stderr(line: string): void;
20
+ }) => {
21
+ safeToCleanup: () => boolean;
22
+ mount: string;
23
+ seed(): Promise<void>;
24
+ export(): Promise<void>;
25
+ dispose(closureVerified: boolean): Promise<void>;
26
+ };
27
+ export {};
@@ -0,0 +1,161 @@
1
+ import { constants } from "node:fs";
2
+ import { lstat, mkdir, open, realpath, rename } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { parseDetachedContainerInspect } from "../../runProjectDocker.js";
5
+ import { trainingOutputCopyProgram } from "./outputCopy.js";
6
+ const ownerLabel = "com.spawnfile.training.owner";
7
+ const inspectFormat = "{{json .Id}}\n{{json .Name}}\n{{json .Image}}\n{{json .Config.Labels}}";
8
+ const target = "/run/training/output";
9
+ export const trainingOutputVolumeEnabled = () => {
10
+ const setting = process.env.SPAWNFILE_TRAINING_OUTPUT_STORAGE;
11
+ if (setting !== undefined && setting !== "volume" && setting !== "bind")
12
+ throw Error("SPAWNFILE_TRAINING_OUTPUT_STORAGE must be volume or bind");
13
+ return setting !== "bind";
14
+ };
15
+ /** One launch owns this volume; budgets and auth volumes are never touched. */
16
+ export const createTrainingOutputVolume = (options) => {
17
+ const { call } = options;
18
+ const volume = `${options.name}-output`;
19
+ let attempted = false, seeded = false, exported = false, exportAttempted = false, helperClosed = true;
20
+ const recovery = () => `Training output retained in Docker volume ${volume}. Recover with: docker --context ${options.context} run --rm --network none --read-only --mount type=volume,src=${volume},dst=/output,readonly --entrypoint /bin/tar ${options.image} -C /output -cpf - . > training-output-recovery.tar`;
21
+ const owned = async () => {
22
+ const result = await call(["volume", "inspect", volume, "--format", "{{json .}}"], true);
23
+ if (result.code !== 0) {
24
+ const listed = await call(["volume", "ls", "--filter", `name=^${volume}$`, "--format", "{{.Name}}"], true);
25
+ if (listed.code === 0 && !listed.stdout.trim())
26
+ return false;
27
+ throw Error("Training output volume closure is unknown");
28
+ }
29
+ const info = JSON.parse(result.stdout);
30
+ if (info.Name !== volume || info.Driver !== "local" || (info.Options && Object.keys(info.Options).length) || info.Labels?.[ownerLabel] !== options.name)
31
+ throw Error("Refusing unverified training output volume");
32
+ return true;
33
+ };
34
+ const transfer = async (direction) => {
35
+ if (!await owned())
36
+ throw Error("Training output volume is missing");
37
+ const name = `${volume}-${direction}`;
38
+ const labels = { [ownerLabel]: name };
39
+ const hostStage = path.join(options.scratch, "output-export");
40
+ if (direction === "export")
41
+ await mkdir(hostStage, { mode: 0o700 });
42
+ const mounts = direction === "seed"
43
+ ? [`type=bind,src=${options.host},dst=/source,readonly`, `type=volume,src=${volume},dst=/destination,volume-nocopy`]
44
+ : [`type=volume,src=${volume},dst=/source,readonly,volume-nocopy`, `type=bind,src=${hostStage},dst=/destination`];
45
+ let creationAttempted = false, containerId;
46
+ try {
47
+ creationAttempted = true;
48
+ helperClosed = false;
49
+ const created = await call(["container", "create", "--name", name, "--label", `${ownerLabel}=${name}`,
50
+ "--network", "none", "--read-only", "--user", "0:0", "--security-opt", "no-new-privileges",
51
+ // Retain only Docker's default CHOWN, DAC_OVERRIDE, FOWNER and FSETID for copying
52
+ // private runtime files and assigning the native/broker uid. No cap-add.
53
+ ...["AUDIT_WRITE", "KILL", "MKNOD", "NET_BIND_SERVICE", "NET_RAW", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"].flatMap(cap => ["--cap-drop", cap]),
54
+ "--pids-limit", "32", "--memory", "256m", "--cpus", "1", "--workdir", "/",
55
+ ...mounts.flatMap(mount => ["--mount", mount]), "--entrypoint", "node", options.image,
56
+ "-e", trainingOutputCopyProgram, "/source", "/destination",
57
+ String(direction === "seed" ? options.runtimeUid : options.uid), String(direction === "seed" ? options.runtimeGid : options.gid)], direction === "export");
58
+ const id = created.stdout.trim();
59
+ containerId = id;
60
+ if (created.code !== 0 || !/^[a-f0-9]{64}$/u.test(id))
61
+ throw Error(`Cannot create training output ${direction} helper`);
62
+ const checked = await call(["container", "inspect", "--format", inspectFormat, name], true);
63
+ if (checked.code !== 0 || parseDetachedContainerInspect(checked.stdout, id, labels, name).imageId !== options.image)
64
+ throw Error("Training output helper identity mismatch");
65
+ const result = await call(["container", "start", "--attach", id], direction === "export");
66
+ const terminal = await call(["container", "inspect", "--format", "{{json .State}}", id], true);
67
+ const state = JSON.parse(terminal.stdout);
68
+ if (result.code !== 0 || result.stdout.trim() !== "spawnfile-output-copy-complete" || terminal.code !== 0 || state.Running !== false || state.ExitCode !== 0)
69
+ throw Error(`Training output ${direction} failed (copy incomplete or exceeds limits): ${result.stderr.replace(/\p{Cc}/gu, " ").slice(0, 2048)}`);
70
+ }
71
+ finally {
72
+ if (creationAttempted) {
73
+ const found = await call(["container", "inspect", "--format", inspectFormat, name], true);
74
+ if (found.code === 0) {
75
+ const id = JSON.parse(found.stdout.split("\n")[0]);
76
+ if (typeof id !== "string" || parseDetachedContainerInspect(found.stdout, id, labels, name).imageId !== options.image || (containerId && /^[a-f0-9]{64}$/u.test(containerId) && id !== containerId))
77
+ throw Error("Refusing cleanup of unverified training output helper");
78
+ const removed = await call(["container", "rm", "--force", id], true);
79
+ if (removed.code !== 0)
80
+ throw Error("Cannot remove training output helper");
81
+ }
82
+ const remaining = await call(["container", "ls", "--all", "--filter", `name=^/${name}$`, "--format", "{{.ID}}"], true);
83
+ if (remaining.code !== 0 || remaining.stdout.trim())
84
+ throw Error("Training output helper closure is unknown");
85
+ helperClosed = true;
86
+ }
87
+ }
88
+ if (direction === "export") {
89
+ if (await realpath(options.host) !== options.host || !(await lstat(options.host)).isDirectory())
90
+ throw Error("Training host output changed before export");
91
+ const backup = path.join(options.scratch, "output-before-export");
92
+ await rename(options.host, backup);
93
+ try {
94
+ await rename(hostStage, options.host);
95
+ }
96
+ catch (error) {
97
+ await rename(backup, options.host);
98
+ throw error;
99
+ }
100
+ for (const directory of [options.scratch, path.dirname(options.host)]) {
101
+ const handle = await open(directory, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
102
+ try {
103
+ await handle.sync();
104
+ }
105
+ finally {
106
+ await handle.close();
107
+ }
108
+ }
109
+ }
110
+ };
111
+ return {
112
+ safeToCleanup: () => helperClosed && (!exportAttempted || exported),
113
+ mount: `type=volume,src=${volume},dst=${target},volume-nocopy`,
114
+ async seed() {
115
+ attempted = true;
116
+ const created = await call(["volume", "create", "--driver", "local", "--label", `${ownerLabel}=${options.name}`, volume]);
117
+ if (created.code !== 0 || created.stdout.trim() !== volume || !await owned())
118
+ throw Error("Cannot create owned training output volume");
119
+ await transfer("seed");
120
+ seeded = true;
121
+ options.stderr(`Training output uses VM-local volume ${volume}; host checkpoints update at exit.`);
122
+ },
123
+ async export() {
124
+ if (!seeded || exportAttempted)
125
+ return;
126
+ exportAttempted = true;
127
+ try {
128
+ await transfer("export");
129
+ exported = true;
130
+ }
131
+ catch (error) {
132
+ options.stderr(`Training output export failed: ${error instanceof Error ? error.message : "unknown failure"}. Scratch retained at ${options.scratch}. ${recovery()}`);
133
+ throw Error(`Training output export failed. ${recovery()}`, { cause: error });
134
+ }
135
+ },
136
+ async dispose(closureVerified) {
137
+ if (!attempted)
138
+ return;
139
+ try {
140
+ if (!await owned())
141
+ return;
142
+ if (!helperClosed)
143
+ throw Error("Training output helper closure is unverified");
144
+ if (!closureVerified) {
145
+ options.stderr(recovery());
146
+ return;
147
+ }
148
+ if (seeded && !exported)
149
+ throw Error("Training output has not been exported");
150
+ const removed = await call(["volume", "rm", volume], true);
151
+ const remaining = await call(["volume", "ls", "--filter", `name=^${volume}$`, "--format", "{{.Name}}"], true);
152
+ if (removed.code !== 0 || remaining.code !== 0 || remaining.stdout.trim())
153
+ throw Error("Training output volume removal is unverified");
154
+ }
155
+ catch (error) {
156
+ options.stderr(recovery());
157
+ throw Error(recovery(), { cause: error });
158
+ }
159
+ }
160
+ };
161
+ };
@@ -1,6 +1,8 @@
1
1
  import { type TrainingContext } from "../contract.js";
2
2
  import { type TrainingContainerConfig } from "./contract.js";
3
- export declare const prepareTrainingContainer: (raw: unknown, context: TrainingContext, args: readonly string[]) => Promise<{
3
+ export declare const prepareTrainingContainer: (raw: unknown, context: TrainingContext, args: readonly string[], options?: {
4
+ createOutput?: boolean;
5
+ }) => Promise<{
4
6
  config: TrainingContainerConfig;
5
7
  context: TrainingContext;
6
8
  args: string[];