mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 13:46:32 +03:00
main
60
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
46ffe5caa2 |
Docs: align contributor guidance with the Rust workspace (#732)
Point runtime contributions and rule changes at crates/, document testing a rebuilt local engine, and correct the published-engine CI gate guidance. No runtime or generated provider output changes. AI assistance: prepared with Codex under maintainer pbakaus direction. |
||
|
|
87d8f6d686 |
Track the rule registry as a generated artifact (#728)
* Track the rule registry as a generated artifact `cargo xtask bundle` already wrote the registry to `dist/antipatterns.json` and into `extension/detector/`, but neither is tracked, so a consumer reading this repo from a source checkout or a tarball had no way to get the rule list without a Rust toolchain. The Rust swap made that concrete: impeccable.style imported `cli/engine/registry/antipatterns.mjs` for its rule count and its Slop catalog, and that file is gone. Write the same JSON to `crates/live/assets/antipatterns.json`, next to the in-page bundle and tracked like it, and extend `cargo xtask bundle --check` to fail when either asset is stale. The build's rule-count check now reads the tracked copy first and falls back to the extension copy, so a fresh checkout validates counts instead of skipping the check. Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY * Registry: wire the staleness gate into CI, harden the count read Two review findings on the tracked-registry change. `cargo xtask bundle --check` was never run by CI, so a rule whose name, category, or description changed without changing the rule count could ship a stale `crates/live/assets/antipatterns.json`. The extension job already runs `bun run build:extension` (and so `cargo xtask bundle`) and then asserts a clean tree; adding that file to the path list covers it with the gate that is already there. The bundle beside it stays out: its bytes carry a wasm module built by whatever wasm-pack and wasm-opt the runner installed, so diffing it would fail on toolchain drift rather than on a real change. `readDetectionRuleCount` counted `new Set(rules.map(r => r.id))`, so a shape change would collapse to a set of one `undefined` and read as a one-rule registry, flagging every count claim as stale. Count only non-empty string ids, and say "no readable antipatterns.json" when the file is present but unparseable. Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY * Registry gate: make the trigger honest, name the real count condition The tracked-registry diff check ran on every PR, but the step that regenerates the registry (`bun run build:extension`, which is `cargo xtask bundle`) only runs when the detector trigger fires, and that trigger did not list `crates/bundle`. A PR that changed how the registry is serialized therefore never rebuilt it, and the check compared the committed file against an untouched tree and passed on stale bytes. Two changes. The detector trigger now covers every input the bundle reads: `crates/(bundle|core|foundation|wasm|xtask)/` plus `crates/live/assets/` so a hand-edit of a tracked artifact is regenerated over. And the registry check moved into its own step carrying the same condition as the build it validates, so it no longer claims to check something that was never regenerated; the provider-output check stays unconditional, because `bun run build` runs on every PR. Separately, `readDetectionRuleCount` returns the reason it found no count. "no antipatterns.json" covered three different conditions, and a registry that is present but unparseable sends anyone debugging a count failure to the wrong place. It now reports the paths it looked at, or names the file that is not readable as JSON, or names the file that carries no rule ids. Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY --------- Co-authored-by: Claude Code <noreply@anthropic.com> |
||
|
|
e2ff625b63 |
The Rust engine: one binary replaces every script and the JS detector, fully open (#714)
* Add oracle harness: verb goldens and function-level vectors
Records stdout/stderr/exit/files for every impeccable verb over a fixed
corpus and replays them against an alternate implementation. Adds a loader
hook that captures per-function call vectors from the pure engine modules.
Prepared with AI assistance (Claude Code).
* Oracle: hook, hook-before-edit, hook-admin cases and goldens
Prepared with AI assistance (Claude Code).
* Add docs/CLI-CONTRACT.md: observable behavior of every impeccable verb
Prepared with AI assistance (Claude Code).
* Oracle: context/doctor/pin/surface-brief/critique/palette/embed/signals/csp/seed/genimg/question cases and goldens
Prepared with AI assistance (Claude Code).
* Oracle: live-mode cases and goldens (roots, inject, wrap, insert, accept, session, manual edits, daemon)
Prepared with AI assistance (Claude Code).
* Oracle: mask the binary path before HOME; export launcher env to the binary
Prepared with AI assistance (Claude Code).
* detect: set process.exitCode instead of exiting after the final write
process.exit() right after a large piped stdout write truncated JSON output
at the pipe buffer boundary; found by the oracle harness. Re-record the six
directory-scan goldens that had captured the truncation.
Prepared with AI assistance (Claude Code).
* Oracle: normalize the hook-admin command in both runtimes' forms and audit chars
Prepared with AI assistance (Claude Code).
* Skill text: invoke the impeccable launcher instead of node scripts
Every `node {{scripts_path}}/<name>.mjs` becomes `{{scripts_path}}/impeccable <verb>`
(context-signals -> signals, hook-admin -> hooks). Setup step 1 drops Node, points
Windows shells without sh at impeccable.cmd, and says the launcher runs a
self-contained binary. allowed-tools follows.
Prepared with AI assistance (Claude Code).
* Scripts dir: replace the Node scripts with the impeccable launcher
skill/scripts keeps command-metadata.json and the page JS; every .mjs entry
point, lib/, and live/ are gone (the binary owns those verbs). Adds the POSIX
launcher, impeccable.cmd, VERSION (copied from the new root ENGINE_VERSION),
scripts/fetch-engine.mjs (bun run fetch:engine) to pull the pinned binary
into skill/scripts/bin/<os>-<arch>/, and gitignores that bin dir.
Prepared with AI assistance (Claude Code).
* Build: ship the launcher instead of bundling the JS engine
readSourceFiles no longer copies cli/engine into the skill; the scripts
payload is the launcher (executable bit preserved through dist, plugin/, and
universal.zip), impeccable.cmd, VERSION (synced from ENGINE_VERSION on every
build), the page JS, and command-metadata.json. Hook manifests call
`<scripts>/impeccable hook` behind an existence guard (Codex adds a
commandWindows sibling calling impeccable.cmd; Cursor runs hook-before-edit;
GitHub keeps the git rev-parse form; Grok mirrors Claude); the Node probe and
systemMessage notice are gone. build:release fetches the pinned engine for
every target (lenient) and stages bin/<os-arch>/ into the dist skill copies
after root harness dirs and plugin/ were synced, so git-delivered trees stay
launcher-only. The detection-rule count check reads the vendored
extension/detector/antipatterns.json and is skipped when absent.
build:browser is a stub; the codex prefix rewrite leaves
`{{scripts_path}}/impeccable` alone.
Prepared with AI assistance (Claude Code).
* CLI: turn the impeccable npm package into a platform-binary shim
cli/engine, cli/lib, and cli/bin/commands are gone; their behavior lives in
the engine binary. cli/bin/cli.js now resolves the binary from IMPECCABLE_BIN,
the @impeccable/cli-<os>-<arch> optional dependency (templates under
cli/platform-packages/, published by the engine release), the
~/.impeccable/bin/<version>/ cache, or a checksum-verified download, and
execs it. package.json drops the engine dependencies and the library
exports; puppeteer moves to devDependencies for the icon scripts.
README.npm.md describes the shim.
Prepared with AI assistance (Claude Code).
* Tests: gate behavior on the oracle and the engine binary
Unit tests of the deleted Node scripts and the JS detector are removed;
their behavior is pinned by tests/oracle goldens (frozen JS behavior plus
reviewed deltas) and the engine's own tests. tests/oracle.test.mjs replays
the corpus against the binary (IMPECCABLE_BIN or skill/scripts/bin/<target>/,
via tests/lib/engine-bin.mjs) and skips cleanly without one; the framework
fixture sweep drives live-inject, live-wrap, and detect-csp through the
binary the same way. record.mjs learns --bin. The function-level vectors
under tests/oracle/vectors/calls are committed as the frozen snapshot they
can no longer be regenerated from. Suites: core trimmed to build and
transformer tests, oracle added to the default run, detector/live reduced to
packaging and reference checks, the live-e2e helper tests move to the opt-in
live-e2e lane pending its retarget, cli-remote-e2e is an empty placeholder.
Prepared with AI assistance (Claude Code).
* Docs: describe the launcher, the engine pin, and the oracle gate
CLAUDE.md gains an Engine binary section (launcher lookup order, ENGINE_VERSION,
untracked binaries, how tests get one, the oracle as behavior gate, what stays
JavaScript) and drops the Node-script and JS-detector descriptions; the CLI
and detection-rule sections point at the shim and the engine repo. README.md
states the skill needs no runtime and lists the launcher-based hook commands;
AGENTS.md follows. CLI-CONTRACT.md's intro notes the scripts it quotes are
the recorded source, not the tree.
Prepared with AI assistance (Claude Code).
* Tests: tighten the hook command guard assertion
Prepared with AI assistance (Claude Code).
* Oracle: re-golden 46 cases for the engine's own command names; record them in DELTAS.md
Prepared with AI assistance (Claude Code).
* Build: ship launcher-only release zips by default
IMPECCABLE_BUNDLE_ENGINE=1 opts in to staging the engine binaries into the
dist skill copies. Bundling every target into every provider copy put
dist/universal.zip near 340 MB, past the 25 MB Cloudflare Pages file cap
that impeccable install downloads through.
Prepared with AI assistance (Claude Code).
* Tests: drive the live-e2e orchestrator through the engine binary
The session, fake-agent loop, steer test, and manual-edit probe spawn
<binary> <verb> (live-server, live, live-inject, live-wrap, live-insert,
live-accept, live-poll, live-complete) resolved by tests/lib/engine-bin.mjs
instead of node skill/scripts/live-*.mjs; the completion typing the agent
imported from the deleted live/completion.mjs is a small local helper. The
live-e2e helper unit tests move back into the default live suite (the steer
loop skips without a binary).
Prepared with AI assistance (Claude Code).
* Tests: run new-work-e2e through the engine's serve-question and generate-image verbs
Prepared with AI assistance (Claude Code).
* Tests: point the skill-behavior harness at the launcher and engine binary
The bash tool exports IMPECCABLE_BIN so the staged skill's launcher runs
without a download; scenarios assert on 'impeccable context' instead of
context.mjs and skip without a binary.
Prepared with AI assistance (Claude Code).
* Tests: note what plugin-e2e validates before and after the generated-output sync
Prepared with AI assistance (Claude Code).
* Oracle: record the engine's 'wasm-unsafe-eval' CSP meta patch as a reviewed delta
Prepared with AI assistance (Claude Code).
* Rebase reconciliation: fold main's post-freeze work into the swapped tree
The rebase onto origin/main brought changes whose JS engine halves left the
tree with the swap. This commit reconciles what survives:
- Suite map: register main's comp-fidelity unit tests (build-phase,
comp-diff, font-match, hero-checks) in the core suite and
live-browser-ignores in the live suite.
- Payload guard: the skill scripts payload now allowlists the comp-fidelity
build pipeline (comp-spec/comp-diff/build-phase/font-match and their libs),
the one Node toolchain that has not moved into the engine.
- Drop skill/scripts/live/project-ignores.mjs, lib/live-path-globs.mjs, and
their test: they import hook-lib/live-inject/impeccable-paths, which the
swap deleted, and their consumer (the JS live server) is the engine now.
- skill text: the comp pipeline's calls to engine verbs (generate-image,
embed-prompt) use the launcher spelling.
- Oracle: re-record 17 detect goldens over the fixture set main changed
(oklch #592, color-mix #578, 1D grid #615, the two comp-fidelity rules)
and record the gap in DELTAS.md; those JS rule changes are not yet ported
to the engine, and the goldens pin its current behavior.
bun run test (oracle included) and bun run build are green on this tree.
AI-assisted change: implemented with Claude Code.
Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WaJv2c4oN8wS7Ttq4XRqyx
* Launcher: engine-probe PATH validation, working .cmd download path; CI: drop stale path, add oracle job
Byte-identical copies of the engine repo's launchers (engine main
af7572c): the retired 3.x npm CLI on PATH or in ~/.impeccable/bin is
rejected by the engine-probe handshake instead of hijacking every verb;
impeccable.cmd's download path is rewritten as straight-line goto flow
(the parenthesized blocks expanded %url%/%cached% at parse time, making
it dead code) with certutil sha256 verification and a windows-arm64 ->
x64 asset fallback; the final error points at the release download
instead of npm i -g (npm still serves the 3.x CLI).
ci.yml: the generated-output check no longer diffs the deleted
cli/engine/detect-antipatterns-browser.js, and a new oracle job fetches
the pinned engine (bun run fetch:engine) and replays tests/oracle/
against it. The job is continue-on-error with a loud warning until the
first engine release exists; flipping it to required is a release-time
toggle, documented in the workflow.
Verified here: sh -n on both launcher copies, bun run build green, full
oracle replay against the rebuilt engine binary green (770 pass, 0
fail), and a launcher behavior test proving a fake 3.x CLI on PATH is
skipped while the download + checksum chain completes against a local
file server.
Prepared with AI assistance (Claude Code).
* Oracle: restore detector goldens to post-fix behavior after the engine ports
The Aug 17-31 detector fixes (oklch parsing, color-mix nested hex, 1D grid
pass, comment stripping, root-relative linked stylesheets, URL userinfo
redaction, inert ignore-value refusal) and the comp-fidelity rules
organic-clip-path / buried-raster are ported to the engine. Re-records the
gap-pinning detect goldens from the fixed binary (glow.html included: its
.photo-opaque-grad column now carries the buried-raster finding it was
written for), replays the frozen checkHtmlPatterns call vectors through the
last JS engine state in history (db1462b9^; args untouched, 14 of 101
results moved), and rewrites the DELTAS gap section into the landed-ports
note. Each re-recorded json fixture golden byte-matches that JS state's
output; oracle: 770 pass, 0 fail.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WaJv2c4oN8wS7Ttq4XRqyx
* Oracle: pin the Aug 17-31 verb fixes ported to the Rust engine
New cases: hook-session-grok-edit-then-stop (Grok Build camelCase envelope,
end_turn/shutdown/stopHookActive Stop handling,
|
||
|
|
4c5243fcd4 |
Tests: stop the harness leaking live-server processes (#718)
* Tests: stop the harness leaking live-server processes
Nothing owned a live server past the exit paths JavaScript can observe. The
live unit tests spawn the server as a direct child and stop it with an HTTP
/stop plus proc.kill() inside an after() hook; the e2e session and the
target-context tests boot it through `live-server --background` / live.mjs,
which spawns a detached, unref'd daemon that only the `stop` verb ever ends.
A POSIX child does not die with its parent, and a detached daemon is orphaned
to pid 1 from birth, so any exit that skipped teardown (a node:test timeout, a
SIGKILL of the runner, a Ctrl-C, an assertion that threw before the hook) left
the server listening on a fixed live-suite port for good. scripts/run-tests.mjs
did not compensate: it used blocking spawnSync, so no signal handler could run;
it left suite commands in its own process group with nothing that could kill
that group; and it never checked afterwards whether anything survived. Days of
local runs accumulated 197 orphans on one machine, the oldest four days old,
until `bun run test:live` could not claim its ports.
The fix is structural rather than a cleanup sweep bolted on the end, and it is
deliberately implementation-agnostic so it holds for the Node scripts here and
for the Rust `impeccable live-server` on rust-swap:
- tests/lib/live-servers.mjs. armLiveServerReaper(), called once at module
scope by every test file that starts a server, stamps the process env with a
unique marker, installs exit and signal handlers, and spawns a detached
reaper holding a pipe to the process. SIGKILL the process and the pipe closes,
the reaper wakes on EOF and kills the servers carrying that marker. That is
the one case no in-process cleanup can reach. trackServerChild() also
registers direct children (live servers and fixture dev servers) so the
ordinary exits are a cheap kill by handle.
- scripts/lib/live-server-processes.mjs. The scan and kill primitives, shared
by the reaper and the runner. Processes are matched by the environment marker
the harness exported, never by name or port, so a sweep can only ever reach a
server this repo's tests started.
- scripts/run-tests.mjs. Each suite command now runs as its own process-group
leader with SIGINT/SIGTERM/SIGHUP forwarded to the group, and after every
suite the runner checks for live servers carrying that suite's run id. A
survivor is killed and fails the run, so the next leak surfaces in the run
that caused it instead of on a laptop days later. IMPECCABLE_SKIP_LEAK_CHECK=1
bypasses it. `bun run test:cleanup` sweeps leftovers from earlier runs.
- tests/live-server-leak.test.mjs pins the guarantee: it boots a real server
under a process it then SIGKILLs, and fails if the server outlives it. With
IMPECCABLE_NO_TEST_REAPER=1 the test fails, which is what makes it a
regression test rather than a tautology.
Verified: bun run test:live green with zero survivors; scoped live-e2e
(vite8-react-plain) matches pristine main test for test; the SIGKILL repro goes
from 2 orphans to 0; SIGINT and SIGKILL of the runner itself both leave nothing
behind; bun run build green.
Fixes #717
AI assistance: prepared by Claude Code under pbakaus's direction.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
* Review fixes: scope the sweep to whole env entries only
Five review findings on #718, all in the matching layer that decides which
processes a sweep may touch.
The repository-path fallback is gone (Greptile P1). `bun run test:cleanup`
passed REPO_ROOT to findLiveServers, which then also matched any live-server
command line under the checkout, marker or not. A developer running
`impeccable live` in this repo has exactly that command line, so the cleanup
could have killed their own session. The PR promised matching on the exported
environment marker and nothing else; now it does. The cost is that a server
from a run predating the marker is no longer found and has to be killed by
hand, which is the right trade.
Environment entries are compared whole on macOS and BSD (Greptile P1). `ps -E`
flattens the environment into the command column, and that line was searched
with a plain substring test, so IMPECCABLE_TEST_REPO=/work/impeccable also
matched /work/impeccable-copy and one checkout's cleanup could reach a
neighbouring checkout's servers. envLineHasEntry() now requires the marker to
start an entry (line start or whitespace) and to end one (line end, or
whitespace followed by the next KEY=), which is the same whole-entry
comparison the Linux /proc branch already did. Six unit tests cover it,
including the adjacent-path negative case, and a live probe against real
`ps -E` output confirms an exact repo matches while /work/impeccable-copy and
a run-id prefix do not.
The SIGKILL regression test now skips on win32 with a stated reason (Copilot).
The reaper is a POSIX mechanism and armLiveServerReaper() does not arm it
there, so the test asserted a guarantee Windows does not make yet.
Signal exits use the shell convention 128 + signum in both the runner and the
test helper (Copilot, two threads). SIGHUP returned 143; it is 129. Read from
os.constants.signals rather than a hand-written table.
Verified: leak test 7/7 (2 guard, 5 matcher); bun run test:live 895 tests, 0
fail, 0 survivors; scoped live-e2e (vite8-react-plain) 3 pass / 1 fail,
matching pristine main; SIGKILL repro 3 servers up, 0 after; bun run build
green.
AI assistance: prepared by Claude Code under pbakaus's direction.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
* Review fix: make marker values opaque so the matcher has no ambiguous case
Greptile's follow-up P1 on the parser was right, and the parser was the wrong
place to answer it. envLineHasEntry ended an entry at "whitespace followed by
the next KEY=", so a checkout path that extended another one with whitespace
plus a KEY=-shaped token still defeated it, which is exactly the ambiguity the
docblock admitted to. A format that cannot be parsed unambiguously should not
be handed ambiguous input.
So the fix is at the source: no marker value is a path any more. IMPECCABLE_TEST_REPO
now carries repoMarker(), the first 16 hex characters of the sha256 of the
checkout's real path, and the runner and the cleanup command both compute it
the same way from REPO_ROOT. Two checkouts whose paths share a prefix get
unrelated hashes, so a substring cannot arise in the first place, and every
spelling of one checkout (trailing slash, `.` segment, symlink, /private
prefix) resolves to one marker. The run id is now repoMarker plus 8 random
bytes of hex, and the process id p<pid> plus the same, both from a
whitespace-free alphabet.
With every value fixed-alphabet, envLineHasEntry needs only "starts an entry
and ends at whitespace or line end". The KEY= lookahead is gone and so is the
documented unresolvable case. assertMarkerValue keeps the invariant honest: it
refuses any value outside [A-Za-z0-9_-] with a message that says to hash it,
so a future caller that passes a path gets a loud error instead of a silent
mismatch. The readable path is still available for a human reading `ps -E`
output, exported separately as IMPECCABLE_TEST_REPO_PATH, which nothing
matches on and the docblock says so.
Matcher tests: the space-in-value case is gone, since that value can no longer
exist. Added a strict-prefix case (a longer hash-shaped value starting with the
marker), an adjacent-checkout case asserting the two hashes do not even share a
prefix, a symlink/trailing-slash case against real directories, an alphabet
check on all three generators, and one asserting assertMarkerValue throws.
Verified: leak test 10/10; bun run test:live 898 tests, 0 fail, 0 survivors;
scoped live-e2e (vite8-react-plain) 3 pass / 1 fail, matching pristine main;
SIGKILL repro 1 server up, 0 after; bun run build green. A probe against real
`ps -E` output with a hashed marker: this checkout 1 match, its trailing-slash
spelling 1, an adjacent checkout 0, exact run id 1, a run-id prefix 0.
AI assistance: prepared by Claude Code under pbakaus's direction.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
* Review fixes: async group shutdown, and a Windows-safe symlink test
Two Cursor Bugbot findings, both real.
killCurrentGroup busy-waited on alive(child.pid) after sending SIGTERM, which
could never work. A dead child stays a zombie until its parent reaps it, the
parent here is the runner, and the runner reaps through libuv when the event
loop runs. The spin blocked the very loop that would have done the reaping and
then read the unreaped zombie as alive, so every SIGINT, SIGTERM and SIGHUP
burned the full 2s grace and ended in a needless SIGKILL. There is no waitpid
from JavaScript that sees through this, so the wait is now asynchronous and
keyed on the child's own exit event. The logic moved to
scripts/lib/process-group.mjs: trackChildExit exposes the exit as a flag and a
promise, stopGroup races that promise against the grace period and escalates to
SIGKILL only if it loses, and killGroupSync stays synchronous for
process.on('exit'), where nothing can be awaited, so it sends SIGTERM then
SIGKILL without pretending to wait. A second Ctrl-C now skips the grace period
entirely rather than queueing behind it.
Measured on a real SIGINT to a running live suite: 2027ms before, 34ms after.
tests/process-group.test.mjs pins both halves, including the escalation path
against a child that traps SIGTERM, which is not otherwise reachable from a
registered suite.
The repoMarker symlink test called symlinkSync with no type, which throws EPERM
on Windows without Developer Mode. It now passes 'junction' there and 'dir'
elsewhere, the same shape tests/concept-seed.test.mjs uses, and the
trailing-slash and dot-segment cases split into their own test so they keep
running on every platform regardless.
Merged origin/main (through #716) to re-level the branch.
Verified: leak and process-group tests 16/16; bun run test:live 900 tests, 0
fail, 0 survivors; scoped live-e2e (vite8-react-plain) now 4/4, with the
orphaned-session test that #716 fixed passing in 7.2s; bun run build green.
AI assistance: prepared by Claude Code under pbakaus's direction.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
* Review fix: a second Ctrl-C must reach the group the first one is stopping
Cursor Bugbot caught a bug I introduced with the async shutdown, and it is the
same class of leak this PR exists to close. The signal handler cleared
currentChild before awaiting stopGroup, so a second Ctrl-C read a null handle:
killGroupSync did nothing, process.exit walked away from the SIGKILL escalation
still in flight, and because the suite is spawned detached it kept running
after the runner was gone. Impatience with a stuck suite produced exactly the
orphan the change is supposed to prevent.
The shutdown state machine moved into scripts/lib/process-group.mjs as
createGroupShutdown, which holds the group in `stopping` for as long as it is
being ended rather than dropping the only reference to it. A second signal
kills that handle and leaves; process.on('exit') looks at `current` or
`stopping`, so the last-resort path reaches a group mid-shutdown too. The
runner keeps no shutdown state of its own now, which is what made the bug
possible to write in the first place.
The extraction is what makes it testable: `exit` is injectable, so
tests/process-group.test.mjs can drive two signals at a stubborn child that
traps SIGTERM and assert the group dies in under 2s against a 30s grace. Point
that test at the old logic (killGroupSync on the cleared reference) and it
hangs out the full grace and fails, which is the check that it pins something
real. Five cases in all, including the exit-handler path and the no-child case.
Verified: process-group 10/10, live-server-leak 11/11; real double SIGINT to a
running live suite exits in 24ms with zero group members and zero servers left;
bun run test:live 900 tests, 0 fail, 0 survivors; scoped live-e2e
(vite8-react-plain) 4/4; bun run build green.
The core suite wedged twice locally in tests/build-phase.test.mjs, the
pre-existing unbounded-spawnSync hang noted in the PR description that
rust-swap's
|
||
|
|
121602079c |
Deliver the report as its own step; retune the lineup
Two failures the trace test found were structural, not model quirks. critique.md described the report's format and then went straight to writing a temp file, with no step saying to output the report. gemini-3.6-flash and luna both responded by bundling heredoc, snapshot write, trend read, and cleanup into one bash call and stopping, leaving a perfect archive nobody had read. A "Deliver the Report" step now precedes persistence, and persistence describes itself as a copy of what was already sent. gemini-3.6-flash failed three consecutive runs before this and its failures afterward all show the report reaching chat. The close is also step 6 of the persistence list rather than a section after it, since the same shape is what fixed delivery. Lineup: gpt-5.6-luna and deepseek-v4-flash out, gpt-5.6-terra in at reasoningEffort high (IMPECCABLE_SKILL_BEHAVIOR_EFFORT overrides), gemini 3.5 to 3.6. Provider options resolve from the model object inside the harness so the 21 runTurn call sites are untouched. Verified the effort actually reaches the API rather than being silently dropped. The Gemini bump was not cosmetic: 3.5-flash passed critique closes twice and 3.6-flash then failed three times against identical text. A version bump inside one family changed the outcome, so the README now treats cross-version carryover as unmeasured. Known floor, recorded: critique closes is flaky on gemini-3.6-flash, 1 run in 3. Two structural attempts moved it from consistently failing to intermittently passing and then stopped paying. claude-sonnet-5 and gpt-5.6-terra are clean. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
667095d216 |
Harden the test strategy: self-verifying triggers, 40% faster runner, release guards (#501)
* 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> |
||
|
|
6d2af3f800 |
Guard the plugin loader contract that PR #494 exposed (#499)
* 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> |
||
|
|
5f4b58d06d |
Merge pull request #433 from pbakaus/live-v2-rewrite
Live v2: root manifest, mount-ack protocol, AST scaffolder, mechanical accept |
||
|
|
26f54d15c2 |
feat: just-in-time event instructions + frontier default for the LLM e2e agent
Field feedback from two more Codex sessions drove both changes.
JIT instructions (live/instructions.mjs): every event live-poll prints
now carries _instructions, the authoritative next step for that exact
situation with real ids, paths, and line numbers substituted, and only
the active path's rules (a svelte-component session never sees JSX
guidance). The boot payload carries loop instructions the same way.
Instructions are versioned with the scripts, so they cannot drift from
behavior, and live.md's plumbing can keep shrinking toward contract plus
craft guidance. The Codex poll-discipline failure observed in the field
("the long poll was started, but I yielded the task instead of actively
servicing its result") gets a named anti-pattern in both the harness
policy and the boot instructions.
LLM e2e agent: default provider/model moves from Claude Haiku 4.5 to
OpenAI gpt-5.6-terra at medium reasoning effort via an Anthropic-shaped
shim over the ai SDK (the three call sites stay provider-agnostic;
Anthropic and DeepSeek remain selectable). The harness should exercise
the model tier that actually drives live sessions. Both the react and
sveltekit fixtures pass end to end with terra driving the trimmed
live.md and the new _instructions.
This work was produced with AI assistance (Claude Code).
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
||
|
|
690e24129a |
CLAUDE.md: the rule engine is a facade now; drop the dead line numbers
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
17dabf4b7e |
Live v2: root manifest, mount-ack protocol, AST scaffolder, mechanical accept
A ground-up hardening of live mode, driven by a production session in a nested-app monorepo that hit six distinct failure classes. Full design rationale in docs/LIVE-REWRITE-PLAN.md; every Codex-reported failure now has a mechanical fix and a regression test. Roots: live/roots.mjs resolves appRoot/repoRoot/contextRoot once at boot (keyed on dev-server configs, not monorepo brand markers), persists a manifest, and every live CLI re-anchors onto it at startup, so a helper run from the wrong directory can no longer fork session state. Context files are discovered upward to the git root. Render truth: variant_mounted / variant_mount_failed events give the journal per-variant mount state; failures reach the agent's poll queue, raise a persistent error card with Retry (no more localStorage wipe), and an attach probe names root/dev-server mismatches explicitly. The browser rehydrates from the server when localStorage is gone. Svelte: the scaffolder now parses with the app's own svelte 5 compiler. Control flow survives (an each collection crosses the contract as one structured prop), keyed each blocks hydrate synthetic keys, and anything a detached preview cannot support falls back to source-preview instead of shipping a wrong scaffold. Preview modules live in per-publish revision directories, defeating stale transform caches. Accept: CSS is reconciled, not appended. Matching selectors are replaced, params bake from params.json kinds, the compiler's unused-selector pass prunes superseded rules (pre-existing dead rules protected), a selector- loss postcondition refuses any write that would drop hand-written rules, and live-complete refuses to finish while live plumbing remains in source. Also: framework registry (live/frameworks/) with a crash-safe injection journal, session-store snapshot caching with read-only reads, protocol enum consolidation, steer Send button, honest DESIGN-panel empty states. Testing: new unit suites (roots, AST scaffolder, accept CSS, accept pipeline, framework conformance); e2e now fails on preview-tree 404s, proves computed-style mount for every variant, drives the Tune panel through baked params, and injects failures (broken mounts, republish, storage loss). New runtime fixtures: monorepo-nested-vite (repo root != app root) and vite8-sveltekit-stateful (each blocks + state). Nightly full-matrix cron. An independent adversarial review pass preceded this commit; its blocker and major findings are fixed and regression-tested. This work was produced with AI assistance (Claude Code). Co-Authored-By: Claude Code <noreply@anthropic.com> |
||
|
|
5575a027dc |
Flag and repair drift in Impeccable's own project artifacts
v4 changed PRODUCT.md's shape and retired the register axis, so an upgraded project can carry answers nothing reads. Nothing measured that. Two tiers, and the split is a performance contract: - Boot (context.mjs, emitting CONTEXT_STALE) spends only what a boot already spends: markdown already in memory, a bounded set of stats, the small JSON files the boot reads anyway. No new directory walks. One directive for the whole set, throttled to once a week per project so a finding the user declined does not reappear tomorrow. - doctor.mjs runs the deep pass on demand: git drift, ignore lists validated against the live rule registry, hook script paths that stop resolving, and the monorepo workspace sweep. --fix applies only the migrations that carry no decision. Findings are data, not prose, so the boot directive, the text report and --json all render one set. Severity says what should happen: auto (fix on the next write anyway), mention (state once), route (name the command that owns the repair). PRODUCT.md now carries a schema stamp so the checks stop reconstructing a file's vintage from which sections it happens to have. Schema version, not release version: a record written by 4.0.0 is not stale under 4.0.1. DESIGN.md gets no stamp, because it follows the external design.md spec that Stitch lints and every DESIGN.md signal is measurable without one. The highest-value catch is a project that resolves to web while carrying native build files, including a monorepo app inheriting a root record that says web. That one costs output quality silently; nothing failed before. doctor follows the hooks/pin pattern rather than the Commands table, so it stays out of the design menu and the count stays at 23. Also corrects CLAUDE.md, which still documented the register axis, reference/brand.md, reference/product.md, eleven deleted domain reference files, and an extractRegister() whose only occurrence in the repo was that sentence. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
d7d10277d1 |
Merge main into oneshot-v4, keeping the service layer split out
main still carries the site, so every `site/` path resolves to deleted. `tests/docs-integrity.test.js` goes with it (it imports the site's demo renderer), and `package.json` keeps main's `@anthropic-ai/sdk` bump while dropping `@google/genai` and `@paper-design/shaders`, which nothing in the product layer imports. Real code merges: - hook-lib: main's #391 cache fix (sync the remembered set to the live scan so fixed findings stop being named and a reintroduced one fires again) now runs on the immediate tier rather than the whole filtered set. Remembering a deferred finding the per-edit pass never reported would let the Stop deep pass dedupe it away. main's `maxFileBytes` ceiling, `cleanAcked` once-per-file ack, and template-extensions re-export all land alongside the tiering work. - live-browser: main's `hasParams` gate on the Tune badge, keeping this branch's `C.ink` badge text so it stays legible on kinpaku gold. - detect-text: both the block-level codex-grid-background scan and main's inset-stripe CSS check. - test-suites: union of both trigger sets and file lists, minus the site-only entries (`shiki-theme`, `docs-integrity`). - Two hook tests moved off deferred-tier rules (`overused-font`, `side-tab`) onto immediate-tier ones. They assert cache bookkeeping, which the per-edit pass only reaches for the immediate tier. Also drops the site waivers from `.impeccable/config.json` and stops `build:browser` recreating a stray `site/` tree just to write a bundle the other repo builds itself. Co-Authored-By: Claude <noreply@anthropic.com> |
||
|
|
90f9eeb99b |
Split service layer into private impeccable-site repo
The public repo keeps the OSS promise surface: skill, CLI, extension, tests, and the provider build. The site, labs, concept/composition catalogs, image pipeline, Cloudflare functions, and authoring guide move to pbakaus/impeccable-site. concept-seed tests run against a synthetic fixture catalog; the plugin icon and skill categories moved in-repo; build validation narrows to README prose and non-site counts; release notes read from a sibling impeccable-site checkout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7557935fdb |
Expand concept system: modes, ratings, re-roll, breadth strategy
Catalog: mode-aligned staging surfaces (persuade/operate/read/experience), star ratings on approvals feeding challenger draw weights, family retirements, authoring strategy and territory guide, rework and breadth authoring rounds, composition mining from rejected worlds. Seed: six challengers (two per tier), --reroll chains, --mode staging filter, rating-weighted draws. New-work: Present/visualize/re-roll flow, image-gen requirement, register-neutral vocabulary. Pipeline: per-mode staging prompts with split frames, hero-from-board reference generation, render-safety guards. Labs: ratings UI, unrated filter, mode chips, composition approve-guard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7ff8f9216e |
Docs: correct the prose-gate description, ban version bumps in feature PRs (#380)
Two documentation fixes, no code. CLAUDE.md claimed `validateProse` "deliberately skips skill/". Half true, and misleading in the direction that costs a build: `validateProse` does skip it, but `validateSkillProse` then scans `skill/**/*.md` and fails the build on em dashes plus the subset of phrases with no technical reading. An em dash in skill/reference/*.md fails `bun run build` today, which the old text said would not happen. Verified the replacement against build.js: scan roots, extensions, the site/pages/slop exemption, and the enforced phrase list all match. AGENTS.md had no rule about versioning in feature PRs, so both agents and humans kept bumping manifests alongside the change. A version in a feature branch conflicts with every other open branch, and a changelog entry describes a release that has not happened. State the rule where the PR conventions already live, and note in CLAUDE.md that the existing "Bump when: ..." lines say which component a change belongs to, not when to edit the manifest. Assisted-by: Claude Code |
||
|
|
c11cc7b58c |
Route native projects to native command variants (audit, adapt) (#357)
* Route native projects to native command variants for audit and adapt Follow-up to #269. The web audit.md and adapt.md carried "translate this yourself" Platform notes, so a native invocation paid for the full web file (~1.8k / ~2.6k tokens, mostly inapplicable) and did error-prone run-time translation. Authored with AI assistance (Claude Code) under maintainer direction. - New reference/audit.native.md and reference/adapt.native.md: authored native content (VoiceOver/TalkBack, platform conformance, adaptivity dimensions; phone-to-tablet, platform-to-platform, web-to-native strategies). One variant per command covers ios, android, and adaptive; per-OS specifics stay in the platform refs Setup loads regardless. - SKILL.src.md: Commands table lists the variants; Setup step 2 reads the variant instead of the web file when the platform is native. - audit.md / adapt.md: Platform sections replaced with a one-line web-only guard pointing at the variant. - animate.md / layout.md: Platform sections deleted; the Motion and Layout sections of the already-loaded platform refs carry that content. Web users now pay zero tokens for the platform axis in these files. - Skill-behavior scenario 15 pins the route-instead behavior (passes live on claude-sonnet-4-6); CLAUDE.md documents the variant convention. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Phrase command-reference routing as one rule, not rule-plus-exception Copilot review catch: step 2 said "MUST read reference/<command>.md" and then carved out the native variant, which invites loading both files. Now a single rule: read the web reference or the table's native variant, one file, not both. Scenario 15 re-verified live. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Anchor native runs in animate/layout, drop loaded-refs assumption Review-thread fixes, applied with AI assistance (Claude Code) under maintainer direction: - Greptile: deleting the animate/layout Platform sections left native runs alone with web tooling instructions (CSS keyframes, GSAP, Grid, clamp()). Restore a one-line anchor in each pointing at the loaded platform reference's Motion / Layout section (~20 tokens, not the old restatements). - Bugbot: audit.native.md and adapt.native.md asserted the platform refs were "already loaded in Setup", but the command reference loads at step 2, before step 5. Now they instruct: read the platform reference first if Setup hasn't already. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Carry the native-variant rule into routing rules 2 and 3 Bugbot catch: Setup step 2 routed native projects to the variant, but routing rules 2 and 3 (the operative text at command time) still said to load the generic reference file. Both now reference the same one-file variant rule. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Point animate/layout native anchors at the files, not "loaded" refs Bugbot catch, same class as the variant wording fix: the anchor lines said "the loaded platform reference" but command files load at step 2, before the platform refs at step 5. Both anchors now name the files and instruct reading them first if Setup hasn't already. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
3e38e595c7 |
Add platform axis (web / ios / android / adaptive) (#269)
* Add a platform axis (web / ios / android / adaptive) to the skill Orthogonal to register: register decides whether design IS or SERVES the product; platform decides the delivery target and which native conventions apply. Set `## Platform` in PRODUCT.md; a missing field defaults to `web`, so legacy projects are unaffected. - extractPlatform() in skill/scripts/context.mjs (mirrors extractRegister); the CLI appends a NEXT STEP directive to read the native reference(s). `adaptive` (Flutter / RN / KMP shipping both iOS and Android) loads both ios.md and android.md. - New reference/ios.md (Apple HIG distilled) and reference/android.md (Material 3 distilled); reference/web.md is a thin pointer. The native refs frame register's role as narrow: platform conformance is the bar, brand lives in the expressive layer the platform gives you, never by breaking the rails. - Setup step 5 loads the native reference(s) when platform is native. Live mode and the detect CLI stay web-only, gated off ios/android/adaptive. - init asks platform right after register; adapt/audit/animate/layout carry short platform divergence notes; all secondary spots thread `adaptive`. - a11y stays in audit.md (loading it at design time makes output timid), so the native refs carry no Accessibility section; audit.md's Platform section owns native a11y. - Tests: extractPlatform unit coverage + skill-behavior scenario 10 (PRODUCT.md platform ios -> agent loads ios.md). Source-first: only skill/, scripts/, tests/, CLAUDE.md, NOTICE.md, the changelog and version are committed; the sync workflow regenerates the provider trees and ./plugin on merge. ios.md / android.md are distilled from the MIT-licensed ehmo/platform-design-skills; attribution in NOTICE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Address review: gate web tools on native platforms, drop version churn Maintainer-review fixes applied with AI assistance (Claude Code), on top of the rebased platform-axis commit: - Design hook (post-edit and Cursor pre-edit) now resolves the project platform via loadContext + extractPlatform and skips its web rule scan for ios / android / adaptive projects, so React Native / Flutter code never draws web-shaped findings (new hook-lib resolveProjectPlatform / isNativePlatform helpers, covered by unit and subprocess tests). - context.mjs CLI warns on an unrecognized ## Platform value (e.g. a toolchain name like `flutter`) instead of silently defaulting to web; extractRegister / extractPlatform now share extractSectionValue. - Removed reference/web.md: nothing loaded it; CLAUDE.md carries the "web has no extra rulebook" explanation. - init.md: skip live-mode config (Step 6) for native platforms; note the per-app PRODUCT.md pattern for repos shipping web + native. - android.md: Material-everywhere apps that also ship on iPhone still owe iOS OS guarantees (safe areas, Reduce Motion, edge-swipe back). - ios.md: reworded a design-time line that framed Dynamic Type as an accessibility check (a11y stays owned by audit.md). - Renumbered the new skill-behavior scenario to 14 after main's 10-13; updated CLAUDE.md scenario list; added android + unrecognized-value CLI test cases. - No version or changelog changes: versioning happens at release time. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Tighten platform reference prose Editorial pass on the platform-axis text, applied with AI assistance (Claude Code) under maintainer direction: - ios.md / android.md rewritten to house style: single-line paragraphs (no hard wraps), one-sentence scope intro, deduplicated intro/slop-test, register-compression down to two sentences. In-file attribution paragraphs removed (NOTICE.md owns attribution); "read on top of the register reference" cruft removed (SKILL step 5 and the context.mjs directive already say it). Bans sections dropped: they restated the rules above them; the two additive items (tab-bar overload, hover-dependent affordances) folded into rules. ~40% smaller each. - Sub-command Platform sections (adapt, audit, animate, layout), SKILL step 5, init.md platform prose, and the context.mjs directive trimmed the same way. Build (prose validators, counts) and both test runners green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Treat an empty PRODUCT.md section as absent, not the next heading Copilot review catch: extractSectionValue read the next `## ...` heading as the section value when a field was left empty, which made the CLI warn "value `## Product Purpose` is not recognized". Stop at the next heading and return null instead. Regression tests for extractPlatform, extractRegister, and the CLI warning path. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Only read a token list of both native targets as adaptive Bugbot catch: after the exact platform tokens failed, any Platform line containing the words ios and android was classified adaptive, so negated or explanatory prose ("web only, not ios or android") silently loaded both native refs and skipped the hook, with no warning. The combo parse now accepts only list separators and the two platform words; anything else falls through to the CLI's unrecognized-value WARNING. Regression tests added. Applied with AI assistance (Claude Code) under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com> |
||
|
|
0417d2014e | Add issue-first contribution guardrails (#353) | ||
|
|
e83e437cdd |
Release prep: skill v3.9.0, CLI v3.2.0
Bump skill 3.8.0 -> 3.9.0 (plugin.json, marketplace.json, plugin/ subtree, regenerated provider harness output) and CLI 3.1.0 -> 3.2.0 (package.json). Changelog (site/pages/changelog.astro): - Skill v3.9.0: codex grid-background ban, /impeccable bolder design-system lock, critique sub-agent independence on non-Claude/Codex harnesses, bundled helpers under strict-permission harnesses, Codex hook manifest fix. - CLI v3.2.0: codex-grid-background detector rule, external skills-symlink preservation on first install. Also: gitignore nested hook.cache.json/hook.pending.json copies (anchored patterns missed the generated harness dirs), and repoint CLAUDE.md/AGENTS.md changelog docs at changelog.astro with concise, user-facing-only tone guidance. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
793feda5a0 |
Guard plugin/skill version drift in the build (issue #274) (#278)
* Guard plugin/skill version drift in the build (issue #274) The Claude Code marketplace installs from the committed ./plugin subtree, so a version disagreement between the hand-edited manifests and the generated subtree ships stale content under a wrong version. This is the class of bug reported in #274: a version bump that doesn't regenerate ./plugin (e.g. PR #252, where root plugin.json was 3.7.0 while plugin/.claude-plugin/plugin.json was still 3.6.0) merges a drift window onto main, and marketplace/Cowork installs pull the stale subtree. Add a build-time validator that treats root .claude-plugin/plugin.json as the source of truth and fails the build if any of these disagree: - .claude-plugin/marketplace.json plugins[0].version (hand-edited; the post-merge sync workflow never bumps versions, so it can't repair a mismatch here) - plugin/.claude-plugin/plugin.json version (generated subtree) - plugin/skills/impeccable/SKILL.md frontmatter version (bundled skill) It only fires on an inconsistent bump; PRs that don't touch versions keep every file in agreement and stay silent. The pure comparison lives in scripts/lib/validate-plugin-versions.js with direct unit coverage; build.js owns the logging and the non-zero exit. Documents the regenerate-on-bump step in CLAUDE.md's Versioning section. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Harden version-drift collector against malformed/incomplete manifests Address Greptile review on #278: - Wrap every file read/parse in a sentinel helper (extractFromFile) so a half-edited manifest — the exact state during a version bump — yields a clean "could not parse (...)" diagnostic naming the file instead of a raw JSON.parse stack trace out of build(). - Report a present-but-malformed root plugin.json, or one missing its `version` field, as an explicit error. Previously `undefined` version short-circuited the build wrapper's `source == null` guard and passed silently. collectPluginVersions now returns an `errors` array; build.js fails on errors + mismatches combined, and only the genuinely-absent root manifest is a no-op skip. Adds 4 unit tests: malformed checked manifest, malformed root, missing version field, and the absent-root no-errors case. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Make SKILL.md frontmatter version read CRLF-tolerant Address Cursor Bugbot review on #278: readSkillFrontmatterVersion only matched `\n` delimiters, while the shared parseFrontmatter in scripts/lib/utils.js accepts `\r?\n`. A bundled SKILL.md saved with CRLF line endings would parse to a null version and trip a false mismatch against root plugin.json even when the version line is correct. Match the shared parser's `\r?\n` tolerance and drop the `$` anchor on the version line (it would not match before a `\r`). Adds CRLF coverage for both readSkillFrontmatterVersion and collectPluginVersions. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Re-trigger CI (no file change) CI did not fire for 5cda9f6b; force a fresh run on the current tree. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
324cec73a4 | Reorganize contributor docs | ||
|
|
05f9797957 | Remove deprecated cleanup migration (#240) | ||
|
|
325aeaf239 | Organize skill script support modules | ||
|
|
972f5b18be | Improve generated output sync workflow | ||
|
|
92b744beb0 |
feat(site): new Neo Kinpaku social card, sitewide OG default
Replaces the retired light/magenta OG card with a brand-true Kinpaku card (lacquer ground, champagne Alumni Sans headline, kinpaku-gold accent, kintsugi-seam art). Headline: "Design fluency for every AI harness." Command count is read live from command-metadata.json. - scripts/generate-og-image.js: rewritten to render the Kinpaku card via Playwright at 2x and downscale with sharp; outputs og-image-v2.jpg - Base.astro: emit og:image + summary_large_image on every page with a sitewide default (was homepage-only); pages override via ogImage prop - og-image.jpg renamed to og-image-v2.jpg for cache-busting; index.astro reference updated - CLAUDE.md: document `bun run og-image` regeneration + cache-bust steps - .gitignore: ignore .og-build scratch Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
9ffd3211d5 |
Neo Kinpaku design system + Live Mode v3 (#169)
* Add neo kinpaku design system page * skill: rip out baked-in category recipes and saturated-default motion tropes Programmatic bias mining (impeccable-evals) traced four major defects back to specific lines in this skill that contradicted SKILL.md's own first-order-reflex warning: - brand.md "Pairing and voice" prescribed four category→aesthetic recipes (editorial → serif+sans, tech/dev/fintech → tight tracking, consumer/food/travel → script/display serif, creative → rule-break). These directly drove OpenAI's 76% extreme-negative letter-spacing on tech briefs and Anthropic/Google's 28-34% italic-serif-display slop on editorial/food briefs. Replaced with one sentence: the shape depends on the brand, not on the brand's category. - brand.md "Brand permissions" had "Typographic risk. Enormous display type, unexpected italic cuts, mixed cases, hand-drawn headlines, a single oversize word as a hero." — a four-for-one slop driver behind 97% OpenAI comically-large H1, 42% bad-SVG illustration, and the editorial-italic slop. Deleted outright. - typeset.md and teach.md repeated the same category recipes; trimmed to the principle without the recipe. - SKILL.md Typography: added a hard hero-H1 ceiling (clamp() max ≤ 6rem ≈ 96px), with a <codex> block to make it explicit since OpenAI over-indexes here (97% ≥128px vs 24% for Anthropic). - animate.md, bolder.md, brand.md: removed "staggered reveals" and "scroll-triggered transitions" as the prescribed default ambitious motion. By 2026 that's the saturated AI tell, not a choreography. Reserved stagger for legitimate list-sibling rhythm. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: anti-cream + codex-specific defect bans + universal slop bans Second pass after measuring more biases against the eval corpus. - SKILL.md Color: explicit "cream/sand/beige body bg is the saturated AI default of 2026" rule. Tone down the "tint every neutral" line so it doesn't read as "default to warm-tinted near-white" (which OpenAI hits at 74% and Anthropic at 31%-47%). - SKILL.md Absolute bans: add universal bans for two slop patterns detected at 55-95% across providers — tiny uppercase tracked eyebrow above every section (the 2023-era kicker that's now AI grammar) and numbered section markers (01/02/03). Also explicit "text that overflows its container is the universal defect on tablet/mobile." - SKILL.md Absolute bans → <codex> block: ban the GPT-specific defects Paul annotated repeatedly — `border:1px solid` + soft-wide-shadow (≥16px blur) "ghost cards", `border-radius:32px+` over-rounding, hand-drawn/sketchy SVG illustrations (loose-sketch / *-sketch classes, feTurbulence paper-grain filters), repeating-linear-gradient stripes, "X theater" AI-slop copy phrases. - SKILL.md Motion → <gemini> block: the image :hover transform tell (38% Google skill-on rate). Hover effects on images add no info; the image isn't an action target. Animate card chrome, not the image. - SKILL.md Typography: hard display letter-spacing floor ≥-0.04em (OpenAI defaults to -0.075em → cramped). Existing hero ceiling <codex> block extended with the letter-spacing rule. - codex.md Step A example: stop seeding "warm-grounded (deep oxblood + cream)" as the warm-palette template, which primes the cream default. - colorize.md Tinted backgrounds: stop printing the literal cream recipe `oklch(97% 0.01 60)`; replace with brand-anchored guidance. - document.md examples: warm-ash-cream → cool-paper so the example doesn't seed cream as the canonical neutral example. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: universal anti-slop bans + contrast/font-count/all-caps-body rules Third pass after measuring the rest of the cross-provider matrix: - Color: explicit "Verify contrast" rule. Low-contrast text fires at 68% across all providers skill-on (90+% off). The most common failure is muted gray body on a tinted near-white; light-gray-for- elegance is named as the single biggest cause of unreadable AI pages. - Typography: max-3-font-families rule. Overused-fonts (>4 families) fires at 28% Anthropic / 36% Google / 0% OpenAI skill-on; >50% off. Also: universal "no all-caps body copy" (moved from brand-only ban to Shared design laws since product-register also overuses caps). - Copy: anti-aphoristic-cadence ban targets Anthropic's signature "X. No Y." / "X. Just Y." voice (63% skill-on copy-slop rate, 77% off — the worst rate in the matrix). Once-is-voice / three-or-more- is-tell framing per the runner's copy-slop detector. - Copy: anti-SaaS-buzzword-string ban with the literal phrase list the detector watches for (streamline/empower/supercharge, trusted- by-leading, best-in-class/enterprise-grade/cutting-edge, etc). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: strengthen anti-cream rule across full warm-neutral band Smoke validation showed the cream fix worked for Google + OpenAI but Anthropic Sonnet italian-restaurant still shipped `--paper: oklch(90% .018 88)` — cream just outside the L≥95% band the rule cited. Broaden the rule: - Band: OKLCH L 0.84-0.97, C < 0.06, hue 40-100 (was 95-97% / 60-95). - Name the token-name tells explicitly (paper / cream / sand / bone / flour / linen / parchment / wheat / biscuit / ivory) — the model defaults to one of these regardless of what hex it lands on. - Call out the specific brief patterns ("warm, traditional, family- coastal-Italian" / "editorial-restraint") that the model translates into cream by reflex. Then provide three explicit non-cream options: saturated brand color, true off-white at C=0, or darker mid-tone. Warmth in the brand is carried by accent + typography + imagery, not by body bg. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v3.2.0: skill bias-fix release Bumps version from 3.1.1 to mark the four-commit skill cleanup that rips out baked-in category recipes (brand.md), saturated-default motion tropes (staggered reveals everywhere), the cream/sand body-bg AI tell, codex-specific defects (1px+wide-shadow, over-rounding, hand-drawn SVGs, stripes, X-theater copy), the extreme-letter-spacing default, and universal slop bans (all-caps eyebrow on every section, numbered-section markers, all-caps body, font-family-count > 3, aphoristic copy cadence, SaaS buzzword strings). Plus a hard hero-H1 ceiling (clamp() ≤6rem) and a Gemini-specific image:hover transform block. Validated against ~190 post-fix samples — see impeccable-evals biases tab for per-provider deltas. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * drop "no pure black/white" rule entirely The rule was contested in the design world and causing more damage than good — pushing every page into the tinted-near-white default which is the cream/sand AI tell we already explicitly ban elsewhere. Vercel, SVKMS, Brutalist sites, et al. use pure black/white successfully; the skill shouldn't second-guess that. Skill markdown deletions: - SKILL.md Color: drop the "Never use #000 or #fff" bullet. - color-and-contrast.md: drop the "Never Use Pure Gray or Pure Black" subsection, the "Never pure black" table-row prescription, and the "Avoid: Using pure black for large areas" bullet. - colorize.md: drop the "NEVER use pure black or pure white for large areas" bullet. - polish.md: drop the "Tinted neutrals: No pure gray or pure black" half of the bullet (the gray-on-color bullet survives). Detector code (cli/engine): - registry/antipatterns.mjs: remove the `pure-black-white` entry. - rules/checks.mjs: remove the three `findings.push({ id: 'pure-black-white', ... })` emit points (inline #000 bg, Tailwind bg-black class, plain-HTML scan path). - engines/regex/detect-text.mjs: remove the two pure-black-white regex rules (CSS `background: #000…` + Tailwind `bg-black`). - detect-antipatterns-browser.js: regenerated via scripts/build-browser-detector.js. Tests: - detect-antipatterns-fixtures.test.mjs: invert the assertion that pure-black-white fires; expect it to NOT fire post-v3.2. Drop the Tailwind bg-black-opacity edge-case test (no longer relevant). - detect-antipatterns.test.js: drop the standalone "detects pure- black-white in styled-components" test and remove pure-black-white from the multi-detector assertions in PricingCard, globals.css, and GlobalStyle.tsx tests. 166 bun tests pass; 24 node fixture tests pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: strip example patterns from copy rules, strengthen gemini block v3.2 rerun validation surfaced two issues: 1. Copy-slop detector fires more on Gemini under v3.2 (48% → 84%) than under no-skill baseline. Root cause: the anti-aphoristic-cadence rule printed the literal "X. No Y." / "X. Just Y." patterns as examples, and Gemini imitated them as the recommended voice. Same recipe-becomes- bias trap we hit with brand.md:116's "Enormous display type, unexpected italic cuts, mixed cases, hand-drawn headlines" enumeration. Fix: describe the cadence as a rhythm ("serious statement, then punchy short negation") without printing literal patterns. Buzzword list trimmed to a single inline phrase family rather than quoted strings. 2. Gemini image:hover transform Gemini-tell hadn't dropped (31% off → 32% v3.2). Strengthen the <gemini> block: explicit "Never animate <img> elements on hover", call out the Tailwind group-hover:scale / group-hover:rotate / group-hover:translate parent-hover patterns by name (Gemini was reaching for these via Tailwind even though the prior text talked about :hover on the image directly). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: simplify context loading and inline register directive Replaces load-context.mjs's JSON output with a tight markdown block from the renamed context.mjs. The script now extracts PRODUCT.md's `## Register` field and appends a `NEXT STEP:` directive naming the matching reference (brand.md / product.md), which moved Gemini from skipping the register load entirely to honoring it. Drops the `.impeccable.md` auto-migration; makes IMPECCABLE_CONTEXT_DIR a lazy escape hatch consulted only when the default paths come up empty. Setup is now four bullets in one list. The DESIGN.md nudge is gone; in its place, a "familiarize with the existing design system" step that calls out CSS / tokens / running app as authoritative sources alongside DESIGN.md. The standalone `### Register` H3 stays for the cascade rules (task cue → surface → register field). New LLM-backed test suite at tests/skill-behavior/ runs five scenarios against claude-haiku-4-5, gpt-5.4-mini, and gemini-3.1-flash-lite via Vercel AI SDK. Captures real tool traces, asserts on context.mjs calls, brand.md loads, and teach.md fallback. Skips cleanly when API keys are unset. 13-14/15 pass; only stable failure is the v3.2.0-era gpt-mini S4 "don't re-run" regression. Adds @ai-sdk/google as devDep and the test:skill-behavior npm script. Touches em-dashes in skill/SKILL.md and four reference files so `bun run build:skills` passes its skill-prose validator. teach.md and document.md drop their "re-run the loader to refresh session cache" steps since the agent's own write is now the freshest source. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: merge orphan reference files into command sub-skills + inline S-tier invariants Two related restructurings: 1. SKILL.md now carries the cross-domain invariants that catch defects in any project (contrast/placeholder/gray-on-color, similar-font pairing, text-wrap, tabular-nums, centered-stack default, Flex/Grid choice, auto-fit grids, semantic z-index, reduced motion, stagger vs section-fade, premium motion materials, focus-visible, placeholders-aren't-labels, dropdown overflow trap, button/link copy). Greenfield-only rules (theme picking, color strategy, tinted neutrals) live under "New projects only". 2. Reference files merged into their command counterparts: - spatial-design.md -> layout.md - motion-design.md -> animate.md - color-and-contrast.md -> colorize.md - responsive-design.md -> adapt.md - ux-writing.md -> clarify.md - typography.md -> typeset.md (bolder.md redirected) - cognitive-load.md + heuristics-scoring.md + personas.md -> critique.md craft.md and shape.md "load references" lists updated to new file homes. interaction-design.md stays standalone (no 1:1 command verb). Net: 36 -> 27 reference files. Same content, fewer files, no orphaned reference loaded only from craft.md. Also extends the routing rules: if the user's first word doesn't match a command but the intent clearly maps to one, load that command's reference and proceed as if invoked. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: add sub-command + existing-project scenarios; move sub-command load to step 2 Adds three new LLM-backed scenarios to tests/skill-behavior: - S6: `/impeccable polish` → loads polish.md - S7: `/impeccable audit` → loads audit.md - S8: existing SvelteKit project (PRODUCT.md + DESIGN.md + src/app.css + src/lib/components/*.svelte + src/routes/+page.svelte) → agent reads at least one project code file to understand the existing design system S6/S7 surface a real model-floor: gpt-5.4-mini reads brand.md, reads the target index.html, and just does the polish/audit without ever loading the sub-command reference. Stronger SKILL.md wording didn't move it. Captured in the README baseline as a known weakness. Claude and Gemini honor the load reliably. To fix Gemini on S6/S7, sub-command reference loading is now Setup step 2 (right after context.mjs), not step 4 — placing it before the model gets focused on "doing the work". Step 3 (design-system familiarization) is tightened to require at least one project code read even when a sub-command reference loads in step 2, so Claude doesn't laser-focus on the sub-command flow and skip the broader exploration. Two new fixtures: MINIMAL_LANDING_HTML (a tiny static landing page for S6/S7) and SVELTE_PROJECT_FILES (a minimal SvelteKit scaffold with tokens, components, and a routes/+page.svelte for S8). Both designed to look real enough that agents treat them as production code. Suite is now 24 tests across three providers; baseline is 21-22/24, with the stable failures being gpt-5.4-mini scenarios 6 and 7. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: add reveal-animation safety rule (must enhance, not gate visibility) Class-triggered visibility transitions pause on hidden tabs and headless renderers. The italian-restaurant smoke produced a build where 2 sections shipped opacity:0 because the CSS transition never advanced past currentTime=0 (timeline paused). Added one-liner under Motion to prevent the antipattern: reveals must enhance an already-visible default, never gate content visibility on a class-triggered transition. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * skill: restore prescriptive cream/sand/beige paragraph Bisection across 5 historical skill commits on Gemini 3.5 flash fast lane n=3 found that |
||
|
|
e587004ee4 |
Refactor: cleaner top-level directory structure (#138)
* refactor(content): merge content/site/ into site/content/ Phase 1 step 1 of the directory restructure. The dual content tree was called out in CLAUDE.md as cleanup; both trees were already in sync except for anti-patterns-catalog.js, which moves to site/data/. - Delete content/site/skills/ and content/site/tutorials/ (duplicates of site/content/, which is what Astro's content collection actually reads). - Move content/site/anti-patterns-catalog.js -> site/data/. - Update scripts/lib/sub-pages-data.js and scripts/build.js to read from site/content/ and site/data/. - Drop content/site/ from validateProse target list (site/content was already there). - Rewrite the "Two content trees" section in CLAUDE.md as a single-tree pointer; update stale dev-server text mentioning the deleted server/index.js. Tests: 186/186 pass. Skills build: clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(skill): rename source/skills/impeccable/ -> skill/ Phase 1 step 2 of the directory restructure. The path was redundantly nested ("source/" wrapper plus "skills/impeccable/" — singular content hidden behind the plural). Collapses to flat skill/SKILL.md + skill/reference/ + skill/scripts/. - Move source/skills/impeccable/ -> skill/. - Rewrite scripts/lib/utils.js readSourceFiles(): drop the multi-skill iteration (CLAUDE.md commits to a single user-invocable skill); read skill/SKILL.md directly. - Update scripts/build.js, scripts/generate-og-image.js, and the sub-pages data layer to point at skill/. - Update tests/lib/utils.test.js: drop the "multi-skill" and "dir-name fallback" cases, update single-skill paths to skill/. - Update tests/build.test.js similarly: drop "multiple skills" integration test, update paths. - Update non-glob path joins in tests/framework-fixtures.test.mjs, tests/live-e2e/session.mjs, tests/live-e2e/agents/llm-agent.mjs, tools/live-loop.mjs. - Update prose/text references in CLAUDE.md, AGENTS.md, DEVELOP.md, README.md, scripts/lib/sub-pages-data.js, bin/commands/skills.mjs, site/data/anti-patterns-catalog.js, site/pages/docs/[...slug].astro, docs/adr-live-variant-mode.md, docs/plans/. Eval framework note: the separate impeccable-evals repo reads ../impeccable/source/skills/impeccable/ and needs a coordinated rename to ../impeccable/skill/. Tests: 186/186 pass. Skills build: clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor: rename docs/ -> notes/ Phase 1 step 3 of the directory restructure. The internal docs/ dir (ADRs and plans) clashed with the site's /docs route. Renaming it "notes/" makes the difference unambiguous: notes/ is project-internal process, /docs is the user-facing route under site/pages/docs/. No code references the dir; the rename is a clean git mv. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(site): move public/ under site/public/ Phase 2 step 4 of the directory restructure. Public assets and the Astro publicDir now live alongside the rest of the site, so site/ is fully self-contained for static content. - git mv public site/public. - astro.config.mjs: add publicDir: './site/public'. Astro defaults to ./public at the project root, so the override is required. - scripts/build.js: write generated _data, _headers, _redirects, _routes.json, and js/detect-antipatterns-browser.js into site/public/. Also delete the dead _REMOVED() Bun static-site builder (replaced by Astro at #130; the placeholder no longer earns its keep). - scripts/build.js validateProse: replace the stale public/index.html reference (deleted at the Astro migration) with site/pages/index.astro in the count-validation file list, restoring homepage drift detection. - scripts/generate-og-image.js: write OG image into site/public/. - scripts/screenshot-antipatterns.js: read examples from + write screenshots to site/public/antipattern-{examples,images}/. - scripts/lib/sub-pages-data.js: load command demos from site/public/js/demos/commands. - .gitignore: rename the public/* generator-output entries to site/public/*. - CLAUDE.md: refresh CSS/data-file paths (still pointing at the old pre-Astro public/css/ + public/js/ tree), point the changelog and command-add checklists at site/pages/index.astro and site/scripts/data.js + site/scripts/components/framework-viz.js. Cloudflare Pages note: functions/ stays at the repo root because CF Pages auto-discovers it there with no configuration knob to relocate. Moving it under site/ would either break deployment or require a build-time copy step that adds more complexity than the cleanup is worth. Tests: 186/186 pass. Skills + site build clean. _headers, _redirects, _routes.json, _data/ all land in build/ correctly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(cli): consolidate bin/ + src/ + lib/ under cli/ Phase 2 step 5 of the directory restructure. The CLI surface was split across three top-level dirs whose names were easy to mistake for each other (especially src/ vs source/ pre-step-2). Consolidates under cli/. - git mv bin -> cli/bin (CLI entry + skills sub-command) - git mv src -> cli/engine (detect-antipatterns engine + browser variant) - git mv lib -> cli/lib (download-providers helper) Update package.json: - bin.impeccable: cli/bin/cli.js - main + exports: cli/engine/detect-antipatterns.mjs and the ./browser variant - files: ["cli/", "LICENSE"] Update internal references: - cli/bin/cli.js: dynamic import points at ../engine/, package.json read goes one level deeper (../../package.json). - functions/api/download/[type]/[provider]/[id].js + bundle/[provider].js: cli/lib/download-providers.js path. - scripts/build.js, scripts/build-browser-detector.js, scripts/build-extension.js: cli/engine path constants. - scripts/lib/sub-pages-data.js, scripts/lib/utils.js, skill/scripts/ live-server.mjs: comment refs. - tests/detect-antipatterns{,-browser,-fixtures}.test.{js,mjs}, tests/windows-path-fix.test.js: import + read paths. - AGENTS.md, CLAUDE.md: doc paths. Verified: - npx node cli/bin/cli.js --version, --help, detect --help all work. - bun run build, bun run build:browser, bun run build:extension all clean. Browser detector lands at cli/engine/detect-antipatterns-browser.js; extension/detector/detect.js still emits to the same location. - bun run test: 186/186 pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: update browser-detector paths missed in cli/ rename Bugbot caught two runtime path leaks where the comment got renamed to cli/engine/ but the actual code still used the old src/ segment. - skill/scripts/live-server.mjs: detectPaths array now joins cli, engine, detect-antipatterns-browser.js for both the repo-relative lookup (4 dirs up from .claude/skills/impeccable/scripts/ to repo root) and the npm node_modules fallback. Without this fix, the detection overlay would silently not load during live-server sessions. - scripts/build.js: the post-build copy of the browser detector into site/public/js/ was reading from src/. The if (fs.existsSync(...)) guard meant the copy was silently skipping, so antipattern-examples pages would 404 on /js/detect-antipatterns-browser.js once the site was deployed. Tests: 186/186 pass. Build clean. site/public/js/detect-antipatterns-browser.js re-emits as expected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: cleanup-deprecated import path missed an extra .. in cli/ rename Bugbot caught three call sites in cli/bin/commands/skills.mjs that import '../../skill/scripts/cleanup-deprecated.mjs'. Pre-rename, that was correct from bin/commands/ (one parent to bin/, one to repo root). After moving the file from bin/commands/ to cli/bin/commands/, the path is one directory deeper, so it needs three .. segments to reach the repo root. Without the fix, every cleanup invocation throws on import and gets swallowed by the surrounding try/catch — silent skip. cli/bin/cli.js's package.json read already uses '../../package.json' (the same depth pattern), confirming three levels is correct. Verified: dynamic import resolves and exports the expected functions. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: sweep stale path/file references missed in the restructure Same root cause as the two bugbot finds: some references in moved or related files weren't tracked because they didn't match a simple sed pattern. Caught the rest by walking each moved dir's depth and each Astro-migration deletion. Stale path references (post-Astro migration, missed earlier): - CLAUDE.md: legacy URL redirects "live in server/index.js" -> point at the actual sources (scripts/build.js generateCFConfig + site/public/_redirects). - AGENTS.md: counts.js path (public/ -> site/public/), changelog file (public/index.html -> site/pages/index.astro), screenshots note (public/ -> site/), source-of-truth dirs (source/, src/ -> skill/, cli/). - tests/detect-antipatterns-browser.test.mjs: comment about routes "in server/index.js". - skill/reference/live.md: workflow.css example for "this repo" was pre-Astro (public/css/) -> site/styles/. (User-project Vite/Next example unchanged.) Stale path that pointed at moved files: - tests/skills-cli.test.js: CLI path was '..', 'bin', 'cli.js'; now '..', 'cli', 'bin', 'cli.js'. Test isn't wired into bun run test but it would have failed if invoked. Dead files (orphaned by Astro migration, never cleaned up): - tests/server/download-validation.test.js: imported from ../../server/lib/{validation,api-handlers}.js which were deleted in |
||
|
|
122a82f715 |
docs: strip AI prose, add STYLE.md and validateProse (#134)
Site copy was being called out as AI slop (specifically the word
"load-bearing"). Five-pass cleanup with a build validator to keep it
from creeping back.
Pass 1 — mechanical purge:
- Remove "load-bearing" from impeccable.md, brand.md, live.md,
iterate-live.md
- Remove "highest-leverage" from critique.md, typeset.md, designing
- Remove em dashes from all 9 slop-page rule cards
- Replace "leverage" verb in personas.md
Pass 2 — rewrite the worst offenders:
- Changelog v2.0 "Data-driven skill rewrite" entry: drop "data-driven",
"frontier models", "collapses into monoculture", "biggest unlock",
"reflex defaults"; name the actual mechanism
- README opener: drop "deeper expertise and more control"; replace with
three concrete differentiators (7 reference files, 23 commands, 27
detection rules)
- Neo Mirai case study opener: action-first, name the image model used
Pass 3 — editorials:
- Fix negation pivot in distill.md ("simplicity is not about ... It is
about ...")
Pass 4 — homepage why-panels:
- Foundation lead: name the 7 reference files specifically
- Language lead: show the discipline mapping with real command names
- Production-codebases panel: drop "Impeccable isn't a sketchpad"
negation pivot
- Ships-code panel: replace "is native to that world" with "runs there"
Pass 5 — STYLE.md and validator:
- New STYLE.md at root: editorial brief with 12 principles and the
enforced denylist (each rule with a rationale and a suggested
replacement)
- scripts/build.js: validateNoEmDashes becomes validateProse. Adds 21
phrase rules with rationales, catches the \`--\` em-dash substitute,
expands target list to site/pages, site/content, README.md,
README.npm.md
- CLAUDE.md: replace the em-dash section with a STYLE.md pointer and
document the two-content-tree footgun (content/site/ vs site/content/
must be edited in lockstep until they're unified)
Co-authored-by: Claude <noreply@anthropic.com>
|
||
|
|
638af20566 |
Document the release workflow in CLAUDE.md and AGENTS.md
Covers the per-component tag prefixes, the changelog-label convention that the release script matches against, the cleanliness gates, the attached artifacts, and the manual post-release steps for the CLI (npm publish) and the extension (Chrome Web Store upload). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
70a9246401 |
fix(plugin): slim Claude Code install (291MB→770KB) + fix skills path
- Marketplace source moved from "./" to "./plugin", a thin generated subtree containing only the plugin manifest and the impeccable skill. Per-version plugin cache shrinks ~378× (~770 KB instead of ~291 MB), and the lockfile is no longer included in the source path so the cache extraction never runs bun install. (#107) - skills field in plugin.json now ends with a trailing slash to match the documented schema (code.claude.com/docs/en/plugins-reference, every directory example uses ./path/). Three reporters converged on this fix because Claude Code's plugin loader skips command registration on some setups when the slash is missing. (#86) - Anti-patterns maintenance agent moved out of .claude/agents/ into CLAUDE.md / AGENTS.md as concise inline guidance, since it is repo-internal dev workflow, not user-facing. The plugin was also the only place this agent was exposed to install users. - Skills version bumped to 3.0.2 so existing users pick up the new install path on next /plugin update. - Top-level harness directories (.claude/skills/, .cursor/skills/, ...) intentionally stay where they are; npx skills add reads them directly from the GitHub repo and that path is unaffected. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d26ccac1be |
feat(test): pluggable LLM agent for live-mode E2E suite
tests/live-e2e/agents/llm-agent.mjs: a Claude-backed VariantAgent that
implements the same one-method interface as the fake agent
(generateVariants(event, context) → { scopedCss, variants[] }). Default
model claude-haiku-4-5; override via IMPECCABLE_E2E_LLM_MODEL.
Prompt caching is on — the system prompt (instructions + the live-mode
spec from reference/live.md) is the cacheable prefix. First call writes
~10K tokens to cache; subsequent fixtures pay only the cache-read rate.
JSON output is validated for shape (scopedCss, variants[N].innerHtml),
with light error messages on parse failure.
tests/live-e2e.test.mjs: read IMPECCABLE_E2E_AGENT (fake|llm). When 'llm',
construct the LLM agent and skip the case cleanly if ANTHROPIC_API_KEY is
unset. Param-manifest assertions are gated to fake mode (LLM may emit
zero-param "fixed point" variants per the live.md spec). The accepted-h1
class assertion now allows hero-title as one of multiple classes so an
LLM agent that adds classes alongside the original still passes.
Test timeouts widen for LLM mode: 25s first-pass on conditional-render
fixtures (vs 5s for fake), 60s on direct waits (vs 30s). Without these,
the LLM's 3-8s generate latency races the orchestration's state-loss
recovery window.
tests/live-e2e/ui.mjs: clickGo retries up to 3× on stability failures.
Required because conditional-render fixtures (modal/tabs) animate the bar
mid-transition when preActions trigger framework HMR; a single click can
land during a re-render and Playwright's stability gate times out.
Pass rate on a typical sweep: 18/19 in LLM mode, 19/19 in fake mode.
The modal fixture's intrinsic state-loss flake (Fast Refresh resetting
useState(open) when source changes) is amplified by LLM latency and may
need a re-run; documented in CLAUDE.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
4fa02bf573 |
docs: add live-mode E2E test instructions to CLAUDE.md and AGENTS.md
Documents `bun run test:live-e2e`, the IMPECCABLE_E2E_ONLY scope env var, the IMPECCABLE_E2E_DEBUG diagnostic flag, the one-time `npx playwright install chromium` setup, and why the suite is kept off the default `bun run test` path. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
e0ab3a73b7 |
feat(live + site): preserve variant attr on accept, designing-page redesigns
Runtime fix in live-browser.js: the 2s static-server fallback in handleAccept now swaps the outer wrapper with the `[data-impeccable-variant="N"]` div itself (+ display:contents), matching what live-accept.mjs writes to disk. Scope rules anchored on the variant attribute keep matching on the non-HMR path, so the accepted design no longer flashes unstyled until reload. Propagated to all harness script copies. /designing: - §03 Polish redesigned as drenched magenta masthead: commands live in the band, three title/description columns beneath on cream. - §04 Maintain redesigned as architectural poster diptych: extract + document vizzes become the hero element, caption below. - §05 Interop section removed. - §05 (was §06) "Pick a register" renamed to "Brand, or product." with a two-lane hairline-divided layout and an auto-selected framing in the sub. Live mode status: BETA → ALPHA across the periodic table, magazine spread, and docs callout, reflecting real-world-testing readiness. Skill bootstrap: removed the `<post-update-cleanup>` block from source/SKILL.md (the source repo is the origin; running cleanup-deprecated here would touch legitimate source). CLAUDE.md and AGENTS.md now document the skip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
bf6379a5d1 |
chore(skill): drop editorial→brand legacy alias
Pre-prod — no need to carry forward the backwards-compat line in SKILL.md or the historical note in CLAUDE.md. Existing PRODUCT.md files with `register: editorial` will hit the "missing field" branch and get re-inferred from content, which is fine for the tiny number of projects that touched it during iteration. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
562f7361c3 |
feat(skill): rename register from "editorial" to "brand"
"editorial" was doing semantic double duty — naming the strategic
distinction (design IS the product) AND a specific visual aesthetic
(editorial magazines, broadsheets, serif display, italic drop caps).
Models pattern-matched the aesthetic and defaulted to it on every
brand brief, producing magazine-shaped landing pages for hiking
brands, tech tools, restaurants.
The register name now describes the SURFACE KIND, not an aesthetic.
Brand covers every visual lane — tech-minimal, luxury, editorial-
magazine, consumer-warm, brutalist-grid, hand-drawn — each with
legitimate voice within the register.
## Changes
- `reference/editorial.md` → `reference/brand.md`. Content rewritten:
broadened typography guidance (pairing shapes per brand genre,
single-family commitment is valid), broadened color references
(Stripe, Vercel, Liquid Death alongside Klim, Condé Nast), added
a second slop test ("name your aesthetic lane") to prevent drift
into editorial-magazine defaults, added brand ban against the
drift itself.
- SKILL.md: register names brand/product; load brand.md.
- teach.md: register values brand/product; signals renamed; example
principles no longer use "editorial over marketing" phrasing.
- Six sub-commands (animate/bolder/colorize/delight/layout/quieter):
per-register subsections flipped Editorial: → Brand:.
- product.md: cross-references updated.
- live.md: register reference updated; density axis no longer uses
"editorial" as a synonym for "dense".
- typeset.md: per-register paragraph generalised beyond serif+sans
pairing.
- CLAUDE.md: architecture section rewritten; kept "editorial
wrapper" content-authoring term as-is (different meaning).
## Legacy handling
- `editorial` is accepted as an alias for `brand` on PRODUCT.md's
register field — agents treat it as `brand` without asking.
- Documented in SKILL.md setup section and CLAUDE.md.
## What's unchanged
- Register identification priority (task cue → surface → PRODUCT.md).
- Permission structure (brand can go big, product stays restrained).
- Shared design laws, absolute bans, color strategy vocabulary.
- Framework fixtures and tests.
Full build clean, test suite passes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|
|
4daabe5232 |
feat(skill): register split, color strategy, and pre-design intake
Splits the skill into two register references (editorial, product), replaces category-based theme selection with a forced physical-scene inference, and introduces a four-step color strategy axis (Restrained / Committed / Full palette / Drenched) with editorial permission for the bold three. Adds a seed mode to /impeccable document for pre-implementation projects, updates /impeccable teach Step 5 to offer the seed path, and grows /impeccable shape with Design Direction + Scope intake (fidelity, breadth, interactivity, time). Extends live-mode variant distinctness to forbid three variants sharing theme and dominant hue. Also drops the anti-pattern validator coupling, consolidates a11y into audit.md, and updates CLAUDE.md with the register architecture. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
bb94dadda0 |
Add live variant mode: element picker, action panel, poll/reply bridge (22 commands)
New feature: /impeccable live starts an interactive visual iteration server. Users select elements in the browser, pick a design action (bolder, quieter, etc.), and the agent generates HTML+CSS variants written directly to source. The dev server's HMR hot-swaps them in, and MutationObserver progressively reveals each variant in a cycler UI as it arrives. Architecture: - src/live/server.mjs: HTTP + WebSocket server with session token auth, long-poll /poll endpoint for the agent, WebSocket for the browser - src/live/poll.mjs: CLI client (npx impeccable poll / poll --reply) - src/live/browser.js: element picker with keyboard nav (arrows=siblings, shift+arrows=parent/child), action panel (12 commands, freeform input, variant count), variant cycler with progressive reveal via MutationObserver - src/live/protocol.mjs: shared message types and event validation - source/skills/impeccable/reference/live.md: agent loop instructions (inject script, poll loop, generate variants, accept/discard, cleanup) CLI changes: - bin/cli.js: added "poll" top-level command - src/detect-antipatterns.mjs: liveCli() now delegates to src/live/server.mjs - package.json: added ws dependency Registered /impeccable live as command #22 across all standard locations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
e58cbc432f |
Split /onboard back out as its own command (21 commands total)
Pre-3.0, onboard was folded into /harden when we were trying to reduce
namespace pollution. In the single-skill model that tradeoff is gone,
so the weakest of the old merges is the first to undo.
Harden and onboard live in different mental modes. Harden is defensive
(edge cases, i18n, overflow, errors). Onboard is activation (first-run
flows, empty states as CTAs, progressive disclosure). A user thinking
"design the onboarding flow" was never going to type /impeccable harden.
Changes:
- New reference file at source/skills/impeccable/reference/onboard.md,
restored from the pre-merge version in git history rather than the
condensed 33-line summary that was in harden.md.
- Removed the "Onboarding & First-Run Experience" section from
source/skills/impeccable/reference/harden.md.
- Updated harden description/editorial/process-steps to drop onboarding
keywords; split commandProcessSteps so harden stays focused on
production resilience and onboard gets its own phases.
- Registered onboard in: SKILL.md description + command menu + router
table, command-metadata.json, IMPECCABLE_SUB_COMMANDS, pin.mjs
VALID_COMMANDS, SKILL_CATEGORIES, COMMAND_RELATIONSHIPS, data.js
commandCategories + commandProcessSteps + commandRelationships,
framework-viz commandSymbols + commandNumbers.
- Reused the existing content/site/skills/onboard.md editorial wrapper
(it was orphaned by the merge but never deleted), updating it to use
/impeccable onboard.
- Bumped all user-facing count references 20 -> 21: public/index.html,
CLAUDE.md, README.md, NOTICE.md, plugin.json, marketplace.json,
sitemap.xml, build-sub-pages.js.
- Harness dir audit.md and critique.md changes are the
{{available_commands}} placeholder expanding to include onboard.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
2233d82f3a |
Bump skills to 3.0, remove prefixed bundle, redesign install section
- Bump skills plugin version 2.1.1 -> 3.0.0 (plugin.json, marketplace.json, harness SKILL.md files). CLI and Chrome extension unchanged. - Remove prefixed universal zip bundle and all related code: factory.js prefix/outputSuffix options, zip.js variant pass, utils.js prefixSkillReferences, the "universal-prefixed" entry in download-providers.js, and the matching test suite in utils.test.js. - Redesign Get Started step 1 "Install the skill and CLI": two terminal rows (npx skills + npm i -g impeccable) with paired notes, drop the Recommended badge. - Collapse "Other install methods" back into a <details> element so the primary install path is the first thing users see. - Simplify step 3 to "Add the Chrome extension": remove the CLI tool block (now in step 1), use standard .btn .btn-primary for the CTA so it matches other primary buttons (square corners, accent slide-up hover), and lay out the preview screenshot next to the button instead of stacked so the screenshot no longer dominates vertical space. - CLAUDE.md: rewrite with v3.0 architecture, the "no em dash also means no --" rule, the harness-dirs-are-tracked gotcha, the named-export test-spy warning, and the evals inline-skill.ts sync note. - AGENTS.md, DEVELOP.md: drop prefixed variant references. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
b0f44f83c6 |
Consolidate 18 skills into 1 /impeccable skill with 20 commands
Biggest change in a while. Users previously had 18 standalone skill
entries cluttering their /menu; now they have one entry (/impeccable)
that routes to 20 specialized commands via argument dispatch. The pin
mechanism (/impeccable pin audit) restores standalone shortcuts on
demand for commands users hit all the time.
## Architecture
- Single /impeccable skill with command router section in SKILL.md
- 20 commands served via reference files under source/skills/impeccable/reference/
- /impeccable pin <command> creates a lightweight redirect shim so users
who prefer /audit, /polish, etc. can still have them
- Context gathering (teach) auto-runs on first use
- command-metadata.json is the single source of truth for command
descriptions, argument hints, and relationships
## Site rewrite
- Docs URL: /skills renamed to /docs (with /skills permanent redirects)
- Homepage hero frames Impeccable as "one skill with 20 commands"
- "Get Started" split into 50/50 install + how-to-use with editorial
numbered steps, /impeccable shown as the home command with three modes
- New /docs overview: home command hero card + dense category rows
matching the old cheatsheet density, with leads-to/pairs-with/
combines-with relationship metadata served from a shared source
- Cheatsheet merged into /docs, /cheatsheet redirects
- Magazine spread and mobile cards show /impeccable as a stacked
namespace label above the command name at full display size
- Periodic table updated with craft/teach/extract as first-class cells
- Skill detail pages generate from reference files, with an editorial
wrapper per command for tagline + body
- Tutorials and anti-patterns pages updated to use /impeccable <cmd>
## Build system
- Dead code removed (scripts/lib/transformers/shared.js)
- Build log wording fixed ("1 skill" not "1 skills (1 user-invocable)")
- generateApiData fallback branch removed (throws loudly if metadata
missing instead of silently degrading)
- Commands API includes editorial tagline alongside the long description;
UI surfaces prefer tagline for human display, description for auto-
trigger keyword matching
## Gitignore
- Added .claude/scheduled_tasks.lock, .claude/settings.local.json to
ignore list (local Claude Code state that should not be tracked).
- Harness skill directories (.claude/skills/, .agents/skills/, etc.)
remain tracked by design: npx skills reads them from this repo at
install time and they enable clean submodule use.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
239d69d0d8 |
Add skills check command, skip-if-up-to-date in update, decouple versioning
CLI changes (bumped to v2.1.2, skills stay at v2.1.1): - `npx impeccable skills check` compares local skill files against the latest bundle and reports whether updates are available - `npx impeccable skills update` now downloads the bundle first, compares hashes, and skips with "up to date" if nothing changed - Removed the local-modifications warning (was confusing for users who installed via npx skills add) Versioning: - CLI (package.json), skills (plugin.json/marketplace.json), and Chrome extension (manifest.json) are now versioned independently - CLAUDE.md updated to document when to bump each Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
28d0b78430 |
Document private evals framework in CLAUDE.md
Adds an Evals Framework section pointing future Claude sessions at evals/AGENT.md (the comprehensive private guide) and inlines the highest-leverage facts: primary baseline model is gpt-5.4 medium reasoning, n=20 standard sample size, do not use Haiku as primary target, always smoke test before sweep. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
038d281247 |
Drop Tailwind CLI from the build
Tailwind was wired into the build but the project didn't actually use it: no @tailwind/@theme/@apply directives in source CSS, no utility classes in any HTML or JS, no tailwindcss dependency in package.json, and no HTML page linked to the compiled styles.css output. Bun's HTML loader already handles main.css's @import chain transparently in both `bun run dev` and `bun run build`. Removing the Tailwind step: - Deletes buildTailwindCSS() from scripts/build.js (and the now-unused execSync import) - Removes public/css/styles.css (dead compiled output that nothing read) - Updates CLAUDE.md to drop the "must rebuild Tailwind after CSS edits" instruction Verified: `bun run build` produces the same 104 KB CSS chunk linked from index.html via Bun's HTML loader. No more rebuild step after CSS edits. |
||
|
|
3c9cc86061 |
Merge CLI into main repo, switch everything to Apache 2.0
Merges the impeccable-detect CLI repo (pbakaus/impeccable-cli@831a6cc) into this repo. The BSL-1.1 license that motivated the split is gone; everything is now Apache 2.0. - Add bin/, src/, detection tests and fixtures from CLI repo - Merge package.json: name → "impeccable", add bin/exports/files fields - Internal refs now read from local src/ instead of node_modules/ - Update SPDX headers, NOTICE.md, CLAUDE.md, FAQ, npm README - Add prepack/postpack scripts for CLI-focused README on npm - Remove terminal license labels (no longer needed) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c8d654a71a |
Align all version references to 2.0.6, update repo URLs to impeccable-cli
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
d8d5b8acd8 |
Move CLI to separate repo, make this skills-only (Apache 2.0)
The CLI and detection engine now live in pbakaus/impeccable-detect (published as 'impeccable' on npm, BSL-1.1). This repo is purely Apache 2.0: skills, prompts, website, and build system. - Remove bin/ (CLI moved to CLI repo) - Remove README.npm.md (moved to CLI repo) - Remove @impeccable/detect dependency, add impeccable dependency - Set package.json to private (no longer published to npm) - Update all references from @impeccable/detect to impeccable - Update CLAUDE.md, NOTICE.md, FAQ, and changelog - Rebuild all provider skill distributions Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
3974789903 |
Remove detection engine files, now in @impeccable/detect package
Remove all detection engine source, tests, fixtures, and build scripts that have been extracted to the @impeccable/detect package (BSL-1.1). - Delete source/skills/critique/scripts/ (detect-antipatterns.mjs, browser.js) - Delete scripts/build-browser-detector.js - Delete tests/detect-antipatterns*.test.* and tests/fixtures/antipatterns/ - Delete .claude/skills/critique/scripts/detect-antipatterns-browser.js - Update scripts/build.js to read detection count from npm package - Update server/index.js to serve browser script from npm package - Update CLAUDE.md to reference @impeccable/detect - Update package.json test script (detection tests removed) - Update .gitignore (remove obsolete browser script entry) - Rebuild all provider skill distributions with updated critique skill Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
740f2a1975 |
Add large-scan confirmation prompt, fix bun-jsdom docs
Add interactive confirmation when scanning directories with 50+ files, warning about jsdom overhead for HTML files and suggesting --fast or targeting a subdirectory. Auto-skipped in non-TTY (piped/CI) contexts. Update CLAUDE.md and README.md to use node/npx instead of bun for the detect CLI, since bun's jsdom is extremely slow and causes scans to hang. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
03a4433dcc |
Restructure narrative: Foundation, Language, Antidote, Visual Mode
Major site restructure reflecting Impeccable's expanded value prop: - 01 The Foundation: 7 design dimensions, 212 guidelines grid - 02 The Language: merged periodic table + Commands in Action - 03 The Antidote: moved from position 1, anti-patterns + gallery - 04 Visual Mode: live iframe embed of detection overlay demo - Composite demo page combining purple gradients + side-tab cards - Updated hero copy (212 guidelines, 22 commands) - 7-item sticky nav, backward-compat anchor aliases Detection overlay improvements: - Staggered entrance animation (80ms per element) - Banner slides in from top - Skip body/html from overlay targeting (fixes scrollbar bug) - Banner overflow: hidden + maxWidth: 100vw - CLAUDE.md: document that browser script is generated, never edit directly Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |