@design-twin/dtwin 0.0.0-stage → 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 (69) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +959 -2
  3. package/figma-plugin/code.js +4207 -0
  4. package/figma-plugin/manifest.json +28 -0
  5. package/figma-plugin/ui.html +686 -0
  6. package/layer/cross-check.js +2746 -0
  7. package/layer/drift-lint.js +1526 -0
  8. package/layer/get-component.js +553 -0
  9. package/layer/map-bootstrap.js +1404 -0
  10. package/layer/map-validate.js +397 -0
  11. package/package.json +53 -4
  12. package/src/abort-reason.ts +12 -0
  13. package/src/asset-compare.ts +175 -0
  14. package/src/asset-owners.ts +280 -0
  15. package/src/atomic-write.ts +79 -0
  16. package/src/bridge-holder.ts +294 -0
  17. package/src/cli-commands.ts +427 -0
  18. package/src/client-presence.ts +146 -0
  19. package/src/clock.ts +45 -0
  20. package/src/commands.ts +561 -0
  21. package/src/daemon-auth.ts +174 -0
  22. package/src/daemon.ts +788 -0
  23. package/src/delivery.ts +85 -0
  24. package/src/design-system-layout.ts +232 -0
  25. package/src/doc-types.ts +1054 -0
  26. package/src/doctor.ts +602 -0
  27. package/src/errmsg.ts +14 -0
  28. package/src/export-reader.ts +409 -0
  29. package/src/export-verdict.ts +258 -0
  30. package/src/figma-mcp.ts +942 -0
  31. package/src/figma-pull.ts +1265 -0
  32. package/src/file-lock.ts +268 -0
  33. package/src/file-memo.ts +62 -0
  34. package/src/hash.ts +6 -0
  35. package/src/hex-color.ts +39 -0
  36. package/src/human-ms.ts +7 -0
  37. package/src/init.ts +424 -0
  38. package/src/instance-overrides.ts +7 -0
  39. package/src/json-file.ts +79 -0
  40. package/src/json-size.ts +108 -0
  41. package/src/json-util.ts +51 -0
  42. package/src/library-layout.ts +193 -0
  43. package/src/node-id.ts +69 -0
  44. package/src/pages-layout.ts +483 -0
  45. package/src/pending-requests.ts +187 -0
  46. package/src/plugin-frames.ts +32 -0
  47. package/src/png.ts +196 -0
  48. package/src/ports.ts +25 -0
  49. package/src/project-layout.ts +189 -0
  50. package/src/quick-keys.ts +68 -0
  51. package/src/read-json.ts +67 -0
  52. package/src/read-opts.ts +125 -0
  53. package/src/read-plan.ts +105 -0
  54. package/src/read-run.ts +119 -0
  55. package/src/route.ts +243 -0
  56. package/src/seed-components.ts +229 -0
  57. package/src/served-session.ts +347 -0
  58. package/src/server-core.ts +1093 -0
  59. package/src/settings.ts +156 -0
  60. package/src/source-stamp.ts +16 -0
  61. package/src/staleness.ts +63 -0
  62. package/src/stdio.ts +156 -0
  63. package/src/svg-normalize.ts +205 -0
  64. package/src/timeouts.ts +76 -0
  65. package/src/timings.ts +118 -0
  66. package/src/token-store.ts +261 -0
  67. package/src/variables-merge.ts +337 -0
  68. package/src/verbs.ts +140 -0
  69. package/src/write-out.ts +1255 -0
@@ -0,0 +1,553 @@
1
+ // GENERATED from design-to-code/ by claude-plugin/build-scripts.js — edit the source, then rebuild.
2
+
3
+
4
+ // design-to-code/get-component.ts
5
+ import path2 from "node:path";
6
+
7
+ // design-to-code/types.ts
8
+ var PLAN_VERIFICATION_RECORD_SCHEMA = "designtwin/plan-verification-record@2";
9
+ function isJsonObject(x) {
10
+ return typeof x === "object" && x !== null && !Array.isArray(x);
11
+ }
12
+
13
+ // bridge/src/json-util.ts
14
+ function isStringArray(x) {
15
+ return Array.isArray(x) && x.every((v) => typeof v === "string");
16
+ }
17
+
18
+ // design-to-code/doc-guards.ts
19
+ function optArrayOf(x, each) {
20
+ return x === void 0 || Array.isArray(x) && x.every(each);
21
+ }
22
+ var optObj = (x) => x === void 0 || isJsonObject(x);
23
+ var optStr = (x) => x === void 0 || typeof x === "string";
24
+ var anyObject = (x) => isJsonObject(x);
25
+ function isVariable(x) {
26
+ return isJsonObject(x) && typeof x.name === "string" && typeof x.type === "string" && isJsonObject(x.values) && optStr(x.collection);
27
+ }
28
+ function isVariableCollection(x) {
29
+ return isJsonObject(x) && typeof x.name === "string" && isStringArray(x.modes);
30
+ }
31
+ function isTokensDoc(x) {
32
+ return isJsonObject(x) && optArrayOf(x.variables, isVariable) && optArrayOf(x.collections, isVariableCollection) && optArrayOf(x._slices, anyObject) && optArrayOf(x._conflicts, anyObject) && (x.hygiene === void 0 || isStringArray(x.hygiene));
33
+ }
34
+ isTokensDoc.expected = "a token catalog: an object whose `variables` (each {name, type, values}) and `collections` (each {name, modes[]}), when present, are arrays";
35
+ function isCatalogComponent(x) {
36
+ return isJsonObject(x) && typeof x.name === "string" && optStr(x.key) && optStr(x.id) && optObj(x.props) && optArrayOf(x.variants, anyObject);
37
+ }
38
+ function isComponentsCatalog(x) {
39
+ return isJsonObject(x) && Array.isArray(x.components) && x.components.every(isCatalogComponent);
40
+ }
41
+ isComponentsCatalog.expected = "a component catalog: an object with a `components` array of {name, type, key?, id?, props?}";
42
+ function isComponentDetailFile(x) {
43
+ return isJsonObject(x) && typeof x.name === "string" && optArrayOf(x.variants, anyObject) && optObj(x.node);
44
+ }
45
+ isComponentDetailFile.expected = "a component detail file: an object with a `name` and `variants[]` or `node`";
46
+ function isTextStylesDoc(x) {
47
+ return isJsonObject(x) && Array.isArray(x.styles) && x.styles.every((s) => isJsonObject(s) && typeof s.name === "string");
48
+ }
49
+ isTextStylesDoc.expected = "a text-style sheet: an object with a `styles` array of {name, \u2026}";
50
+ function isScreenAssetsDoc(x) {
51
+ return isJsonObject(x) && optArrayOf(x.heavy, (h) => isJsonObject(h) && typeof h.file === "string" && typeof h.bytes === "number" && (h.paths === void 0 || typeof h.paths === "number") && (h.embeddedRaster === void 0 || typeof h.embeddedRaster === "number")) && optArrayOf(x.files, (f) => isJsonObject(f) && typeof f.file === "string" && optStr(f.node));
52
+ }
53
+ isScreenAssetsDoc.expected = "a screen asset manifest: an object whose `heavy` ({file, bytes}) and `files` ({file, node?}), when present, are arrays";
54
+ function isLibrariesIndex(x) {
55
+ return isJsonObject(x) && Array.isArray(x.libraries) && x.libraries.every((r) => isJsonObject(r) && typeof r.dir === "string" && optStr(r.libraryName) && (r.collectionKeys === void 0 || isStringArray(r.collectionKeys)));
56
+ }
57
+ isLibrariesIndex.expected = "a library index: an object with a `libraries` array of {dir, libraryName?, collectionKeys?}";
58
+ var SEVERITIES = ["blocker", "warning", "info"];
59
+ function isAuditOverridesDoc(x) {
60
+ return isJsonObject(x) && Array.isArray(x.overrides) && x.overrides.every((o) => isJsonObject(o) && typeof o.code === "string" && typeof o.severity === "string" && SEVERITIES.includes(o.severity) && typeof o.reason === "string" && o.reason.trim() !== "" && ["nodeId", "token", "component", "collection", "mode", "category", "state", "screen", "decidedBy", "decidedAt"].every((k) => optStr(o[k])));
61
+ }
62
+ isAuditOverridesDoc.expected = "an audit overrides file: { overrides: [{ code, severity: blocker|warning|info, reason (non-empty), nodeId?, token?, component?, collection?, mode?, category?, state?, screen?, decidedBy?, decidedAt? }] }";
63
+ function isAuditReport(x) {
64
+ return isJsonObject(x) && isJsonObject(x.summary) && Array.isArray(x.findings) && x.findings.every((f) => isJsonObject(f) && typeof f.severity === "string" && typeof f.code === "string");
65
+ }
66
+ isAuditReport.expected = "an audit report (written by the audit script's --out): an object with `summary` and a `findings` array of {severity, code, message}";
67
+ function isProposal(x) {
68
+ return isJsonObject(x) && typeof x.name === "string";
69
+ }
70
+ function isProposalList(x) {
71
+ return Array.isArray(x) && x.every(isProposal);
72
+ }
73
+ isProposalList.expected = "a list of component proposals: an array of {name, catalog, confirmed, \u2026}";
74
+ function isVerifyExpectation(x) {
75
+ return isJsonObject(x) && isJsonObject(x.frame) && Array.isArray(x.nodes) && x.nodes.every((n) => isJsonObject(n) && typeof n.nodeId === "string") && optArrayOf(x.instances, anyObject) && optArrayOf(x.interactions, anyObject) && optArrayOf(x.notComparable, anyObject);
76
+ }
77
+ isVerifyExpectation.expected = "a verify expectation (the verify-screen script's --expect output): an object with `frame` and a `nodes` array of {nodeId, \u2026}";
78
+ var isNameVersion = (x) => isJsonObject(x) && typeof x.version === "string" && (typeof x.package === "string" || typeof x.name === "string");
79
+ function isProbeIdentity(x) {
80
+ return isJsonObject(x) && typeof x.name === "string" && (x.version === null || typeof x.version === "string") && typeof x.sha256 === "string" && isNameVersion(x.playwright) && isNameVersion(x.browser);
81
+ }
82
+ function isBuildIdentity(x) {
83
+ return isJsonObject(x) && typeof x.url === "string" && (x.mode === "vite-dev" || x.mode === "static" || x.mode === "unknown") && typeof x.assets === "number" && typeof x.assetsSha256 === "string" && (x.unhashed === void 0 || typeof x.unhashed === "number") && (x.gitHead === null || typeof x.gitHead === "string") && (x.gitDirty === null || typeof x.gitDirty === "boolean");
84
+ }
85
+ var isProbeFrame = (x) => isJsonObject(x) && typeof x.nodeId === "string" && typeof x.selector === "string" && typeof x.via === "string" && isJsonObject(x.rect);
86
+ var isCountMap = (x) => isJsonObject(x) && Object.values(x).every((v) => typeof v === "number");
87
+ var isNavigation = (x) => isJsonObject(x) && Array.isArray(x.events) && typeof x.afterInitialLoad === "number" && typeof x.reruns === "number";
88
+ var isTagsNotInExpectation = (x) => isJsonObject(x) && typeof x.count === "number" && Array.isArray(x.ids) && x.ids.every((r) => isJsonObject(r) && typeof r.id === "string" && typeof r.elements === "number");
89
+ var isReasonMap = (x) => isJsonObject(x) && Object.values(x).every((v) => typeof v === "string");
90
+ var isNum = (x) => typeof x === "number" && Number.isFinite(x);
91
+ function isProbeReach(x) {
92
+ return isJsonObject(x) && Array.isArray(x.steps) && x.steps.every(isJsonObject) && typeof x.sha256 === "string" && typeof x.source === "string" && typeof x.url === "string";
93
+ }
94
+ function isPageOverflow(x) {
95
+ return isJsonObject(x) && isJsonObject(x.viewport) && isNum(x.viewport.w) && isNum(x.viewport.h) && isNum(x.scrollWidth) && isNum(x.clientWidth) && typeof x.overflowX === "string" && typeof x.scrollable === "boolean" && Array.isArray(x.offenders) && x.offenders.every((o) => isJsonObject(o) && typeof o.path === "string" && (o.dt === null || typeof o.dt === "string") && isNum(o.right)) && optStr(x.compatMode);
96
+ }
97
+ var BEHAVIOUR_STATUSES = ["pass", "fail", "warn", "not-run", "unsupported"];
98
+ var isBehaviourStatus = (x) => typeof x === "string" && BEHAVIOUR_STATUSES.some((s) => s === x);
99
+ function isBehaviourCheck(x) {
100
+ return isJsonObject(x) && typeof x.id === "string" && isBehaviourStatus(x.status) && typeof x.detail === "string";
101
+ }
102
+ function isMeasuredBehaviour(x) {
103
+ return isJsonObject(x) && x.version === 1 && typeof x.ran === "boolean" && (x.ran ? Array.isArray(x.checks) && x.checks.every(isBehaviourCheck) : typeof x.why === "string");
104
+ }
105
+ function isMeasuredVisual(x) {
106
+ return isJsonObject(x) && x.version === 1 && typeof x.ran === "boolean" && (x.ran ? isNum(x.differingPct) && isNum(x.shiftTolerantPct) && Array.isArray(x.regions) : typeof x.why === "string");
107
+ }
108
+ var MEASURED_EXTRAS = [
109
+ ["probe", isProbeIdentity, "the shipped probe's identity {name, version, sha256, playwright:{package, version}, browser:{name, version}} \u2014 read as probe: unknown"],
110
+ ["frame", isProbeFrame, "a probe frame {nodeId, selector, via, rect}"],
111
+ ["frames", (x) => Array.isArray(x) && x.every(isProbeFrame), "a list of probe frames {nodeId, selector, via, rect}"],
112
+ ["navigation", isNavigation, "a navigation log {events[], afterInitialLoad, reruns}"],
113
+ ["matchedByCensus", isCountMap, "a {rule: count} map"],
114
+ ["notMeasured", Array.isArray, "a list \u2014 the probe's reasons for unmatched nodes are not used"],
115
+ // the run it belongs to and the build it was served
116
+ ["runId", (x) => typeof x === "string" && x !== "", "a run id (string) \u2014 the measurement is tied to no verify run"],
117
+ ["build", isBuildIdentity, "a build identity {url, mode: vite-dev|static|unknown, assets, assetsSha256, gitHead, gitDirty} \u2014 read as build: unknown"],
118
+ // the shipped probe's foreign tags
119
+ ["tagsNotInExpectation", isTagsNotInExpectation, "a foreign-tag list {count, ids: [{id, elements}]}"],
120
+ // the steps replayed, the page's overflow, the behaviour/a11y block
121
+ ["reach", isProbeReach, "the probe's steps {steps[], sha256, source, url}"],
122
+ ["page", isPageOverflow, "a page overflow {viewport:{w,h}, scrollWidth, clientWidth, overflowX, scrollable, offenders[]} \u2014 page overflow not measured"],
123
+ ["behaviour", isMeasuredBehaviour, "a behaviour block {version: 1, ran: true, checks: [{id, status: pass|fail|warn|not-run|unsupported, detail}], \u2026} or {version: 1, ran: false, why} \u2014 behaviour/a11y not reported"],
124
+ // the visual diff (informational)
125
+ ["visual", isMeasuredVisual, "a visual block {version: 1, ran: true, differingPct, shiftTolerantPct, regions: [\u2026], \u2026} or {version: 1, ran: false, why} \u2014 the visual diff not reported"]
126
+ ];
127
+ function isMeasuredCore(x) {
128
+ return isJsonObject(x) && optArrayOf(x.nodes, (n) => isJsonObject(n) && typeof n.nodeId === "string") && optArrayOf(x.components, anyObject) && optArrayOf(x.interactions, anyObject) && (x.artifacts === void 0 || Array.isArray(x.artifacts)) && optStr(x.mode) && optStr(x.expectationSha256);
129
+ }
130
+ function isVerifyMeasured(x) {
131
+ return isMeasuredCore(x) && MEASURED_EXTRAS.every(([k, ok]) => x[k] === void 0 || ok(x[k])) && (x.nodes === void 0 || Array.isArray(x.nodes) && x.nodes.every((n) => !isJsonObject(n) || n.unmeasured === void 0 || isReasonMap(n.unmeasured)));
132
+ }
133
+ isVerifyMeasured.expected = "probe measurements: an object whose `nodes` (each {nodeId, styles}), `components`, `interactions` and `artifacts`, when present, are arrays";
134
+ function isEvidence(x) {
135
+ return isJsonObject(x) && typeof x.nodeId === "string";
136
+ }
137
+ function isInteractionEvidenceList(x) {
138
+ return Array.isArray(x) && x.every(isEvidence);
139
+ }
140
+ isInteractionEvidenceList.expected = "interaction evidence: a JSON array of {nodeId, trigger, ok, selector, selectorCount, detail}";
141
+ function isMeasuredComponentList(x) {
142
+ return Array.isArray(x) && x.every((c) => isJsonObject(c) && optStr(c.setName) && optStr(c.name) && optStr(c.nodeId) && (c.present === void 0 || typeof c.present === "boolean"));
143
+ }
144
+ isMeasuredComponentList.expected = "component evidence: a JSON array of {setName|nodeId, present: true|false}";
145
+ function isVerifyReport(x) {
146
+ return isJsonObject(x) && optStr(x.schema) && optStr(x.verdict) && optStr(x.screen) && optStr(x.nodeId) && optStr(x.headline) && (x.why === void 0 || isStringArray(x.why)) && (x.integrity === void 0 || isStringArray(x.integrity)) && optArrayOf(x.deltas, anyObject) && optObj(x.inputs);
147
+ }
148
+ isVerifyReport.expected = "a verify report (the verify-screen script's --compare output): an object with `verdict`, `why[]`, `deltas[]`, `inputs`";
149
+ var PLAN_ARRAYS = ["files", "tokens", "components", "hidden", "anchorsSuggested", "deviations", "allowedLiterals", "waivers", "descopes"];
150
+ var PLAN_OBJECTS = ["anchors", "verification", "counts"];
151
+ var PLAN_STRINGS = ["schema", "screen", "screenName", "nodeId", "route", "file", "exportedAt", "status"];
152
+ function planProblem(x) {
153
+ if (!isJsonObject(x)) return "is not a plan (the file holds " + (Array.isArray(x) ? "an array" : x === null ? "null" : typeof x) + ", not an object)";
154
+ for (const k of PLAN_ARRAYS) if (x[k] !== void 0 && !Array.isArray(x[k])) return `is not a valid plan: \`${k}\` must be an array`;
155
+ for (const k of PLAN_OBJECTS) if (x[k] !== void 0 && !isJsonObject(x[k])) return `is not a valid plan: \`${k}\` must be an object`;
156
+ for (const k of PLAN_STRINGS) if (x[k] !== void 0 && x[k] !== null && typeof x[k] !== "string") return `is not a valid plan: \`${k}\` must be a string`;
157
+ if (x.files !== void 0 && !isStringArray(x.files)) return "is not a valid plan: `files` must be an array of paths (strings)";
158
+ for (const k of ["tokens", "components", "allowedLiterals", "deviations", "hidden", "anchorsSuggested", "waivers", "descopes"]) {
159
+ const list = x[k];
160
+ if (Array.isArray(list) && !list.every(isJsonObject)) return `is not a valid plan: every \`${k}\` entry must be an object`;
161
+ }
162
+ if (Array.isArray(x.tokens) && !x.tokens.every((t) => isJsonObject(t) && (t.figmaName === null || optStr(t.figmaName)))) return "is not a valid plan: a `tokens` row's `figmaName` must be a string";
163
+ if (Array.isArray(x.components) && !x.components.every((c) => isJsonObject(c) && typeof c.name === "string")) return "is not a valid plan: every `components` row needs its `name`";
164
+ if (isJsonObject(x.anchors) && !Object.values(x.anchors).every(isJsonObject)) return "is not a valid plan: every `anchors` entry must be an object";
165
+ if (x.auditGate !== void 0 && x.auditGate !== null && !isJsonObject(x.auditGate)) return "is not a valid plan: `auditGate` must be an object or null";
166
+ if (x.target !== void 0 && x.target !== null && typeof x.target !== "string" && !isJsonObject(x.target)) return "is not a valid plan: `target` must be a profile name, an object or null";
167
+ if (x.tagging !== void 0 && x.tagging !== null && !(isJsonObject(x.tagging) && (x.tagging.off === void 0 || typeof x.tagging.off === "boolean") && optStr(x.tagging.reason))) return 'is not a valid plan: `tagging` must be {"off": true, "reason": "\u2026"}';
168
+ if (Array.isArray(x.tokens) && !x.tokens.every((t) => isJsonObject(t) && optStr(t.acknowledged))) return "is not a valid plan: a `tokens` row's `acknowledged` must be a string (the reason)";
169
+ if (isJsonObject(x.verification) && x.verification.hook !== void 0 && !isJsonObject(x.verification.hook)) return "is not a valid plan: `verification.hook` must be an object";
170
+ if (isJsonObject(x.verification) && x.verification.recorded !== void 0 && !isJsonObject(x.verification.recorded)) return "is not a valid plan: `verification.recorded` must be an object";
171
+ for (const k of ["navigate", "interactions"]) if (x[k] !== void 0 && !Array.isArray(x[k])) return `is not a valid plan: \`${k}\` must be an array`;
172
+ return null;
173
+ }
174
+ function isPlan(x) {
175
+ return planProblem(x) === null;
176
+ }
177
+ isPlan.expected = "a plan (started by the plan-skeleton script): an object whose files/tokens/components/deviations are arrays of objects and whose anchors/verification are objects";
178
+ var recIsCount = (x) => typeof x === "number" && Number.isFinite(x);
179
+ var recIsStr = (v) => typeof v === "string";
180
+ var recNeed = (ok) => ({ need: true, ok });
181
+ var recOpt = (ok) => ({ need: false, ok });
182
+ var RECORD_COUNTS = Object.fromEntries(["high", "medium", "low", "accepted", "notMeasured", "inferred"].map((k) => [k, recNeed(recIsCount)]));
183
+ var RECORD_DELTA = { nodeId: recNeed(recIsStr), field: recNeed(recIsStr), severity: recNeed((v) => v === "high" || v === "medium"), expected: recOpt(() => true), actual: recOpt(() => true) };
184
+ var RECORD_A11Y = { tool: recNeed(recIsStr), violations: recNeed(recIsCount), warnings: recNeed(recIsCount), report: recNeed(recIsStr) };
185
+ var RECORD_FIELDS = {
186
+ schema: recNeed((v) => v === PLAN_VERIFICATION_RECORD_SCHEMA),
187
+ by: recNeed(recIsStr),
188
+ at: recNeed(recIsStr),
189
+ report: recNeed(recIsStr),
190
+ reportSha256: recNeed(recIsStr),
191
+ verdict: recNeed(recIsStr),
192
+ headline: recNeed(recIsStr),
193
+ behaviourHeadline: recOpt(recIsStr),
194
+ counts: recNeed(isJsonObject),
195
+ mode: recNeed((v) => v === "rendered" || v === "static-only"),
196
+ reason: recOpt(recIsStr),
197
+ renderer: recOpt(recIsStr),
198
+ artifacts: recNeed(isStringArray),
199
+ deltas: recNeed(Array.isArray),
200
+ a11y: recOpt(isJsonObject)
201
+ };
202
+ var RECORD_KEYS = Object.keys(RECORD_FIELDS);
203
+ var reqStr = (v) => typeof v === "string" && v.trim() !== "";
204
+ function isPlanWaiver(x) {
205
+ return isJsonObject(x) && reqStr(x.nodeId) && reqStr(x.field) && x.designed !== void 0 && x.built !== void 0 && reqStr(x.exportContentSha256) && reqStr(x.reason) && reqStr(x.decidedBy) && reqStr(x.decidedAt) && (x.tolerance === void 0 || typeof x.tolerance === "number" && x.tolerance >= 0) && optStr(x.cause);
206
+ }
207
+ isPlanWaiver.expected = "a plan waiver {nodeId, field, designed, built, exportContentSha256, reason, decidedBy, decidedAt, tolerance?, cause?}";
208
+ function isPlanDescope(x) {
209
+ return isJsonObject(x) && reqStr(x.nodeId) && reqStr(x.trigger) && optStr(x.destinationId) && reqStr(x.exportContentSha256) && reqStr(x.reason) && reqStr(x.decidedBy) && reqStr(x.decidedAt);
210
+ }
211
+ isPlanDescope.expected = "a plan descope {nodeId, trigger, destinationId?, exportContentSha256, reason, decidedBy, decidedAt}";
212
+ function isStringRecord(x) {
213
+ return isJsonObject(x) && Object.values(x).every((v) => typeof v === "string");
214
+ }
215
+ isStringRecord.expected = "an object of strings";
216
+
217
+ // bridge/src/read-json.ts
218
+ import fs from "node:fs";
219
+
220
+ // bridge/src/errmsg.ts
221
+ var errMsg = (e) => typeof e === "string" ? e : String(e && e.message || e);
222
+
223
+ // bridge/src/read-json.ts
224
+ var anyJson = (_x) => true;
225
+ function readFailure(e) {
226
+ const code = e && typeof e === "object" && "code" in e ? e.code : void 0;
227
+ if (code === "ENOENT") return { error: "does not exist", missing: true };
228
+ return {
229
+ error: code === "EISDIR" ? "is a directory, not a file" : code === "EACCES" ? "is not readable (permission denied)" : `could not be read (${String(code || e)})`
230
+ };
231
+ }
232
+ function readJson(file, guard) {
233
+ let buf;
234
+ try {
235
+ buf = fs.readFileSync(file);
236
+ } catch (e) {
237
+ return readFailure(e);
238
+ }
239
+ if (buf.length >= 2 && (buf[0] === 255 && buf[1] === 254 || buf[0] === 254 && buf[1] === 255)) {
240
+ return { error: "is UTF-16, not UTF-8 \u2014 re-save it as UTF-8" };
241
+ }
242
+ let raw = buf.toString("utf8");
243
+ if (raw.charCodeAt(0) === 65279) raw = raw.slice(1);
244
+ let parsed;
245
+ try {
246
+ const value = JSON.parse(raw);
247
+ parsed = value;
248
+ } catch (e) {
249
+ return { error: `is not valid JSON \u2014 ${errMsg(e)}` };
250
+ }
251
+ if (!guard(parsed)) return { error: `is not ${guard.expected || "the expected kind of document"}` };
252
+ return { doc: parsed };
253
+ }
254
+
255
+ // design-to-code/cli-args.ts
256
+ import path from "node:path";
257
+ import { fileURLToPath } from "node:url";
258
+
259
+ // bridge/src/stdio.ts
260
+ import { format, inspect } from "node:util";
261
+ function installQueuedConsole(o = {}) {
262
+ trackWrites(process.stdout);
263
+ trackWrites(process.stderr);
264
+ const out = o.logTo === "stderr" ? process.stderr : process.stdout;
265
+ const err = process.stderr;
266
+ let indent = "";
267
+ const write = (s, text) => {
268
+ s.write((indent ? text.replace(/^/gm, indent) : text) + "\n");
269
+ };
270
+ const line = (s) => (...a) => {
271
+ write(s, format(...a));
272
+ };
273
+ console.log = console.info = console.debug = line(out);
274
+ console.warn = console.error = line(err);
275
+ console.dir = (item, options) => {
276
+ write(out, inspect(item, { customInspect: false, ...options }));
277
+ };
278
+ console.dirxml = line(out);
279
+ console.table = (data) => {
280
+ write(out, inspect(data));
281
+ };
282
+ console.write = (...data) => {
283
+ let n = 0;
284
+ for (const d of data) {
285
+ const b = typeof d === "string" ? Buffer.from(d) : d instanceof ArrayBuffer ? Buffer.from(d) : Buffer.from(d.buffer, d.byteOffset, d.byteLength);
286
+ if (b.length) {
287
+ out.write(b);
288
+ n += b.length;
289
+ }
290
+ }
291
+ return n;
292
+ };
293
+ console.clear = () => {
294
+ if (out.isTTY) out.write("\x1B[1;1H\x1B[0J");
295
+ };
296
+ console.trace = (...a) => {
297
+ const e = new Error(format(...a));
298
+ e.name = "Trace";
299
+ Error.captureStackTrace(e, console.trace);
300
+ write(err, e.stack ?? `Trace: ${e.message}`);
301
+ };
302
+ console.assert = (cond, ...a) => {
303
+ if (!cond) write(err, a.length ? "Assertion failed: " + format(...a) : "Assertion failed");
304
+ };
305
+ console.group = console.groupCollapsed = (...a) => {
306
+ if (a.length) write(out, format(...a));
307
+ indent += " ";
308
+ };
309
+ console.groupEnd = () => {
310
+ indent = indent.slice(0, -2);
311
+ };
312
+ const counts = /* @__PURE__ */ new Map();
313
+ console.count = (label = "default") => {
314
+ const n = (counts.get(label) ?? 0) + 1;
315
+ counts.set(label, n);
316
+ write(out, `${label}: ${n}`);
317
+ };
318
+ console.countReset = (label = "default") => {
319
+ counts.delete(label);
320
+ };
321
+ const timers = /* @__PURE__ */ new Map();
322
+ const elapsed = (label) => {
323
+ const t = timers.get(label);
324
+ return t === void 0 ? null : `${label}: ${(performance.now() - t).toFixed(3)}ms`;
325
+ };
326
+ console.time = (label = "default") => {
327
+ timers.set(label, performance.now());
328
+ };
329
+ console.timeLog = (label = "default", ...a) => {
330
+ const e = elapsed(label);
331
+ if (e === null) write(err, `Warning: No such label '${label}' for console.timeLog()`);
332
+ else write(out, [e, ...a.map((x) => format(x))].join(" "));
333
+ };
334
+ console.timeEnd = (label = "default") => {
335
+ const e = elapsed(label);
336
+ timers.delete(label);
337
+ write(e === null ? err : out, e ?? `Warning: No such label '${label}' for console.timeEnd()`);
338
+ };
339
+ }
340
+ var inFlight = /* @__PURE__ */ new Map();
341
+ function trackWrites(s) {
342
+ if (inFlight.has(s)) return;
343
+ const st = { n: 0, idle: [] };
344
+ inFlight.set(s, st);
345
+ const write = s.write.bind(s);
346
+ const settle = () => {
347
+ if (--st.n === 0) for (const r of st.idle.splice(0)) r();
348
+ };
349
+ s.write = (chunk, encoding, cb) => {
350
+ const done = typeof encoding === "function" ? encoding : cb;
351
+ const enc = typeof encoding === "function" ? void 0 : encoding;
352
+ if (chunk.length === 0) return write(chunk, enc, done);
353
+ st.n++;
354
+ let called = false;
355
+ return write(chunk, enc, (err) => {
356
+ if (!called) {
357
+ called = true;
358
+ settle();
359
+ }
360
+ done?.(err);
361
+ });
362
+ };
363
+ }
364
+ var CliExit = class extends Error {
365
+ code;
366
+ constructor(code) {
367
+ super(`exit ${code}`);
368
+ this.name = "CliExit";
369
+ this.code = code;
370
+ }
371
+ };
372
+ var cliDepth = 0;
373
+ function runCli(main2, o, argv = process.argv.slice(2)) {
374
+ installQueuedConsole();
375
+ const done = o.done ?? ((code) => {
376
+ process.exitCode = code;
377
+ });
378
+ const fail = (e) => {
379
+ if (e instanceof CliExit) return done(e.code);
380
+ console.error(o.errorLine ? o.errorLine(e) : `${o.name}: ${e instanceof Error && e.stack || String(e)}`);
381
+ done(o.errorCode ?? 1);
382
+ };
383
+ cliDepth++;
384
+ let settled = false;
385
+ const leave = () => {
386
+ if (!settled) {
387
+ settled = true;
388
+ cliDepth--;
389
+ }
390
+ };
391
+ try {
392
+ const r = main2(argv);
393
+ if (typeof r === "number") {
394
+ leave();
395
+ done(r);
396
+ } else r.then((c) => {
397
+ leave();
398
+ done(c);
399
+ }, (e) => {
400
+ leave();
401
+ fail(e);
402
+ });
403
+ } catch (e) {
404
+ leave();
405
+ fail(e);
406
+ }
407
+ }
408
+
409
+ // design-to-code/proc.ts
410
+ var pause = new Int32Array(new SharedArrayBuffer(4));
411
+
412
+ // design-to-code/cli-args.ts
413
+ var SELF = fileURLToPath(import.meta.url);
414
+ var shellQuote = (p) => /["$`\\!]/.test(p) ? `'${p.replaceAll("'", `'\\''`)}'` : `"${p}"`;
415
+ var SCRIPT_RUNNER = "bun --no-install --no-env-file";
416
+ var scriptCmd = (name) => `${SCRIPT_RUNNER} ${shellQuote(path.join(path.dirname(SELF), name + path.extname(SELF)))}`;
417
+ function cliArity(tool, positionals, min, max, usage) {
418
+ if (positionals.length < min) {
419
+ console.error(usage);
420
+ return false;
421
+ }
422
+ if (positionals.length > max) {
423
+ console.error(`${tool}: unexpected argument ${positionals.slice(max).join(", ")}
424
+ ${usage}`);
425
+ return false;
426
+ }
427
+ return true;
428
+ }
429
+ var bareArgs = (argv) => argv[0] === "--" ? argv.slice(1) : argv;
430
+
431
+ // design-to-code/catalog-input.ts
432
+ function isManifest(doc, payloadKey) {
433
+ return isJsonObject(doc) && isJsonObject(doc.files) && !Array.isArray(doc[payloadKey]);
434
+ }
435
+ function manifestProblem(doc, givenPath, payloadKey, wantFile) {
436
+ if (!isManifest(doc, payloadKey)) return null;
437
+ return `'${givenPath}' is the design-system MANIFEST (a pointer map), not the '${payloadKey}' catalog.
438
+ Since the design-system split it carries only a stamp, a \`files\` map and \`counts\`.
439
+ Pass the split file instead \u2014 e.g. ${doc.files[payloadKey === "variables" ? "tokens" : "componentsLocal"] || wantFile} (relative to the export dir that holds ${givenPath}).`;
440
+ }
441
+ function loadDocFile(file, what, guard, hint, readAt = file) {
442
+ const r = readJson(readAt, guard);
443
+ if ("doc" in r) return r;
444
+ const ioFailure = r.missing || /^(is a directory|is not readable|could not be read)/.test(r.error);
445
+ return { error: `${what}: '${file}' ${r.error}${ioFailure ? "." : ""}` + (ioFailure && hint ? `
446
+ ${hint}` : "") };
447
+ }
448
+ function loadSplitFile(file, what, guard, payloadKey, wantFile, hint) {
449
+ const r = loadDocFile(file, what, anyJson, hint);
450
+ if ("error" in r) return r;
451
+ const manifest = manifestProblem(r.doc, file, payloadKey, wantFile);
452
+ if (manifest !== null) return { error: manifest };
453
+ if (guard(r.doc)) return { doc: r.doc };
454
+ return { error: `${what}: '${file}' is not ${guard.expected || "the expected kind of document"}` };
455
+ }
456
+
457
+ // bridge/src/design-system-layout.ts
458
+ var DIR = "design-system";
459
+ var TOKENS = "tokens.json";
460
+ var COMPONENTS_LOCAL = "components.local.json";
461
+ var COMPONENTS_LIBRARY = "components.library.json";
462
+ var HYGIENE = "hygiene.json";
463
+ var MANIFEST = "design-system.json";
464
+ var STYLE_KIND_ROWS = {
465
+ paint: { kind: "paint", file: "styles.paint.json", key: "stylesPaint" },
466
+ text: { kind: "text", file: "styles.text.json", key: "stylesText" },
467
+ effect: { kind: "effect", file: "styles.effect.json", key: "stylesEffect" },
468
+ grid: { kind: "grid", file: "styles.grid.json", key: "stylesGrid" },
469
+ animation: { kind: "animation", file: "styles.animation.json", key: "stylesAnimation" }
470
+ // local custom animation styles
471
+ };
472
+ var STYLE_KINDS = Object.values(STYLE_KIND_ROWS);
473
+ var DESIGN_SYSTEM_DIR = DIR;
474
+ var DESIGN_SYSTEM_FILE_NAMES = [TOKENS, ...STYLE_KINDS.map((row) => row.file), COMPONENTS_LOCAL, COMPONENTS_LIBRARY, HYGIENE, MANIFEST];
475
+
476
+ // design-to-code/get-component.ts
477
+ function findComponent(catalog, handle) {
478
+ const comps = catalog && catalog.components || [];
479
+ const byKey = comps.find((c) => c.key === handle);
480
+ if (byKey) return byKey;
481
+ const byId = comps.find((c) => c.id === handle);
482
+ if (byId) return byId;
483
+ const byName = comps.filter((c) => c.name === handle);
484
+ const only = byName.length === 1 ? byName[0] : void 0;
485
+ if (only) return only;
486
+ if (byName.length > 1) {
487
+ const err = new Error(`'${handle}' matches ${byName.length} components by name \u2014 use its key or id instead (${byName.map((c) => c.key || c.id).join(", ")})`);
488
+ err.code = "ambiguous-name";
489
+ throw err;
490
+ }
491
+ return null;
492
+ }
493
+ function resolveVariantsFile(catalogFile, variantsFile) {
494
+ const catalogDir = path2.dirname(catalogFile);
495
+ const root = path2.basename(catalogDir) === DESIGN_SYSTEM_DIR ? path2.dirname(catalogDir) : catalogDir;
496
+ return path2.join(root, variantsFile);
497
+ }
498
+ function readOrThrow(file, guard) {
499
+ const r = readJson(file, guard);
500
+ if ("doc" in r) return r.doc;
501
+ throw new Error(`'${file}' ${r.error}`);
502
+ }
503
+ function getComponent(catalogFile, handle) {
504
+ const loaded = loadSplitFile(catalogFile, "component catalog", isComponentsCatalog, "components", "design-system/components.local.json");
505
+ if ("error" in loaded) throw new Error(loaded.error);
506
+ const catalog = loaded.doc;
507
+ const comp = findComponent(catalog, handle);
508
+ if (!comp) return { found: false };
509
+ const pointer = comp.variantsFile || comp.nodeFile;
510
+ if (!pointer) return { found: true, component: comp, detail: null };
511
+ const detailPath = resolveVariantsFile(catalogFile, pointer);
512
+ const detail = readOrThrow(detailPath, isComponentDetailFile);
513
+ return { found: true, component: comp, detail, detailPath };
514
+ }
515
+ function main(argv) {
516
+ const usage = `usage: ${scriptCmd("get-component")} <design-system/components.local.json> <key|id|name>`;
517
+ if (argv.includes("--help") || argv.includes("-h")) {
518
+ console.log(usage);
519
+ return 0;
520
+ }
521
+ const positionals = bareArgs(argv);
522
+ if (!cliArity("get-component", positionals, 2, 2, usage)) return 2;
523
+ const [catalogFile, handle] = positionals;
524
+ if (!catalogFile || !handle) {
525
+ console.error(usage);
526
+ return 2;
527
+ }
528
+ try {
529
+ const res = getComponent(catalogFile, handle);
530
+ if (!res.found) {
531
+ console.error(`error no component matches '${handle}' in ${catalogFile}`);
532
+ return 1;
533
+ }
534
+ if (!res.detail) {
535
+ console.error(`warn '${handle}' has no variantsFile/nodeFile (no node trees were exported for it \u2014 re-run the export with \`--variant-visuals\` (MCP: variantVisuals:true)) \u2014 printing the catalog entry only`);
536
+ process.stdout.write(JSON.stringify(res.component, null, 2) + "\n");
537
+ return 0;
538
+ }
539
+ process.stdout.write(JSON.stringify(res.detail, null, 2) + "\n");
540
+ } catch (e) {
541
+ const message = e && typeof e === "object" && "message" in e ? e.message : void 0;
542
+ console.error(`error ${String(message)}`);
543
+ return 2;
544
+ }
545
+ return 0;
546
+ }
547
+ if (import.meta.main) runCli(main, { name: "get-component" });
548
+ export {
549
+ findComponent,
550
+ getComponent,
551
+ main,
552
+ resolveVariantsFile
553
+ };