Adds a failing-first regression test proven by ablation. Produced by the #17237
review loop; kept on the review branch rather than pushed to the PR branch.
`stripErrorClassPrefix` took a case-insensitive flag from the two AccountsPane
copies it replaced, which widened `LinuxPackageInstallRecoveryCard` — that site
matched `/^Error:\s*/` on main. The only thing this trims is
`Error.prototype.toString()` output, which V8 always writes as `Error: `, so the
flag could never match a real class prefix the case-sensitive pattern misses; it
could only eat the lowercase severity marker git, rpm, dpkg and pip put in front
of a real reason. `IPC_ENVELOPE`'s own `\w*Error:` group in the same module is
already case-sensitive.
All three call sites now agree, and the card matches main again.
`extractIpcErrorMessage` kept its own regex on the grounds that 18 call sites
depended on its fail-open behaviour. It has 30, all user-facing, and its regex
handed users the wrapper for two envelope shapes, dropped the caller's own
prefix, truncated multi-line reasons at the first newline, and leaked the
handler's error class name.
It now delegates to the canonical stripper and owns no pattern. Four sites whose
fallback was the stringified rejection get readable copy instead, so an envelope
with nothing behind it can no longer reach a user through the fallback either.
Falling back logs the rejection, which none of these sites did before.
Two censuses back it: one enumerates the 30 call sites, one holds the envelope
to a single owning file.
#17230 added stripIpcInvokeEnvelope as a canonical home for Electron's IPC
wrapper. It was the sixth implementation, not the first: nine other files
carried ten hand-rolled copies, and they disagreed.
Measured against a shared corpus, the copies split four ways. An envelope whose
tail has no "Error: " prefix — Electron builds that tail from the main side's
error.toString(), so a rejected non-Error produces one — was left fully visible
by quick-open. A message-less handler failure rendered the bare word "Error" in
the Linux recovery card, the voice download toast and the AI Vault scan row; an
empty tail rendered an empty string in all three. Every copy was anchored at ^,
so an envelope a caller had prefixed with its own context stayed on screen. The
two AccountsPane copies were scoped to their own channel, so a rejection from
any other channel kept its wrapper.
All ten now route through one stripper, moved to src/shared because
ai-vault-scan-error-message is imported by main and cannot reach a renderer-only
module. The canonical regex additionally covers "Error occurred in handler for",
which AccountsPane stripped and the canonical one did not, and a separate
stripErrorClassPrefix keeps the bare "Error: " trim that three sites had — that
prefix is Error.prototype.toString(), not the envelope, and an existing Linux
card test caught its loss.
Nothing is swallowed. The three sites that gained a null fallback now
console.warn the original rejection, which none of them logged before, and
Electron still logs the handler's original error with its stack in main.
extractIpcErrorMessage keeps its own fail-open regex and its 18 call sites are
untouched: it returns the tail verbatim and never returns null.
A census test pins the envelope to the two files that own it, so a seventh copy
fails CI. It lists nine offenders against the pre-fix tree.
A workspace delete that the classifier does not recognise fell through to a
branch that renders the failure string verbatim. For an IPC rejection that
string is Electron's own wrapper — "Error invoking remote method
'worktrees:remove': ..." — so a safe refusal read as a broken app.
Adds stripIpcInvokeEnvelope to the canonical ipc-error module: it returns the
reason behind the wrapper, or null when the wrapper carried no readable reason
(Electron builds the tail from the main side's error.toString(), so a
message-less handler failure arrives as a bare class name). The eight
user-facing sites in the delete flow now route through one copy function that
falls back to a human sentence on null.
Nothing is swallowed: deleteStateByWorktreeId keeps the raw string, the
renderer still console.warns the rejection, and Electron itself logs the
handler's original error with its stack in the main process.
extractIpcErrorMessage keeps its fail-open contract byte-for-byte so its 18
existing call sites are unaffected.
* Improve markdown rich mode: distinguish HTML tags from placeholders
- Consolidate size limit and unsupported content checks into single function
- Refine HTML/JSX detection to validate against rehype-sanitize's known tag names
- Allow bare placeholders like `<id>` and `<project-id>` in rich mode rendering
* Add decision explainer for markdown rich-mode rendering fix
* rm html explainer
* fix(browser): close guest-owned split tab
* fix: check sourceId before toggling floating panel on close
The empty-panel toggle is the ambient fallback only. Guest-initiated
closes (with sourceId) target the main workspace and should not toggle
the panel.
* test(browser-split-shortcuts): remove terminal-mirrors close test and un
Removes test case that verified Cmd+W closes guest-owned browser splits when
active-tab mirrors point to a terminal, along with the helper function and
unused fixture properties that only that test required.
* Clarify automation history unavailability and improve recovery UX
- Improve error message to explain run history is unavailable due to host
version requirements, not automation failure
- Hide misleading "0 runs" count badge when history is unavailable
- Deep-link "update server" recovery actions to specific runtime environment
in settings instead of pane root
- Add test coverage for run count hiding and recovery targeting
* Watch for deep-linked settings targets that render asynchronously
Some settings panes (such as Remote Orca Servers) fetch and render their
rows asynchronously. Deep links can name targets that don't exist yet,
but the scroll effect has no way to know when they finally mount. Add a
MutationObserver-based watcher to detect when async rows appear and
trigger scrolling.
Refs #16646
Unify native, WSL, and direct SSH conflict checks behind the execution host, remove the duplicated SSH classifier, and cover orphan/configured remote behavior across both paths.
Both files describe paths with POSIX literals while their subjects compose
paths through `node:path`, so the assertions only hold where the separator
happens to be `/`.
`node-markdown-document-discovery` keys its fake tree at `/repo/docs` and
`/repo/one`, but `discoverMarkdownRelativePaths` descends with
`join(absoluteDirectoryPath, entry.name)` — `\repo\docs` on win32. The child
lookup misses, `readDirectory` yields nothing, and the walk stops at the root:
`docs/guide.mdx` disappears and the depth-limit case never reaches its limit,
so it resolves `[]` instead of rejecting. Keying the children with `join` walks
the tree the subject actually walks.
`git-fetch-head-lock` expects `cwd: '/tmp/repo'` from a subject that returns
`path.resolve(cwd, 'repo')`, which is `C:\tmp\repo` on win32. Asserting through
`path.resolve` pins the behaviour — that `-C` and `--git-dir` are resolved
against the cwd — rather than the separator of whichever machine runs the suite.
Verified on Windows 11: the two files go from 3 failed / 12 passed to
14 passed / 1 skipped, and the wider `src/shared` run shows no regression.
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Make worktree palette hint rows keyboard-clickable
Hint entries like "See more" are now CommandItems that can be navigated with arrow keys and activated with Enter, instead of being non-interactive divs. This allows keyboard-only users to access the expand actions without mouse interaction.
* Make worktree palette "See more" keyboard-navigable
Preserve cursor position when expanding via keyboard: auto-select the first
newly revealed item at the previous index and restore input focus.
- Translate Agent Dashboard column headers (Needs You / Working / Idle), board title, and total count.
- Translate empty-column placeholder, "You" message badge, terminal preview actions, and error-boundary copy.
- Resolves English fallback in the Agent Dashboard (dashboardPopout) under the Korean locale; only "Done" was previously translated.