@surlymochan/evalid 0.0.0-stage → 0.3.1

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 (192) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/LICENSE +21 -0
  3. package/README.md +315 -2
  4. package/RELEASE_NOTES.md +102 -0
  5. package/atoms/registry.json +758 -0
  6. package/bin/xflow.js +7208 -0
  7. package/docs/adoption/README.md +128 -0
  8. package/docs/adoption/openflow-release-hardening.md +61 -0
  9. package/docs/benchmark-openflow-vs-gstack-superpowers-openspec-2026-05-25.md +81 -0
  10. package/docs/compatibility.md +52 -0
  11. package/docs/competitive-benchmark.md +108 -0
  12. package/docs/corps-operator-guide.md +75 -0
  13. package/docs/demo-proof.md +126 -0
  14. package/docs/examples-gallery.md +115 -0
  15. package/docs/fixtures/tracker-item.json +7 -0
  16. package/docs/goal-vs-codex.md +129 -0
  17. package/docs/gstack-comparison.md +88 -0
  18. package/docs/install-upgrade.md +133 -0
  19. package/docs/integrations.md +49 -0
  20. package/docs/launch-demo.md +123 -0
  21. package/docs/launch-dossier.md +180 -0
  22. package/docs/methodology.md +149 -0
  23. package/docs/npm-publish-handoff.md +83 -0
  24. package/docs/openspec-migration.md +106 -0
  25. package/docs/public-benchmark.md +68 -0
  26. package/docs/public-release.md +145 -0
  27. package/docs/quality-assessment.md +139 -0
  28. package/docs/quickstart.md +156 -0
  29. package/docs/reviewer-guide.md +43 -0
  30. package/docs/spec-kit-benchmark.md +73 -0
  31. package/docs/super-assistant-comparison.md +106 -0
  32. package/docs/superpowers-comparison.md +82 -0
  33. package/docs/team-adoption.md +123 -0
  34. package/docs/tooling-matrix.md +91 -0
  35. package/docs/walkthrough.md +76 -0
  36. package/docs/workflow-manual.md +1125 -0
  37. package/package.json +83 -4
  38. package/prompts/pencil-draft.md +46 -0
  39. package/prompts/pencil-refine.md +46 -0
  40. package/prompts/phase-artifact.md +24 -0
  41. package/prompts/phase-execution.md +32 -0
  42. package/schemas/competitor-reconstruction-contract.schema.json +91 -0
  43. package/schemas/llm-design-review-aggregate.schema.json +83 -0
  44. package/schemas/visual-benchmark.schema.json +978 -0
  45. package/schemas/workflow.schema.json +100 -0
  46. package/scripts/run-tests.mjs +23 -0
  47. package/scripts/takein_digest.py +139 -0
  48. package/specs/README.md +118 -0
  49. package/specs/architecture.md +36 -0
  50. package/specs/product.md +33 -0
  51. package/specs/workflow.md +349 -0
  52. package/src/agent_team/atoms/codex-app-bridge.js +8 -0
  53. package/src/agent_team/atoms/design/competitor-reconstruction-review.js +44 -0
  54. package/src/agent_team/atoms/design/contract-freeze.js +8 -0
  55. package/src/agent_team/atoms/design/generation-contract.js +442 -0
  56. package/src/agent_team/atoms/design/reconstruction-pack.js +246 -0
  57. package/src/agent_team/atoms/design/reference-surface-lock.js +49 -0
  58. package/src/agent_team/atoms/patch-challenge.js +19 -0
  59. package/src/agent_team/atoms/pencil/accept.js +9 -0
  60. package/src/agent_team/atoms/pencil/draft.js +365 -0
  61. package/src/agent_team/atoms/pencil/refine.js +229 -0
  62. package/src/agent_team/atoms/phase-run-dispatch.js +8 -0
  63. package/src/agent_team/atoms/team-run.js +380 -0
  64. package/src/agent_team/atoms/visual/aesthetic-review.js +231 -0
  65. package/src/agent_team/atoms/visual/benchmark-repair-plan.js +291 -0
  66. package/src/agent_team/atoms/visual/benchmark.js +1652 -0
  67. package/src/agent_team/atoms/visual/design-selection.js +23 -0
  68. package/src/agent_team/atoms/visual/direction-synthesis.js +124 -0
  69. package/src/agent_team/atoms/visual/dom-rect-export.js +129 -0
  70. package/src/agent_team/atoms/visual/image-diff.js +186 -0
  71. package/src/agent_team/atoms/visual/layout-competition.js +8 -0
  72. package/src/agent_team/atoms/visual/page-evidence-capture.js +806 -0
  73. package/src/agent_team/atoms/visual/playwright-runtime.js +8 -0
  74. package/src/agent_team/atoms/visual/review-aggregate.js +87 -0
  75. package/src/agent_team/atoms/visual/review.js +77 -0
  76. package/src/agent_team/atoms/visual/visual-report.js +197 -0
  77. package/src/agent_team/atoms/visual/visual-token-export.js +417 -0
  78. package/src/agent_team/common.js +311 -0
  79. package/src/core/atoms/agent-invoke.js +684 -0
  80. package/src/core/atoms/event/ingest.js +30 -0
  81. package/src/core/atoms/experience/digest.js +55 -0
  82. package/src/core/atoms/gate/artifact-verify.js +83 -0
  83. package/src/core/atoms/gate/competitor-contract-validate.js +119 -0
  84. package/src/core/atoms/gate/evidence-collect.js +64 -0
  85. package/src/core/atoms/gate/payload-from-phase-run.js +78 -0
  86. package/src/core/atoms/gate/visual-benchmark-validate.js +183 -0
  87. package/src/core/atoms/gate/workbench.js +79 -0
  88. package/src/core/atoms/intake/classify.js +15 -0
  89. package/src/core/atoms/intake/design-skill-select.js +16 -0
  90. package/src/core/atoms/intake/preview-or-refine.js +19 -0
  91. package/src/core/atoms/intake/recommend.js +20 -0
  92. package/src/core/atoms/intake/research-same-category.js +19 -0
  93. package/src/core/atoms/intervention/create.js +30 -0
  94. package/src/core/atoms/memory/manage.js +27 -0
  95. package/src/core/atoms/memory/mount.js +13 -0
  96. package/src/core/atoms/mission/create.js +19 -0
  97. package/src/core/atoms/mission/list.js +14 -0
  98. package/src/core/atoms/mission/show.js +26 -0
  99. package/src/core/atoms/notify/checkpoint.js +46 -0
  100. package/src/core/atoms/phase-run/complete.js +42 -0
  101. package/src/core/atoms/phase-run/fail.js +40 -0
  102. package/src/core/atoms/phase-run/persist.js +39 -0
  103. package/src/core/atoms/phase-run/start.js +30 -0
  104. package/src/core/atoms/plugin/run.js +76 -0
  105. package/src/core/atoms/policy/gate.js +90 -0
  106. package/src/core/atoms/policy/resolve.js +11 -0
  107. package/src/core/atoms/storage/sync.js +57 -0
  108. package/src/core/atoms/workflow/advance.js +25 -0
  109. package/src/core/atoms/workflow/guard.js +127 -0
  110. package/src/core/atoms/workflow/state-load.js +37 -0
  111. package/src/core/bindings.js +37 -0
  112. package/src/core/change-artifacts.js +134 -0
  113. package/src/core/competitive-score.js +265 -0
  114. package/src/core/concurrency-policy.js +35 -0
  115. package/src/core/execution-log.js +108 -0
  116. package/src/core/intake-recommendation.js +134 -0
  117. package/src/core/memory-state.js +62 -0
  118. package/src/core/mission-state.js +780 -0
  119. package/src/core/pending-gates.js +66 -0
  120. package/src/core/phase-cost.js +116 -0
  121. package/src/core/phase-run-read.js +27 -0
  122. package/src/core/policy-overlay.js +180 -0
  123. package/src/core/state-store.js +201 -0
  124. package/src/core/workflow-executor.js +998 -0
  125. package/src/core/workflow-integrity.js +111 -0
  126. package/src/core/workflow-loader.js +163 -0
  127. package/src/core/workflow-rerun.js +84 -0
  128. package/src/core/workflow-state.js +119 -0
  129. package/src/server.js +1307 -0
  130. package/workflows/corps.yaml +479 -0
  131. package/workflows/yolo.yaml +233 -0
  132. package/xflow/README.md +76 -0
  133. package/xflow/aha/SKILL.md +82 -0
  134. package/xflow/aha/scripts/append_aha.py +50 -0
  135. package/xflow/archive/scripts/archive_change.py +338 -0
  136. package/xflow/archive/templates/merge-design.md +54 -0
  137. package/xflow/archive/templates/merge-workflow.md +26 -0
  138. package/xflow/atoms/__init__.py +6 -0
  139. package/xflow/atoms/a1_issue_create_or_patch.py +70 -0
  140. package/xflow/atoms/a2_branch_create_and_link.py +42 -0
  141. package/xflow/atoms/a3_repo_doctor.py +11 -0
  142. package/xflow/atoms/a4_project_set_status.py +11 -0
  143. package/xflow/atoms/a5_archive_commit_push_close.py +11 -0
  144. package/xflow/atoms/a6_pr_create.py +72 -0
  145. package/xflow/atoms/b1_change_scaffold.py +11 -0
  146. package/xflow/atoms/b2_status_read.py +16 -0
  147. package/xflow/atoms/b2b_status_write.py +20 -0
  148. package/xflow/atoms/b3_status_transition.py +27 -0
  149. package/xflow/atoms/b4_handoff_scaffold_or_refresh.py +11 -0
  150. package/xflow/atoms/b5_aha_append.py +11 -0
  151. package/xflow/atoms/b6_takein_digest.py +11 -0
  152. package/xflow/atoms/b6b_lookback_digest.py +11 -0
  153. package/xflow/atoms/b7_change_mission_bind.py +43 -0
  154. package/xflow/atoms/c1_mem.py +54 -0
  155. package/xflow/atoms/e6_gate_local_precheck.py +23 -0
  156. package/xflow/atoms/h1_design_lite_gate.py +74 -0
  157. package/xflow/atoms/i6a_tdd_run.py +104 -0
  158. package/xflow/atoms/i6b_tdd_proof_validate.py +165 -0
  159. package/xflow/atoms/i6c_tdd_quality_review.py +357 -0
  160. package/xflow/atoms/j1_tests_run.py +129 -0
  161. package/xflow/atoms/j4a_spec_consistency_structural.py +105 -0
  162. package/xflow/atoms/j4b_spec_delta_review.py +316 -0
  163. package/xflow/atoms/j4c_openspec_migration_map.py +121 -0
  164. package/xflow/atoms/j4d_spec_clarify_gate.py +373 -0
  165. package/xflow/atoms/j6_cr_review.py +443 -0
  166. package/xflow/atoms/k1_artifacts_complete_check.py +39 -0
  167. package/xflow/atoms/k2_merge_snippets_apply.py +11 -0
  168. package/xflow/atoms/k3_handoff_refresh.py +14 -0
  169. package/xflow/atoms/k4_mem_lesson_persist.py +65 -0
  170. package/xflow/atoms/k5_archive_publish.py +21 -0
  171. package/xflow/atoms/k6_aha_merge.py +42 -0
  172. package/xflow/atoms/tdd_lib.py +747 -0
  173. package/xflow/corps/SKILL.md +109 -0
  174. package/xflow/exec/scripts/set_issue_in_progress.py +159 -0
  175. package/xflow/goal/SKILL.md +150 -0
  176. package/xflow/handoff/SKILL.md +95 -0
  177. package/xflow/handoff/scripts/scaffold_handoff.py +304 -0
  178. package/xflow/lookback/SKILL.md +66 -0
  179. package/xflow/lookback/scripts/lookback_digest.py +46 -0
  180. package/xflow/openissue/scripts/open_issue_flow.py +438 -0
  181. package/xflow/plan/SKILL.md +38 -0
  182. package/xflow/ralph/SKILL.md +123 -0
  183. package/xflow/scripts/check_installed_xflow_skill_sync.sh +44 -0
  184. package/xflow/scripts/common.py +480 -0
  185. package/xflow/scripts/doctor.py +278 -0
  186. package/xflow/scripts/sync_installed_xflow_skill.sh +134 -0
  187. package/xflow/takein/SKILL.md +81 -0
  188. package/xflow/takein/scripts/takein_digest.py +88 -0
  189. package/xflow/yolo/SKILL.md +66 -0
  190. package/xflow/yolo/scripts/scaffold_specs_change.py +673 -0
  191. package/xflow/yolo/scripts/yolo_gate.py +312 -0
  192. package/xflow/yolo/templates/DESIGN.md +179 -0
@@ -0,0 +1,442 @@
1
+ import { readJsonFile, resolveChangePath, writeJsonFile } from '../../../core/change-artifacts.js';
2
+
3
+ function unique(values = []) {
4
+ return [...new Set(values.filter(Boolean))];
5
+ }
6
+
7
+ function buildGenerationStages(componentBlueprint = []) {
8
+ const stageBuckets = [
9
+ { id: 'shell', description: 'Build the locked surface shell and region anchors first.' },
10
+ { id: 'primary_focus', description: 'Build the most reference-sensitive primary primitives next.' },
11
+ { id: 'secondary_focus', description: 'Add supporting primary primitives without widening scope.' },
12
+ { id: 'polish', description: 'Apply local polish only after core structure and density are in place.' },
13
+ ];
14
+ return stageBuckets
15
+ .map((stage, index) => {
16
+ const components = componentBlueprint.filter((component) => component.stage_bucket === stage.id);
17
+ return {
18
+ id: stage.id,
19
+ order: index + 1,
20
+ description: stage.description,
21
+ target_component_ids: components.map((component) => component.id),
22
+ primary_geometry_profiles: unique(components.map((component) => component.geometry_profile)),
23
+ primary_token_profiles: unique(components.map((component) => component.token_profile)),
24
+ };
25
+ })
26
+ .filter((stage) => stage.target_component_ids.length > 0);
27
+ }
28
+
29
+ function buildPanelFocusSequence(componentBlueprint = [], generationStages = []) {
30
+ const stageWeight = {
31
+ shell: 1,
32
+ primary_focus: 4,
33
+ secondary_focus: 2,
34
+ polish: 1,
35
+ };
36
+ const moduleScores = new Map();
37
+ for (const component of componentBlueprint) {
38
+ const weight = stageWeight[component.stage_bucket] || 1;
39
+ const hierarchyBonus = component.hierarchy_role === 'primary' ? 2 : 0;
40
+ moduleScores.set(component.module, (moduleScores.get(component.module) || 0) + weight + hierarchyBonus);
41
+ }
42
+
43
+ return [...moduleScores.entries()]
44
+ .sort((a, b) => b[1] - a[1])
45
+ .map(([module, score], index) => {
46
+ const moduleComponents = componentBlueprint.filter((component) => component.module === module);
47
+ const stageIds = generationStages
48
+ .filter((stage) => (stage.target_component_ids || []).some((id) => moduleComponents.some((component) => component.id === id)))
49
+ .map((stage) => stage.id);
50
+ return {
51
+ module,
52
+ priority_order: index + 1,
53
+ score,
54
+ target_component_ids: moduleComponents.map((component) => component.id),
55
+ dominant_primitive_roles: unique(moduleComponents.filter((component) => component.hierarchy_role === 'primary').map((component) => component.primitive_role)),
56
+ stage_ids: stageIds,
57
+ local_generation_rule: index === 0
58
+ ? 'Finish the highest-risk panel skeleton and primary primitives before widening to other panels.'
59
+ : 'Expand only after the earlier panel reaches stable density and hierarchy.',
60
+ };
61
+ });
62
+ }
63
+
64
+ function buildAestheticStandard(input = {}, pack = {}) {
65
+ const requested = input.aesthetic_standard && typeof input.aesthetic_standard === 'object'
66
+ ? input.aesthetic_standard
67
+ : {};
68
+ return {
69
+ id: requested.id || 'high_aesthetic_product_surface',
70
+ level: requested.level || 'high',
71
+ min_accept_score: Number.isFinite(Number(requested.min_accept_score)) ? Number(requested.min_accept_score) : 0.88,
72
+ dimensions: requested.dimensions || [
73
+ 'composition_balance',
74
+ 'information_hierarchy',
75
+ 'typography_rhythm',
76
+ 'color_material_control',
77
+ 'density_and_spacing',
78
+ 'interaction_state_polish',
79
+ ],
80
+ anti_patterns: requested.anti_patterns || [
81
+ 'generic_dashboard_spacing',
82
+ 'decorative_card_stacking',
83
+ 'poster_scale_typography_inside_tools',
84
+ 'one_note_palette',
85
+ 'floating_placeholder_panels',
86
+ 'unjustified_gradient_orbs',
87
+ ],
88
+ reference_mode: input.competitor_product || pack.primary_reference_surface
89
+ ? 'reference_backed_high_aesthetic'
90
+ : 'native_high_aesthetic',
91
+ };
92
+ }
93
+
94
+ function buildImageReferenceGeneration(input = {}, primaryReferenceSurface = null) {
95
+ const requested = input.image_reference_generation && typeof input.image_reference_generation === 'object'
96
+ ? input.image_reference_generation
97
+ : {};
98
+ const enabled = requested.enabled !== false;
99
+ const modelCapability = requested.model_capability
100
+ || input.visual_generation_model
101
+ || input.image_model
102
+ || 'gpt_image_v2_style_reference';
103
+ return {
104
+ enabled,
105
+ model_capability: modelCapability,
106
+ role: 'generate high-aesthetic reference frames and component/style sheets before editable UI assembly',
107
+ non_goals: [
108
+ 'do not ship bitmap mockups as the product implementation',
109
+ 'do not bypass DOM/code evidence, benchmark checks, or Pencil editability',
110
+ ],
111
+ required_outputs: [
112
+ {
113
+ id: 'primary_surface_reference_frame',
114
+ purpose: `high-aesthetic frame for ${primaryReferenceSurface || 'the locked primary surface'}`,
115
+ },
116
+ {
117
+ id: 'component_density_sheet',
118
+ purpose: 'row, control, typography, icon, and spacing rhythm targets',
119
+ },
120
+ {
121
+ id: 'state_polish_sheet',
122
+ purpose: 'hover, selected, active, empty, loading, and error state treatment',
123
+ },
124
+ ],
125
+ prompt_contract: [
126
+ 'Use the frozen layout decomposition and visual token contract as constraints.',
127
+ 'Optimize for product credibility, hierarchy, density, and material restraint.',
128
+ 'Return reference guidance that can be translated into editable Pencil/DOM primitives.',
129
+ ],
130
+ required_artifact: 'image_reference_set.json',
131
+ };
132
+ }
133
+
134
+ function buildDesignSystemPack(input = {}, pack = {}, aestheticStandard = {}, imageReferenceGeneration = {}) {
135
+ const requested = input.design_system_pack && typeof input.design_system_pack === 'object'
136
+ ? input.design_system_pack
137
+ : {};
138
+ const componentFamilies = unique((Array.isArray(pack.component_inventory) ? pack.component_inventory : []).map((component) => component.family));
139
+ const stateIds = unique((Array.isArray(pack.state_inventory) ? pack.state_inventory : []).map((state) => state.semantic_state));
140
+ const requiredStates = unique([
141
+ 'default',
142
+ 'hover',
143
+ 'focus',
144
+ 'active',
145
+ 'selected',
146
+ 'disabled',
147
+ 'empty',
148
+ 'loading',
149
+ 'error',
150
+ ...stateIds,
151
+ ...(requested.component_policy?.required_states || []),
152
+ ]);
153
+ const allowedPrimitives = unique([
154
+ 'button',
155
+ 'input',
156
+ 'select',
157
+ 'tabs',
158
+ 'table',
159
+ 'list',
160
+ 'dialog',
161
+ 'sheet',
162
+ 'tooltip',
163
+ 'segmented_control',
164
+ 'calendar',
165
+ 'command_palette',
166
+ 'toast',
167
+ ...componentFamilies,
168
+ ...(requested.component_policy?.allowed_primitives || []),
169
+ ]);
170
+
171
+ return {
172
+ version: 1,
173
+ status: 'ready',
174
+ profile: requested.profile || 'commercial_product_design_system_pack',
175
+ summary: 'Generic corps design-system practice pack compiled from commercial and open generative-UI workflows.',
176
+ practice_sources: [
177
+ {
178
+ id: 'lovable',
179
+ adopted_practices: [
180
+ 'constrained modern web stack contract',
181
+ 'React component-library-first generation',
182
+ 'reusable design-system rules for tokens, components, and setup',
183
+ ],
184
+ non_goals: ['vendor runtime dependency', 'single hosted product lock-in'],
185
+ },
186
+ {
187
+ id: 'open_design',
188
+ adopted_practices: [
189
+ 'local-first artifact loop',
190
+ 'BYOK and swappable model/agent adapters',
191
+ 'skill plus design-system context as generation fuel',
192
+ ],
193
+ non_goals: ['copying any proprietary Claude Design UI shell'],
194
+ },
195
+ {
196
+ id: 'open_codesign',
197
+ adopted_practices: [
198
+ 'sandboxed preview before handoff',
199
+ 'region-level refinement instead of full re-prompting',
200
+ 'exportable artifacts with inline review affordances',
201
+ ],
202
+ non_goals: ['chat-only aesthetics without inspectable artifacts'],
203
+ },
204
+ {
205
+ id: 'openui',
206
+ adopted_practices: [
207
+ 'structured UI language mindset',
208
+ 'component whitelist drives generation prompts',
209
+ 'streaming-friendly UI contracts with typed component boundaries',
210
+ ],
211
+ non_goals: ['freeform untyped page generation as the default'],
212
+ },
213
+ ],
214
+ stack_contract: {
215
+ frontend: requested.stack_contract?.frontend || 'React/Vite/TypeScript-compatible editable UI output',
216
+ styling: requested.stack_contract?.styling || 'Tailwind-style token rhythm with explicit design tokens',
217
+ component_primitives: requested.stack_contract?.component_primitives || 'shadcn/Radix-style accessible primitives when no project design system is provided',
218
+ portability: 'no mandatory vendor service; generated code and proof artifacts stay project-local',
219
+ },
220
+ component_policy: {
221
+ allowed_primitives: allowedPrimitives,
222
+ required_states: requiredStates,
223
+ accessibility: [
224
+ 'keyboard reachable interactive controls',
225
+ 'visible focus state',
226
+ 'semantic labels for icon-only actions',
227
+ ],
228
+ generation_rule: 'Prompt, generate, and refine only through the allowed component primitives unless the change contract adds a scoped exception.',
229
+ },
230
+ visual_token_policy: {
231
+ aesthetic_standard_id: aestheticStandard.id || 'high_aesthetic_product_surface',
232
+ required_token_groups: [
233
+ 'color_roles',
234
+ 'typography_scale',
235
+ 'spacing_scale',
236
+ 'radius_range',
237
+ 'border_weight_tiers',
238
+ 'shadow_strength_tiers',
239
+ 'icon_density',
240
+ ],
241
+ anti_ai_slop_checks: aestheticStandard.anti_patterns || [],
242
+ },
243
+ preview_loop: {
244
+ required_artifacts: [
245
+ 'image_reference_set.json',
246
+ 'visual_benchmark.json',
247
+ 'llm_design_review.json',
248
+ 'aesthetic_review.json',
249
+ ],
250
+ required_evidence: [
251
+ 'previewable editable artifact',
252
+ 'reference-backed screenshot or scenario evidence',
253
+ 'component/state coverage for loading, empty, error, selected, and hover/focus states',
254
+ ],
255
+ image_reference_required: imageReferenceGeneration.enabled !== false,
256
+ },
257
+ prompt_contract: [
258
+ 'Treat the design-system pack as a hard generation constraint, not optional inspiration.',
259
+ 'Prefer component-system consistency over novelty unless the change contract explicitly asks for expressive exploration.',
260
+ 'Refine by region/component/state; do not rewrite the whole surface for local visual issues.',
261
+ 'Keep all output editable, inspectable, and benchmarkable.',
262
+ ],
263
+ };
264
+ }
265
+
266
+ export async function generationContract(input = {}, context = {}) {
267
+ const projectRoot = context.projectRoot || process.cwd();
268
+ const changeId = context.changeId || input.change_id || null;
269
+ if (!changeId) throw new Error('change_id is required for H2f.design.generation_contract');
270
+
271
+ const reconstructionArtifact = readJsonFile(resolveChangePath(projectRoot, changeId, 'reconstruction_pack.json'), null);
272
+ const referenceLockArtifact = readJsonFile(resolveChangePath(projectRoot, changeId, 'reference_surface_lock.json'), null);
273
+ const pack = reconstructionArtifact?.reconstruction_pack || {};
274
+ const lock = referenceLockArtifact?.reference_surface_lock || {};
275
+
276
+ const layoutRegions = Array.isArray(pack.layout_map?.regions) ? pack.layout_map.regions : [];
277
+ const componentInventory = Array.isArray(pack.component_inventory) ? pack.component_inventory : [];
278
+ const componentBlueprint = Array.isArray(pack.component_blueprint) ? pack.component_blueprint : [];
279
+ const stateInventory = Array.isArray(pack.state_inventory) ? pack.state_inventory : [];
280
+ const primaryReferenceSurface = lock.primary_reference_surface || pack.primary_reference_surface || null;
281
+ const generationStages = buildGenerationStages(componentBlueprint);
282
+ const panelFocusSequence = buildPanelFocusSequence(componentBlueprint, generationStages);
283
+ const aestheticStandard = buildAestheticStandard(input, pack);
284
+ const imageReferenceGeneration = buildImageReferenceGeneration(input, primaryReferenceSurface);
285
+ const designSystemPack = buildDesignSystemPack(input, pack, aestheticStandard, imageReferenceGeneration);
286
+
287
+ const payload = {
288
+ version: 1,
289
+ phase: 'generation_contract',
290
+ change_id: changeId,
291
+ generated_at: new Date().toISOString(),
292
+ status: 'ready',
293
+ summary: 'Generation contract converted competitor decomposition into pre-generation constraints.',
294
+ generation_contract: {
295
+ status: 'ready',
296
+ primary_reference_surface: primaryReferenceSurface,
297
+ input_artifacts: [
298
+ 'competitor_reconstruction_review.json',
299
+ 'reference_surface_lock.json',
300
+ 'reconstruction_pack.json',
301
+ ],
302
+ layout_constraints: {
303
+ required_regions: layoutRegions.map((region) => region.id),
304
+ anchor_rules: unique((pack.layout_map?.anchors || []).map((anchor) => anchor.id)),
305
+ composition_rules: [
306
+ 'Preserve region ordering implied by the primary reference surface.',
307
+ 'Do not introduce orphan regions outside the locked decomposition.',
308
+ ],
309
+ },
310
+ component_constraints: {
311
+ required_families: unique(componentInventory.map((component) => component.family)),
312
+ mapping_rules: componentInventory.map((component) => ({
313
+ component_id: component.id,
314
+ semantic_role: component.role,
315
+ required_states: component.required_states || [],
316
+ })),
317
+ component_blueprint: componentBlueprint.map((component) => ({
318
+ id: component.id,
319
+ module: component.module,
320
+ primitive_role: component.primitive_role,
321
+ hierarchy_role: component.hierarchy_role,
322
+ density_tier: component.density_tier,
323
+ geometry_profile: component.geometry_profile,
324
+ token_profile: component.token_profile,
325
+ stage_bucket: component.stage_bucket,
326
+ repair_handles: component.repair_handles || [],
327
+ })),
328
+ staged_generation: {
329
+ mode: 'component_local',
330
+ preserve_unlisted_components: true,
331
+ stages: generationStages,
332
+ },
333
+ panel_focus_sequence: panelFocusSequence,
334
+ },
335
+ state_constraints: {
336
+ required_states: stateInventory.map((state) => state.semantic_state),
337
+ state_family_contracts: stateInventory.map((state) => ({
338
+ state_id: state.id,
339
+ semantic_state: state.semantic_state,
340
+ target_components: state.target_components || [],
341
+ })),
342
+ },
343
+ visual_constraints: {
344
+ aesthetic_standard: aestheticStandard,
345
+ image_reference_generation: imageReferenceGeneration,
346
+ design_system_pack: {
347
+ required_artifact: 'design_system_pack.json',
348
+ profile: designSystemPack.profile,
349
+ practice_sources: designSystemPack.practice_sources.map((source) => source.id),
350
+ component_policy: {
351
+ allowed_primitives: designSystemPack.component_policy.allowed_primitives,
352
+ required_states: designSystemPack.component_policy.required_states,
353
+ },
354
+ },
355
+ pencil_role_boundary: {
356
+ role: 'editable_surface_assembly_and_targeted_refinement',
357
+ sufficient_alone_for_high_aesthetic: false,
358
+ guidance: [
359
+ 'Pencil should assemble and refine editable product surfaces from the frozen contract and visual references.',
360
+ 'For high-aesthetic UI, use image-generation reference frames as taste and material targets, then verify through DOM/canvas benchmark evidence.',
361
+ ],
362
+ },
363
+ token_contract: {
364
+ color_roles: {
365
+ surface: '#f7f8fb',
366
+ text_primary: '#1f2733',
367
+ },
368
+ spacing_scale: {
369
+ base: 4,
370
+ allowed_multipliers: [1, 2, 3, 4, 6],
371
+ tolerance: 1,
372
+ },
373
+ font_weights_required: [400],
374
+ radius_range: { min: 0, max: 24 },
375
+ },
376
+ geometry_hints: {
377
+ row_height_density: {
378
+ compact: 'prefer 32-40px rhythm before decorative padding',
379
+ dense: 'prefer 20-32px rhythm for repeated list/grid items',
380
+ comfortable: 'use only where the reference truly expands interaction space',
381
+ },
382
+ alignment_rules: [
383
+ 'Align repeated primitives to a shared row or column rhythm before styling.',
384
+ 'Keep primary list/calendar primitives width-stable across siblings.',
385
+ ],
386
+ primitive_profiles: unique(componentBlueprint.map((component) => component.geometry_profile)).map((profile) => ({
387
+ id: profile,
388
+ source: 'component_blueprint',
389
+ })),
390
+ },
391
+ token_hints: {
392
+ primitive_token_profiles: unique(componentBlueprint.map((component) => component.token_profile)).map((profile) => ({
393
+ id: profile,
394
+ source: 'component_blueprint',
395
+ })),
396
+ typography_roles: unique(componentBlueprint.map((component) => component.token_hints?.typography_role)),
397
+ spacing_roles: unique(componentBlueprint.map((component) => component.token_hints?.spacing_role)),
398
+ emphasis_roles: unique(componentBlueprint.map((component) => component.token_hints?.emphasis_role)),
399
+ },
400
+ density_rules: [
401
+ 'Match reference workbench density before adding decorative whitespace.',
402
+ 'Preserve detail-vs-list hierarchy from the reference surface.',
403
+ 'Prefer component-local tightening over global scale changes.',
404
+ ],
405
+ anti_drift_rules: pack.visual_token_map?.anti_drift_rules || [],
406
+ },
407
+ repair_policy: {
408
+ mode: 'component_target_only',
409
+ preserve_unlisted_components: true,
410
+ prohibit_whole_page_redraw: true,
411
+ },
412
+ downstream_inputs: {
413
+ benchmark_seed: {
414
+ required_modules: unique(componentInventory.map((component) => component.role)),
415
+ target_surfaces: unique((pack.surface_map || []).map((surface) => surface.surface_id)),
416
+ primary_reference_surface: primaryReferenceSurface,
417
+ required_states: stateInventory.map((state) => state.semantic_state),
418
+ },
419
+ pencil_inputs: [
420
+ 'generation_contract.json',
421
+ 'design_system_pack.json',
422
+ 'reconstruction_pack.json',
423
+ 'reference_surface_lock.json',
424
+ ],
425
+ component_generation_plan: generationStages,
426
+ panel_generation_priority: panelFocusSequence,
427
+ },
428
+ },
429
+ };
430
+
431
+ const artifactPath = resolveChangePath(projectRoot, changeId, 'generation_contract.json');
432
+ writeJsonFile(resolveChangePath(projectRoot, changeId, 'design_system_pack.json'), designSystemPack);
433
+ writeJsonFile(artifactPath, payload);
434
+ return {
435
+ ok: Boolean(primaryReferenceSurface) && layoutRegions.length > 0 && componentInventory.length > 0,
436
+ status: 'ready',
437
+ output_file: artifactPath,
438
+ payload,
439
+ };
440
+ }
441
+
442
+ export default generationContract;
@@ -0,0 +1,246 @@
1
+ import { resolveChangePath, writeJsonFile } from '../../../core/change-artifacts.js';
2
+
3
+ function list(inputValue) {
4
+ return Array.isArray(inputValue) ? inputValue.filter(Boolean) : [];
5
+ }
6
+
7
+ function titleize(value) {
8
+ return String(value || '')
9
+ .split(/[_-]+/)
10
+ .filter(Boolean)
11
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
12
+ .join(' ');
13
+ }
14
+
15
+ function inferComponentFamily(moduleName) {
16
+ if (moduleName.includes('detail')) return 'detail_region';
17
+ if (moduleName.includes('calendar')) return 'planner_region';
18
+ if (moduleName.includes('nav') || moduleName.includes('sidebar')) return 'navigation_region';
19
+ return 'workbench_region';
20
+ }
21
+
22
+ function blueprintTemplatesForModule(moduleName) {
23
+ if (moduleName.includes('calendar')) {
24
+ return [
25
+ { primitive_role: 'toolbar_group', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'horizontal_controls', token_profile: 'toolbar_controls' },
26
+ { primitive_role: 'grid_header', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'calendar_header', token_profile: 'header_labels' },
27
+ { primitive_role: 'grid_cell', hierarchy_role: 'primary', density_tier: 'dense', geometry_profile: 'calendar_cell', token_profile: 'calendar_surface' },
28
+ { primitive_role: 'status_chip', hierarchy_role: 'primary', density_tier: 'dense', geometry_profile: 'chip_inline', token_profile: 'event_chip' },
29
+ { primitive_role: 'selection_badge', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'badge_compact', token_profile: 'selection_badge' },
30
+ ];
31
+ }
32
+ if (moduleName.includes('detail')) {
33
+ return [
34
+ { primitive_role: 'panel_header', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'panel_header', token_profile: 'section_heading' },
35
+ { primitive_role: 'text_block', hierarchy_role: 'primary', density_tier: 'comfortable', geometry_profile: 'stacked_fields', token_profile: 'detail_fields' },
36
+ { primitive_role: 'meta_line', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'meta_row', token_profile: 'detail_meta' },
37
+ { primitive_role: 'input_block', hierarchy_role: 'primary', density_tier: 'comfortable', geometry_profile: 'form_stack', token_profile: 'detail_inputs' },
38
+ ];
39
+ }
40
+ return [
41
+ { primitive_role: 'toolbar_group', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'horizontal_controls', token_profile: 'toolbar_controls' },
42
+ { primitive_role: 'input_block', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'quick_add_row', token_profile: 'quick_add' },
43
+ { primitive_role: 'list_row', hierarchy_role: 'primary', density_tier: 'dense', geometry_profile: 'row_compact', token_profile: 'list_row_surface' },
44
+ { primitive_role: 'selection_badge', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'checkbox_compact', token_profile: 'selection_badge' },
45
+ { primitive_role: 'meta_line', hierarchy_role: 'supporting', density_tier: 'compact', geometry_profile: 'meta_row', token_profile: 'meta_text' },
46
+ ];
47
+ }
48
+
49
+ function buildComponentBlueprint(requiredModules, primaryJourneys) {
50
+ return requiredModules.flatMap((moduleName, moduleIndex) => {
51
+ const templates = blueprintTemplatesForModule(moduleName);
52
+ return templates.map((template, templateIndex) => ({
53
+ id: `${moduleName}_${template.primitive_role}_${templateIndex + 1}`,
54
+ component_id: `${moduleName}_workbench_component`,
55
+ module: moduleName,
56
+ primitive_role: template.primitive_role,
57
+ hierarchy_role: template.hierarchy_role,
58
+ density_tier: template.density_tier,
59
+ geometry_profile: template.geometry_profile,
60
+ token_profile: template.token_profile,
61
+ build_priority: template.hierarchy_role === 'primary' ? 'high' : 'medium',
62
+ expected_states: primaryJourneys.map((journey) => `${journey}_state`),
63
+ geometry_hints: {
64
+ alignment_axis: template.primitive_role === 'toolbar_group' ? 'horizontal' : 'vertical',
65
+ width_behavior: template.primitive_role === 'grid_cell' ? 'fractional' : template.primitive_role === 'list_row' ? 'fill_parent' : 'intrinsic_or_fill',
66
+ height_density: template.density_tier,
67
+ padding_role: template.primitive_role === 'list_row' ? 'row_padding' : template.primitive_role === 'grid_cell' ? 'cell_padding' : 'control_padding',
68
+ },
69
+ token_hints: {
70
+ typography_role: template.primitive_role === 'list_row' ? 'list_body' : template.primitive_role === 'grid_header' ? 'section_label' : 'detail_meta',
71
+ emphasis_role: template.hierarchy_role,
72
+ radius_role: template.primitive_role === 'status_chip' ? 'chip_radius' : template.primitive_role === 'input_block' ? 'control_radius' : 'surface_radius',
73
+ spacing_role: template.primitive_role === 'meta_line' ? 'meta_gap' : 'component_gap',
74
+ },
75
+ local_relationships: [
76
+ templateIndex > 0 ? { type: 'follows', target: `${moduleName}_${templates[templateIndex - 1].primitive_role}_${templateIndex}` } : null,
77
+ { type: 'belongs_to', target: `${moduleName}_workbench_component` },
78
+ ].filter(Boolean),
79
+ stage_bucket: moduleIndex === 0 ? (template.hierarchy_role === 'primary' ? 'primary_focus' : 'shell') : (template.hierarchy_role === 'primary' ? 'secondary_focus' : 'polish'),
80
+ repair_handles: [
81
+ `${template.primitive_role}_geometry`,
82
+ `${template.primitive_role}_tokens`,
83
+ ],
84
+ }));
85
+ });
86
+ }
87
+
88
+ function buildRelationshipGraph(layoutRegions, componentBlueprint) {
89
+ const regionEdges = layoutRegions.map((region, index) => ({
90
+ id: `${region.id}_region_order`,
91
+ type: 'region_order',
92
+ source: region.id,
93
+ target: index === 0 ? null : layoutRegions[index - 1].id,
94
+ detail: index === 0 ? 'leading_region' : 'follows_previous_region',
95
+ }));
96
+
97
+ const componentEdges = componentBlueprint.flatMap((component) => [
98
+ {
99
+ id: `${component.id}_belongs_to`,
100
+ type: 'belongs_to_region',
101
+ source: component.id,
102
+ target: component.module,
103
+ detail: component.hierarchy_role,
104
+ },
105
+ ...component.local_relationships.map((relationship, index) => ({
106
+ id: `${component.id}_local_${index + 1}`,
107
+ type: relationship.type,
108
+ source: component.id,
109
+ target: relationship.target,
110
+ detail: component.stage_bucket,
111
+ })),
112
+ ]);
113
+
114
+ return [...regionEdges, ...componentEdges];
115
+ }
116
+
117
+ export async function reconstructionPack(input = {}, context = {}) {
118
+ const projectRoot = context.projectRoot || process.cwd();
119
+ const changeId = context.changeId || input.change_id || null;
120
+ if (!changeId) throw new Error('change_id is required for H2e.design.reconstruction_pack');
121
+
122
+ const targetSurfaces = list(input.target_surfaces);
123
+ const requiredModules = list(input.required_modules);
124
+ const primaryJourneys = list(input.primary_journeys);
125
+ const businessLogicInvariants = list(input.business_logic_invariants);
126
+ const primaryReferenceSurface = typeof input.primary_reference_surface === 'string' && input.primary_reference_surface.trim()
127
+ ? input.primary_reference_surface.trim()
128
+ : (targetSurfaces[0] || null);
129
+
130
+ const surfaceMap = targetSurfaces.map((surface, index) => ({
131
+ surface_id: surface,
132
+ priority: surface === primaryReferenceSurface ? 'primary' : 'supporting',
133
+ role: surface === primaryReferenceSurface ? 'reference_anchor' : 'support_surface',
134
+ target_modules: requiredModules,
135
+ target_journeys: primaryJourneys,
136
+ target_states: primaryJourneys.map((journey) => `${journey}_state`),
137
+ order: index + 1,
138
+ }));
139
+
140
+ const layoutRegions = requiredModules.map((moduleName, index) => ({
141
+ id: moduleName,
142
+ role: 'required_region',
143
+ relative_position: index === 0 ? 'leading' : index === requiredModules.length - 1 ? 'trailing' : 'center',
144
+ required_presence: true,
145
+ target_modules: [moduleName],
146
+ }));
147
+
148
+ const componentInventory = requiredModules.map((moduleName) => ({
149
+ id: `${moduleName}_workbench_component`,
150
+ role: moduleName,
151
+ family: inferComponentFamily(moduleName),
152
+ density: 'match_reference',
153
+ required_states: primaryJourneys.map((journey) => `${journey}_state`),
154
+ }));
155
+ const componentBlueprint = buildComponentBlueprint(requiredModules, primaryJourneys);
156
+ const relationshipGraph = buildRelationshipGraph(layoutRegions, componentBlueprint);
157
+
158
+ const stateInventory = primaryJourneys.map((journey) => ({
159
+ id: `${journey}_state`,
160
+ semantic_state: journey,
161
+ trigger: 'primary_journey',
162
+ target_components: requiredModules,
163
+ }));
164
+
165
+ const visualTokenMap = {
166
+ typography_roles: ['display', 'section_label', 'list_body', 'detail_meta'],
167
+ spacing_roles: ['panel_gap', 'card_padding', 'toolbar_gap'],
168
+ color_roles: ['surface', 'surface_emphasis', 'text_primary', 'text_muted', 'accent'],
169
+ elevation_roles: ['base', 'raised', 'interactive'],
170
+ anti_drift_rules: [
171
+ 'Do not invent new panel families not present in the reference surface lock.',
172
+ 'Do not swap primary and supporting surfaces during generation.',
173
+ ],
174
+ };
175
+
176
+ const referenceIntermediateModel = {
177
+ reference_dom_regions: surfaceMap.map((surface, index) => ({
178
+ id: `${surface.surface_id}_region`,
179
+ source_surface: surface.surface_id,
180
+ semantic_role: surface.role,
181
+ expected_order: index + 1,
182
+ })),
183
+ reference_component_roles: componentInventory.map((component) => ({
184
+ component_id: component.id,
185
+ family: component.family,
186
+ semantic_role: component.role,
187
+ })),
188
+ reference_component_blueprint: componentBlueprint.map((component) => ({
189
+ component_id: component.id,
190
+ primitive_role: component.primitive_role,
191
+ hierarchy_role: component.hierarchy_role,
192
+ geometry_profile: component.geometry_profile,
193
+ token_profile: component.token_profile,
194
+ })),
195
+ reference_state_matrix: stateInventory.map((state) => ({
196
+ state_id: state.id,
197
+ semantic_state: state.semantic_state,
198
+ target_components: state.target_components,
199
+ })),
200
+ relationship_graph: relationshipGraph,
201
+ reference_token_summary: {
202
+ visual_token_roles: visualTokenMap,
203
+ protected_invariants: businessLogicInvariants,
204
+ },
205
+ };
206
+
207
+ const payload = {
208
+ version: 1,
209
+ phase: 'reconstruction_pack',
210
+ change_id: changeId,
211
+ generated_at: new Date().toISOString(),
212
+ status: 'ready',
213
+ summary: 'Structured competitor decomposition pack prepared for generation-time use.',
214
+ reconstruction_pack: {
215
+ status: 'ready',
216
+ primary_reference_surface: primaryReferenceSurface,
217
+ surface_map: surfaceMap,
218
+ layout_map: {
219
+ regions: layoutRegions,
220
+ anchors: layoutRegions.map((region, index) => ({
221
+ id: `${region.id}_anchor`,
222
+ anchor_role: region.role,
223
+ relative_to: index === 0 ? null : layoutRegions[index - 1].id,
224
+ })),
225
+ },
226
+ component_inventory: componentInventory,
227
+ component_blueprint: componentBlueprint,
228
+ state_inventory: stateInventory,
229
+ visual_token_map: visualTokenMap,
230
+ reference_intermediate_model: referenceIntermediateModel,
231
+ decomposition_summary: `Prepared ${surfaceMap.length} surfaces, ${layoutRegions.length} layout regions, ${componentInventory.length} component families, ${componentBlueprint.length} component primitives, and ${stateInventory.length} primary states.`,
232
+ decomposition_labels: requiredModules.map((moduleName) => titleize(moduleName)),
233
+ },
234
+ };
235
+
236
+ const artifactPath = resolveChangePath(projectRoot, changeId, 'reconstruction_pack.json');
237
+ writeJsonFile(artifactPath, payload);
238
+ return {
239
+ ok: Boolean(primaryReferenceSurface) && surfaceMap.length > 0 && componentInventory.length > 0,
240
+ status: 'ready',
241
+ output_file: artifactPath,
242
+ payload,
243
+ };
244
+ }
245
+
246
+ export default reconstructionPack;