spawnfile 0.1.17 → 0.1.19

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 (490) 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/moltnet-releases.json +4 -4
  489. package/package.json +3 -3
  490. package/runtimes.yaml +8 -6
@@ -85,6 +85,9 @@ const assertSupportedPiSurfaces = (surfaces) => {
85
85
  };
86
86
  export const piAdapter = {
87
87
  assertSupportedModelTarget(target) {
88
+ if (target.reasoningEffort !== undefined) {
89
+ throw new SpawnfileError("validation_error", "Pi runtime does not support reasoning_effort; only Daimon Codex and Grok engines support it");
90
+ }
88
91
  if (target.endpoint) {
89
92
  if (target.provider !== "custom" && target.provider !== "local") {
90
93
  throw new SpawnfileError("validation_error", "Pi runtime only supports endpoints on custom or local model providers");
@@ -1,4 +1,5 @@
1
1
  import path from "node:path";
2
+ import { CLI_ENGINE_SKILL_BASE_DIRECTORIES } from "../common.js";
2
3
  import { listExecutionModelSecretNames } from "../../compiler/modelEnv.js";
3
4
  import { renderPiScheduleSource } from "./appScheduleSource.js";
4
5
  import { createPiAgentConfig, renderPiApp, renderPiAppConfig, renderPiModelsConfig, renderPiPackageJson, resolvePiEngine, } from "./appTemplate.js";
@@ -29,6 +30,11 @@ export const createPiContainerTargets = async (inputs) => {
29
30
  relativePath: `secrets/${secretName}`,
30
31
  }));
31
32
  return [{
33
+ agentPathsByNodeId: Object.fromEntries(agentInputs.map((input) => [input.id, {
34
+ workspacePath: `<instance-root>/workspace/agents/${input.slug}`,
35
+ homePath: `<instance-root>/runtime/agents/${input.slug}`,
36
+ skillRoots: CLI_ENGINE_SKILL_BASE_DIRECTORIES.map((root) => `<instance-root>/workspace/agents/${input.slug}/${path.posix.relative("workspace", root)}`)
37
+ }])),
32
38
  engineByNodeId,
33
39
  envFiles,
34
40
  files: [
@@ -152,6 +152,9 @@ const createContainerTargets = async (inputs) => inputs.map((input) => {
152
152
  });
153
153
  export const picoClawAdapter = {
154
154
  assertSupportedModelTarget(target) {
155
+ if (target.reasoningEffort !== undefined) {
156
+ throw new SpawnfileError("validation_error", "PicoClaw runtime does not support reasoning_effort; only Daimon Codex and Grok engines support it");
157
+ }
155
158
  if (target.endpoint) {
156
159
  if (target.endpoint.compatibility === "anthropic" &&
157
160
  target.auth.method === "none") {
@@ -3,6 +3,8 @@ import type { RuntimeLifecycleStatus } from "../shared/index.js";
3
3
  import type { RuntimeAdapter } from "./types.js";
4
4
  export type RuntimeRegistryInstall = {
5
5
  capabilityReceipt?: string;
6
+ /** Per-architecture receipts embedded in a multi-architecture image index. */
7
+ capabilityReceipts?: DaimonCapabilityReceipts;
6
8
  contractManifestSha256?: string;
7
9
  digest?: string;
8
10
  image: string;
@@ -21,6 +23,7 @@ export type RuntimeRegistryInstall = {
21
23
  } | {
22
24
  kind: "source_repo";
23
25
  };
26
+ export type DaimonCapabilityReceipts = Partial<Record<"amd64" | "arm64", string>>;
24
27
  export interface RuntimeRegistryEntry {
25
28
  defaultBranch: string;
26
29
  install?: RuntimeRegistryInstall;
@@ -16,13 +16,22 @@ const runtimeInstallSchema = z.discriminatedUnion("kind", [
16
16
  z
17
17
  .object({
18
18
  capability_receipt: z.string().regex(/^sha256:[a-f0-9]{64}$/).optional(),
19
+ capability_receipts: z
20
+ .object({
21
+ amd64: z.string().regex(/^sha256:[a-f0-9]{64}$/).optional(),
22
+ arm64: z.string().regex(/^sha256:[a-f0-9]{64}$/).optional()
23
+ })
24
+ .strict()
25
+ .refine((receipts) => Object.keys(receipts).length > 0, "capability_receipts must pin at least one architecture")
26
+ .optional(),
19
27
  contract_manifest_sha256: z.string().regex(/^sha256:[a-f0-9]{64}$/).optional(),
20
28
  digest: z.string().regex(/^sha256:[a-f0-9]{64}$/).optional(),
21
29
  image: z.string().min(1),
22
30
  kind: z.literal("container_image"),
23
31
  tag: z.string().min(1)
24
32
  })
25
- .strict(),
33
+ .strict()
34
+ .refine((install) => !(install.capability_receipt && install.capability_receipts), "capability_receipt and capability_receipts are mutually exclusive"),
26
35
  z
27
36
  .object({
28
37
  kind: z.literal("npm"),
@@ -71,6 +80,9 @@ export const parseRuntimeRegistry = (source) => {
71
80
  ...(entry.install.capability_receipt
72
81
  ? { capabilityReceipt: entry.install.capability_receipt }
73
82
  : {}),
83
+ ...(entry.install.capability_receipts
84
+ ? { capabilityReceipts: { ...entry.install.capability_receipts } }
85
+ : {}),
74
86
  ...(entry.install.contract_manifest_sha256
75
87
  ? { contractManifestSha256: entry.install.contract_manifest_sha256 }
76
88
  : {}),
@@ -34,7 +34,14 @@ export interface ContainerTargetPersistentMount {
34
34
  reason: string;
35
35
  }
36
36
  export type RuntimeContainerConfigValueTransform = "bearer";
37
+ export interface ContainerTargetAgentPaths {
38
+ workspacePath: string;
39
+ homePath: string | null;
40
+ skillRoots: string[];
41
+ }
37
42
  export interface ContainerTarget {
43
+ /** Adapter-owned paths, using the same placeholders as emitted configuration. */
44
+ agentPathsByNodeId?: Record<string, ContainerTargetAgentPaths>;
38
45
  configEnvBindings?: RuntimeContainerConfigEnvBinding[];
39
46
  /**
40
47
  * Optional node id -> resolved engine kind map (currently only populated by
@@ -51,6 +58,12 @@ export interface ContainerTarget {
51
58
  model: string;
52
59
  reasoningEffort: string;
53
60
  }>;
61
+ /** Daimon only: each brokered Grok agent's declared per-turn budget, for its broker registration. */
62
+ grokTurnLimitsByNodeId?: Record<string, {
63
+ maxRequests?: number;
64
+ maxTokens?: number;
65
+ timeoutMs?: number;
66
+ }>;
54
67
  files: EmittedFile[];
55
68
  id: string;
56
69
  opaqueMountTargets?: string[];
@@ -191,6 +204,8 @@ export interface RuntimeAdapter {
191
204
  compileTeam?(node: ResolvedTeamNode): Promise<AdapterCompileResult>;
192
205
  createContainerTargets?(inputs: ContainerTargetInput[]): Promise<ContainerTarget[]>;
193
206
  name: string;
207
+ /** Throws a SpawnfileError for what compile would refuse for this agent; run by `spawnfile validate`. */
208
+ preflightAgent?(node: ResolvedAgentNode, nodeId: string): void;
194
209
  prepareRuntimeAuth?(input: RuntimeAuthPreparationInput): Promise<RuntimeAuthPreparationResult>;
195
210
  scaffoldAgentProject?(): RuntimeAgentScaffold;
196
211
  statusProbes?: RuntimeStatusProbe[];
@@ -35,6 +35,12 @@ export interface UsageLedgerRead {
35
35
  records: UsageRecord[];
36
36
  unreadable: UsageLedgerReadFailure[];
37
37
  }
38
+ /** `cat`s one generation through `exec`. A genuinely absent file reads as
39
+ * empty; every other failure is reported, never swallowed. */
40
+ export declare const readRuntimeFileViaExec: (exec: UsageLedgerExec, filePath: string) => Promise<{
41
+ failure?: UsageLedgerReadFailure;
42
+ text: string;
43
+ }>;
38
44
  /**
39
45
  * Reads both ledger generations (`usage.jsonl` and `usage.jsonl.1`) through
40
46
  * `exec` and parses them. Rotated (older) records are returned before
@@ -66,7 +66,7 @@ const isAbsentLedgerFile = (error) => {
66
66
  };
67
67
  /** `cat`s one generation through `exec`. A genuinely absent file reads as
68
68
  * empty; every other failure is reported, never swallowed. */
69
- const readLedgerGeneration = async (exec, filePath) => {
69
+ export const readRuntimeFileViaExec = async (exec, filePath) => {
70
70
  try {
71
71
  const result = await exec(["cat", filePath]);
72
72
  return { text: result.stdout };
@@ -89,8 +89,8 @@ const readLedgerGeneration = async (exec, filePath) => {
89
89
  */
90
90
  export const readUsageLedgerViaExec = async (exec, paths) => {
91
91
  const [rotated, primary] = await Promise.all([
92
- readLedgerGeneration(exec, paths.rotatedFilePath),
93
- readLedgerGeneration(exec, paths.filePath)
92
+ readRuntimeFileViaExec(exec, paths.rotatedFilePath),
93
+ readRuntimeFileViaExec(exec, paths.filePath)
94
94
  ]);
95
95
  return {
96
96
  // Every row is kept, across both generations: aggregates dedupe by `turn`
@@ -1,5 +1,6 @@
1
1
  export * from "./constants.js";
2
2
  export * from "./errors.js";
3
+ export * from "./recording.js";
3
4
  export * from "./redaction.js";
4
5
  export * from "./types.js";
5
6
  export * from "./volumeNames.js";
@@ -1,5 +1,6 @@
1
1
  export * from "./constants.js";
2
2
  export * from "./errors.js";
3
+ export * from "./recording.js";
3
4
  export * from "./redaction.js";
4
5
  export * from "./types.js";
5
6
  export * from "./volumeNames.js";
@@ -0,0 +1,8 @@
1
+ export declare const DEFAULT_RECORD_KEEP_MS: number;
2
+ /** Absence disables recording; an empty declaration opts into the default window. */
3
+ export declare const recordingKeepMs: (record: {
4
+ keep?: string;
5
+ } | undefined) => number | undefined;
6
+ export declare const maxRecordingKeepMs: (records: Iterable<{
7
+ keep?: string;
8
+ } | undefined>) => number | undefined;
@@ -0,0 +1,25 @@
1
+ import { SpawnfileError } from "./errors.js";
2
+ export const DEFAULT_RECORD_KEEP_MS = 30 * 24 * 60 * 60_000;
3
+ /** Absence disables recording; an empty declaration opts into the default window. */
4
+ export const recordingKeepMs = (record) => {
5
+ if (record === undefined)
6
+ return undefined;
7
+ if (record.keep === undefined)
8
+ return DEFAULT_RECORD_KEEP_MS;
9
+ const match = /^([1-9][0-9]*)([mhd])$/u.exec(record.keep);
10
+ const factors = { m: 60_000, h: 60 * 60_000, d: 24 * 60 * 60_000 };
11
+ const milliseconds = match ? Number(match[1]) * factors[match[2]] : NaN;
12
+ if (!Number.isSafeInteger(milliseconds) || milliseconds <= 0) {
13
+ throw new SpawnfileError("validation_error", "record.keep must be a safe positive duration matching ^[1-9][0-9]*[mhd]$");
14
+ }
15
+ return milliseconds;
16
+ };
17
+ export const maxRecordingKeepMs = (records) => {
18
+ let maximum;
19
+ for (const record of records) {
20
+ const keep = recordingKeepMs(record);
21
+ if (keep !== undefined)
22
+ maximum = Math.max(maximum ?? 0, keep);
23
+ }
24
+ return maximum;
25
+ };
@@ -44,7 +44,7 @@ const ordinaryOptions = (raw) => {
44
44
  return true;
45
45
  };
46
46
  const validate = (file, args, options) => {
47
- if (typeof file !== "string" || file.length < 1 || file.length > 128 || file.includes("\0")
47
+ if (typeof file !== "string" || file.length < 1 || Buffer.byteLength(file, "utf8") > 1_024 || file.includes("\0")
48
48
  || Buffer.from(file, "utf8").toString("utf8") !== file
49
49
  || !Array.isArray(args) || nodeTypes.isProxy(args)
50
50
  || Object.getPrototypeOf(args) !== Array.prototype || args.length > 1_024
@@ -50,7 +50,8 @@ const selectTargetContext = (input) => {
50
50
  const isDockerContextEndpoint = (endpoint) => endpoint.length <= 4_096
51
51
  && /^(?:npipe|ssh|tcp|unix|fd|http|https):\/\/[^\s]+$/u.test(endpoint);
52
52
  const selectTargetOptions = (input) => {
53
- if (input.dockerCommand !== undefined && (typeof input.dockerCommand !== "string" || input.dockerCommand.length === 0 || input.dockerCommand.length > 128)) {
53
+ if (input.dockerCommand !== undefined && (typeof input.dockerCommand !== "string" || input.dockerCommand.length === 0
54
+ || input.dockerCommand.includes("\0") || Buffer.byteLength(input.dockerCommand, "utf8") > 1_024)) {
54
55
  return selectionFailure("validation_error");
55
56
  }
56
57
  if (input.timeoutMs !== undefined && (typeof input.timeoutMs !== "number" || !Number.isSafeInteger(input.timeoutMs) || input.timeoutMs < 1 || input.timeoutMs > 120_000)) {
@@ -0,0 +1,31 @@
1
+ import { type LinkOps } from "./feedLayout.js";
2
+ import { type FeedLandedRecord } from "./feedRecord.js";
3
+ import { type FeedExec, type ResolvedFeedSource } from "./feedSource.js";
4
+ import { type FeedTarget } from "./feedTarget.js";
5
+ export interface FeedRuntime {
6
+ exec?: FeedExec;
7
+ log?: (line: string) => void;
8
+ now?: () => Date;
9
+ ops?: LinkOps;
10
+ }
11
+ export interface FeedLandResult {
12
+ revision: string;
13
+ reused: boolean;
14
+ tree: string;
15
+ treesRemoved: string[];
16
+ unknownTrees: string[];
17
+ }
18
+ export declare const isoSeconds: (date: Date) => string;
19
+ /**
20
+ * The declared validation hook: the gate between "staged" and "reachable". Non-zero exit lands nothing.
21
+ * It validates; it may not edit: the tree is digested before and after, and any change is a refusal,
22
+ * because changed bytes would be served under a revision that does not describe them.
23
+ */
24
+ export declare const runFeedValidation: (target: FeedTarget, tree: string, resolved: ResolvedFeedSource) => void;
25
+ export declare const landFeed: (target: FeedTarget, resolved: ResolvedFeedSource, record: FeedLandedRecord | null, { exact, force, heals, period, runtime }?: {
26
+ exact?: boolean;
27
+ force?: boolean;
28
+ heals?: Record<string, number>;
29
+ period?: string;
30
+ runtime?: FeedRuntime;
31
+ }) => FeedLandResult;
@@ -0,0 +1,174 @@
1
+ // The mutating half of a refresh: stage, validate, freeze, land, point `current`, publish the identity,
2
+ // record, collect garbage. Read feedLayout.ts first: it owns every rule about what may touch the volume.
3
+ //
4
+ // WHAT THIS FILE DECIDES FROM, EXHAUSTIVELY: the host record and manifests outside the volume, the
5
+ // source, and the host clock. The volume itself is read only to assert that what is about to be touched
6
+ // is the real directory the host created, and to find a tree name nobody occupies.
7
+ //
8
+ // GENERATIONS, NOT REPLACEMENTS. A tree is never replaced under its own name: a re-land of revision R
9
+ // lands as `trees/R.1` (then `.2`, ...) beside the drifted `trees/R`, `current` moves to it with one
10
+ // rename, and the drifted tree is retired later like any other. So `current` never dangles, not even
11
+ // between two adjacent renames, and nothing the host did not record is ever parked or deleted.
12
+ import { spawnSync } from "node:child_process";
13
+ import { lstatSync, mkdirSync, readdirSync } from "node:fs";
14
+ import path from "node:path";
15
+ import { FEED_TREES_DIR, LINK_OPS, assertRealDirectory, feedError, feedTreeLink, landTree, ownAndFreeze, parkTree, pointCurrent, removeTree } from "./feedLayout.js";
16
+ import { buildFeedManifest, compareFeedManifest, manifestDrift, readFeedManifest, removeFeedManifest, writeFeedManifest } from "./feedManifest.js";
17
+ import { ensureFeedLanding, publishFeedLanded } from "./feedLandings.js";
18
+ import { FEED_IDENTITY_VERSION, FEED_LANDED_VERSION, writeFeedIdentity } from "./feedRecord.js";
19
+ import { stageFeedContent } from "./feedPrepare.js";
20
+ import { digestDirectory, hostExec } from "./feedSource.js";
21
+ import { feedStagingDir, feedTrashDir } from "./feedTarget.js";
22
+ export const isoSeconds = (date) => `${date.toISOString().slice(0, 19)}Z`;
23
+ const stampOf = (date) => `${isoSeconds(date).replace(/[:-]/gu, "")}.${process.pid}`;
24
+ /**
25
+ * The declared validation hook: the gate between "staged" and "reachable". Non-zero exit lands nothing.
26
+ * It validates; it may not edit: the tree is digested before and after, and any change is a refusal,
27
+ * because changed bytes would be served under a revision that does not describe them.
28
+ */
29
+ export const runFeedValidation = (target, tree, resolved) => {
30
+ if (!target.validate)
31
+ return;
32
+ const before = digestDirectory(tree);
33
+ const [command, ...args] = target.validate.command;
34
+ const result = spawnSync(command, args, {
35
+ cwd: target.validate.cwd,
36
+ encoding: "utf8",
37
+ env: {
38
+ ...process.env,
39
+ SPAWNFILE_FEED_PROVENANCE: JSON.stringify(resolved.provenance),
40
+ SPAWNFILE_FEED_RESOURCE: target.resourceId,
41
+ SPAWNFILE_FEED_REVISION: resolved.revision,
42
+ SPAWNFILE_FEED_TREE: tree
43
+ },
44
+ maxBuffer: 16 * 1024 * 1024,
45
+ stdio: ["ignore", "pipe", "pipe"],
46
+ timeout: target.validate.timeoutMs
47
+ });
48
+ if (result.error?.code === "ETIMEDOUT") {
49
+ throw feedError(`the feed validation command for ${target.resourceId} did not finish within ${Math.round(target.validate.timeoutMs / 1000)}s and was killed; nothing was landed`);
50
+ }
51
+ if (result.error)
52
+ throw feedError(`the feed validation command for ${target.resourceId} could not run: ${result.error.message}`);
53
+ if (result.status !== 0) {
54
+ const output = `${result.stderr ?? ""}${result.stdout ?? ""}`.trim().split("\n").slice(-20).join("\n");
55
+ throw feedError(`the feed validation command rejected revision ${resolved.revision.slice(0, 12)} of ${target.resourceId} (${result.signal ? `killed by ${result.signal}` : `exit ${result.status}`}); nothing was landed${output ? `:\n${output}` : ""}`);
56
+ }
57
+ if (digestDirectory(tree) !== before)
58
+ throw feedError(`the feed validation command for ${target.resourceId} modified the tree it was validating; a validation hook may only read it, so nothing was landed`);
59
+ };
60
+ const treesDirOf = (target) => path.join(target.volume, FEED_TREES_DIR);
61
+ const treeMatches = (target, name) => {
62
+ const treePath = path.join(treesDirOf(target), name);
63
+ if (!assertRealDirectory(treePath, `the fed tree ${FEED_TREES_DIR}/${name.slice(0, 12)}`))
64
+ return false;
65
+ const manifest = readFeedManifest(target.stateDir, name);
66
+ return manifest !== null && manifestDrift(compareFeedManifest(treePath, manifest)).length === 0;
67
+ };
68
+ /** The first name for `revision` that nothing occupies -- whatever occupies the others, the host never moves it. */
69
+ const freshTreeName = (target, revision) => {
70
+ for (let generation = 0;; generation += 1) {
71
+ const name = generation === 0 ? revision : `${revision}.${generation}`;
72
+ try {
73
+ lstatSync(path.join(treesDirOf(target), name));
74
+ }
75
+ catch {
76
+ return name;
77
+ }
78
+ }
79
+ };
80
+ /** Copies, validates, owns and freezes OUTSIDE the volume, then moves the finished tree in with one rename. */
81
+ const stageAndLand = (target, resolved, { exact, exec, log }) => {
82
+ const stagingDir = path.join(feedStagingDir(target), `${resolved.revision}-${process.pid}`);
83
+ removeTree(stagingDir, { volume: target.volume });
84
+ mkdirSync(stagingDir);
85
+ let staged;
86
+ try {
87
+ staged = stageFeedContent(target, resolved, stagingDir, { exec, log });
88
+ // A held volume re-lands exactly what it serves: inputs that moved mid-copy are a refusal, not a new revision.
89
+ if (exact && staged.revision !== resolved.revision)
90
+ throw feedError(`the source moved while ${resolved.revision.slice(0, 12)} was being re-landed (copied ${staged.revision.slice(0, 12)}); a held volume never advances, so nothing was landed`);
91
+ if (staged.revision !== resolved.revision)
92
+ log(`the source moved while it was copied; landing what was copied as ${staged.revision.slice(0, 12)}`);
93
+ runFeedValidation(target, stagingDir, staged);
94
+ ownAndFreeze(stagingDir, { owner: target.owner, volume: target.volume });
95
+ }
96
+ catch (error) {
97
+ try {
98
+ removeTree(stagingDir, { volume: target.volume });
99
+ }
100
+ catch { /* the original error says more */ }
101
+ throw error;
102
+ }
103
+ const name = freshTreeName(target, staged.revision);
104
+ writeFeedManifest(target.stateDir, buildFeedManifest(stagingDir, name));
105
+ landTree(stagingDir, path.join(treesDirOf(target), name));
106
+ log(`landed ${FEED_TREES_DIR}/${name.slice(0, 12)}${name.length > 64 ? name.slice(64) : ""}`);
107
+ return { name, resolved: staged };
108
+ };
109
+ /**
110
+ * Retires recorded trees beyond `keep`, oldest-served first by the host's own order (never by
111
+ * filesystem mtimes). Names the host never recorded are reported and left in place.
112
+ */
113
+ const collectGarbage = (target, order, serving, now) => {
114
+ const treesDir = treesDirOf(target);
115
+ if (!assertRealDirectory(treesDir, "the fed volume's trees/ directory"))
116
+ return { removed: [], unknown: [] };
117
+ const present = readdirSync(treesDir, { withFileTypes: true });
118
+ const real = new Set(present.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
119
+ const unknown = present.map((entry) => entry.name).filter((name) => !order.includes(name)).sort();
120
+ const retired = order.filter((name) => name !== serving);
121
+ const doomed = retired.slice(0, Math.max(0, retired.length - target.keep));
122
+ for (const name of doomed) {
123
+ if (!real.has(name))
124
+ continue;
125
+ removeTree(parkTree(path.join(treesDir, name), feedTrashDir(target), stampOf(now)), { volume: target.volume });
126
+ }
127
+ return { removed: doomed, unknown };
128
+ };
129
+ export const landFeed = (target, resolved, record, { exact = false, force = false, heals = {}, period, runtime = {} } = {}) => {
130
+ const clock = runtime.now ?? (() => new Date()), log = runtime.log ?? (() => undefined), exec = runtime.exec ?? hostExec;
131
+ if (record && (target.record || record.recording))
132
+ ensureFeedLanding(target, record, clock());
133
+ // Preserve the existing timestamp behavior when recording is absent.
134
+ const started = target.record ? undefined : clock();
135
+ if (!assertRealDirectory(treesDirOf(target), "the fed volume's trees/ directory"))
136
+ mkdirSync(treesDirOf(target), { mode: 0o755 });
137
+ // A retained tree for this revision is reused only when the host recorded it and its manifest still
138
+ // describes it -- and it passes the validation policy as declared NOW, like any new tree.
139
+ const retained = force ? undefined : [...(record?.trees ?? [])].reverse().find((name) => name.slice(0, 64) === resolved.revision && treeMatches(target, name));
140
+ let name, landedSource = resolved;
141
+ if (retained) {
142
+ runFeedValidation(target, path.join(treesDirOf(target), retained), resolved);
143
+ name = retained;
144
+ }
145
+ else
146
+ ({ name, resolved: landedSource } = stageAndLand(target, resolved, { exact, exec, log }));
147
+ const revision = landedSource.revision;
148
+ let switchingAt;
149
+ const changed = pointCurrent(target.volume, feedTreeLink(name), { ops: runtime.ops ?? LINK_OPS, tmpDir: feedStagingDir(target),
150
+ ...(target.record ? { beforeRename: () => { switchingAt = clock().toISOString(); } } : {}) });
151
+ const now = started ?? clock();
152
+ if (changed)
153
+ log(`current -> ${feedTreeLink(name.slice(0, 12))}`);
154
+ const manifest = readFeedManifest(target.stateDir, name) ?? buildFeedManifest(path.join(treesDirOf(target), name), name);
155
+ const identity = {
156
+ files: manifest.files, landed_at: target.record ? now.toISOString() : isoSeconds(now), resource: target.resourceId, revision, source: landedSource.provenance,
157
+ tree: feedTreeLink(name), version: FEED_IDENTITY_VERSION, volume: target.volumeName
158
+ };
159
+ const identitySha = writeFeedIdentity(target.volume, identity, { owner: target.owner, tmpDir: feedStagingDir(target) });
160
+ // Order is serving history: the serving tree is always last.
161
+ let trees = [...(record?.trees ?? []).filter((entry) => entry !== name), name];
162
+ let previous = record;
163
+ const write = () => previous = publishFeedLanded(target, { heals, identity, identity_sha256: identitySha, ...(period ? { period } : {}), revision, tree: name, trees, version: FEED_LANDED_VERSION }, now, previous, switchingAt);
164
+ write();
165
+ const gc = collectGarbage(target, trees, name, now);
166
+ if (gc.removed.length) {
167
+ for (const removed of gc.removed)
168
+ removeFeedManifest(target.stateDir, removed);
169
+ trees = trees.filter((entry) => !gc.removed.includes(entry));
170
+ write();
171
+ log(`retired ${gc.removed.length} tree(s): ${gc.removed.map((entry) => entry.slice(0, 12)).join(", ")}`);
172
+ }
173
+ return { revision, reused: retained !== undefined, tree: name, treesRemoved: gc.removed, unknownTrees: gc.unknown };
174
+ };
@@ -0,0 +1,45 @@
1
+ import { type FeedLandedRecord } from "./feedRecord.js";
2
+ import type { FeedPreparedProvenance } from "./feedSource.js";
3
+ import type { FeedTarget } from "./feedTarget.js";
4
+ export declare const FEED_LANDING_VERSION = "spawnfile.volume-feed-landing.v1";
5
+ export declare const FEED_LANDINGS_FILE = "landings.jsonl";
6
+ export interface FeedLanding {
7
+ version: typeof FEED_LANDING_VERSION;
8
+ resource: string;
9
+ volume: string;
10
+ revision: string;
11
+ tree: string;
12
+ source: ({
13
+ kind: "git";
14
+ repo: string;
15
+ } | {
16
+ kind: "directory";
17
+ directory: string;
18
+ }) & {
19
+ prepared?: FeedPreparedProvenance;
20
+ };
21
+ commit?: string;
22
+ ref?: string;
23
+ paths?: string[];
24
+ switching_at: string;
25
+ landed_at: string;
26
+ period?: string;
27
+ }
28
+ export declare const isFeedLanding: (value: unknown) => value is FeedLanding;
29
+ /** Invalid lines are findings beside valid entries; an absent log is an empty history. */
30
+ export declare const readFeedLandings: (stateDir: string) => {
31
+ entries: FeedLanding[];
32
+ errors: string[];
33
+ };
34
+ /** A transition's inclusive window cannot identify which tree a concurrent reader observed. */
35
+ export declare const feedLandingAt: (entries: readonly FeedLanding[], instant: string | Date) => (FeedLanding & {
36
+ ambiguous?: true;
37
+ }) | null;
38
+ type LandingTarget = Pick<FeedTarget, "stateDir" | "record"> & Partial<Pick<FeedTarget, "source">>;
39
+ /** Call only after writing the corresponding landed.json; the existing feed lock serializes writers. */
40
+ export declare const appendFeedLanding: (target: LandingTarget, record: FeedLandedRecord, now: Date) => void;
41
+ /** A verified clean host record seeds opt-in history or repairs a previously failed append. */
42
+ export declare const ensureFeedLanding: (target: LandingTarget, record: FeedLandedRecord, now: Date) => void;
43
+ /** Reconcile the authoritative predecessor before ANY replacement, even a revision advance. */
44
+ export declare const publishFeedLanded: (target: FeedTarget, record: FeedLandedRecord, now: Date, previous: FeedLandedRecord | null, switchingAt?: string) => FeedLandedRecord;
45
+ export {};
@@ -0,0 +1,111 @@
1
+ // Recording history is host state, beside landed.json, and survives retirement of the physical trees.
2
+ import path from "node:path";
3
+ import { appendRetainedJsonl, entryAt, readRetainedJsonl, syncFileSync } from "../filesystem/index.js";
4
+ import { isFeedRevision, isFeedTreeName, writeFeedLanded } from "./feedRecord.js";
5
+ export const FEED_LANDING_VERSION = "spawnfile.volume-feed-landing.v1";
6
+ export const FEED_LANDINGS_FILE = "landings.jsonl";
7
+ const object = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
8
+ const text = (value) => typeof value === "string" && value.length > 0;
9
+ const stringArray = (value) => Array.isArray(value) && value.every(text);
10
+ const prepared = (value) => {
11
+ if (value === undefined)
12
+ return true;
13
+ if (!object(value) || !isFeedRevision(value.source_revision) || !Array.isArray(value.include))
14
+ return false;
15
+ if (!value.include.every((entry) => object(entry) && isFeedRevision(entry.digest) && text(entry.to)))
16
+ return false;
17
+ const recipe = value.prepare;
18
+ return recipe === null || (object(recipe) && stringArray(recipe.command)
19
+ && (recipe.image === null || text(recipe.image)) && (recipe.network === null || typeof recipe.network === "boolean")
20
+ && (recipe.platform === null || text(recipe.platform)));
21
+ };
22
+ export const isFeedLanding = (value) => {
23
+ if (!object(value) || value.version !== FEED_LANDING_VERSION || !text(value.resource) || !text(value.volume))
24
+ return false;
25
+ if (!isFeedRevision(value.revision) || !text(value.tree) || value.tree !== `trees/${value.tree.slice(6)}`
26
+ || !isFeedTreeName(value.tree.slice(6)) || value.tree.slice(6, 70) !== value.revision)
27
+ return false;
28
+ if (!text(value.landed_at) || !Number.isFinite(Date.parse(value.landed_at)))
29
+ return false;
30
+ if (!text(value.switching_at) || !Number.isFinite(Date.parse(value.switching_at))
31
+ || Date.parse(value.switching_at) > Date.parse(value.landed_at))
32
+ return false;
33
+ if (value.period !== undefined && (typeof value.period !== "string" || !/^\d{4}-\d{2}-\d{2}$/u.test(value.period)))
34
+ return false;
35
+ if (!object(value.source) || !prepared(value.source.prepared))
36
+ return false;
37
+ if (value.source.kind === "directory") {
38
+ return text(value.source.directory) && value.commit === undefined && value.ref === undefined && value.paths === undefined;
39
+ }
40
+ return value.source.kind === "git" && text(value.source.repo) && text(value.commit) && /^[0-9a-f]{40}(?:[0-9a-f]{24})?$/u.test(value.commit)
41
+ && text(value.ref) && (value.paths === undefined || stringArray(value.paths));
42
+ };
43
+ /** Invalid lines are findings beside valid entries; an absent log is an empty history. */
44
+ export const readFeedLandings = (stateDir) => readRetainedJsonl(path.join(stateDir, FEED_LANDINGS_FILE), isFeedLanding);
45
+ /** A transition's inclusive window cannot identify which tree a concurrent reader observed. */
46
+ export const feedLandingAt = (entries, instant) => {
47
+ const at = instant instanceof Date ? instant.getTime() : Date.parse(instant);
48
+ const transition = entryAt(entries.filter((entry) => at <= Date.parse(entry.landed_at)), instant, (entry) => entry.switching_at);
49
+ return transition ? { ...transition, ambiguous: true } : entryAt(entries, instant, (entry) => entry.landed_at);
50
+ };
51
+ const landingFromRecord = (target, record) => {
52
+ if (record.recording)
53
+ return record.recording.landing;
54
+ if (!target.source)
55
+ throw new Error("Landed record has no recoverable recording provenance");
56
+ const identity = record.identity, provenance = identity.source;
57
+ const source = target.source.kind === "git"
58
+ ? { kind: "git", repo: target.source.repo }
59
+ : { directory: target.source.directory, kind: "directory" };
60
+ if (provenance.prepared)
61
+ source.prepared = provenance.prepared;
62
+ return {
63
+ version: FEED_LANDING_VERSION, resource: identity.resource, volume: identity.volume,
64
+ revision: identity.revision, tree: identity.tree, source, switching_at: identity.landed_at, landed_at: identity.landed_at,
65
+ ...(provenance.kind === "git" ? { commit: provenance.commit, ref: provenance.ref, ...(provenance.paths ? { paths: provenance.paths } : {}) } : {}),
66
+ ...(record.period ? { period: record.period } : {})
67
+ };
68
+ };
69
+ /** Call only after writing the corresponding landed.json; the existing feed lock serializes writers. */
70
+ export const appendFeedLanding = (target, record, now) => {
71
+ const keepMs = record.recording?.keep_ms ?? target.record?.keepMs;
72
+ if (keepMs === undefined)
73
+ return;
74
+ const entry = landingFromRecord(target, record);
75
+ appendRetainedJsonl(path.join(target.stateDir, FEED_LANDINGS_FILE), entry, {
76
+ isEntry: isFeedLanding, keepMs, now, timeOf: (landing) => landing.landed_at
77
+ });
78
+ };
79
+ /** A verified clean host record seeds opt-in history or repairs a previously failed append. */
80
+ export const ensureFeedLanding = (target, record, now) => {
81
+ if (!target.record && !record.recording)
82
+ return;
83
+ const expected = JSON.stringify(landingFromRecord(target, record));
84
+ const history = readFeedLandings(target.stateDir);
85
+ if (history.errors.length)
86
+ throw new Error(`Cannot reconcile feed history: ${history.errors.join("; ")}`);
87
+ if (JSON.stringify(history.entries.at(-1)) === expected) {
88
+ syncFileSync(path.join(target.stateDir, FEED_LANDINGS_FILE));
89
+ return;
90
+ }
91
+ // Also covers recovery after a previous host-record directory fsync failed.
92
+ syncFileSync(path.join(target.stateDir, "landed.json"));
93
+ appendFeedLanding(target, record, now);
94
+ };
95
+ /** Reconcile the authoritative predecessor before ANY replacement, even a revision advance. */
96
+ export const publishFeedLanded = (target, record, now, previous, switchingAt) => {
97
+ if (previous)
98
+ ensureFeedLanding(target, previous, now);
99
+ const { recording: _previousRecording, ...next } = record;
100
+ const landing = target.record ? landingFromRecord(target, next) : undefined;
101
+ if (landing)
102
+ landing.switching_at = switchingAt
103
+ ?? (previous?.identity.landed_at === next.identity.landed_at ? previous.recording?.landing.switching_at : undefined)
104
+ ?? landing.landed_at;
105
+ const published = writeFeedLanded(target.stateDir, target.record ? {
106
+ ...next, recording: { keep_ms: target.record.keepMs, landing: landing }
107
+ } : next);
108
+ if (target.record)
109
+ ensureFeedLanding(target, published, now);
110
+ return published;
111
+ };