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