* Fix: tear down annotation overlay when Escape exits live pick mode.
The configure prompt auto-focuses and bypasses the global Escape handler, so its local path must hide the annot overlay; togglePick off now does the same as a safety net.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Improve live mode steer pill typing affordance.
Show a visible caret and placeholder when focused, expand on pointerdown, and drop the muddy border so the graphite surface carries the affordance alone.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Improve live mode configure bar layout and pill styling.
Align pills and input on a shared text track, refine muted pill chrome with a quiet action border, and center the row with symmetric inset so spacing reads evenly in the 36px bar.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Add x1 to live mode variant count picker.
The configure bar count pill now cycles 1→2→3→4→1 so users can request a single variant.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Polish live mode configure bar, edit badge, and action picker.
Refine selection pill layout and tooltips, shrink edit copy to an icon aligned with the outline, right-align the action picker, and sync demo styles and regression coverage.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix live mode element nav when configure input is focused.
Passthrough empty arrow keys from the configure and steer prompts so handleKeyDown can move between pickable elements without breaking autofocus typing.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Remove accidental live.js inject from Base.astro.
Strip the localhost helper script tag left over from local live mode iteration so the PR ships only intentional UI changes.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix review findings: pick-cursor state sync, anchor recovery, e2e selectors.
Code review of this branch surfaced ten confirmed bugs plus three smaller
ones; this commit fixes all of them.
- Route every interaction-state transition through a new setLiveState()
helper that re-syncs the pick-mode crosshair, fixing four confirmed
cursor bugs: never appearing on pick toggle (sync ran before the state
change), sticking through the configure phase, surviving teardown
page-wide, and the style mounting inside the adapter's shadow root
where it can't match the host document (now document.head).
- Anchor recovery: a matching id is decisive again (hashed class names
and component tags broke recovery), empty-text elements can no longer
match the fuzzy text passes (".includes('')" hole plus shortest-text
preference), and the dead 2-class-subset fallback is removed.
- Selection pill: drop the hover-only "armed" guard so keyboard
activation works; the pill arms on focus as well as hover.
- Configure chrome: remove the configure-bar tooltip on teardown, align
restorePickerBarChrome padding with initBar (5px), share the
configure-input stylesheet with the insert row, and sync the
ui-core.mjs surface inventory with live-browser.js.
- Site demos: delete the stale duplicate .live-demo-ctx-selection rule
that killed the teal pill on dark pages, and keep the configure-phase
demo bar on the overlay's dark surface in light mode so the near-white
prompt text stays readable.
- E2E/contract tests: match the icon-only submit button by aria-label
("Generate variants") instead of the removed "Go" text, and update
source-contract pins for setLiveState and buildConfigureSubmitButton.
Verified: bun run test green, live-mode E2E 23/23 across all fixtures.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Wire insert voice button into syncVoiceUi listening state.
Voice on the insert configure row runs through the same 'configure' mode,
but syncVoiceUi only stamped data-listening/aria state on the replace
row's #impeccable-live-configure-voice, so the insert button never pulsed
while listening. Target whichever of the two row buttons is mounted, the
same either-row pattern syncConfigureInputChrome uses.
Addresses Bugbot review comment on PR #242.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Reinject from source when the session wrapper lands during anchor recovery.
The anchor-recovery observer stood down as soon as the session's variant
wrapper appeared in the DOM, without running injectVariantsFromSource.
A wrapper can land incomplete (wrap HMR landed, variant insert did not),
which is exactly the case injectVariantsFromSource's existing-wrapper
replace path handles - so recovery ended with the bar stuck and no
variants. Route both the anchor-found and wrapper-landed cases through
injectVariantsFromSource, which owns wrapper replacement, recovery-flag
clearing, and variant display.
Addresses Bugbot review comment on PR #242.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Restore inline edit drafts before configure chrome teardown disables editing.
teardownConfigureChrome called disableInlineEdit() ahead of hideBar(),
wiping inlineEditRows and the impeccableOriginalText metadata that
hideBar()'s EDITING-state restoreInlineEditDrafts() needs - so turning
Pick off mid "Edit copy" left edited DOM text in place, neither saved
nor canceled. Let hideBar() own the sequence: it restores drafts first,
then disables inline edit.
Addresses Bugbot review comment on PR #242.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Copy guidance (em-dash bans, buzzword bans, button-label / link-text
phrasing, aphoristic-cadence) doesn't belong in the main design skill.
It's not design-specific — the skill is trying to do too much. The six
rules being dropped (every-word-earns, no-em-dashes, no-aphoristic-cadence,
no-buzzwords, button-verb-object, link-standalone) are now better served
by:
- The impeccable engine's antipattern detectors (em-dash-overuse,
marketing-buzzword, aphoristic-cadence, copy-slop) for linting at scan
time.
- The /clarify subcommand for surfacing the same checks when reviewing
copy specifically.
The em-dash ban for the SKILL prose itself still lives in STYLE.md and the
build-time prose validator — that's separate from the skill's guidance to
agents.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The v2.1 ablation sweep (n=10 × 4 brand niches × 3 providers, anchored to
commit 54c3a502, ~544 cells) confirmed these four rules carry no weight in
the skill:
- skill-typo-no-all-caps-body — duplicate of brand-ban-all-caps-body; brand
version is more specific (reserves caps for labels + headings)
- skill-typo-codex-hero-ceiling-repeat — the codex-block restatement of
skill-typo-hero-ceiling didn't add reinforcement on top of the universal
rule
- skill-typo-scale-ratio — duplicate of brand-typo-modular-scale; same
signal, brand version carries the clamp() / fluid implementation detail
- skill-typo-font-count — models don't reach for ≥4 font families in any
niche we test, so the rule has no measurable effect
Each deletion is the Agent A / B / C / D Phase-2 audit recommendation;
none of the four ever validated under either prose state.
Adds EMPIRICAL_VALIDATION.md naming the seven cross-provider winners as the
trustworthy core, and documents the systemic findings (self-priming, detector
saturation, vocabulary anchoring) so future skill edits can avoid the same
traps.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(live-inject): preserve the character after an insertAfter anchor
insertTag()'s insertAfter branch sliced the post-anchor remainder by
prefix.length. When the anchor was not already followed by a newline,
prefix is one character longer than the anchor (the appended '\n'), so
content.slice(prefix.length) dropped the first real character after the
anchor — e.g. `<head>X...` lost the `X` during live-mode injection (#227).
Slice the remainder from the original anchor offset instead. The
insertBefore branch and the already-followed-by-newline case are
unchanged. Add a regression test for both the no-trailing-newline and
newline cases, and regenerate the tracked per-agent bundles so the fix
ships everywhere.
Fixes#227. Root-cause analysis from the issue reporter.
* Fix live inject CRLF insertAfter handling
---------
Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
Derive a Gecko-compatible manifest at build time and package
extension-firefox.zip alongside the Chrome zip:
- background service worker is declared as an event-page `scripts`
entry (top-level listeners + in-memory Map run unchanged on Gecko)
- browser_specific_settings.gecko with id, strict_min_version 140.0,
and data_collection_permissions (required by AMO; honored on 140+)
- packZip helper parameterized over cwd/excludes; `*.DS_Store` strips
junk at every depth and .DS_Store is excluded from the staging copy
- guard against a missing background.service_worker shape
CI now builds the extension and runs a pinned `web-ext@8 lint` over
the staged Firefox tree (innerHTML warnings are non-blocking); the
unpacked staging dir is excluded from the uploaded artifact. The
release script attaches both zips and points to AMO.
Bumps the extension to v1.2.0 with a changelog entry.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com>
Mirrors the 5 prose changes in skill/SKILL.src.md + skill/reference/brand.md
out to every harness directory (`.claude`, `.gemini`, `.cursor`, `.codex`,
`.agents`, etc.) so the staged skill that workers / agents read matches the
source. Auto-generated by `bun run build:skills`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase-2 ablation audit caught these rules causing the exact behavior they
ban via the literal examples in their own prose. Verified: OpenAI samples
under skill-on produced "fake theater", "vendor theater", "heatmap theater"
as verbatim copies of the 'X theater' example. Same pattern for the
restrained-on-cream example, the aphoristic-cadence template, and the
"reserve uppercase for…" enumeration.
- skill-ban-codex-x-theater: drop the 3 syntactic templates + 3 example
phrases ("Productivity theater" etc.)
- brand-imagery-required: drop the niche enumeration that cued
"imagery not required elsewhere"
- skill-typo-no-all-caps-body: drop the "Reserve uppercase for labels /
eyebrows / badges" enumeration that primed uppercase usage
- brand-color-no-converge: drop the "restrained-on-cream" example that
was priming cream-heavy palettes
- skill-copy-no-aphoristic-cadence: drop the literal cadence template
("serious statement, then punchy short negation") that named the
rhythm it bans
Ablation re-run pending in impeccable-evals to measure impact.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* Improve CI test coverage
* Stabilize live E2E harness
* Shard live E2E CI
* Cache live E2E CI dependencies
* Stabilize live E2E smoke CI
* Update generated live browser bundles
* Tighten live E2E smoke runtime
* Prevent live E2E smoke hangs
* Stabilize live E2E CI coverage
* Fix stale accept DOM cleanup
* Regenerate live browser outputs
The verbs/labels/icons were copied three ways: live-browser.js (ICONS + ACTIONS),
VISUAL_ACTIONS in live-event-validation.mjs, and the marketing demo. Collapse
them to one source, skill/scripts/live-vocabulary.mjs (LIVE_COMMANDS + derived
VISUAL_ACTIONS).
- live-event-validation.mjs imports VISUAL_ACTIONS from it.
- live-server.mjs serializes LIVE_COMMANDS into window.__IMPECCABLE_VOCAB__ when
it serves /live.js, next to the token/port. live-browser.js (served raw, can't
import at runtime) builds its ICONS + ACTIONS from that injected vocab instead
of an inline copy — byte-identical icons, zero behaviour change.
- site/components/LiveDemoPalette.astro imports the same module at build time, so
the demo and the real picker can no longer drift.
Adds a /live.js test asserting the injected vocab deep-equals the canonical list.
Harness skill dirs refreshed via build. (Pre-existing, unrelated: `bun run
build:site` fails on an htmlparser2 import in the CLI detector.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrite the hero around the why (the missing design vocabulary) instead of the
live-mode how: "The missing design vocabulary for agents." The live demo now
opens the picker's command palette and picks a verb before generating, which is
the move that makes the live approach unique and was previously skipped.
- Demo palette mirrors the real action picker (live-browser.js): same 12 verbs,
the same SVG icons, a 4-col icon-over-label grid, selected chip on a kinpaku
wash with its icon recolored. Light + dark covered.
- Shared <LiveDemoPalette> component renders the grid from one list, so the hero
and /live-mode no longer hand-copy the markup. /live-mode lands on "delight",
the hero on "colorize" (via data-demo-pick); pages without a palette filter the
switcher beats out of the shared timeline.
- Trim the opening beats so the cursor clicks the element at ~1.3s (was ~2s), and
slow the palette browse so the vocabulary is readable.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>