Addresses Critical #1 + Important #2/#3/#4 from the Task 9 code review.
CRITICAL — Tab/Enter were stolen by CodeJar before the popup handler
saw them. CodeJar registers its keydown listener during construction
(line ~159), so it ran first in bubble order: Tab handler
preventDefaulted and inserted 2 spaces, Enter handler preventDefaulted
+ stopPropagation'd (with leading indent), so the popup-accept either
ran on corrupted state or never fired at all. Fix: register the popup
listener with {capture: true} and call stopPropagation on the keys we
own — that way capture phase fires before CodeJar's bubble listener
and the key is fully consumed by the popup while it's visible. Normal
typing (popup hidden) early-returns without stopPropagation, so
CodeJar's tab-indent + enter-preserve-indent still work when there's
no autocomplete to accept.
IMPORTANT — destroy() leaked the popup <ul> into document.body. Each
mount/destroy cycle (e.g. modal close/reopen) left an orphan popup.
Fix: pop.remove() in destroy().
IMPORTANT — async refreshPopup could race in stale renders if the
first keystroke fired the vocab fetch and the second keystroke
captured a different ctx before the fetch resolved. Fix: warm the
cache with a fire-and-forget loadVocab(language) at mount, so the
first user keystroke hits cache. Eliminates the only realistic window
for the race.
IMPORTANT — acceptCompletion's Range.setStart could throw
IndexSizeError on pathological state (caret inside a tokenized span
where the fragment isn't fully upstream). Fix: try/catch the entire
DOM mutation block, log + dismiss on failure. Plus an inline comment
documenting the single-text-node invariant the current grammars hold.
Plan source updated for the capture-phase fix (most important for
future regeneration); the other fixes are smaller and only mirrored
into the actual code.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Task 9 plan template used the captured \`jar\` closure variable in
acceptCompletion, which becomes stale after setLanguage's
tear-down-and-remount. Same class of bug Task 4's review caught and
fixed. Update the plan to match the correct implementation.
The plan template (and verbatim implementation) listed five of the six
editor asset URLs in the structural test — vendor/prism.css was
omitted. If a future change drops the Prism stylesheet from the
partial, syntax tokens lose their color rules silently and the test
still passes. Add the missing assertion and update the plan to match.
Addresses Minor #1 from the Task 6 code review.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses two Minor follow-ups from the Task 4 code review:
- findFilenameInput previously included `body` in its closest() selector,
meaning any "auto" textarea outside a modal would walk all the way up
and pick up the files-editor modal's filename input from elsewhere in
the document. Drop `body` so out-of-modal "auto" usage degrades
cleanly to "plain".
- setValue now dispatches an `input` event on the textarea after
writing, matching the onUpdate mirror. Task 10 wires the files-editor
modal to call setValue when loading file content — without this fix,
textarea-listening code (e.g. unsaved-changes indicators) wouldn't
see programmatic loads. Now setValue and user typing produce the
same observable side effects.
Plan source block updated to match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The plan had Step 1 (initial widget) + Step 2 (setLanguage patch); the
implementation merges them into one final file. Update the plan to
show the final file verbatim so a future regeneration produces the
same output. Step 2 in the plan is renumbered to 'Manual verification
note' (just the deferred-to-Task-6 sentence) for completeness.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses Important #1 + Minor #2/#3 from the Task 3 re-review:
- --color-bg-popover-active light value: #f3f4f6 → #e5e7eb. The prior
value was within ~1.05:1 luminance of the white surface — keyboard
navigation through the autocomplete list had no visible focus
indicator in light mode. e5e7eb (Tailwind gray-200) clears that.
- Drop dead fallback hexes on the four guaranteed tokens
(--color-string/-keyword/-number/-bg-popover-active). They never
fired post-fix and only produced a dark-mode-only palette if
tokens.css somehow failed to load — i.e. they were misleading.
- Plan source block (Task 3 Step 2) replaced with the post-fix CSS
verbatim + a new Step 2b that documents the tokens.css additions
alongside the editor.css template, so a fresh regeneration
produces the same file.
Deferred: cross-cutting --font-mono token (Minor #4 — would touch 7+
sites outside Task 3's scope).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses Important #1 + #2 from the Task 3 code review:
- Adds --color-string, --color-keyword, --color-number,
--color-bg-popover-active to tokens.css in both the :root and dark
blocks. GitHub-style palette tuned for legibility on each theme's
surface.
- Updates .editor-code to use the same padding tokens, font-family
stack, font-size, and line-height as the existing textarea rule so
the contenteditable doesn't visibly jump when the widget mounts.
- Drops the caret-color override (browser default adapts to system
theme — no token needed).
Plan source block updated to match.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `\b` word boundary anchor prevents the optional minus from ever
matching from positions where signed numbers naturally appear (` -1`,
`(-1`, `=-1` all word-boundary-from-non-word and the `-?` fires zero
chars). Negative numbers are tokenised via the operator class instead,
which is the consistent behaviour the grammar already exhibits.
Plan source block updated to match so a fresh regeneration produces the
same file.
Addresses Minor #1 from the Task 2 code review.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Spec reviewer caught that the literal 'Prism.languages.bash' string
doesn't appear in the minified prism.js (minifier renames Prism→e).
Switch the verification grep to match either the bash shebang token
or any languages.bash assignment; both survive minification.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Task 1 implementation discovered that codejar v4.0.0 ships its
browser bundle at /dist/codejar.js, not the package root. The vendor
README already records the correct URL; this patch keeps the plan
itself accurate for future regeneration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The original Task 1 instructed a human to click through prismjs.com's
configurator UI — a step a subagent can't perform. Replace with direct
curl from jsdelivr for both Prism components (core + clike + bash
concatenated) and CodeJar, plus a sed-based ESM-export strip and a
window-global shim. Updates the vendor README template accordingly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>