mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-11 21:57:14 +03:00
a8ce5962d3f4ec0069400afa17e9916cde949706
39
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
6ebc24ad66 |
Add DeepSeek Harness as a supported skills provider (#746)
* Add DeepSeek Harness as a supported skills provider npx impeccable install now detects ~/.dsh (or $DSH_HOME when it sits under home) and installs into ~/.dsh/skills, the user-level skill root DeepSeek Harness scans, with project-level .dsh/skills on the same layout as other providers. Aliases: dsh, deepseek, deepseek-harness. Engine: PROVIDER_DIRS / aliases / display / input order / global hint, $DSH_HOME-aware user skills dir, provider id resolution from the skill dir, pin harness dirs, bundle path normalization for hashing. Build: dsh transformer target emitting the frontmatter DeepSeek Harness reads (user-invocable, license, compatibility, metadata; unknown keys are ignored there) with no emitHooks (DSH hooks are in-process plugins, not on-disk manifests) and no agentFormat (no documented on-disk subagent format); placeholders (AGENTS.md config file, ask_user_question tool, / command prefix), provider block tags, universal README entry. Docs: HARNESSES.md row and frontmatter column, CLI-CONTRACT constants, README/DEVELOP/AGENTS provider lists. Validation: cargo test --workspace; node scripts/run-tests.mjs core (138 pass); bun run build (19 providers, dist/dsh artifact verified); engine smoke against a fake HOME with a local bundle: install --providers=dsh --scope=global, auto-detected install, and update all resolve the .dsh provider. Generated provider output intentionally omitted per repo policy; the sync workflow regenerates tracked .dsh/skills after merge. Prepared with AI assistance (DeepSeek Harness coding agent). * Address review: DSH_HOME-only detection, generated-output pathspecs - Detect DeepSeek Harness through the resolved $DSH_HOME (fallback ~/.dsh) instead of gating on a fixed ~/.dsh path, so a DSH_HOME-only setup is offered by a provider-less install; generalize the two env-relocated config-dir hints (OpenCode, DSH) into one shared probe. - Add .dsh to the sync workflow's GENERATED_PATHS and CI's generated drift check so the tracked .dsh/skills payload is committed and validated. - Cover both behaviors: new install_detection_tests (DSH_HOME-only, default ~/.dsh, refused outside-home override) and a CLI-CONTRACT note on the resolved detection path. Validation: cargo test --workspace; node scripts/run-tests.mjs core (138 pass); engine smoke: DSH_HOME-only fake HOME installs globally into the resolved skills dir. Prepared with AI assistance (DeepSeek Harness coding agent). * Fix DeepSeek Harness home paths on Windows Use native relative-path containment, cover case and drive boundaries, and verify relocated global install/update without changing project skills. Add DSH output coverage and correct the install documentation. AI assistance: Codex, under pbakaus maintainer direction. * Document the CLI limit on external DSH homes Clarify that outside-home manual copies are not detected or updated by the CLI. AI assistance: Codex, under pbakaus maintainer direction. --------- Co-authored-by: Paul Bakaus <paul.bakaus@gmail.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
|
||
|
|
482368511a |
Fix Codex skill version metadata (#703)
Move Codex and .agents skill versions under metadata while keeping all version readers compatible with legacy top-level frontmatter.\n\nAI assistance: prepared with Codex under maintainer direction. |
||
|
|
9736a9f6e9 |
Fix OpenCode slash command bridge (#483)
Add a first-class OpenCode command bridge across builds, installs, updates, linked installs, and pinned shortcuts. Preserve current provider behavior while backfilling missing or drifted command files.\n\nAI assistance: contributor and maintainer work used AI tools as disclosed in the PR discussion and commits. |
||
|
|
0e5c6cbe17 |
Keep critique's report out of the question's message
The critique report and the AskUserQuestion call shipped in one assistant message, so the report stayed hidden until the user answered the picker and the command read as if it had never run. Reorder critique's persistence steps so the temp-file cleanup runs after the report and trend line are sent. That cleanup now ends the message carrying the report, leaving the questions to open a fresh one. Both critique.md and overdrive.md state the constraint and why it exists, so the ordering is not an unexplained sequence a model can optimize away. Overdrive additionally moves its direction descriptions inside the question options, where the user is actually reading them. Also fix the ask_instruction splices. The placeholder is a complete sentence, but five call sites spliced it mid-sentence and shipped text like "stop and STOP and call the AskUserQuestion tool to clarify. before expanding it". Every call site is now sentence-initial and the twelve lowercase provider values are capitalized to match, with a comment in utils.js pinning the contract. Record a workflow-contract baseline for the current model lineup. The two failures seen while validating this change are pre-existing: bolder refinement fails on deepseek-v4-flash identically with bolder.md reverted to HEAD, and redesign replaces DESIGN is flaky on assertions driven by new-work.md, which this change does not touch. Prepared with AI assistance (Claude Code). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
a075d89bdb |
Simplify CSS color channel parsing (#520)
Centralize CSS numeric token parsing and characterize every supported color unit while preserving config and filtering behavior. AI-assisted: Codex implemented this refactor under pbakaus’s scheduled architecture-simplification authorization. |
||
|
|
99c4189788 |
Fix Google Fonts value suppression
AI-assisted change. |
||
|
|
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> |
||
|
|
d146d2084b |
Stop the design hook lying about findings it already reported (#391)
* Stop the design hook lying about findings it already reported
Three fixes, all aimed at the hook being trustworthy enough that an agent
keeps reading it.
1. The session cache was append-only, so the hook lied and then went blind.
`rememberFindings` unioned new keys into the remembered set and nothing ever
removed them, and the pending ack took its count from that set rather than
from the live scan. Fixing two of three findings produced:
Still has 3 finding(s) flagged earlier this session
(overused-font:1:inter, overused-font:2:roboto, overused-font:3:geist)
with roboto and geist already gone. Worse, a finding that was fixed and then
reintroduced was deduped against the stale memory and never re-reported, so
the hook was permanently blind to that regression for the rest of the session.
The cache now syncs to the complete current scan on every scan, so the count
shrinks as work lands and a reintroduced finding reads as fresh. Dedup within
a session still works, because it compares against the previous scan rather
than against all history. A detector failure leaves the remembered set alone
instead of recording an empty scan as truth.
2. The size ceiling, for generated files that do not live under dist/.
`GENERATED_PATH` covered dist, build, out, .next, .cache, coverage and
.min., but repos commit browser bundles and vendored detector copies next to
source. The hook was reading and scanning a 215KB generated bundle, and
reporting findings in it. Added `generated` as a path segment, matched with
separators on both sides so authored names such as generated-utils.ts and
CodeGenerator.tsx still get scanned, plus a `limits.maxFileBytes` ceiling
defaulting to 128KB. In this codebase authored files top out at 86KB while
the bundles start at 215KB, so the gap is comfortable.
3. The clean ack repeated on every clean edit.
It carries no finding, only the standing steer that a silent hook is not a
verdict on the design. That steer is worth saying, but not dozens of times
per session. It now fires once per file per session and reports
`clean-ack-deduped` in the audit log so suppressed noise stays visible. The
pending ack is deliberately untouched: it names real unresolved work, and the
comment explaining why it must repeat still holds.
Verified end-to-end against the built hook: three findings, fix two and the
count drops to one naming only the survivor, fix the last and it goes clean,
edit again and it stays silent, reintroduce and it fires as fresh.
Generated provider output is deliberately left out; the sync workflow owns it.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>
* Address review: three clean-ack and audit bugs in the dedupe change
All three were introduced by this PR and all three are fair catches.
Quiet mode spent the ack (bugbot). A clean scan marked cleanAcked and
persisted it even when quiet suppressed all output, so a later non-quiet run
in the same session never got the steer. The quiet decision is now hoisted
above the scan loop and quiet leaves the ack unspent.
Multi-file events lost the ack (copilot). The first clean target became
cleanWinner unconditionally; if that file was already acked, cleanAckDeduped
went true and the `!cleanWinner` guard meant a later target that had never
been acked could never win. A raw apply_patch touching two files would drop
the second file's ack entirely. The loop now keeps looking for a target that
is actually owed an ack.
audit.bytes leaked across targets (copilot). It was set when a file was
skipped as too-large and never cleared, so in a multi-file event a later
emitted result carried the skipped file's byte count. Cleared per iteration.
The tests use a raw apply_patch payload rather than MultiEdit, because
MultiEdit in this harness is single-file ({ file_path, edits: [] }) and would
not have exercised the multi-target paths at all. Verified the three tests
fail against the pre-fix code and pass after, so they are not passing for the
wrong reason.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>
* Address review: font-size waivers silently did nothing
Two more review findings, both real.
Specific-value font-size waivers were dead config (greptile). The rule emits an
ignoreValue, and the hook's own directive footer tells the agent to waive
value-specific findings with `hooks ignore-value <rule> <value>`, but
`design-system-font-size` was missing from the direct-value rule set in
`extractFindingIgnoreValue`. The extracted value came back empty, so any
waiver naming an actual size was compared against nothing and silently
dropped. Only the `*` wildcard worked, which is why the framework-viz waiver
earlier in this branch appeared to function.
Reproduced against the built hook: with a `0.82rem` waiver the finding still
fired; it now goes clean, while a waiver naming a different size correctly
still fires, so this is not over-matching.
Wrong audit skip reason (bugbot). In a mixed multi-target run, an earlier UI
file whose ack was already spent set `cleanAckDeduped`, and a later non-UI
clean file became the winner. The tail then reported `clean-ack-deduped` when
the honest reason was `non-ui-ack`. Audit-label only, no behavior change.
Reordered so the winner is described first and dedupe is reported only when it
is genuinely why nothing was emitted.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>
* Mirror the font-size waiver fix into the CLI's config reader
Bugbot caught that the previous commit only fixed one of two copies.
`extractFindingIgnoreValue` exists twice, in skill/scripts/hook-lib.mjs and in
cli/lib/impeccable-config.mjs, and the direct-value rule list is duplicated in
both. Adding design-system-font-size to the hook alone meant the same
.impeccable/config.json filtered differently depending on the entry point: a
size waiver was honored by the hook and ignored by `npx impeccable detect`.
The two functions are otherwise byte-identical, so this restores parity rather
than changing CLI behavior independently. The new test notes the duplication so
the next person knows the pair has drifted once already.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>
* Fix the audit byte-count leak properly, not just one scan order
My earlier fix cleared audit.bytes at the top of each iteration, which was
wrong twice over, and bugbot caught both.
The clear sat below the sensitive, generated, extension, ignore-file and
file-missing continues, so a later target exiting through any of those never
reached it and kept the oversized file's size while audit.file pointed
somewhere else. It also only handled the bundle-scanned-first order; when the
oversized file came last, the byte count was set after the emitting file had
already been decided and rode along on its audit entry regardless.
The root problem was keeping per-file state on the shared audit object. The
size is now held in a local and attached only when the oversized skip is the
run's actual outcome, so it cannot describe a file other than the one being
reported. Tests cover both scan orders, an early-continue target after the
skip, and the single-oversized-file case where the count should still appear.
Prepared with AI assistance (Claude Code).
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
|
||
|
|
2b1f36c43e |
Add concept world catalog and review workflow
AI-assisted: prepared by Codex at Paul's request. |
||
|
|
da99645a58 |
Add OpenAI plugin submission bundle (#363)
* Add OpenAI plugin submission bundle Build a Codex-native OpenAI plugin with bundled hooks, public listing metadata, submission guidance, privacy coverage, and regression tests. AI assistance: OpenAI Codex prepared and validated these changes under maintainer direction. * Fix provider script command rendering Replace heuristic rewrites across executable scripts with one explicit provider marker, render pinned shortcuts per target harness, and remove the personal email from the public publisher manifest. Addresses automated review feedback on PR #363. AI assistance: OpenAI Codex prepared and validated these changes under maintainer direction. |
||
|
|
ca121aa35f |
Fix: file-scoped wildcard ignores suppress non-value-bearing rules (#296) (#309)
A file-scoped wildcard ignore (add-value <rule> "*" --file <glob>) silently no-op'd for rules with no extractable value, such as side-tab. isIgnoredFindingValue bailed on an empty value before the wildcard/file-scope branch could run. Require a value only on the specific-value path; let the scoped wildcard match on rule + file. Mirrored in skill/scripts/hook-lib.mjs for CLI/hook parity. |
||
|
|
8b0c895703 |
[codex] Fix CLI skill update detection (#257)
* Fix CLI skill update detection * Preserve linked skills during install refresh * Keep existing installs working offline * Respect provider scope during install refresh |
||
|
|
51d01e3a5f |
[codex] Add design-aware detector rules (#252)
* Add design-aware detector rules * Fix design-aware detector noise * Unify CLI and hook detector ignores * Fix remaining design-system review findings * Add detector ignore CLI * Fix design detector review findings * Fix design color source false positives * Fix core test suite registration * Add design-aware detector docs * Fix font priority design-system parsing * Fix color ignore value matching |
||
|
|
8cf2be110d |
feat(cli): interactive hook consent + unified .impeccable/config.json (#245)
* feat(cli): interactive hook consent + unified .impeccable/config.json Make the design-hook install a conscious choice and unify scattered config into one file. Interactive consent - On an interactive `skills install`/`update`, the CLI explains what the hook does and offers to install it (default yes), then records the per-developer decision in the gitignored `.impeccable/config.local.json`, so it never re-asks. A recorded decision or an already-installed hook short-circuits; `-y`/non-TTY keeps the historical install-by-default behavior; `--no-hooks` is a one-off skip that records nothing. The trigger keys on "is the hook installed?" + "is there a recorded decision?", not a brittle version check. Unified config - `.impeccable/config.json` (shared) and `.impeccable/config.local.json` (gitignored) now hold all Impeccable settings: hook settings under a `hook` key, plus top-level `updateCheck`. `/impeccable hooks` writes the `hook` subtree, preserving siblings. The hook runtime reads `hook.quiet` and `hook.auditLog`; context boot reads `updateCheck`. The legacy `IMPECCABLE_HOOK_DISABLED|QUIET|LOG` and `IMPECCABLE_NO_UPDATE_CHECK` env vars still work and override config; docs now lead with config and treat env vars as a legacy note. - No backward compat for the pre-unification `hook.json`/`hook.local.json` (the hook shipped an hour ago; nothing in the wild uses it). This repo's own hook config is migrated to `.impeccable/config.json`. The CLI and skill scripts are separate trees, so a small CLI-side config module (cli/lib/impeccable-config.mjs) duplicates the config-path and .git/info/exclude handling; comments flag the duplication. Tests: new cli config unit test; skills-cli consent tests (declined skips, accepted installs, --no-hooks records nothing); hook.test.mjs back-compat removed and quiet/auditLog-from-config + gitexclude coverage added. Full suite green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hooks): preserve sibling config fields + resolve audit log from event cwd (Bugbot) Two Bugbot findings: - High: `/impeccable hooks` edits replaced the whole `hook` object with the merge-helper output, dropping fields those helpers don't manage — so an `ignore-value --local` could wipe the recorded install consent and make the CLI re-prompt. writeConfig now merges over the existing hook object, keeping consent/quiet/auditLog. - Medium: config-based audit logging resolved hook.auditLog from process.cwd(), which can differ from the hook event's project root (and Cursor's pre-edit hook passed no cwd). The hook now stamps the resolved project root on the audit entry, and writeAuditLog reads config from entry.cwd when present. Tests: a /impeccable hooks edit preserves consent + quiet; writeAuditLog resolves config auditLog from entry.cwd, not the fallback cwd. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(hooks): resolve a relative auditLog path against the project root (Bugbot) A relative hook.auditLog was read from the project root but written relative to the hook process cwd, so when those differ the log went to the wrong place. writeAuditLog now resolves a relative target (from env or config) against the same project root it reads config from. Absolute and ~/ paths are unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix hook consent recovery and smoke config * Fix hook consent explainer for Cursor * Fix empty hook target consent --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
972f5b18be | Improve generated output sync workflow | ||
|
|
f7f2bfc800 |
feat(detector): deprecate --fast (now a no-op, full scan always)
Since the jsdom removal the static HTML/CSS analysis is fast (~4ms/file) and covers every rule, so the regex-only `--fast` path only loses coverage (it ran ~10 of 41 rules) for no real speed win. It's a foot-gun: a `--fast` scan can read "clean" because most rules silently don't run. Deprecate gracefully rather than hard-remove: the flag is still accepted (so existing CI scripts don't break) but ignored, with a one-line stderr notice, and the full scan always runs. Dropped from --help and the example. Removed the `--fast` suggestion from the many-files warning and from critique.md's scan guidance. Ships to users via a CLI release (npm) and rides the next skill release in the bundled detector. Tests updated to assert the deprecation behavior. 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 |
||
|
|
bc1894889e |
Improve critique skill reliability
- add provider-specific block compilation and tests - bundle detector scripts for skill critique runs - harden critique orchestration, browser handling, and storage |
||
|
|
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 |
||
|
|
18fa503d44 |
fix: normalize quoted user-invocable frontmatter (#87)
* fix: normalize quoted user-invokable frontmatter Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> * fix: preserve quoted non-boolean frontmatter values Only normalize quoted booleans for the user-invocable frontmatter flag so other quoted fields like argument-hint and description continue to round-trip as plain strings. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> --------- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
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> |
||
|
|
f957fcad20 |
Fix: quote YAML scalars that contain colon-space in frontmatter
generateYamlFrontmatter only re-quoted values starting with `[` or `{`,
but parseFrontmatter strips surrounding quotes on input. Descriptions
containing `: ` (e.g. "Also handles: critique...") round-tripped into
unquoted plain scalars that YAML parsers reject. Added a yamlNeedsQuoting
check covering colon-space, space-hash, YAML indicator chars, reserved
keywords, and number-like strings, plus regression tests.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
f683f413c8 |
Rename frontend-design to impeccable, fold teach-impeccable into teach mode
Major skill consolidation for v2.0:
- Rename source/skills/frontend-design/ to source/skills/impeccable/
with user-invocable: true and argument-hint: "[teach]"
- Fold teach-impeccable body into impeccable as "Teach Mode" section,
activated via /impeccable teach
- Create deprecation shims:
- frontend-design: redirects to /impeccable
- teach-impeccable: redirects to /impeccable teach
- Update all 16 skill cross-references from {{command_prefix}}frontend-design
to {{command_prefix}}impeccable and {{command_prefix}}teach-impeccable to
{{command_prefix}}impeccable teach
- Update CLI sentinel detection to use 'impeccable' (with teach-impeccable
as legacy fallback)
- Update build system readPatterns() path and EXCLUDED_FROM_SUGGESTIONS
- Update all public files (data.js, cheatsheet, index, viz, demos)
- Update all documentation (README, NOTICE, AGENTS, plugin.json)
- Update all test expectations
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
112317fd05 |
Rebase Trae support onto new factory architecture
Merge main (factory refactor) and adapt Trae to use the config-driven transformer system instead of a standalone trae.js file. Two provider entries (trae-cn, trae) replace the custom dual-directory logic. Also adds placeholderProvider support to the factory for providers that share placeholder configs but need separate output directories. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
2d4c7899dd |
Update provider configs from official docs, add HARNESSES.md reference
Research each harness's official documentation to verify and correct
provider frontmatter configs. Remove Codex/Gemini body transforms that
targeted their commands systems, not skills.
- Add compatibility + metadata to Cursor and Agents (Copilot)
- Add allowed-tools to Pi
- Remove Codex $ARGNAME and Gemini {{args}} body transforms
- Add HARNESSES.md as source of truth for harness capabilities
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|
|
6de73abf1b |
Fix invalid YAML frontmatter and consolidate build transformers
Fixes #67: argument-hint values starting with [ were parsed as YAML flow sequences. Replace structured args arrays in source files with pre-formatted argument-hint strings, and quote values starting with [ or { in generateYamlFrontmatter(). Also consolidates 8 nearly-identical transformer files into a single config-driven createTransformer() factory. Adding a new provider now requires only a config object in providers.js instead of a full file. - Replace args source frontmatter with argument-hint strings - Add YAML quoting for values starting with [ or { - Add quote stripping to parseFrontmatter() for round-trip support - Create factory.js + providers.js, delete 8 individual transformers - Replace 16 explicit build.js calls with a loop over PROVIDERS - Consolidate 8 test files into 2 (factory + providers) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c878f7db5a | Merge branch 'main' into add-trae-support | ||
|
|
9faa690047 | Fix Trae output format and add tests | ||
|
|
998dd0c68a |
Merge pull request #52 from Gujiassh/fix/preserve-prefixed-article-casing
fix: preserve article casing in prefixed skill references |
||
|
|
df1c26ce63 |
Fix user-invokable -> user-invocable spelling across entire codebase
PR #50 fixed the output SKILL.md files but the source files, build scripts, tests, docs, and server code still used the wrong spelling. Claude Code expects `user-invocable` (with c) for slash command autocomplete to work. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
b1becfc341 |
fix: preserve article casing in prefixed skill references
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> |
||
|
|
bac8696851 |
fix: correct AskUserQuestionTool to AskUserQuestion tool
The Claude Code tool is called AskUserQuestion, not AskUserQuestionTool. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
c54337c4fa |
test: add missing OpenCode transformer tests
Every other provider transformer (cursor, claude-code, gemini, codex, agents, kiro, pi) has a dedicated test file, but OpenCode was missing. Adds 23 tests covering directory structure, frontmatter fields (including args, allowed-tools, user-invokable, compatibility, metadata), placeholder replacement, reference file handling, prefix/suffix options, skill cross-reference prefixing, directory cleanup, and log output. |
||
|
|
bb5ba2f305 |
feat: add Pi provider support, fix community health files, recategorize /onboard
- Add first-class Pi (pi.dev) provider with transformer, tests, and build integration - Fix CODEOWNERS username (@paulbakaus → @pbakaus) - Add missing providers to issue/PR templates (Copilot, Kiro, OpenCode, Pi) - Add Pi and OpenCode logos to homepage hero and install sections - Move /onboard from "system" to "enhancement" category - Update README and DEVELOP.md with all supported providers Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
04f26b3e4d |
Fix Kiro ref file bug, add missing test coverage for Agents/Kiro/utils
Fix bug in Kiro transformer where commandNames was incorrectly passed to replacePlaceholders for reference files. Add dedicated test suites for Agents and Kiro transformers, and add unit tests for replacePlaceholders and prefixSkillReferences utilities. (107 → 164 tests) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
472273942c |
Fix broken tests to match actual implementation
The test suite was significantly out of sync with the actual codebase
after a major refactoring from a command+skills architecture to a unified
skills-only architecture.
Changes:
- Updated all transformer tests to match new API:
- Transformers now take (skills, distDir, patterns, options) instead of (commands, skills, distDir)
- Output paths changed (e.g., .cursor/skills/ instead of cursor/commands/)
- Removed tests for GEMINI.md and AGENTS.md files (no longer generated)
- Updated utils.test.js to match readSourceFiles behavior:
- readSourceFiles now returns { skills } only, not { commands, skills }
- Skills are read from directory structure (source/skills/{name}/SKILL.md)
- Fixed reference file ordering expectations (fs.readdirSync is not ordered)
- Updated build.test.js to match new build orchestration
- Fixed expectations for placeholder replacement behavior
- Added missing readPatterns import to utils.test.js
All 107 tests now pass.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
||
|
|
661293796c | initial commit and build out |