Commit Graph
17041 Commits
Author SHA1 Message Date
OrcaWinandOrcaWin 3058cdd1a8 ci(node-server): run PR and scheduled qualification on free hosted runners (#34560)
Only explicit fast_runners callers (manual, hourly/daily/adhoc builds) keep
Blacksmith; qualified-orcad-template's cache/save jobs always use ubuntu-latest.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 15:14:01 -07:00
Kelvin Amoaba 917ef9c737 feat(browser): install Chrome extensions from the Web Store into Orca's browser (#30940) 2026-10-27 22:04:12 +00:00
OrcaWinandOrcaWin c791ee2d98 test(wsl): stop the bash bridge flood test re-concatenating every chunk (#34524)
decode() collected payload chunks even when no payload was expected, and with
expected = 0 every data event ran Buffer.concat over all chunks so far. The
128 MB desktop-reads-slowly flood therefore copied quadratically: ~9 s idle under
bun, over 30 s under node or a loaded CI runner, timing the test out.
Collection now lives in received(), used only by the tests that check a payload.

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 14:58:58 -07:00
Brennan Benson e225433c77 Lint: flag store selectors that subscribe to the whole host-status map (#34517)
* lint: flag whole host-status map selectors

* lint: keep whole host-status map findings advisory
2026-10-27 14:56:45 -07:00
Neil 84decfd2a2 feat(editor): VS Code markdown highlighting and sticky headings in source mode (#34537)
* feat(editor): VS Code markdown highlighting and sticky headings in source mode

* fix(editor): address review on markdown TextMate highlighting

- resolve fence grammars from the first word of the info string
- give fence grammars the cold-compile retry budget
- fall back to Monarch markdown when TextMate fails to load
- bound heading-scan line length
2026-10-27 14:46:30 -07:00
OrcaWinandOrcaWin 649dc1a6fb test: remove 113 low-value tests (#34541)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 14:45:01 -07:00
Neil 8fe31c930e feat(wsl): note why an idle distro stays held, and fail the holder's scan closed (#34534)
* feat(wsl): note why an idle distro stays held, and fail the holder's scan closed

When user work keeps the holder from releasing, it writes the first few process names (at
most 5) to ~/.orca/wsl-holder-blocked, replaced whole and cleared on release, for the desktop
to read later. A /proc without the holder's own entry, or a status file it cannot parse, now
keeps the hold instead of reading as idle.

* fix(wsl): count an unreadable /proc entry only when it is the user's own

Review of #34534: under hidepid=noaccess root's status files are unreadable, so each read as
this user's work and the distro never released. An unreadable entry now counts only when its
directory belongs to this user. The holder also clears a half-written note on start and
rewrites the note only when it changed.
2026-10-27 14:42:00 -07:00
OrcaWinandOrcaWin 7b8ca17c64 build(runtime): target Node 24 while retaining host compatibility (#34177)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 14:40:37 -07:00
Jinjing 54411a9a96 fix(chat): open chat name settings from naming failures (#34533)
* fix(chat): link naming failures to chat name settings

* fix(chat): hide naming settings link when controls are unavailable
2026-10-27 14:27:53 -07:00
OrcaWinandOrcaWin 9fd9cd7362 test: remove 260 low-value tests (#34535)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 14:24:21 -07:00
Brennan Benson 9510726341 Stop host status changes from rebuilding the sidebar workspace list (#34500)
* Stop unrelated host status publications rebuilding sidebar workspace state

* Follow sidebar selector lint conventions

* Scope sidebar status reads to mounted consumers

* Cover each unrelated sidebar status publication

* Fix sidebar isolation lint and formatting

* Type the composed sidebar header fixture without assertions

* Remove unused React imports from sidebar contract tests

* Reuse folder record selector and prune stale focus allowance
2026-10-27 14:15:30 -07:00
Jinjing a2b378018a Withhold virtual review tabs from mobile sessions (#34254) 2026-10-27 14:09:22 -07:00
Brennan Benson e71d4358c1 Native chat tabs can hand off work from their right-click menu (#34504)
* Add native chat hand-off menu on main

* Fix saved chat hand-off observations and RPC exports

* Reuse indexed chat tabs for hand-off subscriptions

* Match saved-chat clear fixture to current journal API
2026-10-27 14:06:57 -07:00
Neil 2bf43b7140 fix(automations): keep a desktop automation's dispatch token off a runtime host's create (#34525)
A desktop-scheduled automation whose project lives on a managed Orca server
sent its dispatch token to the server, which never minted it and rejected every
run with "Invalid automation provenance request". The token now goes only to
this desktop's own create.

Fixes #34433
2026-10-27 13:58:49 -07:00
OrcaWinandOrcaWin 1d2778fa99 test: remove 150 low-value tests (#34520)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 13:57:27 -07:00
Brennan Bensonand0668000615 203f4e777c fix(tasks): keep preset highlights in sync with filters (#34216)
* fix(tasks): derive preset highlights from the applied query

Reuse the parsed query and already loaded viewer login for personal preset matching. Keep the stored preset field for resume and task-kind behavior.

Co-authored-by: 0668000615 <wen.xiaosong@xydigit.com>

* fix(tasks): limit preset identity matching to known sources

* fix(tasks): wait for source identity before matching viewer aliases

* fix(tasks): match preset highlights to query tokens

Require the effective open state and recognize personal presets by their @me query tokens. Remove viewer identity matching while preserving existing preset persistence and task-kind behavior.

Co-authored-by: 0668000615 <wen.xiaosong@xydigit.com>

---------

Co-authored-by: 0668000615 <wen.xiaosong@xydigit.com>
2026-10-27 13:50:27 -07:00
Brennan BensonandWooseong Kim 287a34c0e5 fix(github-project): show linked PRs and sub-issue progress (#34185)
* fix(github-project): render linked PR and sub-issue progress values

* fix(github-project): probe schema support for project column values

* fix(github-project): preserve independently supported project fields

* Preserve nullable project values and unsupported fetch concurrency

* Exercise project relation payloads through unchanged consumers

* Combine project coordination test cache imports

* Use checked project payload types in consumer tests

* Place project provider column contract in cross-layer tests

---------

Co-authored-by: Wooseong Kim <innocarpe@gmail.com>
2026-10-27 13:48:54 -07:00
Brennan BensonandDavid Anderson 379724a333 Keep working GitLab hosts when another login fails (#34184)
* fix(gitlab): retain successful hosts from partial auth failures

Read rejected auth-status output without treating failed host headings or
API error advice as successful logins. Publish positive results through
the existing context-owned cache; keep backoff when no login succeeds.

Co-authored-by: David Anderson <cantspamdave@gmail.com>

* fix(gitlab): preserve discovery retries with partial host evidence

* fix(gitlab): escape auth marker for ASCII server bundle

---------

Co-authored-by: David Anderson <cantspamdave@gmail.com>
2026-10-27 13:47:52 -07:00
6ecd992f44 Correct GitLab MR checks for failed and manual pipelines (#34176)
* Correct GitLab MR check status for failed and manual pipelines

Use the same single-MR read for linked and branch-discovered reviews so a
list summary cannot hide a failed pipeline. Preserve lookup failures for
strict callers and keep detail reads within the existing branch cache.

Set mergeable manual pipelines to neutral without claiming an unrun stage
passed; keep blocking manual pipelines pending.

Co-authored-by: Son of Odin <2700975-son-of-odin@users.noreply.gitlab.com>
Co-authored-by: Emily <hadikcze@gmail.com>

* test: cover GitLab MR check status consumers

* test: type GitLab MR fixtures from mapper input

* chore: document GitLab MR boundary assertion exceptions

* test: share GitLab MR producer and consumer fixtures

---------

Co-authored-by: Son of Odin <2700975-son-of-odin@users.noreply.gitlab.com>
Co-authored-by: Emily <hadikcze@gmail.com>
2026-10-27 13:47:24 -07:00
Brennan BensonandIsaac Mello 41755b5b24 fix(tasks): let Linear section headers collapse and expand (#34173)
* fix(tasks): make Linear list section headers collapsible

* test(tasks): cover Linear section collapse and keyboard activation

* test(tasks): bound Linear section toggle work at scale

* fix(tasks): compose Linear section surface with standard button

* fix(tasks): keep section keyboard focus inside the row

---------

Co-authored-by: Isaac Mello <dzordinetwork@gmail.com>
2026-10-27 13:46:23 -07:00
Brennan BensonandHotragn 8f3d8c8583 fix(gitlab): preserve MR pagination when totals are missing (#34171)
* fix(gitlab): keep paging merge requests when GitLab omits the totals

When total headers are absent, a full response advertises another page to probe and a short response ends pagination. Keep the existing header precedence and unknown total count.

Tracked in #33800

* test(gitlab): cover MR pagination exhaustion and header precedence

* test(gitlab): verify unknown-total metadata across list consumers

* test(gitlab): cover remaining screen consumers of list metadata

* test: use checked GitLab RPC runtime fixtures

---------

Co-authored-by: Hotragn <103170876+Hotragn@users.noreply.github.com>
2026-10-27 13:46:07 -07:00
NeilandClaude Opus 5.5 9a51b9845c fix(ssh): start a stopped managed server whose recycled PID hid it on hosts without ps (#34519)
* fix(ssh): prove a recycled server PID exited on hosts without ps

On slim Linux images that ship no ps, the managed server's liveness probe
could not read the recorded PID's argv, so after a reboot a PID that now
named another process read as LIVE (same user) or UNKNOWN (root). The wake
then refused to start the stopped server, the update deferred on the
terminal census, and the host stayed unreachable. Read argv and the
zombie state from /proc when ps is missing.

Fixes #34149

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ssh): name argv-less PIDs from /proc stat; annotate e2e timeout

Kernel threads and zombies have an empty cmdline, so a recycled PID owned
by one stayed UNKNOWN on hosts without ps. Quote the stat pattern so the
probe also parses inside command substitution on older bash.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ssh): fall back to the stat line only after cmdline was read

A failed tr must stay unproven rather than make a live server's PID look
recycled.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:27:49 -07:00
Neil 43c8ee5e50 fix(codex): keep the Codex app's bundled plugins in Orca-managed homes (#33621)
* fix(codex): keep the Codex app's bundled plugins in Orca-managed homes

Codex only loads the openai-bundled marketplace when its source sits under
the active CODEX_HOME. The config mirror copied ~/.codex's source verbatim,
so managed homes silently dropped bundled plugins such as visualize.
Link ~/.codex/.tmp/bundled-marketplaces into managed homes and rebase the
mirrored source onto it.

* fix(codex): rebase bundled marketplace onto the canonical managed home

Codex canonicalizes CODEX_HOME before comparing the bundled marketplace
source, so a managed home reached through a symlink (symlinked userData,
/tmp on macOS) was still rejected.
2026-10-27 13:19:22 -07:00
Neil f57d00f045 refactor: group shared native-chat upgrade-tip audience (#34509) 2026-10-27 13:17:14 -07:00
Brennan Benson 64c7d954fd test(native-chat): cover mixed drops through question submission (#33632)
* test(native-chat): preserve mixed drops through question submission

* test(native-chat): complete send harness setup

* test: remove duplicate delayed mixed-drop case
2026-10-27 13:12:48 -07:00
Brennan Benson be619433be fix: keep startup prompts usable during agent restore (#30978)
* refactor(terminal): separate startup commands from live input

* fix(terminal): run POSIX startup commands from shell prompt hooks

* fix(terminal): preserve staged commands in shell-owned startup

* fix(terminal): correct startup types and release spawn environment

* fix: keep startup prompts usable during agent restore

* test: run startup prompt regression in the native runtime

* fix(zsh): retire deferred startup callback safely

* test: make shell readiness fixtures satisfy timing checks
2026-10-27 13:11:31 -07:00
Brennan Benson 32a9b3b959 Skip command Stop history for ordinary chat replies (#34320) 2026-10-27 13:01:18 -07:00
ZrzzzzandBrennan Benson c48b349d9c fix(ports): attribute listeners through workspace symlinks (#33730)
* fix(ports): attribute listeners through workspace symlinks

* fix(ports): bound workspace realpath resolution during scans

* Preserve port URLs through incomplete workspace alias observations

* Bound workspace alias lookups with expiring FIFO admission

* Bound alias admission per workspace scan phase

* Document fake-clock lookup timers for the test policy

* Keep fake-clock recovery coverage on the alias under test

* Wait only on existing workspace alias observations

* Assert advertised port URLs within the node test boundary

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-27 13:00:55 -07:00
OrcaWin fbe08ba14d test: remove 134 redundant tests (#34511)
Removes 134 redundant test registrations across native-chat projection, sidebar ordering, and palette matching. Deletes two entire suites: notice appearance mapping and ordering scenarios whose test-owned Host supplies the behavior being asserted.

Retains 154 registrations covering state transitions, competing inputs, FIFO tool pairing, sidebar feed application, and search ranking. Production code is unchanged. Removes the two deleted suites’ timing entries and lowers the wall-clock baseline only for the deleted Date.now assertion.

Validation: isolated static registration/body preservation, formatting, lint, discovery, runtime routing, and metadata checks. Full PR CI must verify 275 expanded cases across 17 owning test roots, including the transcript-contract aggregator; 185 cases belong to retained selected sources and required counterparts. No local runtime tests were run.
2026-10-27 13:00:29 -07:00
Sojiro.OandBrennan Benson 9802866ed5 fix(editor): Copy Remote URL links to the code the workspace is on, with the selected line range (#33597)
* fix(editor): Copy Remote URL links to the code the workspace is on, with the selected line range

The gutter menu's Copy Remote URL always built the link on the default
branch and dropped any multi-line selection. Prefer the HEAD commit when
origin already has it, then the origin branch the current branch tracks,
then the default branch; carry an optional end line through IPC, RPC and
the git provider so a selection becomes a line range.

* fix: pair remote file links with published repository refs

* fix: prepare exact remote file fallback before publication scan

* test: consolidate remote file URL integration coverage

* test: document real-clock cancellation deadline proof

* test: handle optional cancellation signal in assertion

* test: reuse spawned child fixture across runtimes

---------

Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
2026-10-27 13:00:23 -07:00
Brennan Benson b46fb04487 fix: finish admitted terminal prompts after sender disconnects (#34373)
* fix: finish admitted terminal prompts after sender disconnects

* test: consolidate prompt input contract assertions

* Keep first-submit ownership independent of sender observation

* Recheck prompt ownership after awaited guards

* Cover abandoned prompt admission during restored pane startup

* Use typed provider write spy in prompt socket regression
2026-10-27 12:55:42 -07:00
OrcaWinandOrcaWin c5552d60b1 test: remove duplicate real-time WSL hook relay stop-settle test (#34510)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 12:45:32 -07:00
Brennan Benson 2d89c356a1 Show an unacknowledged Claude message once after reopening (#34355)
* Keep unacknowledged Claude prompts single after reopening

* test: bound local prompt recovery indexing at scale
2026-10-27 12:35:16 -07:00
Brennan Benson a238091bc0 Warn before closing an active native chat (#34236)
* fix(chat): confirm before closing active native chats

* Repair native chat close settings and consent coverage

* Cover native close consent in workspace and floating tests

* Require consent before closing active native chats

* Fix close-warning typed values in deferred actions and tests

* Preserve admission ownership and reconcile relevant send evidence

* Separate chat read lifetime from send settlement and activation effects

* Fix required read activation typing
2026-10-27 12:32:53 -07:00
Brennan BensonandOrca Worker f0eb0949d0 fix(windows): delete again succeeds after a held file is released (#34058)
* fix(windows): stop recursive deletes from retry-storming when a file is held open

Node's async recursive rm retries every nested entry separately and orphans
sibling walkers when it rejects, so deleting a workspace holding a live
browser profile multiplied filesystem work per directory level until the
main process hung. Delete Windows host trees with a walker that retries
whole passes from one shared budget and leaves nothing running on failure.

Also bound and log detached worktree removal, and fail a file transaction
whose proper-lockfile lock is compromised instead of throwing from its timer.

* fix(windows): retry a locked delete as whole passes instead of a custom walker

Replace the hand-rolled tree walker with Node's own recursive rm and no
per-entry retries. Async rm gives each nested entry its own retry counter and
never stops siblings, which is what multiplied the work; with retries off each
pass is one bounded walk, and a transient Windows lock repeats the whole pass
from the existing 250/500/1000/2000 ms budget, checking the job's signal
between passes.

A failed delete now names the file another program holds open instead of
Node's EBUSY/EPERM text. Drop the 30-minute background deadline. The lost-lock
error no longer embeds the library's message and says the write may or may not
have been saved.

* test: cover bounded deletion failure and recovery contracts

* test: prune unchanged cleanup coverage

* fix(worktrees): give truthful failed-delete cleanup advice

* test: document fake-clock retry adapter

* fix(windows): preserve checkout ownership until files are removed

* fix: preserve worktree ownership checks across metadata aliases

* test: make checkout retry clock completion explicit

* Keep failed Windows workspace deletions retryable

* test: correct removal fixture imports and path formatting

* fix: retain failed removal until a retry is accepted

* test: identify the mocked backoff clock

* test: preserve failed removal records and recreate marker fixtures

* test(worktrees): preserve exact checkout bytes in refusal contract

* test(worktrees): exercise current native deletion contracts

* test(windows): prove long-path deletion through native checkout removal

* test(windows): preserve real Git runner exports in removal fixture

---------

Co-authored-by: Orca Worker <orca-worker@localhost>
2026-10-27 12:31:10 -07:00
Brennan Benson a588c8ce66 fix(orchestration): settled workers stop reading resting slash lists (#34342)
* fix(orchestration): observe journal publications for worker redrive

* test(orchestration): remove redrive fixture type assertion

* test(orchestration): cover CLI redrive and worker publication scale

* test(orchestration): respect CLI project boundary and type worker fixtures
2026-10-27 12:24:27 -07:00
Neil cf7379610f Change wording from 'low value' to 'negative value' (#34507) 2026-10-27 12:22:37 -07:00
OrcaWinandOrcaWin 0294e1118a test: remove 47 low-value tests (#34505)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 12:20:50 -07:00
Jinjing 4b4bcc2e60 Revert "Size tabs to titles and preserve floating panel drag space (#34025)" (#34506)
This reverts commit 316b1887fd.
2026-10-27 12:12:33 -07:00
Neil 55dffb479a refactor: group shared native-chat empty-state copy (#34503) 2026-10-27 11:55:40 -07:00
OrcaWin d45d579ea4 perf(notebook): skip re-rendering unchanged cell outputs while typing (#34334) 2026-10-27 11:43:05 -07:00
OrcaWinandOrcaWin 05fc67ff51 test: remove 69 low-value syntax, script, policy and chat tests (#34497)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 11:30:19 -07:00
Neil 8414076859 refactor(shared): group native chat notice presentation (#34481) 2026-10-27 11:23:49 -07:00
OrcaWinandOrcaWin 964c64b0cc test: remove 64 low-value file, terminal and language tests (#34482)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-27 11:03:23 -07:00
Kelvin Amoabaandzhangxaochen 2a9d874e67 fix(mobile): leave Agent Session History when you resume a session from it (#34485)
* fix(mobile): leave Agent Session History when resuming a session from it

Resuming always pushed the session screen, so Back from it landed on the
history screen again (A -> B -> A). History now learns it was opened from a
session (origin=session, as Source Control does): resuming into that same
workspace pops back to it, anything else replaces the history screen.

The history screen is a page in the shell, and the page could only ask the
shell to push. The navigate notify gains an optional replace flag; a page with
no in-page history asks the shell to replace its screen, and one with history
below pops its own entry and has the shell push. Older shells strip the flag
and push as before.

Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>

* fix(mobile): show the resumed terminal on the session that opened Agent Session History

Going back to the session screen below kept its old tab: the session pins its
own pick over the host's caller-scoped snapshot. History now hands the resumed
terminal to that session through the registry Source Control already uses for
opened diffs, renamed to session-screen-handlers since it carries both.

* refactor(mobile): positional replace flag on notifyNavigate, share the owned-session test fixture

* fix(mobile): keep MobileWebShellScreen under its line cap

---------

Co-authored-by: zhangxaochen <3416677+zhangxaochen@users.noreply.github.com>
2026-10-27 17:58:49 +00:00
Anthony ScarlataandNeil ac154dc6a3 fix(notifications): keep Windows notification history clicks working (#33649)
On Windows a toast "closes" with reason timedOut when the banner hides,
but it stays clickable in Action Center. Releasing on that close (and on
the 5-minute fallback timer) dropped the click handler, so clicking the
notification from history did nothing.

On win32, ignore timedOut closes and drop the fallback timer; instead
retain up to 256 notifications and close + release the oldest past that
limit so history never holds a toast whose handler was discarded.

Co-authored-by: Neil <neil@stably.ai>
2026-10-27 10:36:03 -07:00
Kelvin Amoaba f87a746200 feat(mobile): light and dark themes with desktop's palettes (#34217)
* feat(mobile): light and dark themes with desktop's palettes

Settings → Appearance offers System, Light and Dark. The shell passes the
resolved scheme to over-the-air pages in its init frame.

Fixes #22184

* fix(mobile): draw your chat messages in desktop's user bubble

Desktop uses a faint surface with a hairline border in both themes; the inverted fill went black in light.

* test(mobile): re-measure the page script sweep after the shared theme hooks

Every route now imports the theme hooks while the entry does not, so they emit one shared script (96 for the tree). Re-swept every route prefix; the worst route step is now 15.

* test(mobile): read themed stylesheets in the text-input font-size census

The census only unwrapped StyleSheet.create({...}); inputs styled through themedStyleSheet(() => ({...})) came back unread.
2026-10-27 17:35:31 +00:00
Brennan Benson 7cb23565c9 fix(native-chat): resting chat skill checks share one capped Codex process per account (#34349)
* fix(native-chat): resting chat skill checks share one capped Codex process per account

A resting chat's slash list started one hidden codex app-server per
folder, each kept alive 70 s outside the two-check limit, and a scan
waiting in line for 30 s was treated as hung and doubled. With many
resting folders this kept about a hundred Codex processes alive.

- The catalog runs one scan per folder at a time; readers join it.
  Failures retry three times, then wait for the TTL. Entries unread for
  an hour are dropped.
- Codex folders that share an account, binary, arguments and
  environment are answered by one app-server, batched into skills/list,
  with at most two probe processes alive until their teardown ends.
  A probe that cannot start backs off, and a refresh does not reset it;
  an explicit refresh asks a live probe to reload.
- Batched replies are matched to their own folder.

Tracked in #34141.

* test: use fake timers for resting Codex probe cache checks

* fix(native-chat): bound resting discovery and retain process ownership

* fix(native-chat): close cancelled late directory acquisitions

* test(native-chat): complete cancellation discovery fixture

* test(native-chat): align fixtures with resolved workspace contracts
2026-10-27 10:33:48 -07:00
Brennan Bensonandm4air 4a39d186da Extract conversation switch foundations without activating them (#34384)
Co-authored-by: m4air <m4air@Mac.localdomain>
2026-10-27 10:27:58 -07:00
Kelvin Amoaba 5429d20f43 fix(mobile): show files named like constructor as plain text instead of failing diffs (#34475)
Mobile kept its own copy of the language tables and looked file names up
on plain objects, so constructor, toString or __proto__ returned an
Object member and lowlight threw. Mobile now uses desktop's shared
detector, which only reads own keys; .make moves into the shared table
so mobile keeps its Makefile highlighting.
2026-10-27 17:21:27 +00:00