openuispec 0.2.18 → 0.2.20

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 (45) hide show
  1. package/README.md +2 -10
  2. package/dist/check/audit.js +392 -0
  3. package/dist/check/index.js +216 -0
  4. package/dist/cli/configure-target.js +391 -0
  5. package/dist/cli/index.js +510 -0
  6. package/dist/cli/init.js +1047 -0
  7. package/dist/drift/index.js +903 -0
  8. package/dist/mcp-server/index.js +886 -0
  9. package/dist/mcp-server/preview-render.js +1761 -0
  10. package/dist/mcp-server/preview.js +233 -0
  11. package/dist/mcp-server/screenshot-android.js +458 -0
  12. package/dist/mcp-server/screenshot-ios.js +639 -0
  13. package/dist/mcp-server/screenshot-shared.js +180 -0
  14. package/dist/mcp-server/screenshot.js +459 -0
  15. package/dist/prepare/index.js +1216 -0
  16. package/dist/runtime/package-paths.js +33 -0
  17. package/dist/schema/semantic-lint.js +564 -0
  18. package/dist/schema/validate.js +689 -0
  19. package/dist/status/index.js +194 -0
  20. package/docs/images/how-it-works.svg +56 -0
  21. package/docs/images/workflows.svg +76 -0
  22. package/package.json +12 -13
  23. package/check/audit.ts +0 -426
  24. package/check/index.ts +0 -320
  25. package/cli/configure-target.ts +0 -523
  26. package/cli/index.ts +0 -537
  27. package/cli/init.ts +0 -1253
  28. package/docs/images/how-it-works-dark.png +0 -0
  29. package/docs/images/how-it-works-light.png +0 -0
  30. package/docs/images/workflows-dark.png +0 -0
  31. package/docs/images/workflows-light.png +0 -0
  32. package/drift/index.ts +0 -1165
  33. package/mcp-server/index.ts +0 -1041
  34. package/mcp-server/preview-render.ts +0 -1922
  35. package/mcp-server/preview.ts +0 -292
  36. package/mcp-server/screenshot-android.ts +0 -621
  37. package/mcp-server/screenshot-ios.ts +0 -753
  38. package/mcp-server/screenshot-shared.ts +0 -237
  39. package/mcp-server/screenshot.ts +0 -563
  40. package/prepare/index.ts +0 -1530
  41. package/schema/semantic-lint.ts +0 -692
  42. package/schema/validate.ts +0 -870
  43. package/scripts/regenerate-previews.ts +0 -136
  44. package/scripts/take-all-screenshots.ts +0 -507
  45. package/status/index.ts +0 -275
@@ -0,0 +1,194 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Cross-target status summary for OpenUISpec projects.
4
+ *
5
+ * Usage:
6
+ * openuispec status # summarize every target
7
+ * openuispec status --json # machine-readable output
8
+ */
9
+ import { existsSync } from "node:fs";
10
+ import { computeDrift, computeSharedDrift, discoverTargets, explainDrift, findProjectDir, formatBaseline, hasDriftChanges, readOutputDirs, readProjectName, readSharedLayers, readSharedLayerState, resolveOutputDir, stateFilePath, } from "../drift/index.js";
11
+ import { readFileSync } from "node:fs";
12
+ function configuredTargets(projectDir) {
13
+ try {
14
+ const manifest = readOutputDirs(projectDir);
15
+ const keys = Object.keys(manifest);
16
+ if (keys.length > 0)
17
+ return keys.sort();
18
+ }
19
+ catch {
20
+ // ignore
21
+ }
22
+ // Fallback to common targets when manifest output_dir is absent.
23
+ return ["android", "ios", "web"];
24
+ }
25
+ function allTargets(projectDir, projectName) {
26
+ const seen = new Set(configuredTargets(projectDir));
27
+ for (const target of discoverTargets(projectDir, projectName)) {
28
+ seen.add(target);
29
+ }
30
+ return Array.from(seen).sort();
31
+ }
32
+ function readState(statePath) {
33
+ return JSON.parse(readFileSync(statePath, "utf-8"));
34
+ }
35
+ function buildTargetStatus(cwd, projectDir, projectName, target) {
36
+ const outputDir = resolveOutputDir(projectDir, projectName, target);
37
+ const outputExists = existsSync(outputDir);
38
+ const path = stateFilePath(projectDir, projectName, target);
39
+ if (!existsSync(path)) {
40
+ return {
41
+ target,
42
+ output_dir: outputDir,
43
+ output_exists: outputExists,
44
+ snapshot: false,
45
+ snapshot_at: null,
46
+ baseline: {
47
+ kind: null,
48
+ commit: null,
49
+ branch: null,
50
+ label: null,
51
+ },
52
+ changed: 0,
53
+ added: 0,
54
+ removed: 0,
55
+ behind: false,
56
+ explain_available: false,
57
+ status: outputExists ? "needs baseline" : "needs generation",
58
+ recommended_next_step: outputExists
59
+ ? `Review the generated output, then run \`openuispec drift --snapshot --target ${target}\` to create the baseline.`
60
+ : `Run code generation for "${target}", then \`openuispec prepare --target ${target}\` to build the target work bundle.`,
61
+ note: outputExists
62
+ ? "Baseline pending — generated code exists but user has not yet confirmed it with a snapshot."
63
+ : `Output directory not found. Run code generation for "${target}" first.`,
64
+ };
65
+ }
66
+ const state = readState(path);
67
+ const result = computeDrift(projectDir, state, false);
68
+ const explanation = explainDrift(projectDir, result);
69
+ const changed = result.drift.changed.length;
70
+ const added = result.drift.added.length;
71
+ const removed = result.drift.removed.length;
72
+ return {
73
+ target,
74
+ output_dir: outputDir,
75
+ output_exists: outputExists,
76
+ snapshot: true,
77
+ snapshot_at: state.snapshot_at,
78
+ baseline: {
79
+ kind: state.baseline?.kind ?? null,
80
+ commit: state.baseline?.commit ?? null,
81
+ branch: state.baseline?.branch ?? null,
82
+ label: formatBaseline(state.baseline),
83
+ },
84
+ changed,
85
+ added,
86
+ removed,
87
+ behind: changed + added + removed > 0,
88
+ explain_available: explanation.available,
89
+ status: changed + added + removed > 0 ? "behind" : "up to date",
90
+ recommended_next_step: changed + added + removed > 0
91
+ ? `Run \`openuispec prepare --target ${target}\` to build the target work bundle for the pending spec changes.`
92
+ : `No immediate action required for "${target}". Re-run \`openuispec status\` after spec changes or after re-baselining.`,
93
+ note: explanation.available ? undefined : explanation.note,
94
+ };
95
+ }
96
+ function buildSharedLayerStatus(projectDir, layer) {
97
+ const state = readSharedLayerState(layer);
98
+ if (!state) {
99
+ return {
100
+ name: layer.name,
101
+ platforms: layer.platforms,
102
+ root: layer.root,
103
+ snapshot: false,
104
+ snapshot_at: null,
105
+ generated_by_target: null,
106
+ has_drift: false,
107
+ status: "needs generation",
108
+ };
109
+ }
110
+ let hasDrift = false;
111
+ if (layer.tracks.length > 0) {
112
+ hasDrift = hasDriftChanges(computeSharedDrift(projectDir, layer).drift);
113
+ }
114
+ return {
115
+ name: layer.name,
116
+ platforms: layer.platforms,
117
+ root: layer.root,
118
+ snapshot: true,
119
+ snapshot_at: state.snapshot_at,
120
+ generated_by_target: state.generated_by_target,
121
+ has_drift: hasDrift,
122
+ status: hasDrift ? "behind" : "up to date",
123
+ };
124
+ }
125
+ export function buildStatusResult(cwd = process.cwd()) {
126
+ const projectDir = findProjectDir(cwd);
127
+ const projectName = readProjectName(projectDir);
128
+ const targets = allTargets(projectDir, projectName).map((target) => buildTargetStatus(cwd, projectDir, projectName, target));
129
+ const sharedLayers = readSharedLayers(projectDir);
130
+ const sharedLayerStatuses = sharedLayers.length > 0
131
+ ? sharedLayers.map((layer) => buildSharedLayerStatus(projectDir, layer))
132
+ : undefined;
133
+ return {
134
+ project: projectName,
135
+ targets,
136
+ ...(sharedLayerStatuses ? { shared_layers: sharedLayerStatuses } : {}),
137
+ };
138
+ }
139
+ function printReport(result) {
140
+ console.log("OpenUISpec Status");
141
+ console.log("=================");
142
+ console.log(`Project: ${result.project}`);
143
+ console.log("");
144
+ for (const target of result.targets) {
145
+ const summary = target.snapshot
146
+ ? `${target.changed} changed, ${target.added} added, ${target.removed} removed`
147
+ : target.output_exists
148
+ ? "no snapshot"
149
+ : "output missing";
150
+ console.log(`${target.target}`);
151
+ console.log(` output: ${target.output_dir}`);
152
+ console.log(` output exists: ${target.output_exists ? "yes" : "no"}`);
153
+ console.log(` snapshot: ${target.snapshot ? target.snapshot_at : "missing"}`);
154
+ if (target.baseline.label) {
155
+ console.log(` baseline: ${target.baseline.label}`);
156
+ }
157
+ console.log(` drift: ${summary}`);
158
+ console.log(` status: ${target.status}`);
159
+ console.log(` explain: ${target.explain_available ? "available" : "unavailable"}`);
160
+ if (target.note) {
161
+ console.log(` note: ${target.note}`);
162
+ }
163
+ console.log(` next: ${target.recommended_next_step}`);
164
+ console.log("");
165
+ }
166
+ if (result.shared_layers && result.shared_layers.length > 0) {
167
+ console.log("Shared Layers");
168
+ console.log("─────────────");
169
+ for (const layer of result.shared_layers) {
170
+ console.log(`${layer.name} (${layer.platforms.join(", ")})`);
171
+ console.log(` root: ${layer.root}`);
172
+ console.log(` snapshot: ${layer.snapshot ? layer.snapshot_at : "missing"}`);
173
+ if (layer.generated_by_target) {
174
+ console.log(` generated by: ${layer.generated_by_target}`);
175
+ }
176
+ console.log(` status: ${layer.status}`);
177
+ console.log("");
178
+ }
179
+ }
180
+ }
181
+ export function runStatus(argv) {
182
+ const isJson = argv.includes("--json");
183
+ const result = buildStatusResult(process.cwd());
184
+ if (isJson) {
185
+ console.log(JSON.stringify(result, null, 2));
186
+ return;
187
+ }
188
+ printReport(result);
189
+ }
190
+ const isDirectRun = process.argv[1]?.endsWith("status/index.ts") ||
191
+ process.argv[1]?.endsWith("status/index.js");
192
+ if (isDirectRun) {
193
+ runStatus(process.argv.slice(2));
194
+ }
@@ -0,0 +1,56 @@
1
+ <svg width="100%" viewBox="0 0 680 470" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></marker>
4
+
5
+ <mask id="imagine-text-gaps-o7de63" maskUnits="userSpaceOnUse"><rect x="0" y="0" width="680" height="470" fill="white"/><rect x="256.6324462890625" y="12.305379867553711" width="166.73512268066406" height="20.52798843383789" fill="black" rx="2"/><rect x="69.6505126953125" y="62.305381774902344" width="90.69898223876953" height="20.527990341186523" fill="black" rx="2"/><rect x="46.96881103515625" y="84.19429016113281" width="136.0624237060547" height="18.16684913635254" fill="black" rx="2"/><rect x="91.05573272705078" y="120.19429779052734" width="47.88853454589844" height="18.16684913635254" fill="black" rx="2"/><rect x="83.20494079589844" y="156.1942901611328" width="63.590126037597656" height="18.16684913635254" fill="black" rx="2"/><rect x="75.04055786132812" y="192.19430541992188" width="79.91889953613281" height="18.16684913635254" fill="black" rx="2"/><rect x="88.12275695800781" y="228.19430541992188" width="53.75449752807617" height="18.16684913635254" fill="black" rx="2"/><rect x="94.92210388183594" y="264.1943054199219" width="40.15579605102539" height="18.16684913635254" fill="black" rx="2"/><rect x="69.73905181884766" y="300.1943054199219" width="90.52189636230469" height="18.16684913635254" fill="black" rx="2"/><rect x="67.63247680664062" y="336.1943054199219" width="94.73506164550781" height="18.16684913635254" fill="black" rx="2"/><rect x="73.51688385009766" y="372.1943054199219" width="82.96624755859375" height="18.16684913635254" fill="black" rx="2"/><rect x="217" y="214.1942901611328" width="35.17526435852051" height="18.16684913635254" fill="black" rx="2"/><rect x="292.1412048339844" y="152.30538940429688" width="89.71763610839844" height="20.527990341186523" fill="black" rx="2"/><rect x="300.2318115234375" y="174.1942901611328" width="73.53643798828125" height="18.16684913635254" fill="black" rx="2"/><rect x="280.6084899902344" y="208.1942901611328" width="112.78303527832031" height="18.16684913635254" fill="black" rx="2"/><rect x="272.58062744140625" y="244.1942901611328" width="128.83879852294922" height="18.16684913635254" fill="black" rx="2"/><rect x="288.5773620605469" y="280.1943054199219" width="96.84532928466797" height="18.16684913635254" fill="black" rx="2"/><rect x="442.0000305175781" y="138.1942901611328" width="36.606706619262695" height="18.16684913635254" fill="black" rx="2"/><rect x="442.0000305175781" y="214.1942901611328" width="39.89016914367676" height="18.16684913635254" fill="black" rx="2"/><rect x="442.0000305175781" y="304.1943054199219" width="69.11670303344727" height="18.16684913635254" fill="black" rx="2"/><rect x="519.6734619140625" y="106.30538177490234" width="98.65308380126953" height="20.527990341186523" fill="black" rx="2"/><rect x="507.6279602050781" y="128.1942901611328" width="122.74410247802734" height="18.16684913635254" fill="black" rx="2"/><rect x="497.83660888671875" y="208.30538940429688" width="142.3268280029297" height="20.527990341186523" fill="black" rx="2"/><rect x="505.4365234375" y="230.1942901611328" width="127.12696838378906" height="18.16684913635254" fill="black" rx="2"/><rect x="521.5771484375" y="314.3053894042969" width="94.84574127197266" height="20.527990341186523" fill="black" rx="2"/><rect x="499.4488220214844" y="336.1943054199219" width="139.10238647460938" height="18.16684913635254" fill="black" rx="2"/><rect x="138.05886840820312" y="434.1943054199219" width="403.8822937011719" height="18.16684913635254" fill="black" rx="2"/></mask></defs>
6
+
7
+ <rect width="680" height="460" rx="12" fill="#F5F1E8" style="fill:rgb(245, 241, 232);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
8
+
9
+ <text x="340" y="28" text-anchor="middle" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">How OpenUISpec works</text>
10
+
11
+ <rect x="40" y="52" width="150" height="370" rx="12" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
12
+ <text x="115" y="78" text-anchor="middle" fill="#633806" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">OpenUISpec</text>
13
+ <text x="115" y="98" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Semantic spec (YAML)</text>
14
+
15
+ <rect x="56" y="116" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="134" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Tokens</text>
16
+ <rect x="56" y="152" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="170" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Contracts</text>
17
+ <rect x="56" y="188" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="206" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Components</text>
18
+ <rect x="56" y="224" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="242" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Screens</text>
19
+ <rect x="56" y="260" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="278" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Flows</text>
20
+ <rect x="56" y="296" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="314" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Actions &amp; data</text>
21
+ <rect x="56" y="332" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="350" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Platform config</text>
22
+ <rect x="56" y="368" width="118" height="28" rx="6" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="115" y="386" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Design intent</text>
23
+
24
+ <line x1="194" y1="237" x2="248" y2="237" stroke="#BA7517" stroke-width="1.5" stroke-dasharray="4 3" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(186, 117, 23);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-dasharray:4px, 3px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
25
+ <text x="221" y="228" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">spec</text>
26
+
27
+ <rect x="252" y="140" width="170" height="194" rx="12" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
28
+ <text x="337" y="168" text-anchor="middle" fill="#26215C" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">AI generator</text>
29
+ <text x="337" y="188" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">MCP server</text>
30
+
31
+ <rect x="268" y="204" width="138" height="28" rx="6" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="337" y="222" text-anchor="middle" fill="#3C3489" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Read spec context</text>
32
+ <rect x="268" y="240" width="138" height="28" rx="6" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="337" y="258" text-anchor="middle" fill="#3C3489" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Generate native code</text>
33
+ <rect x="268" y="276" width="138" height="28" rx="6" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="337" y="294" text-anchor="middle" fill="#3C3489" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Validate &amp; audit</text>
34
+
35
+ <line x1="426" y1="198" x2="490" y2="134" stroke="#534AB7" stroke-width="1.5" marker-end="url(#arrow)" mask="url(#imagine-text-gaps-o7de63)" style="fill:rgb(0, 0, 0);stroke:rgb(83, 74, 183);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
36
+ <line x1="426" y1="237" x2="490" y2="237" stroke="#534AB7" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(83, 74, 183);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
37
+ <line x1="426" y1="276" x2="490" y2="340" stroke="#534AB7" stroke-width="1.5" marker-end="url(#arrow)" mask="url(#imagine-text-gaps-o7de63)" style="fill:rgb(0, 0, 0);stroke:rgb(83, 74, 183);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
38
+
39
+ <text x="446" y="152" fill="#5F5E5A" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">Swift</text>
40
+ <text x="446" y="228" fill="#5F5E5A" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">Kotlin</text>
41
+ <text x="446" y="318" fill="#5F5E5A" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">TypeScript</text>
42
+
43
+ <rect x="494" y="92" width="150" height="80" rx="10" fill="#E6F1FB" stroke="#85B7EB" stroke-width="0.5" style="fill:rgb(230, 241, 251);stroke:rgb(133, 183, 235);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
44
+ <text x="569" y="122" text-anchor="middle" fill="#042C53" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">iOS — SwiftUI</text>
45
+ <text x="569" y="142" text-anchor="middle" fill="#185FA5" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Native, platform feel</text>
46
+
47
+ <rect x="494" y="198" width="150" height="80" rx="10" fill="#EAF3DE" stroke="#97C459" stroke-width="0.5" style="fill:rgb(234, 243, 222);stroke:rgb(151, 196, 89);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
48
+ <text x="569" y="224" text-anchor="middle" fill="#173404" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">Android — Compose</text>
49
+ <text x="569" y="244" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Material You theming</text>
50
+
51
+ <rect x="494" y="304" width="150" height="80" rx="10" fill="#FAECE7" stroke="#F0997B" stroke-width="0.5" style="fill:rgb(250, 236, 231);stroke:rgb(240, 153, 123);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
52
+ <text x="569" y="330" text-anchor="middle" fill="#4A1B0C" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">Web — React</text>
53
+ <text x="569" y="350" text-anchor="middle" fill="#993C1D" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Responsive, accessible</text>
54
+
55
+ <text x="340" y="448" text-anchor="middle" fill="#888780" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Share the intent · generate native code · each platform feels like home</text>
56
+ </svg>
@@ -0,0 +1,76 @@
1
+ <svg width="100%" viewBox="0 0 680 530" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <marker id="arrow" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M2 1L8 5L2 9" fill="none" stroke="context-stroke" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></marker>
4
+
5
+ </defs>
6
+
7
+ <rect width="680" height="520" rx="12" fill="#F5F1E8" style="fill:rgb(245, 241, 232);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
8
+
9
+ <text x="340" y="28" text-anchor="middle" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">Workflows</text>
10
+
11
+ <rect x="40" y="48" width="106" height="26" rx="13" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="93" y="65" text-anchor="middle" fill="#633806" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Design mode</text>
12
+ <text x="158" y="65" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">Spec-first — new features, design system changes</text>
13
+
14
+ <rect x="40" y="86" width="152" height="106" rx="10" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
15
+ <text x="116" y="108" text-anchor="middle" fill="#633806" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">1 · Define</text>
16
+ <text x="116" y="128" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Author spec YAML</text>
17
+ <text x="116" y="144" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Tokens, contracts,</text>
18
+ <text x="116" y="160" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">screens, flows</text>
19
+ <text x="116" y="208" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec validate</text>
20
+
21
+ <line x1="196" y1="139" x2="228" y2="139" stroke="#BA7517" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(186, 117, 23);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
22
+
23
+ <rect x="232" y="86" width="162" height="106" rx="10" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
24
+ <text x="313" y="108" text-anchor="middle" fill="#26215C" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">2 · Generate</text>
25
+ <text x="313" y="128" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">AI reads spec via MCP</text>
26
+ <text x="313" y="144" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Produces native code</text>
27
+ <text x="313" y="160" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">per platform target</text>
28
+ <text x="313" y="208" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec prepare</text>
29
+
30
+ <line x1="398" y1="139" x2="430" y2="139" stroke="#BA7517" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(186, 117, 23);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
31
+
32
+ <rect x="434" y="86" width="152" height="106" rx="10" fill="#EAF3DE" stroke="#97C459" stroke-width="0.5" style="fill:rgb(234, 243, 222);stroke:rgb(151, 196, 89);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
33
+ <text x="510" y="108" text-anchor="middle" fill="#173404" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">3 · Refine</text>
34
+ <text x="510" y="128" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Platform teams adjust</text>
35
+ <text x="510" y="144" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">for native polish</text>
36
+ <text x="510" y="160" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Snapshot baseline</text>
37
+ <text x="510" y="208" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec drift --snapshot</text>
38
+
39
+ <line x1="590" y1="139" x2="610" y2="139" stroke="#B4B2A9" stroke-width="0.5" stroke-dasharray="3 2" style="fill:rgb(0, 0, 0);stroke:rgb(180, 178, 169);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-dasharray:3px, 2px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
40
+ <rect x="614" y="115" width="52" height="48" rx="8" fill="#E1F5EE" stroke="#5DCAA5" stroke-width="0.5" style="fill:rgb(225, 245, 238);stroke:rgb(93, 202, 165);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="640" y="135" text-anchor="middle" fill="#085041" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Native</text><text x="640" y="149" text-anchor="middle" fill="#085041" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">apps</text>
41
+
42
+ <line x1="40" y1="242" x2="640" y2="242" stroke="#D3D1C7" stroke-width="0.5" stroke-dasharray="6 4" style="fill:rgb(0, 0, 0);stroke:rgb(211, 209, 199);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-dasharray:6px, 4px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
43
+ <text x="340" y="258" text-anchor="middle" fill="#888780" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">or</text>
44
+
45
+ <rect x="40" y="274" width="132" height="26" rx="13" fill="#E6F1FB" stroke="#85B7EB" stroke-width="0.5" style="fill:rgb(230, 241, 251);stroke:rgb(133, 183, 235);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="106" y="291" text-anchor="middle" fill="#0C447C" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Development mode</text>
46
+ <text x="184" y="291" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:start;dominant-baseline:auto">Platform-first — day-to-day iteration, fixes, polish</text>
47
+
48
+ <rect x="40" y="312" width="152" height="106" rx="10" fill="#EAF3DE" stroke="#97C459" stroke-width="0.5" style="fill:rgb(234, 243, 222);stroke:rgb(151, 196, 89);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
49
+ <text x="116" y="334" text-anchor="middle" fill="#173404" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">1 · Code</text>
50
+ <text x="116" y="354" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Edit native code</text>
51
+ <text x="116" y="370" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Live preview, hot reload</text>
52
+ <text x="116" y="386" text-anchor="middle" fill="#3B6D11" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Fix, tweak, polish</text>
53
+
54
+ <line x1="196" y1="365" x2="228" y2="365" stroke="#185FA5" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(24, 95, 165);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
55
+
56
+ <rect x="232" y="312" width="162" height="106" rx="10" fill="#FAEEDA" stroke="#EF9F27" stroke-width="0.5" style="fill:rgb(250, 238, 218);stroke:rgb(239, 159, 39);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
57
+ <text x="313" y="334" text-anchor="middle" fill="#633806" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">2 · Sync</text>
58
+ <text x="313" y="354" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">AI reads code changes</text>
59
+ <text x="313" y="370" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Updates spec YAML</text>
60
+ <text x="313" y="386" text-anchor="middle" fill="#854F0B" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">to match platform code</text>
61
+ <text x="313" y="434" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec drift --explain</text>
62
+
63
+ <line x1="398" y1="365" x2="430" y2="365" stroke="#185FA5" stroke-width="1.5" marker-end="url(#arrow)" style="fill:rgb(0, 0, 0);stroke:rgb(24, 95, 165);color:rgb(0, 0, 0);stroke-width:1.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
64
+
65
+ <rect x="434" y="312" width="152" height="106" rx="10" fill="#EEEDFE" stroke="#7F77DD" stroke-width="0.5" style="fill:rgb(238, 237, 254);stroke:rgb(127, 119, 221);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
66
+ <text x="510" y="334" text-anchor="middle" fill="#26215C" style="fill:rgb(44, 44, 42);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:14px;font-weight:500;text-anchor:middle;dominant-baseline:auto">3 · Propagate</text>
67
+ <text x="510" y="354" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Other platforms see</text>
68
+ <text x="510" y="370" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">spec diff and update</text>
69
+ <text x="510" y="386" text-anchor="middle" fill="#534AB7" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">their code accordingly</text>
70
+ <text x="510" y="434" text-anchor="middle" fill="#888780" font-style="italic" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;font-style:italic;text-anchor:middle;dominant-baseline:auto">openuispec status</text>
71
+
72
+ <line x1="590" y1="365" x2="610" y2="365" stroke="#B4B2A9" stroke-width="0.5" stroke-dasharray="3 2" style="fill:rgb(0, 0, 0);stroke:rgb(180, 178, 169);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-dasharray:3px, 2px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/>
73
+ <rect x="614" y="341" width="52" height="48" rx="8" fill="#E1F5EE" stroke="#5DCAA5" stroke-width="0.5" style="fill:rgb(225, 245, 238);stroke:rgb(93, 202, 165);color:rgb(0, 0, 0);stroke-width:0.5px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:&quot;Anthropic Sans&quot;, -apple-system, &quot;system-ui&quot;, &quot;Segoe UI&quot;, sans-serif;font-size:16px;font-weight:400;text-anchor:start;dominant-baseline:auto"/><text x="640" y="361" text-anchor="middle" fill="#085041" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">All in</text><text x="640" y="375" text-anchor="middle" fill="#085041" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">sync</text>
74
+
75
+ <text x="340" y="500" text-anchor="middle" fill="#888780" style="fill:rgb(95, 94, 90);stroke:none;color:rgb(0, 0, 0);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;opacity:1;font-family:system-ui, -apple-system, sans-serif;font-size:12px;font-weight:400;text-anchor:middle;dominant-baseline:auto">Spec lives in version control · diffs are human-readable · drift is detected, not hidden</text>
76
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openuispec",
3
- "version": "0.2.18",
3
+ "version": "0.2.20",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "A semantic UI specification format for AI-native, platform-native app development",
@@ -10,27 +10,23 @@
10
10
  "url": "https://github.com/rsktash/openuispec.git"
11
11
  },
12
12
  "files": [
13
- "cli/",
14
- "check/",
15
- "drift/",
16
- "mcp-server/",
17
- "prepare/",
18
- "status/",
19
- "schema/",
13
+ "dist/",
14
+ "cli/target-presets.json",
15
+ "schema/**/*.json",
20
16
  "spec/",
21
17
  "docs/",
22
18
  "examples/*/openuispec/**",
23
19
  "examples/*/openuispec.yaml",
24
20
  "examples/*/README.md",
25
- "scripts/",
26
21
  "README.md",
27
22
  "LICENSE"
28
23
  ],
29
24
  "bin": {
30
- "openuispec": "./cli/index.ts",
31
- "openuispec-mcp": "./mcp-server/index.ts"
25
+ "openuispec": "./dist/cli/index.js",
26
+ "openuispec-mcp": "./dist/mcp-server/index.js"
32
27
  },
33
28
  "scripts": {
29
+ "build": "tsc -p tsconfig.build.json && node scripts/fix-dist-bins.mjs",
34
30
  "test": "node --import tsx --test tests/check.test.ts tests/configure-target.test.ts tests/drift-prepare.test.ts tests/init.test.ts tests/mcp-tools.test.ts tests/semantic-lint.test.ts tests/status.test.ts",
35
31
  "test:screenshot": "node --import tsx --test tests/mcp-screenshot.test.ts",
36
32
  "test:all": "node --import tsx --test tests/*.test.ts",
@@ -45,6 +41,8 @@
45
41
  "drift:snapshot": "tsx drift/index.ts --snapshot --target",
46
42
  "prepare:target": "tsx prepare/index.ts",
47
43
  "status": "tsx status/index.ts",
44
+ "prepare": "npm run build",
45
+ "prepack": "npm run build",
48
46
  "postinstall": "echo \"\\n ✓ openuispec installed — if upgrading, run: openuispec update-rules\\n\"",
49
47
  "cloc": "cloc --exclude-dir=$(tr '\n' ',' < .cloc-ignore) ."
50
48
  },
@@ -52,14 +50,15 @@
52
50
  "@modelcontextprotocol/sdk": "^1.27.1",
53
51
  "ajv": "^8.17.1",
54
52
  "ajv-formats": "^3.0.1",
55
- "tsx": "^4.19.4",
56
- "yaml": "^2.7.1"
53
+ "yaml": "^2.7.1",
54
+ "zod": "^3.25.76"
57
55
  },
58
56
  "optionalDependencies": {
59
57
  "puppeteer": "^24.39.1"
60
58
  },
61
59
  "devDependencies": {
62
60
  "@types/node": "^25.5.0",
61
+ "tsx": "^4.19.4",
63
62
  "typescript": "^5.8.3"
64
63
  }
65
64
  }