fix(comet-ai): use matched input selector, tighten finalCheck, doc stability semantics#21
Conversation
…ability semantics
### `findInputElement` return value was ignored
`sendPrompt` called `findInputElement()` (which iterates a list of
candidate selectors and returns the first one that matches), then
discarded the result and hardcoded `[contenteditable="true"]` for the
typing logic. On pages where the real input is a `<textarea>` AND a
different unrelated `contenteditable` exists somewhere on the page
(e.g. a hidden search box), focus / typing landed on the wrong
element. Now we route through the selector that the discovery loop
actually matched, and branch on `el.isContentEditable` / `'value' in el`
so contenteditable elements get `execCommand('insertText', ...)` and
form controls get `.value =` + `input` event.
### `finalCheck` matched `[class*="animate"]` — too broad
Perplexity's brand mark uses `animate-pulse` permanently. The
"submission succeeded?" probe used `[class*="animate"]`, which
matches that brand mark, so `hasLoading` was effectively always
`true` on any Perplexity page. The `form.submit()` last-resort
branch — meant to fire when neither key dispatch nor button click
worked — therefore never fired. Tightened to specific progress
indicators: `animate-spin`, `loading`, `thinking`.
### `isResponseStable` semantics were off-by-one in the doc
The constant was named `STABILITY_THRESHOLD` with the comment
"Response must be same for 2 checks". The actual behaviour: counter
increments only AFTER the first matching call, so the function
returns `true` on the 3rd consecutive identical poll (which is what
the existing unit test asserts). Renamed to `STABLE_REPEATS_REQUIRED`
and rewrote the comment to describe the true semantics — "unchanged
for `STABLE_REPEATS_REQUIRED + 1` consecutive polls". The constant
value (2) is unchanged; the test still passes; no behavioural
change, just an accurate name + comment.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Code Review: PR #21 — fix(comet-ai): use matched input selector, tighten finalCheck, doc stability semanticsReviewed commit: Overall AssessmentThis is a well-motivated correctness PR with clear explanations. The three changes are logically sound and the PR description accurately describes the problems being fixed. I have a few observations ranging from a potential bug to minor suggestions. 1. Matched Input Selector — Correctness (LGTM)The fix is correct: using The branching logic ( Edge case confirmed safe: if a matched selector returns an element that is neither contenteditable nor has a 2. finalCheck Tightening — Correct, but Inconsistency Remains (Medium)The fix for However, the PR introduces an inconsistency: The earlier submission check at line ~140 (inside const hasLoading = document.querySelector('[class*="animate-spin"], [class*="animate-pulse"]') !== null;This check still matches
Recommendation: Apply the same tightening to line 140. Replace Similarly, 3. Stability Semantics Rename — CorrectThe rename from Summary Table
Verdict: The PR's changes are correct and improve the codebase. The |
Summary
Three small correctness fixes in `src/comet-ai.ts`.
1. `findInputElement` return value was ignored
`sendPrompt` called `findInputElement()` (which iterates candidate selectors and returns the first that matches), then discarded the result and hardcoded `[contenteditable="true"]` for the typing logic. On pages where the real input is a `<textarea>` and a different unrelated `contenteditable` exists somewhere on the page (e.g. a hidden search box), focus / typing landed on the wrong element.
Now we route through the selector that the discovery loop matched, and branch on `el.isContentEditable` / `'value' in el` so contenteditable elements get `execCommand('insertText', ...)` and form controls get `.value =` + `input` event.
2. `finalCheck` matched `[class*="animate"]` — too broad
Perplexity's brand mark uses `animate-pulse` permanently. The "submission succeeded?" probe used `[class*="animate"]`, which matches that brand mark, so `hasLoading` was effectively always `true` on any Perplexity page. The `form.submit()` last-resort branch — meant to fire when neither key dispatch nor button click worked — therefore never fired.
Tightened to specific progress indicators: `animate-spin`, `loading`, `thinking`.
3. `isResponseStable` doc-vs-code off-by-one
The constant was named `STABILITY_THRESHOLD` with the comment "Response must be same for 2 checks". The actual behaviour: counter increments only AFTER the first matching call, so the function returns `true` on the 3rd consecutive identical poll (which is what the existing unit test asserts).
Renamed to `STABLE_REPEATS_REQUIRED` and rewrote the comment to describe the true semantics. The constant value (2) is unchanged, the test still passes, no behavioural change — just an accurate name + comment.
Compatibility
No public API change. The matched-selector fix is the only one with a visible runtime delta, and that's the intended behaviour (the previous version was a latent bug).
Test plan
🤖 Generated with Claude Code