stylegallery 0.1.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 (346) hide show
  1. package/AGENTS.md +156 -0
  2. package/CATALOG.md +69 -0
  3. package/DOMAINS.md +65 -0
  4. package/GOVERNANCE.md +222 -0
  5. package/GUIDE.md +59 -0
  6. package/README.md +313 -0
  7. package/consumer-reference/adapters/style-dictionary.config.mjs +36 -0
  8. package/consumer-reference/agent-native/README.md +157 -0
  9. package/consumer-reference/agent-native/registry.json +640 -0
  10. package/consumer-reference/agent-native/schema/agent-native.schema.json +848 -0
  11. package/consumer-reference/agent-native/schema/epistemic.schema.json +14 -0
  12. package/consumer-reference/agent-native/schema/execution.schema.json +12 -0
  13. package/consumer-reference/agent-native/schema/identity.schema.json +10 -0
  14. package/consumer-reference/agent-native/schema/learning.schema.json +12 -0
  15. package/consumer-reference/agent-native/schema/manifest.schema.json +6 -0
  16. package/consumer-reference/agent-native/schema/operation.schema.json +12 -0
  17. package/consumer-reference/agent-native/schema/protocol-binding.schema.json +9 -0
  18. package/consumer-reference/agent-native/schema/retrieval.schema.json +10 -0
  19. package/consumer-reference/baselines/calibration.json +260 -0
  20. package/consumer-reference/baselines/manifest.json +21 -0
  21. package/consumer-reference/contract.md +83 -0
  22. package/consumer-reference/fixtures/consumer-conformance/e2e-fixture.mjs +282 -0
  23. package/consumer-reference/fixtures/consumer-conformance/manifest.json +102 -0
  24. package/consumer-reference/fixtures/consumer-conformance/runtime-proof.mjs +32 -0
  25. package/consumer-reference/fixtures/consumer-conformance/valid-migration-result.json +18 -0
  26. package/consumer-reference/fixtures/consumer-conformance/valid-migration.json +142 -0
  27. package/consumer-reference/fixtures/invalid-stable-ended-support.json +19 -0
  28. package/consumer-reference/fixtures/promotion/invalid-blocking-evidence.json +26 -0
  29. package/consumer-reference/fixtures/promotion/invalid-count-only.json +29 -0
  30. package/consumer-reference/fixtures/promotion/invalid-missing-owner-migration.json +25 -0
  31. package/consumer-reference/fixtures/promotion/invalid-normative-bypass-no-regression.json +25 -0
  32. package/consumer-reference/fixtures/promotion/invalid-related-counted-independent.json +45 -0
  33. package/consumer-reference/fixtures/promotion/invalid-stable-ended-support.json +26 -0
  34. package/consumer-reference/fixtures/promotion/manifest.json +15 -0
  35. package/consumer-reference/fixtures/promotion/valid-deferred-example.json +67 -0
  36. package/consumer-reference/fixtures/promotion/valid-normative-bypass.json +67 -0
  37. package/consumer-reference/fixtures/token-portability/invalid-cycle.json +7 -0
  38. package/consumer-reference/fixtures/token-portability/invalid-dangling-alias.json +6 -0
  39. package/consumer-reference/fixtures/token-portability/invalid-extends.json +4 -0
  40. package/consumer-reference/fixtures/token-portability/invalid-json-pointer.json +7 -0
  41. package/consumer-reference/fixtures/token-portability/invalid-resolver.json +9 -0
  42. package/consumer-reference/fixtures/token-portability/invalid-type-mismatch.json +10 -0
  43. package/consumer-reference/fixtures/token-portability/invalid-unknown-reserved.json +6 -0
  44. package/consumer-reference/fixtures/token-portability/invalid-untested-type.json +6 -0
  45. package/consumer-reference/fixtures/token-portability/valid-border.json +14 -0
  46. package/consumer-reference/fixtures/token-portability/valid-reference.json +32 -0
  47. package/consumer-reference/fixtures/token-portability/valid-whole-alias.json +7 -0
  48. package/consumer-reference/fixtures/valid-deprecated.json +21 -0
  49. package/consumer-reference/fixtures/valid-experimental.json +19 -0
  50. package/consumer-reference/generated/manifest.json +40 -0
  51. package/consumer-reference/generated/tokens.css +12 -0
  52. package/consumer-reference/index.md +32 -0
  53. package/consumer-reference/policies/shared-experimental.json +37 -0
  54. package/consumer-reference/schema/ax-evidence.schema.json +30 -0
  55. package/consumer-reference/schema/baseline-manifest.schema.json +55 -0
  56. package/consumer-reference/schema/calibration-record.schema.json +190 -0
  57. package/consumer-reference/schema/capture-session.schema.json +161 -0
  58. package/consumer-reference/schema/component-state.schema.json +150 -0
  59. package/consumer-reference/schema/consumer-conformance-record.schema.json +365 -0
  60. package/consumer-reference/schema/dom-evidence.schema.json +38 -0
  61. package/consumer-reference/schema/evidence-record.schema.json +81 -0
  62. package/consumer-reference/schema/fixture-manifest.schema.json +32 -0
  63. package/consumer-reference/schema/item.schema.json +188 -0
  64. package/consumer-reference/schema/page-evidence-manifest.schema.json +216 -0
  65. package/consumer-reference/schema/page-evidence-session.schema.json +119 -0
  66. package/consumer-reference/schema/portable-tokens.schema.json +104 -0
  67. package/consumer-reference/schema/promotion-rfc.schema.json +219 -0
  68. package/consumer-reference/schema/runtime-evidence-manifest.schema.json +33 -0
  69. package/consumer-reference/schema/visual-evidence.schema.json +31 -0
  70. package/design-engineering/consumer-migration-readiness.md +124 -0
  71. package/design-engineering/index.md +28 -0
  72. package/design-engineering/interface-craft.md +107 -0
  73. package/design-engineering/reference-profiles/external-adaptation/index.md +12 -0
  74. package/design-engineering/reference-profiles/governed-local/editorial/components/button.component.json +125 -0
  75. package/design-engineering/reference-profiles/governed-local/editorial/evidence/button.evidence.json +3504 -0
  76. package/design-engineering/reference-profiles/governed-local/editorial/fixtures/button.fixture.json +65 -0
  77. package/design-engineering/reference-profiles/governed-local/editorial/generated/evidence-coverage.md +23 -0
  78. package/design-engineering/reference-profiles/governed-local/editorial/generated/keyboard-matrix.md +19 -0
  79. package/design-engineering/reference-profiles/governed-local/editorial/generated/state-matrix.md +21 -0
  80. package/design-engineering/reference-profiles/governed-local/editorial/local-foundations.json +12 -0
  81. package/design-engineering/reference-profiles/governed-local/editorial/profile.json +43 -0
  82. package/design-engineering/reference-profiles/governed-local/editorial/states/button.states.json +195 -0
  83. package/design-engineering/reference-profiles/governed-local/editorial/tokens.dtcg.json +17 -0
  84. package/design-engineering/reference-profiles/governed-local/index.md +26 -0
  85. package/design-engineering/reference-profiles/governed-local/terminal/components/button.component.json +125 -0
  86. package/design-engineering/reference-profiles/governed-local/terminal/evidence/button.evidence.json +3504 -0
  87. package/design-engineering/reference-profiles/governed-local/terminal/fixtures/button.fixture.json +65 -0
  88. package/design-engineering/reference-profiles/governed-local/terminal/generated/evidence-coverage.md +23 -0
  89. package/design-engineering/reference-profiles/governed-local/terminal/generated/keyboard-matrix.md +19 -0
  90. package/design-engineering/reference-profiles/governed-local/terminal/generated/state-matrix.md +21 -0
  91. package/design-engineering/reference-profiles/governed-local/terminal/local-foundations.json +12 -0
  92. package/design-engineering/reference-profiles/governed-local/terminal/profile.json +43 -0
  93. package/design-engineering/reference-profiles/governed-local/terminal/states/button.states.json +195 -0
  94. package/design-engineering/reference-profiles/governed-local/terminal/tokens.dtcg.json +17 -0
  95. package/design-engineering/reference-profiles/index.md +19 -0
  96. package/game-ui/classification.md +82 -0
  97. package/game-ui/index.md +35 -0
  98. package/game-ui/reference-record.md +62 -0
  99. package/game-ui/screen-hierarchy.md +107 -0
  100. package/game-ui/unity/architecture.md +166 -0
  101. package/game-ui/unity/cli-loop.md +84 -0
  102. package/game-ui/unity/data/unity-technologies-public-repositories.json +26654 -0
  103. package/game-ui/unity/org-wiki.md +146 -0
  104. package/game-ui/unity/repository-map.md +102 -0
  105. package/game-ui/unity/ui-systems.md +85 -0
  106. package/guides/decision-tree.md +149 -0
  107. package/guides/documentation-mode-taxonomy.md +157 -0
  108. package/guides/layout-brief.md +220 -0
  109. package/guides/vocabulary.md +148 -0
  110. package/guides/webpage-generation-workflow.md +185 -0
  111. package/index.md +36 -0
  112. package/layout/index.md +26 -0
  113. package/motion/index.md +24 -0
  114. package/motion/practice-reference.md +145 -0
  115. package/motion/review-workflow.md +86 -0
  116. package/motion/vocabulary.md +82 -0
  117. package/package.json +78 -0
  118. package/patterns/centering/center.md +87 -0
  119. package/patterns/centering/index.md +6 -0
  120. package/patterns/centering/super-center.md +89 -0
  121. package/patterns/containment/box.md +87 -0
  122. package/patterns/containment/clamped-card.md +86 -0
  123. package/patterns/containment/content-limiter.md +87 -0
  124. package/patterns/containment/fluid-styles.md +86 -0
  125. package/patterns/containment/index.md +8 -0
  126. package/patterns/grid-repetition/card-grid.md +88 -0
  127. package/patterns/grid-repetition/columns.md +87 -0
  128. package/patterns/grid-repetition/dense-grid.md +88 -0
  129. package/patterns/grid-repetition/grid-wrapper.md +89 -0
  130. package/patterns/grid-repetition/index.md +12 -0
  131. package/patterns/grid-repetition/masonry-approx.md +87 -0
  132. package/patterns/grid-repetition/page-grid.md +90 -0
  133. package/patterns/grid-repetition/ram-grid.md +88 -0
  134. package/patterns/grid-repetition/twelve-span-grid.md +92 -0
  135. package/patterns/in-line-grouping/badge-list.md +94 -0
  136. package/patterns/in-line-grouping/breadcrumb.md +89 -0
  137. package/patterns/in-line-grouping/cluster.md +89 -0
  138. package/patterns/in-line-grouping/deconstructed-pancake.md +92 -0
  139. package/patterns/in-line-grouping/index.md +13 -0
  140. package/patterns/in-line-grouping/pagination.md +89 -0
  141. package/patterns/in-line-grouping/reel.md +90 -0
  142. package/patterns/in-line-grouping/split-nav.md +97 -0
  143. package/patterns/in-line-grouping/tab-strip.md +88 -0
  144. package/patterns/in-line-grouping/wrap-row.md +89 -0
  145. package/patterns/index.md +13 -0
  146. package/patterns/media-fit/frame.md +95 -0
  147. package/patterns/media-fit/icon-frame.md +87 -0
  148. package/patterns/media-fit/index.md +6 -0
  149. package/patterns/overlay-exception/imposter.md +95 -0
  150. package/patterns/overlay-exception/index.md +6 -0
  151. package/patterns/overlay-exception/overlay-stack.md +89 -0
  152. package/patterns/split-sidebar/index.md +12 -0
  153. package/patterns/split-sidebar/list-detail.md +95 -0
  154. package/patterns/split-sidebar/main-with-rail.md +95 -0
  155. package/patterns/split-sidebar/media-object.md +102 -0
  156. package/patterns/split-sidebar/sidebar.md +101 -0
  157. package/patterns/split-sidebar/split-screen.md +92 -0
  158. package/patterns/split-sidebar/sticky-aside.md +97 -0
  159. package/patterns/split-sidebar/supporting-pane.md +95 -0
  160. package/patterns/split-sidebar/switcher.md +93 -0
  161. package/patterns/stacking/feed.md +88 -0
  162. package/patterns/stacking/index.md +8 -0
  163. package/patterns/stacking/line-up.md +95 -0
  164. package/patterns/stacking/stack.md +87 -0
  165. package/patterns/stacking/step-nav.md +88 -0
  166. package/patterns/viewport-shell/cover.md +90 -0
  167. package/patterns/viewport-shell/fixed-sidenav-shell.md +97 -0
  168. package/patterns/viewport-shell/holy-grail.md +112 -0
  169. package/patterns/viewport-shell/index.md +11 -0
  170. package/patterns/viewport-shell/panel-layout.md +95 -0
  171. package/patterns/viewport-shell/scroll-body-shell.md +93 -0
  172. package/patterns/viewport-shell/sticky-footer.md +92 -0
  173. package/patterns/viewport-shell/sticky-header.md +86 -0
  174. package/platform-guides/apple-interaction.md +89 -0
  175. package/platform-guides/index.md +26 -0
  176. package/quality/claim-records/index.md +3 -0
  177. package/quality/claim-records/samples.md +92 -0
  178. package/quality/claim-records/stylegallery-multidomain-scope.md +42 -0
  179. package/quality/claims.md +77 -0
  180. package/quality/evidence/accessibility.md +58 -0
  181. package/quality/evidence/consumer-migration.md +42 -0
  182. package/quality/evidence/design-rationale.md +34 -0
  183. package/quality/evidence/executable-evidence.md +79 -0
  184. package/quality/evidence/families.md +56 -0
  185. package/quality/evidence/hci-evaluation.md +36 -0
  186. package/quality/evidence/index.md +16 -0
  187. package/quality/evidence/pattern-contract-audit.md +96 -0
  188. package/quality/evidence/search-metadata-polyhierarchy.md +86 -0
  189. package/quality/evidence/sources.md +43 -0
  190. package/quality/evidence/tokens.md +33 -0
  191. package/quality/evidence/visual-qa.md +41 -0
  192. package/quality/gates/accessibility-evidence.md +60 -0
  193. package/quality/gates/consumer-migration-evidence.md +53 -0
  194. package/quality/gates/design-claim.md +56 -0
  195. package/quality/gates/harmony-evaluation.md +78 -0
  196. package/quality/gates/index.md +13 -0
  197. package/quality/gates/layout.md +52 -0
  198. package/quality/gates/rationale.md +53 -0
  199. package/quality/gates/visual-evidence.md +47 -0
  200. package/quality/index.md +55 -0
  201. package/quality/principles.md +58 -0
  202. package/recipes/article-page.md +52 -0
  203. package/recipes/command-surface.md +55 -0
  204. package/recipes/dashboard.md +56 -0
  205. package/recipes/form-flow.md +55 -0
  206. package/recipes/homepage.md +89 -0
  207. package/recipes/index.md +13 -0
  208. package/recipes/list-detail.md +55 -0
  209. package/recipes/primitive-to-recipe-matrix.md +83 -0
  210. package/recipes/saas-settings.md +52 -0
  211. package/scripts/agent-native/a2a-projection.mjs +248 -0
  212. package/scripts/agent-native/agui-projection.mjs +178 -0
  213. package/scripts/agent-native/canonical-json.mjs +109 -0
  214. package/scripts/agent-native/cli-adapter.mjs +68 -0
  215. package/scripts/agent-native/events.mjs +113 -0
  216. package/scripts/agent-native/execution.mjs +227 -0
  217. package/scripts/agent-native/fixture.mjs +159 -0
  218. package/scripts/agent-native/identity.mjs +184 -0
  219. package/scripts/agent-native/immutable-store.mjs +102 -0
  220. package/scripts/agent-native/knowledge.mjs +168 -0
  221. package/scripts/agent-native/learning-records.mjs +244 -0
  222. package/scripts/agent-native/learning.mjs +247 -0
  223. package/scripts/agent-native/mcp-adapter.mjs +173 -0
  224. package/scripts/agent-native/queries.mjs +173 -0
  225. package/scripts/agent-native/registry.mjs +154 -0
  226. package/scripts/agent-native/retrieval.mjs +171 -0
  227. package/scripts/agent-native/self-description.mjs +160 -0
  228. package/scripts/artifact-metadata.mjs +20 -0
  229. package/scripts/audit-evidence-freshness.mjs +308 -0
  230. package/scripts/baseline-contract.mjs +189 -0
  231. package/scripts/baseline-schema-parity.mjs +40 -0
  232. package/scripts/build-reference-artifacts.mjs +127 -0
  233. package/scripts/calibration-raw-contract.mjs +172 -0
  234. package/scripts/capture-session-contract.mjs +187 -0
  235. package/scripts/component-state-artifact-fixture.mjs +44 -0
  236. package/scripts/component-state-contract.mjs +99 -0
  237. package/scripts/component-state-semantics.mjs +128 -0
  238. package/scripts/component-state-workflow-contract.mjs +67 -0
  239. package/scripts/component-state-workflow-negative-cases.mjs +64 -0
  240. package/scripts/consumer-conformance-contract.mjs +198 -0
  241. package/scripts/consumer-evidence-governance-contract.mjs +210 -0
  242. package/scripts/consumer-reference-case-runner.mjs +93 -0
  243. package/scripts/consumer-reference-schema.mjs +155 -0
  244. package/scripts/create-component-state-session.mjs +100 -0
  245. package/scripts/create-page-evidence-session.mjs +139 -0
  246. package/scripts/domain-document-boundaries.mjs +40 -0
  247. package/scripts/domain-validation-checks.mjs +141 -0
  248. package/scripts/evidence-artifact-contract.mjs +191 -0
  249. package/scripts/finalize-component-state-evidence.mjs +165 -0
  250. package/scripts/finalize-page-evidence.mjs +197 -0
  251. package/scripts/generate-consumer-reference-evidence.mjs +154 -0
  252. package/scripts/generate-patterns.mjs +218 -0
  253. package/scripts/governance-matrix-contract.mjs +73 -0
  254. package/scripts/governance-matrix-negative-cases.mjs +114 -0
  255. package/scripts/governance-policy-contract.mjs +49 -0
  256. package/scripts/governance-test-fixture.mjs +321 -0
  257. package/scripts/governance-workflow-negative-cases.mjs +241 -0
  258. package/scripts/governed-profile-registry.mjs +125 -0
  259. package/scripts/json-schema-formats.mjs +31 -0
  260. package/scripts/markdown-structure.mjs +45 -0
  261. package/scripts/page-artifact-metadata.mjs +124 -0
  262. package/scripts/page-evidence-contract.mjs +297 -0
  263. package/scripts/page-evidence-fixture.mjs +271 -0
  264. package/scripts/pattern-data.mjs +325 -0
  265. package/scripts/profile-record-contract.mjs +140 -0
  266. package/scripts/promotion-attestation-contract.mjs +91 -0
  267. package/scripts/promotion-boundary-test-contract.mjs +92 -0
  268. package/scripts/promotion-fixture-inventory.mjs +109 -0
  269. package/scripts/promotion-governance-contract.mjs +28 -0
  270. package/scripts/reference-artifact-path-contract.mjs +28 -0
  271. package/scripts/reference-profile-contract.mjs +114 -0
  272. package/scripts/reference-token-contract.mjs +156 -0
  273. package/scripts/run-consumer-page-evidence-ci.mjs +170 -0
  274. package/scripts/sg-mcp.mjs +16 -0
  275. package/scripts/sg.mjs +27 -0
  276. package/scripts/strict-json.mjs +72 -0
  277. package/scripts/summarize-sentinel-calibration.mjs +98 -0
  278. package/scripts/test-agent-adapter-conformance.mjs +250 -0
  279. package/scripts/test-agent-conformance-receipt.mjs +106 -0
  280. package/scripts/test-agent-events.mjs +81 -0
  281. package/scripts/test-agent-execution-effects.mjs +114 -0
  282. package/scripts/test-agent-execution-fixtures.mjs +140 -0
  283. package/scripts/test-agent-execution-kernel.mjs +39 -0
  284. package/scripts/test-agent-execution-learning.mjs +130 -0
  285. package/scripts/test-agent-execution-lifecycle.mjs +143 -0
  286. package/scripts/test-agent-execution-safety.mjs +158 -0
  287. package/scripts/test-agent-execution-views.mjs +117 -0
  288. package/scripts/test-agent-identity-integrity-cases.mjs +160 -0
  289. package/scripts/test-agent-knowledge-kernel.mjs +183 -0
  290. package/scripts/test-agent-learning.mjs +246 -0
  291. package/scripts/test-agent-mcp.mjs +246 -0
  292. package/scripts/test-agent-native-schemas.mjs +215 -0
  293. package/scripts/test-agent-projections.mjs +249 -0
  294. package/scripts/test-agent-registry-mcp-integrity.mjs +215 -0
  295. package/scripts/test-agent-registry-mutations.mjs +110 -0
  296. package/scripts/test-audit-evidence-freshness.mjs +177 -0
  297. package/scripts/test-component-state-sentinel.mjs +35 -0
  298. package/scripts/test-component-state-source-contract.mjs +83 -0
  299. package/scripts/test-consumer-conformance-sentinel.mjs +165 -0
  300. package/scripts/test-consumer-reference-sentinel.mjs +31 -0
  301. package/scripts/test-generate-consumer-reference-evidence.mjs +124 -0
  302. package/scripts/test-json-cli-output.mjs +151 -0
  303. package/scripts/test-json-schema-formats.mjs +40 -0
  304. package/scripts/test-reference-adapters.mjs +199 -0
  305. package/scripts/test-renderer-purity.mjs +34 -0
  306. package/scripts/test-sg-cli.mjs +129 -0
  307. package/scripts/test-summarize-sentinel-calibration.mjs +226 -0
  308. package/scripts/test-validate-baseline-manifest.mjs +234 -0
  309. package/scripts/test-validate-component-state-artifacts.mjs +243 -0
  310. package/scripts/test-validate-component-state.mjs +106 -0
  311. package/scripts/test-validate-consumer-conformance.mjs +427 -0
  312. package/scripts/test-validate-consumer-reference-cli.mjs +69 -0
  313. package/scripts/test-validate-consumer-reference.mjs +263 -0
  314. package/scripts/test-validate-domains.mjs +357 -0
  315. package/scripts/test-validate-governance.mjs +292 -0
  316. package/scripts/test-validate-ia.mjs +262 -0
  317. package/scripts/test-validate-okf.mjs +73 -0
  318. package/scripts/test-validate-page-evidence.mjs +302 -0
  319. package/scripts/test-validate-patterns.mjs +157 -0
  320. package/scripts/test-validate-promotion-rfc.mjs +250 -0
  321. package/scripts/test-validate-reference-profiles.mjs +170 -0
  322. package/scripts/test-validate-unity-org-wiki.mjs +57 -0
  323. package/scripts/test-validate-unity-source-contracts.mjs +67 -0
  324. package/scripts/test-validate-vocabulary.mjs +174 -0
  325. package/scripts/test-validate-webpage-workflow.mjs +293 -0
  326. package/scripts/validate-baseline-manifest.mjs +44 -0
  327. package/scripts/validate-catalog.mjs +65 -0
  328. package/scripts/validate-component-state.mjs +141 -0
  329. package/scripts/validate-consumer-conformance.mjs +477 -0
  330. package/scripts/validate-consumer-reference.mjs +288 -0
  331. package/scripts/validate-domains.mjs +237 -0
  332. package/scripts/validate-governance.mjs +248 -0
  333. package/scripts/validate-ia.mjs +136 -0
  334. package/scripts/validate-links.mjs +66 -0
  335. package/scripts/validate-okf.mjs +104 -0
  336. package/scripts/validate-page-evidence.mjs +191 -0
  337. package/scripts/validate-patterns.mjs +246 -0
  338. package/scripts/validate-promotion-rfc.mjs +224 -0
  339. package/scripts/validate-reference-artifacts.mjs +125 -0
  340. package/scripts/validate-renderer-purity.mjs +56 -0
  341. package/scripts/validate-unity-org-wiki.mjs +146 -0
  342. package/scripts/validate-unity-source-contracts.mjs +107 -0
  343. package/scripts/validate-vocabulary.mjs +115 -0
  344. package/scripts/validate-webpage-workflow.mjs +254 -0
  345. package/scripts/visual-expectation-contract.mjs +20 -0
  346. package/scripts/workflow-action-contract.mjs +163 -0
@@ -0,0 +1,248 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { componentStateWorkflowFailures } from "./component-state-workflow-contract.mjs";
6
+ import { consumerEvidenceGovernanceFailures } from "./consumer-evidence-governance-contract.mjs";
7
+ import { referenceOwnershipFailures } from "./governance-matrix-contract.mjs";
8
+ import { immutableActionPins, requiredCodeowners, sentinelProvenanceClauses } from "./governance-policy-contract.mjs";
9
+ import { promotionGovernanceFailures } from "./promotion-governance-contract.mjs";
10
+ import { workflowActionFailures } from "./workflow-action-contract.mjs";
11
+
12
+ const json = new Set(process.argv.slice(2)).has("--json");
13
+ const root = process.cwd();
14
+ const failures = [];
15
+ const warnings = [];
16
+ function read(relative) {
17
+ const target = path.join(root, relative);
18
+ if (!fs.existsSync(target)) {
19
+ failures.push(`${relative}: missing file`);
20
+ return "";
21
+ }
22
+ return fs.readFileSync(target, "utf8");
23
+ }
24
+
25
+ function requireIncludes(relative, text) {
26
+ if (!read(relative).includes(text)) failures.push(`${relative}: missing ${text}`);
27
+ }
28
+
29
+ function recommendIncludes(relative, text, label = `recommended wording missing ${text}`) {
30
+ if (!read(relative).includes(text)) warnings.push(`${relative}: ${label}`);
31
+ }
32
+
33
+ function requirePattern(relative, pattern, label) {
34
+ if (!pattern.test(read(relative))) failures.push(`${relative}: missing ${label}`);
35
+ }
36
+
37
+ function requireGeneratedWarning(relative) {
38
+ requirePattern(relative, /Generated from `scripts\/generate-patterns\.mjs` and `scripts\/pattern-data\.mjs`\. Do not hand-edit/, "generated warning");
39
+ }
40
+
41
+ function requireGeneratedPatternMetadata(relative) {
42
+ requireIncludes(relative, "lifecycle: generated");
43
+ requireIncludes(relative, "generated_from: scripts/generate-patterns.mjs, scripts/pattern-data.mjs");
44
+ }
45
+
46
+ function requireGovernanceMatrix() {
47
+ const families = [
48
+ "Root repository guide",
49
+ "OKF bundle map",
50
+ "Agent editing rules",
51
+ "Planning guides",
52
+ "Layout recipes",
53
+ "Quality gates and evidence",
54
+ "Consumer reference contract",
55
+ "Governed local reference profiles",
56
+ "Component-state evidence matrices",
57
+ "Consumer migration conformance",
58
+ "Consumer page-evidence lifecycle",
59
+ "Explicit evidence freshness schedule",
60
+ "Deterministic consumer browser conformance",
61
+ "Shared promotion policy",
62
+ "Proposed Chromium sentinel",
63
+ "Domain manifest and scope decision",
64
+ "Layout domain hub",
65
+ "Motion domain guidance",
66
+ "Design Engineering domain guidance",
67
+ "Game UI domain guidance",
68
+ "Platform Guides domain guidance",
69
+ "Pattern data and examples",
70
+ "Pattern generator",
71
+ "Validation scripts",
72
+ "CI workflow",
73
+ ];
74
+ for (const family of families) requireIncludes("GOVERNANCE.md", family);
75
+ requireIncludes("GOVERNANCE.md", "| Doc family | Source of truth | Generator | Generated artifacts | Lifecycle state | Stale trigger | Validator | Review owner |");
76
+ requireIncludes("GOVERNANCE.md", "`scripts/pattern-data.mjs`");
77
+ requireIncludes("GOVERNANCE.md", "`scripts/generate-patterns.mjs`");
78
+ requireIncludes("GOVERNANCE.md", "`scripts/validate-patterns.mjs`, `scripts/validate-catalog.mjs`, `scripts/validate-governance.mjs`");
79
+ requireIncludes("GOVERNANCE.md", "Source-lineage URL changes, generated drift, category changes, or pattern count changes.");
80
+ requireIncludes("GOVERNANCE.md", "Generated structure changes, generated-warning changes, or generated metadata changes.");
81
+ requireIncludes("GOVERNANCE.md", "`scripts/generate-consumer-reference-evidence.mjs`");
82
+ requireIncludes("GOVERNANCE.md", "Browser state evidence begins with `scripts/create-component-state-session.mjs`");
83
+ requireIncludes("GOVERNANCE.md", "Receipt creation rejects dirty relevant sources.");
84
+ requireIncludes("GOVERNANCE.md", "browser-authored visual sidecars bind the same session, scenario, capture time, source digest, PNG bytes, dimensions, and hash");
85
+ requireIncludes("GOVERNANCE.md", "exactly 30 channel passes over the closed 40-file runtime set");
86
+ requireIncludes("GOVERNANCE.md", "Validation uses the receipt and completed manifest interval, not a wall-clock maximum age");
87
+ for (const profile of ["editorial", "terminal"]) {
88
+ for (const artifact of ["state-matrix.md", "keyboard-matrix.md", "evidence-coverage.md"]) {
89
+ requireIncludes("GOVERNANCE.md", `design-engineering/reference-profiles/governed-local/${profile}/generated/${artifact}`);
90
+ }
91
+ }
92
+ }
93
+
94
+ function requireLifecycleStates() {
95
+ for (const state of ["`draft`", "`stable`", "`deprecated`", "`experimental`", "`generated`"]) {
96
+ requireIncludes("GOVERNANCE.md", state);
97
+ }
98
+ }
99
+
100
+ function requireOwnership() {
101
+ for (const ownerRule of requiredCodeowners) {
102
+ requireIncludes(".github/CODEOWNERS", ownerRule);
103
+ }
104
+ requireIncludes("GOVERNANCE.md", "Review Ownership");
105
+ requireIncludes("GOVERNANCE.md", "CODEOWNERS");
106
+ }
107
+
108
+ function requireStalenessDecision() {
109
+ requireIncludes("GOVERNANCE.md", "Audit trigger:");
110
+ requireIncludes("GOVERNANCE.md", "node scripts/validate-links.mjs --json");
111
+ }
112
+
113
+ function requireCiwiring() {
114
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/component-state-workflow-contract.mjs");
115
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/validate-governance.mjs");
116
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/test-validate-governance.mjs");
117
+ requireIncludes(".github/workflows/validate.yml", "node scripts/validate-governance.mjs --json");
118
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-validate-governance.mjs --json");
119
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/validate-domains.mjs");
120
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/test-validate-domains.mjs");
121
+ requireIncludes(".github/workflows/validate.yml", "node scripts/validate-domains.mjs --json");
122
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-validate-domains.mjs");
123
+ requireIncludes(".github/workflows/validate.yml", "node scripts/validate-webpage-workflow.mjs --json");
124
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-validate-webpage-workflow.mjs --json");
125
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/validate-consumer-reference.mjs");
126
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/test-validate-consumer-reference.mjs");
127
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/consumer-reference-case-runner.mjs");
128
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/governed-profile-registry.mjs");
129
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/promotion-attestation-contract.mjs");
130
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/validate-promotion-rfc.mjs");
131
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/test-validate-promotion-rfc.mjs");
132
+ requireIncludes(".github/workflows/validate.yml", "node scripts/validate-consumer-reference.mjs --json");
133
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-validate-consumer-reference.mjs --json");
134
+ requireIncludes(".github/workflows/validate.yml", "node scripts/validate-promotion-rfc.mjs --json");
135
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-validate-promotion-rfc.mjs --json");
136
+ requireIncludes(".github/workflows/validate.yml", "consumer-reference/schema/promotion-rfc.schema.json");
137
+ requireIncludes(".github/workflows/validate.yml", "consumer-reference/policies/shared-experimental.json");
138
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-consumer-reference-sentinel.mjs");
139
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/baseline-schema-parity.mjs");
140
+ requireIncludes(".github/workflows/validate.yml", "node -c scripts/test-component-state-source-contract.mjs");
141
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-component-state-source-contract.mjs");
142
+ requireIncludes(".github/workflows/validate.yml", "consumer-reference/schema/visual-evidence.schema.json");
143
+ requireIncludes(".github/workflows/validate.yml", "node scripts/create-component-state-session.mjs");
144
+ requireIncludes(".github/workflows/validate.yml", "STATE_SESSION_RECEIPT=");
145
+ requireIncludes(".github/workflows/validate.yml", "node scripts/finalize-component-state-evidence.mjs");
146
+ requireIncludes(".github/workflows/validate.yml", "--runtime-manifest");
147
+ requireIncludes(".github/workflows/validate.yml", "node scripts/validate-baseline-manifest.mjs --json");
148
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-validate-baseline-manifest.mjs --json");
149
+ requireIncludes(".github/workflows/validate.yml", "node scripts/test-summarize-sentinel-calibration.mjs");
150
+ requireIncludes(".github/workflows/validate.yml", "node scripts/validate-renderer-purity.mjs --json");
151
+ requireIncludes(".github/workflows/validate.yml", "checkout_sha=\"$(git -c safe.directory=\"$GITHUB_WORKSPACE\" rev-parse HEAD)\"");
152
+ requireIncludes(".github/workflows/validate.yml", "--repository \"changeroa/StyleGallery\" \\");
153
+ requireIncludes(".github/workflows/validate.yml", "--execution-repository \"$GITHUB_REPOSITORY\" \\");
154
+ requireIncludes(".github/workflows/validate.yml", "\"repository\":\"%s\",\"execution_repository\":\"%s\"");
155
+ requireIncludes(".github/workflows/validate.yml", "\"changeroa/StyleGallery\" \"$GITHUB_REPOSITORY\" \"$GITHUB_RUN_ID\"");
156
+ if (/safe\.directory(?:=|\s+)["']?\*["']?/.test(read(".github/workflows/validate.yml"))) {
157
+ failures.push(".github/workflows/validate.yml: broad Git safe.directory wildcard is forbidden");
158
+ }
159
+ requireIncludes(".github/workflows/validate.yml", "permissions:");
160
+ requireIncludes(".github/workflows/validate.yml", "contents: read");
161
+ }
162
+
163
+ function requireComponentStateCiIsolation() {
164
+ const relative = ".github/workflows/validate.yml";
165
+ for (const failure of componentStateWorkflowFailures(read(relative))) failures.push(`${relative}: ${failure}`);
166
+ }
167
+
168
+ function requireImmutableActions() {
169
+ const relative = ".github/workflows/validate.yml";
170
+ const workflow = read(relative);
171
+ for (const pin of immutableActionPins) if (!workflow.includes(pin)) failures.push(`${relative}: missing immutable action pin ${pin}`);
172
+ failures.push(...workflowActionFailures(workflow, relative));
173
+ }
174
+
175
+ function requireRootLinks() {
176
+ for (const relative of ["README.md", "index.md", "AGENTS.md"]) {
177
+ requirePattern(relative, /\[[^\]]+\]\(GOVERNANCE\.md\)/, "link target GOVERNANCE.md");
178
+ }
179
+ recommendIncludes("README.md", "[Governance, Lifecycle, And Docs-As-Code](GOVERNANCE.md)", "recommended link label missing [Governance, Lifecycle, And Docs-As-Code](GOVERNANCE.md)");
180
+ recommendIncludes("index.md", "[Governance, lifecycle, and docs-as-code](GOVERNANCE.md)", "recommended link label missing [Governance, lifecycle, and docs-as-code](GOVERNANCE.md)");
181
+ recommendIncludes("AGENTS.md", "[Governance, Lifecycle, And Docs-As-Code](GOVERNANCE.md)", "recommended link label missing [Governance, Lifecycle, And Docs-As-Code](GOVERNANCE.md)");
182
+ requireIncludes("README.md", "(DOMAINS.md)");
183
+ requireIncludes("index.md", "(DOMAINS.md)");
184
+ requireIncludes("AGENTS.md", "(DOMAINS.md)");
185
+ }
186
+
187
+ function requireEvidenceMap() {
188
+ requireIncludes("quality/evidence/executable-evidence.md", "scripts/validate-governance.mjs");
189
+ requireIncludes("quality/evidence/executable-evidence.md", "scripts/test-validate-governance.mjs");
190
+ recommendIncludes("quality/evidence/executable-evidence.md", "generated warnings, generated metadata, root link targets");
191
+ requireIncludes("quality/evidence/executable-evidence.md", "Missing governance file, generated warning, generated metadata, CODEOWNERS coverage, or stale policy fixtures must fail.");
192
+ requireIncludes("quality/evidence/executable-evidence.md", "Domain metadata, immutable provenance, scope boundaries, and root-route fixtures must fail.");
193
+ requireIncludes("quality/evidence/executable-evidence.md", "Consumer-reference handoffs, schema/runtime parity");
194
+ requireIncludes("quality/evidence/executable-evidence.md", "repository handoff omissions must fail");
195
+ requireIncludes("quality/evidence/executable-evidence.md", "The proposed Chromium sentinel preserves canonical card-grid geometry and truth-derived calibration evidence.");
196
+ requireIncludes("quality/evidence/executable-evidence.md", "Governed-local button states retain source-bound visual, DOM, and accessibility-tree evidence across both example profiles.");
197
+ requireIncludes("quality/evidence/executable-evidence.md", "one clean capture session binds the browser artifacts to the governed source inventory");
198
+ requireIncludes("quality/evidence/executable-evidence.md", "It does not prove product suitability, independent adoption, full accessibility, cross-browser behavior, or owner approval");
199
+ requireIncludes("GOVERNANCE.md", "node scripts/test-consumer-reference-sentinel.mjs");
200
+ requireIncludes("GOVERNANCE.md", "owner.enforcement: \"placeholder\"");
201
+ requireIncludes("GOVERNANCE.md", "review_independence: \"single_account\"");
202
+ }
203
+
204
+ function requireSentinelProvenanceBoundary() {
205
+ for (const relative of ["consumer-reference/contract.md", "quality/evidence/executable-evidence.md", "GOVERNANCE.md"]) {
206
+ for (const clause of sentinelProvenanceClauses) requireIncludes(relative, clause);
207
+ }
208
+ }
209
+
210
+ requireGovernanceMatrix();
211
+ failures.push(...referenceOwnershipFailures(read("GOVERNANCE.md")));
212
+ requireLifecycleStates();
213
+ requireOwnership();
214
+ requireStalenessDecision();
215
+ requireCiwiring();
216
+ failures.push(...consumerEvidenceGovernanceFailures({
217
+ evidence: read("quality/evidence/executable-evidence.md"),
218
+ freshnessWorkflow: read(".github/workflows/evidence-freshness.yml"),
219
+ governance: read("GOVERNANCE.md"),
220
+ validationWorkflow: read(".github/workflows/validate.yml"),
221
+ }));
222
+ requireComponentStateCiIsolation();
223
+ requireImmutableActions();
224
+ requireRootLinks();
225
+ requireEvidenceMap();
226
+ requireSentinelProvenanceBoundary();
227
+ failures.push(...promotionGovernanceFailures(read));
228
+ requireGeneratedWarning("CATALOG.md");
229
+ requireGeneratedWarning("patterns/index.md");
230
+ requireGeneratedWarning("patterns/stacking/index.md");
231
+ requireGeneratedWarning("patterns/stacking/stack.md");
232
+ requireGeneratedPatternMetadata("patterns/stacking/stack.md");
233
+
234
+ const result = {
235
+ failures,
236
+ ok: failures.length === 0,
237
+ warnings,
238
+ };
239
+
240
+ if (json) {
241
+ console.log(JSON.stringify(result, null, 2));
242
+ } else if (result.ok) {
243
+ console.log(`ok: governance policy (${warnings.length} warnings)`);
244
+ } else {
245
+ console.error(result.failures.join("\n"));
246
+ }
247
+
248
+ process.exitCode = result.ok ? 0 : 1;
@@ -0,0 +1,136 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+ import { stripFencedCodeBlocks } from "./markdown-structure.mjs";
6
+
7
+ const args = new Set(process.argv.slice(2));
8
+ const json = args.has("--json");
9
+ const root = process.cwd();
10
+ const failures = [];
11
+
12
+ const rootRoles = [
13
+ ["README.md", "Primary role: repository guide"],
14
+ ["index.md", "Primary role: OKF bundle map"],
15
+ ["GUIDE.md", "Primary role: planning workflow"],
16
+ ["CATALOG.md", "Primary role: pattern lookup"],
17
+ ];
18
+ const domainRoutes = [
19
+ ["Layout", "layout/index.md"],
20
+ ["Motion", "motion/index.md"],
21
+ ["Design Engineering", "design-engineering/index.md"],
22
+ ["Platform Guides", "platform-guides/index.md"],
23
+ ];
24
+ const leafDirectories = ["patterns", "recipes", "quality", "motion", "design-engineering", "platform-guides", "consumer-reference"];
25
+ const nestedIndexes = [
26
+ "design-engineering/reference-profiles/index.md",
27
+ "design-engineering/reference-profiles/governed-local/index.md",
28
+ "design-engineering/reference-profiles/external-adaptation/index.md",
29
+ ];
30
+ const governedProfileLinks = [
31
+ "[Editorial profile](editorial/profile.json)",
32
+ "[Editorial state matrix](editorial/generated/state-matrix.md)",
33
+ "[Editorial keyboard matrix](editorial/generated/keyboard-matrix.md)",
34
+ "[Editorial evidence coverage](editorial/generated/evidence-coverage.md)",
35
+ "[Terminal profile](terminal/profile.json)",
36
+ "[Terminal state matrix](terminal/generated/state-matrix.md)",
37
+ "[Terminal keyboard matrix](terminal/generated/keyboard-matrix.md)",
38
+ "[Terminal evidence coverage](terminal/generated/evidence-coverage.md)",
39
+ ];
40
+ const migrationRoutes = [
41
+ ["README.md", "[Consumer Migration Readiness](design-engineering/consumer-migration-readiness.md)"],
42
+ ["index.md", "[Consumer migration readiness](design-engineering/consumer-migration-readiness.md)"],
43
+ ["design-engineering/index.md", "[Consumer Migration Readiness](consumer-migration-readiness.md)"],
44
+ ["consumer-reference/index.md", "[Consumer Migration Readiness](../design-engineering/consumer-migration-readiness.md)"],
45
+ ["quality/index.md", "[Consumer migration evidence gate](gates/consumer-migration-evidence.md)"],
46
+ ["quality/gates/index.md", "[Consumer migration evidence gate](consumer-migration-evidence.md)"],
47
+ ["quality/evidence/index.md", "[Consumer migration evidence](consumer-migration.md)"],
48
+ ];
49
+
50
+ function read(relative) {
51
+ const target = path.join(root, relative);
52
+ if (!fs.existsSync(target)) {
53
+ failures.push(`${relative}: missing file`);
54
+ return "";
55
+ }
56
+ return fs.readFileSync(target, "utf8");
57
+ }
58
+
59
+ function walk(dir) {
60
+ const absolute = path.join(root, dir);
61
+ if (!fs.existsSync(absolute)) return [];
62
+ return fs.readdirSync(absolute, { withFileTypes: true }).flatMap((entry) => {
63
+ const next = path.join(absolute, entry.name);
64
+ if (entry.isDirectory()) return walk(path.relative(root, next));
65
+ if (!entry.isFile() || !entry.name.endsWith(".md") || entry.name === "index.md") return [];
66
+ return [path.relative(root, next)];
67
+ });
68
+ }
69
+
70
+ function requireIncludes(relative, text) {
71
+ if (!stripFencedCodeBlocks(read(relative)).includes(text)) failures.push(`${relative}: missing ${text}`);
72
+ }
73
+
74
+ function requireRootRoles() {
75
+ for (const [relative, role] of rootRoles) {
76
+ requireIncludes(relative, role);
77
+ }
78
+ requireIncludes("README.md", "## Repository Entry Roles");
79
+ requireIncludes("README.md", "## Task Routes");
80
+ requireIncludes("README.md", "## Link Policy");
81
+ requireIncludes("README.md", "Navigation links");
82
+ requireIncludes("README.md", "Citation links");
83
+ requireIncludes("README.md", "Dependency links");
84
+ requireIncludes("quality/index.md", "## Tree-Test Findability QA");
85
+ requireIncludes("README.md", "[Consumer Reference](consumer-reference/index.md)");
86
+ requireIncludes("index.md", "[Consumer reference](consumer-reference/index.md)");
87
+ requireIncludes("design-engineering/index.md", "[Reference Profiles](reference-profiles/index.md)");
88
+ requireIncludes("design-engineering/reference-profiles/index.md", "[External Adaptation](external-adaptation/index.md)");
89
+ requireIncludes("design-engineering/reference-profiles/index.md", "[Governed Local Profiles](governed-local/index.md)");
90
+ for (const link of governedProfileLinks) {
91
+ requireIncludes("design-engineering/reference-profiles/governed-local/index.md", link);
92
+ }
93
+ for (const [relative, link] of migrationRoutes) requireIncludes(relative, link);
94
+ }
95
+
96
+ function requireTaskRoutes() {
97
+ const content = stripFencedCodeBlocks(read("README.md"));
98
+ const section = content.split("## Task Routes")[1]?.split("\n## ")[0] ?? "";
99
+ const routeRows = section.split("\n").filter((line) => /^\| `[^`]+` \| \[[^\]]+\]\([^)]+\) \|/.test(line));
100
+ if (routeRows.length < 10) failures.push(`README.md: expected at least 10 task route rows, found ${routeRows.length}`);
101
+ }
102
+
103
+ function requireDomainRoutes() {
104
+ for (const relative of ["README.md", "index.md"]) {
105
+ for (const [label, target] of domainRoutes) requireIncludes(relative, `[${label}](${target})`);
106
+ }
107
+ }
108
+
109
+ function requireLeafNavigation() {
110
+ for (const file of [...leafDirectories.flatMap(walk), ...nestedIndexes]) {
111
+ const content = stripFencedCodeBlocks(read(file));
112
+ if (!/^Parent: \[[^\]]+\]\([^)]+\)/m.test(content)) failures.push(`${file}: missing Parent navigation link`);
113
+ if (!/^Next: \[[^\]]+\]\([^)]+\)/m.test(content)) failures.push(`${file}: missing Next navigation link`);
114
+ }
115
+ }
116
+
117
+ requireRootRoles();
118
+ requireTaskRoutes();
119
+ requireDomainRoutes();
120
+ requireLeafNavigation();
121
+
122
+ const result = {
123
+ checkedLeafFiles: leafDirectories.flatMap(walk).length + nestedIndexes.length,
124
+ failures,
125
+ ok: failures.length === 0,
126
+ };
127
+
128
+ if (json) {
129
+ console.log(JSON.stringify(result, null, 2));
130
+ } else if (result.ok) {
131
+ console.log(`ok: ${result.checkedLeafFiles} IA leaf files`);
132
+ } else {
133
+ console.error(result.failures.join("\n"));
134
+ }
135
+
136
+ process.exitCode = result.ok ? 0 : 1;
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ const args = new Set(process.argv.slice(2));
7
+ const json = args.has("--json");
8
+ const root = process.cwd();
9
+ const failures = [];
10
+
11
+ function walk(dir) {
12
+ return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
13
+ if (entry.name === ".git" || entry.name === ".omo" || entry.name === "node_modules") return [];
14
+ const next = path.join(dir, entry.name);
15
+ if (entry.isDirectory()) return walk(next);
16
+ if (!entry.isFile() || !entry.name.endsWith(".md")) return [];
17
+ return [next];
18
+ });
19
+ }
20
+
21
+ function stripFencedCodeBlocks(content) {
22
+ return content.replace(/```[\s\S]*?```/g, "");
23
+ }
24
+
25
+ function localTarget(rawTarget) {
26
+ const target = rawTarget.trim();
27
+ if (!target || target.startsWith("#")) return null;
28
+ if (/^[a-z][a-z0-9+.-]*:/i.test(target)) return null;
29
+ return target.split("#")[0].split("?")[0];
30
+ }
31
+
32
+ function checkLink(file, target) {
33
+ const local = localTarget(target);
34
+ if (!local) return;
35
+ const decoded = decodeURIComponent(local);
36
+ const absolute = path.resolve(path.dirname(file), decoded);
37
+ if (!absolute.startsWith(root)) {
38
+ failures.push(`${path.relative(root, file)}: link escapes repository: ${target}`);
39
+ return;
40
+ }
41
+ if (!fs.existsSync(absolute)) failures.push(`${path.relative(root, file)}: missing link target: ${target}`);
42
+ }
43
+
44
+ const files = walk(root);
45
+ for (const file of files) {
46
+ const content = stripFencedCodeBlocks(fs.readFileSync(file, "utf8"));
47
+ for (const match of content.matchAll(/(?<!!)\[[^\]]+\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g)) {
48
+ checkLink(file, match[1]);
49
+ }
50
+ }
51
+
52
+ const result = {
53
+ checkedFiles: files.length,
54
+ failures,
55
+ ok: failures.length === 0,
56
+ };
57
+
58
+ if (json) {
59
+ console.log(JSON.stringify(result, null, 2));
60
+ } else if (result.ok) {
61
+ console.log(`ok: ${files.length} markdown files`);
62
+ } else {
63
+ console.error(result.failures.join("\n"));
64
+ }
65
+
66
+ process.exitCode = result.ok ? 0 : 1;
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ const args = new Set(process.argv.slice(2));
7
+ const json = args.has("--json");
8
+ const root = process.cwd();
9
+ const ignoredDirs = new Set([".git", ".omo", "node_modules"]);
10
+ const failures = [];
11
+
12
+ function walk(dir) {
13
+ return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
14
+ if (ignoredDirs.has(entry.name)) return [];
15
+ const next = path.join(dir, entry.name);
16
+ if (entry.isDirectory()) return walk(next);
17
+ return entry.isFile() && entry.name.endsWith(".md") ? [next] : [];
18
+ });
19
+ }
20
+
21
+ function frontmatter(content) {
22
+ const match = content.match(/^---\n([\s\S]*?)\n---\n/);
23
+ if (!match) return null;
24
+ const metadata = {};
25
+ for (const line of match[1].split("\n")) {
26
+ const index = line.indexOf(":");
27
+ if (index === -1) continue;
28
+ metadata[line.slice(0, index).trim()] = line.slice(index + 1).trim().replace(/^["']|["']$/g, "");
29
+ }
30
+ return metadata;
31
+ }
32
+
33
+ function hasRootOnlyOkfFrontmatter(file, metadata) {
34
+ return file === "index.md" && metadata && Object.keys(metadata).every((key) => key === "okf_version");
35
+ }
36
+
37
+ function checkIndex(file, content) {
38
+ const metadata = frontmatter(content);
39
+ if (metadata && !hasRootOnlyOkfFrontmatter(file, metadata)) {
40
+ failures.push(`${file}: index.md must not contain concept frontmatter`);
41
+ }
42
+ if (!content.match(/^#\s+\S/m)) failures.push(`${file}: index.md must contain at least one heading`);
43
+ if (!content.match(/\[[^\]]+\]\([^)]+\)/)) failures.push(`${file}: index.md must list at least one markdown link`);
44
+ }
45
+
46
+ function checkLog(file, content) {
47
+ if (frontmatter(content)) failures.push(`${file}: log.md must not contain frontmatter`);
48
+ if (!content.match(/^#\s+\S/m)) failures.push(`${file}: log.md must contain a title heading`);
49
+ const dateHeadings = [...content.matchAll(/^##\s+(.+)$/gm)].map((match) => match[1].trim());
50
+ for (const heading of dateHeadings) {
51
+ if (!heading.match(/^\d{4}-\d{2}-\d{2}$/)) failures.push(`${file}: log.md date heading must be YYYY-MM-DD: ${heading}`);
52
+ }
53
+ }
54
+
55
+ function checkConcept(file, content) {
56
+ const metadata = frontmatter(content);
57
+ if (!metadata) {
58
+ failures.push(`${file}: missing OKF frontmatter`);
59
+ return;
60
+ }
61
+ if (!metadata.type) failures.push(`${file}: missing required OKF type`);
62
+ }
63
+
64
+ const files = walk(root);
65
+ let conceptCount = 0;
66
+ let indexCount = 0;
67
+ let logCount = 0;
68
+
69
+ for (const absolute of files) {
70
+ const file = path.relative(root, absolute);
71
+ const content = fs.readFileSync(absolute, "utf8");
72
+ const basename = path.basename(file);
73
+ if (basename === "index.md") {
74
+ indexCount += 1;
75
+ checkIndex(file, content);
76
+ } else if (basename === "log.md") {
77
+ logCount += 1;
78
+ checkLog(file, content);
79
+ } else {
80
+ conceptCount += 1;
81
+ checkConcept(file, content);
82
+ }
83
+ }
84
+
85
+ if (!files.includes(path.join(root, "index.md"))) failures.push("missing root index.md");
86
+ if (!files.includes(path.join(root, "log.md"))) failures.push("missing root log.md");
87
+
88
+ const result = {
89
+ ok: failures.length === 0,
90
+ conceptCount,
91
+ indexCount,
92
+ logCount,
93
+ failures,
94
+ };
95
+
96
+ if (json) {
97
+ console.log(JSON.stringify(result, null, 2));
98
+ } else if (result.ok) {
99
+ console.log(`ok: ${conceptCount} concepts, ${indexCount} indexes, ${logCount} logs`);
100
+ } else {
101
+ console.error(failures.join("\n"));
102
+ }
103
+
104
+ process.exitCode = result.ok ? 0 : 1;