On the eph-pve3 runners needrestart stops after apt-get install at an
interactive 'Daemons using outdated libraries' prompt, and the job
hangs until it times out (PR #66's build-linux, PR #68's test job).
Set NEEDRESTART_MODE=a and DEBIAN_FRONTEND=noninteractive for the
workflow and pass them through sudo, which resets the environment.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
--appimage-extract creates every directory 0700 regardless of the
modes stored in the image (verified by packing a 0755 AppDir and
extracting it under umask 022), so the post-repack guard failed on a
correct image. Check files, which extract with their stored modes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The STT job failed on the home runner with 'no route to host' to the
act_runner cache service while exporting the build cache. Import errors
are warnings, export errors are fatal without ignore-error=true, which
build.yml already sets. Ephemeral runners hit the same thing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI builds with cache-from: type=gha, so the apt-get upgrade layer was
reused until the base digest or the layer text changed, and security
fixes published since then never reached the image. The RUN now uses an
APT_REFRESH build arg, which build.yml sets to the ISO week, and a weekly
schedule trigger rebuilds without a commit. Publishing is gated on
event_name != 'pull_request' so the scheduled run (always on main)
publishes and PR runs still only validate.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The instructions told Claude the user can Shift+click a path, but the gate
(TerminalView's opensOnClick) opens on a plain click unless a program holds
the mouse, and then takes xterm's force-selection modifier: Shift on
Linux/Windows, Option on macOS.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A single bad or truncated byte made the fatal decoder throw, and the whole
payload was then re-read as Latin-1, re-mojibaking every valid multi-byte
character in it. Decode non-fatally so only the bad bytes become U+FFFD.
No Latin-1 fallback is kept: every sender here emits UTF-8.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The empty-joiner rule fired whenever a row ended at the edge and its last
token plus the next row's first token were wider than a line, so a short
word at the edge followed by a URL that wrap-ansi moved down whole became
'thehttps://...'. Lengths alone cannot tell that from one long token split
after 'the', so a next-row token that starts a URL (scheme://) is now
treated as a fresh word, unless one of the two pieces fills its entire row
(only the middle piece of a token longer than a line does). The captured
70-column URL split still rejoins without a space.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
isWide looked at a single UTF-16 code unit, so an astral character at the
break (CJK Ext-B, emoji) was a lone surrogate of width 1 and the rejoin
inserted a space between two wide characters.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A selection of just `│ a │ b │` rows passed the 'wholly inside a box'
test, so the outer borders were stripped and the inner │ kept. A row with
a vertical rule inside its borders is a table row, not a box row.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CONTAINER_HOME was declared twice (file_viewer/resolve.rs and
commands/inspect_commands.rs); it now lives once in docker/mod.rs as
pub(crate). xtermLineJoin's PATH_CHAR re-declared filePathLinks' TOKEN
character class; filePathLinks now exports PATH_SEGMENT_CLASS and both
regexes are built from it (TOKEN's source is byte-identical).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
With hard-wrap bridging a long chain of continuation rows made the walk up
to the chain's start unbounded while the walk down stopped at the
2048-char budget, so a hover deep in the chain could get back text that
did not contain its own row, after reading the whole chain. Stop the walk
up after half the budget, always include the hovered row, and drop the
indent of a mid-chain first row.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two column-0 lines of shell output where the first happens to fill the
row (a 40-char path at 40 cols, then src/main.rs) were glued into one
bogus path. Claude Code draws continuation rows at least 2 cells in, so
require that.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
appimagetool's continuous build of 2026-11-01 refuses an AppDir with
restrictive modes. --appimage-extract writes it under the runner's
umask, which produced a 0700 root and 0770 AppRun.wrapped, and we
repacked exactly that: an image other users could not start. chmod
-R a+rX before the repack, and assert the modes after it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Shift+click did nothing useful on Claude Code's scratchpad paths
(/tmp/claude-<uid>/-workspace/<session>/scratchpad/x.md). Claude Code
wraps its own output: a word longer than the line is broken mid-word and
the rest drawn on the next row with cursor moves, so xterm never marks
that row isWrapped. The link provider saw two fragments: the first has no
extension (no link), the second is a relative `…/scratchpad/x.md` probed
under /workspace and not found.
- xtermLineJoin bridges such breaks when given cols: the row runs to the
edge, the next row continues with path characters after its indent, and
the two runs could not have fit on one line (keeps prose apart).
- Backend: `~/p` resolves to /home/claude/p; a relative path the project
roots do not have is probed again under /home/claude and /tmp, in a
second exec so a project file never becomes a chooser.
- CLAUDE_INSTRUCTIONS asks Claude to print full absolute paths for files
outside the project (changes the fingerprint: one recreation per project).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The plain-text URL regex handed to WebLinksAddon ran to the next
whitespace, so `See https://x/docs.`, `(https://x/a)` and markdown
`[t](https://x/a)` underlined and opened the URL with the trailing `.`
or `)` attached. The addon underlines exactly what the regex matches and
passes that text to the click handler, so the fix has to be in the match.
lib/urlMatch.ts adds TERMINAL_URL_REGEX, using GitHub/linkify-style
rules: a URL never ends in `.,;:!?*`, and a closing `)]}` is kept only
when it closes a bracket opened inside the URL (one level), so
Wikipedia's `Foo_(bar)`, IPv6 `[::1]` and `a[]=` keys survive while a
wrapping paren is dropped. `-_~=/` are never trimmed (base64url OAuth
state, padding). The allowed character set is unchanged.
UrlDetector's toast candidates use the same trimming via findUrls, but
still decide whether to wait for more output from the raw run's end, so
a chunk ending `.../file.` is not emitted before `tar.gz` arrives.
sanitizeRelayUrl and the opensOnClick gate are untouched.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nothing in container/Dockerfile pins a version (gh, docker-ce-cli and
Node come from their apt repos, pnpm/Playwright/uv/ruff/rustup/Claude
Code/AWS CLI resolve latest), so a rebuild is what delivers fixes. Two
things stood in the way:
- `apt-get install` never upgrades packages the ubuntu:24.04 image
already ships, so a noble-security fix stays out until Canonical
refreshes the tag. The first apt layer now runs `apt-get upgrade -y`
inside the existing retry pattern.
- CI builds with `cache-from: type=gha`, so the layers only re-run when
the base digest or a layer's text changes. Trivy on the published
image (built 2026-10-16) found libbrotli1 1.1.0-2build2
(CVE-2026-111497, HIGH), zlib1g 1.3.dfsg-3.1ubuntu2.2 (CVE-2026-85091)
and pnpm's bundled undici 6.29.0 (CVE-2026-109383, CVE-2026-109869,
CVE-2026-87018, all HIGH). Changing this layer invalidates the cache
once, so the next CI build rebuilds everything.
A local `docker build --pull` of this tree succeeds (amd64). Trivy finds
no fixable OS or Node vulnerabilities in it: Node 22.23.4, gh 2.103.3,
docker CLI 29.9.2, AWS CLI 2.39.3, pnpm 12.16.1, Playwright 1.64.1,
Claude Code 2.1.316. What remains is uv 0.13.6's bundled rustls 0.23.45
(GHSA-c8m5-c952-6cm4, MEDIUM). That is fixed on uv's main branch but not
in a release yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
22.14.0 is from early 2025 and has missed every Node 22 security release
since, the latest being 22.23.4 (2026-10-20, marked security in
nodejs.org/dist/index.json). The step only runs when `node` is absent
from the build VM, so this governs a fresh or rebuilt VM; an existing
install on WindowsBuilder is left as it is.
No advisories exist in OSV for the pinned actions (checkout@v4,
build-push-action@v5, login-action@v3, setup-buildx-action@v3,
setup-qemu-action@v3).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
python:3.11-slim ships CPython 3.11's frozen pip 24.0 and setuptools
79.0.1. OSV lists six pip advisories (CVE-2025-8869, CVE-2026-1703,
CVE-2026-3219, CVE-2026-6357, CVE-2026-8643, CVE-2026-13346; fixed by
26.2) and two setuptools ones (CVE-2026-59890, GHSA-xmj3-9gf7-h52w;
fixed by 84.1.0). Upgrading them first also means the app installs run
under a patched pip.
After the change the image resolves pip 26.2.2 and setuptools 84.2.1,
and an OSV batch query over all 41 installed packages comes back clean
(fastapi 0.162.0, starlette 1.10.0, python-multipart 0.0.33,
uvicorn 0.54.0, faster-whisper 1.2.1, ...). Trivy finds no fixable
Debian 13.7 OS vulnerabilities in the current python:3.11-slim, so no
apt upgrade layer is added. Smoke-tested: /health 200 and /transcribe
200 on a generated WAV.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
v1.96.0 is affected by two advisories published since it was pinned:
- CVE-2026-84377 / GHSA-3cv6-jpf6-8222: authenticated SSRF and
provider-credential exfiltration via unvalidated request-body URLs
(fixed 1.96.2 on that line). This container holds a billed provider key.
- CVE-2026-114612 / GHSA-7hp6-4w63-5g45: privilege escalation to proxy
admin via cross-domain reuse of the salt key (fixed 1.103.1; no 1.96.x
backport).
v1.106.6 (2026-10-28) is the newest stable release with no OSV advisories.
Tag and digest updated together; the index digest was read with
`docker buildx imagetools inspect` and cosign-verified against LiteLLM's
pinned public key. GATEWAY_REGISTRY_IMAGE in gateway.rs is kept in
lockstep.
Smoke-tested with a config shaped like render_config()'s output: the
proxy starts, /v1/messages without a key is a 401, and with the master
key the Anthropic-format request is translated and routed to the
configured OpenAI base. Note this LiteLLM refuses to start with no
master_key at all; Triple-C always renders one, so that is not a
regression for us.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>