Skip to content

fix: correct tool shapes, installer hang, and the half-built non-Stitch source paths - #23

Merged
gabelul merged 3 commits into
mainfrom
fix/api-shape-corrections
Jul 20, 2026
Merged

fix: correct tool shapes, installer hang, and the half-built non-Stitch source paths#23
gabelul merged 3 commits into
mainfrom
fix/api-shape-corrections

Conversation

@gabelul

@gabelul gabelul commented Jul 20, 2026

Copy link
Copy Markdown
Owner

Three review passes plus an exhaustive schema comparison and an actual install test. Everything here would have shipped broken in 1.12.0.

Would have failed every call

apply_design_system documented selectedScreenIds: ["abc"]; the live API takes selectedScreenInstances: [{id, sourceScreen}]. Both new DESIGN.md skills route into it, so the release's headline feature dead-ended.

update_design_system was structurally wrong — name nested inside designSystem, projectId absent entirely. Live takes all three as siblings, all required.

Found by comparing all 15 tools against live rather than only the reported ones:

  • generate_variantsprompt and variantOptions documented optional, actually required
  • get_screenname missing entirely; it's the current identifier and takes the full resource path, while projectId/screenId are deprecated but still mandatory

All 15 schemas now match live on properties and required fields, checked programmatically.

Installer died in any non-TTY context

npx @booplex/stitch-kit under CI, Docker, or piped input printed the API-key prompt then exited with Detected unsettled top-level await. readline's callback never fires on EOF, so the promise never settled — a silently failed install.

Verified fixed against a scratch HOME seeded with all seven client markers: exits 0, agent + 36 skills to Codex and OpenCode, 36 skills to Crush, agent-only to Claude Code (skills ship via plugin), MCP-only for Cursor and VS Code. That also makes the README's "Works with" table a measured fact rather than an unverified claim.

The non-Stitch routes were a door with no room

PR #21 made six conversion skills accept local HTML and URLs, but only edited Step 1:

  • Token extraction assumed a Stitch-emitted tailwind.config. Arbitrary HTML has none, so the new routes couldn't resolve colors, fonts, radii or dark mode at all. Now a four-step chain — tailwind.config → CSS custom properties → linked/inline stylesheet → infer from dominant computed values and say what was inferred. Plus an explicit note that the URL route fetches only the single HTML response.
  • RN and SwiftUI demanded a Stitch design in five places each, including telling users to "regenerate with deviceType: MOBILE" — meaningless to someone who supplied a local file. The constraint was always a mobile layout. Stitch screens still check deviceType; local files and URLs check viewport meta, mobile-first media queries, narrow root widths, touch targets. Mobile-only requirement unchanged.

Smaller corrections

  • assetId goes bare to apply_design_system but prefixed to generate_screen_from_text and update_design_system — three skills taught the wrong form
  • generate_screen_from_text was missing its designSystem param. Here the skills were right and our schema was stale — that param is what makes DESIGN.md → design system → generation hold together
  • Input payloads sent font, backgroundLight, backgroundDark, description, designTokens, styleGuidelines — none exist on the live input. Output examples showing font stay; it's returned, just not settable
  • DesignTheme had required: null despite requiring five fields
  • ROBOTO offered as a font value; not in the enum (ROBOTO_FLEX is)
  • README claimed every target ships TypeScript and ARIA — false for the HTML target and SwiftUI
  • create_design_system_from_design_md.json had $defs outside the arguments fragment, so its $ref didn't resolve standalone
  • Skill counts and the two new wrappers were missing from AGENTS.md and the agent definition, so the shipped agent didn't know its own new skills existed

Validator: Passed with 30 warning(s) — no errors.

Gabi added 3 commits July 20, 2026 21:34
A review pass caught that several documented tool shapes no longer match the
live server. Anyone following these docs would build calls the API rejects.
Verified every one of the 15 tools against the live schemas rather than
patching only what was reported — which turned up two more nobody had flagged.

apply_design_system was the worst of it. Docs said `selectedScreenIds:
["abc123"]`; the API takes `selectedScreenInstances: [{id, sourceScreen}]`.
Both new DESIGN.md skills route into it, so the feature this release is built
around dead-ended. The instance id is not the source screen id, and swapping
them fails — the skill now says so explicitly.

update_design_system was structurally wrong: `name` was nested inside
`designSystem` and `projectId` was absent entirely. The live tool takes all
three as siblings, all required.

Found by the sweep, not the review:
- generate_variants documented `prompt` and `variantOptions` as optional;
  both are required
- get_screen omitted `name` altogether — it's the current identifier and
  takes the full resource path, while projectId/screenId are deprecated but
  still mandatory

Also corrected:
- assetId goes BARE to apply_design_system but PREFIXED to
  generate_screen_from_text and update_design_system. Three skills taught the
  wrong form; each now states which tool wants which.
- generate_screen_from_text was missing its `designSystem` param. Here the
  skills were right and our schema was stale — that param is what makes
  DESIGN.md -> design system -> generation actually hold together.
- Input payloads sent `font`, `backgroundLight`, `backgroundDark`,
  `description`, `designTokens`, `styleGuidelines`. None exist on the live
  input. The output examples that show `font` stay — it is returned, just not
  settable.
- DesignTheme had `required: null` despite requiring five fields
- `ROBOTO` was offered as a font value; it isn't in the enum (`ROBOTO_FLEX`
  is). Same class as the fictional names caught earlier.
- Skill/tool counts and the two new wrappers were missing from AGENTS.md and
  the agent definition, so the shipped agent didn't know its own new skills
  existed.

All 15 schemas now match the live server on properties and required fields,
checked programmatically.
`npx @booplex/stitch-kit < /dev/null`, or any run without a TTY — CI, Docker,
a piped install — printed the API-key prompt and then died with "Detected
unsettled top-level await". readline's question callback never fires on EOF,
so the promise never settled and node exited partway through. The user got a
silently failed install, no error, no skills.

prompt() now returns '' when stdin isn't a TTY, and listens for readline's
`close` event so EOF resolves instead of hanging. Callers already treat empty
as "skipped", so the install continues and prints the manual MCP config.

Verified against a scratch HOME seeded with all seven client marker
directories: exits 0, installs the agent and 36 skills to Codex/OpenCode,
36 skills to Crush, agent-only to Claude Code (skills ship via the plugin),
and MCP-only config for Cursor and VS Code — which matches the "Works with"
table in the README exactly.
Accepting local HTML and URLs was bolted onto Step 1 without touching the
rest of each skill, so the new routes were a door with no room behind it.

Design tokens assumed a Stitch-emitted `tailwind.config` in `<head>`. Ordinary
HTML doesn't have one, so the two routes we just advertised had no way to
resolve colors, fonts, radii or dark mode. All six skills now resolve tokens in
order — inline tailwind.config, then CSS custom properties, then a linked or
inline stylesheet, then inferring from the most frequent computed values and
telling the user what was inferred. They also state that the URL route only
fetches the single HTML response, so linked stylesheets may not come along,
and to say so rather than invent a palette.

React Native and SwiftUI promised three sources then demanded a Stitch design
with `deviceType: MOBILE` in five places each — including telling users to
"regenerate with deviceType: MOBILE", which is meaningless to someone who
handed over a local file. The constraint was always a mobile *layout*, not a
Stitch artefact. Stitch screens are still checked via deviceType; local files
and URLs are checked by viewport meta, mobile-first media queries, narrow root
widths and touch-sized targets. The mobile-only requirement is unchanged.

Also:
- README no longer claims every target ships TypeScript and ARIA. Dark mode
  and tokens are universal; TS/ARIA are web-target only, SwiftUI emits Swift
  with native accessibility APIs, and the HTML target has no build step.
- `create_design_system_from_design_md.json` had `$defs` outside the
  `arguments` fragment the schema README calls the complete input schema, so
  its `$ref` didn't resolve when validated standalone. Moved inside.
@gabelul
gabelul merged commit f1c4e4f into main Jul 20, 2026
1 check passed
@gabelul
gabelul deleted the fix/api-shape-corrections branch July 20, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant