mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-21 18:47:02 +03:00
502f0f28b55520f4286ac1353f3f73e5058739e9
421
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
71a3341289 |
bake: the anchor must have matched one element on the page
The lasting rules a bake appends apply to every element the anchor matches, so a `tag.class` anchor shared by siblings (three cards from one JSX element, say) restyled all of them, not the element the user picked. The overlay now journals, with the generate event, the anchor it would bake on (`element.anchor`: the id, else the tag with its classes) and how many elements matched it when Go fired (`element.anchorMatches`). The planner bakes only when the source anchor is that same selector and the count is one; otherwise it leaves the carbonize block with the count in `bakeSkipped`, and the agent integrates the variant by hand. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
695d1bd515 |
generate: plan, tune, and accept exactly like live
The lane's variants were tamer than the ones a live session makes on the same element: its poll instructions replaced live.md's planning method with a cheat sheet, its reference forbade knobs, told the agent to copy the markup verbatim and to treat DESIGN.md as a hard boundary, and its accept appended anchored overrides instead of integrating the design. Measured on the same page with Opus, live runs promoted a tier, broke the grid, and declared knobs; lane runs restyled three equal boxes. Now a Go the generate verb fires gets the same _instructions as a user's Go (the action's reference, section 4 planning, knobs per section 7), generate.md hands the design work to live.md's Handle generate and its Required after accept, Setup runs as for any command, the Tune chip behaves as in any session, and the mechanical bake is opt-in (--bake) instead of the lane's default. The start verdict points at live.md, and `browser` (the config key the opener reads) is a recognized key. Goldens re-recorded for the accept help and the recognized-keys line. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
496b386504 |
overlay: a lane session shows the variant bar and nothing else
The generate lane hides the helper's global bar, but the overlay drew it first and hid it on `connected`, the Tune chip spun for the seconds between the variants mounting and the done reply even though the lane declares no knobs, and the agent-target pick rendered the edit-copy pencil with its "disabled while applying" tooltip. The served script's prelude now says when the bar is hidden so it is never drawn; a session records who fired its Go (`sessionOrigin`, saved with the session) and never shows the pending Tune chip when the generate verb did; the agent-target pick suppresses the edit-copy badge for the session. A user's own pick, Go, and session are unchanged, and the source test pins every gate. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
65c8089182 |
Only the lease holder may answer an agent target; leave a plain bar alone
Review found that /agent-target-result checked the shared helper token and nothing else, so any connected overlay could resolve a target it never claimed. A result post now names the overlay (`clientId`), and while the target is pending only its lease holder's word lands: a bystander gets 409 (not_holder, or unclaimed when nobody holds it) and the request stays pending. The overlay sends its client id with every result. Every protocol case now answers from the tab that actually holds the claim. Also: the helper-wide bar preference is applied on every connected frame, and restoring wrote an empty display value, which dropped the bar's own inline flex layout for a plain live session that never asked for anything. Hiding remembers the bar's display value, restoring puts exactly that back, and a restore on a visible bar is a no-op. A plain boot through the launcher keeps display: flex after connect and its payload carries none of the lane's keys. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
1a699913e4 |
Make the generate lane's bar preference helper-wide
The maintainer still saw the bottom bar: two tabs were connected to the helper, the tab that won the roll call hid its bar, and the tab on screen never did. The hide was also applied only at Go, so the wait before it showed the bar as well. The helper now owns the preference. `impeccable live --no-live-bar` posts `/live-bar` right after the helper is up, so the bar never appears in any tab; an agent target carrying `hideLiveBar` sets the same flag before the target goes out. The helper broadcasts `live_bar` to every connected tab, answers `hideLiveBar` on every `connected` frame (reloads, later tabs) and on `/status`, and the flag lives as long as the helper. The overlay just follows: no per-tab memory, no session scoping, the variant controls still show. The same preference skips the overlay's "No PRODUCT.md found" connect notice, which sent the user to init inside a lane that runs without context by design. Verified in a real Chromium session with two tabs, screenshots at each stage: idle (bar in both), after Go (bar gone in both), after reloading both, after the accept during the bake, after a reload after that. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7c42d0feba |
Keep the live bar hidden for the helper's lifetime, not the session's
The maintainer still saw the bottom bar on the generate lane: the hide was released the moment the accepted session ended, which is the start of the agent's bake, so the bar sat there for the minute until the helper stopped. The choice now lives in sessionStorage keyed on the helper token: applied at Go, re-applied by every reload's bar rebuild, kept through the accept and the bake, and forgotten only when the helper stops and takes the overlay with it. The next `impeccable live` boots with the bar again. Verified in a real Chromium tab: hidden through a reload, the accept, and a reload after the accept; the helper stop removes it entirely. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e3a121d081 |
Generate lane: settle the Tune state without knobs, and hide the live bar on request
Two things the maintainer hit testing the lane. The Tune chip spun forever after a generation whose variants declared no knobs (the lane's default). The overlay flips the parameter phase to pending at Go and only settled it when the wrapper mounted; the page reloads on the JSX write, the resumed session restores "pending" from its cache with the variants already mounted, and the agent's done reply never re-checked. Now the done reply completes the phase once every variant is mounted, and a resume with a pending state asks the helper's session record whether that generation already finished. A generation with no knobs shows no chip; one with knobs shows them. `live-generate --no-live-bar` (body `hideLiveBar: true`, forwarded on the agent_target payload) keeps the helper's global bar hidden for the session it starts; the variant controls still show, the choice survives a reload through the session cache, and the bar returns the moment that session ends on any path. generate.md passes the flag. Verified in a real Chromium tab: no chip before and after a reload, bar hidden through the reload, bar back after the accept. Rust and protocol cases for the flag, a CLI parse test, contract pins for both fixes. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
76db418212 |
Address review: every answered agent target fences a late Go
Only targets answered with a session were fenced against a delayed generate event. A request that timed out (or ended in another failure verdict the CLI already reported) was simply forgotten, so a Go whose capture outlasted the timeout still opened a session nobody was told about. `resolve_agent_target` now records every terminal resolution, with the answering session when the verdict carried one, and `agent_target_refusal` refuses a generate event for any answered target unless it comes from the answering session itself. The browser_timeout instructions no longer send the agent to live-status for a session that can no longer start. The overlay's refusal toast covers both causes. Tests: a Rust integration case and a Node protocol case (claim, time out, late Go refused with 409 and nothing journaled), a unit test for the timeout instruction; contract doc updated. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7adb81672d |
Address review: a superseded Go never opens a second session
An overlay renews its lease right before Go, then captures and uploads the element before its generate event leaves. When that outlasts the lease and its result post is lost, a rescuer can claim the target and Go, and the helper accepted both generate events: two sessions for one request. The generate envelope now carries this page's clientId, and the helper refuses a generate event for a target that another page holds under a live lease, or that was already answered with a different session (`served_agent_targets`, recorded on every ok resolution): 409 `agent_target_already_served`, nothing journaled. The overlay treats that refusal like a foreign session and hands the surface back. The answering session's own event stays welcome, so the common path (result post first, then the event) is unchanged. Tests: two Rust integration cases (rival lease, answered elsewhere, welcome for the serving session) and a Node protocol case, contract pins for the envelope and the refusal handling, contract doc. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
b5210471fb |
Address review: the generate event resolves the agent target it serves
A winning overlay could reload after handleGo() minted a session but
before its result post landed. The close released its lease, the
server replayed the still-pending target, and another tab (or the
reloaded page, once it abandoned the unknown session) could claim it
and fire a second Go for a request that already had a session.
The overlay now names the target on the generate event it fires for it
(`agentTarget: {targetId, result}`, the same result it posts), and the
helper resolves the pending request the moment that event is accepted,
stripping the envelope before journaling. Whichever of the event and
the result post lands first answers; a page that dies between Go and
its result cannot leave the request pending, and a request whose event
never reached the helper is served exactly once by the rescuer.
Tests: a Rust integration case and a Node protocol case (claim, Go
event without a result post, verdict carries the session, a late claim
finds nothing pending, the journal carries no envelope), contract pins
for the handoff, and the contract doc.
Written with AI assistance (Claude).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
335945525d |
Address review: a done target stays off-limits for a replay
Marking a target done on reply opened a window: an EventSource reconnect replays the still-pending target while the result is on the wire, the tab is GENERATING by then, so it declined busy, the server handed the lease back mid-resolution, and another tab could claim and fire a second Go. `agentTargetTaken` now covers both acting and done, so a replay of a target this page took a lease on is ignored, and the late-mount watch stops on either. Contract pins for the guard and the watch. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a3bb21cbde |
Address review: one Go per tab, declines for a granted miss, and grace per overlay
Four review threads on the agent-target protocol and the hook stand-down. Overlay: a tab acting on one target is busy for every other target (`agent_target_in_flight`), so two held generate requests can never both be claimed by one tab and the second Go can never overwrite the session the first one minted. Every exit from actOnAgentTarget ends the acting state, and teardown clears the target ledger, so a Go that never happened does not refuse the next connection's targets. A miss after a granted claim now declines (handing the lease back so another page or a remount can serve) instead of posting a result that ended the request for every tab. Hook: the live-preview marker probe runs before the per-session edit cap, so a file already past the cap stands down for a variants wrap instead of emitting the suppression notice. Server: each overlay's first no_match word extends the resolution grace by the full window (its watch re-reports do not), so an overlay that reports after another page's grace lapsed still gets its late-mount watch instead of completing the roll call with a no_match verdict. Tests: a Rust and a Node protocol case for the late overlay's grace, a hook case for the cap-then-wrap order, and contract pins for the busy check, the decline on a granted miss, and the teardown clear. Written with AI assistance (Claude). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
79a27051a2 |
Address review: hold an all-no_match roll call open for a resolution grace
When the unresolvable page's decline was the last word, the roll call completed on it, the answer said pending:false, and the page's watcher never started, so an element that mounted a moment later was still answered no_match. A page's no_match is a provisional word: the server now keeps an all-no_match roll call open for IMPECCABLE_AGENT_TARGET_RESOLVE_GRACE_MS (default 3000) after the first such report, re-judging when the grace lapses, so a page that keeps watching can still claim (the stale report is dropped on its eligible claim); a busy report still answers at once. The overlay reports a miss immediately and re-checks every half second for as long as the answer says pending. A genuine no_match now takes about the grace instead of tens of milliseconds, inside the server's hold. Rust integration case for the late mount claiming within the grace, the protocol case, and the contract assertions updated; the contract documents the grace and its env override. AI-assisted: implemented and tested with Claude Code under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
bd4ec3a11c |
Address review: the server ends the resolution watch, and a reconnect re-participates
Two ways a page's word could go stale after the resolve-before-claim change: an element that mounts later than the quick re-checks, and an EventSource reconnect that did not overlap the old connection (the server drops that page's word on the close, replays the target, and the replay guard ignored it, so the roll call waited on a word that never came). A decline's answer now carries pending, like a denied claim does, so a page that could not resolve the target reports the miss after the quick re-checks (the roll call can complete on the other overlays' words) and keeps re-checking once a second for as long as the server says the request is pending, claiming the moment the element mounts; the server drops the stale report on an eligible claim and ends the watch by answering pending:false once the request resolved or timed out. The overlay tracks its participation per target: a replayed target is ignored only while this page is acting on it, and is otherwise handled again, so a busy or unresolvable page re-declines (idempotent) and an idle page claims. Unit, protocol, and contract cases updated; the decline answers now say whether the request is still pending. AI-assisted: implemented and tested with Claude Code under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
46f1dd6b36 |
Address review: re-check a failed resolution before declining an agent target
A page's element can be momentarily absent (a route still rendering, an HMR commit mid-swap), so a failed resolution is not that page's final word. The overlay now re-checks at 300, 700, and 1500 ms, claims the moment the element mounts (the server already drops the stale report on an eligible claim), and reports only the last miss. A genuine no_match now takes about two seconds instead of tens of milliseconds, well inside the server's hold. Also normalizes a path separator in the new hook unit test, which failed on rust-windows because the audit's file path carries backslashes there. AI-assisted: implemented and tested with Claude Code under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
25263adc51 |
Roll call: a page that cannot resolve the target declines instead of claiming
Field-testing with two pages open showed the first-wins claim letting the wrong page answer: a tab whose page lacks the element won the claim, resolved the selector locally, and replied no_match while another page had the element. The overlay now resolves the selector before any claim and, when its page cannot resolve it, declines with reason no_match and the resolution verdict; the same check runs on the busy-to-idle re-claim. The server records that verdict on the report and, once every connected overlay has declined, prefers a report that could serve later (a tab mid-session or with an apply in flight, which answers busy so the agent retries) over no_match, and returns the resolution verdict only when no page can serve; the timeout uses the same precedence. Also from the same field tests: a tab on another page of the app was resuming this page's session from the per-origin localStorage cache after a dev-server reload re-initialised it, then sat in GENERATING for a wrapper it never renders and declined every later target. restoreSessionWithoutWrapper now resumes a cached session only on the page that saved it, the check the server-adoption branch beside it already applied. Covered by two Rust integration cases, two protocol cases, and contract assertions for the resolve-before-claim path and the page gate; the cross-page scenario of the field harness passes on a two-page site. AI-assisted: found by field tests and fixed with Claude Code under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
da403a3410 |
Address review: the overlay, not the connection, is the roll-call participant
An EventSource reconnect opens a replacement connection under the same page-level clientId before the old connection is seen to close, so the close handler used to retire the reconnected overlay's report and hand its lease back mid-flight. remove_sse_client now retires a client's word only when no other connection still carries its id, the roll call counts distinct overlays (plus id-less connections) instead of raw connections, and the overlay ignores a replayed target it already handled, so a reconnect never starts a second claim or a second Go. Covered by two new HTTP cases in crates/cli/tests/agent_target.rs, a protocol case in tests/live-agent-target.test.mjs, and the overlay contract suite. AI-assisted: implemented and tested with Claude Code under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d397140a77 |
Port /impeccable generate to the engine crates
The Node-era server, CLI, hook, and pin halves of the generate command move into the Rust workspace, with the protocol unchanged: - crates/live: POST /agent-target is held open on a channel plus a timer thread (the manual-apply deferred pattern), releasing its turnstile ticket before it parks like /poll; /agent-target-result resolves it; /agent-target-claim is the roll call with its renewable lease. SSE connections carry the overlay's clientId: a late overlay is replayed every pending target, and a disconnect retires that overlay's report, releases its lease, and re-judges each roll call. Shutdown drains held requests with server_stopping. - crates/live/src/live_generate.rs: the live-generate verb (the router already forwards every live* verb), same flags, verdicts, and _instructions, spelled with the engine's self command. - crates/hook: every entry stands down on live preview markers (skipped: live-preview), checking the proposed content and the file on disk for hook-before-edit. - crates/context: pin accepts generate; the crate's command-metadata.json copy carries its entry. Tests: crates/cli/tests/agent_target.rs (six HTTP cases with an SSE reader), tests/live-agent-target.test.mjs rewritten to drive the binary (28 cases, registered in the live suite), hook stand-down cases, oracle goldens for live-generate plus the re-recorded pin list goldens, the e2e prompt assertion waiting for the journaled event, and the contract documented in docs/CLI-CONTRACT.md. AI-assisted: implemented and tested with Claude Code under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
fc89b0ed62 |
Add /impeccable generate: agent-initiated live variants (Node-era squash)
Squash of the ten commits reviewed on PR #626, plus the last review round's connection-aware roll call, before the rebase onto the Rust engine: the generate command reference and router row, the overlay's agent-target handling (roll call, leases, replay, rescue), the Node-era live-server routes and live-generate CLI, the hook stand-down, the pricing cards e2e fixture, and the unit, contract, e2e, and skill-behavior tests. The server, CLI, hook, and pin halves are ported to the engine crates in the commits that follow. AI-assisted: implemented and tested with Claude Code under maintainer direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
a8ce5962d3 |
Fix silent launcher setup failures (#788)
* Fix silent launcher setup failures Report cache creation, cache write, and download failures with recovery guidance while preserving lazy engine downloads. AI-assisted by Codex. * Fix Windows staging-write failure handling Branch directly on redirection failure and reject staging directories before cleanup. Add coverage for an existing read-only staging file. AI-assisted by Codex. |
||
|
|
73a6f51a54 |
Release engine 0.1.5, CLI 4.1.0 and skill 4.3.0 (#787)
* Release engine 0.1.5, CLI 4.1.0 and skill 4.3.0 Ship GPT Image 2.5 Flare and native transparent assets. Refresh generated provider distributions for the release. Prepared with AI assistance under the maintainer's instructions. * Fix: lock released engine platform packages Regenerate all five 0.1.5 platform resolutions after npm publication and verify frozen installation. Prepared with AI assistance under maintainer instructions. |
||
|
|
12ffee04c2 |
Release engine 0.1.4, CLI 4.0.5 and skill 4.2.3 (#782)
Engine assets and all five platform packages are published and verified. Frozen install, CLI download fallback, and regression checks passed. AI assistance: Codex, under maintainer direction. |
||
|
|
f64da20b07 |
Release: engine 0.1.3, CLI 4.0.4 and skill 4.2.2 (#752)
* Release: prepare engine 0.1.3, CLI 4.0.4 and skill 4.2.2 Ship the merged DeepSeek Harness, picker and launcher-refusal fixes. Intentionally refresh generated provider and plugin release metadata. Keep this branch off main until all engine binaries and npm platform packages exist; refresh bun.lock after publication. AI assistance: Codex, under maintainer direction. * Release: lock published engine 0.1.3 packages Refresh exact platform package resolutions after publication. All five npm binaries match the checksum-verified release assets. Addresses both lockfile review findings. AI assistance: Codex. |
||
|
|
831cabee8b |
Release: CLI 4.0.3 and skill 4.2.1 with signed Windows engine (#743)
* Release: prepare signed engine 0.1.2 Bump engine and platform-package pins for the first Azure-signed Windows release. Keep this branch off main until release assets and all platform packages are published; refresh bun.lock after publication. AI assistance: Codex. * Release: CLI 4.0.3 and skill 4.2.1 Ship the verified signed Windows engine 0.1.2. Refresh provider/plugin version metadata and engine pins intentionally for release. All five platform packages are published and byte-verified. AI assistance: Codex. |
||
|
|
6e61113e3c |
Fix: report removed launcher downloads accurately (#741)
* Fix: distinguish removed launcher downloads from checksum failures Related to #740; keep the antivirus investigation open. Add executable launcher regressions and a native Windows CI lane. AI assistance: prepared with Codex under Paul Bakaus direction. * Fix: diagnose downloads removed during cache placement Cover removal and truncation around rename and preserve fail-closed behavior through cache placement. AI-assisted under maintainer direction. * Test Windows launcher hash and placement failures Inject failures at command boundaries in a staged test copy while retaining real launcher control flow. Cover both platforms with the same assertions. AI-assisted under maintainer direction. |
||
|
|
eebfb7c2ce |
Release: CLI 4.0.2 and engine 0.1.1
Ship signed skill-bundle verification, fix annotated-session checkpoint ordering, and pin all published engine platform packages. Validated with Rust, Node, browser, and provider-backed end-to-end tests. AI assistance: prepared and validated with Codex under Paul Bakaus direction. |
||
|
|
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,
|
||
|
|
524fb8c950 |
Live: a discard releases every wrapper it hid
Bugbot on #720: the non-restoreOriginal discard now hides every matching wrapper, but the delayed fallback still released only the first querySelector hit. A target inside a `.map()` renders one wrapper per item, so the rest stayed at display:none and their original content never came back on the static and missed-HMR flows that fallback exists for. The hide, the existence checks, and the release now all speak about the same set. discardedWrappers(sessionId) is the one place that collects it; releaseDiscardedStaticWrappers takes the stylesheet down once and releases each wrapper; releaseDiscardedStaticWrapper drops its sessionId argument and just unwinds the node it is given. The HMR-ownership decision still reads the first wrapper, which is fair: duplicates all render from one source element, so ownership is uniform across them. The reload branch is unchanged because a reload restores every original at once. Covered by a source-shape test rather than an e2e scenario: hasFrameworkHmrOwnership is true for every React, Vue, and Svelte runtime fixture, so all of them take the watcher path and none can reach the static release. The existing framework-ownership guards in the same file move to the new shape and keep their intent, including the one that says only non-discard cleanup may blank the wrapper while waiting for HMR. Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY |
||
|
|
f240348cc5 |
Live: every active-session wrapper lookup goes through the resolver
Cursor Bugbot on #720: findVariantsWrapper alone was not enough. resolveBarAnchor, the visible-variant element, mountedParameterCount, readVisibleVariantFromDOM, showVariantInDOM, the source injection, and the whole accept path still took the first [data-impeccable-variants] match, so in the relocated-wrapper case Tune never bound and the bar kept anchoring to the empty scaffold even after the resume reached CYCLING. Thirteen call sites now resolve through findVariantsWrapper. The resolver split in two so a missing id cannot silently widen the lookup to any session: findVariantsWrapper(sessionId) returns null without an id, and findAnyVariantsWrapper() is the entry point for the two resume paths that have no id yet. Both share pickPopulatedVariantsWrapper, which is the old querySelector whenever there are fewer than two matches. Discard cleanup now hides every duplicate wrapper rather than the first, since a target inside a `.map()` renders one per item and hiding one left the rest of the discarded variants on screen. What still takes a raw first match is deliberate: bare existence checks, selector strings for stylesheets and observers (which want to cover every match), querySelectorAll sweeps, the parsed source document, and the Svelte component wrapper, which holds no variant children at all. The source-shape test pins that exact set by name, so a new raw lookup fails until it is either routed through the resolver or justified there. Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY |
||
|
|
f7c92d9eb9 |
Live: the shader teardown can no longer race its own construction
The new cycling assertion caught a real defect on CI: vite8-react-insert
reached CYCLING with #impeccable-live-shader still painted over the page.
showShaderOverlay is async. It appends its canvas synchronously, then
awaits createImageBitmap and finishes the GL setup before it publishes
shaderState. hideShaderOverlay returned early on a null shaderState, so a
teardown that landed inside that window did nothing, and the construction
then published itself over a session that had already left GENERATING,
with no teardown left to run. The scroll tick kept repositioning it,
which is why the CI page.html shows the canvas sized from the capture
rect but styled to the cycling anchor.
Every teardown now bumps a shader epoch before it does anything else, and
a construction pins the epoch it owns and abandons its canvas (releasing
the GL context) at every point past an await and before any publish,
including both bitmap-fallback publishes. A teardown also drops a shader
node that no shaderState owns, so an already-orphaned canvas cannot
survive one.
Reproduced by widening the append-to-publish window: with a 400ms delay
after uiAppend, vite8-react-insert failed with the CI error and the probe
showed the teardown arriving at CYCLING with shaderState still null.
The same run passes with this change, as does a 1500ms window on insert
and plain. Locally that window is about 4ms, which is why it only showed
on a slower runner.
The four remaining setLiveState('CYCLING') sites that did not lower the
loader now do: the SSE done handler (the one route that can reach CYCLING
from GENERATING), the Svelte republish remount, and the two accept
failure recoveries.
The e2e assertion already waits up to 5s for the shader to clear, so it
was never racing a legitimate teardown; it is left as it is.
Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY
|
||
|
|
6d5f78eebf |
Live: the loader now hands off when the resume is the arrival
The overlay could sit in its generating shader over a DOM that already held all three variants, and only a page refresh cleared it (#719). The server's generation preflight runs live-wrap with --defer-source-write, so the wrapper and every variant reach the DOM in a single HMR batch. The deferred-wrapper scout is constructed at init and the variant MutationObserver at Go; observer callbacks run in construction order, so on that batch the scout resumes first and resumeSession, not the observer, is the transition into CYCLING. It set the state and the bar but never called hideShaderOverlay(), so the frozen capture of the original stayed painted over the variants. It also reported browser_resumed, which does not count as publication progress, and then disconnected and re-created the observer, dropping the records that observer had already queued for the same batch, so variants_ready never fired at all. resumeSession now finishes the same transition the observer does (shader down, inline edit off, insert session finalized, params panel rebuilt) and reports variants_ready when it already holds every variant. The deferred scout names itself in the journal as browser_resumed_deferred_wrapper, so the two resume paths are no longer indistinguishable. Wrapper resolution goes through findVariantsWrapper, which prefers a wrapper that actually holds non-original variants. A target inside a .map() renders one wrapper per item, and an agent that relocates the wrapper out of the shared primitive live-wrap scaffolded leaves an empty one behind; first match could pin either and strand the session at 0/N. With zero or one match this is the querySelector it replaces. Tests: waitForCycling now asserts the generating shader is gone once the bar cycles, across every runtime fixture (it failed on vite8-react-plain before this change and passes after), marked no-retry so the reload recovery cannot hide it. Source-shape tests pin the transition, the variants_ready report, and the wrapper preference. Co-Authored-By: Claude Code <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vau2X53xGTjjTCXWMVBoNY |
||
|
|
3f815865ab |
Self-discard orphaned JSX live sessions again (#716)
* Self-discard orphaned JSX live sessions again (#715) #694 stopped the source fallback from fetching and DOMParser-injecting raw JSX, which was painting {expressions} and comment markers into the page. The JSX gate it put in front of the fetch decided everything from the live DOM alone, and an unmounted wrapper looks exactly like a wrapper that was deleted from the file, so it treated both as "wait for mount": the orphan branch counted down its retry budget and then fell out of the function with no terminal action. A resumed CYCLING session whose region had been edited out of source therefore never reached discardOrphanedSession, the durable snapshot stayed out of the discarded phase, and the picker stayed frozen, which is the #439 regression the live-e2e scenario pins. The fix restores the decision without restoring the parse: probeJsxWrapperForOrphan reads the file as plain text and matches the session marker, so no DOM is ever built from JSX. Marker present means the component is simply not mounted and the observer keeps waiting; marker absent after the same retry budget the HTML path uses means the file moved on, and the session self-discards. 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 * Orphan probe: a source read that fails also retries, then discards Review on #716 (Greptile, Copilot): the probe's empty catch swallowed a failed /source read, so a session whose file had been renamed or deleted (404), or that hit a transient fetch failure, neither retried nor reached a terminal action, which is the frozen-picker failure the probe exists to end. A read that cannot answer now shares the retry budget with a read that answers without the marker, and after the budget the session is discarded with a reason that names the failure. Unit test pins that the probe has no empty catch and that the failure path discards. 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 * Orphan probe: only evidence that the wrapper is gone may discard Review on #716 (Greptile, second pass): after the previous change a transient /source failure that outlasted the 3.6 s retry budget discarded a valid session, and a discard is durable. Now a read that answers without the marker, or a 404 (the file renamed or deleted), retries on the budget and then discards; any other failure retries on the budget and then keeps the session, warns, and tells the user it is checked again on the next event. The unit test pins both halves. 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 --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> |
||
|
|
8b326fc81e |
Fix: resolve unique --target names in monorepos (#700) (#706)
* Fix: resolve unique --target names in monorepos (#700) Bare child names such as Cantaro.Web now match a unique workspace candidate instead of being reported missing. AI assistance: Cursor Grok 4.6 implemented this change. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix: resolve --target once in the context CLI Reuse the resolved path for loadContext so a bare name does not walk workspace candidates twice. AI assistance: Cursor Grok 4.6 implemented this change. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix: match unique --target names after cwd absolutizing Live and other helpers resolve --target against cwd before context.mjs sees it. Treat a missing single-segment path the same as a bare workspace name so those callers still select the unique child. AI assistance: Cursor Grok 4.6 implemented this change. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Paul Bakaus <paul.bakaus@gmail.com> |
||
|
|
fa44839f72 |
Fix detector URL scans and advisory handling (#709)
* Fix detector URL and advisory handling Recover joined URL arguments without splitting local paths, derive advisory behavior from registry severity across consumers, inspect readable linked CSS in URL scans, and report only the dominant primary font. AI assistance disclosure: Implemented and verified with Codex under maintainer direction. * Filter linked CSS to rendered selectors Flatten linked stylesheet grouping rules and collect only selector rules that target the live DOM, preventing unused grouped and selector-less patterns from leaking into URL findings. AI assistance disclosure: Implemented and verified with Codex under maintainer direction. * Fix detector review edge cases AI assistance disclosure: Codex implemented and verified these fixes under maintainer direction. * Preserve unresolved linked CSS selectors AI assistance disclosure: Codex implemented and verified this fix under maintainer direction. * Fix linked CSS selector filtering Resolve pseudo-element selectors to live hosts, reject unresolvable linked CSS findings, and make the regression assertions independent. Also ignore comment delimiters when recovering CSS rule selectors. AI assistance disclosure: This commit was prepared with Codex under maintainer direction. * Skip unresolved container query CSS Exclude linked container-query groups when their current applicability cannot be resolved, with a browser regression proving inactive styles do not leak. AI assistance disclosure: This commit was prepared with Codex under maintainer direction. * Detect active container query CSS Use a temporary custom-property probe so the browser decides whether a nested style rule actually applies in the current container layout. AI assistance disclosure: Codex helped implement and test this fix under maintainer direction. * Filter inactive linked CSS states Keep valid empty pseudo-class matches authoritative and omit selector-less linked at-rules that cannot be tied to rendered nodes. AI assistance disclosure: Codex helped implement and test this fix under maintainer direction. * Parse pseudo-elements without rewriting literals Preserve quoted attribute values and escaped identifiers while resolving real pseudo-elements to live hosts. AI assistance disclosure: Codex helped implement and test this fix under maintainer direction. * Restore live linked keyframes AI assistance disclosure: Codex helped implement and verify this fix under maintainer direction. * Handle grouped linked keyframes AI assistance disclosure: Codex helped implement and verify this fix under maintainer direction. * Respect keyframe definition order AI assistance disclosure: Codex helped implement and verify this fix under maintainer direction. * Resolve effective linked keyframes AI assistance disclosure: Codex helped implement and verify this fix under maintainer direction. * Fix keyframe easing detection Serialize effective per-keyframe easing back into the linked stylesheet corpus so overshoot motion is detected. Add a browser regression with a neutral animation name.\n\nAI assistance disclosure: Codex helped implement and test this fix under maintainer direction. |
||
|
|
672ca29642 |
Fix Next.js 16 CSP and parent hook discovery (#710)
* Fix CSP and hook ancestor discovery Recognize Next.js 16 proxy files when detecting runtime CSP and mirror harness ancestor lookup when locating active hook manifests for nested projects. AI assistance disclosure: Implemented and verified with Codex under maintainer direction. * Tighten hook and proxy discovery AI assistance disclosure: Codex implemented and verified these fixes under maintainer direction. * Honor ancestor hook disable config AI assistance disclosure: Codex implemented and verified this fix under maintainer direction. * Keep hook discovery within target repository Stop manifest discovery at the target repository boundary instead of re-adding an outer workspace root, with regression coverage for nested Git targets. AI assistance disclosure: This commit was prepared with Codex under maintainer direction. * Detect proxy CSP in nested Next apps Recognize proxy files at root or src placement relative to nested Next project markers while continuing to ignore unrelated proxy helpers. AI assistance disclosure: This commit was prepared with Codex under maintainer direction. * Resolve external targets from their own repository Scope explicit sibling targets to their own Git root so caller context and hook manifests cannot suppress required detector guidance. AI assistance disclosure: This commit was prepared with Codex under maintainer direction. * Isolate explicit targets at Git boundaries Keep nested repositories and external targets out of caller and home-level context or hook discovery. AI assistance disclosure: Codex helped implement and test this fix under maintainer direction. |
||
|
|
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. |
||
|
|
38e102f0b2 |
Fix: never inject raw JSX in live-mode fallback (#454) (#694)
* Fix: never inject raw JSX in live-mode fallback (#454) On React/JSX targets, missed HMR used to fetch source and DOMParser-inject it, painting {expressions} and comment markers as page text. Adopt a live wrapper that already has variants, otherwise leave HMR alone. AI assistance: Cursor Grok 4.6 implemented this change. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix: wait for unmounted JSX variants instead of tearing down (#454) A missing live wrapper on React is often a closed modal or other route, not a failed generation. Leave the observer armed so mount can still reach CYCLING. AI assistance: Cursor Grok 4.6 implemented this change. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix: recover empty JSX replace wraps after fallback retries (#454) Insert scaffolds still wait for HMR. A replace wrapper with no variants after retries is a failed generation and should leave GENERATING. AI assistance: Cursor Grok 4.6 implemented this change. Co-authored-by: Cursor <cursoragent@cursor.com> * Fix: align live-reference setup assertions with current SKILL.src.md #689 shortened Setup step 2, but the live-reference tests still expected the old playbook sentence, which kept CI red on main and this branch. AI assistance: Cursor Grok 4.6 implemented this change. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
6bc4f242c7 |
Fix live cleanup races with framework HMR (#695)
Guard delayed accept and discard DOM fallbacks when framework/HMR ownership is present, while preserving static-page cleanup. Add unit/source regressions for both paths and refresh stale Setup wording assertions from #689. AI-assisted: prepared with Codex under @pbakaus direction. |
||
|
|
632912b5ae |
Fix live script response encoding (#690)
Declare UTF-8 on the generated live and detector JavaScript responses and cover both endpoints with integration assertions.\n\nAI-assisted: prepared with Codex under @pbakaus direction. |
||
|
|
187790826d |
Fix concept seed under symlinked installs (#686)
Resolve the CLI entry path through realpath and cover linked skill directories on Unix and Windows junctions. AI-assisted change: implemented with Codex under @pbakaus direction. |
||
|
|
5211bdf4b1 |
Fix: critique snapshot close path (#660)
Preserve critique trend history while closing the exact processed snapshot. Track target identity and content freshness for local files and URLs, isolate colliding streams, and prevent legacy snapshots from resurfacing after a modern close. Validated with 50 focused tests, a clean 17-provider build, 834 core tests, passing GitHub CI and Cursor Bugbot, Greptile 5/5, and zero unresolved review threads. AI-assisted maintainer repair: implemented and reviewed with Codex under @pbakaus direction. |
||
|
|
4fb66a15e7 |
Fix prompt embedding for install paths with spaces (#676)
Resolves the embed helper with a filesystem path, reports fallback accurately, and adds regression coverage while leaving generated harness output to the post-merge sync.\n\nAI-assisted maintainer repair, review, and validation by Codex under maintainer direction. |
||
|
|
8c59bc7fb0 |
Centralize image prompt parsing (#641)
Centralize raster prompt lookup and PNG chunk parsing while preserving read, scan, replacement, and sidecar behavior. AI-assisted merge: reviewed and executed by Codex under explicit interactive maintainer direction. |
||
|
|
fc442be223 |
Fix: make hooks reset remove installed manifest entries (#668)
Fixes #512 and resolves the verified reproduction in #667.\n\nAI-assisted change: reviewed and merged by Codex under maintainer direction. |
||
|
|
f1e8d4e70e |
Simplify named rule extraction
AI-assisted by OpenAI Codex under maintainer pbakaus's scheduled-refactor authorization. |
||
|
|
9434dde9af |
Merge main: skipScan visual-contrast coverage, live overlay waivers, generated output sync
The generated browser bundle is rebuilt from the merged engine sources in the next commit's build step (both branches had regenerated it). AI-assisted (Claude Code). |
||
|
|
10f7c7b6f8 |
The unreferenced-plate refusal names its own escape: --artifact <page> when the scan cannot see the reference
Closes the residual page-inference edge (no recorded artifact, no index.html, several root HTML files) by making the conservative refusal self-correcting instead of adding more inference; the gate never falsely passes in that configuration, only asks for the page. AI-assisted (Claude Code). |
||
|
|
af109a85ae |
gateHero resolves the page before the unreferenced-plates check
Greptile's fourth finding on the seam: the no-artifact path was depth-limited. The page default (index.html, or the one .html at the root) now applies before unreferencedPlates, so the link-following path, which is exact and unbounded, handles every build that has a page; the bounded walk is only the no-page fallback. AI-assisted (Claude Code). |
||
|
|
0d2df39339 |
Root-relative stylesheet hrefs resolve against the project, not the drive root
Bugbot on #599: path.resolve treated /assets/hero.css as filesystem-absolute. Both the working directory and the artifact's directory are tried; unreadable candidates skip. AI-assisted (Claude Code). |