@warpgogol/werkstatt-shared 0.14.0 → 0.15.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 (437) hide show
  1. package/README.md +31 -13
  2. package/README.uk.md +25 -15
  3. package/package.json +519 -762
  4. package/src/{share/agent → agent}/ard-catalog.ts +6 -1
  5. package/src/{share/agent → agent}/dns-aid.test.ts +2 -2
  6. package/src/{share/agent → agent}/manifest.ts +15 -1
  7. package/src/{share/agent → agent}/search.ts +6 -1
  8. package/src/{share → agent}/tests/api-catalog.test.ts +2 -2
  9. package/src/{share → agent}/tests/ard-catalog.test.ts +2 -2
  10. package/src/{share → agent}/tests/capability.test.ts +1 -1
  11. package/src/{share → agent}/tests/fleet-catalog.test.ts +1 -1
  12. package/src/{share → agent}/tests/knowledge.test.ts +2 -2
  13. package/src/{share → agent}/tests/manifest.test.ts +1 -1
  14. package/src/{share → agent}/tests/mcp-card.test.ts +2 -2
  15. package/src/agent/tests/omit-empty.test.ts +33 -0
  16. package/src/{share → agent}/tests/openapi.test.ts +2 -2
  17. package/src/{share → agent}/tests/proof.test.ts +1 -1
  18. package/src/{share → attribution}/material-credits.ts +4 -4
  19. package/src/{share → checks}/check-hints.ts +6 -1
  20. package/src/checks/index.ts +4 -1
  21. package/src/checks/lib/astro-site-url.ts +6 -1
  22. package/src/checks/lib/i18n.ts +14 -0
  23. package/src/checks/result-helpers.ts +22 -5
  24. package/src/checks/tests/remediation-auto-populate.test.ts +83 -0
  25. package/src/{share → client-scripts}/counter-utils.ts +6 -2
  26. package/src/{share/scripts → client-scripts}/external-link-qr.ts +11 -16
  27. package/src/{share/scripts → client-scripts}/external-links.ts +12 -1
  28. package/src/{share/scripts → client-scripts}/gsap-counter.ts +8 -3
  29. package/src/client-scripts/index.ts +35 -0
  30. package/src/{share/scripts → client-scripts}/inline-number-animation.ts +1 -1
  31. package/src/{share/scripts → client-scripts}/lenis.ts +6 -1
  32. package/src/{share/scripts → client-scripts}/lordicon.ts +6 -1
  33. package/src/{share/scripts → client-scripts}/orchestrator.ts +10 -1
  34. package/src/{share/scripts → client-scripts}/scheduler.ts +6 -1
  35. package/src/client-scripts/scroll-spy.ts +106 -0
  36. package/src/client-scripts/tests/external-link-qr.test.ts +8 -0
  37. package/src/client-scripts/tests/external-links.test.ts +25 -0
  38. package/src/client-scripts/tests/gsap-counter.test.ts +8 -0
  39. package/src/client-scripts/tests/gsap-mountain-journey.test.ts +8 -0
  40. package/src/client-scripts/tests/gsap-parallax.test.ts +8 -0
  41. package/src/client-scripts/tests/gsap-reveal.test.ts +8 -0
  42. package/src/client-scripts/tests/gsap-stagger.test.ts +8 -0
  43. package/src/client-scripts/tests/inline-number-animation.test.ts +8 -0
  44. package/src/client-scripts/tests/lenis.test.ts +8 -0
  45. package/src/client-scripts/tests/live-photos.test.ts +8 -0
  46. package/src/client-scripts/tests/lordicon.test.ts +8 -0
  47. package/src/client-scripts/tests/orchestrator.test.ts +47 -0
  48. package/src/client-scripts/tests/scheduler.test.ts +23 -0
  49. package/src/client-scripts/tests/scroll-spy.test.ts +204 -0
  50. package/src/{share/scripts → client-scripts/tests}/video-player.test.ts +51 -31
  51. package/src/component/contracts.ts +206 -0
  52. package/src/component/index.ts +11 -0
  53. package/src/{share → content}/content-reference.ts +3 -3
  54. package/src/{share/content → content}/entity-id.ts +6 -3
  55. package/src/content/index.ts +3 -0
  56. package/src/{share/content → content}/merge.ts +6 -1
  57. package/src/content/system-manifest.test.ts +107 -0
  58. package/src/content/system-manifest.ts +12 -94
  59. package/src/{share → content}/tests/resolve-field-path.test.ts +1 -1
  60. package/src/{share → content}/tests/substitute-deep.test.ts +1 -1
  61. package/src/content-discipline/index.ts +19 -0
  62. package/src/{share/content-discipline → content-discipline}/parsers.ts +2 -2
  63. package/src/{share/env.d.ts → env.d.ts} +6 -3
  64. package/src/fingerprint/canonical-json.ts +731 -0
  65. package/src/fingerprint/index.ts +12 -0
  66. package/src/fingerprint/primitives.ts +72 -0
  67. package/src/{share/i18n → i18n}/localization.ts +6 -2
  68. package/src/integration/adapters.ts +10 -71
  69. package/src/integration/dispatch.ts +1 -1
  70. package/src/integration/funnel.ts +6 -1
  71. package/src/integration/index.ts +101 -4
  72. package/src/integration/lagebild-destination-adapter.ts +108 -0
  73. package/src/integration/lagebild-ingress.ts +7 -12
  74. package/src/integration/orchestration.ts +11 -10
  75. package/src/integration/tests/deliver-event.test.ts +1 -1
  76. package/src/integration/tests/dispatch.test.ts +4 -4
  77. package/src/integration/tests/hub-runtime.test.ts +22 -14
  78. package/src/integration/vitest.config.ts +8 -0
  79. package/src/kernel/desired-state.ts +227 -0
  80. package/src/kernel/diagnostic.ts +289 -0
  81. package/src/kernel/fs-atomic.ts +131 -0
  82. package/src/kernel/index.ts +15 -0
  83. package/src/kernel/tests/fs-atomic.test.ts +150 -0
  84. package/src/kernel/tests/workspace-io.test.ts +187 -0
  85. package/src/kernel/types.ts +459 -0
  86. package/src/kernel/workspace-io.ts +248 -0
  87. package/src/{share → knowledge}/tests/claim.test.ts +1 -1
  88. package/src/{share → knowledge}/tests/derivation.test.ts +1 -1
  89. package/src/{share → knowledge}/tests/freshness.test.ts +1 -1
  90. package/src/{share → knowledge}/tests/ledger.test.ts +1 -1
  91. package/src/{share → knowledge}/tests/plan.test.ts +1 -1
  92. package/src/{share → knowledge}/tests/source.test.ts +1 -1
  93. package/src/legal/index.ts +15 -0
  94. package/src/{share/middleware → middleware}/access-protection.ts +8 -8
  95. package/src/{share → node}/dev-props-validator.ts +6 -1
  96. package/src/{share → node}/import-scan.ts +23 -3
  97. package/src/{share → node}/semantic/derived-prices-loader.ts +4 -2
  98. package/src/{share → node}/semantic/markdown-twin-provenance.ts +1 -1
  99. package/src/node/tests/derived-prices-loader.test.ts +59 -0
  100. package/src/node/tests/markdown-twin-provenance.test.ts +152 -0
  101. package/src/observability/env-resolver.ts +6 -1
  102. package/src/observability/index.ts +6 -1
  103. package/src/observability/otlp-converter.ts +6 -1
  104. package/src/observability/otlp-transport.ts +6 -1
  105. package/src/observability/pusher.ts +6 -1
  106. package/src/observability/redact.ts +6 -1
  107. package/src/observability/typed-refs.ts +6 -2
  108. package/src/observability/vitest.config.ts +1 -0
  109. package/src/{share → offers}/formula-eval.ts +3 -3
  110. package/src/{share → offers}/tests/formula-eval.test.ts +2 -2
  111. package/src/onboarding/index.ts +1 -0
  112. package/src/{share → onboarding}/tests/onboarding-yaml.test.ts +1 -1
  113. package/src/ontology/archetype-registry.ts +6 -1
  114. package/src/ontology/archetypes/index.json +33 -1
  115. package/src/ontology/archetypes/index.yaml +27 -1
  116. package/src/ontology/archetypes/sections/entity-grid.yaml +46 -0
  117. package/src/ontology/archetypes/sections/exit-diagram.yaml +43 -0
  118. package/src/ontology/biome-token-projection.ts +6 -1
  119. package/src/ontology/cosmic/index.ts +6 -1
  120. package/src/ontology/cosmic/moon-catalog.ts +6 -1
  121. package/src/ontology/cosmic/planet-catalog.ts +6 -1
  122. package/src/ontology/cosmic/star-catalog.ts +6 -1
  123. package/src/ontology/enums.ts +6 -1
  124. package/src/ontology/external-surfaces/index.ts +1 -1
  125. package/src/ontology/index.ts +6 -2
  126. package/src/ontology/manifest.ts +26 -4
  127. package/src/ontology/operations/artifact-store.ts +45 -0
  128. package/src/ontology/operations/dht.ts +98 -0
  129. package/src/ontology/operations/handoff.ts +92 -0
  130. package/src/ontology/operations/index.ts +187 -1
  131. package/src/ontology/operations/leitstand.ts +99 -0
  132. package/src/ontology/operations/materialization.ts +90 -0
  133. package/src/ontology/operations/mission.ts +111 -0
  134. package/src/ontology/operations/naming-policy.ts +132 -0
  135. package/src/ontology/operations/notausgang.ts +64 -0
  136. package/src/ontology/operations/release.ts +121 -0
  137. package/src/ontology/operations/sternsystem.ts +192 -0
  138. package/src/ontology/operations/werkstatt.ts +48 -0
  139. package/src/ontology/schemas/biome.ts +7 -2
  140. package/src/ontology/schemas/capability.ts +1 -1
  141. package/src/ontology/schemas/constellation.ts +6 -1
  142. package/src/ontology/schemas/index.ts +6 -2
  143. package/src/ontology/schemas/manifest-resolver.ts +6 -1
  144. package/src/ontology/schemas/page-entry.ts +9 -5
  145. package/src/ontology/schemas/system/growth.ts +6 -1
  146. package/src/ontology/schemas/system/manifest.ts +40 -1
  147. package/src/ontology/schemas/system/page-output.ts +7 -6
  148. package/src/ontology/schemas/system/tests/growth.test.ts +22 -0
  149. package/src/ontology/schemas/system/tests/integrations.test.ts +12 -0
  150. package/src/ontology/schemas/system/tests/manifest.test.ts +22 -0
  151. package/src/ontology/schemas/system/tests/page-output.test.ts +13 -0
  152. package/src/ontology/schemas/system/tests/release.test.ts +22 -0
  153. package/src/ontology/schemas/system/tests/text.test.ts +18 -0
  154. package/src/ontology/schemas/system/tests/verification.test.ts +12 -0
  155. package/src/ontology/schemas/system/text.ts +15 -0
  156. package/src/ontology/schemas/system.ts +6 -2
  157. package/src/ontology/schemas/tests/biome.test.ts +19 -0
  158. package/src/ontology/schemas/tests/capability.test.ts +22 -0
  159. package/src/ontology/schemas/tests/constellation.test.ts +22 -0
  160. package/src/ontology/schemas/tests/dns-records.test.ts +13 -0
  161. package/src/ontology/schemas/tests/manifest-resolver.test.ts +13 -0
  162. package/src/ontology/schemas/tests/page-entry.test.ts +22 -0
  163. package/src/ontology/schemas/tests/section-archetype.test.ts +12 -0
  164. package/src/ontology/schemas/tests/site-family.test.ts +18 -0
  165. package/src/ontology/schemas/tests/system.test.ts +20 -0
  166. package/src/ontology/shared-section-props/body-fragments.ts +2 -0
  167. package/src/ontology/tests/sternsystem-owner.test.ts +1 -1
  168. package/src/ontology/vitest.config.ts +1 -0
  169. package/src/{share → page}/page.ts +13 -9
  170. package/src/{share → page}/tests/dev-props-validator.test.ts +1 -1
  171. package/src/{share → page}/tests/hero-section-numbering-parity.test.ts +1 -1
  172. package/src/passport/index.ts +6 -1
  173. package/src/passport/key-rotate.ts +10 -2
  174. package/src/passport/schema.ts +6 -1
  175. package/src/passport/sign.ts +8 -3
  176. package/src/passport/vitest.config.ts +1 -0
  177. package/src/pbt/index.test.ts +95 -0
  178. package/src/pbt/index.ts +251 -0
  179. package/src/plugin/plugin-contract.ts +1 -1
  180. package/src/{share → policy}/entitlement.ts +24 -4
  181. package/src/{share → policy}/feature-policy.ts +8 -3
  182. package/src/{share → policy}/visibility.ts +7 -2
  183. package/src/redirects/redirects.ts +117 -0
  184. package/src/{share → redirects/tests}/redirects.test.ts +1 -1
  185. package/src/remediation/remediation-catalog.ts +316 -0
  186. package/src/{share/routes → routes}/template-filter.ts +1 -1
  187. package/src/{share → runtime}/runtime-context.ts +7 -2
  188. package/src/{share → runtime}/shared-context.ts +1 -1
  189. package/src/{share/schemas → schemas}/claims.ts +2 -2
  190. package/src/{share/schemas → schemas}/effects.ts +6 -1
  191. package/src/{share/schemas → schemas}/features.ts +1 -1
  192. package/src/{share/schemas → schemas}/index.ts +3 -3
  193. package/src/{share/schemas → schemas}/navigation.ts +6 -1
  194. package/src/{share/schemas → schemas}/page-base.ts +6 -2
  195. package/src/{share/schemas → schemas}/person.ts +1 -1
  196. package/src/{share/schemas → schemas}/standard-list-item.ts +1 -1
  197. package/src/schemas/tests/claim-records.test.ts +52 -0
  198. package/src/schemas/tests/claims.test.ts +23 -0
  199. package/src/schemas/tests/effects.test.ts +116 -0
  200. package/src/schemas/tests/features.test.ts +61 -0
  201. package/src/schemas/tests/horizontal-align.test.ts +16 -0
  202. package/src/schemas/tests/icon-color.test.ts +16 -0
  203. package/src/schemas/tests/live-photo.test.ts +40 -0
  204. package/src/schemas/tests/material-credit.test.ts +51 -0
  205. package/src/schemas/tests/media.test.ts +26 -0
  206. package/src/schemas/tests/navigation.test.ts +58 -0
  207. package/src/schemas/tests/page-base.test.ts +19 -0
  208. package/src/schemas/tests/participant.test.ts +26 -0
  209. package/src/schemas/tests/person.test.ts +12 -0
  210. package/src/schemas/tests/print.test.ts +30 -0
  211. package/src/schemas/tests/section-background.test.ts +31 -0
  212. package/src/schemas/tests/section-body.test.ts +16 -0
  213. package/src/schemas/tests/section-cards.test.ts +17 -0
  214. package/src/schemas/tests/section-cta.test.ts +41 -0
  215. package/src/schemas/tests/section-header.test.ts +31 -0
  216. package/src/schemas/tests/section-image.test.ts +24 -0
  217. package/src/schemas/tests/section-motion.test.ts +29 -0
  218. package/src/schemas/tests/section-shell.test.ts +42 -0
  219. package/src/schemas/tests/section-stats.test.ts +17 -0
  220. package/src/schemas/tests/site-background.test.ts +33 -0
  221. package/src/schemas/tests/standard-list-item.test.ts +16 -0
  222. package/src/{share → sections}/rfc0042-utils.ts +1 -1
  223. package/src/{share/semantic → semantic}/block-extractors/index.ts +20 -1
  224. package/src/{share/semantic → semantic}/business-projection.ts +95 -1
  225. package/src/semantic/canonical-uri.ts +54 -0
  226. package/src/{share/semantic → semantic}/extract.ts +100 -1
  227. package/src/semantic/fact-extraction.test.ts +47 -0
  228. package/src/semantic/fact-extraction.ts +46 -0
  229. package/src/semantic/freshness.ts +67 -0
  230. package/src/{share/semantic → semantic}/ids.ts +6 -1
  231. package/src/{share/semantic → semantic}/index.ts +9 -2
  232. package/src/{share/semantic → semantic}/jsonld/breadcrumb.ts +6 -2
  233. package/src/{share/semantic → semantic}/jsonld/context.ts +6 -2
  234. package/src/{share/semantic → semantic}/jsonld/faq.ts +6 -2
  235. package/src/{share/semantic → semantic}/jsonld/initiative.ts +6 -1
  236. package/src/{share/semantic → semantic}/jsonld/organization.ts +6 -1
  237. package/src/{share/semantic → semantic}/jsonld/person.ts +6 -2
  238. package/src/{share/semantic → semantic}/jsonld/service.ts +6 -2
  239. package/src/semantic/jsonld/shared.ts +36 -0
  240. package/src/semantic/jsonld/tests/article.test.ts +89 -0
  241. package/src/semantic/jsonld/tests/breadcrumb.test.ts +62 -0
  242. package/src/semantic/jsonld/tests/collection-list.test.ts +39 -0
  243. package/src/semantic/jsonld/tests/faq.test.ts +60 -0
  244. package/src/semantic/jsonld/tests/initiative.test.ts +56 -0
  245. package/src/semantic/jsonld/tests/organization.test.ts +123 -0
  246. package/src/semantic/jsonld/tests/person.test.ts +89 -0
  247. package/src/semantic/jsonld/tests/service.test.ts +65 -0
  248. package/src/semantic/jsonld/tests/shared.test.ts +41 -0
  249. package/src/semantic/jsonld/tests/video.test.ts +84 -0
  250. package/src/semantic/jsonld/tests/webpage.test.ts +93 -0
  251. package/src/semantic/jsonld/tests/website.test.ts +27 -0
  252. package/src/semantic/jsonld/types.ts +24 -0
  253. package/src/{share/semantic → semantic}/jsonld/webpage.ts +6 -1
  254. package/src/semantic/jsonld/website.ts +32 -0
  255. package/src/{share/semantic → semantic}/jsonld.ts +6 -1
  256. package/src/{share/semantic → semantic}/llms.ts +41 -3
  257. package/src/{share/semantic → semantic}/models.ts +27 -38
  258. package/src/{share/semantic → semantic}/organization-profile.ts +3 -0
  259. package/src/{share/semantic → semantic}/page-builders/markdown-page.ts +6 -3
  260. package/src/{share/semantic → semantic}/page-utils.ts +6 -3
  261. package/src/semantic/tests/ai.test.ts +55 -0
  262. package/src/semantic/tests/block-extraction.test.ts +34 -0
  263. package/src/{share/tests/breadcrumbs.test.ts → semantic/tests/breadcrumbs-0229.test.ts} +1 -1
  264. package/src/semantic/tests/breadcrumbs.test.ts +127 -0
  265. package/src/{share → semantic}/tests/build-page-price-markers.test.ts +2 -2
  266. package/src/semantic/tests/build-page.test.ts +122 -0
  267. package/src/semantic/tests/business-projection.test.ts +367 -0
  268. package/src/semantic/tests/canonical-uri.test.ts +56 -0
  269. package/src/semantic/tests/extract.test.ts +209 -0
  270. package/src/semantic/tests/feed.test.ts +113 -0
  271. package/src/semantic/tests/freshness.pbt.test.ts +108 -0
  272. package/src/semantic/tests/helpers.ts +32 -0
  273. package/src/semantic/tests/ids.test.ts +118 -0
  274. package/src/{share/tests/image-sitemap.test.ts → semantic/tests/image-sitemap-0150.test.ts} +1 -1
  275. package/src/semantic/tests/image-sitemap.test.ts +109 -0
  276. package/src/{share → semantic}/tests/jsonld-service.test.ts +2 -2
  277. package/src/{share → semantic}/tests/jsonld-video.test.ts +3 -3
  278. package/src/{share → semantic}/tests/jsonld-webpage.test.ts +3 -3
  279. package/src/semantic/tests/jsonld.test.ts +61 -0
  280. package/src/{share → semantic}/tests/llms-0789.test.ts +2 -2
  281. package/src/semantic/tests/llms-policy.test.ts +60 -0
  282. package/src/semantic/tests/llms.test.ts +164 -0
  283. package/src/semantic/tests/markdown-hygiene.test.ts +72 -0
  284. package/src/semantic/tests/markdown-page.test.ts +97 -0
  285. package/src/{share → semantic}/tests/organization-jsonld.test.ts +3 -3
  286. package/src/semantic/tests/organization-profile.test.ts +107 -0
  287. package/src/{share/tests/output-projection.test.ts → semantic/tests/output-projection-0143.test.ts} +1 -1
  288. package/src/semantic/tests/output-projection.test.ts +77 -0
  289. package/src/semantic/tests/page-markdown.test.ts +98 -0
  290. package/src/semantic/tests/page-utils.test.ts +88 -0
  291. package/src/{share/tests/price-marker-resolver.test.ts → semantic/tests/price-marker-resolver-0767.test.ts} +2 -2
  292. package/src/semantic/tests/price-marker-resolver.test.ts +90 -0
  293. package/src/semantic/tests/project-claims.pbt.test.ts +60 -0
  294. package/src/semantic/tests/robots.test.ts +70 -0
  295. package/src/{share/semantic → semantic}/tests/split-sentences.test.ts +1 -1
  296. package/src/{share → semantic}/tests/twin-path.test.ts +1 -1
  297. package/src/semantic/tests/update-stamp.test.ts +102 -0
  298. package/src/signing/index.ts +13 -0
  299. package/src/signing/key.ts +139 -0
  300. package/src/signing/sign.ts +66 -0
  301. package/src/signing/types.ts +29 -0
  302. package/src/{share/slug → slug}/slug-url.ts +4 -1
  303. package/src/stack/run-tool.ts +108 -0
  304. package/src/stack/stack-checks.ts +124 -0
  305. package/src/stack/tests/run-tool.test.ts +138 -0
  306. package/src/stack/tests/stack-checks.test.ts +141 -0
  307. package/src/stack/tests/walk-files.test.ts +131 -0
  308. package/src/stack/walk-files.ts +114 -0
  309. package/src/surface/blueprint.ts +342 -66
  310. package/src/surface/decision-composer.ts +6 -1
  311. package/src/surface/geo.ts +6 -1
  312. package/src/surface/index.ts +11 -7
  313. package/src/surface/types.ts +2 -2
  314. package/src/surface/vitest.config.ts +1 -0
  315. package/src/tests/signing-core.test.ts +129 -0
  316. package/src/{share → text}/css-value-normalize.ts +6 -1
  317. package/src/text/string-utils.ts +24 -0
  318. package/src/{share → text}/tests/text-normalize.test.ts +5 -0
  319. package/src/{share → text}/text-normalize.ts +4 -3
  320. package/src/{share → text}/wrap-inline-numbers.ts +1 -1
  321. package/src/types/axiom-study.d.ts +36 -0
  322. package/src/types/hls-js-light.d.ts +21 -0
  323. package/src/types/qrcode-browser.d.ts +23 -0
  324. package/src/typography/fix.pbt.test.ts +208 -0
  325. package/src/typography/fix.ts +148 -0
  326. package/src/typography/index.ts +54 -0
  327. package/src/typography/locale-defaults.ts +97 -0
  328. package/src/typography/rules-tier1.test.ts +459 -0
  329. package/src/typography/rules-tier1.ts +925 -0
  330. package/src/typography/rules-tier2-locale.pbt.test.ts +190 -0
  331. package/src/typography/rules-tier2-locale.test.ts +286 -0
  332. package/src/typography/rules-tier2-locale.ts +399 -0
  333. package/src/typography/rules-tier2-structure.test.ts +330 -0
  334. package/src/typography/rules-tier2-structure.ts +378 -0
  335. package/src/typography/rules-tier3-advisory.test.ts +290 -0
  336. package/src/typography/rules-tier3-advisory.ts +239 -0
  337. package/src/typography/text-surface.test.ts +244 -0
  338. package/src/typography/text-surface.ts +448 -0
  339. package/src/index.ts +0 -14
  340. package/src/integration/port-barrel.ts +0 -105
  341. package/src/share/content/index.ts +0 -16
  342. package/src/share/content-discipline/index.ts +0 -14
  343. package/src/share/index.ts +0 -86
  344. package/src/share/legal/index.ts +0 -1
  345. package/src/share/redirects.ts +0 -54
  346. package/src/share/scripts/index.ts +0 -26
  347. package/src/share/semantic/jsonld/shared.ts +0 -31
  348. package/src/share/semantic/jsonld/types.ts +0 -18
  349. package/src/share/semantic/jsonld/website.ts +0 -27
  350. package/src/share/string-utils.ts +0 -19
  351. package/src/share/types/axiom-study.d.ts +0 -22
  352. package/src/share/types/hls-js-light.d.ts +0 -16
  353. package/src/share/types/qrcode-browser.d.ts +0 -18
  354. package/src/share/utility-registry.yaml +0 -36
  355. package/src/share/vitest.config.ts +0 -8
  356. package/src/surface/blueprint-schema.ts +0 -314
  357. package/src/surface/blueprint-types.ts +0 -256
  358. /package/src/{share/agent → agent}/api-catalog.ts +0 -0
  359. /package/src/{share/agent → agent}/capability.ts +0 -0
  360. /package/src/{share/agent → agent}/dns-aid.ts +0 -0
  361. /package/src/{share/agent → agent}/fleet-catalog.ts +0 -0
  362. /package/src/{share/agent → agent}/index.ts +0 -0
  363. /package/src/{share/agent → agent}/knowledge.ts +0 -0
  364. /package/src/{share/agent → agent}/mcp-card.ts +0 -0
  365. /package/src/{share/agent → agent}/omit-empty.ts +0 -0
  366. /package/src/{share/agent → agent}/openapi.ts +0 -0
  367. /package/src/{share/agent → agent}/proof.ts +0 -0
  368. /package/src/{share/agent → agent}/search.test.ts +0 -0
  369. /package/src/{share → attribution}/attribution-display.ts +0 -0
  370. /package/src/{share/scripts → client-scripts}/gsap-mountain-journey.ts +0 -0
  371. /package/src/{share/scripts → client-scripts}/gsap-parallax.ts +0 -0
  372. /package/src/{share/scripts → client-scripts}/gsap-reveal.ts +0 -0
  373. /package/src/{share/scripts → client-scripts}/gsap-stagger.ts +0 -0
  374. /package/src/{share/scripts → client-scripts}/live-photos.ts +0 -0
  375. /package/src/{share/scripts → client-scripts}/video-player.ts +0 -0
  376. /package/src/{share/content → content}/resolve-field-path.ts +0 -0
  377. /package/src/{share/content → content}/substitute-deep.ts +0 -0
  378. /package/src/{share → content}/tests/content-ref-index.test.ts +0 -0
  379. /package/src/{share/content-discipline → content-discipline}/types.ts +0 -0
  380. /package/src/{share → image-provider}/image-provider.ts +0 -0
  381. /package/src/{share/knowledge → knowledge}/claim.ts +0 -0
  382. /package/src/{share/knowledge → knowledge}/derivation.ts +0 -0
  383. /package/src/{share/knowledge → knowledge}/freshness.ts +0 -0
  384. /package/src/{share/knowledge → knowledge}/index.ts +0 -0
  385. /package/src/{share/knowledge → knowledge}/ledger.ts +0 -0
  386. /package/src/{share/knowledge → knowledge}/plan.ts +0 -0
  387. /package/src/{share/knowledge → knowledge}/source.ts +0 -0
  388. /package/src/{share/legal → legal}/translation-policy.ts +0 -0
  389. /package/src/{share/middleware → middleware}/language-redirect.ts +0 -0
  390. /package/src/{share/middleware → middleware}/tests/access-protection.test.ts +0 -0
  391. /package/src/{share → node}/fs/index.ts +0 -0
  392. /package/src/{share/tests/markdown-twin-provenance.test.ts → node/tests/markdown-twin-provenance-0613.test.ts} +0 -0
  393. /package/src/{share → offers}/offer-capacity.ts +0 -0
  394. /package/src/{share/onboarding-yaml/index.ts → onboarding/yaml.ts} +0 -0
  395. /package/src/{share → ontology}/tests/ontology-role-by-cosmic-name.test.ts +0 -0
  396. /package/src/{share/routes → routes}/tests/template-filter.test.ts +0 -0
  397. /package/src/{share/schemas → schemas}/claim-records.ts +0 -0
  398. /package/src/{share/schemas → schemas}/horizontal-align.ts +0 -0
  399. /package/src/{share/schemas → schemas}/icon-color.ts +0 -0
  400. /package/src/{share/schemas → schemas}/live-photo.ts +0 -0
  401. /package/src/{share/schemas → schemas}/material-credit.ts +0 -0
  402. /package/src/{share/schemas → schemas}/media.ts +0 -0
  403. /package/src/{share/schemas → schemas}/participant.ts +0 -0
  404. /package/src/{share/schemas → schemas}/print.ts +0 -0
  405. /package/src/{share/schemas → schemas}/section-background.ts +0 -0
  406. /package/src/{share/schemas → schemas}/section-body.ts +0 -0
  407. /package/src/{share/schemas → schemas}/section-cards.ts +0 -0
  408. /package/src/{share/schemas → schemas}/section-cta.ts +0 -0
  409. /package/src/{share/schemas → schemas}/section-header.ts +0 -0
  410. /package/src/{share/schemas → schemas}/section-image.ts +0 -0
  411. /package/src/{share/schemas → schemas}/section-motion.ts +0 -0
  412. /package/src/{share/schemas → schemas}/section-shell.ts +0 -0
  413. /package/src/{share/schemas → schemas}/section-stats.ts +0 -0
  414. /package/src/{share/schemas → schemas}/site-background.ts +0 -0
  415. /package/src/{share/semantic → semantic}/ai.ts +0 -0
  416. /package/src/{share/semantic → semantic}/block-extraction.ts +0 -0
  417. /package/src/{share/semantic → semantic}/breadcrumbs.ts +0 -0
  418. /package/src/{share/semantic → semantic}/build-page.ts +0 -0
  419. /package/src/{share/semantic → semantic}/feed.ts +0 -0
  420. /package/src/{share/semantic → semantic}/image-sitemap.ts +0 -0
  421. /package/src/{share/semantic → semantic}/jsonld/article.ts +0 -0
  422. /package/src/{share/semantic → semantic}/jsonld/collection-list.ts +0 -0
  423. /package/src/{share/semantic → semantic}/jsonld/video.ts +0 -0
  424. /package/src/{share/semantic → semantic}/llms-policy.ts +0 -0
  425. /package/src/{share/semantic → semantic}/markdown-hygiene.ts +0 -0
  426. /package/src/{share/semantic → semantic}/output-projection.ts +0 -0
  427. /package/src/{share/semantic → semantic}/page-markdown.ts +0 -0
  428. /package/src/{share/semantic → semantic}/price-marker-resolver.ts +0 -0
  429. /package/src/{share/semantic → semantic}/robots.ts +0 -0
  430. /package/src/{share/semantic → semantic}/update-stamp.ts +0 -0
  431. /package/src/{share/slug → slug}/heading-slugger.ts +0 -0
  432. /package/src/{share/slug → slug}/index.ts +0 -0
  433. /package/src/{share/slug → slug}/slug-id.ts +0 -0
  434. /package/src/{share/slug → slug}/strategies.ts +0 -0
  435. /package/src/{share/slug → slug}/tests/slug.test.ts +0 -0
  436. /package/src/{share → text}/tests/text-normalize.pbt.test.ts +0 -0
  437. /package/src/{share → text}/text-position.ts +0 -0
@@ -0,0 +1,102 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import {
3
+ isValidStampDate,
4
+ resolveAuthoredStamp,
5
+ resolveCklStamp,
6
+ resolvePageUpdateStamp,
7
+ } from "../update-stamp.ts";
8
+
9
+ describe("isValidStampDate", () => {
10
+ it("accepts YYYY-MM-DD", () => {
11
+ expect(isValidStampDate("2024-01-15")).toBe(true);
12
+ });
13
+
14
+ it("rejects non-string", () => {
15
+ expect(isValidStampDate(20240115)).toBe(false);
16
+ });
17
+
18
+ it("rejects wrong format", () => {
19
+ expect(isValidStampDate("2024/01/15")).toBe(false);
20
+ expect(isValidStampDate("January 15, 2024")).toBe(false);
21
+ });
22
+ });
23
+
24
+ describe("resolveAuthoredStamp", () => {
25
+ it("uses output.sitemap.lastmod first", () => {
26
+ const result = resolveAuthoredStamp({
27
+ output: { sitemap: { lastmod: "2024-06-01" } },
28
+ });
29
+ expect(result?.date).toBe("2024-06-01");
30
+ expect(result?.source).toBe("authored-system-output");
31
+ });
32
+
33
+ it("uses article.updatedAt when no sitemap lastmod", () => {
34
+ const result = resolveAuthoredStamp({
35
+ article: { updatedAt: "2024-05-01" },
36
+ });
37
+ expect(result?.date).toBe("2024-05-01");
38
+ expect(result?.source).toBe("authored-page-frontmatter");
39
+ });
40
+
41
+ it("uses article.publishedAt when no updatedAt", () => {
42
+ const result = resolveAuthoredStamp({
43
+ article: { publishedAt: "2024-01-01" },
44
+ });
45
+ expect(result?.date).toBe("2024-01-01");
46
+ });
47
+
48
+ it("returns undefined when no valid dates", () => {
49
+ expect(resolveAuthoredStamp({})).toBeUndefined();
50
+ });
51
+
52
+ it("ignores invalid date formats", () => {
53
+ expect(resolveAuthoredStamp({ article: { updatedAt: "not-a-date" } })).toBeUndefined();
54
+ });
55
+ });
56
+
57
+ describe("resolveCklStamp", () => {
58
+ it("returns latest valid date", () => {
59
+ const result = resolveCklStamp(["2024-01-01", "2024-06-15", "2024-03-01"], ["ledger"]);
60
+ expect(result?.date).toBe("2024-06-15");
61
+ expect(result?.source).toBe("ckl-claim-ledger");
62
+ });
63
+
64
+ it("returns undefined when no valid dates", () => {
65
+ expect(resolveCklStamp(["invalid"], ["ledger"])).toBeUndefined();
66
+ });
67
+ });
68
+
69
+ describe("resolvePageUpdateStamp", () => {
70
+ it("prefers authored stamp over CKL", () => {
71
+ const result = resolvePageUpdateStamp({
72
+ pageId: "p1",
73
+ lang: "de",
74
+ pageEntry: { output: { sitemap: { lastmod: "2024-06-01" } } },
75
+ cklLedgerDates: ["2024-01-01"],
76
+ });
77
+ expect(result.stamp?.date).toBe("2024-06-01");
78
+ expect(result.stamp?.source).toBe("authored-system-output");
79
+ });
80
+
81
+ it("falls back to CKL when no authored stamp", () => {
82
+ const result = resolvePageUpdateStamp({
83
+ pageId: "p1",
84
+ lang: "de",
85
+ pageEntry: {},
86
+ cklLedgerDates: ["2024-03-01"],
87
+ cklInputs: ["ledger"],
88
+ });
89
+ expect(result.stamp?.date).toBe("2024-03-01");
90
+ expect(result.stamp?.source).toBe("ckl-claim-ledger");
91
+ });
92
+
93
+ it("returns missingReason when no sources available", () => {
94
+ const result = resolvePageUpdateStamp({
95
+ pageId: "p1",
96
+ lang: "de",
97
+ pageEntry: {},
98
+ });
99
+ expect(result.stamp).toBeUndefined();
100
+ expect(result.missingReason).toBe("no-content-source");
101
+ });
102
+ });
@@ -0,0 +1,13 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>Barrel export for @warpgogol/werkstatt-shared/signing sub-path. Re-exports the Ed25519 signing core (key generation, sign/verify, signing types) sunk from @warpgogol/werkstatt-engine per RFC-1104.</purpose>
4
+ <non-goals>Does not re-export engine signing commands (signing-commands.ts stays in engine).</non-goals>
5
+ </MODULE_CONTRACT>
6
+ <CHANGE_SUMMARY>
7
+ <item>RFC-1104: initial barrel — signing core sunk from werkstatt-engine.</item>
8
+ </CHANGE_SUMMARY>
9
+ */
10
+
11
+ export * from "./types.ts";
12
+ export * from "./key.ts";
13
+ export * from "./sign.ts";
@@ -0,0 +1,139 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>RFC-0921: Shared Ed25519 key management — generation, loading, saving, and encoding helpers.</purpose>
4
+
5
+
6
+ <non-goals>
7
+ <item>Does not implement signing or verification — those live in sign.ts.</item>
8
+ <item>Does not manage key publication or key rotation — domain-specific concerns belong in consumers.</item>
9
+ </non-goals>
10
+ </MODULE_CONTRACT>
11
+ <CHANGE_SUMMARY>
12
+ <item>RFC-0921: initial signing key management module.</item>
13
+ <item>RFC-1097: step 6 — compass.migrate codemod run
14
+
15
+ Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.</item>
16
+ <item>RFC-1097: sweep — werkstatt-engine clean
17
+
18
+ Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.</item>
19
+ </CHANGE_SUMMARY>
20
+ */
21
+
22
+ import fs from "node:fs/promises";
23
+ import { existsSync } from "node:fs";
24
+ import path from "node:path";
25
+ import { createPrivateKey, createPublicKey } from "node:crypto";
26
+ import * as ed from "@noble/ed25519";
27
+ import type { KeyEncoding, SigningKeyPair } from "./types.ts";
28
+
29
+ export async function generateKeyPair(): Promise<SigningKeyPair> {
30
+ const privateKey = ed.utils.randomSecretKey();
31
+ const publicKey = await getPublicKey(privateKey);
32
+ return { privateKey, publicKey };
33
+ }
34
+
35
+ export async function getPublicKey(privateKey: Uint8Array): Promise<Uint8Array> {
36
+ return ed.getPublicKeyAsync(privateKey);
37
+ }
38
+
39
+ export async function loadPrivateKey(
40
+ source: { pem: string } | { hex: string } | { filePath: string; encoding: KeyEncoding },
41
+ ): Promise<Uint8Array> {
42
+ if ("pem" in source) {
43
+ return fromPem(source.pem);
44
+ }
45
+ if ("hex" in source) {
46
+ return fromHex(source.hex);
47
+ }
48
+ const raw = (await fs.readFile(source.filePath, "utf8")).trim();
49
+ if (source.encoding === "pem") {
50
+ return fromPem(raw);
51
+ }
52
+ return fromHex(raw);
53
+ }
54
+
55
+ export async function loadPublicKey(
56
+ source: { pem: string } | { hex: string } | { filePath: string; encoding: KeyEncoding },
57
+ ): Promise<Uint8Array> {
58
+ if ("pem" in source) {
59
+ return fromPem(source.pem);
60
+ }
61
+ if ("hex" in source) {
62
+ return fromHex(source.hex);
63
+ }
64
+ const raw = (await fs.readFile(source.filePath, "utf8")).trim();
65
+ if (source.encoding === "pem") {
66
+ return fromPem(raw);
67
+ }
68
+ return fromHex(raw);
69
+ }
70
+
71
+ export async function saveKeyPair(
72
+ keyPair: SigningKeyPair,
73
+ outputDir: string,
74
+ encoding: KeyEncoding,
75
+ ): Promise<{ privateKeyPath: string; publicKeyPath: string }> {
76
+ await fs.mkdir(outputDir, { recursive: true });
77
+
78
+ const privateKeyPath = path.join(outputDir, `signing.key${encoding === "pem" ? ".pem" : ""}`);
79
+ const publicKeyPath = path.join(outputDir, `signing.key.pub${encoding === "pem" ? ".pem" : ""}`);
80
+
81
+ if (encoding === "pem") {
82
+ await fs.writeFile(privateKeyPath, toPem(keyPair.privateKey, "private"), "utf8");
83
+ await fs.writeFile(publicKeyPath, toPem(keyPair.publicKey, "public"), "utf8");
84
+ } else {
85
+ await fs.writeFile(privateKeyPath, toHex(keyPair.privateKey), "utf8");
86
+ await fs.writeFile(publicKeyPath, toHex(keyPair.publicKey), "utf8");
87
+ }
88
+
89
+ return { privateKeyPath, publicKeyPath };
90
+ }
91
+
92
+ export function toHex(bytes: Uint8Array): string {
93
+ return Buffer.from(bytes).toString("hex");
94
+ }
95
+
96
+ export function fromHex(hex: string): Uint8Array {
97
+ return new Uint8Array(Buffer.from(hex, "hex"));
98
+ }
99
+
100
+ export function toPem(bytes: Uint8Array, type: "private" | "public"): string {
101
+ const label = type === "private" ? "PRIVATE KEY" : "PUBLIC KEY";
102
+ const base64 = Buffer.from(bytes).toString("base64");
103
+ const lines = base64.match(/.{1,64}/g) ?? [base64];
104
+ return `-----BEGIN ${label}-----\n${lines.join("\n")}\n-----END ${label}-----\n`;
105
+ }
106
+
107
+ export function fromPem(pem: string): Uint8Array {
108
+ const base64 = pem
109
+ .replace(/-----BEGIN [A-Z ]+-----/g, "")
110
+ .replace(/-----END [A-Z ]+-----/g, "")
111
+ .replace(/\s+/g, "");
112
+ return new Uint8Array(Buffer.from(base64, "base64"));
113
+ }
114
+
115
+ export function privateKeyPemToBytes(pem: string): Uint8Array {
116
+ const key = createPrivateKey(pem);
117
+ if (key.asymmetricKeyType !== "ed25519") {
118
+ throw new Error(
119
+ `Wrong private key type: ${key.asymmetricKeyType ?? "unknown"}. Expected ed25519.`,
120
+ );
121
+ }
122
+ const jwk = key.export({ format: "jwk" }) as { d: string };
123
+ return new Uint8Array(Buffer.from(jwk.d, "base64url"));
124
+ }
125
+
126
+ export function publicKeyPemToBytes(pem: string): Uint8Array {
127
+ const key = createPublicKey(pem);
128
+ if (key.asymmetricKeyType !== "ed25519") {
129
+ throw new Error(
130
+ `Wrong public key type: ${key.asymmetricKeyType ?? "unknown"}. Expected ed25519.`,
131
+ );
132
+ }
133
+ const jwk = key.export({ format: "jwk" }) as { x: string };
134
+ return new Uint8Array(Buffer.from(jwk.x, "base64url"));
135
+ }
136
+
137
+ export function keyExists(filePath: string): boolean {
138
+ return existsSync(filePath);
139
+ }
@@ -0,0 +1,66 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>RFC-0921: Shared Ed25519 sign/verify primitives — canonicalization, raw byte signing, and convenience wrappers.</purpose>
4
+
5
+
6
+ <non-goals>
7
+ <item>Does not implement key generation or loading — those live in key.ts.</item>
8
+ <item>Does not implement multibase encoding — that is a Cosmic Passport concern.</item>
9
+ <item>Does not implement Bordbuch or manifest storage — those are consumer concerns.</item>
10
+ </non-goals>
11
+ </MODULE_CONTRACT>
12
+ <CHANGE_SUMMARY>
13
+ <item>RFC-0921: initial signing primitives module.</item>
14
+ <item>RFC-1097: step 6 — compass.migrate codemod run
15
+
16
+ Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.</item>
17
+ <item>RFC-1097: sweep — werkstatt-engine clean
18
+
19
+ Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.</item>
20
+ </CHANGE_SUMMARY>
21
+ */
22
+
23
+ import * as ed from "@noble/ed25519";
24
+ import {
25
+ snapshotCanonicalJsonObjectV1,
26
+ canonicalJsonBytesV1,
27
+ } from "../fingerprint/canonical-json.ts";
28
+ import type { SignablePayload } from "./types.ts";
29
+
30
+ export function canonicalBytes(payload: SignablePayload): Uint8Array {
31
+ const snapshot = snapshotCanonicalJsonObjectV1(payload);
32
+ if (!snapshot.ok) {
33
+ throw new Error(
34
+ `CERT-CANONICAL-SNAPSHOT-01: failed to canonicalize payload (${snapshot.code})`,
35
+ );
36
+ }
37
+ return canonicalJsonBytesV1(snapshot.value);
38
+ }
39
+
40
+ export async function signBytes(privateKey: Uint8Array, message: Uint8Array): Promise<Uint8Array> {
41
+ return ed.signAsync(message, privateKey);
42
+ }
43
+
44
+ export async function verifyBytes(
45
+ publicKey: Uint8Array,
46
+ message: Uint8Array,
47
+ signature: Uint8Array,
48
+ ): Promise<boolean> {
49
+ try {
50
+ return await ed.verifyAsync(signature, message, publicKey);
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ export async function sign(privateKey: Uint8Array, payload: SignablePayload): Promise<Uint8Array> {
57
+ return signBytes(privateKey, canonicalBytes(payload));
58
+ }
59
+
60
+ export async function verify(
61
+ publicKey: Uint8Array,
62
+ payload: SignablePayload,
63
+ signature: Uint8Array,
64
+ ): Promise<boolean> {
65
+ return verifyBytes(publicKey, canonicalBytes(payload), signature);
66
+ }
@@ -0,0 +1,29 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>RFC-0921: Shared Ed25519 signing core types — used by Nachweis, Integrity, and Cosmic Passport.</purpose>
4
+
5
+
6
+ <non-goals>
7
+ <item>Does not implement signing or key generation logic — those live in sign.ts and key.ts.</item>
8
+ <item>Does not define domain-specific payload shapes — consumers define their own and pass them as Record&lt;string, unknown&gt;.</item>
9
+ </non-goals>
10
+ </MODULE_CONTRACT>
11
+ <CHANGE_SUMMARY>
12
+ <item>RFC-0921: initial signing core types module.</item>
13
+ <item>RFC-1097: step 6 — compass.migrate codemod run
14
+
15
+ Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.</item>
16
+ <item>RFC-1097: sweep — werkstatt-engine clean
17
+
18
+ Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.</item>
19
+ </CHANGE_SUMMARY>
20
+ */
21
+
22
+ export type KeyEncoding = "pem" | "hex";
23
+
24
+ export interface SigningKeyPair {
25
+ privateKey: Uint8Array;
26
+ publicKey: Uint8Array;
27
+ }
28
+
29
+ export type SignablePayload = Record<string, unknown>;
@@ -1,12 +1,15 @@
1
1
  /*
2
2
  <MODULE_CONTRACT>
3
- <purpose>Canonical locale-aware URL slug generation (RFC-0915, DNA-88).</purpose>
3
+ <purpose>slug-url — canonical locale-aware URL slug generation for site routes (RFC-0915, DNA-88).</purpose>
4
4
  <non-goals>
5
5
  <item>Do not handle heading anchor deduplication — use HeadingSlugger for that.</item>
6
6
  </non-goals>
7
7
  </MODULE_CONTRACT>
8
8
  <CHANGE_SUMMARY>
9
9
  <item>RFC-0915: extracted from werkstatt-site/src/domain/geo/slug.ts as canonical URL slug function.</item>
10
+ <item>RFC-1097: sweep — tail packages clean
11
+
12
+ Sweep batch 3: rewrote ~95 purposes across werkstatt-knowledge, werkstatt-shared, godot-game, phaser-game, lifecycle-core, projektarchiv-*, portal-*, billing-*, typescript (CONTRACT-02/PURPOSE-02). Real KEY_DECISIONS on 5 godot utils, non-goals on 5 CONTRACT-03 files, headers on 4 headerless files, CS-07 history literal fix on 2 files. Policy: vitest.config.ts + test-fixtures testPatterns, worker-configuration.d.ts excludedPath. All non-site/engine packages now 0 diagnostics.</item>
10
13
  </CHANGE_SUMMARY>
11
14
  */
12
15
 
@@ -0,0 +1,108 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>runTool — the single subprocess seam for stack plugins (RFC-1100). Owns the
4
+ shared prologue every external-binary call needs: dist/ preflight, required-env
5
+ presence check, env merge, timeout, and error mapping to ToolResult. Production
6
+ uses the default execFileSync adapter; tests inject a recording ToolExecutor so no
7
+ test mocks node:child_process.</purpose>
8
+
9
+ <non-goals>
10
+ <item>Does not validate tool-specific config — callers check their own config fields before calling runTool.</item>
11
+ <item>Does not use shell interpolation — execFile with an argument array only (DNA-89).</item>
12
+ <item>Does not run in the browser — server-only (Node child_process).</item>
13
+ </non-goals>
14
+ </MODULE_CONTRACT>
15
+ <CHANGE_SUMMARY>
16
+ <item>RFC-1100: initial subprocess seam — runTool + ToolSpec/ToolResult/ToolExecutor; replaces per-call-site execFileSync prologues in stack plugins.</item>
17
+ <item>RFC-1100: step 1 — shared tool/fs/check seams (walkFiles, runTool, defineStackChecks)</item>
18
+ </CHANGE_SUMMARY>
19
+ */
20
+
21
+ // Server-only. Do not import from browser/client scripts.
22
+
23
+ import { execFileSync } from "node:child_process";
24
+ import { existsSync } from "node:fs";
25
+ import { join } from "node:path";
26
+
27
+ export interface ToolSpec {
28
+ /** Binary to execute, e.g. "npx". */
29
+ bin: string;
30
+ /** Argument array — never a shell string (DNA-89). */
31
+ args: string[];
32
+ /** Working directory for the subprocess. */
33
+ cwd: string;
34
+ /** Extra environment merged over process.env for the subprocess. */
35
+ env?: Record<string, string>;
36
+ /** Subprocess timeout. Default 120_000 ms. */
37
+ timeoutMs?: number;
38
+ /** Preflight: require <cwd>/dist to exist before executing. */
39
+ requireDist?: boolean;
40
+ /** Preflight: require these env vars to be non-empty after the env merge. */
41
+ requireEnv?: string[];
42
+ }
43
+
44
+ export interface ToolResult {
45
+ success: boolean;
46
+ stdout?: string;
47
+ errors?: string[];
48
+ /** Which phase produced the failure — lets callers keep preflight messages unwrapped. */
49
+ failedAt?: "preflight" | "exec";
50
+ }
51
+
52
+ /**
53
+ * Executes a ToolSpec. Injectable so tests record specs instead of spawning
54
+ * processes — pass a fake that captures the spec and returns a canned ToolResult.
55
+ */
56
+ export type ToolExecutor = (spec: ToolSpec) => ToolResult;
57
+
58
+ const DEFAULT_TIMEOUT_MS = 120_000;
59
+
60
+ const execFileExecutor: ToolExecutor = (spec) => {
61
+ try {
62
+ const stdout = execFileSync(spec.bin, spec.args, {
63
+ cwd: spec.cwd,
64
+ encoding: "utf-8",
65
+ timeout: spec.timeoutMs ?? DEFAULT_TIMEOUT_MS,
66
+ stdio: ["pipe", "pipe", "pipe"],
67
+ env: { ...process.env, ...spec.env },
68
+ });
69
+ return { success: true, stdout };
70
+ } catch (err) {
71
+ const message = err instanceof Error ? err.message : String(err);
72
+ return { success: false, errors: [message], failedAt: "exec" };
73
+ }
74
+ };
75
+
76
+ export function runTool(spec: ToolSpec, executor: ToolExecutor = execFileExecutor): ToolResult {
77
+ if (spec.requireDist) {
78
+ const distDir = join(spec.cwd, "dist");
79
+ if (!existsSync(distDir)) {
80
+ return {
81
+ success: false,
82
+ errors: [`dist/ directory not found at ${distDir} — run build first`],
83
+ failedAt: "preflight",
84
+ };
85
+ }
86
+ }
87
+
88
+ if (spec.requireEnv && spec.requireEnv.length > 0) {
89
+ const mergedEnv = { ...process.env, ...spec.env };
90
+ const missing = spec.requireEnv.filter((name) => !mergedEnv[name]);
91
+ if (missing.length > 0) {
92
+ return {
93
+ success: false,
94
+ errors: missing.map(
95
+ (name) => `Required environment variable ${name} is not set`,
96
+ ),
97
+ failedAt: "preflight",
98
+ };
99
+ }
100
+ }
101
+
102
+ try {
103
+ return executor(spec);
104
+ } catch (err) {
105
+ const message = err instanceof Error ? err.message : String(err);
106
+ return { success: false, errors: [message], failedAt: "exec" };
107
+ }
108
+ }
@@ -0,0 +1,124 @@
1
+ /*
2
+ <MODULE_CONTRACT>
3
+ <purpose>defineStackChecks — the spec-driven check harness for stack plugins
4
+ (RFC-1100). A plugin declares one StackCheckSpec table; the harness derives kernel
5
+ command declarations, the checkGate hook body, and invariant table rows from it.
6
+ Validator files keep only a pure check() function — they never shape
7
+ KernelCommandResult or register commands themselves.</purpose>
8
+
9
+ <non-goals>
10
+ <item>Does not implement stack-specific rules — those live in the plugin's check() functions.</item>
11
+ <item>Does not read files — check() functions consume the plugin's model/walker seams.</item>
12
+ </non-goals>
13
+ </MODULE_CONTRACT>
14
+ <CHANGE_SUMMARY>
15
+ <item>RFC-1100: initial spec-driven check harness — StackCheckSpec, StackCheckViolation, StackCheckData, defineStackChecks returning commands + runCheckGate + invariantRows.</item>
16
+ <item>RFC-1100: step 1 — shared tool/fs/check seams (walkFiles, runTool, defineStackChecks)</item>
17
+ </CHANGE_SUMMARY>
18
+ */
19
+
20
+ import type {
21
+ KernelCommandDefinition,
22
+ KernelCommandResult,
23
+ } from "@warpgogol/werkstatt-shared/kernel";
24
+ import type { HookResult, PluginHookContext } from "../plugin/plugin-contract.ts";
25
+
26
+ /** A single rule violation emitted by a stack check() function. */
27
+ export interface StackCheckViolation {
28
+ ruleId: string;
29
+ file: string;
30
+ message: string;
31
+ line?: number;
32
+ details?: Record<string, unknown>;
33
+ }
34
+
35
+ /** Uniform data payload every stack check command returns. */
36
+ export interface StackCheckData {
37
+ command: string;
38
+ status: "pass" | "fail";
39
+ violations: StackCheckViolation[];
40
+ }
41
+
42
+ export interface StackCheckSpec {
43
+ /** Kernel command name, e.g. "phaser.scenes.validate". */
44
+ name: string;
45
+ /** Human-readable command description. */
46
+ description: string;
47
+ /** The single contract this check enforces (DNA-91). */
48
+ contract: string;
49
+ /** Rule IDs this check emits (DNA-91). */
50
+ rules: string[];
51
+ /** Workspace-relative path globs this check reads (RFC-0266). */
52
+ reads: string[];
53
+ /** Invariant ID for invariantRows — defaults to rules[0]. */
54
+ invariantId?: string;
55
+ /** Pure rule logic: project root in, violations out. */
56
+ check: (projectRoot: string) => Promise<StackCheckViolation[]>;
57
+ }
58
+
59
+ export interface StackCheckDeclarations {
60
+ /** Kernel command declarations, one per spec entry. */
61
+ commands: KernelCommandDefinition<StackCheckData>[];
62
+ /** The plugin's checkGate hook body — runs every spec in order. */
63
+ runCheckGate: (ctx: PluginHookContext) => Promise<HookResult>;
64
+ /** Invariant table rows derived from the spec — { id, command } pairs. */
65
+ invariantRows: Array<{ id: string; command: string }>;
66
+ }
67
+
68
+ function toCommand(spec: StackCheckSpec): KernelCommandDefinition<StackCheckData> {
69
+ return {
70
+ name: spec.name,
71
+ description: spec.description,
72
+ contract: spec.contract,
73
+ rules: spec.rules,
74
+ reads: spec.reads,
75
+ scope: "workspace",
76
+ cacheable: false,
77
+ async execute(_input, context): Promise<KernelCommandResult<StackCheckData>> {
78
+ const violations = await spec.check(context.workspaceRoot);
79
+ const status = violations.length === 0 ? "pass" : "fail";
80
+ return {
81
+ data: { command: spec.name, status, violations },
82
+ exitCode: status === "pass" ? 0 : 1,
83
+ summary: `${spec.name}: ${status} (${violations.length} violations)`,
84
+ };
85
+ },
86
+ };
87
+ }
88
+
89
+ /** Short gate-log label: "phaser.scenes.validate" → "scenes". */
90
+ function gateLabel(commandName: string): string {
91
+ return commandName.split(".")[1] ?? commandName;
92
+ }
93
+
94
+ export function defineStackChecks(specs: StackCheckSpec[]): StackCheckDeclarations {
95
+ const commands = specs.map(toCommand);
96
+
97
+ async function runCheckGate(ctx: PluginHookContext): Promise<HookResult> {
98
+ const projectRoot = ctx.workpiecePath ?? ctx.workspaceRoot;
99
+ const errors: string[] = [];
100
+ const statuses: string[] = [];
101
+
102
+ for (const spec of specs) {
103
+ const violations = await spec.check(projectRoot);
104
+ const status = violations.length === 0 ? "pass" : "fail";
105
+ statuses.push(`${gateLabel(spec.name)}=${status}`);
106
+ if (violations.length > 0) {
107
+ errors.push(`${spec.name}: ${violations.length} violations`);
108
+ }
109
+ }
110
+
111
+ ctx.logger.info(`checkGate: ${statuses.join(", ")}`);
112
+
113
+ return {
114
+ success: errors.length === 0,
115
+ errors: errors.length > 0 ? errors : undefined,
116
+ };
117
+ }
118
+
119
+ const invariantRows = specs
120
+ .map((spec) => ({ id: spec.invariantId ?? spec.rules[0], command: spec.name }))
121
+ .filter((row): row is { id: string; command: string } => typeof row.id === "string");
122
+
123
+ return { commands, runCheckGate, invariantRows };
124
+ }