@starci/hfs 4.11.21 → 4.12.0

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 (1088) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +31 -31
  3. package/ci/cli.d.mts +15 -0
  4. package/ci/cli.mjs +71 -52
  5. package/ci/github.d.mts +43 -0
  6. package/ci/github.mjs +33 -28
  7. package/ci/local.d.mts +12 -0
  8. package/ci/local.mjs +145 -108
  9. package/ci/secret.d.mts +15 -0
  10. package/ci/secret.mjs +31 -21
  11. package/ci/vars.d.mts +17 -0
  12. package/ci/vars.mjs +47 -33
  13. package/ci/verify.d.mts +18 -0
  14. package/ci/verify.mjs +52 -40
  15. package/codemod/button-intent.d.mts +63 -0
  16. package/codemod/button-intent.mjs +338 -285
  17. package/coverage/cli.d.mts +28 -0
  18. package/coverage/cli.mjs +65 -51
  19. package/db/backup-receipt.d.mts +28 -0
  20. package/db/backup-receipt.mjs +78 -58
  21. package/db/drift.d.mts +86 -0
  22. package/db/drift.mjs +213 -180
  23. package/db/dump.d.mts +52 -0
  24. package/db/dump.mjs +63 -56
  25. package/db/entity-list.d.mts +4 -0
  26. package/db/entity-list.mjs +0 -2
  27. package/db/image.d.mts +8 -0
  28. package/db/image.mjs +1 -2
  29. package/db/migrate.d.mts +104 -0
  30. package/db/migrate.mjs +207 -167
  31. package/db/new.d.mts +11 -0
  32. package/db/new.mjs +25 -25
  33. package/db/post-cutover.d.mts +5 -0
  34. package/db/post-cutover.mjs +89 -82
  35. package/db/postgres.d.mts +71 -0
  36. package/db/postgres.mjs +62 -61
  37. package/emit/compiler.d.mts +3 -0
  38. package/emit/compiler.mjs +25 -27
  39. package/emit/contracts.d.mts +35 -0
  40. package/emit/contracts.mjs +46 -50
  41. package/emit/events.d.mts +9 -0
  42. package/emit/events.mjs +19 -20
  43. package/emit/form-bounds.d.mts +83 -0
  44. package/emit/form-bounds.mjs +133 -117
  45. package/emit/graphql-input-bounds.d.mts +63 -0
  46. package/emit/graphql-input-bounds.mjs +90 -79
  47. package/emit/input-bounds.d.mts +30 -0
  48. package/emit/input-bounds.mjs +29 -27
  49. package/emit/operation-schemas.d.mts +24 -0
  50. package/emit/operation-schemas.mjs +136 -116
  51. package/emit/operations-worker.d.mts +1 -0
  52. package/emit/operations-worker.mjs +9 -7
  53. package/emit/operations.d.mts +47 -0
  54. package/emit/operations.mjs +124 -133
  55. package/emit/schema-worker.d.mts +1 -0
  56. package/emit/schema-worker.mjs +57 -50
  57. package/emit/static-graph.d.mts +48 -0
  58. package/emit/static-graph.mjs +766 -640
  59. package/emit/type-schema.d.mts +29 -0
  60. package/emit/type-schema.mjs +153 -140
  61. package/lint/bound-sys.cjs +27 -33
  62. package/lint/chunk.d.mts +17 -0
  63. package/lint/chunk.mjs +41 -31
  64. package/lint/run.d.mts +120 -0
  65. package/lint/run.mjs +415 -322
  66. package/package.json +21 -4
  67. package/release/candidate-ci.d.mts +46 -0
  68. package/release/candidate-ci.mjs +76 -70
  69. package/release/gate.d.mts +120 -0
  70. package/release/gate.mjs +358 -330
  71. package/release/index.d.mts +68 -0
  72. package/release/index.mjs +95 -73
  73. package/release/lint-report.d.mts +14 -0
  74. package/release/lint-report.mjs +33 -32
  75. package/release/push.d.mts +32 -0
  76. package/release/push.mjs +92 -79
  77. package/release/records.d.mts +18 -0
  78. package/release/records.mjs +22 -21
  79. package/release/sonar-quality-gate.d.mts +18 -0
  80. package/release/sonar-quality-gate.mjs +60 -52
  81. package/release/urgent.d.mts +20 -0
  82. package/release/urgent.mjs +76 -74
  83. package/report/order.d.mts +1 -0
  84. package/report/sonar.d.mts +73 -0
  85. package/report/sonar.mjs +82 -89
  86. package/runtime/engine/admission.d.mts +209 -0
  87. package/runtime/engine/admission.mjs +225 -204
  88. package/runtime/engine/by-code-unit.d.mts +5 -0
  89. package/runtime/engine/by-code-unit.mjs +6 -6
  90. package/runtime/engine/config.d.mts +333 -0
  91. package/runtime/engine/config.mjs +486 -328
  92. package/runtime/engine/db/blob.d.mts +83 -0
  93. package/runtime/engine/db/blob.mjs +344 -268
  94. package/runtime/engine/db/event-compact.d.mts +21 -0
  95. package/runtime/engine/db/event-compact.mjs +34 -38
  96. package/runtime/engine/db/machine-connection.d.mts +68 -0
  97. package/runtime/engine/db/machine-connection.mjs +166 -119
  98. package/runtime/engine/db/machine-open.d.mts +26 -0
  99. package/runtime/engine/db/machine-open.mjs +59 -45
  100. package/runtime/engine/db/machine-schema.d.mts +34 -0
  101. package/runtime/engine/db/machine-schema.mjs +102 -83
  102. package/runtime/engine/db/machine.d.mts +1746 -0
  103. package/runtime/engine/db/machine.mjs +1040 -734
  104. package/runtime/engine/db/provider-reservations.d.mts +169 -0
  105. package/runtime/engine/db/provider-reservations.mjs +141 -119
  106. package/runtime/engine/db/provision-lock.d.mts +23 -0
  107. package/runtime/engine/db/provision-lock.mjs +14 -14
  108. package/runtime/engine/db/ref-value.d.mts +19 -0
  109. package/runtime/engine/db/ref-value.mjs +36 -35
  110. package/runtime/engine/db/sqlite-types.d.mts +28 -0
  111. package/runtime/engine/db/sqlite-types.mjs +4 -0
  112. package/runtime/engine/digest.d.mts +4 -0
  113. package/runtime/engine/digest.mjs +16 -7
  114. package/runtime/engine/invalid-config.d.mts +13 -0
  115. package/runtime/engine/invalid-config.mjs +17 -11
  116. package/runtime/engine/model-config.d.mts +91 -0
  117. package/runtime/engine/model-config.mjs +98 -76
  118. package/runtime/engine/orca-config.d.mts +26 -0
  119. package/runtime/engine/orca-config.mjs +22 -17
  120. package/runtime/engine/plain-object.d.mts +2 -0
  121. package/runtime/engine/refuse.d.mts +9 -0
  122. package/runtime/engine/refuse.mjs +3 -6
  123. package/runtime/engine/release-config.d.mts +19 -0
  124. package/runtime/engine/release-config.mjs +22 -18
  125. package/runtime/engine/removed-vocabulary.d.mts +12 -0
  126. package/runtime/engine/removed-vocabulary.mjs +21 -20
  127. package/runtime/engine/resources-config.d.mts +34 -0
  128. package/runtime/engine/resources-config.mjs +42 -35
  129. package/runtime/engine/runtime-root.d.mts +28 -0
  130. package/runtime/engine/runtime-root.mjs +11 -13
  131. package/runtime/engine/secrets.d.mts +41 -0
  132. package/runtime/engine/secrets.mjs +170 -102
  133. package/runtime/engine/sonar-config.d.mts +10 -0
  134. package/runtime/engine/sonar-config.mjs +16 -13
  135. package/runtime/engine/temp-root.d.mts +17 -0
  136. package/runtime/engine/temp-root.mjs +3 -9
  137. package/runtime/engine/yaml.d.mts +9 -0
  138. package/runtime/knowledge/hfs/canon-pins.yaml +10 -10
  139. package/runtime/knowledge/hfs/ci-standard.yaml +2 -2
  140. package/runtime/knowledge/hfs/rules.yaml +72 -6
  141. package/runtime/knowledge/hfs/slots.yaml +3 -3
  142. package/runtime/knowledge/sonar-gate.yaml +1 -1
  143. package/runtime/modules/kernel/failure-codes.yaml +43 -32
  144. package/runtime/modules/schemas/application-stacks.schema.yaml +3 -3
  145. package/runtime/packages/cli/src/catalog.generated.d.mts +13 -0
  146. package/runtime/packages/cli/src/catalog.generated.mjs +1853 -14824
  147. package/runtime/packages/cli/src/validate-args.d.mts +74 -0
  148. package/runtime/packages/cli/src/validate-args.mjs +183 -171
  149. package/runtime/packages/jest-preset/sonar-exclusions.cjs +5 -5
  150. package/runtime/scripts/api/fs/claim-file.d.mts +12 -0
  151. package/runtime/scripts/api/fs/claim-file.mjs +31 -17
  152. package/runtime/scripts/api/fs/ensure-temp-root.d.mts +4 -0
  153. package/runtime/scripts/api/fs/ensure-temp-root.mjs +15 -14
  154. package/runtime/scripts/api/fs/forbidden-root.d.mts +15 -0
  155. package/runtime/scripts/api/fs/forbidden-root.mjs +31 -23
  156. package/runtime/scripts/api/fs/is-link-like.d.mts +10 -0
  157. package/runtime/scripts/api/fs/is-link-like.mjs +25 -11
  158. package/runtime/scripts/api/fs/lib.d.mts +12 -0
  159. package/runtime/scripts/api/fs/lib.mjs +28 -8
  160. package/runtime/scripts/api/fs/make-temp-dir.d.mts +5 -0
  161. package/runtime/scripts/api/fs/make-temp-dir.mjs +3 -4
  162. package/runtime/scripts/api/fs/rename-over.d.mts +13 -0
  163. package/runtime/scripts/api/fs/rename-over.mjs +16 -10
  164. package/runtime/scripts/api/fs/safe-remove.d.mts +25 -0
  165. package/runtime/scripts/api/fs/safe-remove.mjs +129 -71
  166. package/runtime/scripts/api/git/add.d.mts +3 -0
  167. package/runtime/scripts/api/git/add.mjs +0 -1
  168. package/runtime/scripts/api/git/cat-file.d.mts +3 -0
  169. package/runtime/scripts/api/git/cat-file.mjs +0 -1
  170. package/runtime/scripts/api/git/check-ignore.d.mts +3 -0
  171. package/runtime/scripts/api/git/check-ignore.mjs +0 -1
  172. package/runtime/scripts/api/git/commit-tree.d.mts +3 -0
  173. package/runtime/scripts/api/git/commit-tree.mjs +0 -1
  174. package/runtime/scripts/api/git/config-get.d.mts +10 -0
  175. package/runtime/scripts/api/git/config-get.mjs +1 -2
  176. package/runtime/scripts/api/git/diff.d.mts +3 -0
  177. package/runtime/scripts/api/git/diff.mjs +0 -1
  178. package/runtime/scripts/api/git/init.d.mts +7 -0
  179. package/runtime/scripts/api/git/init.mjs +1 -2
  180. package/runtime/scripts/api/git/is-ancestor.d.mts +5 -0
  181. package/runtime/scripts/api/git/is-ancestor.mjs +0 -1
  182. package/runtime/scripts/api/git/lib.d.mts +67 -0
  183. package/runtime/scripts/api/git/lib.mjs +32 -32
  184. package/runtime/scripts/api/git/ls-files.d.mts +3 -0
  185. package/runtime/scripts/api/git/ls-files.mjs +0 -1
  186. package/runtime/scripts/api/git/ls-tree.d.mts +3 -0
  187. package/runtime/scripts/api/git/ls-tree.mjs +0 -1
  188. package/runtime/scripts/api/git/merge-base.d.mts +5 -0
  189. package/runtime/scripts/api/git/merge-base.mjs +2 -3
  190. package/runtime/scripts/api/git/remote.d.mts +3 -0
  191. package/runtime/scripts/api/git/remote.mjs +0 -1
  192. package/runtime/scripts/api/git/rev-parse-query.d.mts +3 -0
  193. package/runtime/scripts/api/git/rev-parse-query.mjs +0 -1
  194. package/runtime/scripts/api/git/show.d.mts +3 -0
  195. package/runtime/scripts/api/git/show.mjs +0 -1
  196. package/runtime/scripts/api/git/tag.d.mts +3 -0
  197. package/runtime/scripts/api/git/tag.mjs +0 -1
  198. package/runtime/scripts/api/git/update-ref.d.mts +7 -0
  199. package/runtime/scripts/api/git/update-ref.mjs +1 -2
  200. package/runtime/scripts/api/git/write-tree.d.mts +3 -0
  201. package/runtime/scripts/api/git/write-tree.mjs +0 -1
  202. package/runtime/scripts/api/node/lib.d.mts +7 -0
  203. package/runtime/scripts/api/node/lib.mjs +17 -7
  204. package/runtime/scripts/api/node/run-node.d.mts +3 -0
  205. package/runtime/scripts/api/node/run-node.mjs +0 -3
  206. package/runtime/scripts/api/process/resolve-real-tool.d.mts +12 -0
  207. package/runtime/scripts/api/process/resolve-real-tool.mjs +46 -38
  208. package/runtime/scripts/api/process/run-program.d.mts +3 -0
  209. package/runtime/scripts/api/process/run-program.mjs +5 -2
  210. package/runtime/scripts/api/sops/decrypt.d.mts +9 -0
  211. package/runtime/scripts/api/sops/decrypt.mjs +1 -2
  212. package/runtime/scripts/api/sops/lib.d.mts +149 -0
  213. package/runtime/scripts/api/sops/lib.mjs +417 -318
  214. package/runtime/scripts/api/sops/resolve-sops.d.mts +3 -0
  215. package/runtime/scripts/api/sops/resolve-sops.mjs +1 -2
  216. package/runtime/scripts/api/sops/seal.d.mts +19 -0
  217. package/runtime/scripts/api/sops/seal.mjs +14 -10
  218. package/runtime/scripts/api/sops/selected-age-recipient.d.mts +3 -0
  219. package/runtime/scripts/api/sops/selected-age-recipient.mjs +1 -2
  220. package/runtime/scripts/api/sops/update-keys.d.mts +16 -0
  221. package/runtime/scripts/api/sops/update-keys.mjs +11 -8
  222. package/runtime/scripts/cli/gen-catalog.d.mts +42 -0
  223. package/runtime/scripts/cli/gen-catalog.mjs +72 -0
  224. package/runtime/scripts/gates/runtime-host.d.mts +23 -0
  225. package/runtime/scripts/gates/runtime-host.mjs +48 -41
  226. package/runtime/scripts/gates/sonar-gate.d.mts +219 -0
  227. package/runtime/scripts/gates/sonar-gate.mjs +166 -153
  228. package/runtime/scripts/gates/starcistacks-ci.d.mts +35 -0
  229. package/runtime/scripts/gates/starcistacks-ci.mjs +47 -39
  230. package/runtime/scripts/gates/starcistacks-form.d.mts +80 -0
  231. package/runtime/scripts/gates/starcistacks-form.mjs +16 -14
  232. package/runtime/scripts/gates/starcistacks-runtime.d.mts +1 -0
  233. package/runtime/scripts/gates/starcistacks-value-file.d.mts +2 -0
  234. package/runtime/scripts/gates/starcistacks-value-file.mjs +14 -11
  235. package/runtime/scripts/gates/starcistacks.d.mts +141 -0
  236. package/runtime/scripts/gates/starcistacks.mjs +470 -355
  237. package/runtime/scripts/guards/git-pathspec.d.mts +48 -0
  238. package/runtime/scripts/guards/git-pathspec.mjs +215 -130
  239. package/runtime/scripts/guards/git-policy.d.mts +30 -0
  240. package/runtime/scripts/guards/git-policy.mjs +278 -235
  241. package/runtime/scripts/guards/hook-io.d.mts +22 -0
  242. package/runtime/scripts/guards/hook-io.mjs +77 -63
  243. package/runtime/scripts/guards/push-scan.d.mts +31 -0
  244. package/runtime/scripts/guards/push-scan.mjs +93 -80
  245. package/runtime/scripts/guards/release-push-gate.d.mts +22 -0
  246. package/runtime/scripts/guards/release-push-gate.mjs +40 -38
  247. package/runtime/scripts/hfs/allows.d.mts +24 -0
  248. package/runtime/scripts/hfs/allows.mjs +37 -38
  249. package/runtime/scripts/hfs/app-wiring.d.mts +72 -0
  250. package/runtime/scripts/hfs/app-wiring.mjs +197 -167
  251. package/runtime/scripts/hfs/architecture/ast-walks.d.mts +89 -0
  252. package/runtime/scripts/hfs/architecture/ast-walks.mjs +180 -163
  253. package/runtime/scripts/hfs/architecture/automatic-gates.d.mts +21 -0
  254. package/runtime/scripts/hfs/architecture/automatic-gates.mjs +80 -73
  255. package/runtime/scripts/hfs/architecture/backend-app-files.d.mts +10 -0
  256. package/runtime/scripts/hfs/architecture/backend-app-files.mjs +88 -77
  257. package/runtime/scripts/hfs/architecture/backend.d.mts +5 -0
  258. package/runtime/scripts/hfs/architecture/backend.mjs +378 -357
  259. package/runtime/scripts/hfs/architecture/background-unowned.d.mts +25 -0
  260. package/runtime/scripts/hfs/architecture/background-unowned.mjs +201 -187
  261. package/runtime/scripts/hfs/architecture/canon-clones.d.mts +8 -0
  262. package/runtime/scripts/hfs/architecture/canon-clones.mjs +260 -209
  263. package/runtime/scripts/hfs/architecture/canon-jsx-clones.d.mts +5 -0
  264. package/runtime/scripts/hfs/architecture/canon-jsx-clones.mjs +149 -116
  265. package/runtime/scripts/hfs/architecture/client-reaches-server.d.mts +28 -0
  266. package/runtime/scripts/hfs/architecture/client-reaches-server.mjs +72 -68
  267. package/runtime/scripts/hfs/architecture/clones.d.mts +54 -0
  268. package/runtime/scripts/hfs/architecture/clones.mjs +212 -217
  269. package/runtime/scripts/hfs/architecture/config-unread.d.mts +14 -0
  270. package/runtime/scripts/hfs/architecture/config-unread.mjs +7 -9
  271. package/runtime/scripts/hfs/architecture/config.d.mts +74 -0
  272. package/runtime/scripts/hfs/architecture/config.mjs +302 -268
  273. package/runtime/scripts/hfs/architecture/connection-map.d.mts +33 -0
  274. package/runtime/scripts/hfs/architecture/connection-map.mjs +258 -225
  275. package/runtime/scripts/hfs/architecture/constructor-deps.d.mts +57 -0
  276. package/runtime/scripts/hfs/architecture/constructor-deps.mjs +80 -71
  277. package/runtime/scripts/hfs/architecture/context-coupling.d.mts +21 -0
  278. package/runtime/scripts/hfs/architecture/context-coupling.mjs +82 -77
  279. package/runtime/scripts/hfs/architecture/context-map.d.mts +102 -0
  280. package/runtime/scripts/hfs/architecture/context-map.mjs +267 -234
  281. package/runtime/scripts/hfs/architecture/context-owner.d.mts +15 -0
  282. package/runtime/scripts/hfs/architecture/context-owner.mjs +73 -61
  283. package/runtime/scripts/hfs/architecture/context-platform-tables.d.mts +18 -0
  284. package/runtime/scripts/hfs/architecture/context-platform-tables.mjs +47 -43
  285. package/runtime/scripts/hfs/architecture/context-transaction.d.mts +20 -0
  286. package/runtime/scripts/hfs/architecture/context-transaction.mjs +54 -52
  287. package/runtime/scripts/hfs/architecture/contract-fixture-guard.d.mts +37 -0
  288. package/runtime/scripts/hfs/architecture/contract-fixture-guard.mjs +113 -104
  289. package/runtime/scripts/hfs/architecture/contracts-readonly.d.mts +32 -0
  290. package/runtime/scripts/hfs/architecture/contracts-readonly.mjs +288 -270
  291. package/runtime/scripts/hfs/architecture/contracts.d.mts +30 -0
  292. package/runtime/scripts/hfs/architecture/contracts.mjs +408 -393
  293. package/runtime/scripts/hfs/architecture/cross-app-duplicate.d.mts +27 -0
  294. package/runtime/scripts/hfs/architecture/cross-app-duplicate.mjs +50 -51
  295. package/runtime/scripts/hfs/architecture/dead-exports-bindings.d.mts +21 -0
  296. package/runtime/scripts/hfs/architecture/dead-exports-bindings.mjs +143 -119
  297. package/runtime/scripts/hfs/architecture/dead-exports.d.mts +32 -0
  298. package/runtime/scripts/hfs/architecture/dead-exports.mjs +286 -228
  299. package/runtime/scripts/hfs/architecture/default-deny.d.mts +21 -0
  300. package/runtime/scripts/hfs/architecture/default-deny.mjs +129 -110
  301. package/runtime/scripts/hfs/architecture/doc-language.d.mts +17 -0
  302. package/runtime/scripts/hfs/architecture/doc-language.mjs +24 -19
  303. package/runtime/scripts/hfs/architecture/entity-registry.d.mts +49 -0
  304. package/runtime/scripts/hfs/architecture/entity-registry.mjs +20 -22
  305. package/runtime/scripts/hfs/architecture/entrypoint.d.mts +13 -0
  306. package/runtime/scripts/hfs/architecture/entrypoint.mjs +47 -45
  307. package/runtime/scripts/hfs/architecture/error-codes.d.mts +16 -0
  308. package/runtime/scripts/hfs/architecture/error-codes.mjs +37 -35
  309. package/runtime/scripts/hfs/architecture/error-masked.d.mts +16 -0
  310. package/runtime/scripts/hfs/architecture/error-masked.mjs +55 -59
  311. package/runtime/scripts/hfs/architecture/fe-slot-allows.d.mts +38 -0
  312. package/runtime/scripts/hfs/architecture/fe-slot-allows.mjs +24 -23
  313. package/runtime/scripts/hfs/architecture/feature-shape.d.mts +26 -0
  314. package/runtime/scripts/hfs/architecture/feature-shape.mjs +40 -38
  315. package/runtime/scripts/hfs/architecture/framework-pinned.d.mts +3 -0
  316. package/runtime/scripts/hfs/architecture/framework-pinned.mjs +21 -21
  317. package/runtime/scripts/hfs/architecture/frontend-block-render.d.mts +26 -0
  318. package/runtime/scripts/hfs/architecture/frontend-block-render.mjs +106 -98
  319. package/runtime/scripts/hfs/architecture/frontend-grammar.d.mts +7 -0
  320. package/runtime/scripts/hfs/architecture/frontend-grammar.mjs +153 -150
  321. package/runtime/scripts/hfs/architecture/frontend-routing.d.mts +23 -0
  322. package/runtime/scripts/hfs/architecture/frontend-routing.mjs +161 -149
  323. package/runtime/scripts/hfs/architecture/frontend-world-render.d.mts +72 -0
  324. package/runtime/scripts/hfs/architecture/frontend-world-render.mjs +343 -305
  325. package/runtime/scripts/hfs/architecture/frontend-world.d.mts +94 -0
  326. package/runtime/scripts/hfs/architecture/frontend-world.mjs +340 -294
  327. package/runtime/scripts/hfs/architecture/frontend.d.mts +31 -0
  328. package/runtime/scripts/hfs/architecture/frontend.mjs +174 -184
  329. package/runtime/scripts/hfs/architecture/function-spec-providers.d.mts +27 -0
  330. package/runtime/scripts/hfs/architecture/function-spec-providers.mjs +124 -106
  331. package/runtime/scripts/hfs/architecture/hfs-graph.d.mts +78 -0
  332. package/runtime/scripts/hfs/architecture/hfs-graph.mjs +52 -48
  333. package/runtime/scripts/hfs/architecture/hfs.d.mts +135 -0
  334. package/runtime/scripts/hfs/architecture/hfs.mjs +328 -282
  335. package/runtime/scripts/hfs/architecture/hooks-are-hooks.d.mts +24 -0
  336. package/runtime/scripts/hfs/architecture/hooks-are-hooks.mjs +81 -71
  337. package/runtime/scripts/hfs/architecture/i18n-keys.d.mts +31 -0
  338. package/runtime/scripts/hfs/architecture/i18n-keys.mjs +155 -141
  339. package/runtime/scripts/hfs/architecture/identity.d.mts +7 -0
  340. package/runtime/scripts/hfs/architecture/identity.mjs +141 -125
  341. package/runtime/scripts/hfs/architecture/index.d.mts +101 -0
  342. package/runtime/scripts/hfs/architecture/index.mjs +272 -272
  343. package/runtime/scripts/hfs/architecture/injection-token-exported.d.mts +21 -0
  344. package/runtime/scripts/hfs/architecture/injection-token-exported.mjs +45 -43
  345. package/runtime/scripts/hfs/architecture/jwt-ast.d.mts +16 -0
  346. package/runtime/scripts/hfs/architecture/jwt-ast.mjs +195 -176
  347. package/runtime/scripts/hfs/architecture/machine-ast.d.mts +88 -0
  348. package/runtime/scripts/hfs/architecture/machine-ast.mjs +163 -155
  349. package/runtime/scripts/hfs/architecture/managed-scripts.d.mts +2 -0
  350. package/runtime/scripts/hfs/architecture/managed-scripts.mjs +19 -20
  351. package/runtime/scripts/hfs/architecture/module-per-transport.d.mts +35 -0
  352. package/runtime/scripts/hfs/architecture/module-per-transport.mjs +177 -172
  353. package/runtime/scripts/hfs/architecture/next-data-contract.d.mts +35 -0
  354. package/runtime/scripts/hfs/architecture/next-data-contract.mjs +100 -78
  355. package/runtime/scripts/hfs/architecture/next-data-inference.d.mts +39 -0
  356. package/runtime/scripts/hfs/architecture/next-data-inference.mjs +170 -154
  357. package/runtime/scripts/hfs/architecture/next-data-key.d.mts +50 -0
  358. package/runtime/scripts/hfs/architecture/next-data-key.mjs +311 -275
  359. package/runtime/scripts/hfs/architecture/next-data-symbols.d.mts +5 -0
  360. package/runtime/scripts/hfs/architecture/next-data-symbols.mjs +17 -17
  361. package/runtime/scripts/hfs/architecture/next-data.d.mts +36 -0
  362. package/runtime/scripts/hfs/architecture/next-data.mjs +351 -334
  363. package/runtime/scripts/hfs/architecture/operation-contract-roots.d.mts +10 -0
  364. package/runtime/scripts/hfs/architecture/operation-contract-roots.mjs +39 -37
  365. package/runtime/scripts/hfs/architecture/owners.d.mts +5 -0
  366. package/runtime/scripts/hfs/architecture/owners.mjs +97 -98
  367. package/runtime/scripts/hfs/architecture/package-shape.d.mts +26 -0
  368. package/runtime/scripts/hfs/architecture/package-shape.mjs +56 -55
  369. package/runtime/scripts/hfs/architecture/presentation.d.mts +24 -0
  370. package/runtime/scripts/hfs/architecture/presentation.mjs +138 -130
  371. package/runtime/scripts/hfs/architecture/reachability.d.mts +25 -0
  372. package/runtime/scripts/hfs/architecture/reachability.mjs +258 -241
  373. package/runtime/scripts/hfs/architecture/register-once.d.mts +18 -0
  374. package/runtime/scripts/hfs/architecture/register-once.mjs +152 -139
  375. package/runtime/scripts/hfs/architecture/registration.d.mts +15 -0
  376. package/runtime/scripts/hfs/architecture/registration.mjs +301 -267
  377. package/runtime/scripts/hfs/architecture/required-files.d.mts +64 -0
  378. package/runtime/scripts/hfs/architecture/required-files.mjs +172 -167
  379. package/runtime/scripts/hfs/architecture/route-files-thin.d.mts +23 -0
  380. package/runtime/scripts/hfs/architecture/route-files-thin.mjs +85 -77
  381. package/runtime/scripts/hfs/architecture/schema-owner.d.mts +34 -0
  382. package/runtime/scripts/hfs/architecture/schema-owner.mjs +206 -181
  383. package/runtime/scripts/hfs/architecture/server-action.d.mts +22 -0
  384. package/runtime/scripts/hfs/architecture/server-action.mjs +48 -48
  385. package/runtime/scripts/hfs/architecture/side-boundary.d.mts +3 -0
  386. package/runtime/scripts/hfs/architecture/side-boundary.mjs +2 -5
  387. package/runtime/scripts/hfs/architecture/source-names-shape.d.mts +85 -0
  388. package/runtime/scripts/hfs/architecture/source-names-shape.mjs +261 -259
  389. package/runtime/scripts/hfs/architecture/source-names.d.mts +7 -0
  390. package/runtime/scripts/hfs/architecture/source-names.mjs +304 -278
  391. package/runtime/scripts/hfs/architecture/sql-keys.d.mts +5 -0
  392. package/runtime/scripts/hfs/architecture/sql-keys.mjs +277 -194
  393. package/runtime/scripts/hfs/architecture/sql-owner.d.mts +30 -0
  394. package/runtime/scripts/hfs/architecture/sql-owner.mjs +236 -194
  395. package/runtime/scripts/hfs/architecture/sql-returning.d.mts +22 -0
  396. package/runtime/scripts/hfs/architecture/sql-returning.mjs +46 -45
  397. package/runtime/scripts/hfs/architecture/sql-token-forms.d.mts +21 -0
  398. package/runtime/scripts/hfs/architecture/sql-token-forms.mjs +86 -74
  399. package/runtime/scripts/hfs/architecture/sql-tokens.d.mts +32 -0
  400. package/runtime/scripts/hfs/architecture/sql-tokens.mjs +456 -341
  401. package/runtime/scripts/hfs/architecture/staged-consumers.d.mts +7 -0
  402. package/runtime/scripts/hfs/architecture/staged-consumers.mjs +35 -30
  403. package/runtime/scripts/hfs/architecture/surface.d.mts +26 -0
  404. package/runtime/scripts/hfs/architecture/surface.mjs +64 -74
  405. package/runtime/scripts/hfs/architecture/symbols.d.mts +11 -0
  406. package/runtime/scripts/hfs/architecture/symbols.mjs +209 -216
  407. package/runtime/scripts/hfs/architecture/test-world-files.d.mts +45 -0
  408. package/runtime/scripts/hfs/architecture/test-world-files.mjs +165 -155
  409. package/runtime/scripts/hfs/architecture/tiers.d.mts +29 -0
  410. package/runtime/scripts/hfs/architecture/tiers.mjs +161 -154
  411. package/runtime/scripts/hfs/architecture/transport-owner.d.mts +37 -0
  412. package/runtime/scripts/hfs/architecture/transport-owner.mjs +155 -149
  413. package/runtime/scripts/hfs/architecture/type-context.d.mts +60 -0
  414. package/runtime/scripts/hfs/architecture/type-context.mjs +255 -250
  415. package/runtime/scripts/hfs/architecture/typescript.d.mts +94 -0
  416. package/runtime/scripts/hfs/architecture/typescript.mjs +358 -318
  417. package/runtime/scripts/hfs/architecture/unit-spec-providers.d.mts +34 -0
  418. package/runtime/scripts/hfs/architecture/unit-spec-providers.mjs +110 -92
  419. package/runtime/scripts/hfs/architecture.d.mts +13 -0
  420. package/runtime/scripts/hfs/architecture.mjs +39 -29
  421. package/runtime/scripts/hfs/canon-pins.d.mts +26 -0
  422. package/runtime/scripts/hfs/canon-pins.mjs +5 -8
  423. package/runtime/scripts/hfs/catalog-once.d.mts +2 -0
  424. package/runtime/scripts/hfs/catalog-once.mjs +8 -9
  425. package/runtime/scripts/hfs/check-results.d.mts +29 -0
  426. package/runtime/scripts/hfs/check-results.mjs +14 -18
  427. package/runtime/scripts/hfs/check.d.mts +144 -0
  428. package/runtime/scripts/hfs/check.mjs +309 -329
  429. package/runtime/scripts/hfs/ci-declaration.d.mts +77 -0
  430. package/runtime/scripts/hfs/ci-declaration.mjs +99 -87
  431. package/runtime/scripts/hfs/coverage-from.d.mts +22 -0
  432. package/runtime/scripts/hfs/coverage-from.mjs +52 -49
  433. package/runtime/scripts/hfs/coverage-scope.d.mts +87 -0
  434. package/runtime/scripts/hfs/coverage-scope.mjs +139 -142
  435. package/runtime/scripts/hfs/db-baseline-verb.d.mts +84 -0
  436. package/runtime/scripts/hfs/db-baseline-verb.mjs +327 -266
  437. package/runtime/scripts/hfs/db-errors.d.mts +2 -0
  438. package/runtime/scripts/hfs/db-errors.mjs +2 -1
  439. package/runtime/scripts/hfs/db-plan-verb.d.mts +33 -0
  440. package/runtime/scripts/hfs/db-plan-verb.mjs +174 -128
  441. package/runtime/scripts/hfs/db-restamp-verb.d.mts +5 -0
  442. package/runtime/scripts/hfs/db-restamp-verb.mjs +94 -70
  443. package/runtime/scripts/hfs/db-squash.d.mts +117 -0
  444. package/runtime/scripts/hfs/db-squash.mjs +414 -351
  445. package/runtime/scripts/hfs/declaration-shape.d.mts +3 -0
  446. package/runtime/scripts/hfs/declaration-shape.mjs +140 -103
  447. package/runtime/scripts/hfs/declaration-slots.d.mts +18 -0
  448. package/runtime/scripts/hfs/declaration-slots.mjs +64 -61
  449. package/runtime/scripts/hfs/doc-commands.d.mts +71 -0
  450. package/runtime/scripts/hfs/doc-commands.mjs +257 -250
  451. package/runtime/scripts/hfs/edition-slots.d.mts +37 -0
  452. package/runtime/scripts/hfs/edition-slots.mjs +43 -40
  453. package/runtime/scripts/hfs/example-secrets.d.mts +18 -0
  454. package/runtime/scripts/hfs/example-secrets.mjs +173 -154
  455. package/runtime/scripts/hfs/gate-threshold.d.mts +20 -0
  456. package/runtime/scripts/hfs/gate-threshold.mjs +28 -0
  457. package/runtime/scripts/hfs/grammar-presentation.d.mts +74 -0
  458. package/runtime/scripts/hfs/grammar-presentation.mjs +109 -106
  459. package/runtime/scripts/hfs/linear-text.d.mts +6 -0
  460. package/runtime/scripts/hfs/linear-text.mjs +20 -20
  461. package/runtime/scripts/hfs/manifest-shape.d.mts +216 -0
  462. package/runtime/scripts/hfs/manifest-shape.mjs +399 -324
  463. package/runtime/scripts/hfs/param-names.d.mts +3 -0
  464. package/runtime/scripts/hfs/param-names.mjs +6 -11
  465. package/runtime/scripts/hfs/path-findings.d.mts +22 -0
  466. package/runtime/scripts/hfs/path-findings.mjs +120 -100
  467. package/runtime/scripts/hfs/pin-findings.d.mts +19 -0
  468. package/runtime/scripts/hfs/pin-findings.mjs +26 -21
  469. package/runtime/scripts/hfs/refusal-codes.d.mts +1 -0
  470. package/runtime/scripts/hfs/refusal-codes.mjs +2 -2
  471. package/runtime/scripts/hfs/repo-identity.d.mts +15 -0
  472. package/runtime/scripts/hfs/repo-identity.mjs +55 -42
  473. package/runtime/scripts/hfs/rule-catalog.d.mts +77 -0
  474. package/runtime/scripts/hfs/rule-catalog.mjs +353 -257
  475. package/runtime/scripts/hfs/rule-params-shape.d.mts +10 -0
  476. package/runtime/scripts/hfs/rule-params-shape.mjs +60 -47
  477. package/runtime/scripts/hfs/rules/a15-findings.d.mts +18 -0
  478. package/runtime/scripts/hfs/rules/a15-findings.mjs +59 -55
  479. package/runtime/scripts/hfs/rules/app-env-required.d.mts +9 -0
  480. package/runtime/scripts/hfs/rules/app-env-required.mjs +13 -13
  481. package/runtime/scripts/hfs/rules/app-root.d.mts +15 -0
  482. package/runtime/scripts/hfs/rules/app-root.mjs +20 -21
  483. package/runtime/scripts/hfs/rules/app-workflow-findings.d.mts +12 -0
  484. package/runtime/scripts/hfs/rules/app-workflow-findings.mjs +4 -4
  485. package/runtime/scripts/hfs/rules/assets.d.mts +13 -0
  486. package/runtime/scripts/hfs/rules/assets.mjs +58 -46
  487. package/runtime/scripts/hfs/rules/boot-proof.d.mts +11 -0
  488. package/runtime/scripts/hfs/rules/boot-proof.mjs +7 -8
  489. package/runtime/scripts/hfs/rules/bypass-markers.d.mts +9 -0
  490. package/runtime/scripts/hfs/rules/bypass-markers.mjs +7 -12
  491. package/runtime/scripts/hfs/rules/canon-copy-drift.d.mts +10 -0
  492. package/runtime/scripts/hfs/rules/canon-copy-drift.mjs +70 -68
  493. package/runtime/scripts/hfs/rules/ci-custody.d.mts +7 -0
  494. package/runtime/scripts/hfs/rules/ci-custody.mjs +72 -73
  495. package/runtime/scripts/hfs/rules/ci-standard.d.mts +12 -0
  496. package/runtime/scripts/hfs/rules/ci-standard.mjs +149 -142
  497. package/runtime/scripts/hfs/rules/cli.d.mts +7 -0
  498. package/runtime/scripts/hfs/rules/cli.mjs +24 -23
  499. package/runtime/scripts/hfs/rules/contract-compat.d.mts +11 -0
  500. package/runtime/scripts/hfs/rules/contract-compat.mjs +64 -53
  501. package/runtime/scripts/hfs/rules/contract.d.mts +26 -0
  502. package/runtime/scripts/hfs/rules/contract.mjs +126 -111
  503. package/runtime/scripts/hfs/rules/coverage-below.d.mts +17 -0
  504. package/runtime/scripts/hfs/rules/coverage-below.mjs +200 -167
  505. package/runtime/scripts/hfs/rules/database-access.d.mts +12 -0
  506. package/runtime/scripts/hfs/rules/database-access.mjs +231 -202
  507. package/runtime/scripts/hfs/rules/database-baseline.d.mts +22 -0
  508. package/runtime/scripts/hfs/rules/database-baseline.mjs +104 -104
  509. package/runtime/scripts/hfs/rules/database-config.d.mts +11 -0
  510. package/runtime/scripts/hfs/rules/database-config.mjs +101 -135
  511. package/runtime/scripts/hfs/rules/database-constants.d.mts +36 -0
  512. package/runtime/scripts/hfs/rules/database-constants.mjs +7 -7
  513. package/runtime/scripts/hfs/rules/database-migrations.d.mts +41 -0
  514. package/runtime/scripts/hfs/rules/database-migrations.mjs +428 -388
  515. package/runtime/scripts/hfs/rules/database-plpgsql.d.mts +5 -0
  516. package/runtime/scripts/hfs/rules/database-plpgsql.mjs +278 -259
  517. package/runtime/scripts/hfs/rules/database-queue-sources.d.mts +4 -0
  518. package/runtime/scripts/hfs/rules/database-queue-sources.mjs +48 -43
  519. package/runtime/scripts/hfs/rules/database-queues.d.mts +15 -0
  520. package/runtime/scripts/hfs/rules/database-queues.mjs +211 -182
  521. package/runtime/scripts/hfs/rules/database-sql.d.mts +16 -0
  522. package/runtime/scripts/hfs/rules/database-sql.mjs +394 -394
  523. package/runtime/scripts/hfs/rules/database-transaction.d.mts +3 -0
  524. package/runtime/scripts/hfs/rules/database-transaction.mjs +25 -27
  525. package/runtime/scripts/hfs/rules/database.d.mts +22 -0
  526. package/runtime/scripts/hfs/rules/database.mjs +42 -58
  527. package/runtime/scripts/hfs/rules/deploy-scan.d.mts +10 -0
  528. package/runtime/scripts/hfs/rules/deploy-scan.mjs +177 -168
  529. package/runtime/scripts/hfs/rules/deploy-workflow.d.mts +3 -0
  530. package/runtime/scripts/hfs/rules/deploy-workflow.mjs +194 -171
  531. package/runtime/scripts/hfs/rules/deps.d.mts +6 -0
  532. package/runtime/scripts/hfs/rules/deps.mjs +61 -60
  533. package/runtime/scripts/hfs/rules/doc-fresh.d.mts +11 -0
  534. package/runtime/scripts/hfs/rules/doc-fresh.mjs +242 -223
  535. package/runtime/scripts/hfs/rules/docker-health.d.mts +9 -0
  536. package/runtime/scripts/hfs/rules/docker-health.mjs +222 -196
  537. package/runtime/scripts/hfs/rules/docker.d.mts +13 -0
  538. package/runtime/scripts/hfs/rules/docker.mjs +234 -208
  539. package/runtime/scripts/hfs/rules/edition.d.mts +18 -0
  540. package/runtime/scripts/hfs/rules/edition.mjs +103 -101
  541. package/runtime/scripts/hfs/rules/env-parity.d.mts +25 -0
  542. package/runtime/scripts/hfs/rules/env-parity.mjs +278 -252
  543. package/runtime/scripts/hfs/rules/env-value-shape.d.mts +21 -0
  544. package/runtime/scripts/hfs/rules/env-value-shape.mjs +82 -67
  545. package/runtime/scripts/hfs/rules/event-bus.d.mts +17 -0
  546. package/runtime/scripts/hfs/rules/event-bus.mjs +145 -133
  547. package/runtime/scripts/hfs/rules/event-tables.d.mts +7 -0
  548. package/runtime/scripts/hfs/rules/event-tables.mjs +77 -75
  549. package/runtime/scripts/hfs/rules/fe-build-args.d.mts +10 -0
  550. package/runtime/scripts/hfs/rules/fe-build-args.mjs +116 -99
  551. package/runtime/scripts/hfs/rules/fe-contract-documents.d.mts +7 -0
  552. package/runtime/scripts/hfs/rules/fe-contract-documents.mjs +121 -111
  553. package/runtime/scripts/hfs/rules/fe-no-tests.d.mts +9 -0
  554. package/runtime/scripts/hfs/rules/fe-no-tests.mjs +37 -36
  555. package/runtime/scripts/hfs/rules/fe-stack.d.mts +23 -0
  556. package/runtime/scripts/hfs/rules/fe-stack.mjs +108 -105
  557. package/runtime/scripts/hfs/rules/feature-files.d.mts +10 -0
  558. package/runtime/scripts/hfs/rules/feature-files.mjs +14 -19
  559. package/runtime/scripts/hfs/rules/frontend-tree.d.mts +18 -0
  560. package/runtime/scripts/hfs/rules/frontend-tree.mjs +105 -91
  561. package/runtime/scripts/hfs/rules/integration-specs.d.mts +7 -0
  562. package/runtime/scripts/hfs/rules/integration-specs.mjs +190 -177
  563. package/runtime/scripts/hfs/rules/kinds.d.mts +6 -0
  564. package/runtime/scripts/hfs/rules/kinds.mjs +88 -81
  565. package/runtime/scripts/hfs/rules/lexicon.d.mts +9 -0
  566. package/runtime/scripts/hfs/rules/lexicon.mjs +43 -40
  567. package/runtime/scripts/hfs/rules/lint-suppression.d.mts +5 -0
  568. package/runtime/scripts/hfs/rules/lint-suppression.mjs +22 -20
  569. package/runtime/scripts/hfs/rules/lite-proof-lane.d.mts +9 -0
  570. package/runtime/scripts/hfs/rules/lite-proof-lane.mjs +59 -58
  571. package/runtime/scripts/hfs/rules/lite-secrets.d.mts +12 -0
  572. package/runtime/scripts/hfs/rules/lite-secrets.mjs +60 -63
  573. package/runtime/scripts/hfs/rules/mcp-tools.d.mts +7 -0
  574. package/runtime/scripts/hfs/rules/mcp-tools.mjs +56 -41
  575. package/runtime/scripts/hfs/rules/monorepo.d.mts +17 -0
  576. package/runtime/scripts/hfs/rules/monorepo.mjs +153 -138
  577. package/runtime/scripts/hfs/rules/peer-integrations.d.mts +7 -0
  578. package/runtime/scripts/hfs/rules/peer-integrations.mjs +39 -36
  579. package/runtime/scripts/hfs/rules/pipeline.d.mts +7 -0
  580. package/runtime/scripts/hfs/rules/pipeline.mjs +53 -53
  581. package/runtime/scripts/hfs/rules/proof-commands.d.mts +14 -0
  582. package/runtime/scripts/hfs/rules/proof-commands.mjs +52 -41
  583. package/runtime/scripts/hfs/rules/read.d.mts +7 -0
  584. package/runtime/scripts/hfs/rules/read.mjs +19 -15
  585. package/runtime/scripts/hfs/rules/release-provenance.d.mts +12 -0
  586. package/runtime/scripts/hfs/rules/release-provenance.mjs +196 -159
  587. package/runtime/scripts/hfs/rules/repo-local-checks.d.mts +5 -0
  588. package/runtime/scripts/hfs/rules/repo-local-checks.mjs +19 -17
  589. package/runtime/scripts/hfs/rules/rule-types.d.mts +40 -0
  590. package/runtime/scripts/hfs/rules/rule-types.mjs +4 -0
  591. package/runtime/scripts/hfs/rules/saga-delivery.d.mts +2 -0
  592. package/runtime/scripts/hfs/rules/saga-delivery.mjs +58 -50
  593. package/runtime/scripts/hfs/rules/saga.d.mts +7 -0
  594. package/runtime/scripts/hfs/rules/saga.mjs +151 -145
  595. package/runtime/scripts/hfs/rules/script-hygiene.d.mts +11 -0
  596. package/runtime/scripts/hfs/rules/script-hygiene.mjs +112 -95
  597. package/runtime/scripts/hfs/rules/secret-custody-only.d.mts +7 -0
  598. package/runtime/scripts/hfs/rules/secret-custody-only.mjs +29 -35
  599. package/runtime/scripts/hfs/rules/secrets.d.mts +29 -0
  600. package/runtime/scripts/hfs/rules/secrets.mjs +45 -44
  601. package/runtime/scripts/hfs/rules/services.d.mts +7 -0
  602. package/runtime/scripts/hfs/rules/services.mjs +148 -148
  603. package/runtime/scripts/hfs/rules/spec-placement.d.mts +8 -0
  604. package/runtime/scripts/hfs/rules/spec-placement.mjs +12 -13
  605. package/runtime/scripts/hfs/rules/stack-tooling.d.mts +11 -0
  606. package/runtime/scripts/hfs/rules/stack-tooling.mjs +45 -52
  607. package/runtime/scripts/hfs/rules/stacks-auth-cookie-domain.d.mts +30 -0
  608. package/runtime/scripts/hfs/rules/stacks-auth-cookie-domain.mjs +149 -0
  609. package/runtime/scripts/hfs/rules/stacks-deploy.d.mts +7 -0
  610. package/runtime/scripts/hfs/rules/stacks-deploy.mjs +32 -42
  611. package/runtime/scripts/hfs/rules/stacks-ingress.d.mts +16 -0
  612. package/runtime/scripts/hfs/rules/stacks-ingress.mjs +62 -64
  613. package/runtime/scripts/hfs/rules/stacks-lite-backing.d.mts +17 -0
  614. package/runtime/scripts/hfs/rules/stacks-lite-backing.mjs +111 -116
  615. package/runtime/scripts/hfs/rules/stacks-release.d.mts +26 -0
  616. package/runtime/scripts/hfs/rules/stacks-release.mjs +335 -309
  617. package/runtime/scripts/hfs/rules/stacks-runtime.d.mts +31 -0
  618. package/runtime/scripts/hfs/rules/stacks-runtime.mjs +130 -124
  619. package/runtime/scripts/hfs/rules/stacks-swarm.d.mts +5 -0
  620. package/runtime/scripts/hfs/rules/stacks-swarm.mjs +366 -344
  621. package/runtime/scripts/hfs/rules/stacks.d.mts +7 -0
  622. package/runtime/scripts/hfs/rules/stacks.mjs +37 -38
  623. package/runtime/scripts/hfs/rules/staged-specs.d.mts +10 -0
  624. package/runtime/scripts/hfs/rules/staged-specs.mjs +14 -18
  625. package/runtime/scripts/hfs/rules/supply-chain.d.mts +10 -0
  626. package/runtime/scripts/hfs/rules/supply-chain.mjs +143 -150
  627. package/runtime/scripts/hfs/rules/test-topology.d.mts +5 -0
  628. package/runtime/scripts/hfs/rules/test-topology.mjs +23 -21
  629. package/runtime/scripts/hfs/rules/text-integrity.d.mts +9 -0
  630. package/runtime/scripts/hfs/rules/text-integrity.mjs +47 -43
  631. package/runtime/scripts/hfs/rules/unused-symbol-flow.d.mts +22 -0
  632. package/runtime/scripts/hfs/rules/unused-symbol-flow.mjs +226 -204
  633. package/runtime/scripts/hfs/rules/unused-symbol-ledger.d.mts +7 -0
  634. package/runtime/scripts/hfs/rules/unused-symbol-ledger.mjs +70 -49
  635. package/runtime/scripts/hfs/rules/unused-symbol-properties.d.mts +12 -0
  636. package/runtime/scripts/hfs/rules/unused-symbol-properties.mjs +141 -126
  637. package/runtime/scripts/hfs/rules/unused-symbol-translators.d.mts +8 -0
  638. package/runtime/scripts/hfs/rules/unused-symbol-translators.mjs +160 -140
  639. package/runtime/scripts/hfs/rules/unused-symbol-values.d.mts +9 -0
  640. package/runtime/scripts/hfs/rules/unused-symbol-values.mjs +138 -125
  641. package/runtime/scripts/hfs/rules/unused-symbol.d.mts +11 -0
  642. package/runtime/scripts/hfs/rules/unused-symbol.mjs +283 -253
  643. package/runtime/scripts/hfs/rules/workflow-contexts.d.mts +8 -0
  644. package/runtime/scripts/hfs/rules/workflow-contexts.mjs +79 -67
  645. package/runtime/scripts/hfs/runtime-rules/git-triggers.d.mts +6 -0
  646. package/runtime/scripts/hfs/runtime-rules/git-triggers.mjs +36 -35
  647. package/runtime/scripts/hfs/runtime-rules/hook-shape.d.mts +10 -0
  648. package/runtime/scripts/hfs/runtime-rules/hook-shape.mjs +45 -42
  649. package/runtime/scripts/hfs/runtime-rules/source-ast.d.mts +39 -0
  650. package/runtime/scripts/hfs/runtime-rules/source-ast.mjs +130 -116
  651. package/runtime/scripts/hfs/runtime-rules/workflow-source.d.mts +5 -0
  652. package/runtime/scripts/hfs/runtime-rules/workflow-source.mjs +8 -7
  653. package/runtime/scripts/hfs/sealed-members.d.mts +22 -0
  654. package/runtime/scripts/hfs/sealed-members.mjs +79 -75
  655. package/runtime/scripts/hfs/secret-bootstrap-crypto.d.mts +12 -0
  656. package/runtime/scripts/hfs/secret-bootstrap-crypto.mjs +151 -167
  657. package/runtime/scripts/hfs/secret-document.d.mts +16 -0
  658. package/runtime/scripts/hfs/secret-document.mjs +59 -75
  659. package/runtime/scripts/hfs/secret-edit.d.mts +14 -0
  660. package/runtime/scripts/hfs/secret-edit.mjs +115 -135
  661. package/runtime/scripts/hfs/secret-errors.d.mts +4 -0
  662. package/runtime/scripts/hfs/secret-errors.mjs +19 -16
  663. package/runtime/scripts/hfs/secret-files.d.mts +20 -0
  664. package/runtime/scripts/hfs/secret-files.mjs +103 -112
  665. package/runtime/scripts/hfs/secret-init.d.mts +108 -0
  666. package/runtime/scripts/hfs/secret-init.mjs +304 -346
  667. package/runtime/scripts/hfs/secret-output.d.mts +18 -0
  668. package/runtime/scripts/hfs/secret-output.mjs +52 -80
  669. package/runtime/scripts/hfs/secret-prompt.d.mts +39 -0
  670. package/runtime/scripts/hfs/secret-prompt.mjs +108 -93
  671. package/runtime/scripts/hfs/secret-sops.d.mts +29 -0
  672. package/runtime/scripts/hfs/secret-sops.mjs +161 -199
  673. package/runtime/scripts/hfs/secret-standard.d.mts +89 -0
  674. package/runtime/scripts/hfs/secret-standard.mjs +300 -264
  675. package/runtime/scripts/hfs/secret-store.d.mts +36 -0
  676. package/runtime/scripts/hfs/secret-store.mjs +120 -136
  677. package/runtime/scripts/hfs/secret.d.mts +40 -0
  678. package/runtime/scripts/hfs/secret.mjs +254 -222
  679. package/runtime/scripts/hfs/slot-app-view.d.mts +11 -0
  680. package/runtime/scripts/hfs/slot-app-view.mjs +69 -74
  681. package/runtime/scripts/hfs/slot-classify.d.mts +75 -0
  682. package/runtime/scripts/hfs/slot-classify.mjs +42 -38
  683. package/runtime/scripts/hfs/slot-errors.d.mts +6 -0
  684. package/runtime/scripts/hfs/slot-errors.mjs +8 -7
  685. package/runtime/scripts/hfs/slot-imports.d.mts +8 -0
  686. package/runtime/scripts/hfs/slot-imports.mjs +70 -63
  687. package/runtime/scripts/hfs/slot-manifest-shape.d.mts +9 -0
  688. package/runtime/scripts/hfs/slot-manifest-shape.mjs +74 -52
  689. package/runtime/scripts/hfs/slot-match.d.mts +50 -0
  690. package/runtime/scripts/hfs/slot-match.mjs +122 -111
  691. package/runtime/scripts/hfs/slot-path.d.mts +1 -0
  692. package/runtime/scripts/hfs/slot-path.mjs +0 -2
  693. package/runtime/scripts/hfs/slot-required.d.mts +11 -0
  694. package/runtime/scripts/hfs/slot-required.mjs +65 -59
  695. package/runtime/scripts/hfs/slot-semantic-problems.d.mts +9 -0
  696. package/runtime/scripts/hfs/slot-semantic-problems.mjs +138 -112
  697. package/runtime/scripts/hfs/slot-side-problems.d.mts +3 -0
  698. package/runtime/scripts/hfs/slot-side-problems.mjs +23 -19
  699. package/runtime/scripts/hfs/slots.d.mts +188 -0
  700. package/runtime/scripts/hfs/slots.mjs +175 -152
  701. package/runtime/scripts/hfs/sql/pg-parse.d.mts +9 -0
  702. package/runtime/scripts/hfs/sql/pg-parse.mjs +25 -25
  703. package/runtime/scripts/hfs/stack-config-kit.d.mts +22 -0
  704. package/runtime/scripts/hfs/stack-config-kit.mjs +21 -17
  705. package/runtime/scripts/hfs/stack-deploy-config.d.mts +155 -0
  706. package/runtime/scripts/hfs/stack-deploy-config.mjs +345 -273
  707. package/runtime/scripts/hfs/stack-ingress-config.d.mts +74 -0
  708. package/runtime/scripts/hfs/stack-ingress-config.mjs +211 -177
  709. package/runtime/scripts/hfs/stacks-gate.d.mts +52 -0
  710. package/runtime/scripts/hfs/stacks-gate.mjs +557 -397
  711. package/runtime/scripts/hfs/starcistacks-runtime.d.mts +7 -0
  712. package/runtime/scripts/hfs/starcistacks-runtime.mjs +51 -40
  713. package/runtime/scripts/hfs/test-world-slot.d.mts +2 -0
  714. package/runtime/scripts/hfs/test-world-slot.mjs +0 -1
  715. package/runtime/scripts/hfs/trailing-slashes.d.mts +2 -0
  716. package/runtime/scripts/hfs/trailing-slashes.mjs +4 -4
  717. package/runtime/scripts/hfs/tree-findings.d.mts +9 -0
  718. package/runtime/scripts/hfs/tree-findings.mjs +18 -17
  719. package/runtime/scripts/hfs/tree.d.mts +35 -0
  720. package/runtime/scripts/hfs/tree.mjs +56 -46
  721. package/runtime/scripts/hfs/typescript-programs.d.mts +36 -0
  722. package/runtime/scripts/hfs/typescript-programs.mjs +66 -69
  723. package/runtime/scripts/hfs/view.d.mts +45 -0
  724. package/runtime/scripts/hfs/view.mjs +38 -40
  725. package/runtime/scripts/lib/bypass-markers.d.mts +15 -0
  726. package/runtime/scripts/lib/bypass-markers.mjs +210 -197
  727. package/runtime/scripts/lib/cli-arg.d.mts +67 -0
  728. package/runtime/scripts/lib/cli-arg.mjs +59 -63
  729. package/runtime/scripts/lib/command-tokens.d.mts +11 -0
  730. package/runtime/scripts/lib/command-tokens.mjs +77 -78
  731. package/runtime/scripts/lib/compose-values.d.mts +6 -0
  732. package/runtime/scripts/lib/compose-values.mjs +7 -7
  733. package/runtime/scripts/lib/css-rules.d.mts +36 -0
  734. package/runtime/scripts/lib/css-rules.mjs +181 -171
  735. package/runtime/scripts/lib/deployment-findings.d.mts +9 -0
  736. package/runtime/scripts/lib/deployment-findings.mjs +4 -4
  737. package/runtime/scripts/lib/dockerfile.d.mts +39 -0
  738. package/runtime/scripts/lib/dockerfile.mjs +131 -114
  739. package/runtime/scripts/lib/dom-tree.d.mts +7 -0
  740. package/runtime/scripts/lib/dom-tree.mjs +3 -3
  741. package/runtime/scripts/lib/env.d.mts +12 -0
  742. package/runtime/scripts/lib/env.mjs +3 -6
  743. package/runtime/scripts/lib/escape.d.mts +6 -0
  744. package/runtime/scripts/lib/escape.mjs +2 -6
  745. package/runtime/scripts/lib/event-contract.d.mts +21 -0
  746. package/runtime/scripts/lib/event-contract.mjs +73 -78
  747. package/runtime/scripts/lib/event-items.d.mts +20 -0
  748. package/runtime/scripts/lib/event-items.mjs +27 -15
  749. package/runtime/scripts/lib/example-refs.d.mts +69 -0
  750. package/runtime/scripts/lib/example-refs.mjs +145 -129
  751. package/runtime/scripts/lib/fs-kind.d.mts +12 -0
  752. package/runtime/scripts/lib/fs-kind.mjs +20 -10
  753. package/runtime/scripts/lib/git-hooks-dir.d.mts +15 -0
  754. package/runtime/scripts/lib/git-hooks-dir.mjs +16 -16
  755. package/runtime/scripts/lib/git.d.mts +24 -0
  756. package/runtime/scripts/lib/git.mjs +15 -16
  757. package/runtime/scripts/lib/glob.d.mts +4 -0
  758. package/runtime/scripts/lib/glob.mjs +23 -14
  759. package/runtime/scripts/lib/grammar-lint.d.mts +47 -0
  760. package/runtime/scripts/lib/grammar-lint.mjs +33 -37
  761. package/runtime/scripts/lib/grammar-vendor-parity-jsx.d.mts +40 -0
  762. package/runtime/scripts/lib/grammar-vendor-parity-jsx.mjs +285 -266
  763. package/runtime/scripts/lib/grammar-vendor-parity.d.mts +61 -0
  764. package/runtime/scripts/lib/grammar-vendor-parity.mjs +209 -216
  765. package/runtime/scripts/lib/graphql-contract.d.mts +53 -0
  766. package/runtime/scripts/lib/graphql-contract.mjs +201 -198
  767. package/runtime/scripts/lib/graphql-sdl.d.mts +66 -0
  768. package/runtime/scripts/lib/graphql-sdl.mjs +230 -205
  769. package/runtime/scripts/lib/hook-limits.d.mts +11 -0
  770. package/runtime/scripts/lib/hook-limits.mjs +0 -1
  771. package/runtime/scripts/lib/i18n.d.mts +48 -0
  772. package/runtime/scripts/lib/i18n.mjs +32 -35
  773. package/runtime/scripts/lib/in-order.d.mts +12 -0
  774. package/runtime/scripts/lib/in-order.mjs +57 -38
  775. package/runtime/scripts/lib/is-main.d.mts +6 -0
  776. package/runtime/scripts/lib/is-main.mjs +11 -4
  777. package/runtime/scripts/lib/js-lex.d.mts +32 -0
  778. package/runtime/scripts/lib/js-lex.mjs +196 -162
  779. package/runtime/scripts/lib/json-clone.d.mts +11 -0
  780. package/runtime/scripts/lib/json-clone.mjs +45 -36
  781. package/runtime/scripts/lib/json-schema.d.mts +2 -0
  782. package/runtime/scripts/lib/json-schema.mjs +127 -90
  783. package/runtime/scripts/lib/json.d.mts +16 -0
  784. package/runtime/scripts/lib/json.mjs +26 -14
  785. package/runtime/scripts/lib/language.d.mts +44 -0
  786. package/runtime/scripts/lib/language.mjs +133 -129
  787. package/runtime/scripts/lib/list.d.mts +17 -0
  788. package/runtime/scripts/lib/list.mjs +9 -14
  789. package/runtime/scripts/lib/loosening-budgets.d.mts +12 -0
  790. package/runtime/scripts/lib/loosening-budgets.mjs +35 -29
  791. package/runtime/scripts/lib/loosening-config.d.mts +64 -0
  792. package/runtime/scripts/lib/loosening-config.mjs +267 -236
  793. package/runtime/scripts/lib/loosening-state.d.mts +77 -0
  794. package/runtime/scripts/lib/loosening-state.mjs +134 -128
  795. package/runtime/scripts/lib/mutation-fence.d.mts +11 -0
  796. package/runtime/scripts/lib/mutation-fence.mjs +10 -5
  797. package/runtime/scripts/lib/normalize.d.mts +12 -0
  798. package/runtime/scripts/lib/normalize.mjs +11 -11
  799. package/runtime/scripts/lib/numeric-match.d.mts +2 -0
  800. package/runtime/scripts/lib/numeric-match.mjs +2 -2
  801. package/runtime/scripts/lib/package-at.d.mts +24 -0
  802. package/runtime/scripts/lib/package-at.mjs +34 -31
  803. package/runtime/scripts/lib/path-key.d.mts +76 -0
  804. package/runtime/scripts/lib/path-key.mjs +53 -38
  805. package/runtime/scripts/lib/pid-alive.d.mts +2 -0
  806. package/runtime/scripts/lib/pid-alive.mjs +10 -3
  807. package/runtime/scripts/lib/properties.d.mts +2 -0
  808. package/runtime/scripts/lib/properties.mjs +17 -11
  809. package/runtime/scripts/lib/provision-operation-schema.d.mts +4 -0
  810. package/runtime/scripts/lib/provision-operation-schema.mjs +4 -5
  811. package/runtime/scripts/lib/read-text.d.mts +12 -0
  812. package/runtime/scripts/lib/read-text.mjs +30 -17
  813. package/runtime/scripts/lib/redact.d.mts +52 -0
  814. package/runtime/scripts/lib/redact.mjs +135 -121
  815. package/runtime/scripts/lib/regex.d.mts +2 -0
  816. package/runtime/scripts/lib/regex.mjs +1 -2
  817. package/runtime/scripts/lib/roots.d.mts +32 -0
  818. package/runtime/scripts/lib/roots.mjs +5 -15
  819. package/runtime/scripts/lib/runtime-example.d.mts +1 -0
  820. package/runtime/scripts/lib/runtime-example.mjs +10 -8
  821. package/runtime/scripts/lib/same-text.d.mts +2 -0
  822. package/runtime/scripts/lib/same-text.mjs +0 -1
  823. package/runtime/scripts/lib/sealed-member.d.mts +16 -0
  824. package/runtime/scripts/lib/sealed-member.mjs +8 -13
  825. package/runtime/scripts/lib/secret-patterns.d.mts +30 -0
  826. package/runtime/scripts/lib/secret-patterns.mjs +175 -163
  827. package/runtime/scripts/lib/shell-source.d.mts +2 -0
  828. package/runtime/scripts/lib/shell-source.mjs +0 -1
  829. package/runtime/scripts/lib/sleep-sync.d.mts +2 -0
  830. package/runtime/scripts/lib/sleep-sync.mjs +5 -6
  831. package/runtime/scripts/lib/sops-envelope.d.mts +34 -0
  832. package/runtime/scripts/lib/sops-envelope.mjs +148 -120
  833. package/runtime/scripts/lib/source-phrases.d.mts +4 -0
  834. package/runtime/scripts/lib/source-phrases.mjs +13 -13
  835. package/runtime/scripts/lib/sql-ast.d.mts +13 -0
  836. package/runtime/scripts/lib/sql-ast.mjs +19 -18
  837. package/runtime/scripts/lib/sqlite.d.mts +21 -0
  838. package/runtime/scripts/lib/sqlite.mjs +3 -9
  839. package/runtime/scripts/lib/stack-declaration.d.mts +51 -0
  840. package/runtime/scripts/lib/stack-declaration.mjs +27 -20
  841. package/runtime/scripts/lib/stack-services.d.mts +73 -0
  842. package/runtime/scripts/lib/stack-services.mjs +128 -129
  843. package/runtime/scripts/lib/starciwork-boundary.d.mts +10 -0
  844. package/runtime/scripts/lib/starciwork-boundary.mjs +98 -92
  845. package/runtime/scripts/lib/swarm-stack.d.mts +24 -0
  846. package/runtime/scripts/lib/swarm-stack.mjs +112 -100
  847. package/runtime/scripts/lib/trim-end.d.mts +2 -0
  848. package/runtime/scripts/lib/trim-end.mjs +4 -4
  849. package/runtime/scripts/lib/ts-analysis.d.mts +24 -0
  850. package/runtime/scripts/lib/ts-analysis.mjs +28 -26
  851. package/runtime/scripts/lib/ts-ast.d.mts +36 -0
  852. package/runtime/scripts/lib/ts-ast.mjs +36 -42
  853. package/runtime/scripts/lib/walk.d.mts +19 -0
  854. package/runtime/scripts/lib/walk.mjs +33 -27
  855. package/runtime/scripts/lib/work-edition.d.mts +10 -0
  856. package/runtime/scripts/lib/work-edition.mjs +29 -21
  857. package/runtime/scripts/lib/workflow-events.d.mts +2 -0
  858. package/runtime/scripts/lib/workflow-events.mjs +5 -4
  859. package/runtime/scripts/lib/worktree-exclude.d.mts +16 -0
  860. package/runtime/scripts/lib/worktree-exclude.mjs +6 -8
  861. package/runtime/scripts/lib/yaml-cached.d.mts +2 -0
  862. package/runtime/scripts/lib/yaml-cached.mjs +4 -4
  863. package/runtime/scripts/machine/artifact-hold.d.mts +26 -0
  864. package/runtime/scripts/machine/artifact-hold.mjs +22 -23
  865. package/runtime/scripts/work/asset-slot.d.mts +96 -0
  866. package/runtime/scripts/work/asset-slot.mjs +201 -175
  867. package/runtime/scripts/work/draw/draw-dna-anatomy.d.mts +30 -0
  868. package/runtime/scripts/work/draw/draw-dna-anatomy.mjs +40 -36
  869. package/runtime/scripts/work/draw/draw-dna-findings.d.mts +12 -0
  870. package/runtime/scripts/work/draw/draw-dna-findings.mjs +240 -206
  871. package/runtime/scripts/work/draw/draw-dna-selector.d.mts +7 -0
  872. package/runtime/scripts/work/draw/draw-dna-selector.mjs +28 -28
  873. package/runtime/scripts/work/draw/draw-dna.d.mts +191 -0
  874. package/runtime/scripts/work/draw/draw-dna.mjs +283 -249
  875. package/runtime/scripts/work/grammar-proposal.d.mts +83 -0
  876. package/runtime/scripts/work/grammar-proposal.mjs +215 -178
  877. package/runtime/scripts/work/work-io.d.mts +62 -0
  878. package/runtime/scripts/work/work-io.mjs +82 -63
  879. package/scaffold/add-app.d.mts +15 -0
  880. package/scaffold/add-app.mjs +111 -163
  881. package/scaffold/add-cli-lite.d.mts +8 -0
  882. package/scaffold/add-cli-lite.mjs +173 -207
  883. package/scaffold/add-compose.d.mts +44 -0
  884. package/scaffold/add-compose.mjs +62 -62
  885. package/scaffold/add-database-lite.d.mts +2 -0
  886. package/scaffold/add-database-lite.mjs +10 -10
  887. package/scaffold/add-fe-layout.d.mts +16 -0
  888. package/scaffold/add-fe-layout.mjs +23 -23
  889. package/scaffold/add-fe-overlay.d.mts +17 -0
  890. package/scaffold/add-fe-overlay.mjs +76 -78
  891. package/scaffold/add-fe-page.d.mts +41 -0
  892. package/scaffold/add-fe-page.mjs +84 -89
  893. package/scaffold/add-fe-unit.d.mts +59 -0
  894. package/scaffold/add-fe-unit.mjs +205 -197
  895. package/scaffold/add-inbox-lite.d.mts +17 -0
  896. package/scaffold/add-inbox-lite.mjs +209 -264
  897. package/scaffold/add-plan.d.mts +68 -0
  898. package/scaffold/add-plan.mjs +164 -149
  899. package/scaffold/add-queue-lite.d.mts +34 -0
  900. package/scaffold/add-queue-lite.mjs +267 -267
  901. package/scaffold/add-table.d.mts +16 -0
  902. package/scaffold/add-table.mjs +405 -442
  903. package/scaffold/add.d.mts +34 -0
  904. package/scaffold/add.mjs +260 -246
  905. package/scaffold/app.d.mts +198 -0
  906. package/scaffold/app.mjs +413 -391
  907. package/scaffold/edition-gate.d.mts +49 -0
  908. package/scaffold/edition-gate.mjs +19 -29
  909. package/scaffold/image.d.mts +4 -0
  910. package/scaffold/image.mjs +12 -12
  911. package/scaffold/lite-exports.d.mts +15 -0
  912. package/scaffold/lite-exports.mjs +262 -255
  913. package/scaffold/pattern-file-slots.d.mts +7 -0
  914. package/scaffold/pattern-file-slots.mjs +29 -24
  915. package/scaffold/service.d.mts +60 -0
  916. package/scaffold/service.mjs +297 -279
  917. package/scaffold/test-world.d.mts +31 -0
  918. package/scaffold/test-world.mjs +71 -78
  919. package/scaffold/yaml-block-edit.d.mts +23 -0
  920. package/scaffold/yaml-block-edit.mjs +95 -87
  921. package/scripts/sync-bundles.d.mts +31 -0
  922. package/src/fixtures/bypass-index.d.mts +4 -0
  923. package/src/fixtures/hfs-stack-tooling/passing.d.mts +8 -0
  924. package/src/fixtures/hfs-stack-tooling/violating.d.mts +19 -0
  925. package/src/fixtures/hfs-stacks-full/model-unavailable.d.mts +10 -0
  926. package/src/fixtures/hfs-stacks-full/passing.d.mts +19 -0
  927. package/src/fixtures/hfs-stacks-full/violating.d.mts +10 -0
  928. package/src/fixtures/loosening/adversarial.d.mts +4 -0
  929. package/src/fixtures/loosening/forms.d.mts +16 -0
  930. package/src/fixtures/loosening/swallows.d.mts +5 -0
  931. package/src/helpers/hfs-arch-fixture.d.mts +47 -0
  932. package/src/helpers/hfs-cli-fixture.d.mts +65 -0
  933. package/src/helpers/hfs-hfs-docker-rules-fixture.d.mts +5 -0
  934. package/src/helpers/hfs-secret-fixture.d.mts +19 -0
  935. package/src/helpers/pre-push-fixture.d.mts +21 -0
  936. package/src/helpers/stack-compose.d.mts +6 -0
  937. package/src/helpers/swarm-stack-fixture.d.mts +18 -0
  938. package/src/helpers/tmpdir.d.mts +2 -0
  939. package/src/main.d.mts +58 -0
  940. package/src/main.mjs +494 -346
  941. package/stack/age-install.d.mts +13 -0
  942. package/stack/age-install.mjs +28 -25
  943. package/stack/backup.d.mts +11 -0
  944. package/stack/backup.mjs +76 -69
  945. package/stack/build-args.d.mts +7 -0
  946. package/stack/build-args.mjs +22 -23
  947. package/stack/build.d.mts +8 -0
  948. package/stack/build.mjs +138 -119
  949. package/stack/cli.d.mts +55 -0
  950. package/stack/cli.mjs +187 -130
  951. package/stack/config.d.mts +197 -0
  952. package/stack/config.mjs +47 -33
  953. package/stack/context.d.mts +122 -0
  954. package/stack/context.mjs +63 -65
  955. package/stack/converge.d.mts +13 -0
  956. package/stack/converge.mjs +73 -69
  957. package/stack/deploy.d.mts +88 -0
  958. package/stack/deploy.mjs +272 -224
  959. package/stack/digest.d.mts +8 -0
  960. package/stack/digest.mjs +1 -6
  961. package/stack/docker-transport.d.mts +5 -0
  962. package/stack/docker-transport.mjs +101 -93
  963. package/stack/edge-alias.d.mts +42 -0
  964. package/stack/edge-alias.mjs +62 -60
  965. package/stack/errors.d.mts +18 -0
  966. package/stack/errors.mjs +8 -10
  967. package/stack/image-scan.d.mts +20 -0
  968. package/stack/image-scan.mjs +114 -101
  969. package/stack/ingress-create.d.mts +4 -0
  970. package/stack/ingress-create.mjs +82 -86
  971. package/stack/ingress-publish.d.mts +6 -0
  972. package/stack/ingress-publish.mjs +194 -182
  973. package/stack/ingress.d.mts +55 -0
  974. package/stack/ingress.mjs +534 -524
  975. package/stack/jobs.d.mts +12 -0
  976. package/stack/jobs.mjs +35 -34
  977. package/stack/live-restore.d.mts +35 -0
  978. package/stack/live-restore.mjs +120 -125
  979. package/stack/post-deploy.d.mts +8 -0
  980. package/stack/post-deploy.mjs +25 -25
  981. package/stack/prepare.d.mts +24 -0
  982. package/stack/prepare.mjs +213 -200
  983. package/stack/private-file.d.mts +5 -0
  984. package/stack/private-file.mjs +9 -9
  985. package/stack/provision.d.mts +25 -0
  986. package/stack/provision.mjs +64 -63
  987. package/stack/prune.d.mts +11 -0
  988. package/stack/prune.mjs +38 -27
  989. package/stack/release-store.d.mts +28 -0
  990. package/stack/release-store.mjs +68 -67
  991. package/stack/remote.d.mts +83 -0
  992. package/stack/remote.mjs +176 -162
  993. package/stack/render.d.mts +14 -0
  994. package/stack/render.mjs +132 -124
  995. package/stack/retire.d.mts +9 -0
  996. package/stack/retire.mjs +31 -34
  997. package/stack/sealed.d.mts +46 -0
  998. package/stack/sealed.mjs +78 -82
  999. package/stack/server-key.d.mts +67 -0
  1000. package/stack/server-key.mjs +217 -203
  1001. package/stack/ssh-session.d.mts +29 -0
  1002. package/stack/ssh-session.mjs +133 -123
  1003. package/stack/target-binding.d.mts +21 -0
  1004. package/stack/target-binding.mjs +68 -44
  1005. package/stack/task.d.mts +12 -0
  1006. package/stack/task.mjs +26 -31
  1007. package/stack/urgent-floor.d.mts +106 -0
  1008. package/stack/urgent-floor.mjs +211 -160
  1009. package/stack/urgent-release.d.mts +38 -0
  1010. package/stack/urgent-release.mjs +26 -22
  1011. package/stack/verify.d.mts +14 -0
  1012. package/stack/verify.mjs +75 -65
  1013. package/sync/ci-commands.d.mts +26 -0
  1014. package/sync/ci-commands.mjs +181 -182
  1015. package/sync/cli.d.mts +8 -0
  1016. package/sync/cli.mjs +9 -9
  1017. package/sync/format.d.mts +38 -0
  1018. package/sync/format.mjs +30 -24
  1019. package/sync/hygiene.d.mts +23 -0
  1020. package/sync/hygiene.mjs +113 -99
  1021. package/sync/index.d.mts +237 -0
  1022. package/sync/index.mjs +457 -436
  1023. package/sync/managed.d.mts +23 -0
  1024. package/sync/managed.mjs +104 -94
  1025. package/sync/quality-services.d.mts +35 -0
  1026. package/sync/quality-services.mjs +48 -41
  1027. package/sync/readme-badges.d.mts +13 -0
  1028. package/sync/readme-badges.mjs +45 -44
  1029. package/sync/sonar-key.d.mts +31 -0
  1030. package/sync/sonar-key.mjs +29 -28
  1031. package/sync/stack-images.d.mts +36 -0
  1032. package/sync/stack-images.mjs +85 -95
  1033. package/sync/ts-strict.d.mts +14 -0
  1034. package/sync/ts-strict.mjs +43 -34
  1035. package/templates/app/ci-workflows/github/workflows/ci.yml +1 -1
  1036. package/templates/app/ci-workflows/github/workflows/images.yml +1 -1
  1037. package/templates/app/ci-workflows/github/workflows/stack-deploy.yml +2 -2
  1038. package/templates/app/ci-workflows/github/workflows/stack-key-restore.yml +1 -1
  1039. package/templates/app/ci-workflows-lite/github/workflows/ci.yml +1 -1
  1040. package/templates/app/ci-workflows-lite/github/workflows/db-deploy.yml +3 -3
  1041. package/templates/app/ci-workflows-lite/github/workflows/images.yml +1 -1
  1042. package/templates/app/ci-workflows-lite/github/workflows/stack-deploy.yml +2 -2
  1043. package/templates/app/ci-workflows-lite/github/workflows/stack-key-restore.yml +1 -1
  1044. package/templates/app/codegen-lite/scripts/codegen.mjs +1 -1
  1045. package/templates/app/db-bootstrap/db/bootstrap.sql +1 -1
  1046. package/templates/app/db-image/starcistacks/images/db/Dockerfile +1 -1
  1047. package/templates/app/hooks/husky/pre-commit +2 -2
  1048. package/templates/app/package-scripts/db.json +3 -3
  1049. package/templates/app/package-scripts/package.json +1 -1
  1050. package/templates/app/quality-config/sonar-project.properties +1 -1
  1051. package/templates/app/skeleton/.starcistacks/application-stacks.yaml +2 -2
  1052. package/templates/app/skeleton/.starcistacks/production/README.md +4 -4
  1053. package/templates/app/skeleton/.starcistacks/production/infra/swarm/stack.yaml +8 -3
  1054. package/templates/app/skeleton/README.md +1 -1
  1055. package/templates/app/skeleton-lite/.starcistacks/application-stacks.yaml +2 -2
  1056. package/templates/app/skeleton-lite/.starcistacks/dev/README.md +1 -1
  1057. package/templates/app/skeleton-lite/.starcistacks/dev/infra/swarm/stack.yaml +6 -2
  1058. package/templates/app/skeleton-lite/.starcistacks/dev/runtime/env/KEYS.md +3 -2
  1059. package/templates/app/skeleton-lite/.starcistacks/production/README.md +5 -5
  1060. package/templates/app/skeleton-lite/.starcistacks/production/infra/swarm/stack.yaml +7 -2
  1061. package/templates/app/skeleton-lite/.starcistacks/production/runtime/env/KEYS.md +3 -2
  1062. package/templates/app/skeleton-lite/README.md +2 -2
  1063. package/templates/be/skeleton/apps/cli/src/compose/platform.ts +1 -1
  1064. package/templates/be/skeleton/apps/cli/src/main.ts +6 -4
  1065. package/templates/be/skeleton/src/modules/platform/config/env-source.config.ts +12 -0
  1066. package/templates/be/skeleton/src/modules/platform/database/abstract.entity.ts +19 -0
  1067. package/templates/be/skeleton/src/modules/platform/database/database.module.ts +7 -1
  1068. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.spec.ts +19 -0
  1069. package/templates/be/skeleton/src/modules/platform/logging/json-logger.service.ts +4 -3
  1070. package/templates/be/skeleton/src/modules/platform/logging/logging.module.ts +1 -1
  1071. package/templates/be/skeleton/src/modules/platform/logging/logging.options.ts +5 -2
  1072. package/templates/be/skeleton-lite/apps/cli/src/compose/platform.ts +1 -1
  1073. package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.config.spec.ts +40 -0
  1074. package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.config.ts +1 -0
  1075. package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.cookie.spec.ts +48 -1
  1076. package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.cookie.ts +5 -0
  1077. package/templates/be/skeleton-lite/src/modules/integrations/passport/passport.options.ts +5 -0
  1078. package/templates/be/skeleton-lite/src/modules/integrations/passport/strategies/google.strategy.ts +1 -1
  1079. package/templates/be/skeleton-lite/src/modules/integrations/passport/strategies/oauth-state.store.ts +7 -3
  1080. package/templates/be/skeleton-lite/src/modules/platform/database/database.module.ts +7 -1
  1081. package/templates/be/table/entity.ts.tpl +4 -15
  1082. package/upgrade/check.d.mts +9 -0
  1083. package/upgrade/check.mjs +8 -8
  1084. package/upgrade/file-state.d.mts +6 -0
  1085. package/upgrade/file-state.mjs +32 -40
  1086. package/upgrade/index.d.mts +13 -0
  1087. package/upgrade/index.mjs +122 -151
  1088. package/vendor-types.d.mts +8 -0
package/release/gate.mjs CHANGED
@@ -14,10 +14,8 @@ import { failure, refusal } from '../stack/errors.mjs';
14
14
  import { produceLintReports } from './lint-report.mjs';
15
15
  import { URGENT_RULING, l4Path, readUrgent, recordRow, writeUrgent } from './records.mjs';
16
16
  import { sonarQualityGate } from './sonar-quality-gate.mjs';
17
-
18
17
  export const RELEASE_CODE = 'RELEASE_CONFIG_INVALID';
19
18
  const SONAR_UNREACHABLE = 'SONAR_UNREACHABLE';
20
-
21
19
  const FIELDS = new Set(['gates', 'tagPrefix', 'defaultBranch', 'requireCi']);
22
20
  /** Release-block keys that no longer exist, each with what replaced it. */
23
21
  const REMOVED_FIELDS = new Map([['tagMatchesVersion', 'the release tag is always <tagPrefix><package.json version>; delete the key']]);
@@ -40,433 +38,463 @@ const SCRIPT_GATES = ['format:check', 'typecheck', 'build:be', 'lint', 'db:lint'
40
38
  const WORLD_SCRIPTS = ['test:integration', 'test:e2e', 'test:contract'];
41
39
  // An app with an entity list (db/entity-list.mjs) checks its entities against the migrated schema: a row of every gate, declared or default.
42
40
  const DB_DRIFT = { name: 'db-drift', command: ['npx', 'starci', 'app', 'db', 'drift'], summary: null, env: {} };
43
-
44
41
  /** True for a branch or remote name git can take as one argument (no leading dash, only path-like characters). */
45
42
  export const refName = (value) => typeof value === 'string' && REF_NAME.test(value);
46
-
47
43
  const scriptGate = (script) => ({
48
- name: script.replaceAll(':', '-'),
49
- command: ['npm', 'run', script],
50
- summary: script === 'test' ? 'jest' : null,
51
- env: {},
44
+ name: script.replaceAll(':', '-'),
45
+ command: ['npm', 'run', script],
46
+ summary: script === 'test' ? 'jest' : null,
47
+ env: {},
52
48
  });
53
-
54
49
  /** Default gates run app-check, the enabled audit, then every managed script present in the app and the entity drift row, Sonar following when it is declared. */
55
50
  function defaultGates(scripts, audit, entities) {
56
- const present = SCRIPT_GATES.filter((script) => typeof scripts?.[script] === 'string');
57
- const world = typeof scripts?.['test:e2e'] === 'string' ? WORLD_SCRIPTS.filter((script) => typeof scripts?.[script] === 'string') : [];
58
- return [{ name: 'app-check', command: ['npx', 'starci', 'app', 'check'], summary: null, env: {} }, ...(audit ? [audit] : []), ...present.map(scriptGate), ...world.map(scriptGate), ...(entities ? [DB_DRIFT] : [])];
51
+ const present = SCRIPT_GATES.filter((script) => typeof scripts?.[script] === 'string');
52
+ const world = typeof scripts?.['test:e2e'] === 'string' ? WORLD_SCRIPTS.filter((script) => typeof scripts?.[script] === 'string') : [];
53
+ return [{ name: 'app-check', command: ['npx', 'starci', 'app', 'check'], summary: null, env: {} }, ...(audit ? [audit] : []), ...present.map(scriptGate), ...world.map(scriptGate), ...(entities ? [DB_DRIFT] : [])];
59
54
  }
60
-
61
55
  /** Shared quality settings retain the release reader's audit validation, disabled mode and legacy string host compatibility. */
62
56
  function releaseServices(services, options) {
63
- const audit = services?.audit ?? {};
64
- if (!plain(audit) || (audit.in !== undefined && (!Array.isArray(audit.in) || !audit.in.every((scope) => typeof scope === 'string'))) || (audit.omitDev !== undefined && typeof audit.omitDev !== 'boolean')) throw refusal(RELEASE_CODE, 'services.audit must be a mapping with a string-list in and boolean omitDev');
65
- const sonar = services?.sonar;
66
- const compatible = typeof sonar?.host === 'string' ? { ...sonar, host: { public: sonar.host } } : sonar;
67
- const quality = qualityServices({ services: { ...services, sonar: compatible } }, options);
68
- if (audit.mode === 'disabled') quality.audit = null;
69
- return quality;
70
- }
71
-
57
+ const audit = services?.audit ?? {};
58
+ if (!plain(audit) || (audit.in !== undefined && (!Array.isArray(audit.in) || !audit.in.every((scope) => typeof scope === 'string'))) || (audit.omitDev !== undefined && typeof audit.omitDev !== 'boolean'))
59
+ throw refusal(RELEASE_CODE, 'services.audit must be a mapping with a string-list in and boolean omitDev');
60
+ const sonar = services?.sonar;
61
+ const compatible = typeof sonar?.host === 'string' ? { ...sonar, host: { public: sonar.host } } : sonar;
62
+ const quality = qualityServices({ services: { ...services, sonar: compatible } }, options);
63
+ if (audit.mode === 'disabled')
64
+ quality.audit = null;
65
+ return quality;
66
+ }
72
67
  /** The shared audit settings preserve release scope, level and development-dependency selection. */
73
68
  function auditGate(audit) {
74
- if (!audit || !audit.in.includes('release-gate')) return null;
75
- if (!['info', 'low', 'moderate', 'high', 'critical'].includes(audit.level)) throw refusal(RELEASE_CODE, 'services.audit.level must be an npm audit level');
76
- return { name: 'audit', command: ['npm', 'audit', ...(audit.omitDev ? ['--omit=dev'] : []), `--audit-level=${audit.level}`], summary: null, env: {} };
69
+ if (!audit || !audit.in.includes('release-gate'))
70
+ return null;
71
+ if (!['info', 'low', 'moderate', 'high', 'critical'].includes(audit.level))
72
+ throw refusal(RELEASE_CODE, 'services.audit.level must be an npm audit level');
73
+ return { name: 'audit', command: ['npm', 'audit', ...(audit.omitDev ? ['--omit=dev'] : []), `--audit-level=${audit.level}`], summary: null, env: {} };
77
74
  }
78
-
79
75
  /** A requested local Sonar scan uses only the declared host and token variable; the token never enters argv. */
80
76
  function sonarGate(services, env) {
81
- const configured = services?.sonar;
82
- const sonar = configured?.provider === 'sonarcloud' ? { ...configured, host: 'https://sonarcloud.io' } : configured;
83
- const tokenName = sonar?.token;
84
- if (!sonar?.host || !ENV_KEY.test(tokenName) || !env[tokenName]) throw refusal('RELEASE_SONAR_UNAVAILABLE', 'declare an enabled services.sonar host and set its ci.token environment variable');
85
- const command = ['npx', '--yes', '@sonar/scan@4.3.0', `-Dsonar.host.url=${sonar.host}`];
86
- const organization = sonar.organization ?? (sonar.organizationVar ? env[sonar.organizationVar] : null);
87
- if (organization) command.push(`-Dsonar.organization=${organization}`);
88
- if (!command.every((word) => TOKEN.test(word))) throw refusal('RELEASE_SONAR_UNAVAILABLE', 'Sonar host and organization must be plain command arguments');
89
- return { name: 'sonar', command, summary: null, env: { SONAR_TOKEN: env[tokenName] }, provider: sonar,
90
- credentialNames: [...new Set(['SONAR_TOKEN', tokenName])] };
91
- }
92
-
77
+ const configured = services?.sonar;
78
+ const sonar = configured?.provider === 'sonarcloud' ? { ...configured, host: 'https://sonarcloud.io' } : configured;
79
+ const tokenName = sonar?.token;
80
+ if (!sonar?.host || !ENV_KEY.test(tokenName) || !env[tokenName])
81
+ throw refusal('RELEASE_SONAR_UNAVAILABLE', 'declare an enabled services.sonar host and set its ci.token environment variable');
82
+ const command = ['npx', '--yes', '@sonar/scan@4.3.0', `-Dsonar.host.url=${sonar.host}`];
83
+ const organization = sonar.organization ?? (sonar.organizationVar ? env[sonar.organizationVar] : null);
84
+ if (organization)
85
+ command.push(`-Dsonar.organization=${organization}`);
86
+ if (!command.every((word) => TOKEN.test(word)))
87
+ throw refusal('RELEASE_SONAR_UNAVAILABLE', 'Sonar host and organization must be plain command arguments');
88
+ return { name: 'sonar', command, summary: null, env: { SONAR_TOKEN: env[tokenName] }, provider: sonar,
89
+ credentialNames: [...new Set(['SONAR_TOKEN', tokenName])] };
90
+ }
93
91
  function gateProblems(entry, at, seen) {
94
- const found = [];
95
- for (const key of Object.keys(entry)) if (!GATE_FIELDS.has(key)) found.push(`${at}.${key}: is not a field of a gate`);
96
- if (typeof entry.name !== 'string' || !GATE_NAME.test(entry.name)) found.push(`${at}.name: must match ${GATE_NAME}`);
97
- else if (seen.has(entry.name)) found.push(`${at}.name: ${entry.name} is declared twice`);
98
- const command = entry.command;
99
- if (!Array.isArray(command) || command.length === 0 || !command.every((word) => typeof word === 'string' && TOKEN.test(word))) found.push(`${at}.command: must be a non-empty list of plain words (no shell strings)`);
100
- if (entry.summary !== undefined && entry.summary !== 'jest') found.push(`${at}.summary: must be jest`);
101
- const env = entry.env ?? {};
102
- if (!plain(env) || !Object.entries(env).every(([key, value]) => ENV_KEY.test(key) && typeof value === 'string')) found.push(`${at}.env: must map UPPER_CASE names to string values`);
103
- return found;
104
- }
105
-
92
+ const found = [];
93
+ for (const key of Object.keys(entry))
94
+ if (!GATE_FIELDS.has(key))
95
+ found.push(`${at}.${key}: is not a field of a gate`);
96
+ if (typeof entry.name !== 'string' || !GATE_NAME.test(entry.name))
97
+ found.push(`${at}.name: must match ${GATE_NAME}`);
98
+ else if (seen.has(entry.name))
99
+ found.push(`${at}.name: ${entry.name} is declared twice`);
100
+ const command = entry.command;
101
+ if (!Array.isArray(command) || command.length === 0 || !command.every((word) => typeof word === 'string' && TOKEN.test(word)))
102
+ found.push(`${at}.command: must be a non-empty list of plain words (no shell strings)`);
103
+ if (entry.summary !== undefined && entry.summary !== 'jest')
104
+ found.push(`${at}.summary: must be jest`);
105
+ const env = entry.env ?? {};
106
+ if (!plain(env) || !Object.entries(env).every(([key, value]) => ENV_KEY.test(key) && typeof value === 'string'))
107
+ found.push(`${at}.env: must map UPPER_CASE names to string values`);
108
+ return found;
109
+ }
106
110
  function gatesOf(list, problems) {
107
- if (!Array.isArray(list) || list.length === 0) {
108
- problems.push('release.gates: must be a non-empty list');
109
- return [];
110
- }
111
- const seen = new Set();
112
- const gates = [];
113
- list.forEach((entry, index) => {
114
- const at = `release.gates[${index}]`;
115
- const found = plain(entry) ? gateProblems(entry, at, seen) : [`${at}: must be a mapping`];
116
- problems.push(...found);
117
- if (found.length === 0) {
118
- seen.add(entry.name);
119
- gates.push({ name: entry.name, command: entry.command, summary: entry.summary ?? null, env: entry.env ?? {} });
111
+ if (!Array.isArray(list) || list.length === 0) {
112
+ problems.push('release.gates: must be a non-empty list');
113
+ return [];
120
114
  }
121
- });
122
- return gates;
115
+ const seen = new Set();
116
+ const gates = [];
117
+ list.forEach((entry, index) => {
118
+ const at = `release.gates[${index}]`;
119
+ const found = plain(entry) ? gateProblems(entry, at, seen) : [`${at}: must be a mapping`];
120
+ problems.push(...found);
121
+ if (found.length === 0) {
122
+ seen.add(entry.name);
123
+ gates.push({ name: entry.name, command: entry.command, summary: entry.summary ?? null, env: entry.env ?? {} });
124
+ }
125
+ });
126
+ return gates;
123
127
  }
124
-
125
128
  /** Judges the optional `release:` block. Absence is fine (defaults). Returns { config } or { problems }. */
126
129
  export function normalizeRelease(block, scripts = {}, services = {}, options = {}) {
127
- const raw = block ?? {};
128
- if (!plain(raw)) return { problems: ['release: must be a mapping'] };
129
- const problems = [];
130
- for (const key of Object.keys(raw)) {
131
- if (REMOVED_FIELDS.has(key)) problems.push(`release.${key}: is removed (${REMOVED_FIELDS.get(key)})`);
132
- else if (!FIELDS.has(key)) problems.push(`release.${key}: is not a field of the release block`);
133
- }
134
- const tagPrefix = raw.tagPrefix ?? 'v';
135
- const defaultBranch = raw.defaultBranch ?? 'main';
136
- // The candidate CI of `release push` is an app's choice and off by default (owner ruling release-require-ci-per-project); the local gate never is.
137
- const requireCi = raw.requireCi ?? false;
138
- if (typeof tagPrefix !== 'string' || !PREFIX.test(tagPrefix)) problems.push(`release.tagPrefix: must match ${PREFIX}`);
139
- if (!refName(defaultBranch)) problems.push(`release.defaultBranch: must match ${REF_NAME}`);
140
- if (typeof requireCi !== 'boolean') problems.push('release.requireCi: must be true or false');
141
- const quality = releaseServices(services, options);
142
- const audit = auditGate(quality.audit);
143
- const gates = raw.gates === undefined ? defaultGates(scripts, audit, options.entities === true) : gatesOf(raw.gates, problems);
144
- if (raw.gates !== undefined && audit && !gates.some((gate) => gate.name === 'audit')) gates.push(audit);
145
- if (raw.gates !== undefined && options.entities === true && !gates.some((gate) => gate.name === DB_DRIFT.name)) gates.push(DB_DRIFT);
146
- return problems.length === 0 ? { config: { gates, tagPrefix, defaultBranch, requireCi, services: quality } } : { problems };
147
- }
148
-
130
+ const given = block ?? {};
131
+ if (!plain(given))
132
+ return { problems: ['release: must be a mapping'] };
133
+ const raw = given; // reason: the release block is YAML parsed from disk; every field is judged below
134
+ const problems = [];
135
+ for (const key of Object.keys(raw)) {
136
+ if (REMOVED_FIELDS.has(key))
137
+ problems.push(`release.${key}: is removed (${REMOVED_FIELDS.get(key)})`);
138
+ else if (!FIELDS.has(key))
139
+ problems.push(`release.${key}: is not a field of the release block`);
140
+ }
141
+ const tagPrefix = raw.tagPrefix ?? 'v';
142
+ const defaultBranch = raw.defaultBranch ?? 'main';
143
+ // The candidate CI of `release push` is an app's choice and off by default (owner ruling release-require-ci-per-project); the local gate never is.
144
+ const requireCi = raw.requireCi ?? false;
145
+ if (typeof tagPrefix !== 'string' || !PREFIX.test(tagPrefix))
146
+ problems.push(`release.tagPrefix: must match ${PREFIX}`);
147
+ if (!refName(defaultBranch))
148
+ problems.push(`release.defaultBranch: must match ${REF_NAME}`);
149
+ if (typeof requireCi !== 'boolean')
150
+ problems.push('release.requireCi: must be true or false');
151
+ const quality = releaseServices(services, options);
152
+ const audit = auditGate(quality.audit);
153
+ const gates = raw.gates === undefined ? defaultGates(scripts, audit, options.entities === true) : gatesOf(raw.gates, problems);
154
+ if (raw.gates !== undefined && audit && !gates.some((gate) => gate.name === 'audit'))
155
+ gates.push(audit);
156
+ if (raw.gates !== undefined && options.entities === true && !gates.some((gate) => gate.name === DB_DRIFT.name))
157
+ gates.push(DB_DRIFT);
158
+ return problems.length === 0 ? { config: { gates, tagPrefix, defaultBranch, requireCi, services: quality } } : { problems };
159
+ }
149
160
  /* ---- git through the seam */
150
-
151
161
  /** Runs git in the app root; a missing git or (unless allowFail) a non-zero exit is a failure whose message names the first stderr line. */
152
162
  export function git(ctx, args, { allowFail = false } = {}) {
153
- const run = tool(ctx, 'git', args, { cwd: ctx.cwd, env: ctx.env });
154
- if (run.error) throw failure('RELEASE_GIT_MISSING', `cannot run git (${run.error.message})`);
155
- if (run.status !== 0 && !allowFail) throw failure('RELEASE_GIT_FAILED', `git ${args.slice(0, 2).join(' ')}: ${firstLine(run.stderr)}`);
156
- return { code: run.status, stdout: String(run.stdout ?? '').trim(), stderr: String(run.stderr ?? '') };
163
+ const run = tool(ctx, 'git', args, { cwd: ctx.cwd, env: ctx.env });
164
+ if (run.error)
165
+ throw failure('RELEASE_GIT_MISSING', `cannot run git (${run.error.message})`);
166
+ if (run.status !== 0 && !allowFail)
167
+ throw failure('RELEASE_GIT_FAILED', `git ${args.slice(0, 2).join(' ')}: ${firstLine(run.stderr)}`);
168
+ return { code: run.status, stdout: String(run.stdout ?? '').trim(), stderr: String(run.stderr ?? '') };
157
169
  }
158
-
159
170
  /** The directory that holds the L4 records: <git common dir>/starci-release. */
160
171
  export const releaseDir = (ctx) => path.join(path.resolve(ctx.cwd, git(ctx, ['rev-parse', '--git-common-dir']).stdout), 'starci-release');
161
-
162
172
  /** Annotated tags `<prefix><digit>*` that point at HEAD (lightweight tags do not count: the hook ignores them). */
163
173
  export function annotatedOnHead(ctx, prefix) {
164
- const names = lines(git(ctx, ['tag', '--points-at', 'HEAD', '--list', `${prefix}[0-9]*`]).stdout);
165
- return names.filter((name) => git(ctx, ['cat-file', '-t', `refs/tags/${name}`], { allowFail: true }).stdout === 'tag');
174
+ const names = lines(git(ctx, ['tag', '--points-at', 'HEAD', '--list', `${prefix}[0-9]*`]).stdout);
175
+ return names.filter((name) => git(ctx, ['cat-file', '-t', `refs/tags/${name}`], { allowFail: true }).stdout === 'tag');
166
176
  }
167
-
168
177
  /** Every tag on HEAD whose name ends in a version, annotated or not, under any prefix: a release commit carries exactly one. */
169
178
  const versionTagsOnHead = (ctx) => lines(git(ctx, ['tag', '--points-at', 'HEAD']).stdout).filter((name) => /[0-9]+[.][0-9]+[.][0-9]+$/u.test(name));
170
-
171
179
  /** The rewrittenBy predicate of the app's slots: true for a path a dev server writes (hfs slots `rewrittenBy`); without a readable hfs.json, for none. */
172
180
  function rewrittenByDevServer(root) {
173
- let hfs;
174
- try { hfs = openHfs({ repoRoot: root }); } catch { return () => false; }
175
- return (file) => typeof hfs.slotOf(file)?.rewrittenBy === 'string';
181
+ let hfs; // reason: openHfs is the slot machine of the app's hfs.json (runtime/scripts/hfs/slots.mjs)
182
+ try {
183
+ hfs = openHfs({ repoRoot: root });
184
+ }
185
+ catch {
186
+ return () => false;
187
+ }
188
+ return (file) => typeof hfs.slotOf(file)?.rewrittenBy === 'string';
176
189
  }
177
-
178
190
  /**
179
191
  * The paths that make the tree dirty: every changed tracked path and every untracked one, except an untracked file the app's slots declare a dev
180
192
  * server rewrites (`rewrittenBy`, e.g. the AGENTS.md `next dev` writes): that one is known generated output, never a change of the release.
181
193
  */
182
194
  export function dirtyPaths(ctx) {
183
- const rewritten = rewrittenByDevServer(ctx.cwd);
184
- return lines(git(ctx, ['status', '--porcelain', '--untracked-files=all']).stdout)
185
- .filter((line) => !(line.startsWith('?? ') && rewritten(line.slice(3).replace(/^"|"$/gu, ''))));
195
+ const rewritten = rewrittenByDevServer(ctx.cwd);
196
+ return lines(git(ctx, ['status', '--porcelain', '--untracked-files=all']).stdout)
197
+ .filter((line) => !(line.startsWith('?? ') && rewritten(line.slice(3).replace(/^"|"$/gu, ''))));
186
198
  }
187
-
188
199
  /** Tag names that exist locally or on the remote. */
189
200
  function takenTags(ctx, prefix, remote) {
190
- const local = lines(git(ctx, ['tag', '--list', `${prefix}*`]).stdout);
191
- const listed = lines(git(ctx, ['ls-remote', '--tags', remote], { allowFail: true }).stdout);
192
- const remoteNames = listed.map((line) => line.split('refs/tags/')[1]?.replace(/\^\{\}$/u, '')).filter(Boolean);
193
- return new Set([...local, ...remoteNames]);
201
+ const local = lines(git(ctx, ['tag', '--list', `${prefix}*`]).stdout);
202
+ const listed = lines(git(ctx, ['ls-remote', '--tags', remote], { allowFail: true }).stdout);
203
+ const remoteNames = listed.map((line) => line.split('refs/tags/')[1]?.replace(/\^\{\}$/u, '')).filter((name) => Boolean(name));
204
+ return new Set([...local, ...remoteNames]);
194
205
  }
195
-
196
206
  /** The tag this release uses is `<prefix><package version>`; its state is on-head (reused), free (will be created) or taken (exists on another commit). */
197
207
  function chooseTag(ctx, config, { prefix, remote }) {
198
- const tag = `${prefix}${config.version}`;
199
- if (annotatedOnHead(ctx, prefix).includes(tag)) return { tag, state: 'on-head' };
200
- return { tag, state: takenTags(ctx, prefix, remote).has(tag) ? 'taken' : 'free' };
208
+ const tag = `${prefix}${config.version}`;
209
+ if (annotatedOnHead(ctx, prefix).includes(tag))
210
+ return { tag, state: 'on-head' };
211
+ return { tag, state: takenTags(ctx, prefix, remote).has(tag) ? 'taken' : 'free' };
201
212
  }
202
-
203
213
  /* ---- gate results */
204
-
205
214
  const sha256 = (file) => createHash('sha256').update(fs.readFileSync(file)).digest('hex');
206
-
207
215
  const lineAfter = (text, label) => {
208
- const found = text.split('\n').find((line) => line.startsWith(label));
209
- return found === undefined ? null : found.slice(label.length).trim();
216
+ const found = text.split('\n').find((line) => line.startsWith(label));
217
+ return found === undefined ? null : found.slice(label.length).trim();
210
218
  };
211
-
212
219
  /** The jest summary lines of a log: { suites, failedSuites, tests, failed, passed } or null when jest printed none. */
213
220
  function jestSummary(text) {
214
- const suites = lineAfter(text, 'Test Suites:');
215
- const tests = lineAfter(text, 'Tests:');
216
- if (suites === null || tests === null) return null;
217
- const count = (line, word) => Number(new RegExp(String.raw`(\d+) ${word}`, 'u').exec(line)?.[1] ?? 0);
218
- return {
219
- suites: count(suites, 'total'), failedSuites: count(suites, 'failed'),
220
- tests: count(tests, 'total'), failed: count(tests, 'failed'), passed: count(tests, 'passed'),
221
- };
222
- }
223
-
221
+ const suites = lineAfter(text, 'Test Suites:');
222
+ const tests = lineAfter(text, 'Tests:');
223
+ if (suites === null || tests === null)
224
+ return null;
225
+ const count = (line, word) => Number(new RegExp(String.raw `(\d+) ${word}`, 'u').exec(line)?.[1] ?? 0);
226
+ return {
227
+ suites: count(suites, 'total'), failedSuites: count(suites, 'failed'),
228
+ tests: count(tests, 'total'), failed: count(tests, 'failed'), passed: count(tests, 'passed'),
229
+ };
230
+ }
224
231
  /** Judges a jest-style gate from its log: green needs suites that all passed, every test passed and no coverage threshold miss. */
225
232
  function judgeJest(text) {
226
- const summary = jestSummary(text);
227
- const misses = (text.match(THRESHOLD_MISS) ?? []).length;
228
- if (!summary) return { pass: false, detail: 'no jest summary in the log', summary: null, misses };
229
- const pass = summary.suites > 0 && summary.failedSuites === 0 && summary.failed === 0 && summary.passed === summary.tests && misses === 0;
230
- const detail = `suites ${summary.suites - summary.failedSuites}/${summary.suites}, tests ${summary.passed}/${summary.tests}, coverage-threshold misses ${misses}`;
231
- return { pass, detail, summary, misses };
232
- }
233
-
233
+ const summary = jestSummary(text);
234
+ const misses = (text.match(THRESHOLD_MISS) ?? []).length;
235
+ if (!summary)
236
+ return { pass: false, detail: 'no jest summary in the log', summary: null, misses };
237
+ const pass = summary.suites > 0 && summary.failedSuites === 0 && summary.failed === 0 && summary.passed === summary.tests && misses === 0;
238
+ const detail = `suites ${summary.suites - summary.failedSuites}/${summary.suites}, tests ${summary.passed}/${summary.tests}, coverage-threshold misses ${misses}`;
239
+ return { pass, detail, summary, misses };
240
+ }
234
241
  /** [command, args] to start an argv; on Windows npm and npx are .cmd files, so they start through cmd.exe (words are validated, never a shell string). */
235
242
  export function launch(argv, platform) {
236
- if (platform === 'win32' && WRAPPED.has(argv[0])) return ['cmd.exe', ['/d', '/s', '/c', ...argv]];
237
- return [argv[0], argv.slice(1)];
243
+ if (platform === 'win32' && WRAPPED.has(argv[0]))
244
+ return ['cmd.exe', ['/d', '/s', '/c', ...argv]];
245
+ return [argv[0], argv.slice(1)];
238
246
  }
239
-
240
247
  /** Sonar availability is public and bounded; HTTP uses the existing injected fetch seam. An unreachable host is a red row: Sonar is required. */
241
248
  async function sonarAvailability(ctx, gate) {
242
- const sonar = gate.provider;
243
- if (!sonar) return null;
244
- let up = false;
245
- try {
246
- const response = await ctx.fetch(sonar.host.replace(/\/$/u, '') + '/api/system/status', { signal: AbortSignal.timeout(10000) });
247
- up = response.ok && (await response.json()).status === 'UP';
248
- } catch { up = false; }
249
- if (up) return null;
250
- return { pass: false, detail: `${SONAR_UNREACHABLE}: ${sonar.host} did not report UP within ten seconds` };
251
- }
252
-
249
+ const sonar = gate.provider;
250
+ if (!sonar)
251
+ return null;
252
+ let up = false;
253
+ try {
254
+ const response = await ctx.fetch(sonar.host.replace(/\/$/u, '') + '/api/system/status', { signal: AbortSignal.timeout(10000) });
255
+ up = response.ok && (await response.json()).status === 'UP';
256
+ }
257
+ catch {
258
+ up = false;
259
+ }
260
+ if (up)
261
+ return null;
262
+ return { pass: false, detail: `${SONAR_UNREACHABLE}: ${sonar.host} did not report UP within ten seconds` };
263
+ }
253
264
  /** An unreachable Sonar host stays a red row with a real log and no scan invocation. */
254
265
  export async function runAvailableGate(ctx, gate, options) {
255
- const availability = await sonarAvailability(ctx, gate);
256
- const log = path.join(options.dir, `${gate.name}.log`);
257
- if (!availability) {
258
- if (!gate.provider) return runGate(ctx, gate, options);
259
- // The scanner imports the app's declared external issues report: produce it first with the app's own lint, as the managed CI does.
260
- const started = ctx.now();
261
- const lint = produceLintReports(ctx, { launch, platform: options.platform, env: withoutCredentials(ctx.env, options.credentialNames) });
262
- if (lint.pass) return judgeQualityGate(ctx, gate, runGate(ctx, gate, { ...options, preface: lint.text }));
263
- fs.writeFileSync(log, lint.text);
264
- return { name: gate.name, command: gate.command.join(' '), pass: false, detail: 'lint report failed (see log)', seconds: Math.round((ctx.now() - started) / 1000),
265
- summary: null, log: path.resolve(log), logSha256: sha256(log), env: Object.keys(gate.env) };
266
- }
267
- fs.writeFileSync(log, availability.detail + '\n');
268
- return { name: gate.name, command: gate.command.join(' '), ...availability, seconds: 0,
269
- summary: null, log: path.resolve(log), logSha256: sha256(log), env: Object.keys(gate.env) };
270
- }
271
-
266
+ const availability = await sonarAvailability(ctx, gate);
267
+ const log = path.join(options.dir, `${gate.name}.log`);
268
+ if (!availability) {
269
+ if (!gate.provider)
270
+ return runGate(ctx, gate, options);
271
+ // The scanner imports the app's declared external issues report: produce it first with the app's own lint, as the managed CI does.
272
+ const started = ctx.now();
273
+ const lint = produceLintReports(ctx, { launch, platform: options.platform, env: withoutCredentials(ctx.env, options.credentialNames) });
274
+ if (lint.pass)
275
+ return judgeQualityGate(ctx, gate, runGate(ctx, gate, { ...options, preface: lint.text }));
276
+ fs.writeFileSync(log, lint.text);
277
+ return { name: gate.name, command: gate.command.join(' '), pass: false, detail: 'lint report failed (see log)', seconds: Math.round((ctx.now() - started) / 1000),
278
+ summary: null, log: path.resolve(log), logSha256: sha256(log), env: Object.keys(gate.env) };
279
+ }
280
+ fs.writeFileSync(log, availability.detail + '\n');
281
+ return { name: gate.name, command: gate.command.join(' '), ...availability, seconds: 0,
282
+ summary: null, log: path.resolve(log), logSha256: sha256(log), env: Object.keys(gate.env) };
283
+ }
272
284
  /**
273
285
  * A scanner that exited 0 only uploaded its report: the row passes when the server's quality gate of that analysis is OK
274
286
  * (sonar-quality-gate.mjs). The verdict replaces the row's detail and is appended to its log; the row's time includes the wait.
275
287
  */
276
288
  async function judgeQualityGate(ctx, gate, row) {
277
- if (!row.pass) return row;
278
- const started = ctx.now();
279
- const verdict = await sonarQualityGate(ctx, { cwd: ctx.cwd, host: gate.provider.host, token: gate.env.SONAR_TOKEN });
280
- const failed = (verdict.conditions ?? []).map((line) => ` failed: ${line}\n`).join('');
281
- fs.appendFileSync(row.log, `\nquality gate: ${verdict.detail}\n${failed}`);
282
- return { ...row, pass: verdict.pass, detail: verdict.detail, seconds: row.seconds + Math.round((ctx.now() - started) / 1000), logSha256: sha256(row.log) };
283
- }
284
-
289
+ if (!row.pass)
290
+ return row;
291
+ const started = ctx.now();
292
+ const verdict = await sonarQualityGate(ctx, { cwd: ctx.cwd, host: gate.provider.host, token: gate.env.SONAR_TOKEN });
293
+ const failed = (verdict.conditions ?? []).map((line) => ` failed: ${line}\n`).join('');
294
+ fs.appendFileSync(row.log, `\nquality gate: ${verdict.detail}\n${failed}`);
295
+ return { ...row, pass: verdict.pass, detail: verdict.detail, seconds: row.seconds + Math.round((ctx.now() - started) / 1000), logSha256: sha256(row.log) };
296
+ }
285
297
  export const withoutCredentials = (values, credentialNames) => {
286
- const selected = new Set(credentialNames);
287
- return Object.fromEntries(Object.entries(values ?? {}).filter(([key]) => !selected.has(key.toUpperCase())));
298
+ const selected = new Set(credentialNames);
299
+ return Object.fromEntries(Object.entries(values ?? {}).filter(([key]) => !selected.has(key.toUpperCase())));
288
300
  };
289
-
290
301
  export function runGate(ctx, gate, { dir, platform, credentialNames, preface = '' }) {
291
- const log = path.join(dir, `${gate.name}.log`);
292
- const started = ctx.now();
293
- const [command, args] = launch(gate.command, platform);
294
- // The native scanner alone consumes Sonar credentials; ordinary gates cannot inherit or reintroduce them.
295
- const env = { ...ctx.env, ...(gate.provider ? gate.env : withoutCredentials(gate.env, credentialNames)) };
296
- const run = tool(ctx, command, args, { cwd: ctx.cwd, env });
297
- const output = `${run.stdout ?? ''}${run.stderr ?? ''}`;
298
- const text = gate.name === 'sonar' && gate.env.SONAR_TOKEN ? output.replaceAll(gate.env.SONAR_TOKEN, '[REDACTED]') : output;
299
- fs.writeFileSync(log, preface + text);
300
- const verdict = judgeVerdict(run, gate, text);
301
- if (gate.name === 'sonar' && gate.env.SONAR_TOKEN) verdict.detail = verdict.detail.replaceAll(gate.env.SONAR_TOKEN, '[REDACTED]');
302
- const seconds = Math.round((ctx.now() - started) / 1000);
303
- return {
304
- name: gate.name, command: gate.command.join(' '), pass: verdict.pass, detail: verdict.detail, seconds,
305
- summary: verdict.summary ?? null, log: path.resolve(log), logSha256: sha256(log), env: Object.keys(gate.env),
306
- };
307
- }
308
-
302
+ const log = path.join(dir, `${gate.name}.log`);
303
+ const started = ctx.now();
304
+ const [command, args] = launch(gate.command, platform);
305
+ // The native scanner alone consumes Sonar credentials; ordinary gates cannot inherit or reintroduce them.
306
+ const env = { ...ctx.env, ...(gate.provider ? gate.env : withoutCredentials(gate.env, credentialNames)) };
307
+ const run = tool(ctx, command, args, { cwd: ctx.cwd, env });
308
+ const output = `${run.stdout ?? ''}${run.stderr ?? ''}`;
309
+ const text = gate.name === 'sonar' && gate.env.SONAR_TOKEN ? output.replaceAll(gate.env.SONAR_TOKEN, '[REDACTED]') : output;
310
+ fs.writeFileSync(log, preface + text);
311
+ const verdict = judgeVerdict(run, gate, text);
312
+ if (gate.name === 'sonar' && gate.env.SONAR_TOKEN)
313
+ verdict.detail = verdict.detail.replaceAll(gate.env.SONAR_TOKEN, '[REDACTED]');
314
+ const seconds = Math.round((ctx.now() - started) / 1000);
315
+ return {
316
+ name: gate.name, command: gate.command.join(' '), pass: verdict.pass, detail: verdict.detail, seconds,
317
+ summary: verdict.summary ?? null, log: path.resolve(log), logSha256: sha256(log), env: Object.keys(gate.env),
318
+ };
319
+ }
309
320
  function judgeVerdict(run, gate, text) {
310
- if (run.error) return { pass: false, detail: `cannot run (${run.error.message})` };
311
- if (run.status !== 0) return { pass: false, detail: `exit ${run.status}` };
312
- if (gate.summary === 'jest') return judgeJest(text);
313
- return { pass: true, detail: 'exit 0' };
321
+ if (run.error)
322
+ return { pass: false, detail: `cannot run (${run.error.message})` };
323
+ if (run.status !== 0)
324
+ return { pass: false, detail: `exit ${run.status}` };
325
+ if (gate.summary === 'jest')
326
+ return judgeJest(text);
327
+ return { pass: true, detail: 'exit 0' };
314
328
  }
315
-
316
329
  /* ---- the gate */
317
-
318
330
  function sourceProblem(ctx, source, head) {
319
- if (source === 'HEAD') return null;
320
- if (!refName(source)) return `--source ${source} is not a ref name`;
321
- const resolved = git(ctx, ['rev-parse', '--verify', `${source}^{commit}`], { allowFail: true });
322
- if (resolved.code !== 0) return `cannot resolve --source ${source}`;
323
- if (resolved.stdout !== head) return `--source ${source} is ${resolved.stdout.slice(0, 10)} but HEAD is ${head.slice(0, 10)}: the hook and the L4 record are about HEAD; check the candidate out first`;
324
- return null;
325
- }
326
-
331
+ if (source === 'HEAD')
332
+ return null;
333
+ if (!refName(source))
334
+ return `--sha ${source} is not a ref name`;
335
+ const resolved = git(ctx, ['rev-parse', '--verify', `${source}^{commit}`], { allowFail: true });
336
+ if (resolved.code !== 0)
337
+ return `cannot resolve --sha ${source}`;
338
+ if (resolved.stdout !== head)
339
+ return `--sha ${source} is ${resolved.stdout.slice(0, 10)} but HEAD is ${head.slice(0, 10)}: the hook and the L4 record are about HEAD; check the candidate out first`;
340
+ return null;
341
+ }
327
342
  function tagLine({ tag, state }) {
328
- if (state === 'on-head') return `tag ${tag} (annotated, already on HEAD)`;
329
- if (state === 'taken') return `tag ${tag} (TAKEN by another commit)`;
330
- return `tag ${tag} (free: will be created, annotated)`;
343
+ if (state === 'on-head')
344
+ return `tag ${tag} (annotated, already on HEAD)`;
345
+ if (state === 'taken')
346
+ return `tag ${tag} (TAKEN by another commit)`;
347
+ return `tag ${tag} (free: will be created, annotated)`;
331
348
  }
332
-
333
349
  /** Everything that can be known without running a gate: the facts, the red preconditions and the lines that describe them. */
334
350
  export function inspect(ctx, config, options) {
335
- const head = git(ctx, ['rev-parse', 'HEAD']).stdout;
336
- const branch = git(ctx, ['rev-parse', '--abbrev-ref', 'HEAD'], { allowFail: true }).stdout;
337
- const out = [`checkout ${ctx.cwd}`, `HEAD ${head} (${branch})`];
338
- const red = [];
339
- const problem = sourceProblem(ctx, options.source ?? 'HEAD', head);
340
- if (problem) red.push(problem);
341
- const dirty = dirtyPaths(ctx);
342
- if (dirty.length > 0) red.push(`working tree is not clean (${dirty.length} path(s), first: ${dirty[0].slice(0, 100)}): the record would vouch for files that are not in HEAD`);
343
- else out.push('worktree clean');
344
- const prefix = options.tagPrefix ?? config.tagPrefix;
345
- if (!PREFIX.test(prefix)) throw refusal('RELEASE_USAGE', `--tag-prefix must match ${PREFIX}`);
346
- const chosen = chooseTag(ctx, config, { prefix, remote: 'origin' });
347
- if (chosen.state === 'taken') red.push(`tag ${chosen.tag} already exists on another commit (local or remote)`);
348
- const stray = versionTagsOnHead(ctx).filter((name) => name !== chosen.tag);
349
- if (stray.length > 0) red.push(`HEAD already carries the release tag ${stray[0]} but package.json version ${config.version} gives ${chosen.tag}: a release commit carries exactly one tag, so set the version to match the tag or release a new commit`);
350
- out.push(tagLine(chosen));
351
- return { head, chosen, red, out };
352
- }
353
-
351
+ const head = git(ctx, ['rev-parse', 'HEAD']).stdout;
352
+ const branch = git(ctx, ['rev-parse', '--abbrev-ref', 'HEAD'], { allowFail: true }).stdout;
353
+ const out = [`checkout ${ctx.cwd}`, `HEAD ${head} (${branch})`];
354
+ const red = [];
355
+ const problem = sourceProblem(ctx, (options.source ?? 'HEAD'), head);
356
+ if (problem)
357
+ red.push(problem);
358
+ const dirty = dirtyPaths(ctx);
359
+ if (dirty.length > 0)
360
+ red.push(`working tree is not clean (${dirty.length} path(s), first: ${dirty[0].slice(0, 100)}): the record would vouch for files that are not in HEAD`);
361
+ else
362
+ out.push('worktree clean');
363
+ const prefix = (options.tagPrefix ?? config.tagPrefix);
364
+ if (!PREFIX.test(prefix))
365
+ throw refusal('RELEASE_USAGE', `--tag-prefix must match ${PREFIX}`);
366
+ const chosen = chooseTag(ctx, config, { prefix, remote: 'origin' });
367
+ if (chosen.state === 'taken')
368
+ red.push(`tag ${chosen.tag} already exists on another commit (local or remote)`);
369
+ const stray = versionTagsOnHead(ctx).filter((name) => name !== chosen.tag);
370
+ if (stray.length > 0)
371
+ red.push(`HEAD already carries the release tag ${stray[0]} but package.json version ${config.version} gives ${chosen.tag}: a release commit carries exactly one tag, so set the version to match the tag or release a new commit`);
372
+ out.push(tagLine(chosen));
373
+ return { head, chosen, red, out };
374
+ }
354
375
  function planLines(config, facts, dir, recordPath) {
355
- const out = [`L4 record ${recordPath}`, `logs ${dir}`, '', 'gates (every gate must pass, in this order):'];
356
- for (const gate of config.gates) {
357
- const summary = gate.summary ? ` (summary: ${gate.summary})` : '';
358
- const teardown = gate.teardownOf ? ` (teardown of ${gate.teardownOf}: runs whenever it ran)` : '';
359
- out.push(` ${gate.name.padEnd(17)} ${gate.command.join(' ')}${summary}${teardown}`);
360
- }
361
- out.push(`then: write ${path.basename(recordPath)} and \`git tag -a ${facts.chosen.tag}\` on ${facts.head.slice(0, 10)}; push it with \`starci app release push\`.`);
362
- return out;
363
- }
364
-
376
+ const out = [`L4 record ${recordPath}`, `logs ${dir}`, '', 'gates (every gate must pass, in this order):'];
377
+ for (const gate of config.gates) {
378
+ const summary = gate.summary ? ` (summary: ${gate.summary})` : '';
379
+ const teardown = gate.teardownOf ? ` (teardown of ${gate.teardownOf}: runs whenever it ran)` : '';
380
+ out.push(` ${gate.name.padEnd(17)} ${gate.command.join(' ')}${summary}${teardown}`);
381
+ }
382
+ out.push(`then: write ${path.basename(recordPath)} and \`git tag -a ${facts.chosen.tag}\` on ${facts.head.slice(0, 10)}; push it with \`starci app release push\`.`);
383
+ return out;
384
+ }
365
385
  export function assertUnmoved(ctx, head) {
366
- const now = git(ctx, ['rev-parse', 'HEAD']).stdout;
367
- if (now !== head) throw failure('RELEASE_HEAD_MOVED', `HEAD moved during the gates (${head.slice(0, 10)} -> ${now.slice(0, 10)}). No record.`);
368
- const dirty = dirtyPaths(ctx);
369
- if (dirty.length > 0) throw failure('RELEASE_TREE_DIRTY', `the gates left ${dirty.length} changed or untracked path(s) (first: ${dirty[0].slice(0, 100)}): generated files differ from HEAD. Commit or ignore them properly, then rerun. No record.`);
386
+ const now = git(ctx, ['rev-parse', 'HEAD']).stdout;
387
+ if (now !== head)
388
+ throw failure('RELEASE_HEAD_MOVED', `HEAD moved during the gates (${head.slice(0, 10)} -> ${now.slice(0, 10)}). No record.`);
389
+ const dirty = dirtyPaths(ctx);
390
+ if (dirty.length > 0)
391
+ throw failure('RELEASE_TREE_DIRTY', `the gates left ${dirty.length} changed or untracked path(s) (first: ${dirty[0].slice(0, 100)}): generated files differ from HEAD. Commit or ignore them properly, then rerun. No record.`);
370
392
  }
371
-
372
393
  function writeRecord(ctx, { head, tag, results, recordPath, requireCi, promotedFrom = null }) {
373
- const record = {
374
- schema: 'starci-app-l4-record/1', head, tag, createdAt: new Date(ctx.now()).toISOString(), producedBy: 'starci app release gate',
375
- note: 'Every gate passed on a clean HEAD; every entry links its log and sha256.',
376
- ci: requireCi === true ? { required: true, note: 'starci app release push waits for the candidate CI of this sha (release.requireCi=true)' } : { required: false, note: CI_NOT_REQUIRED },
377
- ...(promotedFrom ? { promotedFrom } : {}),
378
- gates: results,
379
- };
380
- fs.mkdirSync(path.dirname(recordPath), { recursive: true });
381
- fs.writeFileSync(recordPath, `${JSON.stringify(record, null, 2)}\n`);
382
- }
383
-
394
+ const record = {
395
+ schema: 'starci-app-l4-record/1', head, tag, createdAt: new Date(ctx.now()).toISOString(), producedBy: 'starci app release gate',
396
+ note: 'Every gate passed on a clean HEAD; every entry links its log and sha256.',
397
+ ci: requireCi === true ? { required: true, note: 'starci app release push waits for the candidate CI of this sha (release.requireCi=true)' } : { required: false, note: CI_NOT_REQUIRED },
398
+ ...(promotedFrom ? { promotedFrom } : {}),
399
+ gates: results,
400
+ };
401
+ fs.mkdirSync(path.dirname(recordPath), { recursive: true });
402
+ fs.writeFileSync(recordPath, `${JSON.stringify(record, null, 2)}\n`);
403
+ }
384
404
  /**
385
405
  * Gates run sequentially because each failure prevents subsequent commands and record creation. A teardown row (`teardownOf`) is the exception: it runs
386
406
  * whenever the row it tears down ran, red or green, so a red row never leaves a started service behind; its own verdict counts like any row's.
387
407
  */
388
408
  async function runAll(ctx, config, options) {
389
- fs.mkdirSync(options.dir, { recursive: true });
390
- return config.gates.reduce(async (pending, gate) => {
391
- const results = await pending;
392
- if (results.some((result) => !result.pass) && !(gate.teardownOf && results.some((result) => result.name === gate.teardownOf))) return results;
393
- const result = await runAvailableGate(ctx, gate, options);
394
- recordRow(options.common, options.head, result);
395
- return [...results, result];
396
- }, Promise.resolve([]));
397
- }
398
-
409
+ fs.mkdirSync(options.dir, { recursive: true });
410
+ return config.gates.reduce(async (pending, gate) => {
411
+ const results = await pending;
412
+ if (results.some((result) => !result.pass) && !(gate.teardownOf && results.some((result) => result.name === gate.teardownOf)))
413
+ return results;
414
+ const result = await runAvailableGate(ctx, gate, options);
415
+ recordRow(options.common, options.head, result);
416
+ return [...results, result];
417
+ }, Promise.resolve([]));
418
+ }
399
419
  export function summaryOf(result) {
400
- return `${result.pass ? 'PASS' : 'FAIL'} ${result.name} (${result.detail}, ${result.seconds}s) log ${result.log}`;
420
+ return `${result.pass ? 'PASS' : 'FAIL'} ${result.name} (${result.detail}, ${result.seconds}s) log ${result.log}`;
401
421
  }
402
-
403
422
  /**
404
423
  * The urgent release a back-fill judges: `tag` must name HEAD (the back-fill runs on the very commit that shipped, never a re-release) and HEAD must
405
424
  * carry an urgent record of that tag. Returns the record; refuses otherwise.
406
425
  */
407
426
  function backfillTarget(ctx, common, tag, head) {
408
- if (!refName(tag)) throw refusal('RELEASE_USAGE', `--backfill ${tag} is not a tag name`);
409
- const resolved = git(ctx, ['rev-parse', '--verify', '--quiet', `refs/tags/${tag}^{commit}`], { allowFail: true });
410
- if (resolved.code !== 0 || resolved.stdout === '') throw refusal('RELEASE_BACKFILL_TAG_UNKNOWN', `no tag ${tag} in this repository`);
411
- if (resolved.stdout !== head) throw refusal('RELEASE_BACKFILL_NOT_ON_TAG', `${tag} is ${resolved.stdout.slice(0, 10)} but HEAD is ${head.slice(0, 10)}: run the back-fill in a clean checkout of the tag (git worktree add --detach <dir> ${tag}), so the full gate judges exactly what shipped`);
412
- const urgent = readUrgent(common, head);
413
- if (!urgent || urgent.tag !== tag) throw refusal('RELEASE_BACKFILL_NOT_URGENT', `${tag} has no urgent record on ${head.slice(0, 10)}: only a release pushed with release push --urgent is back-filled`);
414
- return urgent;
415
- }
416
-
427
+ if (!refName(tag))
428
+ throw refusal('RELEASE_USAGE', `--backfill ${tag} is not a tag name`);
429
+ const resolved = git(ctx, ['rev-parse', '--verify', '--quiet', `refs/tags/${tag}^{commit}`], { allowFail: true });
430
+ if (resolved.code !== 0 || resolved.stdout === '')
431
+ throw refusal('RELEASE_BACKFILL_TAG_UNKNOWN', `no tag ${tag} in this repository`);
432
+ if (resolved.stdout !== head)
433
+ throw refusal('RELEASE_BACKFILL_NOT_ON_TAG', `${tag} is ${resolved.stdout.slice(0, 10)} but HEAD is ${head.slice(0, 10)}: run the back-fill in a clean checkout of the tag (git worktree add --detach <dir> ${tag}), so the full gate judges exactly what shipped`);
434
+ const urgent = readUrgent(common, head);
435
+ if (!urgent || urgent.tag !== tag)
436
+ throw refusal('RELEASE_BACKFILL_NOT_URGENT', `${tag} has no urgent record on ${head.slice(0, 10)}: only a release pushed with release push --urgent is back-filled`);
437
+ return urgent;
438
+ }
417
439
  /** A red back-fill: the urgent record keeps the verdict and the fix ticket (kind verify) the harness opened; nothing on the remote or on prod changes. */
418
440
  function backfillRed(ctx, { common, urgent, failed, openTicket }) {
419
- const names = failed.map((item) => item.name);
420
- const title = `RELEASE_BACKFILL_RED: the back-fill of urgent release ${urgent.tag} (${urgent.head.slice(0, 12)}) is red at ${names.join(', ')}`;
421
- const tail = failed.map((item) => `${item.name}: ${item.detail} (log ${item.log})`).join('\n');
422
- const ticket = typeof openTicket === 'function' ? openTicket({ title, tail, code: 'RELEASE_BACKFILL_RED', tag: urgent.tag, head: urgent.head }) : null;
423
- writeUrgent(common, { ...urgent, backfill: { state: 'red', at: new Date(ctx.now()).toISOString(), failed: names, ticket: ticket ?? null } });
424
- const said = ticket
425
- ? `back-fill red: fix ticket ${ticket} opened (kind verify); ${urgent.tag} stays an urgent release and nothing on the remote or on prod changed`
426
- : `back-fill red: no ticket queue in this run (run it through the starci CLI to open one); ${urgent.tag} stays an urgent release and nothing on the remote or on prod changed`;
427
- return { said, ticket: ticket ?? null };
428
- }
429
-
441
+ const names = failed.map((item) => item.name);
442
+ const title = `RELEASE_BACKFILL_RED: the back-fill of urgent release ${urgent.tag} (${urgent.head.slice(0, 12)}) is red at ${names.join(', ')}`;
443
+ const tail = failed.map((item) => `${item.name}: ${item.detail} (log ${item.log})`).join('\n');
444
+ const ticket = typeof openTicket === 'function' ? openTicket({ title, tail, code: 'RELEASE_BACKFILL_RED', tag: urgent.tag, head: urgent.head }) : null;
445
+ writeUrgent(common, { ...urgent, backfill: { state: 'red', at: new Date(ctx.now()).toISOString(), failed: names, ticket: ticket ?? null } });
446
+ const said = ticket
447
+ ? `back-fill red: fix ticket ${ticket} opened (kind verify); ${urgent.tag} stays an urgent release and nothing on the remote or on prod changed`
448
+ : `back-fill red: no ticket queue in this run (run it through the starci CLI to open one); ${urgent.tag} stays an urgent release and nothing on the remote or on prod changed`;
449
+ return { said, ticket: ticket ?? null };
450
+ }
430
451
  /**
431
452
  * `starci app release gate`: dry run prints the preconditions, the gate list, the head and the tag; --execute runs every gate and, only if required gates pass,
432
- * writes the L4 record and creates the annotated tag. options: { execute, sonar, source, tagPrefix, platform, backfill, openTicket }.
453
+ * writes the L4 record and creates the annotated tag. options: { execute, source (the --sha ref), tagPrefix, platform, backfill, openTicket }.
433
454
  * With `backfill` (a tag pushed by `release push --urgent`, checked out at HEAD) the same full gate judges that commit: green writes its L4 record
434
455
  * (promotedFrom the urgent record) and marks the urgent record promoted, with no new tag and no push; red opens a fix ticket through `openTicket`.
435
456
  */
436
457
  export async function releaseGate(ctx, config, options = {}) {
437
- // Sonar is a row of the managed CI, so it is a row of the local gate whenever the app declares it (and when --sonar asks for it); a missing token is a refusal, never a skip.
438
- if (options.sonar || config.services?.sonar) config = { ...config, gates: [...config.gates.filter((gate) => gate.name !== 'sonar'), sonarGate(config.services, ctx.env)] };
439
- const credentialNames = config.gates.find(gate => gate.provider)?.credentialNames ?? ['SONAR_TOKEN', config.services?.sonar?.token].filter(Boolean);
440
- ctx = Object.create(ctx, {env: {value: withoutCredentials(ctx.env, credentialNames)}});
441
- // The CI verdict of a release is the candidate run of its own sha, judged by `starci app release push` (candidate-ci.mjs, OWNER RULING candidate-ci 2026-10-18):
442
- // the gate no longer refuses over the latest default-branch run.
443
- const facts = inspect(ctx, config, options);
444
- const common = releaseDir(ctx);
445
- const urgent = options.backfill === undefined ? null : backfillTarget(ctx, common, options.backfill, facts.head);
446
- const recordPath = l4Path(common, facts.head);
447
- const dir = path.join(common, facts.head.slice(0, 12));
448
- const plan = [...facts.out, ...planLines(config, facts, dir, recordPath)];
449
- if (urgent) plan.push(`back-fill urgent release ${urgent.tag} (${URGENT_RULING}): green promotes it to this L4 record with no new tag and no push; red opens a fix ticket and changes nothing on prod`);
450
- const base = { head: facts.head, tag: facts.chosen.tag, record: recordPath, gates: config.gates.map((gate) => gate.name), ...(urgent ? { backfill: urgent.tag } : {}) };
451
- if (urgent?.backfill?.state === 'promoted') return { ok: true, lines: [...plan, `back-fill already promoted ${urgent.tag} to ${urgent.backfill.l4}. Nothing to do.`], data: { ...base, red: [], executed: false, promoted: true } };
452
- if (facts.red.length > 0) return { ok: false, lines: [...plan, ...facts.red.map((item) => `RED: ${item}`), 'nothing was run.'], data: { ...base, red: facts.red, executed: false } };
453
- if (options.execute !== true) return { ok: true, lines: [...plan, '', 'dry run: no gate was run, nothing written. preconditions OK.'], data: { ...base, red: [], executed: false } };
454
- const results = await runAll(ctx, config, { dir, common, head: facts.head, platform: options.platform ?? process.platform, credentialNames });
455
- const report = results.map(summaryOf);
456
- const failed = results.filter((result) => !result.pass);
457
- if (failed.length > 0 && urgent) {
458
- const { said, ticket } = backfillRed(ctx, { common, urgent, failed, openTicket: options.openTicket });
459
- return { ok: false, lines: [...plan, ...report, `gate(s) red: ${failed.map((item) => item.name).join(', ')}. No L4 record.`, said], data: { ...base, executed: true, results, promoted: false, ticket } };
460
- }
461
- if (failed.length > 0) return { ok: false, lines: [...plan, ...report, `gate(s) red: ${failed.map((item) => item.name).join(', ')}. No L4 record, no tag.`], data: { ...base, executed: true, results } };
462
- assertUnmoved(ctx, facts.head);
463
- writeRecord(ctx, { head: facts.head, tag: facts.chosen.tag, results, recordPath, requireCi: config.requireCi, promotedFrom: urgent ? { record: `${facts.head}.urgent.json`, reason: urgent.reason, role: urgent.role, at: urgent.createdAt } : null });
464
- if (urgent) {
465
- writeUrgent(common, { ...urgent, backfill: { state: 'promoted', at: new Date(ctx.now()).toISOString(), l4: recordPath } });
466
- return { ok: true, lines: [...plan, ...report, `L4 record written: ${recordPath}`, `back-fill green: urgent release ${urgent.tag} is promoted to a normal L4 release (no re-release, no push)`], data: { ...base, executed: true, results, promoted: true } };
467
- }
468
- const created = facts.chosen.state !== 'on-head';
469
- if (created) git(ctx, ['tag', '-a', facts.chosen.tag, '-m', `release ${facts.chosen.tag}: required gates passed on ${facts.head.slice(0, 12)} (L4 record ${path.basename(recordPath)})`, facts.head]);
470
- const tagged = created ? `annotated tag ${facts.chosen.tag} created on ${facts.head.slice(0, 10)}` : `annotated tag ${facts.chosen.tag} already on ${facts.head.slice(0, 10)}`;
471
- return { ok: true, lines: [...plan, ...report, `L4 record written: ${recordPath}`, tagged], data: { ...base, executed: true, results, tagCreated: created } };
458
+ // Sonar is a row of the managed CI, so it is a row of the local gate whenever the app declares services.sonar; a missing token is a refusal, never a skip.
459
+ if (config.services?.sonar)
460
+ config = { ...config, gates: [...config.gates.filter((gate) => gate.name !== 'sonar'), sonarGate(config.services, ctx.env)] };
461
+ const credentialNames = config.gates.find(gate => gate.provider)?.credentialNames ?? ['SONAR_TOKEN', config.services?.sonar?.token].filter(Boolean);
462
+ ctx = Object.create(ctx, { env: { value: withoutCredentials(ctx.env, credentialNames) } });
463
+ // The CI verdict of a release is the candidate run of its own sha, judged by `starci app release push` (candidate-ci.mjs, OWNER RULING candidate-ci 2026-10-18):
464
+ // the gate no longer refuses over the latest default-branch run.
465
+ const facts = inspect(ctx, config, options);
466
+ const common = releaseDir(ctx);
467
+ const urgent = options.backfill === undefined ? null : backfillTarget(ctx, common, options.backfill, facts.head);
468
+ const recordPath = l4Path(common, facts.head);
469
+ const dir = path.join(common, facts.head.slice(0, 12));
470
+ const plan = [...facts.out, ...planLines(config, facts, dir, recordPath)];
471
+ if (urgent)
472
+ plan.push(`back-fill urgent release ${urgent.tag} (${URGENT_RULING}): green promotes it to this L4 record with no new tag and no push; red opens a fix ticket and changes nothing on prod`);
473
+ const base = { head: facts.head, tag: facts.chosen.tag, record: recordPath, gates: config.gates.map((gate) => gate.name), ...(urgent ? { backfill: urgent.tag } : {}) };
474
+ if (urgent?.backfill?.state === 'promoted')
475
+ return { ok: true, lines: [...plan, `back-fill already promoted ${urgent.tag} to ${urgent.backfill.l4}. Nothing to do.`], data: { ...base, red: [], executed: false, promoted: true } };
476
+ if (facts.red.length > 0)
477
+ return { ok: false, lines: [...plan, ...facts.red.map((item) => `RED: ${item}`), 'nothing was run.'], data: { ...base, red: facts.red, executed: false } };
478
+ if (options.execute !== true)
479
+ return { ok: true, lines: [...plan, '', 'dry run: no gate was run, nothing written. preconditions OK.'], data: { ...base, red: [], executed: false } };
480
+ const results = await runAll(ctx, config, { dir, common, head: facts.head, platform: options.platform ?? process.platform, credentialNames });
481
+ const report = results.map(summaryOf);
482
+ const failed = results.filter((result) => !result.pass);
483
+ if (failed.length > 0 && urgent) {
484
+ const { said, ticket } = backfillRed(ctx, { common, urgent, failed, openTicket: options.openTicket });
485
+ return { ok: false, lines: [...plan, ...report, `gate(s) red: ${failed.map((item) => item.name).join(', ')}. No L4 record.`, said], data: { ...base, executed: true, results, promoted: false, ticket } };
486
+ }
487
+ if (failed.length > 0)
488
+ return { ok: false, lines: [...plan, ...report, `gate(s) red: ${failed.map((item) => item.name).join(', ')}. No L4 record, no tag.`], data: { ...base, executed: true, results } };
489
+ assertUnmoved(ctx, facts.head);
490
+ writeRecord(ctx, { head: facts.head, tag: facts.chosen.tag, results, recordPath, requireCi: config.requireCi, promotedFrom: urgent ? { record: `${facts.head}.urgent.json`, reason: urgent.reason, role: urgent.role, at: urgent.createdAt } : null });
491
+ if (urgent) {
492
+ writeUrgent(common, { ...urgent, backfill: { state: 'promoted', at: new Date(ctx.now()).toISOString(), l4: recordPath } });
493
+ return { ok: true, lines: [...plan, ...report, `L4 record written: ${recordPath}`, `back-fill green: urgent release ${urgent.tag} is promoted to a normal L4 release (no re-release, no push)`], data: { ...base, executed: true, results, promoted: true } };
494
+ }
495
+ const created = facts.chosen.state !== 'on-head';
496
+ if (created)
497
+ git(ctx, ['tag', '-a', facts.chosen.tag, '-m', `release ${facts.chosen.tag}: required gates passed on ${facts.head.slice(0, 12)} (L4 record ${path.basename(recordPath)})`, facts.head]);
498
+ const tagged = created ? `annotated tag ${facts.chosen.tag} created on ${facts.head.slice(0, 10)}` : `annotated tag ${facts.chosen.tag} already on ${facts.head.slice(0, 10)}`;
499
+ return { ok: true, lines: [...plan, ...report, `L4 record written: ${recordPath}`, tagged], data: { ...base, executed: true, results, tagCreated: created } };
472
500
  }