buildanything 2.0.0 → 2.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 (115) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +9 -1
  3. package/README.md +57 -61
  4. package/agents/a11y-architect.md +2 -0
  5. package/agents/briefing-officer.md +172 -0
  6. package/agents/business-model.md +14 -12
  7. package/agents/code-architect.md +6 -1
  8. package/agents/code-reviewer.md +3 -2
  9. package/agents/code-simplifier.md +12 -4
  10. package/agents/design-brand-guardian.md +19 -0
  11. package/agents/design-critic.md +16 -11
  12. package/agents/design-inclusive-visuals-specialist.md +2 -0
  13. package/agents/design-ui-designer.md +17 -0
  14. package/agents/design-ux-architect.md +15 -0
  15. package/agents/design-ux-researcher.md +102 -7
  16. package/agents/engineering-ai-engineer.md +2 -0
  17. package/agents/engineering-backend-architect.md +2 -0
  18. package/agents/engineering-data-engineer.md +2 -0
  19. package/agents/engineering-devops-automator.md +2 -0
  20. package/agents/engineering-frontend-developer.md +13 -0
  21. package/agents/engineering-mobile-app-builder.md +2 -0
  22. package/agents/engineering-rapid-prototyper.md +15 -2
  23. package/agents/engineering-security-engineer.md +2 -0
  24. package/agents/engineering-senior-developer.md +13 -0
  25. package/agents/engineering-sre.md +2 -0
  26. package/agents/engineering-technical-writer.md +2 -0
  27. package/agents/feature-intel.md +8 -7
  28. package/agents/ios-app-review-guardian.md +2 -0
  29. package/agents/ios-foundation-models-specialist.md +2 -0
  30. package/agents/ios-product-reality-auditor.md +292 -0
  31. package/agents/ios-storekit-specialist.md +2 -0
  32. package/agents/ios-swift-architect.md +1 -0
  33. package/agents/ios-swift-search.md +1 -0
  34. package/agents/ios-swift-ui-design.md +7 -4
  35. package/agents/marketing-app-store-optimizer.md +2 -0
  36. package/agents/planner.md +6 -1
  37. package/agents/pr-test-analyzer.md +3 -2
  38. package/agents/product-feedback-synthesizer.md +62 -0
  39. package/agents/product-owner.md +163 -0
  40. package/agents/product-reality-auditor.md +216 -0
  41. package/agents/product-spec-writer.md +176 -0
  42. package/agents/refactor-cleaner.md +9 -1
  43. package/agents/security-reviewer.md +2 -1
  44. package/agents/silent-failure-hunter.md +2 -1
  45. package/agents/swift-build-resolver.md +2 -0
  46. package/agents/swift-reviewer.md +2 -1
  47. package/agents/tech-feasibility.md +5 -3
  48. package/agents/testing-api-tester.md +2 -0
  49. package/agents/testing-evidence-collector.md +24 -0
  50. package/agents/testing-performance-benchmarker.md +2 -0
  51. package/agents/testing-reality-checker.md +2 -1
  52. package/agents/visual-research.md +7 -5
  53. package/bin/adapters/scribe-tool.ts +4 -2
  54. package/bin/adapters/write-lease-tool.ts +1 -1
  55. package/bin/buildanything-runtime.ts +20 -107
  56. package/bin/graph-index.js +24 -0
  57. package/bin/graph-index.ts +340 -0
  58. package/bin/mcp-servers/graph-mcp.js +26 -0
  59. package/bin/mcp-servers/graph-mcp.ts +481 -0
  60. package/bin/mcp-servers/orchestrator-mcp.js +26 -0
  61. package/bin/mcp-servers/orchestrator-mcp.ts +361 -0
  62. package/bin/setup.js +272 -111
  63. package/commands/build.md +424 -177
  64. package/commands/idea-sweep.md +2 -2
  65. package/commands/setup.md +15 -4
  66. package/commands/ux-review.md +3 -3
  67. package/commands/verify.md +3 -0
  68. package/docs/migration/phase-graph.yaml +573 -157
  69. package/hooks/design-md-lint +4 -0
  70. package/hooks/design-md-lint.ts +295 -0
  71. package/hooks/pre-tool-use.ts +37 -6
  72. package/hooks/record-mode-transitions.ts +63 -6
  73. package/hooks/subagent-start.ts +3 -2
  74. package/package.json +3 -1
  75. package/protocols/agent-prompt-authoring.md +165 -0
  76. package/protocols/architecture-schema.md +10 -3
  77. package/protocols/cleanup.md +4 -0
  78. package/protocols/decision-log.md +8 -4
  79. package/protocols/design-md-authoring.md +520 -0
  80. package/protocols/design-md-spec.md +362 -0
  81. package/protocols/fake-data-detector.md +1 -1
  82. package/protocols/ios-fake-data-detector.md +65 -0
  83. package/protocols/ios-phase-branches.md +128 -43
  84. package/protocols/launch-readiness.md +9 -5
  85. package/protocols/metric-loop.md +1 -1
  86. package/protocols/page-spec-schema.md +234 -0
  87. package/protocols/product-spec-schema.md +354 -0
  88. package/protocols/sprint-tasks-schema.md +53 -0
  89. package/protocols/state-schema.json +38 -3
  90. package/protocols/state-schema.md +32 -2
  91. package/protocols/verify.md +29 -1
  92. package/protocols/web-phase-branches.md +246 -76
  93. package/skills/ios/ios-bootstrap/SKILL.md +1 -1
  94. package/src/graph/ids.ts +86 -0
  95. package/src/graph/index.ts +32 -0
  96. package/src/graph/parser/architecture.ts +603 -0
  97. package/src/graph/parser/component-manifest.ts +268 -0
  98. package/src/graph/parser/decisions-jsonl.ts +407 -0
  99. package/src/graph/parser/design-md-pass2.ts +253 -0
  100. package/src/graph/parser/design-md.ts +477 -0
  101. package/src/graph/parser/page-spec.ts +496 -0
  102. package/src/graph/parser/product-spec.ts +930 -0
  103. package/src/graph/parser/screenshot.ts +342 -0
  104. package/src/graph/parser/sprint-tasks.ts +317 -0
  105. package/src/graph/storage/index.ts +1154 -0
  106. package/src/graph/types.ts +432 -0
  107. package/src/graph/util/dhash.ts +84 -0
  108. package/src/lrr/aggregator.ts +105 -10
  109. package/src/orchestrator/hooks/context-header.ts +34 -10
  110. package/src/orchestrator/hooks/token-accounting.ts +25 -14
  111. package/src/orchestrator/mcp/cycle-counter.ts +2 -1
  112. package/src/orchestrator/mcp/scribe.ts +27 -16
  113. package/src/orchestrator/mcp/write-lease.ts +30 -13
  114. package/src/orchestrator/phase4-shared-context.ts +20 -4
  115. package/protocols/visual-dna.md +0 -185
@@ -0,0 +1,253 @@
1
+ // Deterministic extractor for DESIGN.md Pass 2 (design tokens from YAML frontmatter).
2
+ // Source of truth: docs/graph/07-slice3-schema.md §4.2 + protocols/design-md-spec.md.
3
+ // Sibling to design-md.ts (Pass 1) — invoked by CLI dispatch in parallel.
4
+
5
+ import YAML from "yaml";
6
+ import { ids, sha256Hex } from "../ids.js";
7
+ import type {
8
+ ExtractError,
9
+ ExtractResult,
10
+ GraphEdge,
11
+ GraphFragment,
12
+ GraphNode,
13
+ TokenNode,
14
+ } from "../types.js";
15
+
16
+ const PRODUCED_BY_WEB = "design-ui-designer";
17
+ const PRODUCED_AT_STEP_WEB = "3.4";
18
+ const PRODUCED_BY_IOS = "ios-swift-ui-design";
19
+ const PRODUCED_AT_STEP_IOS = "3.2-ios";
20
+ const SCHEMA = "buildanything-slice-3" as const;
21
+
22
+ type TokenLayer = TokenNode["layer"];
23
+ type AxisName = NonNullable<TokenNode["axis_provenance"]>;
24
+
25
+ const SKIP_KEYS = new Set(["version", "name", "description"]);
26
+
27
+ const KNOWN_OBJECT_KEYS: Record<string, TokenLayer> = {
28
+ colors: "color",
29
+ typography: "typography",
30
+ rounded: "shape",
31
+ spacing: "spacing",
32
+ components: "component",
33
+ };
34
+
35
+ // Keys that allow a primitive top-level value (emit one token).
36
+ const PRIMITIVE_OK_KEYS = new Set(["rounded", "spacing"]);
37
+
38
+ interface Ctx {
39
+ mdPath: string;
40
+ errors: ExtractError[];
41
+ }
42
+
43
+ // --- Helpers ---
44
+
45
+ function parseFrontmatter(content: string): { yaml: string; found: boolean } {
46
+ const lines = content.split(/\r?\n/);
47
+ if (lines.length === 0 || lines[0].trim() !== "---") return { yaml: "", found: false };
48
+ for (let i = 1; i < lines.length; i++) {
49
+ if (lines[i].trim() === "---") {
50
+ return { yaml: lines.slice(1, i).join("\n"), found: true };
51
+ }
52
+ }
53
+ return { yaml: "", found: false };
54
+ }
55
+
56
+ function stableStringify(v: unknown): string {
57
+ if (v === null || v === undefined) return String(v);
58
+ if (typeof v !== "object") return JSON.stringify(v);
59
+ if (Array.isArray(v)) return "[" + v.map(stableStringify).join(",") + "]";
60
+ const obj = v as Record<string, unknown>;
61
+ const keys = Object.keys(obj).sort();
62
+ return "{" + keys.map((k) => JSON.stringify(k) + ":" + stableStringify(obj[k])).join(",") + "}";
63
+ }
64
+
65
+ function layerForKey(key: string): TokenLayer {
66
+ if (key in KNOWN_OBJECT_KEYS) return KNOWN_OBJECT_KEYS[key];
67
+ if (key.startsWith("motion-")) return "motion";
68
+ if (key.startsWith("elevation-")) return "elevation";
69
+ if (key.startsWith("shape-")) return "shape";
70
+ if (key.startsWith("type-")) return "type";
71
+ return "component"; // catchall
72
+ }
73
+
74
+ function getAxisProvenance(name: string, layer: TokenLayer): AxisName | null {
75
+ const lower = name.toLowerCase();
76
+ if (lower.includes("glass") || lower.includes("blur")) return "material";
77
+ if (layer === "color") return "character";
78
+ if (layer === "typography") {
79
+ if (name === "typography.scale" || name.endsWith(".scale")) return "density";
80
+ return "type";
81
+ }
82
+ if (layer === "shape") return "character";
83
+ if (layer === "spacing") return "density";
84
+ if (layer === "motion") return "motion";
85
+ if (layer === "elevation") return "material";
86
+ if (layer === "type") return "type";
87
+ if (layer === "component") return null;
88
+ return null;
89
+ }
90
+
91
+ function typographyCategory(key: string): string {
92
+ const idx = key.indexOf("-");
93
+ return idx > 0 ? key.slice(0, idx) : key;
94
+ }
95
+
96
+ function isPlainObject(v: unknown): v is Record<string, unknown> {
97
+ return v !== null && typeof v === "object" && !Array.isArray(v);
98
+ }
99
+
100
+ function emptyFragment(mdPath: string, mdContent: string): GraphFragment {
101
+ return {
102
+ version: 1,
103
+ schema: SCHEMA,
104
+ source_file: mdPath,
105
+ source_sha: sha256Hex(mdContent),
106
+ produced_at: new Date().toISOString(),
107
+ nodes: [],
108
+ edges: [],
109
+ };
110
+ }
111
+
112
+ // --- Token collection ---
113
+
114
+ interface RawToken {
115
+ name: string;
116
+ value: string;
117
+ layer: TokenLayer;
118
+ category: string | null;
119
+ }
120
+
121
+ function collectTokens(
122
+ parsed: Record<string, unknown>,
123
+ ctx: Ctx,
124
+ ): RawToken[] | null {
125
+ const tokens: RawToken[] = [];
126
+
127
+ for (const key of Object.keys(parsed)) {
128
+ if (SKIP_KEYS.has(key)) continue;
129
+ const val = parsed[key];
130
+ if (val === null || val === undefined) continue;
131
+
132
+ const isKnown = key in KNOWN_OBJECT_KEYS;
133
+ const layer = layerForKey(key);
134
+
135
+ if (isKnown) {
136
+ // Empty object → skip
137
+ if (isPlainObject(val) && Object.keys(val).length === 0) continue;
138
+
139
+ // Primitive at top level
140
+ if (!isPlainObject(val)) {
141
+ if (PRIMITIVE_OK_KEYS.has(key)) {
142
+ tokens.push({ name: key, value: String(val), layer, category: null });
143
+ continue;
144
+ }
145
+ ctx.errors.push({ line: 1, message: `${key}: expected object, got ${typeof val}` });
146
+ return null;
147
+ }
148
+
149
+ const obj = val as Record<string, unknown>;
150
+
151
+ if (key === "colors") {
152
+ for (const ck of Object.keys(obj)) {
153
+ tokens.push({ name: `colors.${ck}`, value: String(obj[ck]), layer: "color", category: ck });
154
+ }
155
+ } else if (key === "typography") {
156
+ for (const tk of Object.keys(obj)) {
157
+ const tv = obj[tk];
158
+ const value = isPlainObject(tv) ? stableStringify(tv) : String(tv);
159
+ tokens.push({ name: `typography.${tk}`, value, layer: "typography", category: typographyCategory(tk) });
160
+ }
161
+ } else if (key === "rounded" || key === "spacing") {
162
+ for (const sk of Object.keys(obj)) {
163
+ tokens.push({ name: `${key}.${sk}`, value: String(obj[sk]), layer, category: sk });
164
+ }
165
+ } else if (key === "components") {
166
+ for (const ck of Object.keys(obj)) {
167
+ const cv = obj[ck];
168
+ const value = isPlainObject(cv) ? stableStringify(cv) : String(cv);
169
+ tokens.push({ name: `components.${ck}`, value, layer: "component", category: null });
170
+ }
171
+ }
172
+ } else {
173
+ // Non-standard top-level key
174
+ const value = isPlainObject(val) ? stableStringify(val) : String(val);
175
+ tokens.push({ name: key, value, layer, category: null });
176
+ }
177
+ }
178
+
179
+ return tokens;
180
+ }
181
+
182
+ // --- Main ---
183
+
184
+ export function extractDesignMdTokens(input: { mdPath: string; mdContent: string; projectType?: "web" | "ios" }): ExtractResult {
185
+ const { mdPath, mdContent, projectType } = input;
186
+ const producedBy = projectType === "ios" ? PRODUCED_BY_IOS : PRODUCED_BY_WEB;
187
+ const producedAtStep = projectType === "ios" ? PRODUCED_AT_STEP_IOS : PRODUCED_AT_STEP_WEB;
188
+ const { yaml, found } = parseFrontmatter(mdContent);
189
+
190
+ if (!found) return { ok: true, fragment: emptyFragment(mdPath, mdContent), errors: [] };
191
+
192
+ let parsed: unknown;
193
+ try {
194
+ parsed = YAML.parse(yaml);
195
+ } catch (e: unknown) {
196
+ return { ok: false, errors: [{ line: 1, message: `YAML parse error: ${e instanceof Error ? e.message : String(e)}` }] };
197
+ }
198
+
199
+ if (!parsed || !isPlainObject(parsed)) {
200
+ return { ok: true, fragment: emptyFragment(mdPath, mdContent), errors: [] };
201
+ }
202
+
203
+ const ctx: Ctx = { mdPath, errors: [] };
204
+ const rawTokens = collectTokens(parsed as Record<string, unknown>, ctx);
205
+ if (rawTokens === null) return { ok: false, errors: ctx.errors };
206
+ if (rawTokens.length === 0) return { ok: true, fragment: emptyFragment(mdPath, mdContent), errors: [] };
207
+
208
+ const nodes: GraphNode[] = rawTokens.map((t): TokenNode => ({
209
+ id: ids.token(t.layer, t.name),
210
+ label: t.name,
211
+ entity_type: "token",
212
+ source_file: mdPath,
213
+ source_location: "L1",
214
+ confidence: "EXTRACTED",
215
+ name: t.name,
216
+ value: t.value,
217
+ layer: t.layer,
218
+ axis_provenance: getAxisProvenance(t.name, t.layer),
219
+ category: t.category,
220
+ }));
221
+
222
+ const edges: GraphEdge[] = [];
223
+ for (const node of nodes) {
224
+ const tn = node as TokenNode;
225
+ if (tn.axis_provenance !== null) {
226
+ edges.push({
227
+ source: tn.id,
228
+ target: ids.dnaAxis(tn.axis_provenance),
229
+ relation: "token_derived_from",
230
+ confidence: "EXTRACTED",
231
+ source_file: mdPath,
232
+ source_location: "L1",
233
+ produced_by_agent: producedBy,
234
+ produced_at_step: producedAtStep,
235
+ });
236
+ }
237
+ }
238
+
239
+ nodes.sort((a, b) => a.id.localeCompare(b.id));
240
+ edges.sort((a, b) => `${a.relation} ${a.source} ${a.target}`.localeCompare(`${b.relation} ${b.source} ${b.target}`));
241
+
242
+ const fragment: GraphFragment = {
243
+ version: 1,
244
+ schema: SCHEMA,
245
+ source_file: mdPath,
246
+ source_sha: sha256Hex(mdContent),
247
+ produced_at: new Date().toISOString(),
248
+ nodes,
249
+ edges,
250
+ };
251
+
252
+ return { ok: true, fragment, errors: [] };
253
+ }