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,58 @@
1
+ import type { ReleaseFailureReason } from "./types.js";
2
+ export declare const RELEASE_NOTIFICATION_VERSION: "spawnfile.release-notification.v1";
3
+ export type NotifierConfig = {
4
+ kind: "command";
5
+ command: string;
6
+ } | {
7
+ kind: "none";
8
+ } | {
9
+ kind: "webhook";
10
+ urlEnv: string;
11
+ };
12
+ export interface ReleaseNotification {
13
+ at: string;
14
+ deployment: string;
15
+ host: string;
16
+ identity: string | null;
17
+ message: string;
18
+ reason: ReleaseFailureReason;
19
+ version: typeof RELEASE_NOTIFICATION_VERSION;
20
+ }
21
+ export interface NotifyResult {
22
+ channel: NotifierConfig["kind"];
23
+ delivered: boolean;
24
+ error?: string;
25
+ }
26
+ /**
27
+ * A notification says what broke, not where the box keeps things: anything
28
+ * path-shaped becomes `<path>` and the text is capped. The full detail stays
29
+ * in the release log on the host.
30
+ */
31
+ export declare const shortReason: (message: string) => string;
32
+ export declare const createNotification: (input: {
33
+ deployment: string;
34
+ identity: string | null;
35
+ message: string;
36
+ now?: Date;
37
+ reason: ReleaseFailureReason;
38
+ }) => ReleaseNotification;
39
+ /** Parses CLI declarations; at most one channel. */
40
+ export declare const resolveNotifierConfig: (options: {
41
+ notifyCommand?: string;
42
+ notifyWebhookEnv?: string;
43
+ }) => NotifierConfig;
44
+ export declare const resolveWebhookUrl: (env: NodeJS.ProcessEnv, name: string) => URL;
45
+ export interface NotifyDependencies {
46
+ attempts?: number;
47
+ env?: NodeJS.ProcessEnv;
48
+ fetchImpl?: typeof fetch;
49
+ runCommand?: (command: string, input: string, env: NodeJS.ProcessEnv, timeoutMs: number) => Promise<number | null>;
50
+ sleep?: (ms: number) => Promise<void>;
51
+ timeoutMs?: number;
52
+ }
53
+ /**
54
+ * Never throws: a notifier that crashed the release reporting the failure
55
+ * would be worse than none. The caller records the result in the release log,
56
+ * so an undelivered notification still leaves its text on disk.
57
+ */
58
+ export declare const sendNotification: (config: NotifierConfig, notification: ReleaseNotification, deps?: NotifyDependencies) => Promise<NotifyResult>;
@@ -0,0 +1,126 @@
1
+ import { spawn } from "node:child_process";
2
+ import { hostname } from "node:os";
3
+ import path from "node:path";
4
+ export const RELEASE_NOTIFICATION_VERSION = "spawnfile.release-notification.v1";
5
+ const MAX_MESSAGE_CHARS = 500;
6
+ const PATHLIKE = /(?:\/[A-Za-z0-9._@-]+){2,}\/?/gu;
7
+ /**
8
+ * A notification says what broke, not where the box keeps things: anything
9
+ * path-shaped becomes `<path>` and the text is capped. The full detail stays
10
+ * in the release log on the host.
11
+ */
12
+ export const shortReason = (message) => {
13
+ const scrubbed = message.replace(PATHLIKE, "<path>").replace(/\s+/gu, " ").trim();
14
+ return scrubbed.length > MAX_MESSAGE_CHARS ? `${scrubbed.slice(0, MAX_MESSAGE_CHARS - 1)}…` : scrubbed;
15
+ };
16
+ export const createNotification = (input) => ({
17
+ at: (input.now ?? new Date()).toISOString(),
18
+ deployment: input.deployment,
19
+ host: hostname(),
20
+ identity: input.identity,
21
+ message: shortReason(input.message),
22
+ reason: input.reason,
23
+ version: RELEASE_NOTIFICATION_VERSION
24
+ });
25
+ /** Parses CLI declarations; at most one channel. */
26
+ export const resolveNotifierConfig = (options) => {
27
+ if (options.notifyCommand !== undefined && options.notifyWebhookEnv !== undefined) {
28
+ throw new Error("declare one notifier: --notify-command or --notify-webhook-env, not both");
29
+ }
30
+ if (options.notifyCommand !== undefined) {
31
+ if (!path.isAbsolute(options.notifyCommand))
32
+ throw new Error("--notify-command must be an absolute path to an executable");
33
+ return { command: options.notifyCommand, kind: "command" };
34
+ }
35
+ if (options.notifyWebhookEnv !== undefined) {
36
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/u.test(options.notifyWebhookEnv))
37
+ throw new Error("--notify-webhook-env must name an environment variable");
38
+ return { kind: "webhook", urlEnv: options.notifyWebhookEnv };
39
+ }
40
+ return { kind: "none" };
41
+ };
42
+ const LOOPBACK = new Set(["127.0.0.1", "localhost", "[::1]"]);
43
+ export const resolveWebhookUrl = (env, name) => {
44
+ const raw = env[name];
45
+ if (!raw)
46
+ throw new Error(`${name} is not set, so the webhook notifier has no URL`);
47
+ let url;
48
+ try {
49
+ url = new URL(raw);
50
+ }
51
+ catch {
52
+ throw new Error(`${name} is not a URL`);
53
+ }
54
+ if (url.protocol !== "https:" && !(url.protocol === "http:" && LOOPBACK.has(url.hostname))) {
55
+ throw new Error(`${name} must be an https URL (plain http only for loopback)`);
56
+ }
57
+ return url;
58
+ };
59
+ const runNotifierCommand = (command, input, env, timeoutMs) => new Promise((resolve, reject) => {
60
+ const child = spawn(command, [], { env, stdio: ["pipe", "ignore", "ignore"] });
61
+ const timer = setTimeout(() => child.kill("SIGKILL"), timeoutMs);
62
+ child.once("error", (error) => { clearTimeout(timer); reject(error); });
63
+ child.once("close", (code) => { clearTimeout(timer); resolve(code); });
64
+ child.stdin.on("error", () => undefined);
65
+ child.stdin.end(input);
66
+ });
67
+ const notifyCommand = async (command, notification, deps) => {
68
+ const env = {
69
+ ...(deps.env ?? process.env),
70
+ SPAWNFILE_RELEASE_DEPLOYMENT: notification.deployment,
71
+ SPAWNFILE_RELEASE_IDENTITY: notification.identity ?? "",
72
+ SPAWNFILE_RELEASE_MESSAGE: notification.message,
73
+ SPAWNFILE_RELEASE_REASON: notification.reason
74
+ };
75
+ try {
76
+ const code = await (deps.runCommand ?? runNotifierCommand)(command, `${JSON.stringify(notification)}\n`, env, deps.timeoutMs ?? 60_000);
77
+ return code === 0 ? { channel: "command", delivered: true } : { channel: "command", delivered: false, error: `notifier exited ${code ?? "by signal"}` };
78
+ }
79
+ catch (error) {
80
+ return { channel: "command", delivered: false, error: `notifier could not run: ${error.message}` };
81
+ }
82
+ };
83
+ const notifyWebhook = async (urlEnv, notification, deps) => {
84
+ let url;
85
+ try {
86
+ url = resolveWebhookUrl(deps.env ?? process.env, urlEnv);
87
+ }
88
+ catch (error) {
89
+ return { channel: "webhook", delivered: false, error: error.message };
90
+ }
91
+ const attempts = deps.attempts ?? 3;
92
+ const sleep = deps.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
93
+ const errors = [];
94
+ for (let attempt = 1; attempt <= attempts; attempt += 1) {
95
+ try {
96
+ const response = await (deps.fetchImpl ?? fetch)(url, {
97
+ body: JSON.stringify(notification),
98
+ headers: { "content-type": "application/json" },
99
+ method: "POST",
100
+ redirect: "error",
101
+ signal: AbortSignal.timeout(deps.timeoutMs ?? 15_000)
102
+ });
103
+ if (response.ok)
104
+ return { channel: "webhook", delivered: true };
105
+ errors.push(`HTTP ${response.status}`);
106
+ }
107
+ catch (error) {
108
+ errors.push(error.name === "TimeoutError" ? "timed out" : "request failed");
109
+ }
110
+ if (attempt < attempts)
111
+ await sleep(attempt * 2_000);
112
+ }
113
+ return { channel: "webhook", delivered: false, error: errors.join("; ") };
114
+ };
115
+ /**
116
+ * Never throws: a notifier that crashed the release reporting the failure
117
+ * would be worse than none. The caller records the result in the release log,
118
+ * so an undelivered notification still leaves its text on disk.
119
+ */
120
+ export const sendNotification = async (config, notification, deps = {}) => {
121
+ if (config.kind === "command")
122
+ return notifyCommand(config.command, notification, deps);
123
+ if (config.kind === "webhook")
124
+ return notifyWebhook(config.urlEnv, notification, deps);
125
+ return { channel: "none", delivered: false, error: "no notifier declared" };
126
+ };
@@ -0,0 +1,35 @@
1
+ import { z } from "zod";
2
+ export declare const RELEASE_PENDING_VERSION: "spawnfile.release-pending.v1";
3
+ declare const pendingSchema: z.ZodObject<{
4
+ identity: z.ZodString;
5
+ notified_at: z.ZodNullable<z.ZodString>;
6
+ since: z.ZodString;
7
+ version: z.ZodLiteral<"spawnfile.release-pending.v1">;
8
+ }, z.core.$strict>;
9
+ export type ReleasePending = z.infer<typeof pendingSchema>;
10
+ export interface DeferralDecision {
11
+ ageMs: number;
12
+ /** True exactly once per pending identity after the threshold, or whenever tracking is broken. */
13
+ notify: boolean;
14
+ pending: ReleasePending;
15
+ /** Set when the record that holds "waiting since" could not be read or written. */
16
+ trackingBroken: string | null;
17
+ }
18
+ /**
19
+ * A drain that times out is "not yet", not "broken": on a timer that runs
20
+ * hourly, notifying on every busy hour teaches whoever receives it to ignore
21
+ * the channel. It must not hide forever either, so the instant this identity
22
+ * first deferred is kept beside the ledger and a person hears about it once
23
+ * it has waited longer than `notifyAfterMs`.
24
+ *
25
+ * The record is the only thing that turns "forever" into one notification,
26
+ * so a record that cannot be read or written is itself notified immediately,
27
+ * never silently restarted.
28
+ */
29
+ export declare const recordDeferral: (file: string, identity: string, options: {
30
+ notifyAfterMs: number;
31
+ now?: Date;
32
+ }) => Promise<DeferralDecision>;
33
+ export declare const markDeferralNotified: (file: string, pending: ReleasePending, now?: Date) => Promise<void>;
34
+ export declare const clearDeferral: (file: string) => Promise<void>;
35
+ export {};
@@ -0,0 +1,60 @@
1
+ import { readFile, rm } from "node:fs/promises";
2
+ import { z } from "zod";
3
+ import { writeJsonAtomic } from "./ledger.js";
4
+ export const RELEASE_PENDING_VERSION = "spawnfile.release-pending.v1";
5
+ const pendingSchema = z.object({
6
+ identity: z.string().min(1),
7
+ notified_at: z.string().min(1).nullable(),
8
+ since: z.string().min(1),
9
+ version: z.literal(RELEASE_PENDING_VERSION)
10
+ }).strict();
11
+ /**
12
+ * A drain that times out is "not yet", not "broken": on a timer that runs
13
+ * hourly, notifying on every busy hour teaches whoever receives it to ignore
14
+ * the channel. It must not hide forever either, so the instant this identity
15
+ * first deferred is kept beside the ledger and a person hears about it once
16
+ * it has waited longer than `notifyAfterMs`.
17
+ *
18
+ * The record is the only thing that turns "forever" into one notification,
19
+ * so a record that cannot be read or written is itself notified immediately,
20
+ * never silently restarted.
21
+ */
22
+ export const recordDeferral = async (file, identity, options) => {
23
+ const now = options.now ?? new Date();
24
+ let previous = null;
25
+ let trackingBroken = null;
26
+ try {
27
+ previous = pendingSchema.parse(JSON.parse(await readFile(file, "utf8")));
28
+ }
29
+ catch (error) {
30
+ if (error.code !== "ENOENT") {
31
+ trackingBroken = `the pending-release record ${file} cannot be read`;
32
+ }
33
+ }
34
+ const pending = previous?.identity === identity
35
+ ? { ...previous }
36
+ : { identity, notified_at: null, since: now.toISOString(), version: RELEASE_PENDING_VERSION };
37
+ const since = Date.parse(pending.since);
38
+ const notifiedAt = pending.notified_at === null ? 0 : Date.parse(pending.notified_at);
39
+ if (!Number.isFinite(since) || !Number.isFinite(notifiedAt)) {
40
+ // A record that parses but holds no usable instant is as broken as one that does not parse.
41
+ trackingBroken = `the pending-release record ${file} holds an unreadable timestamp`;
42
+ }
43
+ const ageMs = Number.isFinite(since) ? Math.max(0, now.getTime() - since) : 0;
44
+ // `notified_at` is set only once a notification was actually delivered
45
+ // (markDeferralNotified), so a failed or crashed delivery is retried next run.
46
+ const escalate = ageMs >= options.notifyAfterMs && pending.notified_at === null;
47
+ try {
48
+ await writeJsonAtomic(file, pending);
49
+ }
50
+ catch {
51
+ trackingBroken = `the pending-release record ${file} could not be written`;
52
+ }
53
+ return { ageMs, notify: escalate || trackingBroken !== null, pending, trackingBroken };
54
+ };
55
+ export const markDeferralNotified = async (file, pending, now = new Date()) => {
56
+ await writeJsonAtomic(file, { ...pending, notified_at: now.toISOString() });
57
+ };
58
+ export const clearDeferral = async (file) => {
59
+ await rm(file, { force: true });
60
+ };
@@ -0,0 +1,32 @@
1
+ /**
2
+ * A caller-declared step that must succeed on the new container before the
3
+ * release counts as done (for example installing a credential the image
4
+ * cannot carry). Executed without a shell; it must be idempotent, because a
5
+ * failure leaves the release unrecorded and the next run deploys and runs it
6
+ * again.
7
+ */
8
+ export interface PostDeployHook {
9
+ args: string[];
10
+ command: string;
11
+ timeoutMs: number;
12
+ }
13
+ export interface PostDeployContext {
14
+ containerName: string;
15
+ deployment: string;
16
+ identity: string;
17
+ imageId: string;
18
+ imageTag: string;
19
+ }
20
+ export interface PostDeployResult {
21
+ /** Null when the process ended by signal (including the timeout). */
22
+ exitCode: number | null;
23
+ output: string;
24
+ timedOut: boolean;
25
+ }
26
+ export declare const resolvePostDeployHook: (options: {
27
+ postDeployArg?: string[];
28
+ postDeployCommand?: string;
29
+ timeoutMs: number;
30
+ }) => PostDeployHook | null;
31
+ export declare const postDeployEnvironment: (context: PostDeployContext, env?: NodeJS.ProcessEnv) => NodeJS.ProcessEnv;
32
+ export declare const runPostDeployCommand: (hook: PostDeployHook, context: PostDeployContext, signal?: AbortSignal) => Promise<PostDeployResult>;
@@ -0,0 +1,62 @@
1
+ import { spawn } from "node:child_process";
2
+ import path from "node:path";
3
+ const MAX_OUTPUT_CHARS = 4_000;
4
+ const MAX_TIMEOUT_MS = 24 * 3_600_000;
5
+ export const resolvePostDeployHook = (options) => {
6
+ if (options.postDeployCommand === undefined) {
7
+ if (options.postDeployArg?.length)
8
+ throw new Error("--post-deploy-arg needs --post-deploy-command");
9
+ return null;
10
+ }
11
+ if (!path.isAbsolute(options.postDeployCommand))
12
+ throw new Error("--post-deploy-command must be an absolute path to an executable");
13
+ if (options.timeoutMs > MAX_TIMEOUT_MS)
14
+ throw new Error("--post-deploy-timeout must be at most 24h");
15
+ return { args: options.postDeployArg ?? [], command: options.postDeployCommand, timeoutMs: options.timeoutMs };
16
+ };
17
+ export const postDeployEnvironment = (context, env = process.env) => ({
18
+ ...env,
19
+ SPAWNFILE_RELEASE_CONTAINER: context.containerName,
20
+ SPAWNFILE_RELEASE_DEPLOYMENT: context.deployment,
21
+ SPAWNFILE_RELEASE_IDENTITY: context.identity,
22
+ SPAWNFILE_RELEASE_IMAGE: context.imageTag,
23
+ SPAWNFILE_RELEASE_IMAGE_ID: context.imageId
24
+ });
25
+ /** Keeps the tail: the end of a failing script's output is where it says why. */
26
+ const appendBounded = (current, chunk) => {
27
+ const next = current + chunk;
28
+ return next.length > MAX_OUTPUT_CHARS ? next.slice(next.length - MAX_OUTPUT_CHARS) : next;
29
+ };
30
+ /** Kills the hook's whole process group: a descendant holding its pipes must not outlive it. */
31
+ const killGroup = (pid) => {
32
+ if (pid === undefined)
33
+ return;
34
+ try {
35
+ process.kill(-pid, "SIGKILL");
36
+ }
37
+ catch { /* already gone */ }
38
+ };
39
+ export const runPostDeployCommand = (hook, context, signal) => new Promise((resolve, reject) => {
40
+ if (signal?.aborted) {
41
+ reject(new Error("aborted before the post-deploy command started"));
42
+ return;
43
+ }
44
+ let output = "";
45
+ let timedOut = false;
46
+ // Its own process group, so a timeout or abort reaches every descendant.
47
+ const child = spawn(hook.command, hook.args, { detached: true, env: postDeployEnvironment(context), stdio: ["ignore", "pipe", "pipe"] });
48
+ const kill = () => { killGroup(child.pid); };
49
+ const timer = setTimeout(() => { timedOut = true; kill(); }, hook.timeoutMs);
50
+ signal?.addEventListener("abort", kill, { once: true });
51
+ const done = () => {
52
+ clearTimeout(timer);
53
+ signal?.removeEventListener("abort", kill);
54
+ };
55
+ const collect = (chunk) => { output = appendBounded(output, chunk.toString("utf8")); };
56
+ child.stdout.on("data", collect);
57
+ child.stderr.on("data", collect);
58
+ child.once("error", (error) => { done(); reject(error); });
59
+ // Leftover descendants would hold the pipes open and delay `close` forever.
60
+ child.once("exit", () => { killGroup(child.pid); });
61
+ child.once("close", (code) => { done(); resolve({ exitCode: code, output, timedOut }); });
62
+ });
@@ -0,0 +1,9 @@
1
+ import type { ReleaseDependencies } from "./releaseTypes.js";
2
+ /**
3
+ * The production effects. The identity is the Docker build-context digest the
4
+ * build cache already keys on: a function of everything the image is built
5
+ * from (compiled workspaces, bundles, runtime installs, target architecture),
6
+ * so a change that does not reach the image does not release, and one that
7
+ * does always does.
8
+ */
9
+ export declare const createDefaultReleaseDependencies: () => ReleaseDependencies;
@@ -0,0 +1,115 @@
1
+ import { execFile as execFileCallback } from "node:child_process";
2
+ import { performance } from "node:perf_hooks";
3
+ import { promisify } from "node:util";
4
+ import { buildCompiledProject, createDefaultImageTag, resolveDockerBuildArchitecture, resolveImageTagRoot } from "../compiler/buildProject.js";
5
+ import { compileProject } from "../compiler/compileProject.js";
6
+ import { createDockerBuildContextDigest } from "../compiler/dockerBuildContext.js";
7
+ import { inspectDockerImage } from "../compiler/dockerBuildSkip.js";
8
+ import { requireAuthProfile } from "../auth/index.js";
9
+ import { readRunEnvFile } from "../compiler/runProjectAuth.js";
10
+ import { acquireHomeDeploymentLock, resolveDockerDeploymentTarget, verifyDockerDeploymentTarget } from "../deployment/index.js";
11
+ import { consumeImageUp, createConsumerDockerRunner, extractImageReport, resolveDockerBaseArgs } from "../distribution/index.js";
12
+ import { helperControlCall, requestDrain, requestResume, waitForDrained } from "./drainControl.js";
13
+ import { sendNotification } from "./notify.js";
14
+ import { runPostDeployCommand } from "./postDeploy.js";
15
+ import { inspectUnit, pruneReleaseImages, settleUnit } from "./releaseDocker.js";
16
+ const execFile = promisify(execFileCallback);
17
+ const dockerFor = (request) => createConsumerDockerRunner(request.dockerCommand, resolveDockerBaseArgs({
18
+ ...(request.dockerContext ? { dockerContext: request.dockerContext } : {}),
19
+ ...(request.dockerHost ? { dockerHost: request.dockerHost } : {})
20
+ }));
21
+ /**
22
+ * The production effects. The identity is the Docker build-context digest the
23
+ * build cache already keys on: a function of everything the image is built
24
+ * from (compiled workspaces, bundles, runtime installs, target architecture),
25
+ * so a change that does not reach the image does not release, and one that
26
+ * does always does.
27
+ */
28
+ export const createDefaultReleaseDependencies = () => ({
29
+ async build(request, compiled, imageTag) {
30
+ const result = await buildCompiledProject(request.inputPath, compiled.compileResult, {
31
+ contextDigest: compiled.identity,
32
+ dockerCommand: request.dockerCommand,
33
+ ...(request.dockerContext ? { dockerContext: request.dockerContext } : {}),
34
+ imageTag
35
+ });
36
+ const image = await inspectDockerImage({ dockerCommand: request.dockerCommand, dockerContext: request.dockerContext ?? null, imageTag });
37
+ if (image === null)
38
+ throw new Error(`built image ${imageTag} cannot be inspected`);
39
+ return { buildMs: result.imageBuild?.buildMs ?? null, imageId: image.id, imageTag, skipped: result.imageBuild?.skipped ?? false };
40
+ },
41
+ async compile(request) {
42
+ const started = performance.now();
43
+ const containerArchitecture = await resolveDockerBuildArchitecture({
44
+ dockerCommand: request.dockerCommand,
45
+ ...(request.dockerContext ? { dockerContext: request.dockerContext } : {})
46
+ });
47
+ const compileResult = await compileProject(request.inputPath, {
48
+ bundleIdentity: request.bundleIdentity,
49
+ ...(containerArchitecture ? { containerArchitecture } : {}),
50
+ ...(request.outputDirectory ? { outputDirectory: request.outputDirectory } : {})
51
+ });
52
+ const identity = await createDockerBuildContextDigest(compileResult.outputDirectory);
53
+ return {
54
+ compileMs: performance.now() - started,
55
+ compileResult,
56
+ identity,
57
+ repository: request.imageRepository ?? createDefaultImageTag(resolveImageTagRoot(request.inputPath))
58
+ };
59
+ },
60
+ async deploy(request, imageTag) {
61
+ const started = performance.now();
62
+ const result = await consumeImageUp(imageTag, {
63
+ authProfile: request.authProfile ?? null,
64
+ authProfileName: request.authProfileName ?? null,
65
+ authValues: request.authProfile?.env ?? {},
66
+ deploymentLockHeld: true,
67
+ deploymentName: request.deployment,
68
+ dockerCommand: request.dockerCommand,
69
+ ...(request.dockerContext ? { dockerContext: request.dockerContext } : {}),
70
+ ...(request.dockerHost ? { dockerHost: request.dockerHost } : {}),
71
+ envFileEnv: request.envFileEnv,
72
+ envFilePath: request.envFilePath ?? null,
73
+ now: request.now
74
+ });
75
+ return { containerName: result.containerName, deployMs: performance.now() - started };
76
+ },
77
+ inspectUnit: (request, containerRef) => inspectUnit(dockerFor(request), containerRef),
78
+ notify: (config, notification) => sendNotification(config, notification),
79
+ prune: (request, repository, keep) => pruneReleaseImages(dockerFor(request), repository, keep),
80
+ lockDeployment: (deployment) => acquireHomeDeploymentLock(deployment),
81
+ async prepare(request) {
82
+ return {
83
+ authProfile: request.authProfileName ? await requireAuthProfile(request.authProfileName) : null,
84
+ envFileEnv: await readRunEnvFile(request.envFilePath)
85
+ };
86
+ },
87
+ async runtimesOf(request, imageId) {
88
+ const inspection = await extractImageReport(imageId, {
89
+ dockerCommand: request.dockerCommand,
90
+ ...(request.dockerContext ? { dockerContext: request.dockerContext } : {}),
91
+ ...(request.dockerHost ? { dockerHost: request.dockerHost } : {})
92
+ });
93
+ return inspection.report.runtime_instances.map((instance) => instance.runtime);
94
+ },
95
+ requestDrain: (target) => requestDrain(target, helperControlCall),
96
+ async pinTarget(request) {
97
+ // Not the deployment record's target: image-mode `up` runs Docker against
98
+ // the explicit context or the CLI's own default and only records a target,
99
+ // so the record can name a daemon the deployment does not live on.
100
+ if (request.dockerContext)
101
+ return resolveDockerDeploymentTarget({ context: request.dockerContext, dockerCommand: request.dockerCommand });
102
+ if (process.env.DOCKER_HOST?.trim())
103
+ return resolveDockerDeploymentTarget({ dockerCommand: request.dockerCommand });
104
+ // What a bare `docker` command would use: DOCKER_CONTEXT, else the selected context.
105
+ const { stdout } = await execFile(request.dockerCommand, ["context", "show"], { timeout: 10_000 });
106
+ return resolveDockerDeploymentTarget({ context: stdout.trim() || "default", dockerCommand: request.dockerCommand });
107
+ },
108
+ async verifyTarget(request, target) {
109
+ await verifyDockerDeploymentTarget(target, { dockerCommand: request.dockerCommand });
110
+ },
111
+ requestResume: (target) => requestResume(target, helperControlCall),
112
+ runPostDeploy: (request, hook, context) => runPostDeployCommand(hook, context, request.signal),
113
+ settle: (request, containerRef) => settleUnit(dockerFor(request), containerRef, request.settle),
114
+ waitForDrained: (target, options) => waitForDrained(target, { call: helperControlCall, ...options })
115
+ });
@@ -0,0 +1,38 @@
1
+ import type { DockerCommandRunner } from "../distribution/dockerRunner.js";
2
+ /** Release images are `<repository>:r-<first 12 hex of the identity>`. */
3
+ export declare const RELEASE_TAG_PREFIX = "r-";
4
+ export declare const releaseImageTag: (repository: string, identity: string) => string;
5
+ export interface RunningUnit {
6
+ health: string;
7
+ id: string;
8
+ imageId: string;
9
+ restartCount: number;
10
+ running: boolean;
11
+ }
12
+ /** Null when the container does not exist; a container that exists but cannot be parsed is an error. */
13
+ export declare const inspectUnit: (runDocker: DockerCommandRunner, containerRef: string) => Promise<RunningUnit | null>;
14
+ export interface SettleOptions {
15
+ pollMs: number;
16
+ polls: number;
17
+ sleep?: (ms: number) => Promise<void>;
18
+ stablePolls: number;
19
+ }
20
+ /**
21
+ * Started is not working. A container that is "running (health: starting)"
22
+ * has proved nothing, and a crash-looping one reports `running` between
23
+ * restarts, so this waits until the same healthy observation, restart count
24
+ * included, holds for `stablePolls` consecutive polls.
25
+ */
26
+ export declare const settleUnit: (runDocker: DockerCommandRunner, containerRef: string, options: SettleOptions) => Promise<RunningUnit>;
27
+ export interface PruneResult {
28
+ kept: string[];
29
+ removed: string[];
30
+ skipped: string[];
31
+ }
32
+ /**
33
+ * Bounded disk: keeps the running image and one rollback, removes every other
34
+ * release tag of this repository. Only ever touches `<repository>:r-*` tags a
35
+ * release created, never an image any container (running or stopped, any
36
+ * deployment) still uses, never a volume, never build cache, never `prune`.
37
+ */
38
+ export declare const pruneReleaseImages: (runDocker: DockerCommandRunner, repository: string, keepTags: readonly (string | null | undefined)[]) => Promise<PruneResult>;
@@ -0,0 +1,94 @@
1
+ import { ReleaseError } from "./types.js";
2
+ /** Release images are `<repository>:r-<first 12 hex of the identity>`. */
3
+ export const RELEASE_TAG_PREFIX = "r-";
4
+ export const releaseImageTag = (repository, identity) => `${repository}:${RELEASE_TAG_PREFIX}${identity.replace(/^sha256:/u, "").slice(0, 12)}`;
5
+ // `.State.Health` is absent (not null) without a healthcheck, and Go templates
6
+ // fail on a missing map key, so the whole State object is read and parsed here.
7
+ const INSPECT_FORMAT = "{{json .Id}}\t{{json .Image}}\t{{json .State}}\t{{json .RestartCount}}";
8
+ /** Null when the container does not exist; a container that exists but cannot be parsed is an error. */
9
+ export const inspectUnit = async (runDocker, containerRef) => {
10
+ let raw;
11
+ try {
12
+ raw = (await runDocker(["container", "inspect", "--format", INSPECT_FORMAT, containerRef], { timeoutMs: 15_000 })).toString("utf8").trim();
13
+ }
14
+ catch (error) {
15
+ if (/no such (container|object)/iu.test(error.message))
16
+ return null;
17
+ throw new ReleaseError("blocked", `cannot inspect container ${containerRef}: ${error.message.slice(0, 200)}`);
18
+ }
19
+ try {
20
+ const [id, imageId, state, restarts] = raw.split("\t").map((field) => JSON.parse(field));
21
+ const { Health: health, Running: running } = (state ?? {});
22
+ const status = health === undefined || health === null ? "none" : health.Status;
23
+ if (typeof id !== "string" || typeof imageId !== "string" || typeof running !== "boolean" || typeof status !== "string" || typeof restarts !== "number")
24
+ throw new Error();
25
+ return { health: status, id, imageId, restartCount: restarts, running };
26
+ }
27
+ catch {
28
+ throw new ReleaseError("blocked", `container ${containerRef} returned an unreadable inspection`);
29
+ }
30
+ };
31
+ /**
32
+ * Started is not working. A container that is "running (health: starting)"
33
+ * has proved nothing, and a crash-looping one reports `running` between
34
+ * restarts, so this waits until the same healthy observation, restart count
35
+ * included, holds for `stablePolls` consecutive polls.
36
+ */
37
+ export const settleUnit = async (runDocker, containerRef, options) => {
38
+ const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
39
+ let last = null;
40
+ let stable = 0;
41
+ let observed = null;
42
+ for (let poll = 0; poll < options.polls; poll += 1) {
43
+ let failure = null;
44
+ observed = await inspectUnit(runDocker, containerRef).catch((error) => { failure = error.message.slice(0, 160); return null; });
45
+ const healthy = observed !== null && observed.running && (observed.health === "healthy" || observed.health === "none");
46
+ const key = observed ? `${observed.id} ${observed.running} ${observed.health} ${observed.restartCount}` : failure ?? "missing";
47
+ stable = healthy && key === last ? stable + 1 : healthy ? 1 : 0;
48
+ last = key;
49
+ if (stable >= options.stablePolls)
50
+ return observed;
51
+ if (poll + 1 < options.polls)
52
+ await sleep(options.pollMs);
53
+ }
54
+ throw new ReleaseError("health-failed", `the deployed container never settled healthy; last observed: ${last ?? "nothing"}`);
55
+ };
56
+ const inUseImageIds = async (runDocker) => {
57
+ const ids = (await runDocker(["ps", "-a", "-q", "--no-trunc"])).toString("utf8").split("\n").map((line) => line.trim()).filter(Boolean);
58
+ if (ids.length === 0)
59
+ return new Set();
60
+ const images = (await runDocker(["container", "inspect", "--format", "{{.Image}}", ...ids])).toString("utf8");
61
+ return new Set(images.split("\n").map((line) => line.trim()).filter(Boolean));
62
+ };
63
+ /**
64
+ * Bounded disk: keeps the running image and one rollback, removes every other
65
+ * release tag of this repository. Only ever touches `<repository>:r-*` tags a
66
+ * release created, never an image any container (running or stopped, any
67
+ * deployment) still uses, never a volume, never build cache, never `prune`.
68
+ */
69
+ export const pruneReleaseImages = async (runDocker, repository, keepTags) => {
70
+ const keep = new Set(keepTags.filter((tag) => typeof tag === "string"));
71
+ const listed = (await runDocker(["image", "ls", repository, "--no-trunc", "--format", "{{.Tag}}\t{{.ID}}"])).toString("utf8")
72
+ .split("\n").map((line) => line.trim().split("\t")).filter((row) => row.length === 2 && row[0].startsWith(RELEASE_TAG_PREFIX));
73
+ const used = await inUseImageIds(runDocker);
74
+ const result = { kept: [], removed: [], skipped: [] };
75
+ for (const [tag, id] of listed) {
76
+ const ref = `${repository}:${tag}`;
77
+ if (keep.has(ref)) {
78
+ result.kept.push(ref);
79
+ continue;
80
+ }
81
+ if (used.has(id)) {
82
+ result.skipped.push(ref);
83
+ continue;
84
+ }
85
+ try {
86
+ await runDocker(["image", "rm", ref]);
87
+ result.removed.push(ref);
88
+ }
89
+ catch {
90
+ result.skipped.push(ref);
91
+ }
92
+ }
93
+ return result;
94
+ };