Add /adhd:pull-component skill#4
Merged
Merged
Conversation
Inverse of /adhd:push-component. Reads a Figma Component Set and reconciles its variant properties + lookup-table values back into a React source file. Updates only the design-token surface (Record<Union, string> tables and union type members); function body, JSX, hooks, handlers, and imports are invariant. Key design choices: - The React file IS the snapshot — no parallel state stored in the repo. Lookup tables already encode every design-token value the Figma side cares about. - The mapping lives in adhd.config.ts under components.<path>.figma.url, matching the parent config schema. Bidirectional: written by push on first push, by pull on first scaffold. - Pre-flight uses the same lint engine /adhd:lint and push-component preflight use; STRUCT003/004/005 (raw color, fontSize, effects) on the Figma side blocks the pull. Symmetric pipeline — designer-side variable discipline is enforced in both directions. - Escape hatch: --allow-unbound (or allowUnboundFigma: true in config) converts the abort to a confirm-prompt; off-system entries land in code with // adhd:off-system comments for greppability and self-healing on future pulls. - 1- and 2-axis Record<Union, string> tables supported. Other patterns (inline literals, non-string Records, tables inside function bodies) are reported and skipped — no silent inference. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 tasks decomposing the spec into TDD steps: - Task 1: scaffold lib + CI + Badge synthetic fixture - Task 2: parse-react.js — TS compiler API extraction - Task 3: class-resolver.js — wraps lint-engine for symmetric pipeline - Task 4: differ.js — pure local/figma comparator - Task 5: apply.js — AST-aware source rewrite (function body invariant) - Task 6: config-writer.js — components mapping in adhd.config.ts - Task 7: cli.js subcommand wiring - Task 8: SKILL.md orchestrator (11 phases) - Task 9: push-component additive (write mapping on first push) - Task 10: README + marketplace docs - Task 11: smoke + PR prep Test coverage maps 1:1 to spec acceptance criteria. Each module gets zero-deps unit tests; integration testing uses a synthetic Badge fixture with 4 Figma scenarios (clean, cell-change, added-variant, removed-variant) and golden output files for byte-identity apply verification. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Initial draft had parse-react.js + differ.js + apply.js modules reinventing TypeScript-compiler-API source extraction and AST-aware text replacement. User gut-checked: "Claude Code is the reason we're doing this code gen. I want the intelligence of Claude Code to know how to diff this stuff. I don't want to use rigid, brittle code to do it when we have a full beautiful LLM to do it. For anything not deterministic, we pretty much always use the LLM because the LLM is only getting better." Revised design: - Library shrinks to one module: config-writer.js (deterministic schema-level adhd.config.ts mutation, idempotent, unit-testable). - The SKILL prompt is the brain: reads the React source via Read, extracts the Figma Component Set via use_figma, computes the diff in working memory, prompts via AskUserQuestion, applies via Edit tool calls. Every invariant (function body untouched, off-system comment format, abort conditions) is stated explicitly in the SKILL so any Claude Code agent executes it the same way. - Pre-flight reuses lint-engine via subprocess (no new bridge module). Plan collapses from 11 tasks to 5: scaffold lib + SKILL + push-component additive + README/marketplace + PR. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deterministic surface only: read/write components.<path>.figma.url in adhd.config.ts. Everything intelligent (parsing the React source, diffing against Figma, applying edits) lives in the SKILL prompt where the LLM handles it. Brittle AST/regex approaches don't apply when Claude Code is already in the orchestration loop. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove unused escapeForRegex helper. - Remove COMPONENTS_OPEN_RE.lastIndex reset; the regex has no /g flag so lastIndex is never set by exec(), making the reset meaningless. - Collapse a 4-line comment that just restated variable names into a 2-line note about the iterator's quote-index invariant. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The skill is the brain: reads the React source, extracts the Figma Component Set via use_figma, computes the diff in working memory, prompts via AskUserQuestion, applies edits via the Edit tool. Every invariant (function body untouched, off-system comment format, abort conditions) is stated explicitly in the prompt. Pre-flight reuses lint-engine via subprocess for STRUCT003/004/005 enforcement. Config mapping read/written via config-writer CLI.
- Phase 3: spell out the variable-id → name resolution path. The prior text suggested reading the variable name from Phase 2.5's vars.json, but that map is keyed by name (not id), so the lookup was unreachable. Now the SKILL tells Claude to call getVariableByIdAsync directly and describes the intermediate shape to return from use_figma. - Phase 4: replace the hardcoded "Avatar" placeholder in the in-sync message with <ComponentName>. - Phase 5: align the "Keep ALL" option label with the resolution — it proceeds to the final report rather than exiting silently. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
/adhd:pull-component <react-path | figma-url> [--allow-unbound]— pulls a Figma Component Set back into a React source file. Inverse direction of/adhd:push-component. Updates only design-token lookup tables (Record<Union, string>) and union type aliases — function body, JSX, hooks, handlers, and imports are never touched.Architecture: LLM as the diff/apply engine
This skill runs inside Claude Code, so the LLM is already in the orchestration loop. It reads the React source, extracts the Figma Component Set via
use_figma, computes the diff in working memory, prompts the user viaAskUserQuestion, and applies changes viaEdittool calls. Traditional code is reserved for the deterministic, testable parts:lib/pull-component/config-writer.js— reads & idempotently writescomponents.<path>.figma.urlinadhd.config.ts. Regex + brace-counting parser; zero deps; 9 unit tests.lib/pull-component/cli.js— three subcommands (config-write/read/reverse); 8 surface tests.lint-engine(existing, reused) — pre-flight runs the samecheckStructurethat/adhd:lintuses.skills/pull-component/SKILL.md— the 11-phase orchestrator that handles all the intelligent work via Read/use_figma/AskUserQuestion/Edit.The first draft of this design had
parse-react.js/differ.js/apply.jsmodules doing brittle TS-compiler-API extraction + golden-file-tested AST surgery. User gut-checked: "Claude Code is the reason we're doing this code gen. I want the intelligence of Claude Code to know how to diff this stuff. I don't want to use rigid, brittle code to do it when we have a full beautiful LLM to do it." The revised design pushes intelligence into the SKILL prompt where it belongs; the library shrinks to ~200 lines covering only schema-level config mutation.Pipeline (in SKILL)
/adhd:lint)ADHD pull: <Component>.<axis> (<N> changes))Key design
Record<Union, string>lookup tables already encode every design-token value Figma cares about.adhd.config.tsundercomponents.<path>.figma.url. Written by push on first push (new Phase 11.5 added to push-component as part of this PR), by pull on first scaffold.--allow-unbound(orallowUnboundFigma: truein config) converts the abort to a confirm-prompt. Off-system entries land in code with// adhd:off-systemcomments — greppable, self-healing on future pulls.Out of scope (v1)
Record<Union, string>lookup-table convention — reported and aborted; the convention is now documented as part of the plugin's expectations.Test plan
🤖 Generated with Claude Code