@sun-asterisk/sungen 2.4.6 → 2.5.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.
- package/README.md +88 -7
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/commands/add.js +109 -9
- package/dist/cli/commands/add.js.map +1 -1
- package/dist/cli/commands/figma.d.ts +11 -0
- package/dist/cli/commands/figma.d.ts.map +1 -0
- package/dist/cli/commands/figma.js +178 -0
- package/dist/cli/commands/figma.js.map +1 -0
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +2 -0
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/index.js +4 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/generators/gherkin-parser/index.d.ts +1 -0
- package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
- package/dist/generators/gherkin-parser/index.js +3 -0
- package/dist/generators/gherkin-parser/index.js.map +1 -1
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts +29 -1
- package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +21 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js +11 -2
- package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
- package/dist/generators/test-generator/adapters/playwright/templates/after-all.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/after-each.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/before-all.hbs +8 -0
- package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
- package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +24 -0
- package/dist/generators/test-generator/code-generator.d.ts +2 -0
- package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
- package/dist/generators/test-generator/code-generator.js +109 -12
- package/dist/generators/test-generator/code-generator.js.map +1 -1
- package/dist/generators/test-generator/step-mapper.d.ts +1 -0
- package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
- package/dist/generators/test-generator/step-mapper.js +1 -1
- package/dist/generators/test-generator/step-mapper.js.map +1 -1
- package/dist/generators/test-generator/template-engine.d.ts +29 -1
- package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
- package/dist/generators/test-generator/template-engine.js +11 -2
- package/dist/generators/test-generator/template-engine.js.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.d.ts +11 -2
- package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/data-resolver.js +36 -25
- package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
- package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts +7 -0
- package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts.map +1 -0
- package/dist/generators/test-generator/utils/runtime-data-transformer.js +42 -0
- package/dist/generators/test-generator/utils/runtime-data-transformer.js.map +1 -0
- package/dist/generators/types.d.ts +1 -0
- package/dist/generators/types.d.ts.map +1 -1
- package/dist/generators/types.js.map +1 -1
- package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
- package/dist/orchestrator/ai-rules-updater.js +2 -0
- package/dist/orchestrator/ai-rules-updater.js.map +1 -1
- package/dist/orchestrator/figma/figma-scaffolder-helpers.d.ts +33 -0
- package/dist/orchestrator/figma/figma-scaffolder-helpers.d.ts.map +1 -0
- package/dist/orchestrator/figma/figma-scaffolder-helpers.js +135 -0
- package/dist/orchestrator/figma/figma-scaffolder-helpers.js.map +1 -0
- package/dist/orchestrator/figma/figma-scaffolder-types.d.ts +25 -0
- package/dist/orchestrator/figma/figma-scaffolder-types.d.ts.map +1 -0
- package/dist/orchestrator/figma/figma-scaffolder-types.js +7 -0
- package/dist/orchestrator/figma/figma-scaffolder-types.js.map +1 -0
- package/dist/orchestrator/figma/figma-scaffolder.d.ts +23 -0
- package/dist/orchestrator/figma/figma-scaffolder.d.ts.map +1 -0
- package/dist/orchestrator/figma/figma-scaffolder.js +212 -0
- package/dist/orchestrator/figma/figma-scaffolder.js.map +1 -0
- package/dist/orchestrator/figma/node-path-collapser.d.ts +16 -0
- package/dist/orchestrator/figma/node-path-collapser.d.ts.map +1 -0
- package/dist/orchestrator/figma/node-path-collapser.js +37 -0
- package/dist/orchestrator/figma/node-path-collapser.js.map +1 -0
- package/dist/orchestrator/figma/spec-figma-renderer.d.ts +44 -0
- package/dist/orchestrator/figma/spec-figma-renderer.d.ts.map +1 -0
- package/dist/orchestrator/figma/spec-figma-renderer.js +45 -0
- package/dist/orchestrator/figma/spec-figma-renderer.js.map +1 -0
- package/dist/orchestrator/figma/spec-figma-section-renderers.d.ts +23 -0
- package/dist/orchestrator/figma/spec-figma-section-renderers.d.ts.map +1 -0
- package/dist/orchestrator/figma/spec-figma-section-renderers.js +47 -0
- package/dist/orchestrator/figma/spec-figma-section-renderers.js.map +1 -0
- package/dist/orchestrator/project-initializer.d.ts +9 -0
- package/dist/orchestrator/project-initializer.d.ts.map +1 -1
- package/dist/orchestrator/project-initializer.js +74 -10
- package/dist/orchestrator/project-initializer.js.map +1 -1
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +56 -11
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +30 -17
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-review.md +4 -3
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +34 -2
- package/dist/orchestrator/templates/ai-instructions/claude-config.md +12 -2
- package/dist/orchestrator/templates/ai-instructions/claude-skill-figma-source.md +151 -0
- package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +66 -13
- package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +93 -23
- package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +2 -0
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +53 -9
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +21 -16
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-review.md +4 -3
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +34 -2
- package/dist/orchestrator/templates/ai-instructions/copilot-config.md +12 -2
- package/dist/orchestrator/templates/ai-instructions/copilot-skill-figma-source.md +151 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-figma-source.md +151 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +86 -13
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +61 -0
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +105 -28
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +20 -0
- package/dist/orchestrator/templates/specs-base.d.ts +12 -1
- package/dist/orchestrator/templates/specs-base.d.ts.map +1 -1
- package/dist/orchestrator/templates/specs-base.js +47 -5
- package/dist/orchestrator/templates/specs-base.js.map +1 -1
- package/dist/orchestrator/templates/specs-base.ts +65 -7
- package/dist/orchestrator/templates/specs-test-data.d.ts +14 -0
- package/dist/orchestrator/templates/specs-test-data.d.ts.map +1 -0
- package/dist/orchestrator/templates/specs-test-data.js +100 -0
- package/dist/orchestrator/templates/specs-test-data.js.map +1 -0
- package/dist/orchestrator/templates/specs-test-data.ts +66 -0
- package/dist/tools/figma/figma-auth.d.ts +36 -0
- package/dist/tools/figma/figma-auth.d.ts.map +1 -0
- package/dist/tools/figma/figma-auth.js +182 -0
- package/dist/tools/figma/figma-auth.js.map +1 -0
- package/dist/tools/figma/figma-cache.d.ts +45 -0
- package/dist/tools/figma/figma-cache.d.ts.map +1 -0
- package/dist/tools/figma/figma-cache.js +191 -0
- package/dist/tools/figma/figma-cache.js.map +1 -0
- package/dist/tools/figma/figma-client-types.d.ts +112 -0
- package/dist/tools/figma/figma-client-types.d.ts.map +1 -0
- package/dist/tools/figma/figma-client-types.js +7 -0
- package/dist/tools/figma/figma-client-types.js.map +1 -0
- package/dist/tools/figma/figma-errors.d.ts +49 -0
- package/dist/tools/figma/figma-errors.d.ts.map +1 -0
- package/dist/tools/figma/figma-errors.js +105 -0
- package/dist/tools/figma/figma-errors.js.map +1 -0
- package/dist/tools/figma/figma-image-downloader.d.ts +25 -0
- package/dist/tools/figma/figma-image-downloader.d.ts.map +1 -0
- package/dist/tools/figma/figma-image-downloader.js +128 -0
- package/dist/tools/figma/figma-image-downloader.js.map +1 -0
- package/dist/tools/figma/figma-node-filter.d.ts +26 -0
- package/dist/tools/figma/figma-node-filter.d.ts.map +1 -0
- package/dist/tools/figma/figma-node-filter.js +164 -0
- package/dist/tools/figma/figma-node-filter.js.map +1 -0
- package/dist/tools/figma/figma-rest-client.d.ts +24 -0
- package/dist/tools/figma/figma-rest-client.d.ts.map +1 -0
- package/dist/tools/figma/figma-rest-client.js +154 -0
- package/dist/tools/figma/figma-rest-client.js.map +1 -0
- package/dist/tools/figma/figma-url-parser.d.ts +18 -0
- package/dist/tools/figma/figma-url-parser.d.ts.map +1 -0
- package/dist/tools/figma/figma-url-parser.js +51 -0
- package/dist/tools/figma/figma-url-parser.js.map +1 -0
- package/dist/utils/exec-file-no-throw.d.ts +20 -0
- package/dist/utils/exec-file-no-throw.d.ts.map +1 -0
- package/dist/utils/exec-file-no-throw.js +36 -0
- package/dist/utils/exec-file-no-throw.js.map +1 -0
- package/package.json +1 -1
- package/src/cli/commands/add.ts +80 -9
- package/src/cli/commands/figma.ts +162 -0
- package/src/cli/commands/generate.ts +2 -0
- package/src/cli/index.ts +4 -2
- package/src/generators/gherkin-parser/index.ts +4 -0
- package/src/generators/test-generator/adapters/adapter-interface.ts +12 -1
- package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +14 -2
- package/src/generators/test-generator/adapters/playwright/templates/after-all.hbs +8 -0
- package/src/generators/test-generator/adapters/playwright/templates/after-each.hbs +8 -0
- package/src/generators/test-generator/adapters/playwright/templates/before-all.hbs +8 -0
- package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
- package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +24 -0
- package/src/generators/test-generator/code-generator.ts +122 -13
- package/src/generators/test-generator/step-mapper.ts +2 -2
- package/src/generators/test-generator/template-engine.ts +28 -2
- package/src/generators/test-generator/utils/data-resolver.ts +45 -27
- package/src/generators/test-generator/utils/runtime-data-transformer.ts +51 -0
- package/src/generators/types.ts +1 -0
- package/src/orchestrator/ai-rules-updater.ts +2 -0
- package/src/orchestrator/figma/figma-scaffolder-helpers.ts +126 -0
- package/src/orchestrator/figma/figma-scaffolder-types.ts +26 -0
- package/src/orchestrator/figma/figma-scaffolder.ts +209 -0
- package/src/orchestrator/figma/node-path-collapser.ts +38 -0
- package/src/orchestrator/figma/spec-figma-renderer.ts +80 -0
- package/src/orchestrator/figma/spec-figma-section-renderers.ts +46 -0
- package/src/orchestrator/project-initializer.ts +84 -10
- package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +56 -11
- package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +30 -17
- package/src/orchestrator/templates/ai-instructions/claude-cmd-review.md +4 -3
- package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +34 -2
- package/src/orchestrator/templates/ai-instructions/claude-config.md +12 -2
- package/src/orchestrator/templates/ai-instructions/claude-skill-figma-source.md +151 -0
- package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +66 -13
- package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +93 -23
- package/src/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +2 -0
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +53 -9
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +21 -16
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-review.md +4 -3
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +34 -2
- package/src/orchestrator/templates/ai-instructions/copilot-config.md +12 -2
- package/src/orchestrator/templates/ai-instructions/copilot-skill-figma-source.md +151 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-figma-source.md +151 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +86 -13
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +61 -0
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +105 -28
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +20 -0
- package/src/orchestrator/templates/specs-base.ts +65 -7
- package/src/orchestrator/templates/specs-test-data.ts +66 -0
- package/src/tools/figma/figma-auth.ts +161 -0
- package/src/tools/figma/figma-cache.ts +184 -0
- package/src/tools/figma/figma-client-types.ts +125 -0
- package/src/tools/figma/figma-errors.ts +127 -0
- package/src/tools/figma/figma-image-downloader.ts +112 -0
- package/src/tools/figma/figma-node-filter.ts +198 -0
- package/src/tools/figma/figma-rest-client.ts +183 -0
- package/src/tools/figma/figma-url-parser.ts +55 -0
- package/src/utils/exec-file-no-throw.ts +45 -0
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sungen-figma-source
|
|
3
|
+
description: 'Figma URL → spec_figma.md envelope + LLM-synthesized narrative from cached raw node JSON. Auto-loaded when --figma flag present or spec_figma.md exists.'
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## When This Skill Loads
|
|
8
|
+
|
|
9
|
+
Auto-load triggers (any one is sufficient):
|
|
10
|
+
|
|
11
|
+
- Any sungen AI command invoked with `--figma` flag
|
|
12
|
+
- `requirements/spec_figma.md` exists in the screen directory
|
|
13
|
+
- User mentions a Figma URL or says "generate from Figma"
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
- [ ] `sungen figma auth check` succeeds — PAT is stored and valid
|
|
20
|
+
- [ ] Figma file URL is available (shared file or frame link)
|
|
21
|
+
- [ ] If auth missing → run `sungen figma auth set` and follow the walkthrough
|
|
22
|
+
|
|
23
|
+
**Never paste the PAT into any transcript, spec file, or commit.**
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Two-Layer Architecture
|
|
28
|
+
|
|
29
|
+
`spec_figma.md` has two layers separated by the `<!-- SYNTHESIS-BELOW -->` marker:
|
|
30
|
+
|
|
31
|
+
| Layer | Producer | Overwrite Rule |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| **Envelope** (above marker) | sungen CLI | Regenerated each `sungen figma` run — deterministic |
|
|
34
|
+
| **Narrative** (below marker) | This skill (LLM) | Replaced on re-synthesis — everything from marker to EOF |
|
|
35
|
+
|
|
36
|
+
The envelope contains: YAML frontmatter, Frame metadata, Screenshots. The narrative is synthesized by YOU from the cached raw Figma node JSON.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Inputs You Read
|
|
41
|
+
|
|
42
|
+
The scaffolder persists a raw (unfiltered) Figma node tree to:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
.sungen/figma-cache/<fileKey>/<versionId>/<nodeId>-raw.json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Read this file + the envelope frontmatter of `requirements/spec_figma.md` + any PNGs under `requirements/ui/`. You MUST NOT call the Figma REST API directly — the PAT is not available to you.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Synthesis Task
|
|
53
|
+
|
|
54
|
+
Append 7 narrative sections below `<!-- SYNTHESIS-BELOW -->`. Each section is inferred from the raw node tree (names, types, `characters`, layout bounds, auto-layout direction, componentProperties):
|
|
55
|
+
|
|
56
|
+
### 1. Purpose
|
|
57
|
+
One paragraph. What screen is this? Primary user goal? Infer from frame name + top-level text + dominant CTA.
|
|
58
|
+
|
|
59
|
+
### 2. ASCII Layout
|
|
60
|
+
Rough spatial sketch using box characters. Reflect top-bottom / left-right ordering from absoluteBoundingBox. Keep under ~20 lines. Example:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
┌──────────────────────────────────────┐
|
|
64
|
+
│ [Logo] [Sign In] │
|
|
65
|
+
├──────────────────────────────────────┤
|
|
66
|
+
│ Welcome back │
|
|
67
|
+
│ ┌────────────────────────────────┐ │
|
|
68
|
+
│ │ email@example.com │ │
|
|
69
|
+
│ └────────────────────────────────┘ │
|
|
70
|
+
│ [ Continue ] │
|
|
71
|
+
└──────────────────────────────────────┘
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Regions
|
|
75
|
+
Bulleted list of the major layout regions (header, sidebar, main, footer, modal, etc.) with a one-line purpose each. Use auto-layout frames as region hints.
|
|
76
|
+
|
|
77
|
+
### 4. Actions
|
|
78
|
+
Every interactive element the user can trigger. Derive from nodes whose name/type suggests a button, link, icon-button, menu-item, toggle, etc. Format:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
- **<Action name>** — <what it does> (source: <node name>)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 5. Form Fields
|
|
85
|
+
Every input the user can fill. Include label, type (text/email/password/select/checkbox/radio/textarea/date), required hint if inferable, and placeholder.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
| Label | Type | Required | Placeholder |
|
|
89
|
+
|---|---|---|---|
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Omit entirely (write `_none_`) if no inputs exist.
|
|
93
|
+
|
|
94
|
+
### 6. Data Columns
|
|
95
|
+
If the screen shows a table, list, or card grid — enumerate the columns/fields displayed per row. Otherwise write `_none_`.
|
|
96
|
+
|
|
97
|
+
### 7. Navigation
|
|
98
|
+
Outgoing links, tab bars, breadcrumbs, back buttons — anything that moves the user to another screen. Include both explicit navigation components and implicit CTAs that navigate.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Synthesis Workflow
|
|
103
|
+
|
|
104
|
+
1. Read `requirements/spec_figma.md` — note `file_key`, `node_id`, `figma_version_id` from frontmatter
|
|
105
|
+
2. Read `.sungen/figma-cache/<file_key>/<figma_version_id>/<safe_node_id>-raw.json` (colons in node_id become underscores)
|
|
106
|
+
3. Traverse the tree. Collect: names, types, `characters`, `componentProperties`, `absoluteBoundingBox`
|
|
107
|
+
4. Produce the 7 sections above
|
|
108
|
+
5. **Locate the insertion point** in `spec_figma.md`:
|
|
109
|
+
- **If `<!-- SYNTHESIS-BELOW -->` is present** → replace everything from the marker (inclusive) to EOF with: the marker line, a blank line, then the 7 sections.
|
|
110
|
+
- **If the marker is NOT present** (older `spec_figma.md` pre-envelope-refactor, or hand-edited file) → locate the last non-empty line of the envelope (usually the end of `## Screenshots`), append a blank line, then write the marker, another blank line, then the 7 sections. Do NOT delete any existing envelope content.
|
|
111
|
+
- **If the file is missing entirely** → advise the user to re-run `sungen add --screen <screen> --figma <url> --refresh` to regenerate the envelope first. Do not fabricate one.
|
|
112
|
+
6. Preserve the envelope (frontmatter + Frame + Screenshots) byte-for-byte. Never touch content above the marker.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Re-synthesis
|
|
117
|
+
|
|
118
|
+
- If the envelope's `figma_version_id` changed → envelope is fresh; re-run synthesis
|
|
119
|
+
- If only the narrative is stale (user wants a rewrite) → truncate from marker to EOF and regenerate
|
|
120
|
+
- Never edit content ABOVE the marker — that is the scaffolder's territory
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Selector Heuristics (for downstream `run-test`)
|
|
125
|
+
|
|
126
|
+
During `run-test` Phase 0, provisional selectors can be seeded from the raw JSON:
|
|
127
|
+
|
|
128
|
+
| Figma Signal | Provisional YAML Entry |
|
|
129
|
+
|---|---|
|
|
130
|
+
| Node name ends `Button`, has text | `role: button` + `name: "<text>"` |
|
|
131
|
+
| Node name ends `Input`/`Field` | `placeholder: "<placeholder text>"` |
|
|
132
|
+
| Node name ends `Link`, has text | `role: link` + `name: "<text>"` |
|
|
133
|
+
| componentProperties has `data-testid` | `testid: <value>` |
|
|
134
|
+
| Plain text leaf (outside interactive) | `text: "<content>"` |
|
|
135
|
+
| Node name ends `Icon` | `role: img` + `name: "<accessible name>"` |
|
|
136
|
+
|
|
137
|
+
Every provisional entry MUST carry:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
# @needs-live-verify source=figma node_id=<id>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Provisional selectors feed `selectors.yaml` as candidates. `run-test` Phase 0 verifies them against the live page and overwrites incorrect entries.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Security
|
|
148
|
+
|
|
149
|
+
- Never include the PAT in `spec_figma.md`, selectors, test data, or any committed file
|
|
150
|
+
- Never log or echo the PAT in terminal output
|
|
151
|
+
- Read only from `.sungen/figma-cache/` and screen directories — never from `.env`
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sungen-figma-source
|
|
3
|
+
description: 'Figma URL → spec_figma.md envelope + LLM-synthesized narrative from cached raw node JSON. Auto-loaded when --figma flag present or spec_figma.md exists.'
|
|
4
|
+
user-invocable: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## When This Skill Loads
|
|
8
|
+
|
|
9
|
+
Auto-load triggers (any one is sufficient):
|
|
10
|
+
|
|
11
|
+
- Any sungen AI command invoked with `--figma` flag
|
|
12
|
+
- `requirements/spec_figma.md` exists in the screen directory
|
|
13
|
+
- User mentions a Figma URL or says "generate from Figma"
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
- [ ] `sungen figma auth check` succeeds — PAT is stored and valid
|
|
20
|
+
- [ ] Figma file URL is available (shared file or frame link)
|
|
21
|
+
- [ ] If auth missing → run `sungen figma auth set` and follow the walkthrough
|
|
22
|
+
|
|
23
|
+
**Never paste the PAT into any transcript, spec file, or commit.**
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Two-Layer Architecture
|
|
28
|
+
|
|
29
|
+
`spec_figma.md` has two layers separated by the `<!-- SYNTHESIS-BELOW -->` marker:
|
|
30
|
+
|
|
31
|
+
| Layer | Producer | Overwrite Rule |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| **Envelope** (above marker) | sungen CLI | Regenerated each `sungen figma` run — deterministic |
|
|
34
|
+
| **Narrative** (below marker) | This skill (LLM) | Replaced on re-synthesis — everything from marker to EOF |
|
|
35
|
+
|
|
36
|
+
The envelope contains: YAML frontmatter, Frame metadata, Screenshots. The narrative is synthesized by YOU from the cached raw Figma node JSON.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Inputs You Read
|
|
41
|
+
|
|
42
|
+
The scaffolder persists a raw (unfiltered) Figma node tree to:
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
.sungen/figma-cache/<fileKey>/<versionId>/<nodeId>-raw.json
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Read this file + the envelope frontmatter of `requirements/spec_figma.md` + any PNGs under `requirements/ui/`. You MUST NOT call the Figma REST API directly — the PAT is not available to you.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Synthesis Task
|
|
53
|
+
|
|
54
|
+
Append 7 narrative sections below `<!-- SYNTHESIS-BELOW -->`. Each section is inferred from the raw node tree (names, types, `characters`, layout bounds, auto-layout direction, componentProperties):
|
|
55
|
+
|
|
56
|
+
### 1. Purpose
|
|
57
|
+
One paragraph. What screen is this? Primary user goal? Infer from frame name + top-level text + dominant CTA.
|
|
58
|
+
|
|
59
|
+
### 2. ASCII Layout
|
|
60
|
+
Rough spatial sketch using box characters. Reflect top-bottom / left-right ordering from absoluteBoundingBox. Keep under ~20 lines. Example:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
┌──────────────────────────────────────┐
|
|
64
|
+
│ [Logo] [Sign In] │
|
|
65
|
+
├──────────────────────────────────────┤
|
|
66
|
+
│ Welcome back │
|
|
67
|
+
│ ┌────────────────────────────────┐ │
|
|
68
|
+
│ │ email@example.com │ │
|
|
69
|
+
│ └────────────────────────────────┘ │
|
|
70
|
+
│ [ Continue ] │
|
|
71
|
+
└──────────────────────────────────────┘
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 3. Regions
|
|
75
|
+
Bulleted list of the major layout regions (header, sidebar, main, footer, modal, etc.) with a one-line purpose each. Use auto-layout frames as region hints.
|
|
76
|
+
|
|
77
|
+
### 4. Actions
|
|
78
|
+
Every interactive element the user can trigger. Derive from nodes whose name/type suggests a button, link, icon-button, menu-item, toggle, etc. Format:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
- **<Action name>** — <what it does> (source: <node name>)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 5. Form Fields
|
|
85
|
+
Every input the user can fill. Include label, type (text/email/password/select/checkbox/radio/textarea/date), required hint if inferable, and placeholder.
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
| Label | Type | Required | Placeholder |
|
|
89
|
+
|---|---|---|---|
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Omit entirely (write `_none_`) if no inputs exist.
|
|
93
|
+
|
|
94
|
+
### 6. Data Columns
|
|
95
|
+
If the screen shows a table, list, or card grid — enumerate the columns/fields displayed per row. Otherwise write `_none_`.
|
|
96
|
+
|
|
97
|
+
### 7. Navigation
|
|
98
|
+
Outgoing links, tab bars, breadcrumbs, back buttons — anything that moves the user to another screen. Include both explicit navigation components and implicit CTAs that navigate.
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Synthesis Workflow
|
|
103
|
+
|
|
104
|
+
1. Read `requirements/spec_figma.md` — note `file_key`, `node_id`, `figma_version_id` from frontmatter
|
|
105
|
+
2. Read `.sungen/figma-cache/<file_key>/<figma_version_id>/<safe_node_id>-raw.json` (colons in node_id become underscores)
|
|
106
|
+
3. Traverse the tree. Collect: names, types, `characters`, `componentProperties`, `absoluteBoundingBox`
|
|
107
|
+
4. Produce the 7 sections above
|
|
108
|
+
5. **Locate the insertion point** in `spec_figma.md`:
|
|
109
|
+
- **If `<!-- SYNTHESIS-BELOW -->` is present** → replace everything from the marker (inclusive) to EOF with: the marker line, a blank line, then the 7 sections.
|
|
110
|
+
- **If the marker is NOT present** (older `spec_figma.md` pre-envelope-refactor, or hand-edited file) → locate the last non-empty line of the envelope (usually the end of `## Screenshots`), append a blank line, then write the marker, another blank line, then the 7 sections. Do NOT delete any existing envelope content.
|
|
111
|
+
- **If the file is missing entirely** → advise the user to re-run `sungen add --screen <screen> --figma <url> --refresh` to regenerate the envelope first. Do not fabricate one.
|
|
112
|
+
6. Preserve the envelope (frontmatter + Frame + Screenshots) byte-for-byte. Never touch content above the marker.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Re-synthesis
|
|
117
|
+
|
|
118
|
+
- If the envelope's `figma_version_id` changed → envelope is fresh; re-run synthesis
|
|
119
|
+
- If only the narrative is stale (user wants a rewrite) → truncate from marker to EOF and regenerate
|
|
120
|
+
- Never edit content ABOVE the marker — that is the scaffolder's territory
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Selector Heuristics (for downstream `run-test`)
|
|
125
|
+
|
|
126
|
+
During `run-test` Phase 0, provisional selectors can be seeded from the raw JSON:
|
|
127
|
+
|
|
128
|
+
| Figma Signal | Provisional YAML Entry |
|
|
129
|
+
|---|---|
|
|
130
|
+
| Node name ends `Button`, has text | `role: button` + `name: "<text>"` |
|
|
131
|
+
| Node name ends `Input`/`Field` | `placeholder: "<placeholder text>"` |
|
|
132
|
+
| Node name ends `Link`, has text | `role: link` + `name: "<text>"` |
|
|
133
|
+
| componentProperties has `data-testid` | `testid: <value>` |
|
|
134
|
+
| Plain text leaf (outside interactive) | `text: "<content>"` |
|
|
135
|
+
| Node name ends `Icon` | `role: img` + `name: "<accessible name>"` |
|
|
136
|
+
|
|
137
|
+
Every provisional entry MUST carry:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
# @needs-live-verify source=figma node_id=<id>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Provisional selectors feed `selectors.yaml` as candidates. `run-test` Phase 0 verifies them against the live page and overwrites incorrect entries.
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Security
|
|
148
|
+
|
|
149
|
+
- Never include the PAT in `spec_figma.md`, selectors, test data, or any committed file
|
|
150
|
+
- Never log or echo the PAT in terminal output
|
|
151
|
+
- Read only from `.sungen/figma-cache/` and screen directories — never from `.env`
|
|
@@ -151,6 +151,14 @@ Options: `nth` `exact` `scope` `match` `variant` `frame` `contenteditable` `colu
|
|
|
151
151
|
| `@no-auth` | Disable inherited auth |
|
|
152
152
|
| `@steps:name` | Define reusable step block (base scenario) |
|
|
153
153
|
| `@extend:name` | Prepend Given→When from @steps block (skip Then) |
|
|
154
|
+
| `@cleanup:overlay` | Auto-cleanup: dismiss dialogs/overlays after each test (base.ts fixture) |
|
|
155
|
+
| `@cleanup:forms` | Auto-cleanup: clear form fields after each test (base.ts fixture) |
|
|
156
|
+
| `@cleanup:scroll` | Auto-cleanup: scroll to top after each test (base.ts fixture) |
|
|
157
|
+
| `@cleanup:storage` | Auto-cleanup: clear sessionStorage after each test (base.ts fixture) |
|
|
158
|
+
| `@screenshot:on-failure` | Auto-capture screenshot when test fails (base.ts fixture) |
|
|
159
|
+
| `@beforeAll` | Hook: runs once before all tests → `test.beforeAll()` |
|
|
160
|
+
| `@afterEach` | Hook: runs after each test → `test.afterEach()` (custom cleanup) |
|
|
161
|
+
| `@afterAll` | Hook: runs once after all tests → `test.afterAll()` |
|
|
154
162
|
|
|
155
163
|
### @extend behavior
|
|
156
164
|
|
|
@@ -175,30 +183,28 @@ Options: `nth` `exact` `scope` `match` `variant` `frame` `contenteditable` `colu
|
|
|
175
183
|
| Missing `is` for state | `with {{text}} hidden` | `with {{text}} is hidden` |
|
|
176
184
|
| State as value | `with {{disabled}}` | `is disabled` |
|
|
177
185
|
| Missing target type | `fill [email] with {{v}}` | `fill [email] field with {{v}}` |
|
|
178
|
-
|
|
|
186
|
+
| Background with scope | `Background: ... And User is on [X] dialog` | Use `@steps` + `@extend` for scope-dependent flows |
|
|
179
187
|
| `is on` after When | `When ... And User is on [X] dialog` | `And User see [X] dialog` or separate Given |
|
|
180
188
|
|
|
181
189
|
## Background vs @steps/@extend
|
|
182
190
|
|
|
183
|
-
|
|
191
|
+
Both `Background` and `@steps`/`@extend` are valid — they serve different purposes.
|
|
184
192
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
193
|
+
| Pattern | Use when | Generates |
|
|
194
|
+
|---|---|---|
|
|
195
|
+
| `Background` | Simple shared setup (navigate to page) | `test.beforeEach()` |
|
|
196
|
+
| `@steps`/`@extend` | Complex reusable flows with scope (dialog, frame) | Inline merged steps in `test()` |
|
|
189
197
|
|
|
190
|
-
**
|
|
198
|
+
**Use `Background` for simple navigation:**
|
|
191
199
|
```gherkin
|
|
192
200
|
Background:
|
|
193
|
-
Given User is on [
|
|
194
|
-
When User click [Open] button
|
|
195
|
-
And User is on [Modal] dialog ← keyword mismatch
|
|
201
|
+
Given User is on [Dashboard] page
|
|
196
202
|
|
|
197
|
-
Scenario:
|
|
198
|
-
Then User see [
|
|
203
|
+
Scenario: View stats
|
|
204
|
+
Then User see [Revenue Chart] section
|
|
199
205
|
```
|
|
200
206
|
|
|
201
|
-
**
|
|
207
|
+
**Use `@steps`/`@extend` when scope matters (dialog, frame):**
|
|
202
208
|
```gherkin
|
|
203
209
|
@steps:open_modal
|
|
204
210
|
Scenario: Open modal
|
|
@@ -211,3 +217,70 @@ Scenario: VP-UI-001 Title visible
|
|
|
211
217
|
Given User is on [Modal] dialog
|
|
212
218
|
Then User see [Title] heading
|
|
213
219
|
```
|
|
220
|
+
|
|
221
|
+
**Avoid `Background` with scope-dependent steps** — `When` + `And User is on [X] dialog` creates keyword mismatch (`is on` = Given, not When). Use `@steps`/`@extend` instead.
|
|
222
|
+
|
|
223
|
+
## Hooks & Cleanup
|
|
224
|
+
|
|
225
|
+
Two layers for test lifecycle management. Prefer `@cleanup:*` tags (Layer 1) — they work with base.ts automatically. Use hook scenarios (Layer 2) only for custom logic.
|
|
226
|
+
|
|
227
|
+
### Layer 1: `@cleanup:*` tags (automatic via base.ts)
|
|
228
|
+
|
|
229
|
+
Feature-level tags that activate cleanup fixtures in base.ts. No Gherkin steps needed.
|
|
230
|
+
|
|
231
|
+
```gherkin
|
|
232
|
+
@auth:admin
|
|
233
|
+
@cleanup:overlay
|
|
234
|
+
@cleanup:forms
|
|
235
|
+
Feature: User Management
|
|
236
|
+
Path: /users
|
|
237
|
+
|
|
238
|
+
Background:
|
|
239
|
+
Given User is on [User Management] page
|
|
240
|
+
|
|
241
|
+
Scenario: Create user shows form
|
|
242
|
+
When User click [Add User] button
|
|
243
|
+
Then User see [Create User] dialog
|
|
244
|
+
# After test: overlay auto-dismissed, forms auto-cleared by base.ts
|
|
245
|
+
|
|
246
|
+
Scenario: Search user by name
|
|
247
|
+
When User fill [Search] field with {{search_name}}
|
|
248
|
+
Then User see [User Row] row
|
|
249
|
+
# After test: search field auto-cleared by base.ts
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
| Tag | What base.ts does after each test |
|
|
253
|
+
|---|---|
|
|
254
|
+
| `@cleanup:overlay` | Press Escape, click body, dismiss fixed overlays |
|
|
255
|
+
| `@cleanup:forms` | Clear all input/textarea fields, reset selects |
|
|
256
|
+
| `@cleanup:scroll` | Scroll to top of page |
|
|
257
|
+
| `@cleanup:storage` | Clear sessionStorage |
|
|
258
|
+
|
|
259
|
+
### Layer 2: `@afterEach` scenario (custom cleanup)
|
|
260
|
+
|
|
261
|
+
Only when `@cleanup:*` tags aren't enough — feature-specific logic.
|
|
262
|
+
|
|
263
|
+
```gherkin
|
|
264
|
+
@auth:admin
|
|
265
|
+
@cleanup:overlay
|
|
266
|
+
Feature: Dashboard
|
|
267
|
+
Path: /dashboard
|
|
268
|
+
|
|
269
|
+
Background:
|
|
270
|
+
Given User is on [Dashboard] page
|
|
271
|
+
|
|
272
|
+
@afterEach
|
|
273
|
+
Scenario: Reset dashboard filters
|
|
274
|
+
When User select [Date Filter] dropdown with {{default_period}}
|
|
275
|
+
|
|
276
|
+
Scenario: Filter by last week
|
|
277
|
+
When User select [Date Filter] dropdown with {{last_week}}
|
|
278
|
+
Then User see [Revenue Chart] section
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### Layer 3: `@beforeAll` / `@afterAll` (optional)
|
|
282
|
+
|
|
283
|
+
For one-time setup/teardown. Low priority — most e2e tests don't need these.
|
|
284
|
+
|
|
285
|
+
**Rendering order in `.spec.ts`:**
|
|
286
|
+
`test.describe` → `test.use(storageState)` → `test.use(autoCleanup)` → `test.beforeAll` → `test.beforeEach` → `test.afterEach` → `test.afterAll` → `test()` blocks
|
|
@@ -52,6 +52,67 @@ If existing selectors already cover the feature file, **skip Phase 0** and go st
|
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
55
|
+
## Phase 0 (Provisional): Figma-Only Selector Generation (no live page)
|
|
56
|
+
|
|
57
|
+
**Trigger**: Phase 0 decision tree (in `run-test` command) determined the live page is not reachable AND `requirements/spec_figma.md` exists.
|
|
58
|
+
|
|
59
|
+
**Goal**: produce a compilable `selectors.yaml` seeded from Figma node data so that `sungen generate` succeeds and the test suite can run. Every entry is provisional — it must be verified against a real DOM when the page becomes available.
|
|
60
|
+
|
|
61
|
+
### Inputs
|
|
62
|
+
|
|
63
|
+
- `requirements/spec_figma.md` — specifically:
|
|
64
|
+
- `## Components` table (Name, Type, Role, Text, Variants columns)
|
|
65
|
+
- `## Text Inventory` list (node_id → label text pairs)
|
|
66
|
+
|
|
67
|
+
### Steps
|
|
68
|
+
|
|
69
|
+
1. **Parse references**: collect every `[Reference]` element from the `.feature` file (same as live Phase 0 step 2).
|
|
70
|
+
2. **Match to Figma nodes**: for each `[Reference]`, find the best matching entry in `spec_figma.md` by comparing the reference name against component names and text labels (case-insensitive, partial match allowed).
|
|
71
|
+
3. **Apply heuristic priority** (same order as live Phase 0 — use first applicable):
|
|
72
|
+
|
|
73
|
+
| Priority | Type | Figma Signal |
|
|
74
|
+
|---|---|---|
|
|
75
|
+
| 1 | `testid` | Dev annotation `data-testid=X` in component metadata |
|
|
76
|
+
| 2 | `role` + name | Component type is Button/Link + has text label |
|
|
77
|
+
| 3 | `placeholder` | Component type is Input/Field + has placeholder text |
|
|
78
|
+
| 4 | `label` | Component has associated label text (not placeholder) |
|
|
79
|
+
| 5 | `locator` (CSS) | No accessible name derivable from Figma data |
|
|
80
|
+
| 6 | `text` | Plain text node (not inside interactive component) |
|
|
81
|
+
|
|
82
|
+
See `sungen-figma-source` skill for the authoritative heuristics table mapping Figma signals to YAML entry types.
|
|
83
|
+
|
|
84
|
+
4. **Write entries**: add each entry to `selectors.yaml`, prefixed with the required comment:
|
|
85
|
+
```yaml
|
|
86
|
+
# @needs-live-verify source=figma node_id=<figma-node-id>
|
|
87
|
+
submit-button:
|
|
88
|
+
type: role
|
|
89
|
+
value: button
|
|
90
|
+
name: "Submit"
|
|
91
|
+
```
|
|
92
|
+
- Key naming follows `sungen-selector-keys` conventions (lowercase, Unicode preserved, `--type` / `--N` suffixes).
|
|
93
|
+
- Copy text character-for-character from `## Text Inventory`. Never infer from the Gherkin label.
|
|
94
|
+
- Merge, don't overwrite — preserve the page selector and any user-authored entries.
|
|
95
|
+
|
|
96
|
+
5. **Compile**: `sungen generate --screen <screen>` — must succeed before Phase 1.
|
|
97
|
+
|
|
98
|
+
### Auto-fix on live page (subsequent run-test invocations)
|
|
99
|
+
|
|
100
|
+
When `run-test` is called again and the live page is now reachable:
|
|
101
|
+
- Phase 0 takes ONE `browser_snapshot`.
|
|
102
|
+
- For each entry tagged `# @needs-live-verify` in `selectors.yaml`:
|
|
103
|
+
- Compare the provisional selector against the actual DOM element found in the snapshot.
|
|
104
|
+
- If match → remove the comment line (entry promoted to verified).
|
|
105
|
+
- If mismatch → replace the YAML value with the snapshot-derived selector, then remove the comment (entry corrected and verified).
|
|
106
|
+
- Entries with no corresponding DOM element → log as unresolved, leave comment in place for manual inspection.
|
|
107
|
+
|
|
108
|
+
### Pitfalls
|
|
109
|
+
|
|
110
|
+
- Inferring selector names from Gherkin labels instead of Figma `## Text Inventory` → mismatch on live verification.
|
|
111
|
+
- Omitting `# @needs-live-verify` comment → reviewer has no way to count unverified selectors.
|
|
112
|
+
- Overwriting user-authored selectors during merge → always check for existing keys before adding.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
55
116
|
## Phase 0.5: Auth Persistence (MCP alternative to `sungen makeauth`)
|
|
56
117
|
|
|
57
118
|
Capture an authenticated session from the MCP browser into `specs/.auth/<role>.json` — the same path `sungen makeauth` writes to, which compiled tests already reference via `test.use({ storageState })` based on `@auth:<role>` tags. No `playwright.config.ts` edits needed. Run once per auth lifetime, not on every selector fix.
|