@starci/hfs 4.11.22 → 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 +23 -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 +414 -325
  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 +14 -22
  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 +493 -348
  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/sync/index.mjs CHANGED
@@ -10,8 +10,8 @@
10
10
  // and are listed in this module: the marked blocks of the root .gitignore and README.md, and .starciwork/.gitignore, which lives inside the
11
11
  // .starciwork directory slot. Every file is rendered with the app's hfs.json (both sides and their apps) and, for the Sonar
12
12
  // exclusions, the jest preset the app installs for its be side and the one coverage scope derived from the slot manifest
13
- // (scripts/hfs/coverage-scope.mjs: the be/jest.config.js scope, sonar.coverage.exclusions and the codecov.yml paths, components and exclusions). `--check` compares the sha256 of the rendered content with the
14
- // file on disk and fails on any drift; `--write` rewrites the drifted files. `.gitignore` and README.md are shared files: only the marked
13
+ // (scripts/hfs/coverage-scope.mjs: the be/jest.config.js scope, sonar.coverage.exclusions and the codecov.yml paths, components and exclusions). The default run (a dry run) compares the sha256 of the rendered content with the
14
+ // file on disk and fails on any drift; `--execute` rewrites the drifted files. `.gitignore` and README.md are shared files: only the marked
15
15
  // block is managed and the app's own lines around it are left alone. The root package.json is managed by its `scripts` block
16
16
  // only (mode scripts, compared as parsed JSON): the rest of the file (dependencies, the npm workspaces fe/apps/* and fe/packages/*,
17
17
  // HFS_MONO_WORKSPACES) is the app's. The fe side runs through turbo (turbo.json, app.task-graph): each fe app and package is a workspace.
@@ -22,7 +22,7 @@ import path from 'node:path';
22
22
  import { fileURLToPath } from 'node:url';
23
23
  import { braceVariants } from '../runtime/scripts/lib/glob.mjs';
24
24
  import { codecovPaths, coverageComponents, jestCoverage, sonarCoverageExclusions } from '../runtime/scripts/hfs/coverage-scope.mjs';
25
- import { APP_SCOPE, SIDES, litePresenceOf, loadSlotManifest, resolveRepoDeclaration, slotInEdition } from '../runtime/scripts/hfs/slots.mjs';
25
+ import { APP_SCOPE, SIDES, litePresenceOf, loadSlotManifest, resolveAppDeclaration, slotInEdition } from '../runtime/scripts/hfs/slots.mjs';
26
26
  import { managedGroupOf } from '../runtime/scripts/hfs/edition-slots.mjs';
27
27
  import { declaredSlotEnabled } from '../runtime/scripts/hfs/declaration-slots.mjs';
28
28
  import { feAppPackageName } from '../runtime/scripts/hfs/rules/monorepo.mjs';
@@ -42,7 +42,6 @@ import { readTruths } from '../runtime/scripts/lib/loosening-state.mjs';
42
42
  import { parseYaml as bundledParseYaml } from '../runtime/engine/yaml.mjs';
43
43
  import { bootstrapSection } from '../runtime/scripts/hfs/rules/database-constants.mjs';
44
44
  import { SERVER_AGE_IDENTITY } from '../stack/server-key.mjs';
45
-
46
45
  export const TEMPLATES_DIR = path.join(import.meta.dirname, '..', 'templates');
47
46
  const NODE_MAJOR = 22;
48
47
  const APP_BINARY = 'starci app';
@@ -50,116 +49,114 @@ const APP_BINARY = 'starci app';
50
49
  export const SCOPES = Object.freeze([APP_SCOPE, ...SIDES]);
51
50
  const BLOCK_BEGIN = '# >>> starci app sync (managed block; do not edit) >>>';
52
51
  const BLOCK_END = '# <<< starci app sync <<<';
53
- const HEADER = scope => `# Generated by ${APP_BINARY} sync (${scope === APP_SCOPE ? 'app root' : scope + ' side'}). Do not edit: run "npx ${APP_BINARY} sync --write".`;
54
-
52
+ const HEADER = (scope) => `# Generated by ${APP_BINARY} sync (${scope === APP_SCOPE ? 'app root' : scope + ' side'}). Do not edit: run "npx ${APP_BINARY} sync --execute".`;
55
53
  export class SyncError extends Error {
56
- constructor(code, message) {
57
- super(`${code}: ${message}`);
58
- this.code = code;
59
- }
54
+ code;
55
+ constructor(code, message) {
56
+ super(`${code}: ${message}`);
57
+ this.code = code;
58
+ }
60
59
  }
61
-
62
60
  // mode: file = whole file, block = the marked block inside a file the app also writes to, scripts = the `scripts` block of
63
61
  // package.json, section = the whole file but the one marked section a database verb owns (db/bootstrap.sql, whose squash section
64
62
  // `starci app db baseline --squash` writes). A template that can hold a comment opens with {{header}}; a file whose exact content is
65
63
  // specified (JSON, the eslint one-liner) has no header.
66
64
  const MODE_OF_GROUP = Object.freeze({ 'package-scripts': 'scripts', 'package-scripts-lite': 'scripts', 'db-bootstrap': 'section' });
67
65
  const GLOB_CHARACTERS = new Set('*?<>{}[]');
68
- const literalFile = file => file.length >= 2 && !file.endsWith('/') && ![...file].some(character => GLOB_CHARACTERS.has(character));
69
-
66
+ const literalFile = (file) => file.length >= 2 && !file.endsWith('/') && ![...file].some(character => GLOB_CHARACTERS.has(character));
70
67
  /** The targets no managedBy slot lists as a whole file (see the header of this module); both belong to the app root. */
71
68
  const UNLISTED_TARGETS = Object.freeze([
72
- { path: '.gitignore', template: 'app/gitignore', mode: 'block' },
73
- { path: '.starciwork/.gitignore', template: 'app/starciwork.gitignore', mode: 'file' },
74
- ].map(Object.freeze));
75
-
69
+ { path: '.gitignore', template: 'app/gitignore', mode: 'block' },
70
+ { path: '.starciwork/.gitignore', template: 'app/starciwork.gitignore', mode: 'file' },
71
+ ].map((target) => Object.freeze(target)));
76
72
  const templateName = (scope, group, file) => `${scope}/${group}/${file.split('/').map(segment => segment.replace(/^\./, '')).join('/')}`;
77
73
  const onSide = (scope, file) => (scope === APP_SCOPE ? file : `${scope}/${file}`);
78
-
79
74
  function managedTemplate(scope, group, file, hasTemplate) {
80
- const directories = [scope, 'common'];
81
- const undotted = directories.map(dir => templateName(dir, group, file)).find(name => hasTemplate(name));
82
- if (undotted || !['skeleton', 'skeleton-lite'].includes(group)) return undotted;
83
- return directories.map(dir => `${dir}/${group}/${file}`).find(name => hasTemplate(name));
75
+ const directories = [scope, 'common'];
76
+ const undotted = directories.map(dir => templateName(dir, group, file)).find(name => hasTemplate(name));
77
+ if (undotted || !['skeleton', 'skeleton-lite'].includes(group))
78
+ return undotted;
79
+ return directories.map(dir => `${dir}/${group}/${file}`).find(name => hasTemplate(name));
84
80
  }
85
-
86
81
  function slotTargets(slot, scope, edition, manifest, hasTemplate, enabled) {
87
- if (!slot.profiles.includes(scope) || !slotInEdition(manifest, slot, edition)) return [];
88
- // An opt-in slot is rendered only for a repository that enables it (app.browser-config with `browser: true`).
89
- if (slot.presence === 'opt-in' && !enabled(slot)) return [];
90
- if (edition === 'lite' && litePresenceOf(slot, scope) === 'forbidden') return [];
91
- const group = managedGroupOf(slot, edition);
92
- if (group === undefined) return [];
93
- const effectivePath = edition === 'lite' ? (slot.lite?.path ?? slot.path) : slot.path;
94
- return braceVariants(effectivePath).map(file => {
95
- const managedKey = edition === 'lite' && slot.liteManagedBy !== undefined ? 'liteManagedBy' : 'managedBy';
96
- if (!literalFile(file)) throw new SyncError('HFS_SYNC_MANIFEST_MANAGED', `slot ${slot.id} names ${managedKey} but its path ${effectivePath} is not a list of literal files (${file})`);
97
- const template = managedTemplate(scope, group, file, hasTemplate);
98
- if (!template) throw new SyncError('HFS_SYNC_TEMPLATE_MISSING', `slot ${slot.id} manages ${file} for ${scope}, but templates/{${scope},common}/${group} has no template for it`);
99
- return { path: file, template, mode: MODE_OF_GROUP[group] ?? 'file', slot: slot.id };
100
- });
101
- }
102
-
82
+ if (!slot.profiles.includes(scope) || !slotInEdition(manifest, slot, edition))
83
+ return [];
84
+ // An opt-in slot is rendered only for a repository that enables it (app.browser-config with `browser: true`).
85
+ if (slot.presence === 'opt-in' && !enabled(slot))
86
+ return [];
87
+ if (edition === 'lite' && litePresenceOf(slot, scope) === 'forbidden')
88
+ return [];
89
+ const group = managedGroupOf(slot, edition);
90
+ if (group === undefined)
91
+ return [];
92
+ const effectivePath = edition === 'lite' ? (slot.lite?.path ?? slot.path) : slot.path;
93
+ return braceVariants(effectivePath).map((file) => {
94
+ const managedKey = edition === 'lite' && slot.liteManagedBy !== undefined ? 'liteManagedBy' : 'managedBy';
95
+ if (!literalFile(file))
96
+ throw new SyncError('HFS_SYNC_MANIFEST_MANAGED', `slot ${slot.id} names ${managedKey} but its path ${effectivePath} is not a list of literal files (${file})`);
97
+ const template = managedTemplate(scope, group, file, hasTemplate);
98
+ if (!template)
99
+ throw new SyncError('HFS_SYNC_TEMPLATE_MISSING', `slot ${slot.id} manages ${file} for ${scope}, but templates/{${scope},common}/${group} has no template for it`);
100
+ return { path: file, template, mode: MODE_OF_GROUP[group] ?? 'file', slot: slot.id };
101
+ });
102
+ }
103
103
  function unlistedTargets(scope, edition) {
104
- if (scope !== APP_SCOPE) return [];
105
- return UNLISTED_TARGETS.map(target => {
106
- if (edition !== 'lite') return { ...target };
107
- return { ...target, template: target.path === '.gitignore' ? 'app/gitignore-lite' : 'app/starciwork.gitignore-lite' };
108
- });
104
+ if (scope !== APP_SCOPE)
105
+ return [];
106
+ return UNLISTED_TARGETS.map(target => {
107
+ if (edition !== 'lite')
108
+ return { ...target };
109
+ return { ...target, template: target.path === '.gitignore' ? 'app/gitignore-lite' : 'app/starciwork.gitignore-lite' };
110
+ });
109
111
  }
110
-
111
112
  /**
112
113
  * Every target of `scope` (app, be or fe), its path relative to that scope's folder: the files the manifest's managedBy slots
113
114
  * list, then (app root) the unlisted ones. A slot that names managedBy lists literal files only, and each has a template under
114
115
  * its scope or under common. `enabled(slot)` decides an opt-in slot (renderTargets passes the declaration's); without it every slot
115
116
  * counts, which is what an inventory of the templates needs.
116
117
  */
117
- export function targetsOf(scope, { edition = 'full', manifest = loadSlotManifest(), hasTemplate = name => fs.existsSync(path.join(TEMPLATES_DIR, name)), enabled = () => true } = {}) {
118
- const listed = manifest.slots.flatMap(slot => slotTargets(slot, scope, edition, manifest, hasTemplate, enabled));
119
- return [...listed, ...unlistedTargets(scope, edition)];
120
- }
121
-
122
- const lf = text => text.replace(/\r\n/g, '\n');
123
- export const hashOf = text => createHash('sha256').update(lf(text)).digest('hex');
124
-
118
+ export function targetsOf(scope, { edition = 'full', manifest = loadSlotManifest(), hasTemplate = (name) => fs.existsSync(path.join(TEMPLATES_DIR, name)), enabled = (_slot) => true } = {}) {
119
+ const listed = manifest.slots.flatMap(slot => slotTargets(slot, scope, edition, manifest, hasTemplate, enabled));
120
+ return [...listed, ...unlistedTargets(scope, edition)];
121
+ }
122
+ const lf = (text) => text.replace(/\r\n/g, '\n');
123
+ export const hashOf = (text) => createHash('sha256').update(lf(text)).digest('hex');
125
124
  /**
126
125
  * The hfs.json sync reads: an app declaration valid for the manifest it pins (both sides, their apps, connections, optional slots,
127
126
  * reads). Sync never renders configs for a declaration the eslint canons and starci app check would refuse, so a pin bump cannot leave
128
127
  * lint unable to start. Answers the resolved app.
129
128
  */
130
129
  export function validateHfs(hfs, manifest = loadSlotManifest()) {
131
- try {
132
- return resolveRepoDeclaration(manifest, hfs);
133
- } catch (error) {
134
- throw new SyncError('HFS_SYNC_HFS_INVALID', `hfs.json is not a valid app declaration for manifest ${manifest.version}: ${error.message}`);
135
- }
130
+ try {
131
+ return resolveAppDeclaration(manifest, hfs);
132
+ }
133
+ catch (error) {
134
+ throw new SyncError('HFS_SYNC_HFS_INVALID', `hfs.json is not a valid app declaration for manifest ${manifest.version}: ${error.message}`);
135
+ }
136
136
  }
137
-
138
137
  function readBundled(name) {
139
- return lf(fs.readFileSync(path.join(TEMPLATES_DIR, name), 'utf8'));
138
+ return lf(fs.readFileSync(path.join(TEMPLATES_DIR, name), 'utf8'));
140
139
  }
141
-
142
140
  /**
143
141
  * Fill `{{name}}` from vars and expand `{{> partial}}` lines. A partial line may be written as a line comment (`// {{> partial}}`)
144
142
  * so a JavaScript template stays valid source before rendering. Variable-only lines may also use a line comment;
145
143
  * empty variable-only lines disappear and an unknown name is an error.
146
144
  */
147
145
  export function render(text, vars, readTemplate = readBundled) {
148
- const withPartials = text.replace(/^(?:\/\/ )?\{\{> ([\w./-]+)\}\}\n/gm, (_, name) => trailingNewline(render(readTemplate(name), vars, readTemplate)));
149
- const presentLines = withPartials.replace(/^[ \t]*(?:\/\/ )?\{\{([A-Za-z]\w*)\}\}[ \t]*(?:\n|$)/gm,
150
- (line, key) => vars[key] === '' ? '' : line.replace(/^(\s*)\/\/ /, '$1'));
151
- return presentLines.replace(/\{\{([A-Za-z]\w*)\}\}/g, (_, key) => {
152
- if (!Object.hasOwn(vars, key)) throw new SyncError('HFS_SYNC_TEMPLATE_VARIABLE', `template names {{${key}}}, which sync does not provide`);
153
- return vars[key];
154
- });
155
- }
156
-
146
+ const withPartials = text.replace(/^(?:\/\/ )?\{\{> ([\w./-]+)\}\}\n/gm, (_, name) => trailingNewline(render(readTemplate(name), vars, readTemplate)));
147
+ const presentLines = withPartials.replace(/^[ \t]*(?:\/\/ )?\{\{([A-Za-z]\w*)\}\}[ \t]*(?:\n|$)/gm, (line, key) => vars[key] === '' ? '' : line.replace(/^(\s*)\/\/ /, '$1'));
148
+ return presentLines.replace(/\{\{([A-Za-z]\w*)\}\}/g, (_, key) => {
149
+ if (!Object.hasOwn(vars, key))
150
+ throw new SyncError('HFS_SYNC_TEMPLATE_VARIABLE', `template names {{${key}}}, which sync does not provide`);
151
+ return vars[key];
152
+ });
153
+ }
157
154
  function trailingNewline(text) {
158
- let end = text.length;
159
- while (end > 0 && text[end - 1] === '\n') end -= 1;
160
- return text.slice(0, end) + '\n';
155
+ let end = text.length;
156
+ while (end > 0 && text[end - 1] === '\n')
157
+ end -= 1;
158
+ return text.slice(0, end) + '\n';
161
159
  }
162
-
163
160
  /**
164
161
  * The base image of a lite app's managed .starcistacks/images/db/Dockerfile (contexts/stack/pins.yaml images postgres, ruling:lite-official-postgres-image): the
165
162
  * Docker Official postgres image by digest, to which the Dockerfile adds PGVECTOR_PACKAGE from PGDG and the PGMQ release.
@@ -172,57 +169,53 @@ export const PGVECTOR_PACKAGE = 'postgresql-17-pgvector=0.8.7-1.pgdg13+1';
172
169
  * when Docker adds it. PGDG does not package pgmq; it is SQL objects only, so the Dockerfile copies its control and script files.
173
170
  */
174
171
  export const PGMQ = Object.freeze({
175
- version: '1.13.1',
176
- source: 'https://github.com/pgmq/pgmq/archive/refs/tags/v1.13.1.tar.gz',
177
- sha256: '67221f288f42f95c002a64df40f7d660e765e32df8ada0f2672ba915a14827f7',
172
+ version: '1.13.1',
173
+ source: 'https://github.com/pgmq/pgmq/archive/refs/tags/v1.13.1.tar.gz',
174
+ sha256: '67221f288f42f95c002a64df40f7d660e765e32df8ada0f2672ba915a14827f7',
178
175
  });
179
176
  /** The local tag the development db container and the drift scratch database run, built from the app's .starcistacks/images/db/Dockerfile. */
180
- export const dbLocalImage = project => `${project}-db:local`;
177
+ export const dbLocalImage = (project) => `${project}-db:local`;
181
178
  /** The digest-pinned image of a lite app's declared Redis, in every environment that runs it (ruling:R212/case-10). */
182
179
  export const REDIS_IMAGE = 'redis:7@sha256:c6eabf748fc7a61dbb5a705c78bcf3d6377b1127a97d0ce965c11c44ba46896f';
183
-
184
- const redisDevText = project => render(readBundled('app/package-scripts/redis-dev.json'), { project, redisImage: REDIS_IMAGE });
185
-
180
+ const redisDevText = (project) => render(readBundled('app/package-scripts/redis-dev.json'), { project, redisImage: REDIS_IMAGE });
186
181
  /** The development scripts of a lite app's declared Redis (create once, then start and stop it), as a scripts object. */
187
- export const redisDevScripts = project => JSON.parse(`{${redisDevText(project).trim().replace(/,$/, '')}}`);
188
-
182
+ export const redisDevScripts = (project) => JSON.parse(`{${redisDevText(project).trim().replace(/,$/, '')}}`);
189
183
  /** What the app's sync reads from the jest preset it installs for its be side: the Sonar exclusions ({ sonarExclusions }); both editions install it (a lite back end keeps full's unit run, ruling:R212/case-1, amended by ruling:R212/case-4). */
190
184
  export async function loadPresets(root) {
191
- const name = '@starci/jest-preset';
192
- const require = createRequire(path.join(root, 'package.json'));
193
- let resolved;
194
- try {
195
- resolved = require.resolve(name);
196
- } catch {
197
- throw new SyncError('HFS_SYNC_PRESET_MISSING', `${name} is not installed under ${root}; set it to the exact version in knowledge/hfs/canon-pins.yaml and reinstall`);
198
- }
199
- return { sonarExclusions: require(resolved).sonarExclusions() };
200
- }
201
-
185
+ const name = '@starci/jest-preset';
186
+ const require = createRequire(path.join(root, 'package.json'));
187
+ let resolved;
188
+ try {
189
+ resolved = require.resolve(name);
190
+ }
191
+ catch {
192
+ throw new SyncError('HFS_SYNC_PRESET_MISSING', `${name} is not installed under ${root}; set it to the exact version in knowledge/hfs/canon-pins.yaml and reinstall`);
193
+ }
194
+ return { sonarExclusions: require(resolved).sonarExclusions() };
195
+ }
202
196
  /**
203
197
  * The jest preset's Sonar exclusions as @starci/hfs ships them: `@starci/jest-preset/sonar-exclusions.cjs` (a require-free module),
204
198
  * carried byte for byte in packages/hfs/runtime, so a fresh `starci app scaffold` (nothing installed
205
199
  * yet) and an upgrade render the same list the app's installed preset answers. A missing copy is a refusal, never a render without it.
206
200
  */
207
201
  const BUNDLED_SONAR_EXCLUSIONS = new URL('../runtime/packages/jest-preset/sonar-exclusions.cjs', import.meta.url);
208
-
209
202
  /** The presets ({ sonarExclusions }) of the jest preset version this @starci/hfs pins, read from its bundled copy. */
210
203
  export function bundledPresets() {
211
- let list;
212
- try {
213
- list = createRequire(import.meta.url)(fileURLToPath(BUNDLED_SONAR_EXCLUSIONS));
214
- } catch {
215
- throw new SyncError('HFS_SYNC_PRESET_MISSING', '@starci/hfs ships no runtime/packages/jest-preset/sonar-exclusions.cjs; reinstall @starci/hfs at its published version');
216
- }
217
- return { sonarExclusions: list.join(',') };
218
- }
219
-
204
+ let list;
205
+ try {
206
+ list = createRequire(import.meta.url)(fileURLToPath(BUNDLED_SONAR_EXCLUSIONS));
207
+ }
208
+ catch {
209
+ throw new SyncError('HFS_SYNC_PRESET_MISSING', '@starci/hfs ships no runtime/packages/jest-preset/sonar-exclusions.cjs; reinstall @starci/hfs at its published version');
210
+ }
211
+ return { sonarExclusions: list.join(',') };
212
+ }
220
213
  /** Where the be unit run writes the lcov report (jest `coverageDirectory` coverage under be/, reporter lcov), from the app root. */
221
214
  const LCOV_REPORT = 'be/coverage/lcov.info';
222
215
  /** The design truths this package ships: the one list of the exceptions the canon allows, each with its owner ruling. */
223
216
  const DESIGN_TRUTHS = path.join(import.meta.dirname, '..', 'runtime', 'knowledge', 'hfs', 'design-truths.yaml');
224
217
  /** Every entry the design truths allow on `list`, in manifest order. */
225
- const designTruthEntries = list => [...new Set(readTruths(bundledParseYaml(fs.readFileSync(DESIGN_TRUTHS, 'utf8'))).literal.filter(allow => allow.list === list).flatMap(allow => allow.entries))];
218
+ const designTruthEntries = (list) => [...new Set(readTruths(bundledParseYaml(fs.readFileSync(DESIGN_TRUTHS, 'utf8'))).literal.filter((allow) => allow.list === list).flatMap((allow) => allow.entries))];
226
219
  /**
227
220
  * The entries Sonar's copy-paste detection leaves out: every `cpd-exclusions` entry the design truths
228
221
  * (knowledge/hfs/design-truths.yaml) allow, today the message catalogs (ruling message-catalogs-not-duplicate-code): a catalog
@@ -231,7 +224,6 @@ const designTruthEntries = list => [...new Set(readTruths(bundledParseYaml(fs.re
231
224
  * accepts the block only as this manifest derives it.
232
225
  */
233
226
  export const SONAR_CPD_EXCLUSIONS = Object.freeze(designTruthEntries(LIST.cpd));
234
-
235
227
  /**
236
228
  * The Sonar scope of the jest preset's exclusions (presets.sonarExclusions): its file patterns are the tests, which
237
229
  * `sonar.test.inclusions` takes and `sonar.exclusions` moves out of the sources (`sonar.tests` names every source folder, so the
@@ -239,14 +231,12 @@ export const SONAR_CPD_EXCLUSIONS = Object.freeze(designTruthEntries(LIST.cpd));
239
231
  * build and dependency folders are no source at all. Nothing else is excluded: a generated file is analysed like any other.
240
232
  */
241
233
  export function sonarScope(presets) {
242
- const preset = String(presets?.sonarExclusions ?? '').split(',').map(glob => glob.trim()).filter(Boolean);
243
- const tests = preset.filter(glob => !glob.endsWith('/**'));
244
- return { tests, exclusions: [...new Set([...preset, '**/.next/**', '**/node_modules/**'])] };
234
+ const preset = String(presets?.sonarExclusions ?? '').split(',').map(glob => glob.trim()).filter(Boolean);
235
+ const tests = preset.filter(glob => !glob.endsWith('/**'));
236
+ return { tests, exclusions: [...new Set([...preset, '**/.next/**', '**/node_modules/**'])] };
245
237
  }
246
-
247
238
  const SOURCE_FILE = /\.[cm]?ts$/;
248
239
  const SOURCE_SKIPPED = new Set(['node_modules', 'dist', 'coverage']);
249
-
250
240
  /**
251
241
  * The be source of the app at `root` the coverage components read: { files, read }, `files` be-relative posix paths of every `*.ts` file under
252
242
  * be/apps and be/src (build output and dependencies skipped) and `read` their text. `workPresent` records whether the optional
@@ -254,40 +244,48 @@ const SOURCE_SKIPPED = new Set(['node_modules', 'dist', 'coverage']);
254
244
  * their content. An app with no be folder has no source files.
255
245
  */
256
246
  export function appSource(root, { parseYaml, notices } = {}) {
257
- const files = [];
258
- const walk = dir => {
259
- let entries;
260
- try { entries = fs.readdirSync(path.join(root, 'be', dir), { withFileTypes: true }); } catch { return; }
261
- for (const entry of entries) {
262
- const rel = `${dir}/${entry.name}`;
263
- if (entry.isDirectory()) { if (!SOURCE_SKIPPED.has(entry.name)) walk(rel); } else if (SOURCE_FILE.test(entry.name)) files.push(rel);
264
- }
265
- };
266
- for (const dir of ['apps', 'src']) walk(dir);
267
- return { runtimeExample: isRuntimeExampleApp(root), files: files.sort(byCodeUnit), read: file => fs.readFileSync(path.join(root, 'be', file), 'utf8'),
268
- workPresent: fs.existsSync(path.join(root, '.starciwork')), hasImage: file => isFile(path.join(root, file), { followLinks: false }),
269
- stack: readDeclaredStack(root, { parseYaml }), quality: readDeclaredQuality(root, { parseYaml }),
270
- badges: readDeclaredBadges(root, { parseYaml, notices }),
271
- qualityDeclared: hasDeclaredServices(root, { parseYaml }) };
272
- }
273
-
247
+ const files = [];
248
+ const walk = (dir) => {
249
+ let entries;
250
+ try {
251
+ entries = fs.readdirSync(path.join(root, 'be', dir), { withFileTypes: true });
252
+ }
253
+ catch {
254
+ return;
255
+ }
256
+ for (const entry of entries) {
257
+ const rel = `${dir}/${entry.name}`;
258
+ if (entry.isDirectory()) {
259
+ if (!SOURCE_SKIPPED.has(entry.name))
260
+ walk(rel);
261
+ }
262
+ else if (SOURCE_FILE.test(entry.name))
263
+ files.push(rel);
264
+ }
265
+ };
266
+ for (const dir of ['apps', 'src'])
267
+ walk(dir);
268
+ return { runtimeExample: isRuntimeExampleApp(root), files: files.sort(byCodeUnit), read: (file) => fs.readFileSync(path.join(root, 'be', file), 'utf8'),
269
+ workPresent: fs.existsSync(path.join(root, '.starciwork')), hasImage: (file) => isFile(path.join(root, file), { followLinks: false }),
270
+ stack: readDeclaredStack(root, { parseYaml }), quality: readDeclaredQuality(root, { parseYaml }),
271
+ badges: readDeclaredBadges(root, { parseYaml, notices }),
272
+ qualityDeclared: hasDeclaredServices(root, { parseYaml }) };
273
+ }
274
274
  /**
275
275
  * The Codecov `individual_components` entries of components [{ id, name, paths }]: one `component_id` block each, `prefix` ahead of every path
276
276
  * (the app folder in the runtime repository) and `ids` mapping a component id to its name there.
277
277
  */
278
- export function componentsYaml(components, { prefix = '', ids = id => id } = {}) {
279
- return components.map(component => [` - component_id: ${ids(component.id)}`, ` name: ${ids(component.name)}`, ' paths:', ...component.paths.map(glob => ` - ${JSON.stringify(prefix + glob)}`)].join('\n')).join('\n');
278
+ export function componentsYaml(components, { prefix = '', ids = (id) => id } = {}) {
279
+ return components.map(component => [` - component_id: ${ids(component.id)}`, ` name: ${ids(component.name)}`, ' paths:', ...component.paths.map(glob => ` - ${JSON.stringify(prefix + glob)}`)].join('\n')).join('\n');
280
280
  }
281
-
282
281
  /** The managed be/jest.config.js option text of a coverage scope { roots, roles, files, excludes }, laid out exactly as prettier lays it out (width 120, indent 4). */
283
282
  export function jestCoverageSource(coverage) {
284
- const list = (key, items) => {
285
- const one = ` ${key}: [${items.map(item => JSON.stringify(item)).join(', ')}],`;
286
- return one.length <= 120 ? one : [` ${key}: [`, ...items.map(item => ` ${JSON.stringify(item)},`), ' ],'].join('\n');
287
- };
288
- return ['{', list('roots', coverage.roots), list('roles', coverage.roles), list('files', coverage.files), list('excludes', coverage.excludes), ' }'].join('\n');
283
+ const list = (key, items) => {
284
+ const one = ` ${key}: [${items.map(item => JSON.stringify(item)).join(', ')}],`;
285
+ return one.length <= 120 ? one : [` ${key}: [`, ...items.map(item => ` ${JSON.stringify(item)},`), ' ],'].join('\n');
286
+ };
287
+ return ['{', list('roots', coverage.roots), list('roles', coverage.roles), list('files', coverage.files), list('excludes', coverage.excludes), ' }'].join('\n');
289
288
  }
290
-
291
289
  /**
292
290
  * The script lines the apps add to the root package.json, each ending with a comma (the template puts them mid-object). A be
293
291
  * script runs from be/ (`cd be && ...`, the folder its tsconfig and jest configuration are relative to) or runs the built app; an
@@ -300,369 +298,392 @@ export function jestCoverageSource(coverage) {
300
298
  * `docker:build` builds every image, one after the other, never pushing.
301
299
  */
302
300
  export function appScripts(app, source) {
303
- const line = (name, command) => `${JSON.stringify(name)}: ${JSON.stringify(command)},`;
304
- const be = app.sides.be.apps;
305
- const fe = app.sides.fe.apps;
306
- const apis = be.filter(entry => entry.kind === 'api');
307
- const connections = app.sides.be.connections ?? [];
308
- const watch = entry => `cd be && ts-node-dev --respawn -r tsconfig-paths/register apps/${entry.name}/src/main.ts`;
309
- const built = entry => `node be/dist/apps/${entry.name}/src/main.js`;
310
- const workspace = entry => feAppPackageName(app.project, entry.name);
311
- // Both editions generate before they run (owner ruling 2026-10-13): the fe's GraphQL wire types, and under lite the database types check.
312
- const dev = entry => `npm run codegen --silent && turbo run dev --filter=${workspace(entry)}`;
313
- const images = imageEntries(app, source);
314
- const imageCommand = ({ side, entry }) => `docker build -f ${dockerfilePath(side, entry.name)} -t ${app.project}/${entry.name}:dev .`;
315
- return [
316
- ...(apis.length === 1 ? [line('dev:be', watch(apis[0]))] : apis.map(entry => line(`dev:be:${entry.name}`, watch(entry)))),
317
- ...(fe.length === 1 ? [line('dev:fe', dev(fe[0]))] : fe.map(entry => line(`dev:fe:${entry.name}`, dev(entry)))),
318
- ...be.flatMap(entry => {
319
- if (entry.kind !== 'cli') return [line(`start:${entry.name}`, built(entry))];
320
- return [line('cli', built(entry)), ...(connections.length ? [line('migrate', `${built(entry)} ${MIGRATE_COMMAND}`)] : [])];
321
- }),
322
- ...fe.map(entry => line(`start:${entry.name}`, `npm run start -w ${workspace(entry)}`)),
323
- ...(app.edition !== 'lite' && app.optionalSlots.includes('app.browser') ? [line('test:browser', 'playwright test -c browser/playwright.config.ts')] : []),
324
- line('docker:build', images.map(image => `npm run docker:build:${image.entry.name}`).join(' && ')),
325
- ...images.map(image => line(`docker:build:${image.entry.name}`, imageCommand(image))),
326
- ].join('\n ');
327
- }
328
-
301
+ const line = (name, command) => `${JSON.stringify(name)}: ${JSON.stringify(command)},`;
302
+ const be = app.sides.be.apps;
303
+ const fe = app.sides.fe.apps;
304
+ const apis = be.filter(entry => entry.kind === 'api');
305
+ const connections = app.sides.be.connections ?? [];
306
+ const watch = (entry) => `cd be && ts-node-dev --respawn -r tsconfig-paths/register apps/${entry.name}/src/main.ts`;
307
+ const built = (entry) => `node be/dist/apps/${entry.name}/src/main.js`;
308
+ const workspace = (entry) => feAppPackageName(app.project, entry.name);
309
+ // Both editions generate before they run (owner ruling 2026-10-13): the fe's GraphQL wire types, and under lite the database types check.
310
+ const dev = (entry) => `npm run codegen --silent && turbo run dev --filter=${workspace(entry)}`;
311
+ const images = imageEntries(app, source);
312
+ const imageCommand = ({ side, entry }) => `docker build -f ${dockerfilePath(side, entry.name)} -t ${app.project}/${entry.name}:dev .`;
313
+ return [
314
+ ...(apis.length === 1 ? [line('dev:be', watch(apis[0]))] : apis.map(entry => line(`dev:be:${entry.name}`, watch(entry)))),
315
+ ...(fe.length === 1 ? [line('dev:fe', dev(fe[0]))] : fe.map(entry => line(`dev:fe:${entry.name}`, dev(entry)))),
316
+ ...be.flatMap(entry => {
317
+ if (entry.kind !== 'cli')
318
+ return [line(`start:${entry.name}`, built(entry))];
319
+ return [line('cli', built(entry)), ...(connections.length ? [line('migrate', `${built(entry)} ${MIGRATE_COMMAND}`)] : [])];
320
+ }),
321
+ ...fe.map(entry => line(`start:${entry.name}`, `npm run start -w ${workspace(entry)}`)),
322
+ ...(app.edition !== 'lite' && app.optionalSlots.includes('app.browser') ? [line('test:browser', 'playwright test -c browser/playwright.config.ts')] : []),
323
+ line('docker:build', images.map(image => `npm run docker:build:${image.entry.name}`).join(' && ')),
324
+ ...images.map(image => line(`docker:build:${image.entry.name}`, imageCommand(image))),
325
+ ].join('\n ');
326
+ }
329
327
  /** The cli command that migrates every connection (src/features/cli/migrate/subs/run.cli.ts). */
330
328
  const MIGRATE_COMMAND = 'migrate run';
331
-
332
329
  /** True when the fe side opts into a workspace package (repo.packages or any fe.package.* slot): the sources then include fe/packages/. */
333
- const opensPackages = side => (side.optionalSlots ?? []).some(id => id === 'repo.packages' || String(id).startsWith('fe.package.'));
334
-
330
+ const opensPackages = (side) => (side.optionalSlots ?? []).some(id => id === 'repo.packages' || String(id).startsWith('fe.package.'));
335
331
  /** The stylesheets of the fe side the CSS canon judges, relative to fe/: every app and every workspace package (slot fe.route, fe.package.*). */
336
332
  export const STYLE_GLOB = '{apps,packages}/*/src/**/*.css';
337
-
338
333
  /** Required app images plus lite front ends whose optional Dockerfile the source holds. */
339
334
  function imageEntries(app, source) {
340
- const frontend = app.sides.fe.apps.filter(entry => app.edition !== 'lite' || source?.hasImage?.(dockerfilePath('fe', entry.name)));
341
- return [...app.sides.be.apps.map(entry => ({ side: 'be', entry })), ...frontend.map(entry => ({ side: 'fe', entry }))];
335
+ const frontend = app.sides.fe.apps.filter(entry => app.edition !== 'lite' || source?.hasImage?.(dockerfilePath('fe', entry.name)));
336
+ return [...app.sides.be.apps.map((entry) => ({ side: 'be', entry })), ...frontend.map((entry) => ({ side: 'fe', entry }))];
342
337
  }
343
-
344
338
  /**
345
339
  * The build matrix of the images workflow: one entry per declared app (be then fe, then a lite app's db image), each with the image name and its Dockerfile. The workflow
346
340
  * runs on the release tag, so every image is built there; no path filter narrows it. A YAML block mapping per entry, indented for
347
341
  * `strategy.matrix.include`.
348
342
  */
349
343
  export function imageMatrix(app, source) {
350
- const entry = (side, item) => ` - name: ${item.name}\n file: ${dockerfilePath(side, item.name)}`;
351
- const db = app.edition === 'lite' ? [` - name: ${DB_IMAGE_APP}\n file: ${DB_DOCKERFILE}`] : [];
352
- return [...imageEntries(app, source).map(image => entry(image.side, image.entry)), ...db].join('\n');
344
+ const entry = (side, item) => ` - name: ${item.name}\n file: ${dockerfilePath(side, item.name)}`;
345
+ const db = app.edition === 'lite' ? [` - name: ${DB_IMAGE_APP}\n file: ${DB_DOCKERFILE}`] : [];
346
+ return [...imageEntries(app, source).map(image => entry(image.side, image.entry)), ...db].join('\n');
353
347
  }
354
-
355
348
  /** The Dockerfile of the app a deploy image names (be first, then fe, then a lite app's db image); an app hfs.json does not declare cannot be built by the managed workflow. */
356
349
  function stackDockerfile(app, name) {
357
- if (app.edition === 'lite' && name === DB_IMAGE_APP) return DB_DOCKERFILE;
358
- const side = ['be', 'fe'].find(which => app.sides[which].apps.some(entry => entry.name === name));
359
- if (!side) throw new SyncError('HFS_SYNC_STACK_IMAGE', `deploy.images names the app ${name}, which hfs.json does not declare under be or fe`);
360
- return dockerfilePath(side, name);
350
+ if (app.edition === 'lite' && name === DB_IMAGE_APP)
351
+ return DB_DOCKERFILE;
352
+ const side = ['be', 'fe'].find(which => app.sides[which].apps.some(entry => entry.name === name));
353
+ if (!side)
354
+ throw new SyncError('HFS_SYNC_STACK_IMAGE', `deploy.images names the app ${name}, which hfs.json does not declare under be or fe`);
355
+ return dockerfilePath(side, name);
361
356
  }
362
-
363
357
  const IMAGE_TEMPLATE = Object.freeze({ api: 'be/image/api', worker: 'be/image/worker', cli: 'be/image/cli', next: 'fe/image/next' });
364
-
365
358
  /**
366
359
  * The Dockerfile of every declared app, [{ path, content }] (app-relative): written once by starci app scaffold from templates/<side>/image/<kind>
367
360
  * and then the app's own, judged by the docker rules (R187-R191). A Next image copies the fe packages only when the fe side opts into
368
361
  * them and the be contracts only when the fe side reads them, so each COPY names a folder the app has.
369
362
  */
370
363
  export function imageFiles(app, source) {
371
- const side = app.sides.fe;
372
- const inputs = [...(opensPackages(side) ? ['fe/packages'] : []), ...((side.reads ?? []).includes('be/contracts/') ? ['be/contracts'] : [])];
373
- const copyInputs = inputs.map(folder => `COPY ${folder} ${folder}\n`).join('');
374
- // The folders outside be/ that the back end declares it reads (the generated database types of a lite back end, db/types/) are in every one of its images.
375
- const beFolders = (app.sides.be.reads ?? []).map(folder => folder.replace(/\/$/, ''));
376
- const copyBeInputs = beFolders.map(folder => `COPY ${folder} ${folder}\n`).join('');
377
- const entries = imageEntries(app, source).map(({ side: which, entry: item }) => ({ side: which, item }));
378
- return entries.map(({ side: which, item }) => {
379
- const template = IMAGE_TEMPLATE[item.kind];
380
- const vars = { project: app.project, app: item.name, nodeImage: NODE_IMAGE, port: DEFAULT_PORT, copyInputs, copyBeInputs };
381
- return { path: dockerfilePath(which, item.name), content: render(readBundled(`${template}/Dockerfile`), vars) };
382
- });
383
- }
384
-
364
+ const side = app.sides.fe;
365
+ const inputs = [...(opensPackages(side) ? ['fe/packages'] : []), ...((side.reads ?? []).includes('be/contracts/') ? ['be/contracts'] : [])];
366
+ const copyInputs = inputs.map(folder => `COPY ${folder} ${folder}\n`).join('');
367
+ // The folders outside be/ that the back end declares it reads (the generated database types of a lite back end, db/types/) are in every one of its images.
368
+ const beFolders = (app.sides.be.reads ?? []).map(folder => folder.replace(/\/$/, ''));
369
+ const copyBeInputs = beFolders.map(folder => `COPY ${folder} ${folder}\n`).join('');
370
+ const entries = imageEntries(app, source).map(({ side: which, entry: item }) => ({ side: which, item }));
371
+ return entries.map(({ side: which, item }) => {
372
+ const template = IMAGE_TEMPLATE[item.kind];
373
+ const vars = { project: app.project, app: item.name, nodeImage: NODE_IMAGE, port: DEFAULT_PORT, copyInputs, copyBeInputs };
374
+ return { path: dockerfilePath(which, item.name), content: render(readBundled(`${template}/Dockerfile`), vars) };
375
+ });
376
+ }
385
377
  /** Every value a template of `scope` can name, derived from hfs.json and the presets. */
386
378
  export function variables(app, scope, presets, sonarKey, manifest = loadSlotManifest(), source = { files: [], read: () => '' }) {
387
- const stack = source.stack ?? { images: [], passEnv: [] };
388
- const fe = app.sides.fe;
389
- const packages = opensPackages(fe);
390
- const lite = app.edition === 'lite';
391
- const providers = (app.sides.be.connections ?? []).map(connection => connection.provider);
392
- const quality = source.quality ?? qualityServices({});
393
- const grammarLint = scope === 'fe' ? grammarLintFor(fe.grammar) : null;
394
- return {
395
- header: HEADER(scope),
396
- readmeBadges: source.badges ?? '',
397
- project: app.project,
398
- appBinary: APP_BINARY,
399
- appScripts: appScripts(app, source),
400
- // A lite app's own database runs in development as one container of the image its .starcistacks/images/db/Dockerfile builds (ruling:lite-db-image-in-stacks).
401
- dbImage: dbLocalImage(app.project),
402
- dbBaseImage: DB_BASE_IMAGE,
403
- pgvectorPackage: PGVECTOR_PACKAGE,
404
- pgmqVersion: PGMQ.version,
405
- pgmqSource: PGMQ.source,
406
- pgmqSha256: PGMQ.sha256,
407
- // A lite app's declared Redis (sides.be.backing, ruling:R212/case-10) runs in development as one container of its pinned image.
408
- backingScripts: lite && (app.sides.be.backing ?? []).includes('redis') ? redisDevText(app.project) : '',
409
- // turbo builds every fe app workspace; ^build (turbo.json) builds the packages each app imports first, and caches both.
410
- buildFe: 'npm run codegen --silent && turbo run build --filter=./fe/apps/*',
411
- // The be side with its tsc; every fe workspace with its own typecheck script through turbo (the packages are built first: ^build).
412
- typecheck: 'npm run codegen --silent && tsc -p be/tsconfig.json && turbo run typecheck',
413
- // The typed lint reads the types the fe packages declare (their dist, turbo.json: lint dependsOn ^build), so the packages are built first.
414
- lintPrefix: packages ? 'npm run codegen --silent && turbo run build --filter=./fe/packages/* && ' : 'npm run codegen --silent && ',
415
- nodeMajor: String(NODE_MAJOR),
416
- // The deploy server's age identity the restore workflow writes (stack/server-key.mjs owns the path).
417
- serverAgeIdentity: SERVER_AGE_IDENTITY,
418
- sonarKey: sonarKey ?? app.project,
419
- sonarHostLine: sonarHostLine(quality.sonar),
420
- sonarExclusions: sonarScope(presets).exclusions.join(','),
421
- sonarTestInclusions: sonarScope(presets).tests.join(','),
422
- sonarSources: ['be/apps', 'be/src', 'fe/apps', ...(packages ? ['fe/packages'] : [])].join(','),
423
- lcovReport: LCOV_REPORT,
424
- cpdExclusions: SONAR_CPD_EXCLUSIONS.join(','),
425
- ...ciWorkflowCommands(source, LCOV_REPORT, source.qualityDeclared === false ? undefined : source.quality, { app }),
426
- // The coverage scope is the same in both editions: lite measures exactly what full measures (ruling:R212/case-1, amended by ruling:R212/case-4).
427
- jestCoverage: scope === 'be' ? jestCoverageSource(jestCoverage(manifest, providers)) : '',
428
- coverageExclusions: scope === APP_SCOPE ? sonarCoverageExclusions(manifest, providers).join(',') : '',
429
- codecovExclusions: scope === APP_SCOPE ? sonarCoverageExclusions(manifest, providers).map(glob => ` - ${JSON.stringify(glob)}`).join('\n') : '',
430
- codecovPaths: scope === APP_SCOPE ? codecovPaths(manifest, providers).map(glob => ` - ${JSON.stringify(glob)}`).join('\n') : '',
431
- codecovComponents: scope === APP_SCOPE ? componentsYaml(coverageComponents(manifest, { ...source, apps: app.sides.be.apps, providers })) : '',
432
- codecovTarget: quality.codecov.target,
433
- dependabotUpdates: dependabotUpdates(quality.dependabot),
434
- tsconfigPaths: ['be/tsconfig.json', ...fe.apps.map(entry => `fe/apps/${entry.name}/tsconfig.json`), ...(packages ? ['fe/packages/*/tsconfig.json'] : [])].join(','),
435
- styleGlob: STYLE_GLOB,
436
- grammarLintImport: grammarLint?.package ? `import { ${grammarLint.factory} } from "${grammarLint.package}"` : '',
437
- grammarLintExport: grammarLint?.package ? `export default [...starciFeConfig({ hfs }), ...${grammarLint.factory}({ hfs })]` : 'export default starciFeConfig({ hfs })',
438
- imageMatrix: imageMatrix(app, source),
439
- imageProject: app.project,
440
- ...stackWorkflowVariables(stack, app.project, name => stackDockerfile(app, name)),
441
- };
442
- }
443
-
379
+ const stack = source.stack ?? { images: [], passEnv: [] };
380
+ const fe = app.sides.fe;
381
+ const packages = opensPackages(fe);
382
+ const lite = app.edition === 'lite';
383
+ const providers = (app.sides.be.connections ?? []).map(connection => connection.provider);
384
+ const quality = source.quality ?? qualityServices({});
385
+ const grammarLint = scope === 'fe' ? grammarLintFor(fe.grammar) : null;
386
+ return {
387
+ header: HEADER(scope),
388
+ readmeBadges: source.badges ?? '',
389
+ project: app.project,
390
+ appBinary: APP_BINARY,
391
+ appScripts: appScripts(app, source),
392
+ // A lite app's own database runs in development as one container of the image its .starcistacks/images/db/Dockerfile builds (ruling:lite-db-image-in-stacks).
393
+ dbImage: dbLocalImage(app.project),
394
+ dbBaseImage: DB_BASE_IMAGE,
395
+ pgvectorPackage: PGVECTOR_PACKAGE,
396
+ pgmqVersion: PGMQ.version,
397
+ pgmqSource: PGMQ.source,
398
+ pgmqSha256: PGMQ.sha256,
399
+ // A lite app's declared Redis (sides.be.backing, ruling:R212/case-10) runs in development as one container of its pinned image.
400
+ backingScripts: lite && (app.sides.be.backing ?? []).includes('redis') ? redisDevText(app.project) : '',
401
+ // turbo builds every fe app workspace; ^build (turbo.json) builds the packages each app imports first, and caches both.
402
+ buildFe: 'npm run codegen --silent && turbo run build --filter=./fe/apps/*',
403
+ // The be side with its tsc; every fe workspace with its own typecheck script through turbo (the packages are built first: ^build).
404
+ typecheck: 'npm run codegen --silent && tsc -p be/tsconfig.json && turbo run typecheck',
405
+ // The typed lint reads the types the fe packages declare (their dist, turbo.json: lint dependsOn ^build), so the packages are built first.
406
+ lintPrefix: packages ? 'npm run codegen --silent && turbo run build --filter=./fe/packages/* && ' : 'npm run codegen --silent && ',
407
+ nodeMajor: String(NODE_MAJOR),
408
+ // The deploy server's age identity the restore workflow writes (stack/server-key.mjs owns the path).
409
+ serverAgeIdentity: SERVER_AGE_IDENTITY,
410
+ sonarKey: sonarKey ?? app.project,
411
+ sonarHostLine: sonarHostLine(quality.sonar),
412
+ sonarExclusions: sonarScope(presets).exclusions.join(','),
413
+ sonarTestInclusions: sonarScope(presets).tests.join(','),
414
+ sonarSources: ['be/apps', 'be/src', 'fe/apps', ...(packages ? ['fe/packages'] : [])].join(','),
415
+ lcovReport: LCOV_REPORT,
416
+ cpdExclusions: SONAR_CPD_EXCLUSIONS.join(','),
417
+ ...ciWorkflowCommands(source, LCOV_REPORT, source.qualityDeclared === false ? undefined : source.quality, { app }),
418
+ // The coverage scope is the same in both editions: lite measures exactly what full measures (ruling:R212/case-1, amended by ruling:R212/case-4).
419
+ jestCoverage: scope === 'be' ? jestCoverageSource(jestCoverage(manifest, providers)) : '',
420
+ coverageExclusions: scope === APP_SCOPE ? sonarCoverageExclusions(manifest, providers).join(',') : '',
421
+ codecovExclusions: scope === APP_SCOPE ? sonarCoverageExclusions(manifest, providers).map(glob => ` - ${JSON.stringify(glob)}`).join('\n') : '',
422
+ codecovPaths: scope === APP_SCOPE ? codecovPaths(manifest, providers).map(glob => ` - ${JSON.stringify(glob)}`).join('\n') : '',
423
+ codecovComponents: scope === APP_SCOPE ? componentsYaml(coverageComponents(manifest, { ...source, apps: app.sides.be.apps, providers })) : '',
424
+ codecovTarget: quality.codecov.target,
425
+ dependabotUpdates: dependabotUpdates(quality.dependabot),
426
+ tsconfigPaths: ['be/tsconfig.json', ...fe.apps.map(entry => `fe/apps/${entry.name}/tsconfig.json`), ...(packages ? ['fe/packages/*/tsconfig.json'] : [])].join(','),
427
+ styleGlob: STYLE_GLOB,
428
+ grammarLintImport: grammarLint?.package ? `import { ${grammarLint.factory} } from "${grammarLint.package}"` : '',
429
+ grammarLintExport: grammarLint?.package ? `export default [...starciFeConfig({ hfs }), ...${grammarLint.factory}({ hfs })]` : 'export default starciFeConfig({ hfs })',
430
+ imageMatrix: imageMatrix(app, source),
431
+ imageProject: app.project,
432
+ ...stackWorkflowVariables(stack, app.project, (name) => stackDockerfile(app, name)),
433
+ };
434
+ }
444
435
  // The scripts of a package.json as one comparable text: a line per script, sorted by name (order is not drift).
445
- const scriptsText = scripts => Object.keys(scripts).sort(byCodeUnit)
446
- .map(name => `${name}: ${typeof scripts[name] === 'string' ? scripts[name] : JSON.stringify(scripts[name])}`).join('\n') + '\n';
447
-
436
+ const scriptsText = (scripts) => Object.keys(scripts).sort(byCodeUnit)
437
+ .map(name => `${name}: ${typeof scripts[name] === 'string' ? scripts[name] : JSON.stringify(scripts[name])}`).join('\n') + '\n';
448
438
  function parseScripts(text) {
449
- try {
450
- const { scripts } = JSON.parse(text);
451
- return scripts && typeof scripts === 'object' && !Array.isArray(scripts) ? scripts : null;
452
- } catch {
453
- return null;
454
- }
439
+ try {
440
+ const { scripts } = JSON.parse(text);
441
+ return scripts && typeof scripts === 'object' && !Array.isArray(scripts) ? scripts : null;
442
+ }
443
+ catch {
444
+ return null;
445
+ }
455
446
  }
456
-
457
447
  /**
458
448
  * The managed content of every target of the app: [{ path, mode, content, hash, scope }], paths app-relative (a side's targets under
459
449
  * its folder); a scripts target also carries `scripts`, the parsed block. `sonarKey` is the key the be side's stack declaration
460
450
  * names; without one the key is the project.
461
451
  */
462
452
  export function renderTargets(hfs, presets, { sonarKey, readTemplate = readBundled, manifest = loadSlotManifest(), source } = {}) {
463
- const app = validateHfs(hfs, manifest);
464
- const hasTemplate = name => { try { return readTemplate(name) !== undefined; } catch { return false; } };
465
- return SCOPES.flatMap(scope => {
466
- const vars = variables(app, scope, presets, sonarKey, manifest, source);
467
- const repo = scope === APP_SCOPE ? app : app.sides[scope];
468
- const declaredTargets = targetsOf(scope, { edition: app.edition, manifest, hasTemplate, enabled: slot => declaredSlotEnabled(slot, repo) });
469
- if (scope === APP_SCOPE && source?.badges) declaredTargets.push({ path: 'README.md', mode: 'block', markdown: true, template: 'app/readme-badges/README.md' });
470
- const targets = declaredTargets
471
- .filter(target => !(app.edition === 'lite' && source?.workPresent === false && target.path === '.starciwork/.gitignore'));
472
- return targets.map(target => {
473
- const template = target.path === 'codecov.yml' && source?.quality?.codecov.enabled === false
474
- ? '{{header}}\n# Codecov is disabled in the manifest.\ncodecov:\n require_ci_to_pass: false\n'
475
- : readTemplate(target.template);
476
- const body = trailingNewline(render(template, vars, readTemplate));
477
- const where = onSide(scope, target.path);
478
- if (target.mode === 'scripts') {
479
- const scripts = parseScripts(body);
480
- if (!scripts) throw new SyncError('HFS_SYNC_TEMPLATE_VARIABLE', `the rendered ${target.template} has no scripts object`);
481
- const content = scriptsText(scripts);
482
- return { path: where, scope, mode: 'scripts', content, hash: hashOf(content), scripts };
483
- }
484
- const markers = target.markdown ? { begin: '<!-- >>> starci app sync (managed block; do not edit) >>> -->', end: '<!-- <<< starci app sync <<< -->' } : { begin: BLOCK_BEGIN, end: BLOCK_END };
485
- const spacing = target.markdown ? '\n' : '';
486
- const managed = target.mode === 'block' ? `${markers.begin}\n${spacing}${trailingNewline(body)}${spacing}${markers.end}\n` : body;
487
- return { path: where, scope, mode: target.mode, markdown: target.markdown, markers, content: managed, hash: hashOf(managed) };
453
+ const app = validateHfs(hfs, manifest);
454
+ const hasTemplate = (name) => { try {
455
+ return readTemplate(name) !== undefined;
456
+ }
457
+ catch {
458
+ return false;
459
+ } };
460
+ return SCOPES.flatMap(scope => {
461
+ const vars = variables(app, scope, presets, sonarKey, manifest, source);
462
+ const repo = scope === APP_SCOPE ? app : app.sides[scope];
463
+ const declaredTargets = targetsOf(scope, { edition: app.edition, manifest, hasTemplate, enabled: slot => declaredSlotEnabled(slot, repo) });
464
+ if (scope === APP_SCOPE && source?.badges)
465
+ declaredTargets.push({ path: 'README.md', mode: 'block', markdown: true, template: 'app/readme-badges/README.md' });
466
+ const targets = declaredTargets
467
+ .filter(target => !(app.edition === 'lite' && source?.workPresent === false && target.path === '.starciwork/.gitignore'));
468
+ return targets.map((target) => {
469
+ const template = target.path === 'codecov.yml' && source?.quality?.codecov.enabled === false
470
+ ? '{{header}}\n# Codecov is disabled in the manifest.\ncodecov:\n require_ci_to_pass: false\n'
471
+ : readTemplate(target.template);
472
+ const body = trailingNewline(render(template, vars, readTemplate));
473
+ const where = onSide(scope, target.path);
474
+ if (target.mode === 'scripts') {
475
+ const scripts = parseScripts(body);
476
+ if (!scripts)
477
+ throw new SyncError('HFS_SYNC_TEMPLATE_VARIABLE', `the rendered ${target.template} has no scripts object`);
478
+ const content = scriptsText(scripts);
479
+ return { path: where, scope, mode: 'scripts', content, hash: hashOf(content), scripts };
480
+ }
481
+ const markers = target.markdown ? { begin: '<!-- >>> starci app sync (managed block; do not edit) >>> -->', end: '<!-- <<< starci app sync <<< -->' } : { begin: BLOCK_BEGIN, end: BLOCK_END };
482
+ const spacing = target.markdown ? '\n' : '';
483
+ const managed = target.mode === 'block' ? `${markers.begin}\n${spacing}${trailingNewline(body)}${spacing}${markers.end}\n` : body;
484
+ return { path: where, scope, mode: target.mode, markdown: target.markdown, markers, content: managed, hash: hashOf(managed) };
485
+ });
488
486
  });
489
- });
490
487
  }
491
-
492
488
  // The part of a file sync manages: all of it, all of it but the verb's section, the marked block, or the scripts block as text.
493
489
  function managedPart(mode, text, markers = { begin: BLOCK_BEGIN, end: BLOCK_END }) {
494
- if (mode === 'file') return text;
495
- if (mode === 'section') return bootstrapSection(text).head;
496
- if (mode === 'scripts') {
497
- const scripts = parseScripts(text);
498
- return scripts ? scriptsText(scripts) : null;
499
- }
500
- const start = text.indexOf(markers.begin);
501
- const end = text.indexOf(markers.end);
502
- if (start < 0 || end < start) return null;
503
- const stop = text.indexOf('\n', end);
504
- return text.slice(start, stop < 0 ? text.length : stop + 1);
505
- }
506
-
490
+ if (mode === 'file')
491
+ return text;
492
+ if (mode === 'section')
493
+ return bootstrapSection(text).head;
494
+ if (mode === 'scripts') {
495
+ const scripts = parseScripts(text);
496
+ return scripts ? scriptsText(scripts) : null;
497
+ }
498
+ const start = text.indexOf(markers.begin);
499
+ const end = text.indexOf(markers.end);
500
+ if (start < 0 || end < start)
501
+ return null;
502
+ const stop = text.indexOf('\n', end);
503
+ return text.slice(start, stop < 0 ? text.length : stop + 1);
504
+ }
507
505
  function firstDifference(expected, actual) {
508
- const want = expected.split('\n'), have = actual.split('\n');
509
- for (let index = 0; index < Math.max(want.length, have.length); index += 1) {
510
- if (want[index] !== have[index]) return { line: index + 1, expected: want[index] ?? '(end of file)', actual: have[index] ?? '(end of file)' };
511
- }
512
- return null;
506
+ const want = expected.split('\n'), have = actual.split('\n');
507
+ for (let index = 0; index < Math.max(want.length, have.length); index += 1) {
508
+ if (want[index] !== have[index])
509
+ return { line: index + 1, expected: want[index] ?? '(end of file)', actual: have[index] ?? '(end of file)' };
510
+ }
511
+ return null;
513
512
  }
514
-
515
513
  /** Compare every rendered target with the disk: [{ path, status: ok | missing | drift, expectedHash, actualHash?, difference? }]. */
516
514
  export function checkTargets(root, targets) {
517
- return targets.map(target => {
518
- const file = path.join(root, target.path);
519
- if (!fs.existsSync(file)) return { path: target.path, status: 'missing', expectedHash: target.hash };
520
- const part = managedPart(target.mode, lf(fs.readFileSync(file, 'utf8')), target.markers);
521
- if (part === null) return { path: target.path, status: 'missing', expectedHash: target.hash };
522
- const actualHash = hashOf(part);
523
- if (actualHash === target.hash) return { path: target.path, status: 'ok', expectedHash: target.hash, actualHash };
524
- return { path: target.path, status: 'drift', expectedHash: target.hash, actualHash, difference: firstDifference(target.content, part) };
525
- });
526
- }
527
-
515
+ return targets.map((target) => {
516
+ const file = path.join(root, target.path);
517
+ if (!fs.existsSync(file))
518
+ return { path: target.path, status: 'missing', expectedHash: target.hash };
519
+ const part = managedPart(target.mode, lf(fs.readFileSync(file, 'utf8')), target.markers);
520
+ if (part === null)
521
+ return { path: target.path, status: 'missing', expectedHash: target.hash };
522
+ const actualHash = hashOf(part);
523
+ if (actualHash === target.hash)
524
+ return { path: target.path, status: 'ok', expectedHash: target.hash, actualHash };
525
+ return { path: target.path, status: 'drift', expectedHash: target.hash, actualHash, difference: firstDifference(target.content, part) };
526
+ });
527
+ }
528
528
  function insertAfterTitle(existing, content) {
529
- const title = /^# [^\n]*(?:\n|$)/m.exec(existing);
530
- if (!title) return `${content}\n${existing}`;
531
- const end = title.index + title[0].length;
532
- const heading = trailingNewline(existing.slice(0, end));
533
- return `${heading}\n${content}${existing.slice(end)}`;
529
+ const title = /^# [^\n]*(?:\n|$)/m.exec(existing);
530
+ if (!title)
531
+ return `${content}\n${existing}`;
532
+ const end = title.index + title[0].length;
533
+ const heading = trailingNewline(existing.slice(0, end));
534
+ return `${heading}\n${content}${existing.slice(end)}`;
534
535
  }
535
-
536
536
  /** Apply exactly one target to its whole file while preserving content outside the managed block or scripts. */
537
537
  export function writtenContent(target, existing) {
538
- if (target.mode === 'scripts') {
539
- let pkg = {};
540
- if (existing) {
541
- try { pkg = JSON.parse(existing); } catch { throw new SyncError('HFS_SYNC_HFS_INVALID', `${target.path} is not valid JSON; fix it by hand before sync can set its scripts`); }
538
+ if (target.mode === 'scripts') {
539
+ let pkg = {};
540
+ if (existing) {
541
+ try {
542
+ pkg = JSON.parse(existing);
543
+ }
544
+ catch {
545
+ throw new SyncError('HFS_SYNC_HFS_INVALID', `${target.path} is not valid JSON; fix it by hand before sync can set its scripts`);
546
+ }
547
+ }
548
+ return `${JSON.stringify({ ...pkg, scripts: target.scripts }, null, 2)}\n`;
542
549
  }
543
- return `${JSON.stringify({ ...pkg, scripts: target.scripts }, null, 2)}\n`;
544
- }
545
- if (target.mode === 'section') return `${target.content}${bootstrapSection(existing ?? '').section ?? ''}`;
546
- if (target.mode === 'block' && existing) {
547
- const current = managedPart('block', existing, target.markers);
548
- if (current !== null) return existing.replace(current, () => target.content);
549
- if (target.markdown) return insertAfterTitle(existing, target.content);
550
- return `${target.content}\n${existing}`;
551
- }
552
- return target.content;
553
- }
554
-
550
+ if (target.mode === 'section')
551
+ return `${target.content}${bootstrapSection(existing ?? '').section ?? ''}`;
552
+ if (target.mode === 'block' && existing) {
553
+ const current = managedPart('block', existing, target.markers);
554
+ if (current !== null)
555
+ return existing.replace(current, () => target.content);
556
+ if (target.markdown)
557
+ return insertAfterTitle(existing, target.content);
558
+ return `${target.content}\n${existing}`;
559
+ }
560
+ return target.content;
561
+ }
555
562
  export function writeTargets(root, targets) {
556
- const written = [];
557
- for (const result of checkTargets(root, targets)) {
558
- if (result.status === 'ok') continue;
559
- const target = targets.find(candidate => candidate.path === result.path);
560
- const file = path.join(root, target.path);
561
- const existing = fs.existsSync(file) ? lf(fs.readFileSync(file, 'utf8')) : '';
562
- const next = writtenContent(target, existing);
563
- fs.mkdirSync(path.dirname(file), { recursive: true });
564
- fs.writeFileSync(file, next);
565
- written.push(target.path);
566
- }
567
- return written;
568
- }
569
-
563
+ const written = [];
564
+ for (const result of checkTargets(root, targets)) {
565
+ if (result.status === 'ok')
566
+ continue;
567
+ const target = targets.find(candidate => candidate.path === result.path);
568
+ const file = path.join(root, target.path);
569
+ const existing = fs.existsSync(file) ? lf(fs.readFileSync(file, 'utf8')) : '';
570
+ const next = writtenContent(target, existing);
571
+ fs.mkdirSync(path.dirname(file), { recursive: true });
572
+ fs.writeFileSync(file, next);
573
+ written.push(target.path);
574
+ }
575
+ return written;
576
+ }
570
577
  /** The hfs.json object of the app at `root` (validated), or a SyncError. */
571
578
  export function loadHfs(root, manifest = loadSlotManifest()) {
572
- const file = path.join(root, 'hfs.json');
573
- if (!fs.existsSync(file)) throw new SyncError('HFS_SYNC_HFS_INVALID', `${file} does not exist; starci app sync runs at the app root`);
574
- let hfs;
575
- try {
576
- hfs = JSON.parse(fs.readFileSync(file, 'utf8'));
577
- } catch (error) {
578
- throw new SyncError('HFS_SYNC_HFS_INVALID', `${file} is not valid JSON: ${error.message}`);
579
- }
580
- validateHfs(hfs, manifest);
581
- return hfs;
582
- }
583
-
579
+ const file = path.join(root, 'hfs.json');
580
+ if (!fs.existsSync(file))
581
+ throw new SyncError('HFS_SYNC_HFS_INVALID', `${file} does not exist; starci app sync runs at the app root`);
582
+ let hfs;
583
+ try {
584
+ hfs = JSON.parse(fs.readFileSync(file, 'utf8'));
585
+ }
586
+ catch (error) {
587
+ throw new SyncError('HFS_SYNC_HFS_INVALID', `${file} is not valid JSON: ${error.message}`);
588
+ }
589
+ validateHfs(hfs, manifest);
590
+ return hfs;
591
+ }
584
592
  /** The rendered targets of the app at `root`: its hfs.json, the Sonar key the be side's stack declaration names, the presets it installs. */
585
593
  export async function renderRepo(root, { presets, parseYaml, notices, manifest = loadSlotManifest() } = {}) {
586
- const hfs = loadHfs(root, manifest);
587
- const sonarKey = await readDeclaredSonarKey(root, { parseYaml, fail: message => { throw new SyncError('HFS_SYNC_SONAR_KEY', message); } });
588
- return { hfs, targets: renderTargets(hfs, presets ?? await loadPresets(root), { sonarKey, manifest, source: appSource(root, { parseYaml, notices }) }) };
594
+ const hfs = loadHfs(root, manifest);
595
+ const sonarKey = await readDeclaredSonarKey(root, { parseYaml, fail: (message) => { throw new SyncError('HFS_SYNC_SONAR_KEY', message); } });
596
+ return { hfs, targets: renderTargets(hfs, presets ?? await loadPresets(root), { sonarKey, manifest, source: appSource(root, { parseYaml, notices }) }) };
589
597
  }
590
-
591
598
  /** The folders a lite app's sync retires (ruling lite-self-hosted-postgres-passport-minio): the generated Supabase row types nothing reads any more. */
592
599
  const LITE_RETIRED_DIRS = Object.freeze(['supabase/types']);
593
- /** The files a lite app's sync retires, each with the reason --check prints. */
600
+ /** The files a lite app's sync retires, each with the reason the dry run prints. */
594
601
  const LITE_RETIRED_FILES = Object.freeze({
595
- [RETIRED_DB_DOCKERFILE]: `the db image moved to ${DB_DOCKERFILE} (ruling lite-db-image-in-stacks)`,
602
+ [RETIRED_DB_DOCKERFILE]: `the db image moved to ${DB_DOCKERFILE} (ruling lite-db-image-in-stacks)`,
596
603
  });
597
604
  /** Why a retired file goes: a retired file's own reason, else the folder's. */
598
605
  const retiredReason = (file) => LITE_RETIRED_FILES[file] ?? 'the lite edition generates no database types';
599
-
600
- /** The app-relative files of the retired folders that still exist under `root` of a lite app; sync --write deletes them, --check reports them. */
606
+ /** The app-relative files of the retired folders that still exist under `root` of a lite app; sync --execute deletes them, the dry run reports them. */
601
607
  export function retiredFiles(root, hfs) {
602
- if (hfs?.edition !== 'lite') return [];
603
- const found = [];
604
- const walk = (rel) => {
605
- const full = path.join(root, rel);
606
- const stat = fs.lstatSync(full, { throwIfNoEntry: false });
607
- if (!stat) return;
608
- if (stat.isDirectory()) for (const name of fs.readdirSync(full).sort(byCodeUnit)) walk(`${rel}/${name}`);
609
- else found.push(rel);
610
- };
611
- for (const dir of LITE_RETIRED_DIRS) walk(dir);
612
- for (const file of Object.keys(LITE_RETIRED_FILES)) walk(file);
613
- return found;
614
- }
615
-
616
- /** `starci app sync --check | --write [--cwd <dir>]` at the app root; returns 0 clean, 1 drift, 2 usage. */
608
+ if (hfs?.edition !== 'lite')
609
+ return [];
610
+ const found = [];
611
+ const walk = (rel) => {
612
+ const full = path.join(root, rel);
613
+ const stat = fs.lstatSync(full, { throwIfNoEntry: false });
614
+ if (!stat)
615
+ return;
616
+ if (stat.isDirectory())
617
+ for (const name of fs.readdirSync(full).sort(byCodeUnit))
618
+ walk(`${rel}/${name}`);
619
+ else
620
+ found.push(rel);
621
+ };
622
+ for (const dir of LITE_RETIRED_DIRS)
623
+ walk(dir);
624
+ for (const file of Object.keys(LITE_RETIRED_FILES))
625
+ walk(file);
626
+ return found;
627
+ }
628
+ /** `starci app sync [--execute] [--cwd <dir>]` at the app root: the dry run reports drift, --execute writes; returns 0 clean, 1 drift, 2 usage. */
617
629
  function syncOptions(argv) {
618
- const check = argv.includes('--check'), write = argv.includes('--write');
619
- const cwdAt = argv.indexOf('--cwd');
620
- const known = new Set(['--check', '--write', '--cwd']);
621
- const unknown = argv.find((arg, index) => !known.has(arg) && index !== cwdAt + 1);
622
- if ([check, write].filter(Boolean).length !== 1 || unknown !== undefined || (cwdAt >= 0 && argv[cwdAt + 1] === undefined)) {
623
- return null;
624
- }
625
- return { write, cwdAt };
630
+ const write = argv.includes('--execute');
631
+ const cwdAt = argv.indexOf('--cwd');
632
+ const known = new Set(['--execute', '--cwd']);
633
+ const unknown = argv.find((arg, index) => !known.has(arg) && (cwdAt < 0 || index !== cwdAt + 1));
634
+ if (unknown !== undefined || (cwdAt >= 0 && argv[cwdAt + 1] === undefined) || argv.indexOf('--execute') !== argv.lastIndexOf('--execute')) {
635
+ return null;
636
+ }
637
+ return { write, cwdAt };
626
638
  }
627
-
628
639
  function reportSyncCheck(root, targets, out, retired = []) {
629
- const results = checkTargets(root, targets);
630
- const bad = results.filter(item => item.status !== 'ok');
631
- for (const file of retired) out(`HFS_SYNC_DRIFT ${file}: retired, ${retiredReason(file)}; run "npx starci app sync --write" to delete it`);
632
- for (const result of bad) {
633
- const found = result.actualHash ? `, found ${result.actualHash.slice(0, 12)}` : '';
634
- const where = result.difference ? ` (line ${result.difference.line}: expected ${JSON.stringify(result.difference.expected)}, found ${JSON.stringify(result.difference.actual)})` : '';
635
- out(`HFS_SYNC_DRIFT ${result.path}: ${result.status}, expected sha256 ${result.expectedHash.slice(0, 12)}${found}${where}`);
636
- }
637
- out(`starci app sync --check: ${results.length - bad.length} of ${results.length} in sync${bad.length ? '; run "npx starci app sync --write"' : ''}`);
638
- return bad.length || retired.length ? 1 : 0;
639
- }
640
-
641
- export async function runSync(argv, { cwd = process.cwd(), out = line => process.stdout.write(`${line}\n`), presets, parseYaml } = {}) {
642
- const options = syncOptions(argv);
643
- if (!options) {
644
- out('usage: starci app sync (--check | --write) [--cwd <dir>]');
645
- return 2;
646
- }
647
- const { write, cwdAt } = options;
648
- const root = cwdAt >= 0 ? path.resolve(cwd, argv[cwdAt + 1]) : cwd;
649
- try {
650
- const notices = [];
651
- const { hfs, targets } = await renderRepo(root, { presets, parseYaml, notices });
652
- const retired = retiredFiles(root, hfs);
653
- if (targets.some(target => target.path === 'README.md')) for (const notice of new Set(notices)) out(notice);
654
- if (write) {
655
- const written = writeTargets(root, targets);
656
- for (const file of written) out(`wrote ${file}`);
657
- for (const file of retired) { fs.rmSync(path.join(root, file)); out(`removed ${file} (retired)`); }
658
- for (const dir of LITE_RETIRED_DIRS) if (retired.length && fs.existsSync(path.join(root, dir)) && !fs.readdirSync(path.join(root, dir)).length) fs.rmdirSync(path.join(root, dir));
659
- out(`starci app sync: ${written.length} written, ${targets.length - written.length} already in sync`);
660
- return 0;
640
+ const results = checkTargets(root, targets);
641
+ const bad = results.filter(item => item.status !== 'ok');
642
+ for (const file of retired)
643
+ out(`HFS_SYNC_DRIFT ${file}: retired, ${retiredReason(file)}; run "npx --no-install starci app sync --execute" to delete it`);
644
+ for (const result of bad) {
645
+ const found = result.actualHash ? `, found ${result.actualHash.slice(0, 12)}` : '';
646
+ const where = result.difference ? ` (line ${result.difference.line}: expected ${JSON.stringify(result.difference.expected)}, found ${JSON.stringify(result.difference.actual)})` : '';
647
+ out(`HFS_SYNC_DRIFT ${result.path}: ${result.status}, expected sha256 ${result.expectedHash.slice(0, 12)}${found}${where}`);
648
+ }
649
+ out(`starci app sync: ${results.length - bad.length} of ${results.length} in sync${bad.length ? '; run "npx --no-install starci app sync --execute"' : ''}`);
650
+ return bad.length || retired.length ? 1 : 0;
651
+ }
652
+ export async function runSync(argv, { cwd = process.cwd(), out = (line) => process.stdout.write(`${line}\n`), presets, parseYaml } = {}) {
653
+ const options = syncOptions(argv);
654
+ if (!options) {
655
+ out('usage: starci app sync [--execute] [--cwd <dir>]');
656
+ return 2;
657
+ }
658
+ const { write, cwdAt } = options;
659
+ const root = cwdAt >= 0 ? path.resolve(cwd, argv[cwdAt + 1]) : cwd;
660
+ try {
661
+ const notices = [];
662
+ const { hfs, targets } = await renderRepo(root, { presets, parseYaml, notices });
663
+ const retired = retiredFiles(root, hfs);
664
+ if (targets.some(target => target.path === 'README.md'))
665
+ for (const notice of new Set(notices))
666
+ out(notice);
667
+ if (write) {
668
+ const written = writeTargets(root, targets);
669
+ for (const file of written)
670
+ out(`wrote ${file}`);
671
+ for (const file of retired) {
672
+ fs.rmSync(path.join(root, file));
673
+ out(`removed ${file} (retired)`);
674
+ }
675
+ for (const dir of LITE_RETIRED_DIRS)
676
+ if (retired.length && fs.existsSync(path.join(root, dir)) && !fs.readdirSync(path.join(root, dir)).length)
677
+ fs.rmdirSync(path.join(root, dir));
678
+ out(`starci app sync: ${written.length} written, ${targets.length - written.length} already in sync`);
679
+ return 0;
680
+ }
681
+ return reportSyncCheck(root, targets, out, retired);
682
+ }
683
+ catch (error) {
684
+ if (!(error instanceof SyncError))
685
+ throw error;
686
+ out(error.message);
687
+ return 1;
661
688
  }
662
- return reportSyncCheck(root, targets, out, retired);
663
- } catch (error) {
664
- if (!(error instanceof SyncError)) throw error;
665
- out(error.message);
666
- return 1;
667
- }
668
689
  }