* Route the direction hand by verdict, add the pick card, enforce salience parity
The decision round previously rendered every dealt challenger as an equal
full card whatever the weighing said, so a world that fused poorly (an
underwater world dealt to a flower shop) sat at the same visual weight as
the assigned direction, and concept-level fusion had no surviving output.
Three changes, all presentation-layer; the dice, the assignment, and the
two-axis weighing are untouched:
- Verdict routing: the weighing closes with wins / competitive / declined
per challenger, decided before any borrowing. Declined challengers render
demoted (narrow, quiet, catalog art as a labeled thumb, "Adopt anyway"),
reordered to the end of the deck by the page itself, still adoptable,
never silently dropped. Donations return as named "raised by" lines on
the assigned card: a declined challenger donates ambition and system
discipline, never its clothes.
- The pick card: one card for the model's top-ranked grounded candidate
when the dice assigned another, kicker MY PICK, honest familiarity risk
on its face. One card, never a ranked list, never the lead position; the
anti-menu rule survives with exactly this carve-out.
- Salience parity: a card's imagery weight is capped by the assigned
card's. With a text-only assigned card (no image generation in the
harness), full-bleed catalog heroes demote to labeled thumbs, so what
looks important is the verdict's call, never rendering luck.
serve-question payload gains additive fields (verdict, kept, raised); old
payloads render unchanged. concept-seed's rendered instructions carry the
verdict/donation contract and the pick-card carve-out. Covered by two
Playwright tests in the new-work e2e suite (verdict routing + parity).
Design exploration and rationale were worked through with the maintainer;
research grounding is impeccable.style/research lessons 3-5.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* Add Safer/Bolder re-roll registers to the direction round
The re-roll gains the user's steering wheel on the familiar-to-bold axis.
The decision page renders two register buttons beside the plain re-roll
(payload: reroll: { registers: ["safer", "bolder"] }; booleans still work),
the answer carries the chosen register, and concept-seed gains --register.
The design constraint that shaped the implementation: a register changes
only what a round INSTRUCTS, never what it DEALT. The same key and reroll
count reproduce the same deal whatever the register, so the exclusion chain
never forks and the reproduction contract holds with no API change.
- bolder: the dealt foreign forms become the whole hand, every challenger a
full card; the first-dealt challenger leads (assignment by deal order, so
the dice still choose). The pick card sits out; the canon stays.
- safer: the round's dealt hand is spent unseen and stays excluded; the
model presents its remaining conventional grounded candidates (at most
three) plus the canon executed against named competitors. This is the one
sanctioned lineup of the model's own ranked list, existing only by
explicit user request. Works degraded (needs no catalog); bolder degrades
to a plain grounded round, disclosed.
Registers are user steering, never the model's to pre-select. Covered by a
concept-seed unit test (same-deal invariant, validation) and a Playwright
test (button, answer field, REGISTER directive).
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* Add the execution-contract round: comp-led or code-led, chosen after the direction
The build previously went comp-led for everyone, silently: a generated comp
led and the build chased it, which produces the boldest compositions and
also the measured worst-of-both-worlds failure (ambitious design landed
poorly, no motion, fix rounds after). Models already defect from it by
quietly skipping comp generation, which is unsanctioned code-led with no
contract to catch it. This makes the fork explicit and both paths
defection-proof:
- Comp-led: the comp is law and non-optional once chosen; visualize.md and
the comp-is-king build phases run as today.
- Code-led: no comp of this page, skipped by contract rather than drift.
The QUALITY BAR boards still calibrate finish, and the ambition moves
into the written direction contract (FIRST VIEWPORT plus a named
signature interaction and motion grammar), audited by the finish
reviewer in behavior. Not a discount on commitment.
Placement: a second round on the same open table, right after the
direction lands. Sketches stay in the direction round (they pick the
world); comps are what code-led skips (they bind the composition). The
chosen world sets the default lead; the user flips freely; a standing
preference recorded in PRODUCT.md skips the round on later surfaces; with
no image generation there is no fork, code-led is the only path.
Mechanism: serve-question gains payload-level followup: true, which keeps
the detached server alive after a pick (exactly like re-roll), swaps the
page to the loading hand instead of goodbye, marks the answer with
followup: true so --wait keeps the table, and prints a FOLLOWUP OPEN
directive telling the agent to deliver the next round via --update.
Covered by a Playwright test driving the full two-round flow.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: address PR review bot findings
- Degraded safer register no longer contradicts itself (greptile,
Copilot, cursor): the degraded template previously said "the assigned
index is suspended; the user picks" and then emitted ASSIGNED INDEX,
the mandatory build instruction, and the restated footer anyway. The
degraded safer path now suppresses the assignment machinery entirely,
matching the non-degraded safer round, and restates the user-picks
behavior for truncated readers instead.
- A declined card's declared sketch no longer renders a full media face
(Copilot): the renderer ignores sketch slots on declined cards
outright, so a stray sketch cannot buy back the salience the verdict
took away.
- Bolder rounds no longer carry the generic weighing instruction
(cursor): it measures against the assigned grounded direction, which
the bolder register suspends; a leader-relative variant weighs the
fused challengers against the first-dealt leader instead.
All three pinned by new assertions in tests/concept-seed.test.mjs and
tests/new-work-e2e.test.mjs.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: followup never arms the loading hand in blocking serve mode
cursor[bot] caught a client/server disagreement: the page interpolated its
FOLLOWUP constant from the payload alone, so a followup: true payload served
in blocking mode (no --start) would leave the browser on a loading hand that
nothing resolves, since a blocking server exits on any pick and has no
update channel. The page constant is now armed only when the server is
detached, blocking rounds get the goodbye screen as before, and new-work.md
states that followup belongs only on a detached round; blocking and
structured-tool channels run the build-path round as its own second
question. Pinned in tests/serve-question.test.mjs.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* Add card-kind choice telemetry and the bolder routing disambiguation
The choice ping previously fired only when a dealt catalog challenger won,
so pick-share and canon-share had no denominator and the decision page's
new spectrum could not be measured. The ping now fires once per resolved
attended round on API-dealt rolls: --kind names which card class won
(assigned / pick / challenger / canon), --chosen carries the catalog id
only when a dealt challenger won, and --register rides along when the
round came from a steered hand. Grounded candidates' names never leave the
machine (the ping carries the kind alone), the legacy id-only shape stays
valid, and DO_NOT_TRACK / IMPECCABLE_NO_TELEMETRY still disable the ping
entirely. The seed's TELEMETRY block teaches the new invocation.
Also the naming-collision guard: "bolder" said while a direction round is
open routes to the Bolder hand register, never the bolder refinement
command; one line each in bolder.md and new-work.md.
The /api/chosen field additions land in a sister impeccable-site PR; the
API ignores unknown fields meanwhile, so this is safe to ship first.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: ping test survives a DO_NOT_TRACK shell
cursor[bot]: the pingChosen unit test cleared only IMPECCABLE_NO_TELEMETRY,
so a developer shell with DO_NOT_TRACK set failed the success-path
assertions. The test now clears both, restores prior values in finally,
and passes under DO_NOT_TRACK=1.
AI-assisted change.
Co-Authored-By: Claude Code <noreply@anthropic.com>
---------
Co-authored-by: Claude Code <noreply@anthropic.com>
The list of Live chrome surfaces was inlined into live-browser.js as a
function-scope const when live/ui-core.mjs was deleted for having zero
in-repo references. It had one out-of-repo reference. The private
impeccable-site repo imports it at build time: its Live UI lab must hold
a snapshot for every surface Live defines, and the site build fails with
the surface name when one is missing. Inlining put the list out of reach
of every Node importer, so the site had to regex it back out of the
browser script, and the guard only kept passing because the site's
materialized copy of skill/ was stale.
A guard that reads a list the site itself maintains guards nothing, so
the fix is a real export rather than a better parser.
skill/scripts/live/ui-surfaces.mjs is now the single definition. The
browser-runtime constraint is unchanged and satisfied the same way the
command palette already solves it: live-browser.js is served raw and
injected as a classic <script>, so it cannot import an ES module. The
/live.js assembler serializes the module into
window.__IMPECCABLE_LIVE_UI_SURFACES__ in the prelude it already writes
for the token, port and vocabulary, and live-browser.js reads the global.
assembleLiveBrowserScript defaults the value from the module rather than
taking it from live-server.mjs, so the bundle carries the canonical
inventory by construction instead of by a caller remembering to pass it.
The emitted inventory is byte-identical to the inlined one.
tests/live-ui-surfaces.test.mjs pins both halves of the seam: the module
is the definition (live-browser.js must not redeclare it), the prefix the
module builds ids from matches the PREFIX live-browser.js hardcodes, and
the assembled bundle still carries the list. live-server.test.mjs gets
the matching integration check against a served /live.js.
One existing assertion changed. live-browser-regression.test.mjs checked
that the steer Send control is registered as live chrome by matching the
text of the inline literal's last line. That encoded where the list was
written, not what it contains; it now asserts membership in the imported
LIVE_UI_COMPONENT_IDS, which is the behaviour it was after.
Verified with the full default suite plus a live-e2e fixture run
(vite8-react-modal), so the overlay is exercised end to end in a browser.
AI-assisted via Claude Code under maintainer direction.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Centralize CSS numeric token parsing and characterize every supported color unit while preserving config and filtering behavior.
AI-assisted: Codex implemented this refactor under pbakaus’s scheduled architecture-simplification authorization.
Make critique storage the single owner of snapshot discovery and frontmatter parsing, and keep context signals focused on summarizing the canonical result.
AI-assisted: Prepared by Codex under pbakaus's scheduled architecture-refactor authorization.
Emit Codex-compatible top-level keys while preserving the argument hint under metadata. Keep existing Claude-style pin frontmatter unchanged for other harnesses.
AI assistance: Codex implemented and validated this change under maintainer pbakaus's standing authorization.
* Fix Blade directory detection
AI assistance: Codex reproduced the issue, implemented the fix, and ran the validation described in the pull request.
* Fix compound scan suffix matching
AI assistance: Codex addressed review findings and ran the validation described in the pull request.
Optional `avoid`, two or three negations of 12 to 160 characters. A world built
from posters is at risk of shouting; one built from instruments is at risk of
dead greys. The global detector cannot know which and the author can, so the
"do not" belongs beside the "do" rather than in a rulebook that applies to
everything equally.
Optional on purpose: 541 entries predate it and none of them are wrong for
lacking it, so nothing needs backfilling.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A well-made site was audited for what separates it from a competent one, and the
answer was not its ingredients. It runs the default stack, Next and Tailwind and
Geist, with no world and no unusual technique. What it has is attention to the
surfaces a browser renders for you: 29 focus-visible rules, 15 scrollbar rules,
and styled text selection, caret, underline offset and scroll behaviour.
Those are the cheapest signal that a page was built rather than assembled, and
the ones a model skips most reliably, because nobody asks for them and nothing
looks broken without them. The floor already covers contrast, depth, spacing,
measure, motion and states; this is the layer under all of it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A 3-star held two tickets and a 1-star held none. On a pool this size that is
not a nudge, it is the shape of the draw. Measured against the live catalog:
3-star worlds absorbed 57% of the graphic draw from 65 of 163 eligible worlds,
46% of atmosphere from 13 of 43, and 75% of interaction from 15 of 25. The
reviewer's report that the same worlds keep returning is exactly what a rating
multiplier does to a corpus whose thinnest tier holds 25 worlds.
Now a 3-star draws level with a 2-star, and a 1-star draws at half rather than
not at all. Excluding a marginal keep made rating do a job breadth already does
properly: breadth still removes a niche world from the pool entirely, which is
the honest way to say "too narrow to challenge an arbitrary build", while a
1-star records "unexceptional" and is still worth showing sometimes.
Effect on the same catalog: the 3-star share falls to 39% on graphic, 30% on
atmosphere and 60% on interaction. That last one is no longer a weighting
artefact, it is simply what the tier contains, since 15 of its 25 eligible
worlds are rated 3.
Compositions get the same treatment; the two ticket functions had the identical
shape and no reason to disagree. Both tests asserted the old policy directly
and now assert the new one.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
probe-compking-sol-4 (evals) executed its staged inventory faithfully and
still lost the comp: the brief had already recorded the comp's materials
down (low-contrast textures, a 70-path lake against the comp's hundreds,
a sculpted plate as flat CSS), and the build thread never loads
visualize.md, so nothing told it the comp wins that disagreement. The
comp-is-king block now says the record gets corrected upward, that the
comparison runs against the freshly reopened comp rather than memory,
and that a texture under a near-opaque wash is not shipped material.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Gracefully handle the no-image decision page
Tested the new-work path without image generation and fixed what broke:
- A text-only card's back face (First viewport, The case) was unreachable:
the Details flip chip only rendered inside the media block. Cards with no
imagery now render their full read on the front and skip the back face.
- A hero/board that fails to load (retired catalog URL, offline shell) sat
as a dark void with a zoom cursor. The slot now collapses to a field
painted from the card's own palette with an "artwork unavailable" pill;
broken inspiration PIPs remove themselves.
- Sketchless catalog art rendered unlabeled as the card's face, reading as
the promise of the build. It now carries the same "inspiration" label and
hover title the PIP uses.
- The --schema example pointed at catalog URLs that 404 (missing family
prefix); updated to the real asset paths and noted the text-only front
behavior in the schema prose.
Extends e2e test (e) with the front-read and label assertions and adds
test (f) for the broken-image fallback.
AI-assisted (Claude Code).
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: address PR review bot findings
- cursor[bot]: the unavailable-art scrim painted over the flip chips and
swallowed their clicks; it now passes pointer events through and the
chips render above it.
- Copilot: a palette-less card whose art failed still read as a dark void
and kept the stale Inspiration tooltip; the slot now falls back to the
graphite field in CSS and the tooltip is removed with the art.
Test (f) now covers both: a broken card with back facts must still flip
via Details, and a palette-less broken card gets the labeled fallback.
AI-assisted (Claude Code).
Co-Authored-By: Claude Code <noreply@anthropic.com>
---------
Co-authored-by: Claude Code <noreply@anthropic.com>
* test: harden the test strategy (triggers, runner speed, release guards)
Follow-ups from an end-to-end testing strategy review:
- Suite triggers are now auto-generated from each suite's own file list,
so change-based CI can never miss a test file again (four files were
unreachable by their own edits, and tests/lib/detector-bundle.test.js
triggered core while running in detector). Two new meta-tests pin the
invariant. Hand-written trigger patterns now carry only source paths
and fixture dirs; palette dropped from the live triggers since no
suite tests it.
- The node runner batches all files into one node --test invocation at
concurrency 4 instead of spawning per file. Default suite drops from
~159s to ~100s; the live suite soaked clean three times.
- scripts/release.mjs gets its first tests: 12 scenarios spawning the
real script inside a disposable git repo with a local bare origin,
covering every refusal guard plus notes/tweet rendering, all under
--dry-run.
- skill/scripts/live/ui-core.mjs deleted: zero references repo-wide,
superseded by the July live rewrite, yet still shipping to users.
cli/lib/download-providers.js annotated with its cross-repo consumers
(impeccable-site Pages Functions) so it is not mistaken for dead code.
- CLAUDE.md gains an area-to-suite table for the opt-in suites a change
owes; AGENTS.md syncs the plugin-e2e commands and obligations.
AI-assisted via Claude Code under maintainer direction.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: exclude peeled tag lines from release-test origin cleanup
Copilot: git ls-remote --tags emits ^{} peel lines for annotated tags,
which are not deletable refs; --refs filters them so the cleanup loop
survives a future scenario that pushes an annotated tag.
AI-assisted via Claude Code under maintainer direction.
Co-Authored-By: Claude Code <noreply@anthropic.com>
---------
Co-authored-by: Claude Code <noreply@anthropic.com>
Volta's Windows shims exec through `cmd /C`, which re-parses the argument
list, so the `>=` inside the probe's `node -e` payload was read as output
redirection. The command died with "The filename, directory name, or volume
label syntax is incorrect" before node started, the guard read that as a
missing runtime, and the hook it exists to protect was disabled on every
PostToolUse and Stop. A user on a supported Node 24 got a one-time notice
telling them to install Node 22, then silence.
Clamping with Math.min is the same floor test in the same ES5-only syntax,
with no character cmd.exe can claim. Verified through the Volta shim on Node
24.16.0 and 22.18.0 (exit 0) and against a real Node 20.6.1 binary (exit 1),
so the floor is unchanged. Adds a regression test asserting no `<`, `>`, or
newline reaches any generated `node -e` payload.
Upstream cause: volta-cli/volta#1791.
Prepared with AI assistance (Claude Code).
* Fix: skip POSIX hook guard on Windows installs (#452)
PowerShell rejects the `[ ! -f ... ] ||` guard at parse time, so Codex
hooks generated by `npx impeccable install` on Windows never ran. Emit
the direct `node "PATH"` invocation there; POSIX output is unchanged.
AI-assisted (Cursor).
Co-authored-by: Cursor <cursoragent@cursor.com>
* Keep the missing-file no-op in Windows-generated hook commands
Greptile review on #453: project hook manifests are committable, so a
bare `node "PATH"` written on Windows loses the silent no-op when a
POSIX teammate without the skill consumes it. Replace the bare form
with a shell-agnostic `node -e` existence guard that parses in
PowerShell, cmd.exe, and sh, and forwards the hook's exit code.
AI-assisted (Cursor).
Co-authored-by: Cursor <cursoragent@cursor.com>
* Use Codex's commandWindows field for the Windows hook guard
Per @PatrickSys on #452: Codex runs hooks through COMSPEC (cmd.exe /C),
not PowerShell, and 0.146.0+ selects a commandWindows manifest field on
Windows. Codex entries now always carry the POSIX guard in command plus
an `if exist` cmd.exe guard in commandWindows (his Windows-tested form),
so one .codex/hooks.json is correct on every OS regardless of where the
install ran. Claude/Cursor keep the node -e wrapper on Windows installs
since their manifests have no per-platform field.
AI-assisted (Cursor).
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix: unescape YAML quote escapes in DESIGN.md frontmatter scalars (#428)
parseScalar() stripped a double-quoted scalar's outer quotes without
processing the backslash escapes inside, so a font stack that quotes a
multi-word family the CSS way, e.g.
fontFamily: "\"IBM Plex Sans\", system-ui, sans-serif"
reached allowedFonts as '\"ibm plex sans' and design-system-font flagged
fonts DESIGN.md declares. Also collapses the doubled-quote escape in
single-quoted scalars and keeps a lone quote literal instead of slicing
it to an empty string. Applied to both copies of the parser
(cli/engine/design-system.mjs and skill/scripts/lib/design-parser.mjs).
Co-authored-by: Cursor Agent (AI-assisted change, reviewed and directed
by a maintainer)
* Decode YAML hex and Unicode escapes in double-quoted scalars
Review follow-up: the escape scanner only handled the simple set, so
\xNN, \uNNNN, and \UNNNNNNNN sequences stayed encoded and an escaped
token like "\x23b8422e" never matched #b8422e in CSS. Decode validated
hex escapes in both parser copies; malformed or out-of-range sequences
stay literal. Regression coverage for all three forms.
Co-authored-by: Cursor Agent (AI-assisted change, reviewed and directed
by a maintainer)
* Complete the YAML 1.2 double-quote escape set
Review follow-up: the escape map omitted the escaped space (\ ) and
non-breaking space (\_) forms, so fonts declared with them kept a
literal backslash in allowedFonts and their CSS declarations were
reported as undeclared. Map the full spec 5.7 set (\a \b \v \f \e
\N \L \P included) in both parser copies instead of chasing one escape
at a time. Regression coverage for both named forms.
Co-authored-by: Cursor Agent (AI-assisted change, reviewed and directed
by a maintainer)
* Fix broken-image comment false positives
AI assistance was used to reproduce the issue, implement the fix, and add regression coverage.
* Harden JavaScript comment scanning
AI assistance was used to address automated review feedback, add regression coverage, and run validation.
* Handle comments in template expressions
AI assistance was used to reproduce and fix automated review feedback, add regression coverage, and run validation.
* Preserve JSX around URL and regex syntax
AI assistance was used to reproduce and fix automated review feedback, add regression coverage, and run validation.
* Fix regex keyword property context
AI assistance: Codex identified, implemented, and validated this review follow-up under maintainer authorization.
* Handle JSX slash edge cases
AI assistance: Codex addressed review findings and validated this follow-up under maintainer authorization.
* Ignore CSS-in-JS comments
AI assistance: Codex addressed top-level review findings and validated this follow-up under maintainer authorization.
* Handle remaining slash contexts
Fix JavaScript keyword separation and JSX protocol-relative URL classification so comment stripping preserves only live source. Add focused regressions for the reviewed edge cases.\n\nAI assistance: Codex implemented and validated this change under maintainer authorization.
* Handle generic styled templates
Recognize TypeScript generic arguments consistently in CSS-in-JS extraction and comment sanitization. Add focused regressions for extraction and comment-only styled templates.\n\nAI assistance: Codex implemented and validated this change under maintainer authorization.
* Handle nested styled generics
Teach CSS-in-JS extraction and comment sanitization to scan balanced nested TypeScript generic arguments before template literals. Add regressions for live and commented nested-generic styles.\n\nAI assistance disclosure: Codex implemented and validated this review follow-up under maintainer authorization.
* Handle nested source contexts
Keep regex detection correct after postfix operators, distinguish JSX expression comments from protocol-relative text, and scan nested template literals inside CSS-in-JS interpolations. Add focused regressions for each review finding.\n\nAI assistance disclosure: Codex implemented and validated these review follow-ups under maintainer authorization.
* Complete comment-safe source scanning
Recognize regex literals after for-of, comparisons, and block braces without confusing object-literal division. Route grid-background detection through the offset-preserving comment-neutralized source and add negative and positive controls.\n\nAI assistance disclosure: Codex implemented and validated these review follow-ups under maintainer authorization.
* Handle remaining lexer contexts
Recognize JSX attribute expressions and regex literals inside CSS-in-JS interpolations so comment stripping remains source-safe.\n\nAI-assisted: Codex implemented and validated this change under maintainer authorization.
* Align interpolation regex contexts
Match postfix-update and statement-block regex classification in CSS-in-JS interpolation parsing so templates remain extractable.\n\nAI-assisted: Codex implemented and validated this change under maintainer authorization.
Centralize the browser-safe module set and source transformation so the browser and extension builders cannot drift.
AI assistance: This refactor was prepared by Codex under pbakaus's scheduled architecture-simplification authorization.
* test: guard the plugin loader contract that PR #494 exposed
The agents manifest key shipped for months and silently loaded zero of
the four subagents; no validator looked at the generated plugin
manifest's shape and claude plugin validate never checks it. Three
layers now do:
- scripts/lib/validate-plugin-manifest.js pins the verified loader
contract (KNOWN_LOADER_KEYS allowlist, no agents key, trailing-slash
skills path from issue #86, every skill/agents/*.md shipped in
plugin/agents/), unit-tested in tests/validate-plugin-manifest.test.js
including a check of the real committed subtree.
- The same check gates bun run build next to the version-drift guard.
- tests/plugin-e2e.test.mjs installs the committed ./plugin subtree into
a real Claude Code (sandboxed via CLAUDE_CONFIG_DIR in a temp dir) and
asserts the component inventory: skill parses, all agents visible,
hooks discovered. In the default suite; runs in about a second and
skips cleanly when the claude CLI is absent, so CI is unaffected.
All three failed against the pre-#494 tree for the shipped reason
(Agents 0 of 4) and pass against current main.
AI-assisted via Claude Code under maintainer direction.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: address PR review bot findings
- Copilot: guard collectPluginManifestFindings against valid JSON that is
not an object (null, string, number, array) so a broken manifest is a
finding instead of a build crash; unit test added
- Copilot: update the plugin-e2e header comment, the suite is in the
default lineup rather than opt-in
AI-assisted via Claude Code under maintainer direction.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: harden plugin E2E sandbox isolation
Bugbot: create the sandbox CLAUDE_CONFIG_DIR up front and redirect HOME
and USERPROFILE into the temp workDir too, so a CLI code path that
derives config or cache locations from the home directory instead of
CLAUDE_CONFIG_DIR still cannot touch the developer's real Claude config
when the default suite runs.
AI-assisted via Claude Code under maintainer direction.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: agent parity check mirrors the build's emit rules
Bugbot: the shipped filename is `${claude-name || name}.md` and a
providers: list may exclude claude-code, so comparing raw source
basenames could fail the build on a renamed or provider-scoped agent
with a build:release hint that cannot fix it. The validator now derives
expected filenames the same way the transformer factory does (shared
parseFrontmatter, same providers gate) with unit coverage for renames,
name overrides, and provider-scoped agents.
AI-assisted via Claude Code under maintainer direction.
Co-Authored-By: Claude Code <noreply@anthropic.com>
* fix: run the plugin E2E through a shell on Windows
Bugbot: the claude CLI is a .cmd shim on Windows and Node refuses to
spawn those via execFile without a shell, so the availability probe
always failed and the suite silently skipped there. Windows now invokes
through a shell with every argument double-quoted (temp paths routinely
contain spaces); the POSIX path is unchanged.
AI-assisted via Claude Code under maintainer direction.
Co-Authored-By: Claude Code <noreply@anthropic.com>
---------
Co-authored-by: Claude Code <noreply@anthropic.com>
build.js derives plugin/.claude-plugin/plugin.json from the root manifest and
injects an `agents` array built from the generated agent files. In Claude Code
that array is exactly what stops them loading.
Verified on a throwaway local marketplace, across the plausible shapes:
array of file paths (what build.js emits) -> 0 agents load, skills fine
a string, e.g. "./agents" -> whole plugin fails to load
array containing a directory -> whole plugin fails to load
key omitted -> all agents load, skills fine
Claude Code discovers agents/*.md on its own, and the identifier it uses is the
file name rather than the frontmatter `name`. So the key is not needed, and any
present form of it is worse than its absence.
Confirmed end to end on this repo: with the key emitted,
`claude plugin details impeccable` reports "Agents (0)"; with it omitted it
reports "Agents (4) impeccable-asset-producer, impeccable-documenter,
impeccable-finish-reviewer, impeccable-manual-edit-applier". The agent files
themselves are still copied by the existing copyDirSync a few lines below —
only the manifest key goes away.
Two things make this hard to notice: with a breaking shape
`claude plugin details` prints "Plugin not found" instead of a validation
error, and `claude plugin validate` does not catch it because it validates the
marketplace manifest, not the plugin manifest. The only reliable signal is the
"Agents (N)" line.
The same defect is reported against another project at
addyosmani/agent-skills#449, with the full reproduction.
Scope note: verified on Claude Code only. plugin/ is the Claude-Code / Grok
subtree, and the Grok manifest is written separately just below, so this does
not touch the other harnesses.
Upgrade @babel/parser from 7.29.7 to 8.0.4 and raise the repository Node 22 minimum from 22.12.0 to 22.18.0 across package metadata, CI, and npm documentation.
No parser API migration was required. Validated with the full local suite and refreshed GitHub CI on Node 22.18.0 and Node 24.
Prepared and validated with AI assistance from OpenAI Codex under maintainer instructions.
Keep unmanaged detector fields when ignore-file updates the canonical detector configuration. Add a regression covering existing extension mappings.\n\nAI assistance: Codex implemented and validated this change under maintainer authorization.
Update the coordinated Vercel AI SDK stack and Playwright to their latest compatible patch releases.
Prepared and validated with AI assistance from OpenAI Codex under maintainer automation instructions.
craft is a deprecated compatibility alias, but its SKILL_CATEGORIES entry
kept it advertised in every generated SKILL.md argument-hint. Unmapping it
removes it from the hint while the alias keeps routing through the router
table and command-metadata.json.
AI-assisted change (reviewed by maintainer).
Co-authored-by: Cursor <cursoragent@cursor.com>