Executor instructions: Follow this plan step by step. Run every verification command and confirm the expected result before moving to the next step. If anything in the “STOP conditions” section occurs, stop and report — do not improvise. When done, update the status row for this plan in
plans/README.md— unless a reviewer dispatched you and told you they maintain the index.Drift check (run first):
git diff --stat a6293e1..HEAD -- src/content.ts tests/content-flow.test.tsPlan 001 is expected to have addedtests/content-flow.test.ts; any OTHER change tosrc/content.ts’s keydown handler sincea6293e1means you must re-verify the “Current state” excerpt before proceeding.
a6293e1, 2026-07-17Users typing Chinese, Japanese, or Korean via an IME press Enter to confirm
a composition, not to send. PromptWard’s keydown interceptor treats any plain
Enter in a composer as a send: it calls preventDefault(), runs redaction,
and replays a submit — sending a half-typed prompt mid-composition. This makes
the extension actively harmful for CJK users on every supported site. The
standard fix is to ignore keydown events where event.isComposing is true (or
keyCode === 229, the legacy IME signal some Chromium input paths still emit).
src/content.ts:37-56 — the keydown capture handler. Today:
// src/content.ts:37-39
function onKeydownCapture(event: KeyboardEvent): void {
if (event.key !== "Enter") return;
if (!(event.metaKey || event.ctrlKey || event.shiftKey === false)) return;
There is no isComposing check anywhere in the file
(grep -n "isComposing" src/ returns nothing).
tests/content-flow.test.ts (from plan 001) already has an
“Enter key in editor triggers the flow” test to model the new test on.| Purpose | Command | Expected on success |
|---|---|---|
| Typecheck | npx tsc -p tsconfig.json --noEmit |
exit 0 |
| Tests | npm test |
all pass |
| One file | npx vitest run tests/content-flow.test.ts |
all pass |
In scope:
src/content.ts (the onKeydownCapture function only)tests/content-flow.test.ts (add tests)Out of scope:
onClickCapture / onSubmitCapture — clicks and form submits cannot occur
mid-composition; do not add checks there.src/content/submit-detection.ts, src/content/dom-adapter.ts.advisor/002-ime-compositionfix(content): ignore Enter during IME compositionIn src/content.ts, onKeydownCapture, insert as the FIRST guard (before the
event.key check, since keyCode === 229 events may carry key “Process” or
“Enter” depending on the platform):
function onKeydownCapture(event: KeyboardEvent): void {
// Enter during IME composition confirms the composition, not the send.
if (event.isComposing || event.keyCode === 229) return;
if (event.key !== "Enter") return;
...
Verify: npx tsc -p tsconfig.json --noEmit → exit 0.
In tests/content-flow.test.ts, next to the existing Enter-key test:
isComposing is not intercepted: focus the textarea (with
non-empty text and a protect response that would change it), dispatch
new KeyboardEvent("keydown", { key: "Enter", isComposing: true, bubbles: true, cancelable: true }).
Assert defaultPrevented === false, no PW_PROTECT_TEXT message was sent,
and no promptward-review modal appears.new KeyboardEvent("keydown", { key: "Enter", bubbles: true, cancelable: true })
with Object.defineProperty(event, "keyCode", { get: () => 229 }) (the
KeyboardEventInit dictionary has no keyCode member — jsdom, like
browsers, requires the property override).Verify: npx vitest run tests/content-flow.test.ts → all pass, including 2 new tests.
Verify: npm test → exit 0, all files pass.
Covered in step 2. Pattern: the Enter-key test added by plan 001 in
tests/content-flow.test.ts.
npx tsc -p tsconfig.json --noEmit exits 0npm test exits 0 with 2 new IME tests passinggrep -n "isComposing" src/content.ts shows the guard as the first line of onKeydownCapturegit status shows only src/content.ts, tests/content-flow.test.ts, plans/README.md modifiedplans/README.md status row updatedStop and report back if:
onKeydownCapture no longer matches the excerpt (drift — e.g. plan 004
restructured it first).tests/content-flow.test.ts does not exist (plan 001 has not landed —
this plan depends on its harness).isComposing init property (would indicate a very old
jsdom; the repo pins jsdom 26, which supports it).compositionend-then-Enter send bug is ever reported (some IMEs fire
Enter immediately after compositionend with isComposing already false),
that is a distinct follow-up — deliberately out of scope here.event.key !== "Enter" check,
and must not log (hot path, fires on every keystroke).