Skip to content

feat!: add the Linux adapter - #298

Closed
lahfir wants to merge 1652 commits into
mainfrom
feat/linux-adapter
Closed

lahfir wants to merge 1652 commits into
mainfrom
feat/linux-adapter

Conversation

@lahfir

@lahfir lahfir commented Oct 21, 2026 •

Copy link
Copy Markdown
Collaborator

Adds the Linux adapter through the same CLI, C library, and npm packages as macOS and Windows. AT-SPI observation and ref actions cover GNOME, X11, and Wayland, with explicit platform limits. Target identity and delivery reporting distinguish safe refusals, confirmed effects, and uncertain writes.

The adapter shares visibility and actionability evidence, avoids unsafe bulk Qt property reads, attributes launch handoffs to a proven owner, and uses process-bound GTK exports where ordinary accessibility dispatch blocks in a nested modal loop. Combo selection verifies the committed owner value instead of popup highlighting. Optional monitor reads cannot hold a completed snapshot until its deadline. Clipboard ownership retains security checks while reclaiming proven stale records.

Shared changes include bounded asynchronous Windows placement verification, more precise delivery dispositions, ref-action resolution and recovery, text-sensitive typing deadlines, pointer geometry, and session cleanup. Toolkit coordinate semantics use the toolkit's own AT-SPI declaration; application names and versions do not select runtime behavior.

Validation of the integrated repairs:

  • Final Linux library suite: 2,163 passed, zero failed, 233 intentionally ignored native/environment cases. Core 1,515, macOS 765 and FFI 183 unit tests passed; CLI/integration tests, Clippy, formatting, source rules, architecture isolation and Windows-target core compilation passed. Native Windows runtime and live macOS E2E were not rerun for the Linux-only follow-up. A macOS test-only socket-name collision was reproduced with a frozen clock and fixed by separating concurrent phases; all three affected tests and the full 765-test macOS unit suite pass.
  • Earlier private X11 and Wayland ref-table pass totals are superseded by the strict gate integrated through test: enforce snapshot promises in linux ref contracts #308. Corrected native Wayland results are GTK3 33 passed/3 failed, GTK4 21 passed/9 failed, and Qt 35 passed/4 failed; the Qt combo row also records unexercised collapse setup. The corrected private X11 gate reports GTK3 37 passed, GTK4 21 passed/9 failed, and Qt 36 passed/3 failed. Window-workflow evidence is separate: Openbox and Mutter each passed six VM legs before the last Wayland-specific fixes, and the final release passed native Wayland GTK3 dialog/Save chooser workflows. Independent native regressions cover menu inventory, explicit headed Qt choice commitment, GTK4 entry focus and clipped-viewport refusal.
  • The ref contract keeps snapshot-derived expectations unchanged. An advertised action that refuses fails rather than becoming a passing refusal; fixture close requires a successful response and both independent effects. Both regressions fail before repair and pass afterward; test: enforce snapshot promises in linux ref contracts #308 passes all 21 focused tests and the 344-test harness suite (one skip). No automatic headed fallback is permitted. Native Wayland Qt combo opening requires a user input serial; backend discovery failure remains an error. Semantic menu activation does not require global pointer coordinates, while physical delivery retains its geometry checks.
  • A headless stranger workflow created, saved, reopened and extended a note, verified through independent file contents and a fresh complete snapshot. Earlier seven-sample snapshot latency after warm-up was 33.4/37.2/42.1 ms min/median/max versus 32.2/40.5/48.1 ms baseline. A completed snapshot under withheld RandR replies dropped from 2.025 s to 35–95 ms. These measurements precede the final Wayland fixes.

Measured limits remain visible in the strict failures: GTK 3.24.41 retains stale Atk FOCUSED state after three reset workflows despite correct Gtk focus and delivered effects (L41-30); GTK4 entry activation does not emit the requested callback (L41-22), and tab/list native selection indices cannot be safely inferred from accessible indices (L41-9/L41-12). Qt popup-row selection can highlight without committing the combo value (L41-13), and native Wayland popup opening requires an input serial (L41-29). No raw-state masking, speculative selection write, synthetic headless input or ineffective reset delay was added. A viewport crossing display boundaries is conservatively refused even if the display union covers it.

This is the Linux-to-main promotion PR. Repair PRs #302–#308 are integrated; final CI and review refer to head d5cc0cc. Promotion awaits human approval.

Use Squash and merge: older commits on this branch are unsigned.

@lahfir
lahfir marked this pull request as ready for review October 22, 2026 22:02
@greptile-apps

greptile-apps Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[High impact] The latest repairs appear safe to merge, with both numbered findings addressed and no new blocking issue found.

Summary

This PR adds Linux support through the CLI, C library and npm package.

The latest update tightens the Linux test gate:

  • Linux desktop commands can inspect apps and carry out supported actions.
  • Operation results show what was targeted and how delivery ended.
  • Linux CLI and FFI packages include the clipboard-owner helper.

No new actionable issues were established in the changes since the previous review. Tests were inspected, not run.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Snapshot promises an action] --> B[Run the action]
  B --> C{Successful response?}
  C -->|No| F[Fail the row]
  C -->|Yes| D{Both independent effects appear?}
  D -->|No| F
  D -->|Yes| E[Pass the row]
Loading

Reviews (16) · Last reviewed commit: "test: enforce snapshot promises in linux..." · Reviewed by Greptile

Comment thread crates/ffi/src/types/ref_geometry.rs Resolved
Comment thread crates/linux/src/system/launch/mod.rs Resolved
Comment thread crates/linux/src/system/launch/mod.rs Resolved
Comment thread tests/linux-dist/run-npm-install.sh Resolved
lahfir added 22 commits October 22, 2026 23:28
…ct test

docs/phases.md leaves the repository, so the CI unittest run would fail with
FileNotFoundError. No registry leg is an owner decision today, and Leg already
refuses a non-pass disposition without a reason, so the reason in code is now
where an owner decision is recorded and the test pins that rule instead.
No workflow, hook, script or test calls them: a symlink helper for local skills, a root-only uinput stub whose legs were never written, and an unrun self-test of the npm wrapper smoke, which CI runs directly.
The architecture diagrams and the Slack token illustration were not
linked from anywhere and showed Linux as planned. The acceptance audit
was a withdrawn status record. Two solution docs were folded into the
docs that already carried their context, so each lesson has one home.
Validated in the docs removal ledger (docs-3, 6, 8, 11, 12, 13).
Many learnings named moved files, deleted tests, stale function
signatures, or rules the code no longer follows (bare refs accepted,
native apps never activated, one box lock instead of two slots). Each
now cites the code that holds today, and none cites the planning docs
or the untracked dogfood reports.
Several definitions described one platform as if it were every
platform, missed the Linux adapter, cited probe rows that measure
something else, used a screenshot flag that does not exist, and called
dogfood reports committed. Session Manifest folds into Session and the
must-catch fixture into Gate Self-Test, where each was already half
defined.
CONTRIBUTING.md now points to CLAUDE.md for the engineering rules
instead of keeping a second copy that had drifted (a MockAdapter that
does not exist, an E2E command that exits without the exclusive-desktop
variable). The JSON contract described an unknown disposition the code
no longer emits, the FAQ repeated the README platform table, and the
Windows runner runbook cited plan ids and a trigger branch that merged.
ffi-release-panic-guard already runs the identical grep and publish-github needs it, so the copy in ffi-release-gates added nothing.
skills/agent-desktop-linux/SKILL.md carries the x-release-please-version marker and is published with the other skills, but was missing from extra-files, so its version would have stayed behind.
Several harness commands failed as documented (the Linux consumer run
without AGENT_DESKTOP_WM_ROOT, the discovery inversion without a header
path, a headless probe binary that swiftc names differently) and the
fixtures README listed files that do not exist. The Linux E2E guide
drops plan history and keeps what an operator needs to run and read it.
# Conflicts:
#	tests/e2e-linux/README.md
#	tests/linux-dist/README.md
#	tests/real-apps/README.md
The shared clipping doc already states the same incident and the
repair that superseded it, so the lesson keeps one home. Validated in
the docs removal ledger (docs-14).
…cripts

The skill teaches node scripts/jev/*.mjs, which ship in no installed package,
so it now says up front that it needs a clone of the repository and a
TYPESAFE_API_KEY. Checked against the scripts: run.mjs retries 429/503/529
twice while act.mjs does not, --bin and --execute belong to act.mjs only,
act.mjs sends longer values and the ancestor path, why is null on act, the stop
list and exit codes were incomplete, and JEV_VERIFY_MS was missing.
ad_free_handle works after the adapter is destroyed (native_handle.rs tests
prove it), so the rule is to free handles before destroying the adapter only
for use, not for release. The wait bullet now uses the header's AdWaitMode
field names, AdActionStep lists mechanism and verified, the delivery-semantics
accessor copies values instead of lending a pointer, and the JSON-string table
gains ad_execute_by_ref_timeout, ad_trace_show and ad_trace_export.
Each removed piece repeated a check that another job already runs on the
same OS, or depended on a file that is leaving the repository:

- platform-check: three legs were subsets of clippy --all-targets on the
  same runner; the windows-11-arm leg is now a clippy step in test-windows-arm.
- ffi-header-drift, ffi-python-smoke and ffi-passthrough now run as
  conditional steps on the ffi-panic-guard legs that used the same OS, so
  the header drift gate and the stub checks keep running on every PR.
- check-release-consistency.sh and check-npm-package.js run in the
  supply-chain workflow on every PR, push and weekly, and need no OS.
- the ubuntu bash3 compatibility run was weaker than the macOS Bash 3.2 run.
- trash and trash-cli installs had no caller left.
- check-phases-ledger-citations.ps1 read docs/phases.md, which leaves the
  repository, and would fail the Windows lane.

The viewer_filter.js test moves here from the inspector workflow, so the
shipped viewer code keeps a CI test.
tools/inspector is a local developer viewer that no shipped artifact, skill or release step uses, and its workflow only tested it. The viewer_filter.js test it also ran now lives in the CI workflow.
…nds alone

The reason it is a separate read-only workflow lived only in docs/phases.md, which leaves the repository. A concurrency group stops a busy PR from queueing many full rehearsals, and trash-cli had no caller left.
The probes measure the hosted runner. The one contract they check against crate code, secure-value withholding, is also a plain unit test in the Windows CI lane, so code-only PRs no longer pay for a 30-minute probe run.
The jev-desktop skill left the shipped skill set, so its usage notes move next to the scripts they describe, checked against the current flags and environment variables.
Comment thread crates/linux/src/actions/select/mod.rs Resolved
Comment thread crates/linux/src/tree/observe/mod.rs Resolved
Comment thread crates/linux/src/actions/chain.rs Resolved
lahfir and others added 3 commits October 24, 2026 03:56
fix: await queued windows and reclaim stale clipboard records
…eview

fix: verify combo commits and bound optional snapshot reads
* fix: complete linux ref delivery and safe refusal contracts

* fix: complete Wayland menu and chooser ref contracts

* test: report unsupported action setup as unexercised

* test: separate concurrent overlay fixture sockets
@lahfir

lahfir commented Oct 28, 2026

Copy link
Copy Markdown
Collaborator Author

Delivered through #311. That PR's head contains this branch's tip (2212399), and its squash landed on main as 4c598cd. After main was merged back in (fbb38ba), this PR has no changes against main, and main requires linear history, so there is nothing left to merge. The Linux adapter ships in 1.0.0 (#322).

@lahfir lahfir closed this Oct 28, 2026
@github-project-automation github-project-automation Bot moved this from Todo to Done in Issues and PR Oct 28, 2026
@lahfir lahfir reopened this Oct 28, 2026
@lahfir lahfir closed this Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant