* 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>
Upgrade @babel/parser from 7.29.7 to 8.0.4 and raise the repository Node 22 minimum from 22.12.0 to 22.18.0 across package metadata, CI, and npm documentation.
No parser API migration was required. Validated with the full local suite and refreshed GitHub CI on Node 22.18.0 and Node 24.
Prepared and validated with AI assistance from OpenAI Codex under maintainer instructions.
Version bumps for all three components plus the build:release sync of
the tracked harness dirs and the plugin subtree at 4.0.4, rebased onto
the composition-axes work so the release carries both threads.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
Bump the npm package and regenerate the browser detector bundle with
the advisory tier, entity-aware em-dash counting, and the
undersized-ui-text rule.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A cheap, LLM-free E2E tier for the interactive parts of new-work, mirroring
the two-layer live-e2e pattern (deterministic now, opt-in LLM tier later).
- generate-image.mjs: IMPECCABLE_IMAGE_GEN_FAKE=1 writes a deterministic
offline image (SVG with wrapped prompt + SYNTHETIC COMP label, or a valid
palette-stripe PNG carrying the prompt/marker in a tEXt chunk). Same CLI
contract, no key, no network, $0.00 cost line.
- tests/new-work-e2e/user-bot.mjs: scripted user bot (module + CLI) that
resolves the serve-question daemon from the workspace and drives the real
page via Playwright (pick, re-roll + steer, canon, tab close).
- tests/new-work-e2e.test.mjs: node --test coverage of the serve-question
cycles (pick + CHOSEN CARD, re-roll + --update re-deal, canon + CANON
CHOSEN, tab-close exit-4, text-only card) plus fake image determinism.
- Registered as the opt-in new-work-e2e suite; added test:new-work-e2e.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The v4 repo split dropped astro/wrangler from devDependencies, which
also removed the only (transitive) source of @babel/parser. The
post-apply syntax check in live-copy-edit-agent.mjs requires it to flag
invalid JSX/TSX; without it the check silently degrades to a warning and
tests/live-copy-edit-agent.test.mjs "flags invalid JSX syntax" fails on a
fresh CI install. Production behavior is unchanged: the require stays an
optional, graceful-degrade path for end users, and @babel/parser was
never in the published package's runtime dependencies. Declaring it as a
devDependency just makes the repo's own test environment deterministic.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Bump skill to 4.0.0 (plugin.json + marketplace.json) and the CLI to
3.3.0 (package.json), then run build:release to regenerate the plugin
subtree and all provider harness output to the new versions.
Skill 4.0.0 ships external-dice direction assignment, the reviewed
world catalog dealt through the roll API with rendered quality-bar
cards, the in-browser serve-question decision page, visualize-before-
build, the rebuilt new-work flow, and the 58-rule detector under hook
enforcement. CLI 3.3.0 grows the deterministic detector to 58 rules
and adds config-declared context roots, per-file rule scoping, and
--target resolution for nested products.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
/api/roll deals deterministic challenger rolls server-side (same salts and
sha256 ranking as the local seed, verified bit-for-bit); the request log is
the impression record. /api/chosen takes the anonymous choice ping. Events
land in Workers Analytics Engine.
concept-seed.mjs resolves data in order: local catalog dir, roll API,
degraded promotion-only seed. --chosen sends the choice ping; DO_NOT_TRACK
and IMPECCABLE_NO_TELEMETRY disable it. API-dealt seeds carry the telemetry
instruction inline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Update the coordinated AI SDK stack plus Anthropic, Google GenAI, Astro, and Wrangler minor/patch releases.
Validated with a frozen Bun install, full build, full test suite, and green GitHub checks.
AI assistance: Codex performed dependency review and validation under maintainer automation instructions.
Compare direct Sol execution with cold and persistent app-server paths using identical full-task quality gates, lifecycle timings, and token metrics.\n\nAI-assisted: OpenAI Codex.
Benchmark realistic bolder and polish tasks across fast, full-model, and full-context worker profiles with deterministic and independent quality gates.\n\nAI-assisted: OpenAI Codex.
Measure framework and provider latency, enforce fidelity and cleanup gates, and publish reproducible results on the dev-only Live Lab.\n\nAI-assisted: OpenAI Codex.
Eval evidence showed the per-edit PostToolUse stream fires overwhelmingly
on copy-level rules (em-dash-overuse ~97x/session) and measurably makes
models more conservative, while a full-detector pass at completion is what
actually fixes contrast/padding/glow. Split the hook accordingly:
- Per-edit (PostToolUse) now surfaces only IMMEDIATE_TIER_RULES: broken
output (broken-image, text-overflow, clipped-overflow-container,
body-text-viewport-edge), objective contrast/legibility failures
(low-contrast, gray-on-color, tiny-text), single-property mechanical
slop (gradient-text, dark-glow), and design-system drift (the four
design-system-* rules, which compound if left uncorrected). Everything
else defers. Override with hook.perEditRules: "all" in
.impeccable/config.json. Tiering is off for Cursor/Copilot harnesses,
which have no Stop pass wired, so nothing gets silently dropped there.
- Stop deep pass (runStopHook): runs the FULL rule set over every UI file
touched this session (tracked via the existing hook.cache.json session
state; deferred-only edits now mark the file touched), dedupes against
everything already surfaced per-edit, honors ignore-rule/file/value and
inline disables, reuses the [impeccable@1] envelope, and no-ops fast
when no UI files were touched. Emits hookSpecificOutput
{ hookEventName: "Stop", additionalContext } per the Claude Code SDK
Stop contract (conversation continues so the model can act on it).
Second Stop fire is silent - deep-pass findings are remembered.
- Wiring: Stop entries (timeout 30) in plugin/hooks/hooks.json, the
.claude settings + .codex hooks manifests (transformers + hook-admin
repair path). Claude Code and Codex both dispatch a native Stop event;
Cursor's stop hook is inconsistently dispatched (pre-write gate stays)
and Copilot's agentStop/sessionEnd don't inject model context, so
neither gets a Stop entry - documented in reference/hooks.md.
- Tests: tiering split/override/harness gating, Stop dedupe + silent
no-touched-files + ignore machinery + kill switches; existing per-edit
tests moved to immediate-tier rule ids. 181 tests green; smoke-tested
the built dist skill end to end (glow surfaced per-edit, em-dash only
at Stop, second Stop silent).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Lower the CLI engine floor to Node 22.12 so npx no longer falls back to stale 2.x releases for Node 22/23 users.
Add Node 22.12 CI coverage while preserving the stable required test check, and document the 3.2.1 CLI release notes including the detector and installer fixes already waiting on main.
AI-assisted-by: Codex
On Node v24.16.0 / v26.1.0+, `impeccable install` printed "Downloading
impeccable skills...", exited 0, and installed nothing. A Node streams
regression (nodejs/node#63487) made pause()/resume() no-ops on destroyed
streams, stalling extract-zip's yauzl/fd-slicer read stack partway through;
its promise never settled and the process exited clean with no error.
Swap extract-zip for fflate across both extraction call sites
(downloadAndExtractBundle, copyOrExtractLocalBundle) via a new extractZip
helper. fflate decompresses from an in-memory buffer and never touches the
fs stream path, so it is immune on every Node version. It is pure JS with
zero dependencies, so the Windows fix from #198 (no `unzip` binary) holds.
Unlike extract-zip, fflate is actively maintained.
Because extractZip writes entries itself, it guards against zip-slip (`../`
entries escaping the target dir). Tests add a many-file regression guard
(fails on partial extraction) and a zip-slip rejection test.
Verified end-to-end: the real 1,194-file universal bundle extracts and
installs completely.
Fixes#250.
Co-authored-by: Claude <noreply@anthropic.com>
* docs: add PRD for design detector hook integration
Plans a PostToolUse hook for Claude Code and Codex that runs the
existing design detector after every relevant file write and feeds
findings back to the agent as advisory system-reminder context. No
implementation in this commit; covers UX, technical design, build
pipeline changes, distribution, coverage tradeoffs, and rollout.
Co-authored-by: Cursor <cursoragent@cursor.com>
* docs: revise hook PRD with best-practices review
Folds in the P0/P1/P2 findings from an online best-practices critique
against the official Claude Code and Codex hook references plus 10+
2026 community guides and similar prior-art tools (claw-hooks,
claude-code-hooks-mastery).
Key changes:
- Exec form everywhere (Codex snippet was shell form), with Windows
rationale.
- Default timeout dropped from 10s to 5s.
- Re-entrancy guard (CLAUDE_HOOK_DEPTH) and per-file edit counter.
- Session-scoped finding dedup promoted from open question to v1.
- Per-language inline-ignore syntax map (HTML/JSX/CSS/JS).
- Hard-skip rules for sensitive paths and generated/lock files.
- Honest framing about Claude Code lacking per-plugin hook disable.
- Honest framing about Bash-written files being invisible in v1.
- Codex Windows-not-supported call-out, feature flag note, trust ceremony detail.
- Optional NDJSON audit log via IMPECCABLE_HOOK_LOG.
- Findings cap lowered 8 → 5 with attention-budget rationale.
- Versioned envelope ([impeccable@1]) on rendered template.
- Expanded test plan, decision log, and stdin payload appendix.
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(hooks): ship the design detector hook for Claude Code and Codex
Implements docs/hooks-prd.md: a PostToolUse hook that runs the
impeccable design detector after every Edit/Write/MultiEdit on a UI
file and pushes findings into the agent's next-turn context as a
short system reminder. Silent on clean files. Never blocks an edit.
Why this matters: today, design slop (side-tab borders, gradient
text, purple/cyan palettes, bounce easing, etc.) only gets caught
when a human notices or someone explicitly runs /impeccable audit.
The hook closes the loop at the moment slop is written.
What ships in v1
- skill/scripts/hook.mjs: PostToolUse entry. Reads stdin, runs the
detector in-process (no `npx impeccable` cold start), emits
hookSpecificOutput.additionalContext when fresh findings exist.
- skill/scripts/hook-lib.mjs: extracted helpers (config, cache,
filter, render, audit log, runHook orchestrator). 100% unit-testable.
- skill/scripts/hook-session-start.mjs: SessionStart greeting,
gated by a project-scannable probe + 30-day throttle.
- skill/scripts/hook-admin.mjs: backs /impeccable hooks
on/off/status/ignore-rule/ignore-file/reset.
Hardening built in
- Re-entrancy guard (IMPECCABLE_HOOK_DEPTH) so the hook can never
recursively spawn itself.
- Hard-skip regexes for sensitive paths (.env, .pem, id_rsa,
secrets, credentials, .git) and generated/lock/build output. These
fire before the file is even read; cannot be turned off via config.
- Path-traversal check on the inbound file_path.
- Session-scoped dedup keyed by (session, file, rule, line) so the
same finding never lands in context twice. Prevents the ~12.5K
wasted tokens per chatty session called out in the PRD.
- Per-(session, file) edit counter with a one-shot suppression
notice on the 7th edit, silent after.
- Fail-open contract: every error path returns exit 0 with no
stdout. Optional NDJSON audit log via IMPECCABLE_HOOK_LOG.
Three kill switches (precedence high to low):
1. IMPECCABLE_HOOK_DISABLED env var (1/true/yes/on, case-insensitive)
2. .impeccable/hook.json `enabled: false`
3. /impeccable hooks off slash command (writes the JSON)
Inline ignores are language-aware. `// impeccable: ignore <rule>` for
JS/TS, `<!-- impeccable: ignore <rule> -->` for HTML/Vue/Svelte/Astro,
`{/* impeccable: ignore <rule> */}` for JSX/TSX, `/* impeccable:
ignore <rule> */` for CSS. `*` matches any rule. Directive applies
to the next non-blank line. Same shape as ESLint, Stylelint, Biome.
Build pipeline
- scripts/lib/transformers/hooks.js: per-provider hooks.json
builders, plus the slim .codex-plugin/plugin.json manifest.
- providers.js: emitHooks: 'claude' for claude-code, emitHooks:
'codex' for codex and agents. Codex also emits emitCodexPlugin.
- factory.js: emits hooks/hooks.json next to the skills tree.
- build.js: syncs hooks/ into harness roots and into the slim
plugin/ subtree; writes .codex-plugin/plugin.json. Build is
idempotent (verified: 98 staged files unchanged across two runs).
Claude Code wiring uses exec form (command + args) and the
${CLAUDE_PLUGIN_ROOT} placeholder. Matcher: Edit|Write|MultiEdit.
`if:` glob filters to UI extensions before spawning Node. PostToolUse
timeout 5s, SessionStart timeout 3s.
Codex wiring uses ${PLUGIN_ROOT} (Codex's native placeholder),
matcher Edit|Write|apply_patch, no `if:` analog (the script does the
extension filter). macOS and Linux only; hooks are disabled on
Windows in current Codex builds. The trust ceremony and feature flag
are documented in README.md.
Routing
- /impeccable hooks lives outside the 23-command router table on
purpose: it is plumbing, not a design skill. The hidden
routing slot is added to SKILL.md alongside pin/unpin so the LLM
knows to dispatch it. The 23-command count and all stale-count
validators remain happy.
Tests
- tests/hook.test.mjs: 38 unit tests covering env parsing, config
load + defaults + malformed, cache round-trip + GC,
ignoreRules/minSeverity/inline ignores (all four languages),
globbing with **/*/{a,b}, render template with cap + clamp + 0-line
prefix drop, audit log NDJSON, payload event-name parameterization,
re-entrancy, kill switches, sensitive-path + generated-path +
traversal skips, allowlist filter, config ignoreFiles, edit
counter cycle including the 7th-edit notice, MultiEdit and
apply_patch payload shapes, detector throw swallow, malformed
stdin, missing file race.
- tests/hook-build.test.mjs: 18 integration tests covering hook
manifest shape (matcher, timeouts, exec form, if: glob, placeholders),
Codex differences (${PLUGIN_ROOT}, no if:, no SessionStart),
Codex plugin manifest (no inline hooks field to avoid the
duplicate-file error), routing across the hooksJsonFor table, and
presence of all three committed artifacts plus the bundled detector
the runtime relative-import path depends on.
Full suite: 175 bun tests + 186 node tests, all green.
Docs
- README.md: new "Design hook" section explaining default behavior,
per-project / global / inline disable paths, the JSON schema knobs,
the audit log debug flag, and the slop / a11y coverage split.
- HARNESSES.md: flips the `hooks` row for Codex from No -> Yes
(Claude was already Yes), adds a per-harness hook-surface table
with the manifest location and matcher each provider uses.
Open questions from the PRD intentionally deferred to v2: Bash-write
blind spot, effort-aware suppression, Stop-hook session summary,
per-rule severity, async hook mode. None block v1.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix Codex hook scanning: apply_patch paths and co-located stylesheets
Parse file targets from Codex apply_patch command bodies, co-scan imported
and sibling CSS when UI components are edited, drop the git-sweep PostToolUse
group, and align Codex SessionStart manifest and trust docs with the official
hooks spec.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Gitignore hook session cache and drop local test HTML
Hook dedup/throttle state in .impeccable/hook.cache.json is per-project
runtime data like other .impeccable/ sidecars. Remove an untracked
bad-nested-flexbox scratch page from site/public/.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix Claude Code hook: drop Edit-only if filter so Write/MultiEdit fire
Claude's if permission rule binds to one tool name, so Edit(*.{…}) never
spawned the hook on Write or MultiEdit despite the matcher listing them.
Extension filtering now lives in hook-lib on both Claude and Codex.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Surface Cursor design findings via stop-hook followup
Replace dropped postToolUse additional_context with afterFileEdit recording
and a one-shot stop followup_message so anti-pattern nudges reach the agent.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Fix design hook packaging and scans
* Fix Cursor hook pending bucket fallback
* Fix Sass hook scan coverage
* Fix Cursor hook review findings
* Fix session start dead hook normalization
* Fix hook config and relative scan paths
* Remove SessionStart design hook
* Remove redundant afterFileEdit normalization
* Fix Cursor suppression and module style scans
* Fix sensitive path hook filter
* Fix disabled Cursor stop hook emission
* Refresh hook harness artifacts
* Fix Cursor hook manifest install
* Add hook ignore-value support
* Ignore hook runtime files locally
* Fix Codex plugin hook packaging
* fix: address PR review bot findings
Block numeric hook depth counters from re-entering.
Avoid following stylesheet imports from traversal-looking hook targets.
* fix: gate ignore-value suggestions by supported rules
Only render exact ignore-value commands when the same finding can be suppressed by ignoreValues.
* Package Codex plugin as hook-only
* Remove Codex plugin packaging
* Recover hook install probe plumbing
* Remove Codex hook packaging follow-up doc
* Remove extra hook docs and skill wording changes
* Install real design hooks via skills CLI
* Add provider hook smoke runner
* Fix Cursor hook delivery with preToolUse gate
* Simplify Cursor hook install to preToolUse
* Clarify confirmed hook exceptions
* Persist hook ignores in shared config
* Guard font hook exceptions
* Fix hook install after main rebase
* Fix hook scan target handling
* fix: address hook review findings
* Address hook review feedback
* Stabilize DeepSeek insert live fixture
* Fix Cursor hook Python shell write bypass
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
* Improve CI test coverage
* Stabilize live E2E harness
* Shard live E2E CI
* Cache live E2E CI dependencies
* Stabilize live E2E smoke CI
* Update generated live browser bundles
* Tighten live E2E smoke runtime
* Prevent live E2E smoke hangs
* Stabilize live E2E CI coverage
* Fix stale accept DOM cleanup
* Regenerate live browser outputs