@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.
Files changed (206) hide show
  1. package/README.md +88 -7
  2. package/dist/cli/commands/add.d.ts.map +1 -1
  3. package/dist/cli/commands/add.js +109 -9
  4. package/dist/cli/commands/add.js.map +1 -1
  5. package/dist/cli/commands/figma.d.ts +11 -0
  6. package/dist/cli/commands/figma.d.ts.map +1 -0
  7. package/dist/cli/commands/figma.js +178 -0
  8. package/dist/cli/commands/figma.js.map +1 -0
  9. package/dist/cli/commands/generate.d.ts.map +1 -1
  10. package/dist/cli/commands/generate.js +2 -0
  11. package/dist/cli/commands/generate.js.map +1 -1
  12. package/dist/cli/index.js +4 -2
  13. package/dist/cli/index.js.map +1 -1
  14. package/dist/generators/gherkin-parser/index.d.ts +1 -0
  15. package/dist/generators/gherkin-parser/index.d.ts.map +1 -1
  16. package/dist/generators/gherkin-parser/index.js +3 -0
  17. package/dist/generators/gherkin-parser/index.js.map +1 -1
  18. package/dist/generators/test-generator/adapters/adapter-interface.d.ts +29 -1
  19. package/dist/generators/test-generator/adapters/adapter-interface.d.ts.map +1 -1
  20. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts +21 -1
  21. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.d.ts.map +1 -1
  22. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js +11 -2
  23. package/dist/generators/test-generator/adapters/playwright/playwright-adapter.js.map +1 -1
  24. package/dist/generators/test-generator/adapters/playwright/templates/after-all.hbs +8 -0
  25. package/dist/generators/test-generator/adapters/playwright/templates/after-each.hbs +8 -0
  26. package/dist/generators/test-generator/adapters/playwright/templates/before-all.hbs +8 -0
  27. package/dist/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  28. package/dist/generators/test-generator/adapters/playwright/templates/test-file.hbs +24 -0
  29. package/dist/generators/test-generator/code-generator.d.ts +2 -0
  30. package/dist/generators/test-generator/code-generator.d.ts.map +1 -1
  31. package/dist/generators/test-generator/code-generator.js +109 -12
  32. package/dist/generators/test-generator/code-generator.js.map +1 -1
  33. package/dist/generators/test-generator/step-mapper.d.ts +1 -0
  34. package/dist/generators/test-generator/step-mapper.d.ts.map +1 -1
  35. package/dist/generators/test-generator/step-mapper.js +1 -1
  36. package/dist/generators/test-generator/step-mapper.js.map +1 -1
  37. package/dist/generators/test-generator/template-engine.d.ts +29 -1
  38. package/dist/generators/test-generator/template-engine.d.ts.map +1 -1
  39. package/dist/generators/test-generator/template-engine.js +11 -2
  40. package/dist/generators/test-generator/template-engine.js.map +1 -1
  41. package/dist/generators/test-generator/utils/data-resolver.d.ts +11 -2
  42. package/dist/generators/test-generator/utils/data-resolver.d.ts.map +1 -1
  43. package/dist/generators/test-generator/utils/data-resolver.js +36 -25
  44. package/dist/generators/test-generator/utils/data-resolver.js.map +1 -1
  45. package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts +7 -0
  46. package/dist/generators/test-generator/utils/runtime-data-transformer.d.ts.map +1 -0
  47. package/dist/generators/test-generator/utils/runtime-data-transformer.js +42 -0
  48. package/dist/generators/test-generator/utils/runtime-data-transformer.js.map +1 -0
  49. package/dist/generators/types.d.ts +1 -0
  50. package/dist/generators/types.d.ts.map +1 -1
  51. package/dist/generators/types.js.map +1 -1
  52. package/dist/orchestrator/ai-rules-updater.d.ts.map +1 -1
  53. package/dist/orchestrator/ai-rules-updater.js +2 -0
  54. package/dist/orchestrator/ai-rules-updater.js.map +1 -1
  55. package/dist/orchestrator/figma/figma-scaffolder-helpers.d.ts +33 -0
  56. package/dist/orchestrator/figma/figma-scaffolder-helpers.d.ts.map +1 -0
  57. package/dist/orchestrator/figma/figma-scaffolder-helpers.js +135 -0
  58. package/dist/orchestrator/figma/figma-scaffolder-helpers.js.map +1 -0
  59. package/dist/orchestrator/figma/figma-scaffolder-types.d.ts +25 -0
  60. package/dist/orchestrator/figma/figma-scaffolder-types.d.ts.map +1 -0
  61. package/dist/orchestrator/figma/figma-scaffolder-types.js +7 -0
  62. package/dist/orchestrator/figma/figma-scaffolder-types.js.map +1 -0
  63. package/dist/orchestrator/figma/figma-scaffolder.d.ts +23 -0
  64. package/dist/orchestrator/figma/figma-scaffolder.d.ts.map +1 -0
  65. package/dist/orchestrator/figma/figma-scaffolder.js +212 -0
  66. package/dist/orchestrator/figma/figma-scaffolder.js.map +1 -0
  67. package/dist/orchestrator/figma/node-path-collapser.d.ts +16 -0
  68. package/dist/orchestrator/figma/node-path-collapser.d.ts.map +1 -0
  69. package/dist/orchestrator/figma/node-path-collapser.js +37 -0
  70. package/dist/orchestrator/figma/node-path-collapser.js.map +1 -0
  71. package/dist/orchestrator/figma/spec-figma-renderer.d.ts +44 -0
  72. package/dist/orchestrator/figma/spec-figma-renderer.d.ts.map +1 -0
  73. package/dist/orchestrator/figma/spec-figma-renderer.js +45 -0
  74. package/dist/orchestrator/figma/spec-figma-renderer.js.map +1 -0
  75. package/dist/orchestrator/figma/spec-figma-section-renderers.d.ts +23 -0
  76. package/dist/orchestrator/figma/spec-figma-section-renderers.d.ts.map +1 -0
  77. package/dist/orchestrator/figma/spec-figma-section-renderers.js +47 -0
  78. package/dist/orchestrator/figma/spec-figma-section-renderers.js.map +1 -0
  79. package/dist/orchestrator/project-initializer.d.ts +9 -0
  80. package/dist/orchestrator/project-initializer.d.ts.map +1 -1
  81. package/dist/orchestrator/project-initializer.js +74 -10
  82. package/dist/orchestrator/project-initializer.js.map +1 -1
  83. package/dist/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +56 -11
  84. package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +30 -17
  85. package/dist/orchestrator/templates/ai-instructions/claude-cmd-review.md +4 -3
  86. package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +34 -2
  87. package/dist/orchestrator/templates/ai-instructions/claude-config.md +12 -2
  88. package/dist/orchestrator/templates/ai-instructions/claude-skill-figma-source.md +151 -0
  89. package/dist/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +66 -13
  90. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +93 -23
  91. package/dist/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +2 -0
  92. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +53 -9
  93. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +21 -16
  94. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-review.md +4 -3
  95. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +34 -2
  96. package/dist/orchestrator/templates/ai-instructions/copilot-config.md +12 -2
  97. package/dist/orchestrator/templates/ai-instructions/copilot-skill-figma-source.md +151 -0
  98. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-figma-source.md +151 -0
  99. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +86 -13
  100. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +61 -0
  101. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +105 -28
  102. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +20 -0
  103. package/dist/orchestrator/templates/specs-base.d.ts +12 -1
  104. package/dist/orchestrator/templates/specs-base.d.ts.map +1 -1
  105. package/dist/orchestrator/templates/specs-base.js +47 -5
  106. package/dist/orchestrator/templates/specs-base.js.map +1 -1
  107. package/dist/orchestrator/templates/specs-base.ts +65 -7
  108. package/dist/orchestrator/templates/specs-test-data.d.ts +14 -0
  109. package/dist/orchestrator/templates/specs-test-data.d.ts.map +1 -0
  110. package/dist/orchestrator/templates/specs-test-data.js +100 -0
  111. package/dist/orchestrator/templates/specs-test-data.js.map +1 -0
  112. package/dist/orchestrator/templates/specs-test-data.ts +66 -0
  113. package/dist/tools/figma/figma-auth.d.ts +36 -0
  114. package/dist/tools/figma/figma-auth.d.ts.map +1 -0
  115. package/dist/tools/figma/figma-auth.js +182 -0
  116. package/dist/tools/figma/figma-auth.js.map +1 -0
  117. package/dist/tools/figma/figma-cache.d.ts +45 -0
  118. package/dist/tools/figma/figma-cache.d.ts.map +1 -0
  119. package/dist/tools/figma/figma-cache.js +191 -0
  120. package/dist/tools/figma/figma-cache.js.map +1 -0
  121. package/dist/tools/figma/figma-client-types.d.ts +112 -0
  122. package/dist/tools/figma/figma-client-types.d.ts.map +1 -0
  123. package/dist/tools/figma/figma-client-types.js +7 -0
  124. package/dist/tools/figma/figma-client-types.js.map +1 -0
  125. package/dist/tools/figma/figma-errors.d.ts +49 -0
  126. package/dist/tools/figma/figma-errors.d.ts.map +1 -0
  127. package/dist/tools/figma/figma-errors.js +105 -0
  128. package/dist/tools/figma/figma-errors.js.map +1 -0
  129. package/dist/tools/figma/figma-image-downloader.d.ts +25 -0
  130. package/dist/tools/figma/figma-image-downloader.d.ts.map +1 -0
  131. package/dist/tools/figma/figma-image-downloader.js +128 -0
  132. package/dist/tools/figma/figma-image-downloader.js.map +1 -0
  133. package/dist/tools/figma/figma-node-filter.d.ts +26 -0
  134. package/dist/tools/figma/figma-node-filter.d.ts.map +1 -0
  135. package/dist/tools/figma/figma-node-filter.js +164 -0
  136. package/dist/tools/figma/figma-node-filter.js.map +1 -0
  137. package/dist/tools/figma/figma-rest-client.d.ts +24 -0
  138. package/dist/tools/figma/figma-rest-client.d.ts.map +1 -0
  139. package/dist/tools/figma/figma-rest-client.js +154 -0
  140. package/dist/tools/figma/figma-rest-client.js.map +1 -0
  141. package/dist/tools/figma/figma-url-parser.d.ts +18 -0
  142. package/dist/tools/figma/figma-url-parser.d.ts.map +1 -0
  143. package/dist/tools/figma/figma-url-parser.js +51 -0
  144. package/dist/tools/figma/figma-url-parser.js.map +1 -0
  145. package/dist/utils/exec-file-no-throw.d.ts +20 -0
  146. package/dist/utils/exec-file-no-throw.d.ts.map +1 -0
  147. package/dist/utils/exec-file-no-throw.js +36 -0
  148. package/dist/utils/exec-file-no-throw.js.map +1 -0
  149. package/package.json +1 -1
  150. package/src/cli/commands/add.ts +80 -9
  151. package/src/cli/commands/figma.ts +162 -0
  152. package/src/cli/commands/generate.ts +2 -0
  153. package/src/cli/index.ts +4 -2
  154. package/src/generators/gherkin-parser/index.ts +4 -0
  155. package/src/generators/test-generator/adapters/adapter-interface.ts +12 -1
  156. package/src/generators/test-generator/adapters/playwright/playwright-adapter.ts +14 -2
  157. package/src/generators/test-generator/adapters/playwright/templates/after-all.hbs +8 -0
  158. package/src/generators/test-generator/adapters/playwright/templates/after-each.hbs +8 -0
  159. package/src/generators/test-generator/adapters/playwright/templates/before-all.hbs +8 -0
  160. package/src/generators/test-generator/adapters/playwright/templates/imports.hbs +3 -0
  161. package/src/generators/test-generator/adapters/playwright/templates/test-file.hbs +24 -0
  162. package/src/generators/test-generator/code-generator.ts +122 -13
  163. package/src/generators/test-generator/step-mapper.ts +2 -2
  164. package/src/generators/test-generator/template-engine.ts +28 -2
  165. package/src/generators/test-generator/utils/data-resolver.ts +45 -27
  166. package/src/generators/test-generator/utils/runtime-data-transformer.ts +51 -0
  167. package/src/generators/types.ts +1 -0
  168. package/src/orchestrator/ai-rules-updater.ts +2 -0
  169. package/src/orchestrator/figma/figma-scaffolder-helpers.ts +126 -0
  170. package/src/orchestrator/figma/figma-scaffolder-types.ts +26 -0
  171. package/src/orchestrator/figma/figma-scaffolder.ts +209 -0
  172. package/src/orchestrator/figma/node-path-collapser.ts +38 -0
  173. package/src/orchestrator/figma/spec-figma-renderer.ts +80 -0
  174. package/src/orchestrator/figma/spec-figma-section-renderers.ts +46 -0
  175. package/src/orchestrator/project-initializer.ts +84 -10
  176. package/src/orchestrator/templates/ai-instructions/claude-cmd-add-screen.md +56 -11
  177. package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +30 -17
  178. package/src/orchestrator/templates/ai-instructions/claude-cmd-review.md +4 -3
  179. package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +34 -2
  180. package/src/orchestrator/templates/ai-instructions/claude-config.md +12 -2
  181. package/src/orchestrator/templates/ai-instructions/claude-skill-figma-source.md +151 -0
  182. package/src/orchestrator/templates/ai-instructions/claude-skill-gherkin-syntax.md +66 -13
  183. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-generation.md +93 -23
  184. package/src/orchestrator/templates/ai-instructions/claude-skill-tc-review.md +2 -0
  185. package/src/orchestrator/templates/ai-instructions/copilot-cmd-add-screen.md +53 -9
  186. package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +21 -16
  187. package/src/orchestrator/templates/ai-instructions/copilot-cmd-review.md +4 -3
  188. package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +34 -2
  189. package/src/orchestrator/templates/ai-instructions/copilot-config.md +12 -2
  190. package/src/orchestrator/templates/ai-instructions/copilot-skill-figma-source.md +151 -0
  191. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-figma-source.md +151 -0
  192. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-gherkin-syntax.md +86 -13
  193. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-selector-fix.md +61 -0
  194. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-generation.md +105 -28
  195. package/src/orchestrator/templates/ai-instructions/github-skill-sungen-tc-review.md +20 -0
  196. package/src/orchestrator/templates/specs-base.ts +65 -7
  197. package/src/orchestrator/templates/specs-test-data.ts +66 -0
  198. package/src/tools/figma/figma-auth.ts +161 -0
  199. package/src/tools/figma/figma-cache.ts +184 -0
  200. package/src/tools/figma/figma-client-types.ts +125 -0
  201. package/src/tools/figma/figma-errors.ts +127 -0
  202. package/src/tools/figma/figma-image-downloader.ts +112 -0
  203. package/src/tools/figma/figma-node-filter.ts +198 -0
  204. package/src/tools/figma/figma-rest-client.ts +183 -0
  205. package/src/tools/figma/figma-url-parser.ts +55 -0
  206. 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
- | Using Background | `Background: Given User is on...` | Use `@steps` + `@extend` instead |
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
- **Do NOT use `Background:` block.** Use `@steps` + `@extend` instead.
191
+ Both `Background` and `@steps`/`@extend` are valid — they serve different purposes.
184
192
 
185
- **Why:**
186
- - `Background` runs before EVERY scenario but cannot set dialog/frame scope correctly
187
- - `Background` with `When` + `And User is on [X] dialog` creates keyword mismatch (`is on` = Given, not When)
188
- - `@steps` + `@extend` gives explicit control: base steps run Given→When, extending scenario starts with `Given User is on [X] dialog` (correct scope setup)
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
- **Wrong:**
198
+ **Use `Background` for simple navigation:**
191
199
  ```gherkin
192
200
  Background:
193
- Given User is on [Kudos] page
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: VP-UI-001 Title visible
198
- Then User see [Title] heading
203
+ Scenario: View stats
204
+ Then User see [Revenue Chart] section
199
205
  ```
200
206
 
201
- **Correct:**
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.