@mannyc1/ts-release 0.0.7 → 0.2.2

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 (635) hide show
  1. package/ARCHITECTURE.md +124 -92
  2. package/CHANGELOG.md +115 -0
  3. package/LICENSE +21 -0
  4. package/README.md +278 -324
  5. package/SPEC.md +206 -310
  6. package/apps/release-ts/README.md +32 -0
  7. package/apps/release-ts/src/cli/command.ts +164 -0
  8. package/apps/release-ts/src/cli/commands.ts +351 -0
  9. package/apps/release-ts/src/cli/main.ts +43 -0
  10. package/apps/release-ts/src/cli/node-main.ts +49 -0
  11. package/apps/ts-release-agents/LICENSE +21 -0
  12. package/apps/ts-release-agents/README.md +21 -0
  13. package/apps/ts-release-agents/evals/cases.json +11 -0
  14. package/apps/ts-release-agents/manifests/claude.json +5 -0
  15. package/apps/ts-release-agents/manifests/codex.json +5 -0
  16. package/apps/ts-release-agents/package.json +11 -0
  17. package/apps/ts-release-agents/skills/release/SKILL.md +48 -0
  18. package/apps/ts-release-agents/skills/release/references/configuration.md +18 -0
  19. package/apps/ts-release-agents/skills/release/references/recovery.md +10 -0
  20. package/apps/ts-release-agents/skills/release/references/staged-workflow.md +12 -0
  21. package/apps/ts-release-agents/skills/release/references/target-selection.md +13 -0
  22. package/apps/ts-release-agents/skills/release/references/verification.md +14 -0
  23. package/apps/ts-release-agents/src/build.ts +105 -0
  24. package/apps/ts-release-agents/src/check.ts +117 -0
  25. package/apps/ts-release-agents/src/install.ts +121 -0
  26. package/apps/ts-release-agents/test/contract.test.ts +56 -0
  27. package/apps/ts-release-agents/tsconfig.json +5 -0
  28. package/dist/api/api.d.ts +15 -0
  29. package/dist/api/api.d.ts.map +1 -0
  30. package/dist/api/api.js +244 -0
  31. package/dist/api/api.js.map +1 -0
  32. package/dist/api/errors.d.ts +39 -0
  33. package/dist/api/errors.d.ts.map +1 -0
  34. package/dist/api/errors.js +32 -0
  35. package/dist/api/errors.js.map +1 -0
  36. package/dist/api/input.d.ts +10 -0
  37. package/dist/api/input.d.ts.map +1 -0
  38. package/dist/api/input.js +73 -0
  39. package/dist/api/input.js.map +1 -0
  40. package/dist/api/runtime.d.ts +18 -0
  41. package/dist/api/runtime.d.ts.map +1 -0
  42. package/dist/api/runtime.js +7 -0
  43. package/dist/api/runtime.js.map +1 -0
  44. package/dist/api/types.d.ts +76 -0
  45. package/dist/api/types.d.ts.map +1 -0
  46. package/dist/api/types.js +17 -0
  47. package/dist/api/types.js.map +1 -0
  48. package/dist/bin/ts-release.js +39239 -0
  49. package/dist/capabilities/bun-targets.d.ts +3 -0
  50. package/dist/capabilities/bun-targets.d.ts.map +1 -0
  51. package/dist/capabilities/bun-targets.js +3 -0
  52. package/dist/capabilities/bun-targets.js.map +1 -0
  53. package/dist/capabilities/field-ownership.d.ts +17 -0
  54. package/dist/capabilities/field-ownership.d.ts.map +1 -0
  55. package/dist/capabilities/field-ownership.js +40 -0
  56. package/dist/capabilities/field-ownership.js.map +1 -0
  57. package/dist/capabilities/module.d.ts +91 -0
  58. package/dist/capabilities/module.d.ts.map +1 -0
  59. package/dist/capabilities/module.js +2 -0
  60. package/dist/capabilities/module.js.map +1 -0
  61. package/dist/capabilities/registry.d.ts +829 -0
  62. package/dist/capabilities/registry.d.ts.map +1 -0
  63. package/dist/capabilities/registry.js +291 -0
  64. package/dist/capabilities/registry.js.map +1 -0
  65. package/dist/config/config.d.ts +6 -0
  66. package/dist/config/config.d.ts.map +1 -0
  67. package/dist/config/config.js +42 -0
  68. package/dist/config/config.js.map +1 -0
  69. package/dist/correction/coordinator.d.ts +248 -0
  70. package/dist/correction/coordinator.d.ts.map +1 -0
  71. package/dist/correction/coordinator.js +274 -0
  72. package/dist/correction/coordinator.js.map +1 -0
  73. package/dist/correction/index.d.ts +3 -0
  74. package/dist/correction/index.d.ts.map +1 -0
  75. package/dist/correction/index.js +3 -0
  76. package/dist/correction/index.js.map +1 -0
  77. package/dist/correction/intent.d.ts +111 -0
  78. package/dist/correction/intent.d.ts.map +1 -0
  79. package/dist/correction/intent.js +146 -0
  80. package/dist/correction/intent.js.map +1 -0
  81. package/dist/drivers/archive.d.ts +8 -0
  82. package/dist/drivers/archive.d.ts.map +1 -0
  83. package/dist/drivers/archive.js +101 -0
  84. package/dist/drivers/archive.js.map +1 -0
  85. package/dist/drivers/contain.d.ts +6 -0
  86. package/dist/drivers/contain.d.ts.map +1 -0
  87. package/dist/drivers/contain.js +17 -0
  88. package/dist/drivers/contain.js.map +1 -0
  89. package/dist/drivers/environment.d.ts +4 -0
  90. package/dist/drivers/environment.d.ts.map +1 -0
  91. package/dist/drivers/environment.js +18 -0
  92. package/dist/drivers/environment.js.map +1 -0
  93. package/dist/drivers/errors.d.ts +9 -0
  94. package/dist/drivers/errors.d.ts.map +1 -0
  95. package/dist/drivers/errors.js +6 -0
  96. package/dist/drivers/errors.js.map +1 -0
  97. package/dist/drivers/glob.d.ts +2 -0
  98. package/dist/drivers/glob.d.ts.map +1 -0
  99. package/dist/drivers/glob.js +162 -0
  100. package/dist/drivers/glob.js.map +1 -0
  101. package/dist/drivers/process.d.ts +48 -0
  102. package/dist/drivers/process.d.ts.map +1 -0
  103. package/dist/drivers/process.js +257 -0
  104. package/dist/drivers/process.js.map +1 -0
  105. package/dist/drivers/redact.d.ts +4 -0
  106. package/dist/drivers/redact.d.ts.map +1 -0
  107. package/dist/drivers/redact.js +24 -0
  108. package/dist/drivers/redact.js.map +1 -0
  109. package/dist/drivers/seccomp-helper-source.d.ts +7 -0
  110. package/dist/drivers/seccomp-helper-source.d.ts.map +1 -0
  111. package/dist/drivers/seccomp-helper-source.js +121 -0
  112. package/dist/drivers/seccomp-helper-source.js.map +1 -0
  113. package/dist/drivers/utils.d.ts +4 -0
  114. package/dist/drivers/utils.d.ts.map +1 -0
  115. package/dist/drivers/utils.js +5 -0
  116. package/dist/drivers/utils.js.map +1 -0
  117. package/dist/drivers/workspace.d.ts +6 -0
  118. package/dist/drivers/workspace.d.ts.map +1 -0
  119. package/dist/drivers/workspace.js +49 -0
  120. package/dist/drivers/workspace.js.map +1 -0
  121. package/dist/extensions/provider-adapter.d.ts +48 -0
  122. package/dist/extensions/provider-adapter.d.ts.map +1 -0
  123. package/dist/extensions/provider-adapter.js +64 -0
  124. package/dist/extensions/provider-adapter.js.map +1 -0
  125. package/dist/host.d.ts +33 -0
  126. package/dist/host.d.ts.map +1 -0
  127. package/dist/host.js +20 -0
  128. package/dist/host.js.map +1 -0
  129. package/dist/index.d.ts +19 -1
  130. package/dist/index.d.ts.map +1 -1
  131. package/dist/index.js +12 -1
  132. package/dist/index.js.map +1 -1
  133. package/dist/model/artifact-collection.d.ts +84 -0
  134. package/dist/model/artifact-collection.d.ts.map +1 -0
  135. package/dist/model/artifact-collection.js +185 -0
  136. package/dist/model/artifact-collection.js.map +1 -0
  137. package/dist/model/authority.d.ts +89 -0
  138. package/dist/model/authority.d.ts.map +1 -0
  139. package/dist/model/authority.js +80 -0
  140. package/dist/model/authority.js.map +1 -0
  141. package/dist/model/bun-targets.d.ts +34 -0
  142. package/dist/model/bun-targets.d.ts.map +1 -0
  143. package/dist/model/bun-targets.js +17 -0
  144. package/dist/model/bun-targets.js.map +1 -0
  145. package/dist/model/canonical.d.ts +8 -0
  146. package/dist/model/canonical.d.ts.map +1 -0
  147. package/dist/model/canonical.js +205 -0
  148. package/dist/model/canonical.js.map +1 -0
  149. package/dist/model/catalog.d.ts +76 -0
  150. package/dist/model/catalog.d.ts.map +1 -0
  151. package/dist/model/catalog.js +174 -0
  152. package/dist/model/catalog.js.map +1 -0
  153. package/dist/model/digest.d.ts +53 -0
  154. package/dist/model/digest.d.ts.map +1 -0
  155. package/dist/model/digest.js +127 -0
  156. package/dist/model/digest.js.map +1 -0
  157. package/dist/model/errors.d.ts +14 -0
  158. package/dist/model/errors.d.ts.map +1 -0
  159. package/dist/model/errors.js +8 -0
  160. package/dist/model/errors.js.map +1 -0
  161. package/dist/model/primitives.d.ts +19 -0
  162. package/dist/model/primitives.d.ts.map +1 -0
  163. package/dist/model/primitives.js +18 -0
  164. package/dist/model/primitives.js.map +1 -0
  165. package/dist/model/pypi.d.ts +12 -0
  166. package/dist/model/pypi.d.ts.map +1 -0
  167. package/dist/model/pypi.js +20 -0
  168. package/dist/model/pypi.js.map +1 -0
  169. package/dist/model/python-distribution.d.ts +33 -0
  170. package/dist/model/python-distribution.d.ts.map +1 -0
  171. package/dist/model/python-distribution.js +367 -0
  172. package/dist/model/python-distribution.js.map +1 -0
  173. package/dist/model/secret-patterns.d.ts +2 -0
  174. package/dist/model/secret-patterns.d.ts.map +1 -0
  175. package/dist/model/secret-patterns.js +12 -0
  176. package/dist/model/secret-patterns.js.map +1 -0
  177. package/dist/platform/bun.d.ts +7 -0
  178. package/dist/platform/bun.d.ts.map +1 -0
  179. package/dist/platform/bun.js +15 -0
  180. package/dist/platform/bun.js.map +1 -0
  181. package/dist/platform/credentials.d.ts +32 -0
  182. package/dist/platform/credentials.d.ts.map +1 -0
  183. package/dist/platform/credentials.js +772 -0
  184. package/dist/platform/credentials.js.map +1 -0
  185. package/dist/platform/host-support.d.ts +2 -0
  186. package/dist/platform/host-support.d.ts.map +1 -0
  187. package/dist/platform/host-support.js +4 -0
  188. package/dist/platform/host-support.js.map +1 -0
  189. package/dist/platform/node.d.ts +7 -0
  190. package/dist/platform/node.d.ts.map +1 -0
  191. package/dist/platform/node.js +15 -0
  192. package/dist/platform/node.js.map +1 -0
  193. package/dist/platform/release-runtime.d.ts +11 -0
  194. package/dist/platform/release-runtime.d.ts.map +1 -0
  195. package/dist/platform/release-runtime.js +34 -0
  196. package/dist/platform/release-runtime.js.map +1 -0
  197. package/dist/platform/services.d.ts +15 -0
  198. package/dist/platform/services.d.ts.map +1 -0
  199. package/dist/platform/services.js +30 -0
  200. package/dist/platform/services.js.map +1 -0
  201. package/dist/platform/source-observer.d.ts +5 -0
  202. package/dist/platform/source-observer.d.ts.map +1 -0
  203. package/dist/platform/source-observer.js +159 -0
  204. package/dist/platform/source-observer.js.map +1 -0
  205. package/dist/provider-sdk.d.ts +14 -0
  206. package/dist/provider-sdk.d.ts.map +1 -0
  207. package/dist/provider-sdk.js +10 -0
  208. package/dist/provider-sdk.js.map +1 -0
  209. package/dist/publication/adapter.d.ts +212 -0
  210. package/dist/publication/adapter.d.ts.map +1 -0
  211. package/dist/publication/adapter.js +83 -0
  212. package/dist/publication/adapter.js.map +1 -0
  213. package/dist/publication/authority.d.ts +137 -0
  214. package/dist/publication/authority.d.ts.map +1 -0
  215. package/dist/publication/authority.js +233 -0
  216. package/dist/publication/authority.js.map +1 -0
  217. package/dist/publication/catalog-git.d.ts +37 -0
  218. package/dist/publication/catalog-git.d.ts.map +1 -0
  219. package/dist/publication/catalog-git.js +451 -0
  220. package/dist/publication/catalog-git.js.map +1 -0
  221. package/dist/publication/claim.d.ts +39 -0
  222. package/dist/publication/claim.d.ts.map +1 -0
  223. package/dist/publication/claim.js +31 -0
  224. package/dist/publication/claim.js.map +1 -0
  225. package/dist/publication/coordinator.d.ts +246 -0
  226. package/dist/publication/coordinator.d.ts.map +1 -0
  227. package/dist/publication/coordinator.js +370 -0
  228. package/dist/publication/coordinator.js.map +1 -0
  229. package/dist/publication/github.d.ts +36 -0
  230. package/dist/publication/github.d.ts.map +1 -0
  231. package/dist/publication/github.js +644 -0
  232. package/dist/publication/github.js.map +1 -0
  233. package/dist/publication/http.d.ts +69 -0
  234. package/dist/publication/http.d.ts.map +1 -0
  235. package/dist/publication/http.js +29 -0
  236. package/dist/publication/http.js.map +1 -0
  237. package/dist/publication/index.d.ts +5 -0
  238. package/dist/publication/index.d.ts.map +1 -0
  239. package/dist/publication/index.js +5 -0
  240. package/dist/publication/index.js.map +1 -0
  241. package/dist/publication/npm.d.ts +40 -0
  242. package/dist/publication/npm.d.ts.map +1 -0
  243. package/dist/publication/npm.js +359 -0
  244. package/dist/publication/npm.js.map +1 -0
  245. package/dist/publication/profiles.d.ts +136 -0
  246. package/dist/publication/profiles.d.ts.map +1 -0
  247. package/dist/publication/profiles.js +90 -0
  248. package/dist/publication/profiles.js.map +1 -0
  249. package/dist/publication/publisher.d.ts +82 -0
  250. package/dist/publication/publisher.d.ts.map +1 -0
  251. package/dist/publication/publisher.js +53 -0
  252. package/dist/publication/publisher.js.map +1 -0
  253. package/dist/publication/pypi.d.ts +45 -0
  254. package/dist/publication/pypi.d.ts.map +1 -0
  255. package/dist/publication/pypi.js +369 -0
  256. package/dist/publication/pypi.js.map +1 -0
  257. package/dist/publication/recovery.d.ts +663 -0
  258. package/dist/publication/recovery.d.ts.map +1 -0
  259. package/dist/publication/recovery.js +252 -0
  260. package/dist/publication/recovery.js.map +1 -0
  261. package/dist/publication/report.d.ts +1061 -0
  262. package/dist/publication/report.d.ts.map +1 -0
  263. package/dist/publication/report.js +441 -0
  264. package/dist/publication/report.js.map +1 -0
  265. package/dist/recipes/config.d.ts +296 -0
  266. package/dist/recipes/config.d.ts.map +1 -0
  267. package/dist/recipes/config.js +325 -0
  268. package/dist/recipes/config.js.map +1 -0
  269. package/dist/release/capabilities.d.ts +12 -0
  270. package/dist/release/capabilities.d.ts.map +1 -0
  271. package/dist/release/capabilities.js +395 -0
  272. package/dist/release/capabilities.js.map +1 -0
  273. package/dist/release/compiler.d.ts +5 -0
  274. package/dist/release/compiler.d.ts.map +1 -0
  275. package/dist/release/compiler.js +19 -0
  276. package/dist/release/compiler.js.map +1 -0
  277. package/dist/release/config.d.ts +5 -0
  278. package/dist/release/config.d.ts.map +1 -0
  279. package/dist/release/config.js +10 -0
  280. package/dist/release/config.js.map +1 -0
  281. package/dist/release/context.d.ts +96 -0
  282. package/dist/release/context.d.ts.map +1 -0
  283. package/dist/release/context.js +168 -0
  284. package/dist/release/context.js.map +1 -0
  285. package/dist/release/graph.d.ts +271 -0
  286. package/dist/release/graph.d.ts.map +1 -0
  287. package/dist/release/graph.js +766 -0
  288. package/dist/release/graph.js.map +1 -0
  289. package/dist/release/inspect.d.ts +88 -0
  290. package/dist/release/inspect.d.ts.map +1 -0
  291. package/dist/release/inspect.js +75 -0
  292. package/dist/release/inspect.js.map +1 -0
  293. package/dist/release/prepare.d.ts +24 -0
  294. package/dist/release/prepare.d.ts.map +1 -0
  295. package/dist/release/prepare.js +1116 -0
  296. package/dist/release/prepare.js.map +1 -0
  297. package/dist/release/prepared-ref.d.ts +60 -0
  298. package/dist/release/prepared-ref.d.ts.map +1 -0
  299. package/dist/release/prepared-ref.js +131 -0
  300. package/dist/release/prepared-ref.js.map +1 -0
  301. package/dist/release/prepared-store.d.ts +90 -0
  302. package/dist/release/prepared-store.d.ts.map +1 -0
  303. package/dist/release/prepared-store.js +337 -0
  304. package/dist/release/prepared-store.js.map +1 -0
  305. package/dist/release/prepared.d.ts +172 -0
  306. package/dist/release/prepared.d.ts.map +1 -0
  307. package/dist/release/prepared.js +268 -0
  308. package/dist/release/prepared.js.map +1 -0
  309. package/dist/release/staging.d.ts +31 -0
  310. package/dist/release/staging.d.ts.map +1 -0
  311. package/dist/release/staging.js +218 -0
  312. package/dist/release/staging.js.map +1 -0
  313. package/dist/resolve/authored.d.ts +53 -0
  314. package/dist/resolve/authored.d.ts.map +1 -0
  315. package/dist/resolve/authored.js +55 -0
  316. package/dist/resolve/authored.js.map +1 -0
  317. package/dist/resolve/encode.d.ts +3 -0
  318. package/dist/resolve/encode.d.ts.map +1 -0
  319. package/dist/resolve/encode.js +21 -0
  320. package/dist/resolve/encode.js.map +1 -0
  321. package/dist/resolve/errors.d.ts +7 -0
  322. package/dist/resolve/errors.d.ts.map +1 -0
  323. package/dist/resolve/errors.js +17 -0
  324. package/dist/resolve/errors.js.map +1 -0
  325. package/dist/resolve/facts.d.ts +12 -0
  326. package/dist/resolve/facts.d.ts.map +1 -0
  327. package/dist/resolve/facts.js +18 -0
  328. package/dist/resolve/facts.js.map +1 -0
  329. package/dist/resolve/resolve.d.ts +10 -0
  330. package/dist/resolve/resolve.d.ts.map +1 -0
  331. package/dist/resolve/resolve.js +242 -0
  332. package/dist/resolve/resolve.js.map +1 -0
  333. package/dist/store.d.ts +11 -0
  334. package/dist/store.d.ts.map +1 -0
  335. package/dist/store.js +9 -0
  336. package/dist/store.js.map +1 -0
  337. package/examples/README.md +20 -30
  338. package/examples/github-release/release.config.json +11 -18
  339. package/examples/homebrew-tap/README.md +11 -0
  340. package/examples/homebrew-tap/release.config.json +40 -28
  341. package/examples/multi-target/release.config.json +28 -53
  342. package/examples/npm-first-publish/release.config.json +23 -25
  343. package/examples/npm-only/release.config.json +22 -30
  344. package/examples/portable-cli/README.md +17 -0
  345. package/examples/portable-cli/artifacts/portable-example-0.1.0-darwin-arm64 +1 -0
  346. package/examples/portable-cli/artifacts/portable-example-0.1.0-darwin-x64 +1 -0
  347. package/examples/portable-cli/artifacts/portable-example-0.1.0-linux-arm64 +1 -0
  348. package/examples/portable-cli/artifacts/portable-example-0.1.0-linux-x64 +1 -0
  349. package/examples/portable-cli/artifacts/portable-example-0.1.0-windows-x64.exe +1 -0
  350. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-macosx_10_15_x86_64.whl +1 -0
  351. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-macosx_11_0_arm64.whl +1 -0
  352. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-manylinux2014_aarch64.whl +1 -0
  353. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-manylinux2014_x86_64.whl +1 -0
  354. package/examples/portable-cli/artifacts/portable_example-0.1.0-py3-none-win_amd64.whl +1 -0
  355. package/examples/portable-cli/package.json +9 -0
  356. package/examples/portable-cli/release.config.json +53 -0
  357. package/examples/portable-cli/src/cli.ts +3 -0
  358. package/examples/pypi-registry/README.md +8 -0
  359. package/examples/scoop-bucket/README.md +10 -0
  360. package/examples/scoop-bucket/release.config.json +40 -30
  361. package/package.json +60 -156
  362. package/src/api/api.ts +365 -0
  363. package/src/api/errors.ts +36 -0
  364. package/src/api/input.ts +92 -0
  365. package/src/api/runtime.ts +14 -0
  366. package/src/api/types.ts +103 -0
  367. package/src/capabilities/bun-targets.ts +2 -0
  368. package/src/capabilities/field-ownership.ts +60 -0
  369. package/src/capabilities/module.ts +158 -0
  370. package/src/capabilities/registry.ts +333 -0
  371. package/src/config/config.ts +48 -0
  372. package/src/correction/coordinator.ts +336 -0
  373. package/src/correction/index.ts +2 -0
  374. package/src/correction/intent.ts +172 -0
  375. package/src/drivers/archive.ts +102 -0
  376. package/src/drivers/contain.ts +20 -0
  377. package/src/drivers/environment.ts +28 -0
  378. package/src/drivers/errors.ts +6 -0
  379. package/src/drivers/glob.ts +137 -0
  380. package/src/drivers/process.ts +340 -0
  381. package/src/drivers/redact.ts +31 -0
  382. package/src/drivers/seccomp-helper-source.ts +121 -0
  383. package/src/drivers/utils.ts +10 -0
  384. package/src/drivers/workspace.ts +40 -0
  385. package/src/extensions/provider-adapter.ts +99 -0
  386. package/src/host.ts +140 -0
  387. package/src/index.ts +64 -0
  388. package/src/model/artifact-collection.ts +237 -0
  389. package/src/model/authority.ts +116 -0
  390. package/src/model/bun-targets.ts +34 -0
  391. package/src/model/canonical.ts +205 -0
  392. package/src/model/catalog.ts +220 -0
  393. package/src/model/digest.ts +172 -0
  394. package/src/model/errors.ts +6 -0
  395. package/src/model/primitives.ts +37 -0
  396. package/src/model/pypi.ts +30 -0
  397. package/src/model/python-distribution.ts +360 -0
  398. package/src/model/secret-patterns.ts +11 -0
  399. package/src/platform/bun.ts +38 -0
  400. package/src/platform/credentials.ts +1083 -0
  401. package/src/platform/host-support.ts +4 -0
  402. package/src/platform/node.ts +38 -0
  403. package/src/platform/release-runtime.ts +47 -0
  404. package/src/platform/services.ts +57 -0
  405. package/src/platform/source-observer.ts +193 -0
  406. package/src/provider-sdk.ts +48 -0
  407. package/src/publication/adapter.ts +132 -0
  408. package/src/publication/authority.ts +397 -0
  409. package/src/publication/catalog-git.ts +603 -0
  410. package/src/publication/claim.ts +51 -0
  411. package/src/publication/coordinator.ts +578 -0
  412. package/src/publication/github.ts +954 -0
  413. package/src/publication/http.ts +101 -0
  414. package/src/publication/index.ts +4 -0
  415. package/src/publication/npm.ts +525 -0
  416. package/src/publication/profiles.ts +94 -0
  417. package/src/publication/publisher.ts +130 -0
  418. package/src/publication/pypi.ts +463 -0
  419. package/src/publication/recovery.ts +349 -0
  420. package/src/publication/report.ts +628 -0
  421. package/src/recipes/config.ts +395 -0
  422. package/src/release/capabilities.ts +459 -0
  423. package/src/release/compiler.ts +28 -0
  424. package/src/release/config.ts +12 -0
  425. package/src/release/context.ts +223 -0
  426. package/src/release/graph.ts +866 -0
  427. package/src/release/inspect.ts +83 -0
  428. package/src/release/prepare.ts +1331 -0
  429. package/src/release/prepared-ref.ts +193 -0
  430. package/src/release/prepared-store.ts +377 -0
  431. package/src/release/prepared.ts +299 -0
  432. package/src/release/staging.ts +257 -0
  433. package/src/resolve/authored.ts +64 -0
  434. package/src/resolve/encode.ts +22 -0
  435. package/src/resolve/errors.ts +15 -0
  436. package/src/resolve/facts.ts +18 -0
  437. package/src/resolve/resolve.ts +328 -0
  438. package/src/store.ts +28 -0
  439. package/templates/README.md +55 -72
  440. package/templates/bun-cli-github/README.md +7 -9
  441. package/templates/bun-cli-github/release.config.json +35 -73
  442. package/templates/github-actions/release.yml +57 -0
  443. package/templates/github-actions/reviewed-release.yml +80 -0
  444. package/templates/multi-target-homebrew/README.md +10 -0
  445. package/templates/multi-target-homebrew/release.config.json +43 -60
  446. package/templates/multi-target-scoop/README.md +10 -0
  447. package/templates/multi-target-scoop/release.config.json +43 -62
  448. package/templates/npm-github/release.config.json +25 -38
  449. package/templates/npm-github/reviewed-release.config.json +37 -0
  450. package/templates/npm-only/README.md +10 -0
  451. package/templates/npm-only/release.config.json +15 -30
  452. package/templates/portable-cli/README.md +13 -0
  453. package/templates/portable-cli/release.config.json +53 -0
  454. package/dist/artifacts/adapter.d.ts +0 -39
  455. package/dist/artifacts/adapter.d.ts.map +0 -1
  456. package/dist/artifacts/adapter.js +0 -23
  457. package/dist/artifacts/adapter.js.map +0 -1
  458. package/dist/artifacts/registry.d.ts +0 -21
  459. package/dist/artifacts/registry.d.ts.map +0 -1
  460. package/dist/artifacts/registry.js +0 -21
  461. package/dist/artifacts/registry.js.map +0 -1
  462. package/dist/config/errors.d.ts +0 -24
  463. package/dist/config/errors.d.ts.map +0 -1
  464. package/dist/config/errors.js +0 -19
  465. package/dist/config/errors.js.map +0 -1
  466. package/dist/config/load.d.ts +0 -9
  467. package/dist/config/load.d.ts.map +0 -1
  468. package/dist/config/load.js +0 -29
  469. package/dist/config/load.js.map +0 -1
  470. package/dist/config/schema.d.ts +0 -12
  471. package/dist/config/schema.d.ts.map +0 -1
  472. package/dist/config/schema.js +0 -19
  473. package/dist/config/schema.js.map +0 -1
  474. package/dist/domain/artifact.d.ts +0 -118
  475. package/dist/domain/artifact.d.ts.map +0 -1
  476. package/dist/domain/artifact.js +0 -197
  477. package/dist/domain/artifact.js.map +0 -1
  478. package/dist/domain/evidence.d.ts +0 -59
  479. package/dist/domain/evidence.d.ts.map +0 -1
  480. package/dist/domain/evidence.js +0 -51
  481. package/dist/domain/evidence.js.map +0 -1
  482. package/dist/domain/operation.d.ts +0 -143
  483. package/dist/domain/operation.d.ts.map +0 -1
  484. package/dist/domain/operation.js +0 -198
  485. package/dist/domain/operation.js.map +0 -1
  486. package/dist/domain/release.d.ts +0 -93
  487. package/dist/domain/release.d.ts.map +0 -1
  488. package/dist/domain/release.js +0 -82
  489. package/dist/domain/release.js.map +0 -1
  490. package/dist/domain/remote-state.d.ts +0 -58
  491. package/dist/domain/remote-state.d.ts.map +0 -1
  492. package/dist/domain/remote-state.js +0 -55
  493. package/dist/domain/remote-state.js.map +0 -1
  494. package/dist/domain/target.d.ts +0 -148
  495. package/dist/domain/target.d.ts.map +0 -1
  496. package/dist/domain/target.js +0 -151
  497. package/dist/domain/target.js.map +0 -1
  498. package/dist/host/host.d.ts +0 -32
  499. package/dist/host/host.d.ts.map +0 -1
  500. package/dist/host/host.js +0 -24
  501. package/dist/host/host.js.map +0 -1
  502. package/dist/host/http-live.d.ts +0 -6
  503. package/dist/host/http-live.d.ts.map +0 -1
  504. package/dist/host/http-live.js +0 -86
  505. package/dist/host/http-live.js.map +0 -1
  506. package/dist/host/http.d.ts +0 -43
  507. package/dist/host/http.d.ts.map +0 -1
  508. package/dist/host/http.js +0 -59
  509. package/dist/host/http.js.map +0 -1
  510. package/dist/host/platform.d.ts +0 -10
  511. package/dist/host/platform.d.ts.map +0 -1
  512. package/dist/host/platform.js +0 -114
  513. package/dist/host/platform.js.map +0 -1
  514. package/dist/host/test.d.ts +0 -23
  515. package/dist/host/test.d.ts.map +0 -1
  516. package/dist/host/test.js +0 -222
  517. package/dist/host/test.js.map +0 -1
  518. package/dist/internal/workspace-path.d.ts +0 -15
  519. package/dist/internal/workspace-path.d.ts.map +0 -1
  520. package/dist/internal/workspace-path.js +0 -36
  521. package/dist/internal/workspace-path.js.map +0 -1
  522. package/dist/planner/artifact-inventory.d.ts +0 -9
  523. package/dist/planner/artifact-inventory.d.ts.map +0 -1
  524. package/dist/planner/artifact-inventory.js +0 -86
  525. package/dist/planner/artifact-inventory.js.map +0 -1
  526. package/dist/planner/create-release-plan.d.ts +0 -5
  527. package/dist/planner/create-release-plan.d.ts.map +0 -1
  528. package/dist/planner/create-release-plan.js +0 -25
  529. package/dist/planner/create-release-plan.js.map +0 -1
  530. package/dist/planner/errors.d.ts +0 -67
  531. package/dist/planner/errors.d.ts.map +0 -1
  532. package/dist/planner/errors.js +0 -58
  533. package/dist/planner/errors.js.map +0 -1
  534. package/dist/planner/evidence-recorder.d.ts +0 -28
  535. package/dist/planner/evidence-recorder.d.ts.map +0 -1
  536. package/dist/planner/evidence-recorder.js +0 -362
  537. package/dist/planner/evidence-recorder.js.map +0 -1
  538. package/dist/planner/executor.d.ts +0 -58
  539. package/dist/planner/executor.d.ts.map +0 -1
  540. package/dist/planner/executor.js +0 -147
  541. package/dist/planner/executor.js.map +0 -1
  542. package/dist/planner/normalize-release.d.ts +0 -19
  543. package/dist/planner/normalize-release.d.ts.map +0 -1
  544. package/dist/planner/normalize-release.js +0 -342
  545. package/dist/planner/normalize-release.js.map +0 -1
  546. package/dist/planner/reconcile.d.ts +0 -17
  547. package/dist/planner/reconcile.d.ts.map +0 -1
  548. package/dist/planner/reconcile.js +0 -259
  549. package/dist/planner/reconcile.js.map +0 -1
  550. package/dist/planner/render-plan.d.ts +0 -15
  551. package/dist/planner/render-plan.d.ts.map +0 -1
  552. package/dist/planner/render-plan.js +0 -231
  553. package/dist/planner/render-plan.js.map +0 -1
  554. package/dist/targets/adapter-helpers.d.ts +0 -79
  555. package/dist/targets/adapter-helpers.d.ts.map +0 -1
  556. package/dist/targets/adapter-helpers.js +0 -194
  557. package/dist/targets/adapter-helpers.js.map +0 -1
  558. package/dist/targets/adapter.d.ts +0 -17
  559. package/dist/targets/adapter.d.ts.map +0 -1
  560. package/dist/targets/adapter.js +0 -2
  561. package/dist/targets/adapter.js.map +0 -1
  562. package/dist/targets/github-release.d.ts +0 -25
  563. package/dist/targets/github-release.d.ts.map +0 -1
  564. package/dist/targets/github-release.js +0 -82
  565. package/dist/targets/github-release.js.map +0 -1
  566. package/dist/targets/github.d.ts +0 -11
  567. package/dist/targets/github.d.ts.map +0 -1
  568. package/dist/targets/github.js +0 -117
  569. package/dist/targets/github.js.map +0 -1
  570. package/dist/targets/homebrew.d.ts +0 -11
  571. package/dist/targets/homebrew.d.ts.map +0 -1
  572. package/dist/targets/homebrew.js +0 -210
  573. package/dist/targets/homebrew.js.map +0 -1
  574. package/dist/targets/live.d.ts +0 -5
  575. package/dist/targets/live.d.ts.map +0 -1
  576. package/dist/targets/live.js +0 -50
  577. package/dist/targets/live.js.map +0 -1
  578. package/dist/targets/npm.d.ts +0 -10
  579. package/dist/targets/npm.d.ts.map +0 -1
  580. package/dist/targets/npm.js +0 -112
  581. package/dist/targets/npm.js.map +0 -1
  582. package/dist/targets/pypi.d.ts +0 -11
  583. package/dist/targets/pypi.d.ts.map +0 -1
  584. package/dist/targets/pypi.js +0 -141
  585. package/dist/targets/pypi.js.map +0 -1
  586. package/dist/targets/registry.d.ts +0 -25
  587. package/dist/targets/registry.d.ts.map +0 -1
  588. package/dist/targets/registry.js +0 -34
  589. package/dist/targets/registry.js.map +0 -1
  590. package/dist/targets/scoop.d.ts +0 -11
  591. package/dist/targets/scoop.d.ts.map +0 -1
  592. package/dist/targets/scoop.js +0 -88
  593. package/dist/targets/scoop.js.map +0 -1
  594. package/dist/types/effect-internal.d.ts +0 -5
  595. package/dist/types/effect-internal.d.ts.map +0 -1
  596. package/dist/types/effect-internal.js +0 -2
  597. package/dist/types/effect-internal.js.map +0 -1
  598. package/dist/workflows/config.d.ts +0 -202
  599. package/dist/workflows/config.d.ts.map +0 -1
  600. package/dist/workflows/config.js +0 -420
  601. package/dist/workflows/config.js.map +0 -1
  602. package/dist/workflows/diagnostics.d.ts +0 -62
  603. package/dist/workflows/diagnostics.d.ts.map +0 -1
  604. package/dist/workflows/diagnostics.js +0 -530
  605. package/dist/workflows/diagnostics.js.map +0 -1
  606. package/dist/workflows/distribution.d.ts +0 -25
  607. package/dist/workflows/distribution.d.ts.map +0 -1
  608. package/dist/workflows/distribution.js +0 -24
  609. package/dist/workflows/distribution.js.map +0 -1
  610. package/dist/workflows/evidence.d.ts +0 -17
  611. package/dist/workflows/evidence.d.ts.map +0 -1
  612. package/dist/workflows/evidence.js +0 -32
  613. package/dist/workflows/evidence.js.map +0 -1
  614. package/dist/workflows/index.d.ts +0 -8
  615. package/dist/workflows/index.d.ts.map +0 -1
  616. package/dist/workflows/index.js +0 -7
  617. package/dist/workflows/index.js.map +0 -1
  618. package/dist/workflows/init.d.ts +0 -84
  619. package/dist/workflows/init.d.ts.map +0 -1
  620. package/dist/workflows/init.js +0 -487
  621. package/dist/workflows/init.js.map +0 -1
  622. package/dist/workflows/live.d.ts +0 -9
  623. package/dist/workflows/live.d.ts.map +0 -1
  624. package/dist/workflows/live.js +0 -7
  625. package/dist/workflows/live.js.map +0 -1
  626. package/dist/workflows/options.d.ts +0 -30
  627. package/dist/workflows/options.d.ts.map +0 -1
  628. package/dist/workflows/options.js +0 -16
  629. package/dist/workflows/options.js.map +0 -1
  630. package/examples/non-strict-skips/artifacts/release-example-skips-0.1.0.tgz +0 -1
  631. package/examples/non-strict-skips/release.config.json +0 -31
  632. package/examples/pypi-registry/release.config.json +0 -31
  633. package/templates/github-actions/plan-and-approved-execute.yml +0 -58
  634. package/templates/github-actions/plan-only.yml +0 -33
  635. package/templates/github-actions/trusted-publishing.yml +0 -61
@@ -0,0 +1,137 @@
1
+ // Portable matcher for the documented archive `files` grammar: `*` and `?`
2
+ // inside one segment, `**` as a whole segment spanning segments, `[...]`
3
+ // classes, and `{a,b}` alternation. Patterns reach here already slash
4
+ // normalized, so a backslash is only ever an explicit escape.
5
+ // A malformed pattern (unclosed `[` or `{`) matches nothing, so a typo fails
6
+ // loudly upstream as "patterns matched no workspace files".
7
+ const alternativeLimit = 1024
8
+ const metacharacters = new Set(["\\", "^", "$", ".", "*", "+", "?", "(", ")", "[", "]", "{", "}", "|", "/"])
9
+ const literal = (value: string): string => metacharacters.has(value) ? `\\${value}` : value
10
+ const classLiteral = (value: string): string => ["\\", "]", "^", "["].includes(value) ? `\\${value}` : value
11
+ const classEnd = (pattern: string, open: number): number | undefined => {
12
+ let index = open + 1
13
+ if (pattern[index] === "!" || pattern[index] === "^") index += 1
14
+ if (pattern[index] === "]") index += 1
15
+ while (index < pattern.length) {
16
+ if (pattern[index] === "\\") index += 2
17
+ else if (pattern[index] === "]") return index
18
+ else index += 1
19
+ }
20
+ return undefined
21
+ }
22
+ const characterClass = (body: string): string => {
23
+ const negated = body.startsWith("!") || body.startsWith("^")
24
+ const members = negated ? body.slice(1) : body
25
+ let source = ""
26
+ let index = 0
27
+ while (index < members.length) {
28
+ const value = members[index]!
29
+ if (value === "\\" && index + 1 < members.length) {
30
+ source += `\\${members[index + 1]!}`
31
+ index += 2
32
+ continue
33
+ }
34
+ source += value === "-" ? "-" : classLiteral(value)
35
+ index += 1
36
+ }
37
+ return `[${negated ? "^" : ""}${source}]`
38
+ }
39
+ // `{a,b}` expands to whole alternative patterns because a branch may contain
40
+ // separators (`{src/a,b}/x`); a class is copied verbatim so `,` inside it stays
41
+ // a class member.
42
+ const expand = (
43
+ pattern: string, start: number, depth: number
44
+ ): { readonly alternatives: ReadonlyArray<string>, readonly next: number } | undefined => {
45
+ const completed: Array<string> = []
46
+ let current: ReadonlyArray<string> = [""]
47
+ let index = start
48
+ const append = (text: string) => { current = current.map((value) => value + text) }
49
+ const flush = () => { completed.push(...current); current = [""] }
50
+ while (index < pattern.length) {
51
+ const value = pattern[index]!
52
+ if (value === "\\") {
53
+ if (index + 1 >= pattern.length) return undefined
54
+ append(pattern.slice(index, index + 2))
55
+ index += 2
56
+ } else if (value === "[") {
57
+ const end = classEnd(pattern, index)
58
+ if (end === undefined) return undefined
59
+ append(pattern.slice(index, end + 1))
60
+ index = end + 1
61
+ } else if (value === "{") {
62
+ const group = expand(pattern, index + 1, depth + 1)
63
+ if (group === undefined) return undefined
64
+ current = current.flatMap((prefix) => group.alternatives.map((suffix) => prefix + suffix))
65
+ if (current.length > alternativeLimit) return undefined
66
+ index = group.next
67
+ } else if (depth > 0 && value === "}") {
68
+ flush()
69
+ return { alternatives: completed, next: index + 1 }
70
+ } else if (depth > 0 && value === ",") {
71
+ flush()
72
+ index += 1
73
+ } else {
74
+ append(value)
75
+ index += 1
76
+ }
77
+ }
78
+ if (depth > 0) return undefined
79
+ flush()
80
+ return { alternatives: completed, next: index }
81
+ }
82
+ const globstarAt = (pattern: string, index: number): boolean =>
83
+ pattern.startsWith("**", index) &&
84
+ (index + 2 === pattern.length || pattern[index + 2] === "/")
85
+ const compile = (pattern: string): RegExp | undefined => {
86
+ let source = "^"
87
+ let index = 0
88
+ while (index < pattern.length) {
89
+ const value = pattern[index]!
90
+ if (value === "\\") {
91
+ if (index + 1 >= pattern.length) return undefined
92
+ source += literal(pattern[index + 1]!)
93
+ index += 2
94
+ } else if (value === "[") {
95
+ const end = classEnd(pattern, index)
96
+ if (end === undefined) return undefined
97
+ source += characterClass(pattern.slice(index + 1, end))
98
+ index = end + 1
99
+ } else if (value === "*") {
100
+ let run = 1
101
+ while (pattern[index + run] === "*") run += 1
102
+ const whole = (index === 0 || pattern[index - 1] === "/") &&
103
+ (index + run === pattern.length || pattern[index + run] === "/")
104
+ const rest = index + run + 1
105
+ if (run === 2 && whole && index + run === pattern.length) source += ".*"
106
+ else if (run === 2 && whole) {
107
+ // `**/**` collapses; otherwise `**/` skips whole segments and whatever
108
+ // follows must still match at least one character, so `**/*` never
109
+ // matches a bare directory the way `a/*` does.
110
+ if (!globstarAt(pattern, rest)) {
111
+ source += rest === pattern.length ? "(?:[^/]*/)*" : "(?:[^/]*/)*(?=[\\s\\S])"
112
+ }
113
+ run += 1
114
+ } else source += "[^/]*"
115
+ index += run
116
+ } else if (value === "?") {
117
+ source += "[^/]"
118
+ index += 1
119
+ } else {
120
+ source += literal(value)
121
+ index += 1
122
+ }
123
+ }
124
+ // A reversed class range like [z-a] is legal glob text but an invalid
125
+ // regular expression; it matches nothing, like every other malformed pattern.
126
+ try {
127
+ return new RegExp(`${source}$`)
128
+ } catch {
129
+ return undefined
130
+ }
131
+ }
132
+ export const matchGlob = (pattern: string): (path: string) => boolean => {
133
+ const expanded = expand(pattern, 0, 0)
134
+ const compiled = expanded?.alternatives.map(compile)
135
+ if (compiled === undefined || compiled.some((item) => item === undefined)) return () => false
136
+ return (path) => compiled.some((item) => item!.test(path))
137
+ }
@@ -0,0 +1,340 @@
1
+ import * as Effect from "effect/Effect"
2
+ import * as Stream from "effect/Stream"
3
+ import * as ChildProcess from "effect/unstable/process/ChildProcess"
4
+ import { ChildProcessSpawner } from "effect/unstable/process/ChildProcessSpawner"
5
+ import { createHash } from "node:crypto"
6
+ import {
7
+ accessSync,
8
+ chmodSync,
9
+ constants,
10
+ copyFileSync,
11
+ lstatSync,
12
+ mkdirSync,
13
+ mkdtempSync,
14
+ readFileSync,
15
+ readdirSync,
16
+ realpathSync,
17
+ rmSync,
18
+ statSync,
19
+ writeFileSync
20
+ } from "node:fs"
21
+ import { tmpdir } from "node:os"
22
+ import { delimiter, isAbsolute, join, resolve } from "node:path"
23
+ import { readEnvironment, readOptionalEnv } from "./environment.js"
24
+ import { redactOutput, redactProtocolOutput } from "./redact.js"
25
+ import { networkIsolationHelperSource } from "./seccomp-helper-source.js"
26
+ import { failure } from "./utils.js"
27
+ import { DriverError } from "./errors.js"
28
+
29
+ export interface NetworkIsolationIdentity {
30
+ readonly protocol: "ts-release-seccomp-network-deny/v1"
31
+ readonly helperSha256: string
32
+ readonly librarySha256: string
33
+ readonly bunVersion: string
34
+ readonly bunSha256: string
35
+ readonly kernel: string
36
+ readonly architecture: string
37
+ readonly deniedSyscalls: ReadonlyArray<string>
38
+ }
39
+
40
+ export interface ExecutableIdentity {
41
+ readonly protocol: "ts-release-executable/v1"
42
+ readonly command: string
43
+ readonly sha256: string
44
+ }
45
+
46
+ export interface BunCompileRuntimeIdentity {
47
+ readonly protocol: "ts-release-bun-compile-runtime/v1"
48
+ readonly target: "bun-linux-x64" | "bun-linux-arm64" | "bun-darwin-x64" | "bun-darwin-arm64"
49
+ readonly bunVersion: string
50
+ readonly source: "executing-bun" | "host-cache-private-copy"
51
+ readonly cacheFile: string
52
+ readonly sha256: string
53
+ }
54
+
55
+ const helperDigest = createHash("sha256").update(networkIsolationHelperSource).digest("hex")
56
+
57
+ export type CommandOutcome = {
58
+ readonly exitCode: number, readonly stdout: string, readonly stderr: string,
59
+ /** Present for the production process driver; protocol doubles may omit it. */
60
+ readonly tool?: ExecutableIdentity,
61
+ readonly networkIsolation?: NetworkIsolationIdentity,
62
+ readonly bunCompileRuntime?: BunCompileRuntimeIdentity
63
+ }
64
+ export type RunCommand = (command: {
65
+ readonly argv: ReadonlyArray<string>, readonly cwd: string,
66
+ readonly environmentNames: ReadonlyArray<string>,
67
+ /** Complete redacted stdout for an immediate machine-protocol decoder.
68
+ * The caller must not persist it as diagnostic output. */
69
+ readonly stdout?: "complete-protocol",
70
+ /** Generic commands require the fail-closed Linux/libseccomp filter;
71
+ * certified local-only tools additionally carry their own offline switch. */
72
+ readonly network: "deny" | "offline-cli"
73
+ }) => Effect.Effect<CommandOutcome, DriverError>
74
+
75
+ const collect = (stream: Stream.Stream<Uint8Array, unknown>) =>
76
+ Stream.mkString(Stream.decodeText(stream))
77
+
78
+ const executableIdentity = (command: string, cwd: string, path: string | undefined): ExecutableIdentity => {
79
+ const candidates = command.includes("/")
80
+ ? [isAbsolute(command) ? command : resolve(cwd, command)]
81
+ : (path ?? "").split(delimiter).filter((entry) => entry.length > 0).map((entry) => resolve(entry, command))
82
+ const executable = candidates.find((candidate) => {
83
+ try {
84
+ accessSync(candidate, constants.X_OK)
85
+ return statSync(candidate).isFile()
86
+ } catch {
87
+ return false
88
+ }
89
+ })
90
+ if (executable === undefined) throw new Error(`Executable ${command} is unavailable in the closed PATH.`)
91
+ const canonical = realpathSync(executable)
92
+ return {
93
+ protocol: "ts-release-executable/v1",
94
+ command,
95
+ sha256: createHash("sha256").update(readFileSync(canonical)).digest("hex")
96
+ }
97
+ }
98
+
99
+ const isDigest = (value: unknown): value is string => typeof value === "string" && /^[a-f0-9]{64}$/u.test(value)
100
+ const offlineBunInstallArgv = [
101
+ "bun",
102
+ "install",
103
+ "--offline",
104
+ "--frozen-lockfile",
105
+ "--ignore-scripts",
106
+ "--no-save",
107
+ "--linker=hoisted"
108
+ ] as const
109
+ const isOfflineBunInstall = (command: Parameters<RunCommand>[0]): boolean =>
110
+ command.network === "offline-cli" && command.argv.length === offlineBunInstallArgv.length &&
111
+ command.argv.every((value, index) => value === offlineBunInstallArgv[index])
112
+
113
+ const readBunCacheDirectory = Effect.fn("readBunCacheDirectory")(function*() {
114
+ const configured = yield* readOptionalEnv("BUN_INSTALL_CACHE_DIR")
115
+ const home = configured === undefined ? yield* readOptionalEnv("HOME") : undefined
116
+ const candidate = configured ?? (home === undefined ? undefined : join(home, ".bun", "install", "cache"))
117
+ if (candidate === undefined || candidate.length === 0) {
118
+ return yield* Effect.fail(failure(
119
+ "Certified Bun cache access requires BUN_INSTALL_CACHE_DIR or HOME so the host cache can be located."
120
+ ))
121
+ }
122
+ return yield* Effect.try({
123
+ try: () => {
124
+ if (!isAbsolute(candidate)) throw new Error("the cache path is not absolute")
125
+ const canonical = realpathSync(candidate)
126
+ if (!statSync(canonical).isDirectory()) throw new Error("the cache path is not a directory")
127
+ return canonical
128
+ },
129
+ catch: (cause) => failure(`The offline Bun install cache is unavailable: ${String(cause)}`)
130
+ })
131
+ })
132
+
133
+ const compileRuntimeFiles = {
134
+ "bun-linux-arm64": (version: string) => `bun-linux-aarch64-v${version}`,
135
+ "bun-darwin-x64": (version: string) => `bun-darwin-x64-v${version}`,
136
+ "bun-darwin-arm64": (version: string) => `bun-darwin-aarch64-v${version}`
137
+ } as const
138
+
139
+ type CertifiedBunCompileTarget = BunCompileRuntimeIdentity["target"]
140
+ const certifiedBunCompileTargets = new Set<CertifiedBunCompileTarget>([
141
+ "bun-linux-x64",
142
+ "bun-linux-arm64",
143
+ "bun-darwin-x64",
144
+ "bun-darwin-arm64"
145
+ ])
146
+
147
+ const certifiedBunCompileTarget = (command: Parameters<RunCommand>[0]): CertifiedBunCompileTarget | undefined => {
148
+ const argv = command.argv
149
+ if (command.network !== "deny" || (argv.length !== 8 && argv.length !== 9) ||
150
+ argv[0] !== "bun" || argv[1] !== "build" || argv[2]?.startsWith("-") !== false ||
151
+ argv[3] !== "--compile" || argv[4] !== "--target" || argv[6] !== "--outfile" ||
152
+ argv[7]?.startsWith("-") !== false || (argv.length === 9 && argv[8] !== "--minify")) return undefined
153
+ return certifiedBunCompileTargets.has(argv[5] as CertifiedBunCompileTarget)
154
+ ? argv[5] as CertifiedBunCompileTarget
155
+ : undefined
156
+ }
157
+
158
+ const resolveBunCompileRuntime = Effect.fn("resolveBunCompileRuntime")(function*(
159
+ target: CertifiedBunCompileTarget,
160
+ tool: ExecutableIdentity
161
+ ) {
162
+ const bunVersion = process.versions.bun
163
+ if (bunVersion === undefined || bunVersion.length === 0) {
164
+ return yield* Effect.fail(failure("Certified Bun compilation requires a Bun parent runtime."))
165
+ }
166
+ if (target === "bun-linux-x64") {
167
+ return {
168
+ sourcePath: undefined,
169
+ identity: {
170
+ protocol: "ts-release-bun-compile-runtime/v1",
171
+ target,
172
+ bunVersion,
173
+ source: "executing-bun",
174
+ cacheFile: "executing-bun",
175
+ sha256: tool.sha256
176
+ } satisfies BunCompileRuntimeIdentity
177
+ }
178
+ }
179
+ const cache = yield* readBunCacheDirectory()
180
+ const cacheFile = compileRuntimeFiles[target](bunVersion)
181
+ return yield* Effect.try({
182
+ try: () => {
183
+ const sourcePath = join(cache, cacheFile)
184
+ if (lstatSync(sourcePath).isSymbolicLink() || !lstatSync(sourcePath).isFile() ||
185
+ realpathSync(sourcePath) !== sourcePath) {
186
+ throw new Error("the target runtime is not a canonical regular file")
187
+ }
188
+ return {
189
+ sourcePath,
190
+ identity: {
191
+ protocol: "ts-release-bun-compile-runtime/v1",
192
+ target,
193
+ bunVersion,
194
+ source: "host-cache-private-copy",
195
+ cacheFile,
196
+ sha256: createHash("sha256").update(readFileSync(sourcePath)).digest("hex")
197
+ } satisfies BunCompileRuntimeIdentity
198
+ }
199
+ },
200
+ catch: (cause) => failure(`The certified Bun compile runtime is unavailable: ${String(cause)}`)
201
+ })
202
+ })
203
+
204
+ const parseIsolationIdentity = (path: string): NetworkIsolationIdentity => {
205
+ const value: unknown = JSON.parse(readFileSync(path, "utf8"))
206
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new Error("isolation identity is not an object")
207
+ const item = value as Record<string, unknown>
208
+ if (item.protocol !== "ts-release-seccomp-network-deny/v1" || item.helperSha256 !== helperDigest ||
209
+ !isDigest(item.helperSha256) || !isDigest(item.librarySha256) || !isDigest(item.bunSha256) ||
210
+ typeof item.bunVersion !== "string" || item.bunVersion.length === 0 || typeof item.kernel !== "string" ||
211
+ item.kernel.length === 0 || typeof item.architecture !== "string" || item.architecture.length === 0 ||
212
+ !Array.isArray(item.deniedSyscalls) || item.deniedSyscalls.some((name) => typeof name !== "string")) {
213
+ throw new Error("isolation identity is malformed or disagrees with the embedded helper")
214
+ }
215
+ return item as unknown as NetworkIsolationIdentity
216
+ }
217
+
218
+ // Spawning is the capability that differs across hosts, so it arrives as a
219
+ // service. The runner is built once per live layer and closes over the
220
+ // spawner, keeping DriverCatalog method requirements at never.
221
+ export const makeRunCommand: Effect.Effect<RunCommand, never, ChildProcessSpawner> =
222
+ Effect.gen(function*() {
223
+ const spawner = yield* ChildProcessSpawner
224
+ return (command) => Effect.gen(function*() {
225
+ const baseEnvironment = yield* readEnvironment(command.environmentNames)
226
+ const env = isOfflineBunInstall(command)
227
+ ? {
228
+ ...Object.fromEntries(Object.entries(baseEnvironment).filter(([name]) => name !== "HOME")),
229
+ BUN_INSTALL_CACHE_DIR: yield* readBunCacheDirectory()
230
+ }
231
+ : baseEnvironment
232
+ const executable = command.network === "deny" ? "bun" : command.argv[0]!
233
+ const tool = yield* Effect.try({
234
+ try: () => executableIdentity(executable, command.cwd, env.PATH),
235
+ catch: (cause) => failure(String(cause))
236
+ })
237
+ const compileTarget = certifiedBunCompileTarget(command)
238
+ const compileRuntime = compileTarget === undefined
239
+ ? undefined
240
+ : yield* resolveBunCompileRuntime(compileTarget, tool)
241
+ const compileResources = compileRuntime === undefined
242
+ ? undefined
243
+ : yield* Effect.acquireRelease(
244
+ Effect.sync(() => {
245
+ const directory = mkdtempSync(join(tmpdir(), "ts-release-bun-runtime-"))
246
+ const cache = join(directory, "cache")
247
+ mkdirSync(cache, { mode: 0o700 })
248
+ if (compileRuntime.sourcePath !== undefined) {
249
+ copyFileSync(compileRuntime.sourcePath, join(cache, compileRuntime.identity.cacheFile))
250
+ chmodSync(join(cache, compileRuntime.identity.cacheFile), 0o500)
251
+ }
252
+ chmodSync(cache, 0o500)
253
+ return { directory, cache }
254
+ }),
255
+ ({ cache, directory }) => Effect.sync(() => {
256
+ chmodSync(cache, 0o700)
257
+ rmSync(directory, { recursive: true, force: true })
258
+ })
259
+ )
260
+ const isolationResources = command.network === "deny"
261
+ ? yield* Effect.acquireRelease(
262
+ Effect.sync(() => {
263
+ const directory = mkdtempSync(join(tmpdir(), "ts-release-seccomp-"))
264
+ const helper = join(directory, "network-deny.mjs")
265
+ const identity = join(directory, "identity.json")
266
+ writeFileSync(helper, networkIsolationHelperSource, { mode: 0o500 })
267
+ return { directory, helper, identity }
268
+ }),
269
+ ({ directory }) => Effect.sync(() => rmSync(directory, { recursive: true, force: true }))
270
+ )
271
+ : undefined
272
+ const argv = command.network === "deny"
273
+ ? ["--no-env-file", "--no-install", isolationResources!.helper, ...command.argv]
274
+ : [...command.argv.slice(1)]
275
+ const commandEnvironment = compileResources === undefined
276
+ ? env
277
+ : { ...env, BUN_INSTALL_CACHE_DIR: compileResources.cache }
278
+ const handle = yield* spawner.spawn(ChildProcess.make(
279
+ executable,
280
+ argv,
281
+ {
282
+ cwd: command.cwd,
283
+ env: isolationResources === undefined ? commandEnvironment : {
284
+ ...commandEnvironment,
285
+ TS_RELEASE_NETWORK_IDENTITY_FILE: isolationResources.identity,
286
+ TS_RELEASE_NETWORK_HELPER_SHA256: helperDigest,
287
+ TS_RELEASE_NETWORK_LIBRARY: "libseccomp.so.2"
288
+ },
289
+ stdin: "ignore", stdout: "pipe", stderr: "pipe"
290
+ }
291
+ ))
292
+ const output = yield* Effect.all({
293
+ stdout: collect(handle.stdout),
294
+ stderr: collect(handle.stderr),
295
+ exitCode: handle.exitCode
296
+ }, { concurrency: "unbounded" })
297
+ // Redaction lives here, where the env values are in hand: every
298
+ // consumer of child output (Exec failures, publisher stdout/stderr)
299
+ // is covered at the source and no driver can forget.
300
+ const networkIsolation = isolationResources === undefined
301
+ ? undefined
302
+ : yield* Effect.try({
303
+ try: () => parseIsolationIdentity(isolationResources.identity),
304
+ catch: (cause) => failure(String(cause))
305
+ })
306
+ if (networkIsolation !== undefined && networkIsolation.bunSha256 !== tool.sha256) {
307
+ return yield* Effect.fail(failure("The Bun executable changed between parent resolution and the isolation helper."))
308
+ }
309
+ if (compileResources !== undefined && compileRuntime !== undefined) yield* Effect.try({
310
+ try: () => {
311
+ const entries = readdirSync(compileResources.cache)
312
+ const expected = compileRuntime.sourcePath === undefined ? [] : [compileRuntime.identity.cacheFile]
313
+ if (entries.length !== expected.length || entries.some((entry, index) => entry !== expected[index])) {
314
+ throw new Error("the private runtime cache changed shape")
315
+ }
316
+ if (expected[0] !== undefined) {
317
+ const runtime = join(compileResources.cache, expected[0])
318
+ if (lstatSync(runtime).isSymbolicLink() || !lstatSync(runtime).isFile() ||
319
+ createHash("sha256").update(readFileSync(runtime)).digest("hex") !== compileRuntime.identity.sha256) {
320
+ throw new Error("the private runtime cache changed bytes or type")
321
+ }
322
+ }
323
+ },
324
+ catch: (cause) => failure(`Certified Bun compilation did not preserve its private runtime cache: ${String(cause)}`)
325
+ })
326
+ return {
327
+ stdout: command.stdout === "complete-protocol"
328
+ ? redactProtocolOutput(output.stdout, commandEnvironment)
329
+ : redactOutput(output.stdout, commandEnvironment),
330
+ stderr: redactOutput(output.stderr, commandEnvironment),
331
+ exitCode: Number(output.exitCode),
332
+ tool,
333
+ ...(networkIsolation === undefined ? {} : { networkIsolation }),
334
+ ...(compileRuntime === undefined ? {} : { bunCompileRuntime: compileRuntime.identity })
335
+ }
336
+ }).pipe(
337
+ Effect.scoped,
338
+ Effect.mapError((cause) => cause instanceof DriverError ? cause : failure(String(cause)))
339
+ )
340
+ })
@@ -0,0 +1,31 @@
1
+ import { secretPatterns } from "../model/secret-patterns.js"
2
+
3
+ const EXCERPT_LIMIT = 2000
4
+
5
+ const redact = (text: string, env: Readonly<Record<string, string>>): string => {
6
+ let out = text
7
+ for (const [name, value] of Object.entries(env)
8
+ .filter(([name, value]) => name !== "PATH" && value.length >= 6)
9
+ .sort((left, right) => right[1].length - left[1].length)) {
10
+ out = out.split(value).join(`[redacted:${name}]`)
11
+ }
12
+ for (const pattern of secretPatterns) {
13
+ out = out.replace(new RegExp(pattern.source, `${pattern.flags.replace("u", "")}gu`), "[redacted:token]")
14
+ }
15
+ return out
16
+ }
17
+
18
+ // Redacts KNOWN values (the exact env values the child received, longest
19
+ // first, except PATH) and known token shapes, then bounds the excerpt. Child
20
+ // output enters a durable diagnostic ledger only through this bounded form.
21
+ export const redactOutput = (
22
+ text: string, env: Readonly<Record<string, string>>
23
+ ): string => {
24
+ const out = redact(text, env)
25
+ return out.length > EXCERPT_LIMIT ? `${out.slice(0, EXCERPT_LIMIT)}…[truncated]` : out
26
+ }
27
+
28
+ /** Complete redacted machine-protocol output for immediate decoding only. */
29
+ export const redactProtocolOutput = (
30
+ text: string, env: Readonly<Record<string, string>>
31
+ ): string => redact(text, env)
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Embedded so source, built JS, npm consumers, and standalone CLI bundles all
3
+ * execute the same audited helper bytes through the pinned Bun runtime.
4
+ */
5
+ export const makeNetworkIsolationHelperSource = (requiredLibrary = "libseccomp.so.2"): string => String.raw`import { dlopen, ptr } from "bun:ffi"
6
+ import { createHash } from "node:crypto"
7
+ import { readFileSync, readdirSync, realpathSync, writeFileSync } from "node:fs"
8
+ import { arch, release } from "node:os"
9
+
10
+ const fail = (reason) => {
11
+ process.stderr.write("ts-release network isolation failed closed: " + reason + "\n")
12
+ process.exit(125)
13
+ }
14
+ if (process.platform !== "linux" || !["x64", "arm64"].includes(process.arch)) {
15
+ fail("unsupported host " + process.platform + "/" + process.arch)
16
+ }
17
+ const identityPath = process.env.TS_RELEASE_NETWORK_IDENTITY_FILE
18
+ const expectedHelperDigest = process.env.TS_RELEASE_NETWORK_HELPER_SHA256
19
+ const libraryName = process.env.TS_RELEASE_NETWORK_LIBRARY
20
+ if (!identityPath || !expectedHelperDigest || libraryName !== ${JSON.stringify(requiredLibrary)}) {
21
+ fail("missing or invalid internal isolation parameters")
22
+ }
23
+ const helperDigest = createHash("sha256").update(readFileSync(process.argv[1])).digest("hex")
24
+ if (helperDigest !== expectedHelperDigest) fail("helper digest disagrees with parent")
25
+ const argv = process.argv.slice(2)
26
+ if (argv.length === 0) fail("missing command")
27
+ const deniedSyscalls = [
28
+ "socket", "socketpair", "connect", "bind", "listen", "accept", "accept4",
29
+ "sendto", "sendmsg", "sendmmsg", "recvfrom", "recvmsg", "recvmmsg",
30
+ "io_uring_setup", "io_uring_enter", "io_uring_register", "pidfd_getfd"
31
+ ]
32
+ let library
33
+ try {
34
+ library = dlopen(libraryName, {
35
+ seccomp_init: { args: ["u32"], returns: "ptr" },
36
+ seccomp_rule_add: { args: ["ptr", "u32", "i32", "u32"], returns: "i32" },
37
+ seccomp_load: { args: ["ptr"], returns: "i32" },
38
+ seccomp_release: { args: ["ptr"], returns: "void" },
39
+ seccomp_syscall_resolve_name: { args: ["ptr"], returns: "i32" }
40
+ })
41
+ } catch (cause) {
42
+ fail("libseccomp.so.2 unavailable: " + String(cause))
43
+ }
44
+ let libraryPath
45
+ try {
46
+ const mapping = readFileSync("/proc/self/maps", "utf8").split("\n").find((line) => line.includes("libseccomp.so"))
47
+ const candidate = mapping && mapping.trim().split(/\s+/).at(-1)
48
+ if (!candidate || !candidate.startsWith("/")) fail("loaded libseccomp mapping is unavailable")
49
+ libraryPath = realpathSync(candidate)
50
+ } catch (cause) {
51
+ fail("cannot identify loaded libseccomp: " + String(cause))
52
+ }
53
+ const libraryDigest = createHash("sha256").update(readFileSync(libraryPath)).digest("hex")
54
+ const bunDigest = createHash("sha256").update(readFileSync(realpathSync(process.execPath))).digest("hex")
55
+ const context = library.symbols.seccomp_init(0x7fff0000)
56
+ if (context === null) fail("seccomp_init returned null")
57
+ try {
58
+ for (const name of deniedSyscalls) {
59
+ const bytes = new TextEncoder().encode(name + "\0")
60
+ const syscall = library.symbols.seccomp_syscall_resolve_name(ptr(bytes))
61
+ if (syscall < 0) fail("kernel/libseccomp cannot resolve " + name)
62
+ const result = library.symbols.seccomp_rule_add(context, 0x00050001, syscall, 0)
63
+ if (result !== 0) fail("seccomp_rule_add(" + name + ") returned " + result)
64
+ }
65
+ const loaded = library.symbols.seccomp_load(context)
66
+ if (loaded !== 0) fail("seccomp_load returned " + loaded)
67
+ } finally {
68
+ library.symbols.seccomp_release(context)
69
+ }
70
+ library.close()
71
+ const identity = {
72
+ protocol: "ts-release-seccomp-network-deny/v1",
73
+ helperSha256: helperDigest,
74
+ librarySha256: libraryDigest,
75
+ bunVersion: globalThis["Bun"].version,
76
+ bunSha256: bunDigest,
77
+ kernel: release(),
78
+ architecture: arch(),
79
+ deniedSyscalls
80
+ }
81
+ try {
82
+ writeFileSync(identityPath, JSON.stringify(identity), { encoding: "utf8", flag: "wx", mode: 0o600 })
83
+ } catch (cause) {
84
+ fail("cannot persist isolation identity: " + String(cause))
85
+ }
86
+ const childEnvironment = { ...process.env }
87
+ delete childEnvironment.TS_RELEASE_NETWORK_IDENTITY_FILE
88
+ delete childEnvironment.TS_RELEASE_NETWORK_HELPER_SHA256
89
+ delete childEnvironment.TS_RELEASE_NETWORK_LIBRARY
90
+ // The runtime spawn API preserves caller-provided non-stdio descriptors. Close only the
91
+ // descriptors explicitly inherited without FD_CLOEXEC; Bun's own internal
92
+ // descriptors remain untouched and are closed by exec.
93
+ let libc
94
+ try {
95
+ libc = dlopen("libc.so.6", {
96
+ fcntl: { args: ["i32", "i32"], returns: "i32" },
97
+ close: { args: ["i32"], returns: "i32" }
98
+ })
99
+ for (const item of readdirSync("/proc/self/fd")) {
100
+ const fd = Number(item)
101
+ if (!Number.isSafeInteger(fd) || fd <= 2) continue
102
+ const flags = libc.symbols.fcntl(fd, 1)
103
+ if (flags >= 0 && (flags & 1) === 0) libc.symbols.close(fd)
104
+ }
105
+ libc.close()
106
+ } catch (cause) {
107
+ fail("cannot close inherited non-stdio descriptors: " + String(cause))
108
+ }
109
+ let child
110
+ try {
111
+ child = globalThis["Bun"].spawn(argv, {
112
+ env: childEnvironment,
113
+ stdio: ["ignore", "inherit", "inherit"]
114
+ })
115
+ } catch (cause) {
116
+ fail("isolated child spawn failed: " + String(cause))
117
+ }
118
+ process.exit(await child.exited)
119
+ `
120
+
121
+ export const networkIsolationHelperSource = makeNetworkIsolationHelperSource()
@@ -0,0 +1,10 @@
1
+ import { createHash } from "node:crypto"
2
+ import { DriverError } from "./errors.js"
3
+
4
+ export const failure = (
5
+ reason: string,
6
+ commitment: "before-commit" | "unknown" = "before-commit"
7
+ ) => DriverError.make({ reason, commitment })
8
+
9
+ export const sha256 = (bytes: Uint8Array): string =>
10
+ createHash("sha256").update(bytes).digest("hex")
@@ -0,0 +1,40 @@
1
+ import {
2
+ chmodSync, closeSync, constants, existsSync, fstatSync, fsyncSync, lstatSync,
3
+ mkdirSync, openSync, readFileSync, realpathSync, writeFileSync
4
+ } from "node:fs"
5
+ import { join } from "node:path"
6
+ import { contained } from "./contain.js"
7
+ import { DriverError } from "./errors.js"
8
+
9
+ const fail = (reason: string): DriverError => DriverError.make({ reason, commitment: "before-commit" })
10
+
11
+ export const secureRead = (root: string, path: string): { readonly bytes: Uint8Array, readonly inode: number } => {
12
+ let current = root
13
+ for (const part of path.split(/[\\/]+/u)) {
14
+ current = join(current, part)
15
+ if (lstatSync(current).isSymbolicLink()) throw fail("Structured read encountered a symlink.")
16
+ }
17
+ const descriptor = openSync(current, constants.O_RDONLY | constants.O_NOFOLLOW)
18
+ try {
19
+ const opened = fstatSync(descriptor)
20
+ const resolved = realpathSync(current)
21
+ if (!contained(root, resolved)) throw fail("Opened file escaped the workspace root.")
22
+ const landed = lstatSync(resolved)
23
+ if (landed.ino !== opened.ino || landed.dev !== opened.dev) throw fail("Opened file changed identity.")
24
+ return { bytes: new Uint8Array(readFileSync(descriptor)), inode: opened.ino }
25
+ } finally { closeSync(descriptor) }
26
+ }
27
+
28
+ export const secureWrite = (root: string, path: string, bytes: Uint8Array | string): void => {
29
+ const parts = path.split(/[\\/]+/u).filter((part) => part.length > 0)
30
+ let parent = root
31
+ for (const part of parts.slice(0, -1)) {
32
+ parent = join(parent, part)
33
+ mkdirSync(parent, { recursive: true })
34
+ if (lstatSync(parent).isSymbolicLink()) throw fail("Structured write encountered a symlink.")
35
+ }
36
+ const target = join(parent, parts.at(-1)!)
37
+ if (existsSync(target) && lstatSync(target).isSymbolicLink()) throw fail("Structured write encountered a symlink.")
38
+ const descriptor = openSync(target, constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | constants.O_NOFOLLOW, 0o644)
39
+ try { writeFileSync(descriptor, bytes); fsyncSync(descriptor) } finally { closeSync(descriptor) }
40
+ }