stylegallery 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/AGENTS.md +4 -1
  2. package/DOMAINS.md +2 -6
  3. package/GOVERNANCE.md +10 -9
  4. package/README.md +29 -127
  5. package/consumer-reference/agent-native/v2/admission-policy.json +646 -0
  6. package/consumer-reference/agent-native/v2/material-registry.json +1 -0
  7. package/consumer-reference/agent-native/v2/schema/admission-policy.schema.json +50 -0
  8. package/consumer-reference/agent-native/v2/schema/material-manifest.schema.json +17 -0
  9. package/consumer-reference/agent-native/v2/schema/material-record.schema.json +20 -0
  10. package/consumer-reference/contract.md +1 -1
  11. package/consumer-reference/index.md +5 -3
  12. package/layout/index.md +124 -0
  13. package/log.md +57 -0
  14. package/package.json +183 -22
  15. package/scripts/agent-native/v2/experimental-extension-registry.mjs +143 -0
  16. package/scripts/agent-native/v2/extensions/a2a-projection.mjs +264 -0
  17. package/scripts/agent-native/v2/extensions/agui-projection.mjs +191 -0
  18. package/scripts/agent-native/v2/material-admission.mjs +295 -0
  19. package/scripts/agent-native/v2/material-cli-adapter.mjs +134 -0
  20. package/scripts/agent-native/v2/material-context.mjs +251 -0
  21. package/scripts/agent-native/v2/material-identity.mjs +71 -0
  22. package/scripts/agent-native/v2/material-mcp-adapter.mjs +253 -0
  23. package/scripts/agent-native/v2/material-operation-registry.mjs +123 -0
  24. package/scripts/agent-native/v2/material-queries.mjs +398 -0
  25. package/scripts/agent-native/v2/material-registry.mjs +319 -0
  26. package/scripts/sg-material-mcp.mjs +98 -0
  27. package/scripts/sg-material.mjs +27 -0
  28. package/consumer-reference/adapters/style-dictionary.config.mjs +0 -36
  29. package/consumer-reference/baselines/calibration.json +0 -260
  30. package/consumer-reference/baselines/manifest.json +0 -21
  31. package/consumer-reference/fixtures/consumer-conformance/e2e-fixture.mjs +0 -282
  32. package/consumer-reference/fixtures/consumer-conformance/manifest.json +0 -102
  33. package/consumer-reference/fixtures/consumer-conformance/runtime-proof.mjs +0 -32
  34. package/consumer-reference/fixtures/consumer-conformance/valid-migration-result.json +0 -18
  35. package/consumer-reference/fixtures/consumer-conformance/valid-migration.json +0 -142
  36. package/consumer-reference/fixtures/invalid-stable-ended-support.json +0 -19
  37. package/consumer-reference/fixtures/promotion/invalid-blocking-evidence.json +0 -26
  38. package/consumer-reference/fixtures/promotion/invalid-count-only.json +0 -29
  39. package/consumer-reference/fixtures/promotion/invalid-missing-owner-migration.json +0 -25
  40. package/consumer-reference/fixtures/promotion/invalid-normative-bypass-no-regression.json +0 -25
  41. package/consumer-reference/fixtures/promotion/invalid-related-counted-independent.json +0 -45
  42. package/consumer-reference/fixtures/promotion/invalid-stable-ended-support.json +0 -26
  43. package/consumer-reference/fixtures/promotion/manifest.json +0 -15
  44. package/consumer-reference/fixtures/promotion/valid-deferred-example.json +0 -67
  45. package/consumer-reference/fixtures/promotion/valid-normative-bypass.json +0 -67
  46. package/consumer-reference/fixtures/token-portability/invalid-cycle.json +0 -7
  47. package/consumer-reference/fixtures/token-portability/invalid-dangling-alias.json +0 -6
  48. package/consumer-reference/fixtures/token-portability/invalid-extends.json +0 -4
  49. package/consumer-reference/fixtures/token-portability/invalid-json-pointer.json +0 -7
  50. package/consumer-reference/fixtures/token-portability/invalid-resolver.json +0 -9
  51. package/consumer-reference/fixtures/token-portability/invalid-type-mismatch.json +0 -10
  52. package/consumer-reference/fixtures/token-portability/invalid-unknown-reserved.json +0 -6
  53. package/consumer-reference/fixtures/token-portability/invalid-untested-type.json +0 -6
  54. package/consumer-reference/fixtures/token-portability/valid-border.json +0 -14
  55. package/consumer-reference/fixtures/token-portability/valid-reference.json +0 -32
  56. package/consumer-reference/fixtures/token-portability/valid-whole-alias.json +0 -7
  57. package/consumer-reference/fixtures/valid-deprecated.json +0 -21
  58. package/consumer-reference/fixtures/valid-experimental.json +0 -19
  59. package/consumer-reference/generated/manifest.json +0 -40
  60. package/consumer-reference/generated/tokens.css +0 -12
  61. package/consumer-reference/policies/shared-experimental.json +0 -37
  62. package/consumer-reference/schema/ax-evidence.schema.json +0 -30
  63. package/consumer-reference/schema/baseline-manifest.schema.json +0 -55
  64. package/consumer-reference/schema/calibration-record.schema.json +0 -190
  65. package/consumer-reference/schema/capture-session.schema.json +0 -161
  66. package/consumer-reference/schema/component-state.schema.json +0 -150
  67. package/consumer-reference/schema/consumer-conformance-record.schema.json +0 -365
  68. package/consumer-reference/schema/dom-evidence.schema.json +0 -38
  69. package/consumer-reference/schema/evidence-record.schema.json +0 -81
  70. package/consumer-reference/schema/fixture-manifest.schema.json +0 -32
  71. package/consumer-reference/schema/item.schema.json +0 -188
  72. package/consumer-reference/schema/page-evidence-manifest.schema.json +0 -216
  73. package/consumer-reference/schema/page-evidence-session.schema.json +0 -119
  74. package/consumer-reference/schema/portable-tokens.schema.json +0 -104
  75. package/consumer-reference/schema/promotion-rfc.schema.json +0 -219
  76. package/consumer-reference/schema/runtime-evidence-manifest.schema.json +0 -33
  77. package/consumer-reference/schema/visual-evidence.schema.json +0 -31
  78. package/design-engineering/consumer-migration-readiness.md +0 -124
  79. package/design-engineering/interface-craft.md +0 -107
  80. package/design-engineering/reference-profiles/external-adaptation/index.md +0 -12
  81. package/design-engineering/reference-profiles/governed-local/editorial/components/button.component.json +0 -125
  82. package/design-engineering/reference-profiles/governed-local/editorial/evidence/button.evidence.json +0 -3504
  83. package/design-engineering/reference-profiles/governed-local/editorial/fixtures/button.fixture.json +0 -65
  84. package/design-engineering/reference-profiles/governed-local/editorial/generated/evidence-coverage.md +0 -23
  85. package/design-engineering/reference-profiles/governed-local/editorial/generated/keyboard-matrix.md +0 -19
  86. package/design-engineering/reference-profiles/governed-local/editorial/generated/state-matrix.md +0 -21
  87. package/design-engineering/reference-profiles/governed-local/editorial/local-foundations.json +0 -12
  88. package/design-engineering/reference-profiles/governed-local/editorial/states/button.states.json +0 -195
  89. package/design-engineering/reference-profiles/governed-local/editorial/tokens.dtcg.json +0 -17
  90. package/design-engineering/reference-profiles/governed-local/terminal/components/button.component.json +0 -125
  91. package/design-engineering/reference-profiles/governed-local/terminal/evidence/button.evidence.json +0 -3504
  92. package/design-engineering/reference-profiles/governed-local/terminal/fixtures/button.fixture.json +0 -65
  93. package/design-engineering/reference-profiles/governed-local/terminal/generated/evidence-coverage.md +0 -23
  94. package/design-engineering/reference-profiles/governed-local/terminal/generated/keyboard-matrix.md +0 -19
  95. package/design-engineering/reference-profiles/governed-local/terminal/generated/state-matrix.md +0 -21
  96. package/design-engineering/reference-profiles/governed-local/terminal/local-foundations.json +0 -12
  97. package/design-engineering/reference-profiles/governed-local/terminal/profile.json +0 -43
  98. package/design-engineering/reference-profiles/governed-local/terminal/states/button.states.json +0 -195
  99. package/design-engineering/reference-profiles/governed-local/terminal/tokens.dtcg.json +0 -17
  100. package/game-ui/classification.md +0 -82
  101. package/game-ui/reference-record.md +0 -62
  102. package/game-ui/screen-hierarchy.md +0 -107
  103. package/game-ui/unity/architecture.md +0 -166
  104. package/game-ui/unity/cli-loop.md +0 -84
  105. package/game-ui/unity/data/unity-technologies-public-repositories.json +0 -26654
  106. package/game-ui/unity/org-wiki.md +0 -146
  107. package/game-ui/unity/repository-map.md +0 -102
  108. package/game-ui/unity/ui-systems.md +0 -85
  109. package/motion/practice-reference.md +0 -145
  110. package/motion/review-workflow.md +0 -86
  111. package/motion/vocabulary.md +0 -82
  112. package/platform-guides/apple-interaction.md +0 -89
  113. package/scripts/agent-native/events.mjs +0 -113
  114. package/scripts/agent-native/immutable-store.mjs +0 -102
  115. package/scripts/artifact-metadata.mjs +0 -20
  116. package/scripts/audit-evidence-freshness.mjs +0 -308
  117. package/scripts/baseline-contract.mjs +0 -189
  118. package/scripts/baseline-schema-parity.mjs +0 -40
  119. package/scripts/build-reference-artifacts.mjs +0 -127
  120. package/scripts/calibration-raw-contract.mjs +0 -172
  121. package/scripts/capture-session-contract.mjs +0 -187
  122. package/scripts/component-state-artifact-fixture.mjs +0 -44
  123. package/scripts/component-state-contract.mjs +0 -99
  124. package/scripts/component-state-semantics.mjs +0 -128
  125. package/scripts/component-state-workflow-contract.mjs +0 -67
  126. package/scripts/component-state-workflow-negative-cases.mjs +0 -64
  127. package/scripts/consumer-conformance-contract.mjs +0 -198
  128. package/scripts/consumer-evidence-governance-contract.mjs +0 -210
  129. package/scripts/consumer-reference-case-runner.mjs +0 -93
  130. package/scripts/consumer-reference-schema.mjs +0 -155
  131. package/scripts/create-component-state-session.mjs +0 -100
  132. package/scripts/create-page-evidence-session.mjs +0 -139
  133. package/scripts/domain-document-boundaries.mjs +0 -40
  134. package/scripts/domain-validation-checks.mjs +0 -141
  135. package/scripts/evidence-artifact-contract.mjs +0 -191
  136. package/scripts/finalize-component-state-evidence.mjs +0 -165
  137. package/scripts/finalize-page-evidence.mjs +0 -197
  138. package/scripts/generate-consumer-reference-evidence.mjs +0 -154
  139. package/scripts/generate-patterns.mjs +0 -218
  140. package/scripts/governance-matrix-contract.mjs +0 -73
  141. package/scripts/governance-matrix-negative-cases.mjs +0 -114
  142. package/scripts/governance-policy-contract.mjs +0 -49
  143. package/scripts/governance-test-fixture.mjs +0 -321
  144. package/scripts/governance-workflow-negative-cases.mjs +0 -241
  145. package/scripts/governed-profile-registry.mjs +0 -125
  146. package/scripts/json-schema-formats.mjs +0 -31
  147. package/scripts/markdown-structure.mjs +0 -45
  148. package/scripts/page-artifact-metadata.mjs +0 -124
  149. package/scripts/page-evidence-contract.mjs +0 -297
  150. package/scripts/page-evidence-fixture.mjs +0 -271
  151. package/scripts/pattern-data.mjs +0 -325
  152. package/scripts/profile-record-contract.mjs +0 -140
  153. package/scripts/promotion-attestation-contract.mjs +0 -91
  154. package/scripts/promotion-boundary-test-contract.mjs +0 -92
  155. package/scripts/promotion-fixture-inventory.mjs +0 -109
  156. package/scripts/promotion-governance-contract.mjs +0 -28
  157. package/scripts/reference-artifact-path-contract.mjs +0 -28
  158. package/scripts/reference-profile-contract.mjs +0 -114
  159. package/scripts/reference-token-contract.mjs +0 -156
  160. package/scripts/run-consumer-page-evidence-ci.mjs +0 -170
  161. package/scripts/summarize-sentinel-calibration.mjs +0 -98
  162. package/scripts/test-agent-adapter-conformance.mjs +0 -250
  163. package/scripts/test-agent-conformance-receipt.mjs +0 -106
  164. package/scripts/test-agent-events.mjs +0 -81
  165. package/scripts/test-agent-execution-effects.mjs +0 -114
  166. package/scripts/test-agent-execution-fixtures.mjs +0 -140
  167. package/scripts/test-agent-execution-kernel.mjs +0 -39
  168. package/scripts/test-agent-execution-learning.mjs +0 -130
  169. package/scripts/test-agent-execution-lifecycle.mjs +0 -143
  170. package/scripts/test-agent-execution-safety.mjs +0 -158
  171. package/scripts/test-agent-execution-views.mjs +0 -117
  172. package/scripts/test-agent-identity-integrity-cases.mjs +0 -160
  173. package/scripts/test-agent-knowledge-kernel.mjs +0 -183
  174. package/scripts/test-agent-learning.mjs +0 -246
  175. package/scripts/test-agent-mcp.mjs +0 -246
  176. package/scripts/test-agent-native-schemas.mjs +0 -215
  177. package/scripts/test-agent-projections.mjs +0 -249
  178. package/scripts/test-agent-registry-mcp-integrity.mjs +0 -215
  179. package/scripts/test-agent-registry-mutations.mjs +0 -110
  180. package/scripts/test-audit-evidence-freshness.mjs +0 -177
  181. package/scripts/test-component-state-sentinel.mjs +0 -35
  182. package/scripts/test-component-state-source-contract.mjs +0 -83
  183. package/scripts/test-consumer-conformance-sentinel.mjs +0 -165
  184. package/scripts/test-consumer-reference-sentinel.mjs +0 -31
  185. package/scripts/test-generate-consumer-reference-evidence.mjs +0 -124
  186. package/scripts/test-json-cli-output.mjs +0 -151
  187. package/scripts/test-json-schema-formats.mjs +0 -40
  188. package/scripts/test-reference-adapters.mjs +0 -199
  189. package/scripts/test-renderer-purity.mjs +0 -34
  190. package/scripts/test-sg-cli.mjs +0 -129
  191. package/scripts/test-summarize-sentinel-calibration.mjs +0 -226
  192. package/scripts/test-validate-baseline-manifest.mjs +0 -234
  193. package/scripts/test-validate-component-state-artifacts.mjs +0 -243
  194. package/scripts/test-validate-component-state.mjs +0 -106
  195. package/scripts/test-validate-consumer-conformance.mjs +0 -427
  196. package/scripts/test-validate-consumer-reference-cli.mjs +0 -69
  197. package/scripts/test-validate-consumer-reference.mjs +0 -263
  198. package/scripts/test-validate-domains.mjs +0 -357
  199. package/scripts/test-validate-governance.mjs +0 -292
  200. package/scripts/test-validate-ia.mjs +0 -262
  201. package/scripts/test-validate-okf.mjs +0 -73
  202. package/scripts/test-validate-page-evidence.mjs +0 -302
  203. package/scripts/test-validate-patterns.mjs +0 -157
  204. package/scripts/test-validate-promotion-rfc.mjs +0 -250
  205. package/scripts/test-validate-reference-profiles.mjs +0 -170
  206. package/scripts/test-validate-unity-org-wiki.mjs +0 -57
  207. package/scripts/test-validate-unity-source-contracts.mjs +0 -67
  208. package/scripts/test-validate-vocabulary.mjs +0 -174
  209. package/scripts/test-validate-webpage-workflow.mjs +0 -293
  210. package/scripts/validate-baseline-manifest.mjs +0 -44
  211. package/scripts/validate-catalog.mjs +0 -65
  212. package/scripts/validate-component-state.mjs +0 -141
  213. package/scripts/validate-consumer-conformance.mjs +0 -477
  214. package/scripts/validate-consumer-reference.mjs +0 -288
  215. package/scripts/validate-domains.mjs +0 -237
  216. package/scripts/validate-governance.mjs +0 -248
  217. package/scripts/validate-ia.mjs +0 -136
  218. package/scripts/validate-links.mjs +0 -66
  219. package/scripts/validate-okf.mjs +0 -104
  220. package/scripts/validate-page-evidence.mjs +0 -191
  221. package/scripts/validate-patterns.mjs +0 -246
  222. package/scripts/validate-promotion-rfc.mjs +0 -224
  223. package/scripts/validate-reference-artifacts.mjs +0 -125
  224. package/scripts/validate-renderer-purity.mjs +0 -56
  225. package/scripts/validate-unity-org-wiki.mjs +0 -146
  226. package/scripts/validate-unity-source-contracts.mjs +0 -107
  227. package/scripts/validate-vocabulary.mjs +0 -115
  228. package/scripts/validate-webpage-workflow.mjs +0 -254
  229. package/scripts/visual-expectation-contract.mjs +0 -20
  230. package/scripts/workflow-action-contract.mjs +0 -163
@@ -0,0 +1,319 @@
1
+ import { createHash, randomBytes } from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+
6
+ import { canonicalize, deepFreeze } from "../canonical-json.mjs";
7
+ import {
8
+ createMaterialManifest,
9
+ materialAdmissionPolicy,
10
+ materialStableRefForPath,
11
+ materialVersionIdForSource,
12
+ resolveMaterialRecord,
13
+ validateMaterialManifest,
14
+ } from "./material-admission.mjs";
15
+
16
+ export const MATERIAL_REGISTRY_PATH = "consumer-reference/agent-native/v2/material-registry.json";
17
+ const REGULAR_MODES = new Set(["100644", "100755"]);
18
+ const sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
19
+
20
+ export class MaterialRegistryError extends TypeError {
21
+ constructor(code, message, sourcePath) {
22
+ super(message);
23
+ this.name = "MaterialRegistryError";
24
+ this.code = code;
25
+ if (sourcePath !== undefined) this.path = sourcePath;
26
+ }
27
+ }
28
+
29
+ function fail(code, message, sourcePath) { throw new MaterialRegistryError(code, message, sourcePath); }
30
+ function resultFailure(code, message, sourcePath) {
31
+ return deepFreeze({ ok: false, failures: [{ code, message, ...(sourcePath === undefined ? {} : { path: sourcePath }) }], materials: [] });
32
+ }
33
+ function assertOptions(options, allowed) {
34
+ if (!options || typeof options !== "object" || Array.isArray(options)) fail("material_registry_option_invalid", "options must be an object");
35
+ const unexpected = Object.keys(options).filter((key) => !allowed.has(key));
36
+ if (unexpected.length > 0) fail("material_registry_option_invalid", `unsupported option: ${unexpected[0]}`);
37
+ if (typeof options.repositoryRoot !== "string" || options.repositoryRoot.length === 0) fail("material_repository_invalid", "repositoryRoot must be a non-empty string");
38
+ }
39
+ function realpath(fileSystem, target) {
40
+ const implementation = fileSystem.realpathSync.native ?? fileSystem.realpathSync;
41
+ return implementation.call(fileSystem.realpathSync, target);
42
+ }
43
+ function repositoryState(repositoryRoot) {
44
+ const resolvedRoot = path.resolve(repositoryRoot);
45
+ let stats;
46
+ try { stats = fs.lstatSync(resolvedRoot); } catch (error) { fail("material_repository_invalid", `repository root is unavailable: ${error.message}`); }
47
+ if (!stats.isDirectory() || stats.isSymbolicLink()) fail("material_repository_invalid", "repository root must be a non-symlink directory");
48
+ return { resolvedRoot, canonicalRoot: realpath(fs, resolvedRoot) };
49
+ }
50
+ function trackedInventory(repositoryRoot) {
51
+ const result = spawnSync("git", ["-C", repositoryRoot, "ls-files", "-s", "-z", "--"], {
52
+ encoding: "buffer", maxBuffer: 16 * 1024 * 1024, timeout: 30_000,
53
+ });
54
+ if (result.status !== 0) fail("material_inventory_failed", result.error?.message ?? (result.stderr.toString("utf8").trim() || "git ls-files failed"));
55
+ const entries = new Map();
56
+ const text = result.stdout.subarray(0, result.stdout.at(-1) === 0 ? result.stdout.length - 1 : result.stdout.length).toString("utf8");
57
+ for (const encoded of text.split("\0").filter(Boolean)) {
58
+ const tab = encoded.indexOf("\t");
59
+ const metadata = encoded.slice(0, tab).split(" ");
60
+ if (tab < 0 || metadata.length !== 3) fail("material_inventory_failed", "Git inventory entry is malformed");
61
+ entries.set(encoded.slice(tab + 1), { mode: metadata[0], stage: metadata[2] });
62
+ }
63
+ return entries;
64
+ }
65
+ function inspectPath(root, repositoryPath) {
66
+ let current = root.resolvedRoot;
67
+ let stats;
68
+ try {
69
+ for (const component of repositoryPath.split("/")) {
70
+ current = path.join(current, component);
71
+ stats = fs.lstatSync(current);
72
+ if (stats.isSymbolicLink()) fail("material_path_symlink", "material path components must not be symlinks", repositoryPath);
73
+ }
74
+ } catch (error) {
75
+ if (error instanceof MaterialRegistryError) throw error;
76
+ fail("material_path_unavailable", `tracked material path is unavailable: ${error.message}`, repositoryPath);
77
+ }
78
+ if (!stats.isFile()) fail("material_path_not_regular", "material path must be a regular file", repositoryPath);
79
+ const canonicalTarget = realpath(fs, current);
80
+ const expectedTarget = path.resolve(root.canonicalRoot, ...repositoryPath.split("/"));
81
+ if (canonicalTarget !== expectedTarget || !canonicalTarget.startsWith(`${root.canonicalRoot}${path.sep}`)) {
82
+ fail("material_path_escape", "material canonical path escapes the repository root", repositoryPath);
83
+ }
84
+ return { target: current, canonicalTarget, dev: stats.dev, ino: stats.ino };
85
+ }
86
+ function readInspected(inspection, repositoryPath) {
87
+ let descriptor;
88
+ try {
89
+ descriptor = fs.openSync(inspection.target, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
90
+ const descriptorStats = fs.fstatSync(descriptor);
91
+ const currentStats = fs.lstatSync(inspection.target);
92
+ if (!descriptorStats.isFile() || currentStats.isSymbolicLink() || !currentStats.isFile()
93
+ || descriptorStats.dev !== inspection.dev || descriptorStats.ino !== inspection.ino
94
+ || currentStats.dev !== inspection.dev || currentStats.ino !== inspection.ino
95
+ || realpath(fs, inspection.target) !== inspection.canonicalTarget) {
96
+ fail("material_path_race", "material path identity changed after preflight", repositoryPath);
97
+ }
98
+ return fs.readFileSync(descriptor);
99
+ } catch (error) {
100
+ if (error instanceof MaterialRegistryError) throw error;
101
+ const code = error?.code === "ELOOP" || error?.code === "ENOENT" ? "material_path_race" : "material_read_failed";
102
+ fail(code, `material could not be read safely: ${error.message}`, repositoryPath);
103
+ } finally {
104
+ if (descriptor !== undefined) fs.closeSync(descriptor);
105
+ }
106
+ }
107
+
108
+ function preflightAll(repositoryRoot) {
109
+ const root = repositoryState(repositoryRoot);
110
+ const inventory = trackedInventory(repositoryRoot);
111
+ const inspections = new Map();
112
+ for (const route of materialAdmissionPolicy.allowed_materials) {
113
+ const entry = inventory.get(route.repository_path);
114
+ if (!entry) fail("material_path_untracked", "material path is absent from tracked Git inventory", route.repository_path);
115
+ if (!REGULAR_MODES.has(entry.mode) || entry.stage !== "0") fail("material_git_mode_invalid", "material Git index entry must be a stage-zero regular blob", route.repository_path);
116
+ }
117
+ for (const route of materialAdmissionPolicy.allowed_materials) inspections.set(route.repository_path, inspectPath(root, route.repository_path));
118
+ return inspections;
119
+ }
120
+
121
+ export function generateMaterialRegistry(options) {
122
+ assertOptions(options, new Set(["repositoryRoot"]));
123
+ const inspections = preflightAll(options.repositoryRoot);
124
+ const materials = materialAdmissionPolicy.allowed_materials.map((route) => {
125
+ const bytes = readInspected(inspections.get(route.repository_path), route.repository_path);
126
+ const source_sha256 = sha256(bytes);
127
+ const stable_ref = materialStableRefForPath(route.repository_path);
128
+ return {
129
+ schema_version: "2.0",
130
+ record_kind: "material",
131
+ stable_ref,
132
+ version_id: materialVersionIdForSource(stable_ref, source_sha256),
133
+ repository_path: route.repository_path,
134
+ media_type: materialAdmissionPolicy.media_type,
135
+ source_sha256,
136
+ byte_length: bytes.byteLength,
137
+ lifecycle: route.lifecycle,
138
+ domain: route.domain,
139
+ };
140
+ });
141
+ const manifest = createMaterialManifest(materials);
142
+ const validation = validateMaterialManifest({ repositoryRoot: options.repositoryRoot, manifest });
143
+ if (!validation.ok) fail(validation.failures[0].code, validation.failures[0].message, validation.failures[0].path);
144
+ if (validation.materials.length !== materialAdmissionPolicy.allowed_materials.length) fail("material_registry_cardinality_invalid", "generated registry does not contain the sealed allow-set");
145
+ return manifest;
146
+ }
147
+
148
+ export function validateMaterialRegistry(options) {
149
+ assertOptions(options, new Set(["repositoryRoot", "manifest"]));
150
+ if (!Object.hasOwn(options, "manifest")) return resultFailure("material_manifest_invalid", "manifest is required");
151
+ const result = validateMaterialManifest({ repositoryRoot: options.repositoryRoot, manifest: options.manifest });
152
+ if (!result.ok) return result;
153
+ if (result.materials.length !== materialAdmissionPolicy.allowed_materials.length) return resultFailure("material_registry_cardinality_invalid", "material registry must contain exactly the sealed allow-set");
154
+ const actual = new Set(result.materials.map(({ repository_path }) => repository_path));
155
+ const missing = materialAdmissionPolicy.allowed_materials.find(({ repository_path }) => !actual.has(repository_path));
156
+ if (missing) return resultFailure("material_registry_path_set_invalid", "material registry is missing an admitted policy path", missing.repository_path);
157
+ return result;
158
+ }
159
+
160
+ export function loadMaterialRegistry(options) {
161
+ assertOptions(options, new Set(["repositoryRoot"]));
162
+ const target = path.join(path.resolve(options.repositoryRoot), ...MATERIAL_REGISTRY_PATH.split("/"));
163
+ let bytes;
164
+ try {
165
+ const stats = fs.lstatSync(target);
166
+ if (!stats.isFile() || stats.isSymbolicLink()) fail("material_registry_file_invalid", "material registry must be a regular non-symlink file", MATERIAL_REGISTRY_PATH);
167
+ bytes = fs.readFileSync(target);
168
+ } catch (error) {
169
+ if (error instanceof MaterialRegistryError) throw error;
170
+ fail("material_registry_file_invalid", `material registry is unavailable: ${error.message}`, MATERIAL_REGISTRY_PATH);
171
+ }
172
+ let manifest;
173
+ try { manifest = JSON.parse(bytes.toString("utf8")); } catch (error) { fail("material_registry_json_invalid", error.message, MATERIAL_REGISTRY_PATH); }
174
+ if (!bytes.equals(Buffer.from(canonicalize(manifest), "utf8"))) fail("material_registry_canonical_invalid", "material registry bytes must be canonical JSON", MATERIAL_REGISTRY_PATH);
175
+ const validation = validateMaterialRegistry({ repositoryRoot: options.repositoryRoot, manifest });
176
+ if (!validation.ok) fail(validation.failures[0].code, validation.failures[0].message, validation.failures[0].path);
177
+ return deepFreeze(manifest);
178
+ }
179
+
180
+ function inspectOutputParent(repositoryRoot, fileSystem) {
181
+ const root = repositoryState(repositoryRoot);
182
+ let current = root.resolvedRoot;
183
+ const parentComponents = path.dirname(MATERIAL_REGISTRY_PATH).split("/");
184
+ for (const component of parentComponents) {
185
+ current = path.join(current, component);
186
+ try { fileSystem.mkdirSync(current, { mode: 0o755 }); } catch (error) { if (error.code !== "EEXIST") fail("material_registry_output_parent_invalid", `output parent cannot be created: ${error.message}`, MATERIAL_REGISTRY_PATH); }
187
+ let stats;
188
+ try { stats = fileSystem.lstatSync(current); } catch (error) { fail("material_registry_output_parent_invalid", `output parent is unavailable: ${error.message}`, MATERIAL_REGISTRY_PATH); }
189
+ if (stats.isSymbolicLink()) fail("material_registry_output_parent_symlink", "output parent components must not be symlinks", MATERIAL_REGISTRY_PATH);
190
+ if (!stats.isDirectory()) fail("material_registry_output_parent_invalid", "output parent components must be directories", MATERIAL_REGISTRY_PATH);
191
+ const canonical = realpath(fileSystem, current);
192
+ const expected = path.resolve(root.canonicalRoot, ...path.relative(root.resolvedRoot, current).split(path.sep));
193
+ if (canonical !== expected || (canonical !== root.canonicalRoot && !canonical.startsWith(`${root.canonicalRoot}${path.sep}`))) {
194
+ fail("material_registry_output_parent_escape", "output parent must remain inside the repository", MATERIAL_REGISTRY_PATH);
195
+ }
196
+ }
197
+ const stats = fileSystem.lstatSync(current);
198
+ return { path: current, canonical: realpath(fileSystem, current), dev: stats.dev, ino: stats.ino };
199
+ }
200
+
201
+ function parentUnchanged(parent, fileSystem) {
202
+ try {
203
+ const stats = fileSystem.lstatSync(parent.path);
204
+ return stats.isDirectory() && !stats.isSymbolicLink() && stats.dev === parent.dev && stats.ino === parent.ino && realpath(fileSystem, parent.path) === parent.canonical;
205
+ } catch { return false; }
206
+ }
207
+
208
+ function inspectOutputTarget(target, fileSystem) {
209
+ let stats;
210
+ try { stats = fileSystem.lstatSync(target); } catch (error) {
211
+ if (error.code === "ENOENT") return { exists: false };
212
+ fail("material_registry_output_invalid", `output target is unavailable: ${error.message}`, MATERIAL_REGISTRY_PATH);
213
+ }
214
+ if (stats.isSymbolicLink()) fail("material_registry_output_symlink", "output target must not be a symlink", MATERIAL_REGISTRY_PATH);
215
+ if (!stats.isFile()) fail("material_registry_output_type_invalid", "output target must be a regular file", MATERIAL_REGISTRY_PATH);
216
+ return { exists: true, dev: stats.dev, ino: stats.ino };
217
+ }
218
+
219
+ function readOutputTarget(target, expected, fileSystem) {
220
+ let descriptor;
221
+ try {
222
+ descriptor = fileSystem.openSync(target, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
223
+ const stats = fileSystem.fstatSync(descriptor);
224
+ const current = fileSystem.lstatSync(target);
225
+ if (!stats.isFile() || current.isSymbolicLink() || !current.isFile()
226
+ || (expected?.exists && (stats.dev !== expected.dev || stats.ino !== expected.ino || current.dev !== expected.dev || current.ino !== expected.ino))) {
227
+ fail("material_registry_output_race", "output target identity changed during read", MATERIAL_REGISTRY_PATH);
228
+ }
229
+ return fileSystem.readFileSync(descriptor);
230
+ } catch (error) {
231
+ if (error instanceof MaterialRegistryError) throw error;
232
+ const code = error.code === "ELOOP" ? "material_registry_output_symlink" : "material_registry_output_read_failed";
233
+ fail(code, `output target cannot be read safely: ${error.message}`, MATERIAL_REGISTRY_PATH);
234
+ } finally { if (descriptor !== undefined) fileSystem.closeSync(descriptor); }
235
+ }
236
+
237
+ function postWriteValidation(repositoryRoot, manifest, expectedBytes, target, parent, fileSystem) {
238
+ if (!parentUnchanged(parent, fileSystem)) fail("material_registry_output_parent_race", "output parent identity changed during publication", MATERIAL_REGISTRY_PATH);
239
+ const targetState = inspectOutputTarget(target, fileSystem);
240
+ if (!targetState.exists) fail("material_registry_postwrite_invalid", "published registry is missing", MATERIAL_REGISTRY_PATH);
241
+ const finalBytes = readOutputTarget(target, targetState, fileSystem);
242
+ if (!finalBytes.equals(expectedBytes)) fail("material_registry_postwrite_invalid", "published registry bytes differ from generated canonical bytes", MATERIAL_REGISTRY_PATH);
243
+ let persisted;
244
+ try { persisted = JSON.parse(finalBytes.toString("utf8")); } catch (error) { fail("material_registry_postwrite_invalid", `published registry JSON is invalid: ${error.message}`, MATERIAL_REGISTRY_PATH); }
245
+ if (canonicalize(persisted) !== finalBytes.toString("utf8") || canonicalize(persisted) !== canonicalize(manifest)) {
246
+ fail("material_registry_postwrite_invalid", "published registry is not the generated canonical manifest", MATERIAL_REGISTRY_PATH);
247
+ }
248
+ const validation = validateMaterialRegistry({ repositoryRoot, manifest: persisted });
249
+ if (!validation.ok) {
250
+ const first = validation.failures[0];
251
+ const trackingCodes = new Set(["material_path_untracked", "material_git_mode_invalid", "material_inventory_failed"]);
252
+ const code = trackingCodes.has(first.code) ? "material_registry_postwrite_tracking_drift" : "material_registry_postwrite_source_drift";
253
+ fail(code, `post-write validation failed: ${first.code}`, first.path);
254
+ }
255
+ }
256
+
257
+ export function writeMaterialRegistry(options) {
258
+ assertOptions(options, new Set(["repositoryRoot", "fileSystem"]));
259
+ const fileSystem = options.fileSystem ?? fs;
260
+ if (!fileSystem || typeof fileSystem !== "object") fail("material_registry_option_invalid", "fileSystem must implement the filesystem contract");
261
+ const manifest = generateMaterialRegistry({ repositoryRoot: options.repositoryRoot });
262
+ const bytes = Buffer.from(canonicalize(manifest), "utf8");
263
+ const parent = inspectOutputParent(options.repositoryRoot, fileSystem);
264
+ const target = path.join(parent.path, path.basename(MATERIAL_REGISTRY_PATH));
265
+ const initial = inspectOutputTarget(target, fileSystem);
266
+ let changed = true;
267
+ if (initial.exists) changed = !readOutputTarget(target, initial, fileSystem).equals(bytes);
268
+ let temporary;
269
+ let descriptor;
270
+ try {
271
+ if (changed) {
272
+ temporary = path.join(parent.path, `.material-registry.json.${process.pid}.${randomBytes(12).toString("hex")}`);
273
+ try {
274
+ descriptor = fileSystem.openSync(temporary, fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL | (fs.constants.O_NOFOLLOW ?? 0), 0o600);
275
+ fileSystem.writeFileSync(descriptor, bytes);
276
+ fileSystem.fsyncSync(descriptor);
277
+ fileSystem.fchmodSync(descriptor, 0o644);
278
+ } catch (error) {
279
+ fail("material_registry_output_write_failed", `temporary registry write failed: ${error.message}`, MATERIAL_REGISTRY_PATH);
280
+ } finally {
281
+ if (descriptor !== undefined) { fileSystem.closeSync(descriptor); descriptor = undefined; }
282
+ }
283
+ if (!parentUnchanged(parent, fileSystem)) fail("material_registry_output_parent_race", "output parent changed before publication", MATERIAL_REGISTRY_PATH);
284
+ const current = inspectOutputTarget(target, fileSystem);
285
+ if (initial.exists !== current.exists || (initial.exists && (initial.dev !== current.dev || initial.ino !== current.ino))) {
286
+ if (current.exists && readOutputTarget(target, current, fileSystem).equals(bytes)) changed = false;
287
+ else fail("material_registry_output_race", "output target changed before publication", MATERIAL_REGISTRY_PATH);
288
+ }
289
+ if (changed) {
290
+ try { fileSystem.renameSync(temporary, target); temporary = undefined; }
291
+ catch (error) {
292
+ const code = parentUnchanged(parent, fileSystem) ? "material_registry_output_publish_failed" : "material_registry_output_parent_race";
293
+ fail(code, `atomic registry publication failed: ${error.message}`, MATERIAL_REGISTRY_PATH);
294
+ }
295
+ let parentDescriptor;
296
+ try { parentDescriptor = fileSystem.openSync(parent.path, fs.constants.O_RDONLY); fileSystem.fsyncSync(parentDescriptor); }
297
+ catch (error) { fail("material_registry_output_sync_failed", `output directory sync failed: ${error.message}`, MATERIAL_REGISTRY_PATH); }
298
+ finally { if (parentDescriptor !== undefined) fileSystem.closeSync(parentDescriptor); }
299
+ }
300
+ }
301
+ postWriteValidation(options.repositoryRoot, manifest, bytes, target, parent, fileSystem);
302
+ } finally {
303
+ if (descriptor !== undefined) fileSystem.closeSync(descriptor);
304
+ if (temporary !== undefined) { try { fileSystem.unlinkSync(temporary); } catch (error) { if (error.code !== "ENOENT") throw error; } }
305
+ }
306
+ return deepFreeze({ changed, byte_length: bytes.byteLength, path: MATERIAL_REGISTRY_PATH, sha256: sha256(bytes), version_id: manifest.version_id });
307
+ }
308
+
309
+ export function readManifestBoundMaterial(options) {
310
+ assertOptions(options, new Set(["repositoryRoot", "manifest", "reference"]));
311
+ const validation = validateMaterialRegistry({ repositoryRoot: options.repositoryRoot, manifest: options.manifest });
312
+ if (!validation.ok) fail(validation.failures[0].code, validation.failures[0].message, validation.failures[0].path);
313
+ const record = resolveMaterialRecord({ manifest: options.manifest, reference: options.reference });
314
+ const inspection = inspectPath(repositoryState(options.repositoryRoot), record.repository_path);
315
+ const bytes = readInspected(inspection, record.repository_path);
316
+ if (sha256(bytes) !== record.source_sha256) fail("material_source_hash_mismatch", "material bytes do not match source_sha256", record.repository_path);
317
+ if (bytes.byteLength !== record.byte_length) fail("material_byte_length_mismatch", "material bytes do not match byte_length", record.repository_path);
318
+ return { record, bytes };
319
+ }
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { realpathSync } from "node:fs";
4
+ import { Transform } from "node:stream";
5
+ import { fileURLToPath } from "node:url";
6
+
7
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
8
+
9
+ import { createMaterialMcpServer } from "./agent-native/v2/material-mcp-adapter.mjs";
10
+
11
+ // Maximum raw bytes in one newline-delimited JSON-RPC payload, excluding the LF delimiter.
12
+ export const MATERIAL_MCP_MAX_FRAME_BYTES = 1024 * 1024;
13
+ export const MATERIAL_MCP_FRAME_LIMIT_MESSAGE = `material MCP input frame exceeds ${MATERIAL_MCP_MAX_FRAME_BYTES}-byte limit`;
14
+
15
+ export class MaterialMcpStdin extends Transform {
16
+ constructor(maxFrameBytes = MATERIAL_MCP_MAX_FRAME_BYTES) {
17
+ super();
18
+ this.maxFrameBytes = maxFrameBytes;
19
+ this.frame = Buffer.allocUnsafe(maxFrameBytes + 1);
20
+ this.frameBytes = 0;
21
+ }
22
+
23
+ _transform(chunk, encoding, callback) {
24
+ const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, encoding);
25
+ let offset = 0;
26
+ while (offset < bytes.byteLength) {
27
+ const newline = bytes.indexOf(0x0a, offset);
28
+ const end = newline === -1 ? bytes.byteLength : newline;
29
+ const segmentBytes = end - offset;
30
+ if (this.frameBytes + segmentBytes > this.maxFrameBytes) {
31
+ this.frameBytes = 0;
32
+ const error = new Error(MATERIAL_MCP_FRAME_LIMIT_MESSAGE);
33
+ error.code = "ERR_MATERIAL_MCP_FRAME_TOO_LARGE";
34
+ callback(error);
35
+ return;
36
+ }
37
+ if (segmentBytes > 0) {
38
+ bytes.copy(this.frame, this.frameBytes, offset, end);
39
+ this.frameBytes += segmentBytes;
40
+ }
41
+ if (newline === -1) break;
42
+ this.frame[this.frameBytes] = 0x0a;
43
+ this.push(Buffer.from(this.frame.subarray(0, this.frameBytes + 1)));
44
+ this.frameBytes = 0;
45
+ offset = newline + 1;
46
+ }
47
+ callback();
48
+ }
49
+
50
+ _destroy(error, callback) {
51
+ this.frame = Buffer.alloc(0);
52
+ this.frameBytes = 0;
53
+ callback(error);
54
+ }
55
+ }
56
+
57
+ async function main() {
58
+ const server = createMaterialMcpServer();
59
+ const input = new MaterialMcpStdin();
60
+ const transport = new StdioServerTransport(input);
61
+ let failed = false;
62
+ const failOversizedFrame = (error) => {
63
+ if (failed || error?.code !== "ERR_MATERIAL_MCP_FRAME_TOO_LARGE") return;
64
+ failed = true;
65
+ process.stderr.write(`${error.message}\n`);
66
+ process.exitCode = 1;
67
+ process.stdin.destroy();
68
+ void transport.close();
69
+ };
70
+ input.on("error", failOversizedFrame);
71
+ transport.onerror = failOversizedFrame;
72
+ process.stdout.on("error", (error) => {
73
+ if (error?.code !== "EPIPE") throw error;
74
+ process.stderr.write("material MCP output closed\n");
75
+ process.exitCode = 1;
76
+ process.stdin.destroy();
77
+ void transport.close();
78
+ });
79
+ await server.connect(transport);
80
+ process.stdin.pipe(input);
81
+ }
82
+
83
+ function isDirectRun(entryPath) {
84
+ if (!entryPath) return false;
85
+ try {
86
+ return realpathSync(entryPath) === realpathSync(fileURLToPath(import.meta.url));
87
+ } catch (error) {
88
+ if (["ENOENT", "ENOTDIR"].includes(error?.code)) return false;
89
+ throw error;
90
+ }
91
+ }
92
+
93
+ if (isDirectRun(process.argv[1])) {
94
+ await main().catch((error) => {
95
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
96
+ process.exitCode = 1;
97
+ });
98
+ }
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ function emergencyReport() {
4
+ return {
5
+ failures: [{ code: "material_cli_failed", message: "material CLI failed" }],
6
+ ok: false,
7
+ operation: null,
8
+ };
9
+ }
10
+
11
+ function writeProtocol(output, exitCode) {
12
+ process.stdout.on("error", () => { process.exitCode = 1; });
13
+ process.stdout.write(output);
14
+ process.exitCode = exitCode;
15
+ }
16
+
17
+ async function main() {
18
+ try {
19
+ const { runMaterialCli } = await import("./agent-native/v2/material-cli-adapter.mjs");
20
+ const result = runMaterialCli(process.argv.slice(2));
21
+ writeProtocol(result.output, result.exitCode);
22
+ } catch {
23
+ writeProtocol(`${JSON.stringify(emergencyReport(), null, 2)}\n`, 1);
24
+ }
25
+ }
26
+
27
+ await main();
@@ -1,36 +0,0 @@
1
- import path from "node:path";
2
- import StyleDictionary from "style-dictionary";
3
-
4
- export const adapter = Object.freeze({ name: "style-dictionary", version: "5.5.0" });
5
-
6
- const durationTransform = "stylegallery/duration-css";
7
- if (!Object.hasOwn(StyleDictionary.hooks.transforms, durationTransform)) {
8
- StyleDictionary.registerTransform({
9
- filter: (token) => token.$type === "duration",
10
- name: durationTransform,
11
- transform: (token) => `${token.$value.value}${token.$value.unit}`,
12
- transitive: true,
13
- type: "value",
14
- });
15
- }
16
-
17
- export function createStyleDictionaryConfig(source, output) {
18
- return {
19
- log: { verbosity: "verbose", warnings: "warn" },
20
- platforms: {
21
- css: {
22
- buildPath: `${path.dirname(output)}${path.sep}`,
23
- files: [
24
- {
25
- destination: path.basename(output),
26
- format: "css/variables",
27
- options: { outputReferences: true },
28
- },
29
- ],
30
- transforms: [...StyleDictionary.hooks.transformGroups.css, durationTransform],
31
- },
32
- },
33
- source: [source],
34
- usesDtcg: true,
35
- };
36
- }