Commit Graph

50 Commits

Author SHA1 Message Date
Ignacy Łątka c876fe8dbc ci: add knip anti-dead-code gate (#572)
## What

Adds a CI gate for dead code, using [Knip](https://knip.dev).

We didn't have one. ESLint's `no-unused-vars` only sees unused locals
inside a module, so whole files nobody imports, exports nobody uses, and
dependencies declared but never required all slipped through. Knip
covers that gap in one tool (roughly `ts-prune` + `depcheck` +
`unimported` combined).

The new `.github/workflows/knip.yml` workflow ("Dead Code", job `Knip`)
runs `npm run knip` on push and PR to `main`. `CONTRIBUTING.md`'s
pull-request checklist gains it as a step, with the reason it has to run
against a tree with no build output. Knip reads source directly, mapping
each package's `dist` entry back to `src`, so the job needs no workspace
build. It installs with `--ignore-scripts`: an analysis that only reads
`package.json` and source gains nothing from the seven packages here
that carry a native install script, six of which reach this runner
(`fsevents` is darwin-only). Five try a prebuilt binary before
compiling, and `dtrace-provider` always runs node-gyp but ends in `||
node suppress-error.js` — and off mac/solaris/freebsd its `binding.gyp`
picks a stub target with no sources, so on ubuntu-latest node-gyp builds
nothing for it and `node-pty` is the only package that reaches a
compiler at all — an `optionalDependency`, whose failure npm ignores.
The exposure is a bump that leaves a package with no prebuild for the
runner, which is exactly what `dependabot.yml` pins `tree-sitter`
against (0.25.0 ships no Node 24 prebuild and its compile breaks `npm
ci`).

While adding it I checked whether any other installed checker was
missing a gate. None were: ESLint (`lint.yml`), Prettier (`format.yml`),
`tsc` build + `typecheck:tests` + `typecheck:scripts` + vitest
(`unit-tests.yml`), the workspace-version / focused-test / merge-marker
checks (`repo-hygiene.yml`) and lockfile sync (`lockfile.yml`) are all
already enforced. Dead code was the only gap.

## How it's enforced

`npm run knip` is two invocations:

```
knip --exclude exports,types && knip --include exports,types,classMembers,nsExports,nsTypes --max-issues 206
```

Every issue type knip reports is an error — that is its default
severity, so `knip.jsonc` sets no `rules` block at all. The pre-existing
backlog is bounded by the `--max-issues` ceiling on the second pass
instead of being hidden behind a non-failing severity: it cannot grow
unnoticed, and the number comes down as follow-up passes pay it off.
When a change legitimately adds an export nothing imports yet, the
number moves up in the same commit — that bump is what review should
see, rather than the contributor deleting someone else's backlog to make
room. Two PRs making that identical one-line edit merge without
conflicting, so `main` lands one short of the truth and its
push-triggered run is what catches it. Splitting the passes also keeps a
real failure out from under the backlog — the enforced classes report on
their own, and the second pass only runs once the first is clean.

The second pass names `classMembers`, `nsExports` and `nsTypes`
explicitly because they sit in knip's own `defaultExcludedIssueTypes`:
`--exclude exports,types` never covered them and `--include
exports,types` did not ask for them, so a new unused class member cost
nothing and moving an export behind opaque namespace use took it out of
the ceiling's scope entirely. `classMembers` has 12 findings on the
unbuilt tree the ceiling counts (9 on a built one); the other two have
none today. None of the three is gated at zero — all five parked classes
share the one ceiling, so a new `nsExports` finding passes if something
else in the backlog is retired in the same PR. Naming `classMembers`
also turns knip's `isSkipLibs` off (`create-options.js:122`), which
makes it search declaration files for external references and
**suppresses** 44 export/type findings the same run reports without it —
57/181 becomes 44/150. That, not the 12 findings it adds, is why the
ceiling is lower than the two counts alone would suggest;
`--include-libs` with no `classMembers` reproduces 44/150 exactly.

The ceiling counts what CI counts, against a tree with no build output.
Whether a workspace's `main`/`types` path resolves to an existing file
changes the result, and not by way of anything in that file — a
zero-byte `packages/registry/dist/index.js` moves the count just as a
real build does, while a zero-byte `dist/zzz.js` does nothing. A built
tree reports fewer issues — 43/147/9 = 199 built, against 44/150/12 =
206 unbuilt — so `npm run knip` passing after a local `tsc --build` is
not evidence the job will pass, which is how the Knip job first went red
on 199. The ceiling is 206 and it is exact: 206 passes, 205 fails.
Remove every `dist/` before trusting a number from it.

The ceiling is one total across those classes, so it bounds the backlog
rather than each class: paying off one parked export licences one new
one elsewhere in the same PR. Knip has no per-class ceiling.

`treatConfigHintsAsErrors` is on, so an exemption that stops suppressing
anything fails the job rather than printing a hint below the backlog.

## Config

`knip.jsonc` documents the false positives so the gate is both green and
meaningful.

- **`@swmansion/argent`** is a thin dispatcher whose real payload is an
esbuild bundle of the other workspaces
(`packages/argent/scripts/bundle-tools.cjs`). Knip can't follow imports
across that boundary, so packages consumed only by the bundled-in code
read as unused; 11 are exempted by name here, though not all for that
reason — the http3-quiche transport is pulled in by
`@fails-components/webtransport` itself at runtime, and no first-party
file imports it. They're exempted **by name**, not behind a catch-all:
`ignoreDependencies` also suppresses `unlisted`, and a pattern that
matches everything would take this workspace's own `src/` and `scripts/`
out of that check — where an import with no matching declaration is a
genuine bug rather than a bundler artifact. (It reaches `unresolved`
only nominally: knip matches the list against a package name parsed out
of the specifier, and an unresolvable relative path yields none, so even
a catch-all leaves those reported. `ignoreUnresolved` is the option that
does silence them.)
- **`tool-server`** reaches a few packages in ways static analysis can't
see. The exemptions cover two distinct classes, kept apart in the config
so each stated reason matches the finding it silences:
- *declared but loaded too dynamically to detect* (would be reported as
**unused dependencies**): `tree-sitter` / `tree-sitter-typescript` via
dynamic `_require`, and the http3-quiche transport as a runtime
companion of `@fails-components/webtransport`;
- *imported but deliberately absent from that `package.json`* (would be
reported as **unlisted dependencies**): `sharp` (kept out so the ~30 MB
native binary isn't a cost every consumer pays) and `electron` (an
`optionalDependency` of the published package at one call site, the
Electron main-process API at the other).
- Root `scripts/`: knip resolves those from `package.json` scripts
**and** from `run:` steps in `.github/workflows` via its github-actions
plugin — multi-line `run: |` blocks included. What the plugin doesn't
parse is a PowerShell body, so `scripts/ci/windows-chromium-e2e.mjs` —
invoked at `windows-e2e.yml:176`, in the `windows-latest` job where
PowerShell is the default shell — is the one entry declared by hand.

### Known limits

- `ignoreDependencies` exempts a package **name across its whole
workspace**, in both directions; knip has nothing narrower. While
`sharp` is listed for `tool-server`, an undeclared `import "sharp"`
anywhere in that workspace passes too. The list is held to packages that
genuinely cannot be declared, for exactly that reason.
- Knip analyzes JavaScript and TypeScript only (`DEFAULT_EXTENSIONS`),
so **only 11 of the 30 files under `scripts/` are in the gate at all**.
The other 19 — 15 `.sh` files, `e2e-full/lib/report.py`,
`ci/e2e-chromium-page.html`, and e2e-full's `README.md` and
`results/.gitignore` — are invisible to it however they are reached —
including the whole `scripts/e2e-full/` harness (13 files), invoked from
nothing outside its own directory, its only mention elsewhere being a
`.prettierignore` entry.
- Reachability's widest hole is the workspace entry. Whatever
`src/index.ts` re-exports is reached, so a single `export { x } from
"./dead-module";` takes that module out of `files` altogether — verified
against a module reported as an unused file one run earlier. The same
line applied to parked exports retires them from the count without
deleting anything: re-exporting `equalsCI`, `includesCI` and `Settled`
from `tool-server`'s entry takes 206 to 203 and frees three ceiling
slots. The ceiling bounds what knip can see, not what is dead.
- Test files are entry points, so a production module kept alive only by
its own test still passes `files`. Being reached by a test says nothing
about being reachable in production, which is what the check
approximates, and two modules sit in exactly that gap: `tools/paste` is
imported by two test files and registered by nothing, so it is
unreachable over MCP and HTTP, and `utils/ios-profiler/lifecycle.ts` is
a re-export barrel whose header keeps it "for source compatibility with
existing imports", of which its own test is now the only one — its four
production consumers all import `profiler-shared/lifecycle` directly.
That single test import is exactly what keeps `files` from reporting it:
repoint it and knip returns `Unused files (1)`. `knip --production` is
the lens that reports the class; the repo isn't clean under it — 13
unused files (those two, seven root scripts,
`packages/argent/scripts/{bundle-tools,observe,sync-readme}.cjs` and
`packages/registry/tests/helpers.ts`) with the export/type backlog at
227/206 — measured with `classMembers` off, so comparable to the 57/181
above rather than to the ceiling's 44/150 — so a production-mode pass is
a follow-up of its own.
- The same entry treatment hides the test trees themselves. Root
`package.json`'s `test:scripts` runs `node --test`, which is what makes
knip's node plugin contribute its test entries, and that plugin
registers four entry patterns in **every** workspace: `**/test/**`, plus
`*{.,-,_}test.<ext>`, `test-*.<ext>` and `test.<ext>` matched anywhere.
So none of the **380** JS/TS files under `packages/*/test/` can be
reported unused, and under `packages/*/tests/` only a name none of those
three match can — of today's 15 that is `registry/tests/helpers.ts`
alone, which is why it is the lone `tests/` entry in the `--production`
list above. A `tests/test-utils.ts` or `tests/test.ts` would be just as
invisible. A dead `zz.test.ts` planted in `packages/registry/tests/`
passes; a dead `zz-helper.ts` in the same directory fails.
- `knip@5.88.1` is the last 5.x release ever published — 6.0.0 landed
the next day and `latest` is now 6.x. The pin is deliberate: knip 6
removed the `classMembers` issue type outright, and the shipped script
hard-errors on it (`ERROR: Invalid issue type: classMembers`, exit 2).
Upgrading is therefore not a version bump — it means re-deriving the
ceiling, rewriting the paragraph that explains it, and resolving the
pass-1 findings knip 6 adds (six unlisted binaries: `tail`, `plutil`,
`xctrace`, `netstat`, `pkill`, `pgrep`; two unresolved imports:
`/usr/bin/osascript`, `/usr/libexec/PlistBuddy`). Dependabot's
`npm-minor-patch` group cannot move it, since no 5.x exists above
5.88.1; the `npm-major` group will keep offering the 6.x jump.
- Knip folds `optionalDependencies` into the declared set, so importing
`electron` or `node-pty` is not `unlisted` — they pass because it read
them. What it never reports is an optionalDependency nothing uses, so
only that direction is outside the gate, along with `argent-cli`'s
runtime `req("node-pty")`, resolved through a
`createRequire(import.meta.url)` in `lens-pty.ts`, which knip can't see
either.

## Dead code this found

- `@types/semver` and `@argent/telemetry` from `packages/argent` — both
were being suppressed by exemptions whose stated bundler-boundary reason
could not apply. esbuild strips types and never resolves `@types/*`, and
`packages/argent` names `semver` nowhere; `@argent/telemetry` is aliased
to an absolute source path by `bundle-tools.cjs`, so the declaration
bought nothing. Removing them is proved safe by building: four of the
five bundles still emit and telemetry is inlined in each with no runtime
`require` of it. The fifth, preview-window's main, sits behind a
downloaded native asset absent from a script-free install, so it is
covered by mechanism rather than observation — `bundle-tools.cjs` passes
the same `alias` map to every build, and esbuild's `alias` bypasses node
resolution entirely: deleting `node_modules/@argent/telemetry` outright
leaves all four emitted bundles byte-identical.
Removed alongside, but **not** gate-reported: the `benchmark` npm script
in `packages/argent`, whose `scripts/benchmark.cjs` does not exist. A
dangling script target is a blind spot of this gate — restoring the
script leaves knip at exit 0.

- Four files with no importers: the `render-hook` injected script,
react-profiler's `source-map` + `snippet-extractor`, and
`scripts/setup-in-workspace.cjs` (referenced nowhere, and its own usage
string names a `scripts/setup-project.cjs` that doesn't exist).
- `superagent` in `tool-server`'s `test/http-streaming.test.ts` —
imported for a type but declared in no manifest in the repo, resolving
only through npm hoisting of supertest's own dependency. Reverting that
import to `superagent` reports `Unlisted dependencies (1) … :3:32` and
exits 1; `@types/supertest/index.d.ts:10` re-exports the identical type
(`type Response = superagent.Response`).
- `@clack/prompts` and `@moq/lite` from `tool-server`'s `package.json` —
declared, imported nowhere. (`@moq/net` is the one actually used;
`@moq/lite` isn't a peer of it.)

Also deleted here, but **not** something this gate reported:
`src/tools/simulator/simulator-server.ts`. It sat in the `files` blind
spot above — `interaction-messages.test.ts` imported it, which is enough
to count as reached. `setup-registry.ts` never registers it, so it was
unreachable over MCP and HTTP, and that catalog roll-call was its only
reference; the import and the catalog count (77 → 76) went with it.

## Lockfile

Adding knip moves two transitive packages: `@napi-rs/wasm-runtime` 1.1.5
→ 1.1.6 and `@tybys/wasm-util` 0.10.2 → 0.10.3. Knip pulls in
`@oxc-resolver/binding-wasm32-wasi`, which floors
`@napi-rs/wasm-runtime` at `^1.1.6`, lifting the hoisted entry that had
resolved to 1.1.5 for `@rolldown/binding-wasm32-wasi`'s `^1.1.4`, which
then cascades to `@tybys/wasm-util`. No runtime impact — both are
support packages for the wasm32-wasi fallback bindings, which don't get
installed where a native binding exists; `npm ls` reports both
extraneous on darwin-arm64. Those two are the only resolved versions
that change in the diff; the rest is knip's own tree (49 packages added)
and `@moq/lite` removed.

## Verification

- `npm run knip` exits 0.
- **Coverage of the enforced set.** With no `rules` block, knip's
included set is 15 issue types: ten enforced at zero tolerance by the
first pass, plus the five the second pass names under the ceiling.
Eleven mutations cover all ten, each flipping the gate to exit 1 and
back to 0 on revert:

  | class | mutation |
  | --- | --- |
| `files` | a throwaway `.mjs` in `scripts/`; a throwaway `.ts` in
`packages/argent/src` |
| `dependencies` | a bogus declared dep in
`packages/tool-server/package.json` |
  | `devDependencies` | a bogus declared devDep in the same manifest |
| `optionalPeerDependencies` | `bytes` moved to an optional
`peerDependency` there |
  | `unlisted` | an undeclared import in `packages/argent/src/cli.ts` |
  | `unresolved` | an unresolvable relative specifier in the same file |
| `binaries` | a root `package.json` script invoking a nonexistent
binary |
| `duplicates` | `export default sleep` alongside the existing named
export in `utils/timing.ts` |
| `enumMembers` | an unused member on an enum a second module imports
and uses |
| `catalog` | a `catalog` block in the root `package.json` naming a
package nothing uses |

One nuance worth recording: `duplicates` is narrower than it looks. It
reports a symbol exported both by name and as `default`
(`sleep|default`); a second *named* alias of the same symbol is not a
duplicate, and a freshly added symbol nothing references is not reported
at all — so several naive probes read as a miss.

`enumMembers` needed a shape the repo does not currently contain, not an
unreachable one. The only exported enum here, `ServiceState`, is
re-exported through `@argent/registry`'s entry, where knip counts
exports as used, so an unused member added to it is **not** reported —
but an enum in a non-entry module that another module imports and uses
does report one (`Blue ZzColor …/zz-enum.ts:3:3`, exit 1; deleting the
unused member returns exit 0). That is the ninth of the ten covered.

`catalog` is reachable here despite the repo using npm workspaces:
knip's catalog loader falls back to `manifest.catalog` when there is no
pnpm or yarn workspace file, so a `catalog` block in the root
`package.json` reports `Unused catalog entries (1)` and exits 1.
- The two new mechanisms discriminate as well: one extra unused export
takes the backlog to 207 and fails the ceiling, and a stale
`ignoreDependencies` entry produces `Configuration hints (1) … Remove
from ignoreDependencies` and exit 1.
- `npm ci --ignore-scripts` in a clean worktree, followed by `npx knip`,
is green — the job doesn't need any of the postinstalls it now skips.
- `tsc --build`, `typecheck:tests` (all workspaces),
`typecheck:scripts`, `test:scripts`, `eslint . --max-warnings 0`,
`prettier --check .` and the full workspace vitest suite (4711 passed, 3
skipped across 13 workspaces; 3070 of those are `@argent/tool-server`
alone) are green; `package-lock.json` is untouched by the review pass.
2026-08-10 17:09:16 +02:00
filip131311 68ceb314d6 ci: cut over npm publishing to the unified trusted-publishing workflow (#571)
## Why

Cutover step 3+4 of the plan from #565. `publish-npm.yml` is now
registered on npmjs.com as the **trusted publisher** for
`@swmansion/argent` (2026-07-24) and the OIDC publish path is verified
live: `v0.17.1-next.1` published with a SLSA provenance attestation via
a workflow_dispatch of the unified workflow.

Extra urgency: token-based publishing died on 2026-07-24 (~11:20–15:20
UTC window; npm's 2FA-bypass token restriction) — **`publish-next.yml`'s
canary now fails on every main push** (identical E404 on the registry
PUT, e.g. run 30104847558). The old workflows aren't just redundant,
they're broken; only the trusted-publisher workflow can publish.

## What

- Delete `publish.yml` and `publish-next.yml` — `publish-npm.yml` is the
only publish path.
- `sync-next-tag.yml`: drop the two retired workflow names from the
`workflow_run` trigger.
- `publish-npm.yml`: remove `NODE_AUTH_TOKEN` from both publish steps
(OIDC authenticates; the rest of the job already ran token-less) and
update the header — the cutover plan is replaced by a note that this
file's name is load-bearing for the npmjs.com registration.
- `NPM_TOKEN` stays as a secret: `sync-next-tag.yml` still needs it for
dist-tag mutation, which OIDC doesn't cover. Note the token may
currently be dead for dist-tag writes too — the post-publish sync run
succeeded but had no mutation to make; if a real re-point fails, a fresh
granular token is needed.

## After merging

Set the repo variable to enable canary-on-push (kept as the canary
kill-switch):

```
gh variable set PUBLISH_NPM_UNIFIED --repo software-mansion/argent --body "1"
```

Ordering is safe: until the variable is set, a main push publishes
nothing (the old canary workflow is gone, the new one skips) — no
double-publish window exists.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-24 17:54:00 +02:00
filip131311 2546788a8d ci: unified publish-npm workflow (provenance-ready, trusted-publishing prerequisite) (#565)
## Why

npm provenance / trusted publishing for `@swmansion/argent` requires
registering **one** workflow file as the package's trusted publisher on
npmjs.com — but we currently publish from two (`publish.yml` for stable,
`publish-next.yml` for canaries/prereleases). This PR adds their unified
successor, **`publish-npm.yml`**, without touching the old workflows:
they keep running unchanged until cutover.

## Design

One file, mode derived from the trigger and the version — nothing is
spelled twice:

| Trigger | Behavior |
|---|---|
| `push` to `main` | Canary: version derived + stamped
(`<base>-next.<k>`), published under `next` with the same registry-race
retry loop as before. **Dormant until the `PUBLISH_NPM_UNIFIED` repo
variable is set to `1`** — otherwise every main push would publish two
canaries while `publish-next.yml` still exists. |
| `workflow_dispatch` | Publishes the ref's `package.json` version
verbatim. Dist-tag derived from the version itself: prerelease → `next`,
stable → `latest`. The optional `channel` input is an assertion (fails
on mismatch), not a selector — you can't accidentally ship a prerelease
to `latest` or vice versa. `dry_run` runs the full build + bundle
verification + pack without publishing. |

Provenance is on from day one: the job has `id-token: write` and every
publish path uses `--provenance` (repo is public, `repository.url`
matches — the two things the registry verifies). Token auth
(`NPM_TOKEN`) is kept for now; npm ≥ 11.5.1 is ensured in the job so the
OIDC exchange takes over transparently once the trusted publisher is
registered.

`sync-next-tag.yml` now also triggers on the new workflow, so `next`
keeps getting re-pointed after publishes from either generation. (Until
cutover a main push may trigger the sync twice — once per publish
workflow — which is harmless: the script is idempotent.)

## Cutover checklist (follow-up, also documented in the workflow header)

1. Test: `workflow_dispatch` with `dry_run`, then a real prerelease
dispatch (`v*-next.N` ref).
2. On npmjs.com, register `publish-npm.yml` as the trusted publisher for
`@swmansion/argent` (org `software-mansion`, repo `argent`).
3. Set repo variable `PUBLISH_NPM_UNIFIED=1` and delete `publish.yml` +
`publish-next.yml` in the same PR (also dropping their names from
`sync-next-tag.yml`'s `workflow_run` trigger).
4. Remove `NODE_AUTH_TOKEN` from the publish steps (`NPM_TOKEN` stays
for `sync-next-tag.yml` — dist-tag mutation isn't covered by OIDC);
optionally restrict the package's publishing access to the trusted
publisher only.

## Behavior differences vs the old pair

- Stable dispatch now publishes with an explicit `--tag latest` (same
effect as the old default) and `--provenance`.
- The old `publish-next.yml` dispatch guard ("refuse non-prerelease
versions") is generalized: a stable-version ref dispatched here goes to
`latest` instead of erroring. Set `channel: next` if you want the old
refusal behavior.

🤖 Generated with [Claude Code](https://claude.com/claude-code)
2026-07-24 17:20:18 +02:00
Ignacy Łątka 7400179b5b Windows support: Android + Chromium host control plane (#421)
## What

Makes Argent run on Windows. iOS Simulator is macOS-only (Apple), so on
Windows that means the **Android + Chromium** host control plane. The
blocker was twofold: (1) no Windows `simulator-server` binary, and (2)
POSIX-only assumptions in the tool-server.

Companion radon PR builds the binary and runs the Android emulator E2E
on Windows: software-mansion/radon#134.

## Changes

**Windows-aware tool-server / resolver / bundling**
- New shared `commandOnPath()` helper — `where` on Windows, `command -v`
via `/bin/sh` on POSIX. `android-binary`, `check-deps`, and `vega-cli`
previously hardcoded `/bin/sh`, which never matches on Windows.
- `android-binary`: append `.exe` to `adb`/`emulator` in the
`$ANDROID_HOME` fallback; probe `%LOCALAPPDATA%\Android\Sdk` (Android
Studio's Windows default).
- simulator-server resolver + dispatcher + `bundle-tools` +
`download-simulator-server.sh`: ship and resolve `simulator-server.exe`
on `win32` (new `simulatorServerBinaryName()`), add `win32` to the
bundled host keys, add the `simulator-server-argent-windows.exe`
download target with PE arch validation.
- `stop-metro`: resolve listening PIDs via `netstat -ano` on Windows
(`lsof` is POSIX-only and threw ENOENT).
- `adb.ts`: AVD root resolution used `$HOME` + `startsWith("/")`
(rejects `C:\…`); now `os.homedir()` + `path.isAbsolute()`.
- **`boot-device`**: the emulator was spawned `detached` with
`stdio:"ignore"`; on Windows a detached emulator with NUL stdout/stderr
never reaches `sys.boot_completed` (verified on `windows-latest`: the
identical flag set boots fine with real handles, hangs with NUL).
Redirect the detached emulator's output to a temp log file on win32.
POSIX keeps `"ignore"`.

**Tests** — cross-platform unit coverage for `commandOnPath` (both
branches), win32 `.exe` Android resolution, win32 `.exe`
simulator-server resolution, and a win32 AVD drive-path case; dep-gate
tests now mock at the `commandOnPath` boundary so they're
platform-agnostic.

**CI** — `windows-e2e.yml` (`windows-chromium` on `windows-latest`):
runs the resolver/dep unit tests natively on Windows, confirms `adb.exe`
resolution via the SDK root, then drives a **real headless Chrome over
CDP** through the tool-server (discover → screenshot → describe → tap →
observe the DOM mutation). Flow in `scripts/ci/windows-chromium-e2e.mjs`
(also runnable locally / in Docker). The `simulator-server.exe` build +
the full **Android-emulator E2E on Windows** live in radon CI (the
binary's source is the private radon repo).

## Verification (all green)
- **Chromium control plane on real Windows** (`windows-latest`): `✓
discovered chromium-cdp-9222 → ✓ screenshot → ✓ describe → ✓ gesture-tap
→ ✓ DOM mutation observed`. Resolver/dep unit tests run natively;
`adb.exe` resolves via the SDK root (it's *not* on PATH on the runner —
the gap the resolver closes).
- **Android emulator on real Windows** (radon#134, `windows-latest` /
WHPX): the real Argent path — `boot-device` → `{ booted: true }` →
screenshot via `simulator-server.exe` → gesture-tap — all green. (The
boot-device fix above is what makes the detached emulator reach
`boot_completed`.)
- **Local clean-room E2E**: the Chromium flow runs green in a headless
Linux Docker container (fresh `npm ci`, no host pollution).
- **No regressions**: full tool-server suite (1624) +
native-devtools-ios (16); ESLint/Prettier/typecheck clean; **Wayland
E2E** (Linux AVD boot) and **Vega VVD E2E** still pass (they exercise
the changed `adb.ts` / `boot-device.ts` / `vega-cli.ts` paths).

## Notes
Android-emulator E2E needs WHPX nested virtualization — confirmed
available on the current hosted `windows-latest` image (Server 2025);
the emulator boots hardware-accelerated in ~3 min.

---------

Co-authored-by: Ignacy Łątka <claude-hubert.gancarczyk@swmansion.com>
Co-authored-by: Ignacy Łątka <latekvo@users.noreply.github.com>
2026-07-22 13:53:32 +02:00
filip131311 5d3f7bc62b fix(ci): check tcp ax-service at its platform-neutral bin/tcp path (#540)
## Problem

Every **Publish prerelease to npm (next)** run on main has failed since
#536 landed (e.g. [run
29897926322](https://github.com/software-mansion/argent/actions/runs/29897926322/job/88851967242)),
blocking canaries — including the canary that would ship the ios-remote
ax-service fix itself.

The failing step is the sanity check:

```
test -x packages/argent/bin/darwin/tcp/ax-service
```

But the binary is fine — the job log right above the failure shows `✓
Copied ax-service (tcp) binary → bin/tcp/ax-service`. The whole pipeline
deliberately uses the **platform-neutral** `bin/tcp/` slot, not
`bin/darwin/tcp/`:

- `scripts/download-native-binaries.sh` writes to `bin/tcp/ax-service`
- `bundle-tools.cjs` copies from/to `bin/tcp/ax-service`
- `axServiceBinaryPathTcp()` / `tcpBinDir()` in `native-devtools-ios`
resolve `bin/tcp` on every host

The neutrality is intentional: the tcp ax-service is a darwin/iOS-sim
binary uploaded to and `simctl spawn`'d on the *remote* macOS
orchestrator, so a Linux host must still resolve it — `bin/linux/tcp`
would never match. Only the sanity checks (and their comments) got the
path wrong.

## Fix

- Point the check in `publish-next.yml` and `publish.yml` at
`packages/argent/bin/tcp/ax-service` (the stable-release workflow had
the identical wrong path and would have failed the same way on the next
release).
- Correct the comment claiming `axServiceBinaryPathTcp()` resolves
`bin/darwin/tcp`.

Note:
`packages/argent-private/.github/workflows/build-native-binaries.yml:549`
has the same stale comment ("download-native-binaries.sh writes it to
bin/darwin/tcp/ax-service") — that lives in the private submodule repo,
so it isn't part of this PR.

## Testing

Verified against the failing run's log (binary lands at
`bin/tcp/ax-service`, check looks in `bin/darwin/tcp/`) and
cross-checked all three path producers/consumers listed above. `grep -rn
'darwin/tcp'` now only matches comments explaining why the path is *not*
used.
2026-07-22 10:21:14 +02:00
Juliusz Wajgelt b90970ffa8 ci: ship TCP-transport iOS binaries in the published package (#487)
## Why

argent's `ios-remote` (sim-remote) support drives **ax-service** and
**native-devtools** over a TCP socket, resolving them from
`bin/darwin/tcp/ax-service` and `dylibs/tcp/*.dylib`. `bundle-tools.cjs`
already stages those into the published package **when present**, but
`download-native-binaries.sh` never fetched them — so
`@swmansion/argent` 0.15.0 shipped with no TCP variant at all, and every
`ios-remote` `describe` / `native-*` call failed with "not found".

## What

- **`download-native-binaries.sh`** — fetch the TCP dylibs tarball into
`dylibs/tcp/` and `tcp-ax-service` into `bin/darwin/tcp/ax-service`
(best-effort: skipped with a warning on pre-sim-remote release tags),
with the same Mach-O platform + codesign verification applied to the
iOS/tvOS assets.
- **`publish.yml` / `publish-next.yml`** — hard `test -x`/`test -f`
gates for the four TCP files so a missing build fails the publish loudly
instead of silently regressing (mirrors the existing tvOS gates).
- **`package.json`** — add `build:ios-binaries:tcp` and wire it into
`pack:mcp:local` so local packs match CI.

`bundle-tools.cjs` needs no change — its `ax-service (tcp)` asset entry
and recursive `dylibs/` copy already handle the `tcp/` slot.

## Verified locally

- `npm pack --dry-run -w @swmansion/argent` now lists
`bin/darwin/tcp/ax-service` +
`dylibs/tcp/{libArgentInjectionBootstrap,libKeyboardPatch,libNativeDevtoolsIos}.dylib`.
- `package-manifest.test.ts` (download↔bundle-tools path agreement) and
`native-devtools-ios/index.test.ts` (TCP path resolution) pass.
- End-to-end against a real sim-remote device: with the TCP binaries in
place, `describe` returns the full ax tree and `native-describe-screen`
/ `native-find-views` / `native-full-hierarchy` all return `status: ok`.

## Paired PR

The producer side — the workflow that builds, signs, and uploads these
TCP release assets — is **software-mansion/argent-private#26**. Both
must land for a release to ship the TCP binaries.

## Known follow-up (out of scope here)

`axServiceBinaryPathTcp()` resolves
`bin/<hostPlatformKey()>/tcp/ax-service`, and `bundle-tools.cjs` stages
the TCP ax-service **darwin-only**. So `describe` via ios-remote works
from a macOS argent host (verified), but a **Linux** host would hit "not
found" at `bin/linux/tcp/`. The TCP dylibs are fine cross-host (flat
`dylibs/tcp/`, un-gated). Full Linux-host support means staging the
darwin TCP ax-service into each host's `tcp/` dir, modeled on the
per-platform `simulator-server` loop — left as a follow-up.
2026-07-10 12:42:47 +02:00
Piotr Krawiec 22ff30acb4 ci(vega-vvd-e2e): build host image on runner, drop prebuilt GHCR image (#445)
## Summary


[`finloop/vega-virtual-device-action`](https://github.com/finloop/vega-virtual-device-action)
shipped a new version that **builds the `vega-virtual-device-host` image
on the consumer runner** from its bundled Dockerfile (cached via the
GitHub Actions cache).

## Changes (`.github/workflows/vega-vvd-e2e.yml`)

- **Re-pin the action** `fe151d9 → a0f1776` ([latest
`main`](https://github.com/finloop/vega-virtual-device-action/commit/a0f17767abafb27ec9b58974d94643fc46a4a35d)).
That commit's bundled Dockerfile carries the latest Vega SDK
(`.sdk-version` = `0.23.8358`), so the image the action builds uses it.
- **Drop the prebuilt SDK image.** Removed the `image:`/`pull:` inputs
and the pinned `HOST_IMAGE` GHCR digest
(`ghcr.io/finloop/vega-virtual-device-host@sha256:2110746…`). With no
`image:`, the action builds the host image locally with the pinned SDK.
Also removed the now-unused `host-image` `workflow_dispatch` input.
2026-07-02 12:33:31 +02:00
Ignacy Łątka c4a9f0bd8a ci: publish a "next" canary on every push to main (#423)
**Update after team discussion:** the open question from the original
version of this PR ("should we fire `next` on every push to main?") got
a yes, so this now does exactly that — continuous canary publishing from
`main`. Original tag-sync wiring is still here too. Branch is merged up
to current `main`.

### what it does

every push to main publishes a canary prerelease under the `next`
dist-tag, so `next` always tracks the tip of main.

- **"Publish prerelease to npm (next)"** now also triggers on `push:
branches: [main]`. on that path it derives a version, stamps it into
`packages/argent/package.json`, and publishes `--tag next`. the manual
`workflow_dispatch` path is untouched (gated behind `if:
github.event_name == 'workflow_dispatch'`).
- **version scheme** = `<patch-bump of the highest published
version>-next.<counter>`. a prerelease of the next patch still outranks
the current `latest` (so `next` lands above it) but stays under the
eventual stable. the **counter resets per base**: next index after the
highest `<base>-next.<k>` already on npm, or 0 if the base has no
canaries yet — so each patch line starts at `.0`:

  ```
  0.13.1-next.0, 0.13.1-next.1, ...   ← latest is 0.13.0
       ... 0.13.1 ships stable ...
  0.13.2-next.0, 0.13.2-next.1, ...   ← counter restarts
  ```

lives in `scripts/next-canary-version.mjs` (+ tests) as a pure function
of the published-versions list, reusing the semver helpers from the sync
script.
- **`argent -v` reports the right thing.** the CLI reads its version
from `package.json` at runtime, so stamping is enough — and there's an
in-pipeline step that runs the built `argent --version` and fails the
publish if it doesn't match the version about to ship. verified
end-to-end against the real registry: computed `0.13.1-next.0`, stamped,
built, `argent --version` → `0.13.1-next.0`.
- **collisions self-heal.** the counter is registry-derived, so canary
publishes are serialized (a `concurrency` group) to kill the concurrent
race; the publish step additionally retries a version-exists collision
(npm read-after-write lag on back-to-back runs) by recomputing. any
other publish failure still fails fast.
- canary builds pull the floating `argent-main` / `radon-main` signed
binaries. sync workflow still fires after every publish (self-heals
`next`, and still does the real work after a *stable* release).

### stuff to sanity-check before merge

- this publishes to npm on **every** merge to main — a lot of versions +
a full build/publish run each time. fine if that's the intent (it's the
whole point), just calling it out.
- **native binaries on the canary path are the floating `argent-main`
tag** — if radon's binary build lags a native-source change on main, a
canary can ship fresh JS against slightly-older signed
dylibs/ax-service/APK with no signal (the *missing* case fails loud +
safe; the *stale* case is silent). there's no per-commit signed-binary
build to pin against, so this is inherent to canary-from-main rather
than something this PR can fix — flagging it as the one real "preview
channel can be skewed" caveat.
- during a rapid burst of merges, GitHub's concurrency supersedes
intermediate queued runs — published `-next.N` stay contiguous from 0,
but not literally every commit in a burst gets its own canary.
- like any push trigger, it only goes live once this is on main.
2026-07-01 18:01:53 +02:00
Mateusz Ścianek b8afbed183 feat(tv): Apple TV (tvOS) and Android TV support (#374)
Adds end-to-end support for driving **Apple TV (tvOS)** and **Android TV
(leanback)** targets through argent, using a focus-driven interaction
model (TVs have no touchscreen — interaction is moving a focus highlight
with the remote).

This PR was reworked after review to **reuse the existing cross-platform
tool surface and the `tv-remote` tool from the Vega/Fire TV work
(#366)** rather than ship a separate family of `tv-*` tools.

## What this delivers

TV targets are driven by the **same cross-platform tools as every other
platform**, routed through the existing `dispatchByPlatform` fork
mechanism — there are no dedicated
`tv-describe`/`tv-navigate`/`tv-type`/`tv-set-focus` tools:

- **`describe`** — on a `runtimeKind: "tv"` target, returns the
focus-driven view (focused + focusable elements) instead of a tap tree.
On Android TV it auto-falls-back to the full `uiautomator` tree when the
RN focus engine exposes nothing.
- **`tv-remote`** — the cross-platform remote/D-pad tool from #366, now
extended with `ios` (Apple TV HID daemon) and `android` (Android TV adb
keyevents) branches alongside the existing `vega` branch. Single button,
a `repeat`, or a whole path (`["up","right","select"]`) in one call.
- **`keyboard`** — types into the focused field on a TV target (named
keys are rejected there — they're navigation, which belongs to
`tv-remote`).
- **`button`** stays hardware-only (phones/tablets); it is not a TV
tool.

**Apple TV** runs two native daemons (in-sim AX service + host-side HID
daemon), shipped via the `argent-private` submodule. **Android TV**
reuses the same tool surface, adb-backed (`input keyevent`, `uiautomator
dump`, `input text`).

## Remote vocabulary parity

`tv-remote` exposes the full 16-button vocabulary
(`up`/`down`/`left`/`right`/`select`/`back`/`home`/`menu`/`playPause`/`rewind`/`fastForward`/`next`/`previous`/`volumeUp`/`volumeDown`/`mute`):

| | Apple TV | Android TV | Vega |
|---|---|---|---|
| D-pad / select / back / menu / home / playPause | ✅ | ✅ | ✅ |
| media-transport + volume/mute | ❌ rejected | ✅ | ✅ |

Media-transport/volume keys **genuinely work on Android TV** (real
keycodes — verified live: `volumeUp` moved `STREAM_MUSIC`, `mute`
toggled per `dumpsys audio`). On the **Apple TV simulator** they are
**rejected with a clear error**: on-device testing confirmed the tvOS
sim's HID stack silently drops Consumer-Control events, so returning
success would be a lie.

## Key design points
- **tvOS UDIDs are UUID-shaped and indistinguishable from iOS by
shape.** Handled with `runtimeKind` detection (tvOS runtime string for
Apple TV; `pm list features` leanback/television for Android TV — *not*
`ro.build.characteristics`, which lies on TV emulators).
- Converted launch-app / restart-app / screenshot / screenshot-diff /
run-sequence from **eager** to **lazy** service resolution, so a tvOS
target never spins up (and hangs on) the iOS-only simulator-server /
native-devtools blueprints.
- Native injection selects the platform-matched (TVOSSIMULATOR) dylib
slice; daemons recycle across sim reboots and app relaunches so
injection and focus survive.
- SKILL.md footprint minimized per review: the two TV skills were
collapsed into a single lean **`argent-tv-interact`** (~40 lines).

## Verification
- `npm run build`, ESLint, Prettier, and the full tool-server suite
(**1565 tests**) all pass; CI green (incl. the Apple TV / Android TV /
Vega e2e jobs).
- Core flows verified live against real apps on both an Apple TV 4K
simulator and a Google ATV emulator.

## Dependency / merge order
Pins the `argent-private` submodule to the tip of its `feat/tv-support`
branch (software-mansion/argent-private#20). **Merge that PR to `main`
first, then bump the submodule pointer here to the merged SHA before
merging this PR.**

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 14:59:37 +02:00
Ignacy Łątka 05e619e55d ci: device E2E smoke tests for every hosted-CI platform (#371)
## What

`wayland-e2e.yml` boots an Android AVD on Linux under headless Weston
and asserts the full pipeline works without a display. It guards exactly
one cell of the support matrix. This adds the same
boot→screenshot→gesture-tap smoke test for every other (target × host)
cell that can run on GitHub-hosted runners.

| target | host | job | status |
|---|---|---|---|
| Android emulator | Linux (KVM) | `wayland-e2e.yml` (existing) | ✅ |
| iOS simulator | macOS | `ios-sim-macos` | ✅ |
| Chromium / Electron | Linux (Xvfb) | `chromium-linux` | ✅ |
| Chromium / Electron | macOS | `chromium-macos` | ✅ |

## How

- **`scripts/e2e/drive-device.sh`** — shared driver. Boots one device
through the tool-server, then asserts `booted:true` → screenshot has
real (non-blank) pixels → `gesture-tap` round-trips. Every tool takes
the device id as `udid` and screenshots come back as the same
`data.image.hostPath` envelope on all platforms, so the body is uniform;
each job just supplies the cell-specific boot JSON + device id.
- **`packages/tool-server/test/fixtures/electron-smoke-app/`** — minimal
self-contained Electron app the Chromium jobs point `electronAppPath`
at. It vendors its own electron via its own lockfile (kept out of the
repo root lockfile); CI `npm ci`s it so `boot-electron` resolves
`./node_modules/.bin/electron`.
- **`.github/workflows/e2e-device-smoke.yml`** — three jobs,
`workflow_dispatch` + path-filtered `pull_request`. iOS downloads the
darwin native binaries (injection must succeed for `bootIos` to report
`booted:true`); Chromium-Linux runs under Xvfb with `--no-sandbox`. The
tool-server is started with `TS_NODE_TRANSPILE_ONLY=1` so cold ts-node
startup doesn't flakily exceed the readiness poll on loaded macOS
runners (types are still enforced by the typecheck job).

## Known gaps (supported on real machines, not runnable on hosted
runners)

- **Android emulator on macOS** — the arm64 emulator needs HVF
(`-enable-hvf`), but hosted macOS runners are themselves VMs with no
nested virtualization. Confirmed by running it: qemu dies with `HVF
error: HV_UNSUPPORTED` ~18s into boot, regardless of GPU mode or RAM.
The Android boot/screenshot/tap path is already regression-guarded on
Linux via KVM (`wayland-e2e.yml`), so macOS adds no runnable coverage.
- **Physical devices** — real iOS (CoreDevice HID) and real Android
(adb-USB) have no attached hardware on hosted runners.

Both would need self-hosted runners (a Mac exposing HVF / wired-up
devices). Documented in the workflow header.

## Verification

- All checks green: the 3 device jobs + ESLint + Prettier + Unit tests.
- Locally (before CI): ran `drive-device.sh` end-to-end against a real
tool-server → boot `booted:true`, screenshot **142 KB** (floor 20 KB),
tap `tapped:true`, exit 0; and confirmed via the Argent stack that a tap
at (0.5, 0.5) lands on the fixture's centered button and increments its
counter.
2026-06-26 17:44:17 +02:00
dependabot[bot] a5902e3186 chore(ci)(deps): bump the github-actions group across 1 directory with 4 updates (#403)
Bumps the github-actions group with 4 updates in the / directory:
[actions/checkout](https://github.com/actions/checkout),
[actions/setup-node](https://github.com/actions/setup-node),
[actions/upload-artifact](https://github.com/actions/upload-artifact)
and
[finloop/vega-virtual-device-action](https://github.com/finloop/vega-virtual-device-action).

Updates `actions/checkout` from 4 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/releases">actions/checkout's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>block checking out fork pr for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
<li>getting ready for checkout v7 release by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2464">actions/checkout#2464</a></li>
<li>update error wording by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2467">actions/checkout#2467</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> made
their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.3...v7.0.0">https://github.com/actions/checkout/compare/v6.0.3...v7.0.0</a></p>
<h2>v6.0.3</h2>
<h2>What's Changed</h2>
<ul>
<li>Update changelog by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2357">actions/checkout#2357</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>Update changelog for v6.0.3 by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2446">actions/checkout#2446</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/yaananth"><code>@​yaananth</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.3">https://github.com/actions/checkout/compare/v6...v6.0.3</a></p>
<h2>v6.0.2</h2>
<h2>What's Changed</h2>
<ul>
<li>Add orchestration_id to git user-agent when ACTIONS_ORCHESTRATION_ID
is set by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2355">actions/checkout#2355</a></li>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6.0.1...v6.0.2">https://github.com/actions/checkout/compare/v6.0.1...v6.0.2</a></p>
<h2>v6.0.1</h2>
<h2>What's Changed</h2>
<ul>
<li>Update all references from v5 and v4 to v6 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2314">actions/checkout#2314</a></li>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
<li>Clarify v6 README by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2328">actions/checkout#2328</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/checkout/compare/v6...v6.0.1">https://github.com/actions/checkout/compare/v6...v6.0.1</a></p>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<ul>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>v6-beta by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2298">actions/checkout#2298</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/checkout/blob/main/CHANGELOG.md">actions/checkout's
changelog</a>.</em></p>
<blockquote>
<h1>Changelog</h1>
<h2>v7.0.0</h2>
<ul>
<li>Block checking out fork PR for pull_request_target and workflow_run
by <a href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2454">actions/checkout#2454</a></li>
<li>Bump actions/publish-immutable-action from 0.0.3 to 0.0.4 in the
minor-actions-dependencies group across 1 directory by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2458">actions/checkout#2458</a></li>
<li>Bump flatted from 3.3.1 to 3.4.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2460">actions/checkout#2460</a></li>
<li>Bump js-yaml from 4.1.0 to 4.2.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2461">actions/checkout#2461</a></li>
<li>Bump <code>@​actions/core</code> and
<code>@​actions/tool-cache</code> and Remove uuid by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2459">actions/checkout#2459</a></li>
<li>upgrade module to esm and update dependencies by <a
href="https://github.com/aiqiaoy"><code>@​aiqiaoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2463">actions/checkout#2463</a></li>
<li>Bump the minor-npm-dependencies group across 1 directory with 3
updates by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/checkout/pull/2462">actions/checkout#2462</a></li>
</ul>
<h2>v6.0.3</h2>
<ul>
<li>Fix checkout init for SHA-256 repositories by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2439">actions/checkout#2439</a></li>
<li>fix: expand merge commit SHA regex and add SHA-256 test cases by <a
href="https://github.com/yaananth"><code>@​yaananth</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2414">actions/checkout#2414</a></li>
</ul>
<h2>v6.0.2</h2>
<ul>
<li>Fix tag handling: preserve annotations and explicit fetch-tags by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2356">actions/checkout#2356</a></li>
</ul>
<h2>v6.0.1</h2>
<ul>
<li>Add worktree support for persist-credentials includeIf by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2327">actions/checkout#2327</a></li>
</ul>
<h2>v6.0.0</h2>
<ul>
<li>Persist creds to a separate file by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2286">actions/checkout#2286</a></li>
<li>Update README to include Node.js 24 support details and requirements
by <a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2248">actions/checkout#2248</a></li>
</ul>
<h2>v5.0.1</h2>
<ul>
<li>Port v6 cleanup to v5 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2301">actions/checkout#2301</a></li>
</ul>
<h2>v5.0.0</h2>
<ul>
<li>Update actions checkout to use node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2226">actions/checkout#2226</a></li>
</ul>
<h2>v4.3.1</h2>
<ul>
<li>Port v6 cleanup to v4 by <a
href="https://github.com/ericsciple"><code>@​ericsciple</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2305">actions/checkout#2305</a></li>
</ul>
<h2>v4.3.0</h2>
<ul>
<li>docs: update README.md by <a
href="https://github.com/motss"><code>@​motss</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1971">actions/checkout#1971</a></li>
<li>Add internal repos for checking out multiple repositories by <a
href="https://github.com/mouismail"><code>@​mouismail</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1977">actions/checkout#1977</a></li>
<li>Documentation update - add recommended permissions to Readme by <a
href="https://github.com/benwells"><code>@​benwells</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2043">actions/checkout#2043</a></li>
<li>Adjust positioning of user email note and permissions heading by <a
href="https://github.com/joshmgross"><code>@​joshmgross</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2044">actions/checkout#2044</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2194">actions/checkout#2194</a></li>
<li>Update CODEOWNERS for actions by <a
href="https://github.com/TingluoHuang"><code>@​TingluoHuang</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/2224">actions/checkout#2224</a></li>
<li>Update package dependencies by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/2236">actions/checkout#2236</a></li>
</ul>
<h2>v4.2.2</h2>
<ul>
<li><code>url-helper.ts</code> now leverages well-known environment
variables by <a href="https://github.com/jww3"><code>@​jww3</code></a>
in <a
href="https://redirect.github.com/actions/checkout/pull/1941">actions/checkout#1941</a></li>
<li>Expand unit test coverage for <code>isGhes</code> by <a
href="https://github.com/jww3"><code>@​jww3</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1946">actions/checkout#1946</a></li>
</ul>
<h2>v4.2.1</h2>
<ul>
<li>Check out other refs/* by commit if provided, fall back to ref by <a
href="https://github.com/orhantoy"><code>@​orhantoy</code></a> in <a
href="https://redirect.github.com/actions/checkout/pull/1924">actions/checkout#1924</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/checkout/commit/9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0"><code>9c091bb</code></a>
update error wording (<a
href="https://redirect.github.com/actions/checkout/issues/2467">#2467</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/1044a6dea927916f2c38ba5aeffbc0a847b1221a"><code>1044a6d</code></a>
getting ready for checkout v7 release (<a
href="https://redirect.github.com/actions/checkout/issues/2464">#2464</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/f0282184c7ce73ab54c7e4ab5a617122602e575f"><code>f028218</code></a>
Bump the minor-npm-dependencies group across 1 directory with 3 updates
(<a
href="https://redirect.github.com/actions/checkout/issues/2462">#2462</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/d914b262ffc244530a203ab40decab34c3abf34d"><code>d914b26</code></a>
upgrade module to esm and update dependencies (<a
href="https://redirect.github.com/actions/checkout/issues/2463">#2463</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/537c7ef99cef6e5ddb5e7ff5d16d14510503801d"><code>537c7ef</code></a>
Bump <code>@​actions/core</code> and <code>@​actions/tool-cache</code>
and Remove uuid (<a
href="https://redirect.github.com/actions/checkout/issues/2459">#2459</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/130a169078a413d3a5246a393625e8e742f387f6"><code>130a169</code></a>
Bump js-yaml from 4.1.0 to 4.2.0 (<a
href="https://redirect.github.com/actions/checkout/issues/2461">#2461</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/7d09575332117a40b46e5e020664df234cd416f3"><code>7d09575</code></a>
Bump flatted from 3.3.1 to 3.4.2 (<a
href="https://redirect.github.com/actions/checkout/issues/2460">#2460</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/0f9f3aa320cb53abeb534aeb54048075d9697a0e"><code>0f9f3aa</code></a>
Bump actions/publish-immutable-action (<a
href="https://redirect.github.com/actions/checkout/issues/2458">#2458</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/f9e715a95fcd1f9253f77dd28f11e88d2d6460c7"><code>f9e715a</code></a>
block checking out fork pr for pull_request_target and workflow_run (<a
href="https://redirect.github.com/actions/checkout/issues/2454">#2454</a>)</li>
<li><a
href="https://github.com/actions/checkout/commit/df4cb1c069e1874edd31b4311f1884172cec0e10"><code>df4cb1c</code></a>
Update changelog for v6.0.3 (<a
href="https://redirect.github.com/actions/checkout/issues/2446">#2446</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/checkout/compare/v4...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/setup-node` from 4 to 6
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-node/releases">actions/setup-node's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>What's Changed</h2>
<p><strong>Breaking Changes</strong></p>
<ul>
<li>Limit automatic caching to npm, update workflows and documentation
by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1374">actions/setup-node#1374</a></li>
</ul>
<p><strong>Dependency Upgrades</strong></p>
<ul>
<li>Upgrade ts-jest from 29.1.2 to 29.4.1 and document breaking changes
in v5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1336">#1336</a></li>
<li>Upgrade prettier from 2.8.8 to 3.6.2 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1334">#1334</a></li>
<li>Upgrade actions/publish-action from 0.3.0 to 0.4.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1362">#1362</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v5...v6.0.0">https://github.com/actions/setup-node/compare/v5...v6.0.0</a></p>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<h3>Breaking Changes</h3>
<ul>
<li>Enhance caching in setup-node with automatic package manager
detection by <a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
in <a
href="https://redirect.github.com/actions/setup-node/pull/1348">actions/setup-node#1348</a></li>
</ul>
<p>This update, introduces automatic caching when a valid
<code>packageManager</code> field is present in your
<code>package.json</code>. This aims to improve workflow performance and
make dependency management more seamless.
To disable this automatic caching, set <code>package-manager-cache:
false</code></p>
<pre lang="yaml"><code>steps:
- uses: actions/checkout@v5
- uses: actions/setup-node@v5
  with:
    package-manager-cache: false
</code></pre>
<ul>
<li>Upgrade action to use node24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/setup-node/pull/1325">actions/setup-node#1325</a></li>
</ul>
<p>Make sure your runner is on version v2.327.1 or later to ensure
compatibility with this release. <a
href="https://github.com/actions/runner/releases/tag/v2.327.1">See
Release Notes</a></p>
<h3>Dependency Upgrades</h3>
<ul>
<li>Upgrade <code>@​octokit/request-error</code> and
<code>@​actions/github</code> by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1227">actions/setup-node#1227</a></li>
<li>Upgrade uuid from 9.0.1 to 11.1.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1273">actions/setup-node#1273</a></li>
<li>Upgrade undici from 5.28.5 to 5.29.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1295">actions/setup-node#1295</a></li>
<li>Upgrade form-data to bring in fix for critical vulnerability by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-node/pull/1332">actions/setup-node#1332</a></li>
<li>Upgrade actions/checkout from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-node/pull/1345">actions/setup-node#1345</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/priya-kinthali"><code>@​priya-kinthali</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1348">actions/setup-node#1348</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-node/pull/1325">actions/setup-node#1325</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-node/compare/v4...v5.0.0">https://github.com/actions/setup-node/compare/v4...v5.0.0</a></p>
<h2>v4.4.0</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-node/commit/48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e"><code>48b55a0</code></a>
Update Node.js versions in versions.yml and bump package to v6.4.0 (<a
href="https://redirect.github.com/actions/setup-node/issues/1533">#1533</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/ab72c7e7eba0eaa11f8cab0f5679243900c2cac9"><code>ab72c7e</code></a>
Upgrade <a href="https://github.com/actions"><code>@​actions</code></a>
dependencies (<a
href="https://redirect.github.com/actions/setup-node/issues/1525">#1525</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/53b83947a5a98c8d113130e565377fae1a50d02f"><code>53b8394</code></a>
Bump minimatch from 3.1.2 to 3.1.5 (<a
href="https://redirect.github.com/actions/setup-node/issues/1498">#1498</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/54045abd5dcd3b0fee9ca02fa24c57545834c9cc"><code>54045ab</code></a>
Scope test lockfiles by package manager and update cache tests (<a
href="https://redirect.github.com/actions/setup-node/issues/1495">#1495</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/c882bffdbd4df51ace6b940023952e8669c9932a"><code>c882bff</code></a>
Replace uuid with crypto.randomUUID() (<a
href="https://redirect.github.com/actions/setup-node/issues/1378">#1378</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/774c1d62961e73038a114d59c8847023c003194d"><code>774c1d6</code></a>
feat(node-version-file): support parsing <code>devEngines</code> field
(<a
href="https://redirect.github.com/actions/setup-node/issues/1283">#1283</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/efcb663fc60e97218a2b2d6d827f7830f164739e"><code>efcb663</code></a>
fix: remove hardcoded bearer (<a
href="https://redirect.github.com/actions/setup-node/issues/1467">#1467</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/d02c89dce7e1ba9ef629ce0680989b3a1cc72edb"><code>d02c89d</code></a>
Fix npm audit issues (<a
href="https://redirect.github.com/actions/setup-node/issues/1491">#1491</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/6044e13b5dc448c55e2357c09f80417699197238"><code>6044e13</code></a>
Docs: bump actions/checkout from v5 to v6 (<a
href="https://redirect.github.com/actions/setup-node/issues/1468">#1468</a>)</li>
<li><a
href="https://github.com/actions/setup-node/commit/8e494633d082d609d1e9ff931be32f8a44f1f657"><code>8e49463</code></a>
Fix README typo (<a
href="https://redirect.github.com/actions/setup-node/issues/1226">#1226</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-node/compare/v4...v6">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/upload-artifact` from 4 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>v7 What's new</h2>
<h3>Direct Uploads</h3>
<p>Adds support for uploading single files directly (unzipped). Callers
can set the new <code>archive</code> parameter to <code>false</code> to
skip zipping the file during upload. Right now, we only support single
files. The action will fail if the glob passed resolves to multiple
files. The <code>name</code> parameter is also ignored with this
setting. Instead, the name of the artifact will be the name of the
uploaded file.</p>
<h3>ESM</h3>
<p>To support new versions of the <code>@actions/*</code> packages,
we've upgraded the package to ESM.</p>
<h2>What's Changed</h2>
<ul>
<li>Add proxy integration test by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
<li>Upgrade the module to ESM and bump dependencies by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/762">actions/upload-artifact#762</a></li>
<li>Support direct file uploads by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/764">actions/upload-artifact#764</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Link"><code>@​Link</code></a>- made
their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v6...v7.0.0">https://github.com/actions/upload-artifact/compare/v6...v7.0.0</a></p>
<h2>v6.0.0</h2>
<h2>v6 - What's new</h2>
<blockquote>
<p>[!IMPORTANT]
actions/upload-artifact@v6 now runs on Node.js 24 (<code>runs.using:
node24</code>) and requires a minimum Actions Runner version of 2.327.1.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<h3>Node.js 24</h3>
<p>This release updates the runtime to Node.js 24. v5 had preliminary
support for Node.js 24, however this action was by default still running
on Node.js 20. Now this action by default will run on Node.js 24.</p>
<h2>What's Changed</h2>
<ul>
<li>Upload Artifact Node 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/719">actions/upload-artifact#719</a></li>
<li>fix: update <code>@​actions/artifact</code> for Node.js 24 punycode
deprecation by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/744">actions/upload-artifact#744</a></li>
<li>prepare release v6.0.0 for Node.js 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/745">actions/upload-artifact#745</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0">https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0</a></p>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<p><strong>BREAKING CHANGE:</strong> this update supports Node
<code>v24.x</code>. This is not a breaking change per-se but we're
treating it as such.</p>
<ul>
<li>Update README.md by <a
href="https://github.com/GhadimiR"><code>@​GhadimiR</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/681">actions/upload-artifact#681</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/712">actions/upload-artifact#712</a></li>
<li>Readme: spell out the first use of GHES by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/727">actions/upload-artifact#727</a></li>
<li>Update GHES guidance to include reference to Node 20 version by <a
href="https://github.com/patrikpolyak"><code>@​patrikpolyak</code></a>
in <a
href="https://redirect.github.com/actions/upload-artifact/pull/725">actions/upload-artifact#725</a></li>
<li>Bump <code>@actions/artifact</code> to <code>v4.0.0</code></li>
<li>Prepare <code>v5.0.0</code> by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/734">actions/upload-artifact#734</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a"><code>043fb46</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/797">#797</a>
from actions/yacaovsnc/update-dependency</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/634250c1388765ea7ed0f053e636f1f399000b94"><code>634250c</code></a>
Include changes in typespec/ts-http-runtime 0.3.5</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/e454baaac2be505c9450e11b8f3215c6fc023ce8"><code>e454baa</code></a>
Readme: bump all the example versions to v7 (<a
href="https://redirect.github.com/actions/upload-artifact/issues/796">#796</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/74fad66b98a6d799dc004d3353ccd0e6f6b2530e"><code>74fad66</code></a>
Update the readme with direct upload details (<a
href="https://redirect.github.com/actions/upload-artifact/issues/795">#795</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f"><code>bbbca2d</code></a>
Support direct file uploads (<a
href="https://redirect.github.com/actions/upload-artifact/issues/764">#764</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/589182c5a4cec8920b8c1bce3e2fab1c97a02296"><code>589182c</code></a>
Upgrade the module to ESM and bump dependencies (<a
href="https://redirect.github.com/actions/upload-artifact/issues/762">#762</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/47309c993abb98030a35d55ef7ff34b7fa1074b5"><code>47309c9</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/754">#754</a>
from actions/Link-/add-proxy-integration-tests</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/02a8460834e70dab0ce194c64360c59dc1475ef0"><code>02a8460</code></a>
Add proxy integration test</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/b7c566a772e6b6bfb58ed0dc250532a479d7789f"><code>b7c566a</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/745">#745</a>
from actions/upload-artifact-v6-release</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/e516bc8500aaf3d07d591fcd4ae6ab5f9c391d5b"><code>e516bc8</code></a>
docs: correct description of Node.js 24 support in README</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/upload-artifact/compare/v4...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `finloop/vega-virtual-device-action` from
ed210f760d5aec5cd3f7e54e1529d353b4e66a11 to
fe151d9a807b64e2838080e16a9ff2ea55ee48f6
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/finloop/vega-virtual-device-action/commit/fe151d9a807b64e2838080e16a9ff2ea55ee48f6"><code>fe151d9</code></a>
Merge pull request <a
href="https://redirect.github.com/finloop/vega-virtual-device-action/issues/18">#18</a>
from finloop/claude/stupefied-easley-603dfc</li>
<li><a
href="https://github.com/finloop/vega-virtual-device-action/commit/f1cea162e668d824e70110b1bd791eb17824dcf2"><code>f1cea16</code></a>
Bump Vega SDK 0.22.6759 -&gt; 0.23.8128</li>
<li>See full diff in <a
href="https://github.com/finloop/vega-virtual-device-action/compare/ed210f760d5aec5cd3f7e54e1529d353b4e66a11...fe151d9a807b64e2838080e16a9ff2ea55ee48f6">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-06-26 17:40:38 +02:00
Ignacy Łątka 10ecc9e53d fix(release): auto-sync the npm 'next' dist-tag to the highest published version (#357)
Auto-sync the npm `next` dist-tag to the highest published version (prerelease or stable) so it stops drifting behind `latest`.

- New dependency-free `scripts/sync-next-dist-tag.mjs` (SemVer comparator verified against the `semver` lib in `scripts/sync-next-dist-tag.test.mjs`).
- Runs as a post-publish step in `publish.yml` and `publish-next.yml` (with `continue-on-error` so a transient registry blip never fails an already-successful release), plus a manual `Sync 'next' dist-tag` workflow with a dry-run toggle.
- Only ever advances `next` (never regresses it) to survive a stale post-publish packument read.
- Package-name arg parsing rejects flag/blank tokens so the scoped `@swmansion/argent` default reliably wins.
2026-06-24 12:29:45 +02:00
Piotr Krawiec 0bed3624a0 feat(vega): Amazon Vega (Fire TV) platform support (#366)
## Summary

Adds **Vega (Amazon Fire TV)** as a third Argent platform alongside iOS
and Android. Vega apps are React Native 0.72 + Hermes running on a QEMU
**Virtual Device (VVD)**, driven by a **D-pad tv-remote rather than
touch**. This PR extends Argent's platform abstraction so the existing
tool surface gates correctly on `vega`, and adds the Vega-specific tools
needed to actually drive a Fire TV app end to end.

### Platform abstraction

- `Platform` gains `vega`; `DeviceKind` gains `vvd` (the QEMU VVD);
`ToolCapability` gains a `vega { vvd, device }` block; `ToolDependency`
gains `vega`.
- `assertSupported()` selects the `vega` capability matrix for Vega
devices; `dispatchByPlatform()` gains an optional `vega` branch, and a
Vega dispatch with no branch throws `NotImplementedOnPlatformError`
(501).
- New `vega-cli` util (modeled on `adb.ts`) resolves `vega`/`kepler`
from `PATH` or `~/vega/bin` with the same hardened exec/quoting;
`check-deps` resolves and hints the `vega` dependency.
- The `simulator-server` blueprint is never wired for `vega` (Vega uses
`adb` + the `vega`/`kepler` CLI, not the proprietary binary).

### How Vega is wired

- **Input / screenshot / describe** go over `adb` (input via
`inputd-cli`, screenshots host-side via the Android emulator console,
element tree via the on-device automation toolkit).
- **App lifecycle** goes over the `vega`/`kepler` CLI.
- v1 is **Virtual-Device-only**: every Vega capability is declared
`vvd`. Physical Fire TV is out of scope and untested — the tool-server
does not connect to or detect hardware, so `resolveDevice` classifies
every `amazon-` serial as a VVD by shape. A physical device is therefore
not classified as `device` and not rejected at the capability gate;
supporting and gating real hardware is deferred to a version where it
can be tested.
- Vega runs **React Native 0.72**, which predates the new React Native
DevTools. The CDP/Hermes debugger surface (`debugger-*`, React/native
profilers) depends on integration points the new DevTools provides, so
**debugging and profiling are out of scope for this PR** — Vega
profiling/crash analysis is handled by the
`amazon-devices-buildertools-mcp` server instead.

### Also includes

- `argent-vega` skill documenting the full Vega workflow (target
discovery, the describe → compute-path → `tv-remote` navigation loop,
text injection).
- Vega VVD end-to-end CI workflow.

## Feature support by platform

Legend: ✅ supported · ❌ not supported · ⚠️ degraded / conditional · —
not applicable

| Feature (tool) | iOS | Android | Chromium | **Vega (VVD)** | Vega
notes |
|---|:---:|:---:|:---:|:---:|---|
| **Device discovery** (`list-devices`) | ✅ | ✅ | ✅ | **✅** | Tagged
`platform:"vega"`, `kind:"vvd"`; pass `serial` as `udid` |
| **Boot / start device** | ✅ | ✅ | — | ✅ |  |
| **Launch app** (`launch-app`) | ✅ | ✅ | ✅ | **✅** | `bundleId` =
interactive-component app id from `manifest.toml` |
| **Restart app** (`restart-app`) | ✅ | ✅ | ✅ | **✅** | Terminate +
relaunch |
| **Reinstall app** (`reinstall-app`) | ✅ | ✅ | ❌ | **✅** | Uninstall +
install a `.vpkg` |
| **Screenshot** (`screenshot`) | ✅ | ✅ | ✅ | **✅** | Host-side via
emulator console (needs `adb`); rotation ignored (fixed landscape) |
| **Describe / element tree** (`describe`) | ✅ | ✅ | ✅ | **✅** |
On-device automation toolkit; surfaces `[focused]`/`[selected]` +
normalized frames |
| **Touch gestures** (`gesture-tap`/`swipe`/`scroll`/`drag`/`custom`) |
✅ | ✅ | ✅ | **❌** | Vega is tv-remote-driven; gestures error — use
`tv-remote` |
| **Pinch / rotate gesture** (`gesture-pinch`/`gesture-rotate`) | ✅ | ❌
| ⚠️ | **❌** | N/A on a TV |
| **Remote / D-pad** (`tv-remote`) | — | — | — | **✅** | Vega-only tool;
single key, repeat, or a whole path in one call |
| **Hardware buttons** (`button`) | ✅ | ✅ | — | **❌** | Remote keys live
in `remote` instead |
| **Text input** (`keyboard`) | ✅ | ✅ | ✅ | **✅** | Whole-string
injection via `inputd-cli send_text` |
| **Rotate orientation** (`rotate`) | ✅ | ✅ | — | **❌** | TV framebuffer
is fixed landscape |
| **Open URL / deep link** (`open-url`) | ✅ | ✅ | ✅ | **❌** | Not wired
on Vega |
| **JS debugger** (`debugger-*`) | ✅ | ✅ | ✅ | **❌** | RN 0.72 predates
the new RN DevTools — out of scope for this PR |
| **Native devtools / AX** (`native-describe-screen`, etc.) | ✅ | ❌ | —
| **❌** | iOS-only |
| **Native profiler** (`native-profiler-*`) | ✅ | ✅ | — | **❌** | Use
`amazon-devices-buildertools-mcp` (Perfetto) instead |
| **React profiler** (`react-profiler-*`) | ✅ | ✅ | — | **❌** | Out of
scope; RN 0.72 / new RN DevTools not supported |
| **Screenshot diff** (`screenshot-diff`) | ✅ | ✅ | ✅ | **✅** |
Host-side image comparison; platform-agnostic |
| **Flows record/replay** (`flow-*`) | ✅ | ✅ | ✅ | **✅** | Records any
tool-call sequence |

## Test plan

- [x] `list-devices` surfaces connected Vega devices (`platform:"vega"`,
`kind:"vvd"`)
- [x] `launch-app`, `restart-app`, `reinstall-app`,
`list-installed-apps` work on Vega
- [x] `tv-remote` drives focus (single key, `repeat`, and multi-key
path) and `keyboard` injects whole strings
- [x] `screenshot` returns a frame via the host-side VVD path
- [x] `describe` returns the on-screen element tree with `[focused]`
state and normalized coordinates
- [x] Vega VVD e2e CI workflow passes
- [ ] Test multiple platforms being driven at the same time
    - [x] Android + Vega
    - [ ] iOS + Vega
    - [ ] chrome + Vega

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 20:31:45 +02:00
Ignacy Łątka b165bc39ee ci(wayland-e2e): poll for a warm screenshot instead of a single fixed sleep (#379)
## Problem

The **Boot + drive AVD on headless Weston** job's *"Screenshot returns
real pixels"* step takes a single screenshot 15s after `boot_completed`
and asserts it is > 20 KB. That single shot races **two** independent
warm-up delays:

1. SurfaceFlinger painting the lockscreen UI, and
2. the simulator-server's screenshot stream, which only starts warming
on the **first capture request**.

On slow/contended runners the one-and-only capture comes back as either:
- `{"error":"...no image to export"}` — a cold stream, response has no
`.data` envelope, so the step's `json.load(...)['data']` raises
`KeyError: 'data'`; or
- an all-zero framebuffer that PNG-compresses to ~3–7 KB and fails the
`> 20 KB` check.

Either way the step fails even though the boot was healthy. This is
intermittent — the same commit passes most runs and fails some.

## Fix

Replace the single fixed `sleep 15` + one capture with a **bounded
poll** (15 attempts, 4s apart). Each request also warms the stream, and
the loop exits as soon as a frame exceeds 20 KB. A cold-stream error
response is tolerated and retried rather than aborting the step.
Genuinely broken framebuffers still fail, now with per-attempt
diagnostics in the log.

- Healthy boots pass in the first attempt or two (no slower than before
in the common case).
- Worst-case added headroom is ~60s, only spent when the framebuffer
never warms — which is a real failure worth surfacing.

## Verification

The workflow file is unchanged elsewhere; only this step's `run:` script
changed.

- `prettier --check` passes on the workflow file.
- Extracted the exact `run:` script and ran it against a mock `curl`
covering: cold-error → all-zero frame → real frame (exits 0 on the real
frame); always-cold (exits 1 after 15 attempts); always all-zero
framebuffer (exits 1). Exit codes confirmed 0 / 1 respectively.
2026-06-22 13:30:54 +02:00
Ignacy Łątka dc0930d50c ci: prevent package-lock drift + add repo-hygiene checks (#362)
## Why

We hit a mismatch between a locally-generated `package-lock.json` and
the one on `main`. `npm ci` validates the lockfile loosely and accepts a
stale lock that a fresh `npm install` would rewrite, so the drift
slipped through. This adds CI to catch that, plus a few related
common-mistake guards.

## What

**`Lockfile` workflow** (Node 20) — runs `npm install
--package-lock-only --ignore-scripts` and fails if `package-lock.json`
changes. This is the gap `npm ci` leaves: it asserts the lock is exactly
what npm produces, not merely "consistent enough".

**`Repo Hygiene` workflow** — three fast static guards:
- **Merge-conflict markers** — fail on any `<<<<<<<` / `=======` /
`>>>>>>>` left in a tracked file.
- **Focused tests** — fail on `describe/it/test/bench.only` in
`*.test.ts(x)` / `*.spec.ts(x)`. Uses a POSIX-ERE word-boundary pattern
so it actually fires under `git grep -E` (a `\b` pattern silently
matches nothing there).
- **Workspace version sync** — fail when `packages/*` versions drift,
via `scripts/check-workspace-versions.mjs` (also `npm run
check:versions`).

To make versions consistent, `@argent/ui` is bumped `0.0.1 → 0.12.0` (it
is `private`, so no publish impact).

## Verification (Node 20 / npm 10.8.2, matching CI)

- Lockfile check: no false positive on `main`; idempotent; catches a
tampered lock.
- Merge-marker & `.only` greps: proven to catch real violations and
reject lookalikes (`await.only`, `audit.only`, `foo.it.only`); clean
across the repo.
- `check-workspace-versions.mjs`: reports all packages at `0.12.0`;
passes `eslint` and `typecheck:scripts`.
- All new/changed files pass `prettier --check`; both workflow YAMLs
parse.

## Note: npm version coupling

The check runs on Node 20 (npm 10.8.2), matching the committed lock's
format. npm 11 (Node 24) regenerates the same lock minus cosmetic
`"peer": true` markers — no resolution change, but a contributor who
regenerates on npm 11 would trip the strict diff. The repo pins no
toolchain today (CI mixes Node 20 and 24). Pinning npm/Node repo-wide
would fully close this; left out of scope here — happy to add it as a
follow-up.
2026-06-19 15:19:19 +02:00
dependabot[bot] b02ad64527 chore(ci)(deps): bump the github-actions group across 1 directory with 2 updates (#309)
Bumps the github-actions group with 2 updates in the / directory:
[actions/upload-artifact](https://github.com/actions/upload-artifact)
and [actions/setup-java](https://github.com/actions/setup-java).

Updates `actions/upload-artifact` from 4 to 7
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v7.0.0</h2>
<h2>v7 What's new</h2>
<h3>Direct Uploads</h3>
<p>Adds support for uploading single files directly (unzipped). Callers
can set the new <code>archive</code> parameter to <code>false</code> to
skip zipping the file during upload. Right now, we only support single
files. The action will fail if the glob passed resolves to multiple
files. The <code>name</code> parameter is also ignored with this
setting. Instead, the name of the artifact will be the name of the
uploaded file.</p>
<h3>ESM</h3>
<p>To support new versions of the <code>@actions/*</code> packages,
we've upgraded the package to ESM.</p>
<h2>What's Changed</h2>
<ul>
<li>Add proxy integration test by <a
href="https://github.com/Link"><code>@​Link</code></a>- in <a
href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
<li>Upgrade the module to ESM and bump dependencies by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/762">actions/upload-artifact#762</a></li>
<li>Support direct file uploads by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/764">actions/upload-artifact#764</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a href="https://github.com/Link"><code>@​Link</code></a>- made
their first contribution in <a
href="https://redirect.github.com/actions/upload-artifact/pull/754">actions/upload-artifact#754</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v6...v7.0.0">https://github.com/actions/upload-artifact/compare/v6...v7.0.0</a></p>
<h2>v6.0.0</h2>
<h2>v6 - What's new</h2>
<blockquote>
<p>[!IMPORTANT]
actions/upload-artifact@v6 now runs on Node.js 24 (<code>runs.using:
node24</code>) and requires a minimum Actions Runner version of 2.327.1.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<h3>Node.js 24</h3>
<p>This release updates the runtime to Node.js 24. v5 had preliminary
support for Node.js 24, however this action was by default still running
on Node.js 20. Now this action by default will run on Node.js 24.</p>
<h2>What's Changed</h2>
<ul>
<li>Upload Artifact Node 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/719">actions/upload-artifact#719</a></li>
<li>fix: update <code>@​actions/artifact</code> for Node.js 24 punycode
deprecation by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/744">actions/upload-artifact#744</a></li>
<li>prepare release v6.0.0 for Node.js 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/745">actions/upload-artifact#745</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0">https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0</a></p>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<p><strong>BREAKING CHANGE:</strong> this update supports Node
<code>v24.x</code>. This is not a breaking change per-se but we're
treating it as such.</p>
<ul>
<li>Update README.md by <a
href="https://github.com/GhadimiR"><code>@​GhadimiR</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/681">actions/upload-artifact#681</a></li>
<li>Update README.md by <a
href="https://github.com/nebuk89"><code>@​nebuk89</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/712">actions/upload-artifact#712</a></li>
<li>Readme: spell out the first use of GHES by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/727">actions/upload-artifact#727</a></li>
<li>Update GHES guidance to include reference to Node 20 version by <a
href="https://github.com/patrikpolyak"><code>@​patrikpolyak</code></a>
in <a
href="https://redirect.github.com/actions/upload-artifact/pull/725">actions/upload-artifact#725</a></li>
<li>Bump <code>@actions/artifact</code> to <code>v4.0.0</code></li>
<li>Prepare <code>v5.0.0</code> by <a
href="https://github.com/danwkennedy"><code>@​danwkennedy</code></a> in
<a
href="https://redirect.github.com/actions/upload-artifact/pull/734">actions/upload-artifact#734</a></li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/upload-artifact/commit/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a"><code>043fb46</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/797">#797</a>
from actions/yacaovsnc/update-dependency</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/634250c1388765ea7ed0f053e636f1f399000b94"><code>634250c</code></a>
Include changes in typespec/ts-http-runtime 0.3.5</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/e454baaac2be505c9450e11b8f3215c6fc023ce8"><code>e454baa</code></a>
Readme: bump all the example versions to v7 (<a
href="https://redirect.github.com/actions/upload-artifact/issues/796">#796</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/74fad66b98a6d799dc004d3353ccd0e6f6b2530e"><code>74fad66</code></a>
Update the readme with direct upload details (<a
href="https://redirect.github.com/actions/upload-artifact/issues/795">#795</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f"><code>bbbca2d</code></a>
Support direct file uploads (<a
href="https://redirect.github.com/actions/upload-artifact/issues/764">#764</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/589182c5a4cec8920b8c1bce3e2fab1c97a02296"><code>589182c</code></a>
Upgrade the module to ESM and bump dependencies (<a
href="https://redirect.github.com/actions/upload-artifact/issues/762">#762</a>)</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/47309c993abb98030a35d55ef7ff34b7fa1074b5"><code>47309c9</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/754">#754</a>
from actions/Link-/add-proxy-integration-tests</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/02a8460834e70dab0ce194c64360c59dc1475ef0"><code>02a8460</code></a>
Add proxy integration test</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/b7c566a772e6b6bfb58ed0dc250532a479d7789f"><code>b7c566a</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/745">#745</a>
from actions/upload-artifact-v6-release</li>
<li><a
href="https://github.com/actions/upload-artifact/commit/e516bc8500aaf3d07d591fcd4ae6ab5f9c391d5b"><code>e516bc8</code></a>
docs: correct description of Node.js 24 support in README</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/upload-artifact/compare/v4...v7">compare
view</a></li>
</ul>
</details>
<br />

Updates `actions/setup-java` from 4 to 5
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/setup-java/releases">actions/setup-java's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.0</h2>
<h2>What's Changed</h2>
<h3>Breaking Changes</h3>
<ul>
<li>Upgrade to node 24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/setup-java/pull/888">actions/setup-java#888</a></li>
</ul>
<p>Make sure your runner is updated to this version or newer to use this
release. v2.327.1 <a
href="https://github.com/actions/runner/releases/tag/v2.327.1">Release
Notes</a></p>
<h3>Dependency Upgrades</h3>
<ul>
<li>Upgrade Publish Immutable Action by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/798">actions/setup-java#798</a></li>
<li>Upgrade eslint-plugin-jest from 27.9.0 to 28.11.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-java/pull/730">actions/setup-java#730</a></li>
<li>Upgrade undici from 5.28.5 to 5.29.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-java/pull/833">actions/setup-java#833</a></li>
<li>Upgrade form-data to bring in fix for critical vulnerability by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/887">actions/setup-java#887</a></li>
<li>Upgrade actions/checkout from 4 to 5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a>[bot]
in <a
href="https://redirect.github.com/actions/setup-java/pull/896">actions/setup-java#896</a></li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>Prevent default installation of JetBrains pre-releases by <a
href="https://github.com/priyagupta108"><code>@​priyagupta108</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/859">actions/setup-java#859</a></li>
<li>Improve Error Handling for Setup-Java Action to Help Debug
Intermittent Failures by <a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/848">actions/setup-java#848</a></li>
</ul>
<h2>New Contributors</h2>
<ul>
<li><a
href="https://github.com/gowridurgad"><code>@​gowridurgad</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-java/pull/848">actions/setup-java#848</a></li>
<li><a href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a>
made their first contribution in <a
href="https://redirect.github.com/actions/setup-java/pull/888">actions/setup-java#888</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-java/compare/v4...v5.0.0">https://github.com/actions/setup-java/compare/v4...v5.0.0</a></p>
<h2>v4.8.0</h2>
<h2>What's Changed</h2>
<ul>
<li>License and Audit Fixes by <a
href="https://github.com/HarithaVattikuti"><code>@​HarithaVattikuti</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/960">actions/setup-java#960</a></li>
<li>Update SapMachine URLs by <a
href="https://github.com/RealCLanger"><code>@​RealCLanger</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/965">actions/setup-java#965</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-java/compare/v4...v4.8.0">https://github.com/actions/setup-java/compare/v4...v4.8.0</a></p>
<h2>v4.7.1</h2>
<h2>What's Changed</h2>
<h3>Documentation changes</h3>
<ul>
<li>Add Documentation to Recommend Using GraalVM JDK 17 Version to
17.0.12 to Align with GFTC License Terms by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/704">actions/setup-java#704</a></li>
<li>Remove duplicated GraalVM section in documentation by <a
href="https://github.com/Marcono1234"><code>@​Marcono1234</code></a> in
<a
href="https://redirect.github.com/actions/setup-java/pull/716">actions/setup-java#716</a></li>
</ul>
<h3>Dependency updates:</h3>
<ul>
<li>Upgrade <code>@​action/cache</code> from 4.0.0 to 4.0.2 by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/766">actions/setup-java#766</a></li>
<li>Upgrade <code>@​actions/glob</code> from 0.4.0 to 0.5.0 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-java/pull/744">actions/setup-java#744</a></li>
<li>Upgrade ts-jest from 29.1.2 to 29.2.5 by <a
href="https://github.com/dependabot"><code>@​dependabot</code></a> in <a
href="https://redirect.github.com/actions/setup-java/pull/743">actions/setup-java#743</a></li>
<li>Upgrade <code>@​action/cache</code> to 4.0.3 by <a
href="https://github.com/aparnajyothi-y"><code>@​aparnajyothi-y</code></a>
in <a
href="https://redirect.github.com/actions/setup-java/pull/773">actions/setup-java#773</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/setup-java/compare/v4...v4.7.1">https://github.com/actions/setup-java/compare/v4...v4.7.1</a></p>
<h2>v4.7.0</h2>
<h2>What's Changed</h2>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/actions/setup-java/commit/be666c2fcd27ec809703dec50e508c2fdc7f6654"><code>be666c2</code></a>
Chore: Version Update and Checkout Update to v6 (<a
href="https://redirect.github.com/actions/setup-java/issues/973">#973</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/f7a6fefba97e80156950e16f2a9dafc8579b7d05"><code>f7a6fef</code></a>
Bump actions/checkout from 5 to 6 (<a
href="https://redirect.github.com/actions/setup-java/issues/961">#961</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/d81c4e45f3ac973cc936d79104023e20054ba578"><code>d81c4e4</code></a>
Upgrade <code>@​actions/cache</code> to v5 (<a
href="https://redirect.github.com/actions/setup-java/issues/968">#968</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/1b1bbe1085cb6ab21b5b19b7bebc091a9430026a"><code>1b1bbe1</code></a>
readme update (<a
href="https://redirect.github.com/actions/setup-java/issues/972">#972</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/5d7b2146334bacf88728daaa70414a99f5164e0f"><code>5d7b214</code></a>
Retry on HTTP 522 Connection timed out (<a
href="https://redirect.github.com/actions/setup-java/issues/964">#964</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/f2beeb24e141e01a676f977032f5a29d81c9e27e"><code>f2beeb2</code></a>
Bump actions/publish-action from 0.3.0 to 0.4.0 (<a
href="https://redirect.github.com/actions/setup-java/issues/912">#912</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/4e7e684fbb6e33f88ecb2cf1e6b3797739cf499b"><code>4e7e684</code></a>
feat: Add support for <code>.sdkmanrc</code> file in
<code>java-version-file</code> parameter (<a
href="https://redirect.github.com/actions/setup-java/issues/736">#736</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/46c56d6f92c88cf540acf95a12a4a41197499222"><code>46c56d6</code></a>
Add GitHub Token Support for GraalVM and Refactor Code (<a
href="https://redirect.github.com/actions/setup-java/issues/849">#849</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/66b945764b75604b3cfd644c3ada5232cf6c90c6"><code>66b9457</code></a>
Update SapMachine URLs (<a
href="https://redirect.github.com/actions/setup-java/issues/955">#955</a>)</li>
<li><a
href="https://github.com/actions/setup-java/commit/6ba5449b7dcda52941806a19f0cf626b6420191e"><code>6ba5449</code></a>
Enhance error logging for network failures to include endpoint/IP
details, ad...</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/setup-java/compare/v4...v5">compare
view</a></li>
</ul>
</details>
<br />

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Ignacy Łątka <latkaignacy@gmail.com>
2026-06-17 14:42:17 +02:00
Ignacy Łątka acfe80ab6b chore: add ESLint with typescript-eslint (#349)
## What

Adds type-aware linting to the workspace. Until now the only static gate
on JS/TS was Prettier (formatting) and `tsc` — there was no linter, so
the whole class of bugs `tsc` doesn't catch (floating promises, misused
promises, throwing non-Errors, unsafe stringification, dead code) went
unguarded across ~450 TS files.

- **`eslint.config.mjs`** — flat config. `recommendedTypeChecked` runs
on the TS sources via an explicit `project` list (each package keeps
tests in a separate `tsconfig.test.json` that `projectService` can't
auto-discover, so it's listed explicitly). Type-checked rules are
disabled for the loosely-typed plain-JS build/dev scripts. The
`argent-private` submodule and build artifacts are ignored (mirrors
`.prettierignore`).
- **`lint` / `lint:fix`** npm scripts.
- **`.github/workflows/lint.yml`** — builds the workspace (type-aware
rules need the referenced projects' declarations) then runs `eslint .`.
Node 24 (ESLint 10 requires `^20.19 || ^22.13 || >=24`).

## Rule calibration

This is an adoption PR, so it's deliberately calibrated rather than
maximal:

- **Kept on (bug-catchers):** `no-floating-promises`,
`no-misused-promises` (with `checksVoidReturn: false` to drop the noisy
callback variant), `only-throw-error`, `no-base-to-string`,
`prefer-promise-reject-errors`, `no-unused-vars` (`_`-prefix escape
hatch), plus the ESLint recommended set.
- **Parked off as documented debt:** the high-volume style/`any`-family
rules — `no-unsafe-*`, `require-await`, `no-unnecessary-type-assertion`,
`restrict-template-expressions`, `unbound-method`, `no-explicit-any`,
etc. These flag broad classes of pre-existing code and are out of scope
here; each is commented as a ratchet target for follow-up passes.

All findings from the kept-on rules are fixed in this PR (dead
code/imports, error-cause chaining, **3 genuine floating promises**,
non-Error throws, unsafe stringification). Stale unused `eslint-disable`
directives left over in the tree were removed by `--fix`.

## Verification

Locally, all green: `eslint .` (0 errors), `tsc --build`,
`typecheck:tests`/`typecheck:scripts`, the full `vitest` suite (no
behavior change from the fixes), and `prettier --check`.

## Not included (intentionally)

Other static-analysis gates discussed (CodeQL, dependency-audit,
ShellCheck, actionlint) are out of scope for this PR.
2026-06-17 12:20:55 +02:00
Ignacy Łątka 9b027096d7 feat: Electron support (#247)
## Summary

Adds Electron (Chromium + CDP) as a third device platform alongside iOS
and Android. Argent can boot an Electron app, list it next to
simulators/emulators, drive it with the same tool surface where it makes
sense — taps, swipes, keyboard, screenshots, describe, navigation — and
debug it via the four ported `debugger-*` tools.

Mirrors the sim-server architecture in TypeScript: a per-device server
with HTTP API, MJPEG screencast, refcounted CDP screencast, FPS tracker,
clipboard, and a WebSocket command bus.

## What works on Electron

| group | tools | status |
|---|---|---|
| Lifecycle | `boot-device` (with `electronAppPath`), `launch-app`,
`open-url` | ✅ works |
| Vision | `screenshot`, `describe` (DOM walker w/ shadow-DOM +
same-origin iframes) | ✅ works |
| Input | `gesture-tap`, `gesture-swipe`, `keyboard` (text + named keys)
| ✅ works |
| Sequencing | `run-sequence` (per-step capability check) | ✅ works |
| **JS debugger** | `debugger-connect`, `debugger-status`,
`debugger-evaluate`, `debugger-log-registry` | ✅ **direct CDP** |
| Discovery | `list-devices` (Electron entries shown alongside
sims/emulators) | ✅ works |
| Cleanup | `stop-simulator-server`, `stop-all-simulator-servers`,
`stop-metro` | ✅ works |
| Misc | `update-argent`, `dismiss-update`, `gather-workspace-data`, all
`flow-*` recording tools | ✅ works |

### Debugger port — how it routes

Dispatch lives in `tools/debugger/debugger-service-ref.ts`: an Electron
device id (`electron-cdp-<port>`) routes to a new
`ElectronJsRuntimeDebugger` blueprint that wraps the page CDP session
already opened by `boot-device`. Everything else stays on the
Metro-driven `JsRuntimeDebugger` blueprint. The new blueprint exposes
the same `JsRuntimeDebuggerApi` shape so tool code is unchanged.
`Runtime.consoleAPICalled` events feed into the existing `LogFileWriter`
+ cluster pipeline — `debugger-log-registry` returns the same shape on
Electron as it does on Metro.

## What is cleanly rejected with `Tool 'X' is not supported on electron
app`

HTTP capability gate declines these up-front (HTTP 400):

| group | tools |
|---|---|
| Mobile gestures | `gesture-pinch`, `gesture-rotate`, `gesture-custom`
|
| Mobile controls | `button`, `rotate` |
| App lifecycle | `restart-app`, `reinstall-app` |
| iOS-native | `paste`, all `native-*`, `native-profiler-*` |
| RN-only debugger | `debugger-component-tree`, `debugger-reload-metro`,
`debugger-inspect-element` |
| RN-only network | `view-network-logs`, `view-network-request-details`
|
| RN-only profiler | all `react-profiler-*` (incl. `component-source`),
all `profiler-*` query / combined tools |

## Verification history

Three commits resolved findings from two parallel verification swarms:

- `507b295` — swarm v1 fixes: early-disconnect race in new blueprint,
NaN timestamp crash, disconnect listener leak, missing test coverage for
13 of 15 lockouts, missing disconnect→terminated propagation test, stale
skill + tool descriptions.
- `dd0f185` — pre-existing crash: `spawn()` in boot-electron lacked an
`'error'` event handler; ENOENT escalated to `uncaughtException`. + 4
regression test cases.
- `95161ab` — swarm v2 fixes: orphan promise rejection when pid-less
spawn fires deferred `'error'`, misleading rationale comment, stale
cross-skill references calling this "Metro debugging only".

Branch was also cherry-picked onto v0.8.0 (`e1327b4`) to pick up #245.

## Follow-ups left for separate PRs

- **CPU profiling on Electron** — Chromium's
`Profiler.start`/`Profiler.stop` work fine; only the V8 sample format
differs from Hermes'. A normalizer in the query layer would unlock
`react-profiler-cpu-summary` + `profiler-cpu-query` for arbitrary
Electron renderers (without the React-DevTools commit half).
- **Source-mapped element inspection on Electron** —
`debugger-inspect-element` could be rebuilt on top of
`DOM.getNodeForLocation` + CSS source maps, but it'd be a from-scratch
implementation rather than a port.

## New sim-server-equivalent HTTP surface

Mounted at `/electron-server/:deviceId/*` — not advertised to MCP,
consumed by preview UIs and integration tests:

- `GET /viewport`, `GET /stream.mjpeg` (multipart-JPEG screencast)
- `POST /api/screenshot`, `/api/clipboard/text`, `/api/fps`,
`/api/navigate`, `/api/reload`, `/api/history/back`,
`/api/history/forward`
- `WS /ws` (input commands + event bus)

Sharp is loaded as an optional dependency — screenshots still work
without it (no rotate/resize, just raw PNG).

## Test plan

- [x] 786 vitest cases pass; new coverage for the dispatch helper,
blueprint factory edge cases (early disconnect, NaN timestamp, dispose
symmetry), 15-tool table-driven lockout assertion, and 5 boot-electron
spawn-error scenarios.
- [x] Build + prettier clean.
- [x] E2E swept the original 27 surfaces (11 MCP tools, 8 HTTP
endpoints, MJPEG, WebSocket, 6 capability rejections, session cleanup).
- [x] E2E swept the debugger surface against a live Electron app —
connect / status / evaluate (`1+1`, JSON-stringified globals,
`document.title`) / log-registry (clusters + log file).
- [x] E2E swept the 17 lockouts — every one returns HTTP 400 with `Tool
'X' is not supported on electron app`.
- [x] Two rounds of parallel verification swarm; every real finding
addressed.
- [ ] Reviewer drives an Electron app end-to-end via MCP and confirms
describe / tap / swipe / keyboard / debugger-evaluate land correctly.

---------

Co-authored-by: Filip131311 <contact@filipkaminski.com>
2026-06-12 17:54:45 +02:00
filip131311 73cf47bae6 feat: support arm64 Linux simulator-server binary (#328)
## Summary

The only Linux simulator-server binary argent ships today is x86_64
(`simulator-server-argent-linux` — verified: `ELF 64-bit … x86-64`). On
arm64 Linux hosts (Lima/UTM VMs on Apple Silicon, arm cloud instances,
Raspberry Pi-class devices) the package has no usable binary — the
x86_64 ELF would only fail with `ENOEXEC` at spawn time.

This PR teaches the whole binary pipeline about a **host platform key**:
`process.platform` everywhere, except arm64 Linux which maps to
`linux-arm64`. macOS keeps a single `darwin/` dir because its binary is
universal (lipo); Linux binaries are single-arch ELFs, so each arch gets
its own platform-keyed directory. x86_64 Linux keeps the existing
`linux` key for backward compatibility.

## Changes

- **`@argent/native-devtools-ios` resolver** — new exported
`hostPlatformKey()`; `simulatorServerBinaryPath()` resolves
`bin/linux-arm64/` on arm64 Linux and names the searched key in its
error message.
- **`argent-simulator-server.cjs` dispatcher** (npm `bin` entry) —
mirrors the same key (duplicated deliberately; the dispatcher ships as a
standalone file).
- **`bundle-tools.cjs`** — `linux-arm64` added to the supported host
platform dirs; copied into the package when staged, warn-and-skip
otherwise (same as x86_64 Linux).
- **`scripts/download-simulator-server.sh`** — downloads
`simulator-server-argent-linux-arm64` into `bin/linux-arm64/`; tolerates
the asset being absent (warn + skip) until the upstream release ships
it, so publishing keeps working in the meantime.
- **`scripts/dev.cjs`** — copies the current host's binary by key.
- **publish / publish-next / build-package-artifact workflows** —
`linux-arm64` added to the binary inventory; gated by the existing
`ARGENT_REQUIRE_LINUX_BINARY` flag (now covering both Linux keys via a
`linux*` glob).

## Tests

- Resolver: new arch-aware suite — `linux`+`arm64` → `bin/linux-arm64`,
`linux`+`x64` → `bin/linux`, `darwin`+`arm64` → `bin/darwin`, and the
missing-binary error names `linux-arm64`.
- Dispatcher: end-to-end test faking `process.platform`/`process.arch`
in a child process to exercise the real resolution path on any host.
- Full suite: 146 files / 1651 tests pass. `tsc --build` clean.
- `download-simulator-server.sh` exercised against the live `radon-main`
release: downloads darwin + linux, warn-and-skips the not-yet-published
arm64 asset.

## Dependencies

Companion PR software-mansion/radon#126 adds the `ubuntu-24.04-arm`
build leg that publishes `simulator-server-argent-linux-arm64` to
`simulator-server-releases`. This PR is safe to merge first (the
download script and verify steps tolerate the missing asset); arm64
hosts start working once a release containing the new asset is cut.
2026-06-12 16:20:23 +02:00
filip131311 825b731cbf Add npm package artifact workflow (#320)
## Summary
- Add a manual workflow that checks out `main`, builds the
`@swmansion/argent` package using the same asset downloads and runtime
checks as publishing, and packs it without publishing to npm.
- Upload the generated `.tgz` as the `argent-main-npm-package` GitHub
Actions artifact.

## Test plan
- `npx prettier --check .github/workflows/build-package-artifact.yml`

Made with [Cursor](https://cursor.com)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 14:57:55 +02:00
Paweł Fornagiel 3ccd89f333 feat: add native android profiling (#275)
# Android native profiling via in-process Perfetto WASM

Connected with:
https://github.com/software-mansion/argent-private/pull/16

## TL;DR

Adds **Android** to the native profiler (previously iOS-only) and does
it with a
brand-new engine: instead of shipping Perfetto's `trace_processor_shell`
native
binary and forking it per query, we now run **Perfetto's trace-processor
compiled
to WebAssembly, in-process** inside the tool-server.

- **One ~13 MB `trace_processor.wasm`** runs on every OS/arch — no
per-platform
  binary, no subprocess, fully offline.
- The native profiler is refactored from an iOS-only implementation into
a
**platform-dispatch facade** (`platforms/ios.ts` +
`platforms/android.ts`) over
a new **`profiler-shared/`** layer, so iOS and Android share the
aggregator,
  types, lifecycle, and time-alignment code.
- New **release/pack pipeline** fetches + sha256-verifies the WASM
bundle from
`argent-private-releases`, and bundles it (plus SQL queries and the
Perfetto
  TraceConfig) into the published `@swmansion/argent` package.

End-to-end on a 76 MB trace with 1013 jank rows: **6.3 s** total analyze
(the older per-hang-subprocess approach was projected at ~47 minutes and
never
finished within the tool-call deadline).

---

## TESTING MANUALLY

To test manually run the following packing command checked-out on this
branch:
```
npm run pack:mcp -- argent-@pFornagiel-native-android-devtools-perfetto
```

This will bundle the package with the new binaries. After this PR is
fixed and the binaries are resolved from the main release, the
`argent-@pFornagiel-native-android-devtools-perfetto` release can be
deleted.

## Why

Android needed native CPU/hang/memory profiling to reach parity with
iOS. The
natural engine is Perfetto's trace-processor, but the obvious ways to
ship it are
both bad:

- **`trace_processor_shell` binary** — per-platform (a mac-arm64 pack
shipped a
mac-arm64-only tarball), pinned an OS/arch matrix, and cost a fresh ~1.3
s
subprocess fork **per query**. With one subprocess forked per detected
hang, a
  large trace projected to ~47 minutes.
- **`get.perfetto.dev/trace_processor` Python launcher** — adds a
runtime Python 3
dependency, resolves "latest" at first run (defeats version pinning),
and makes
  the first analyze slow via a network fetch.

The WASM engine is one cross-platform artifact, in-process and
warm-cached: the
trace is parsed **once** and reused across the whole analyze run plus
every
drill-down query.

---

## The three big pieces

### 1. In-process Perfetto WASM engine

New package surface in `@argent/native-devtools-android`:

| File | Role |
| --- | --- |
| `src/wasm-trace-processor.ts` (+476) | The whole engine: boot, glue
patching, warm-cache, fault containment, chunked parse, cell decoding |
| `src/perfetto-engine.d.ts` (+49) | Hand-written types for the
version-agnostic RPC decoder (imported by path, so tsc can't see its own
`.d.ts`) |
| `src/errors.ts` (+68) | `TraceProcessorUnavailableError`
(`wasm_load_failed` / `wasm_path_invalid`) |
| `src/bundled-meta.ts` (+12) | `PERFETTO_VERSION` stamp, regenerated at
pack time |
| `src/index.ts` | Re-exports + package-root accessors
(`traceProcessorQueriesDir`, `traceConfigPath`) |

Public surface: `resolveTraceProcessorAssets()`,
`queryWarm<Row>(tracePath, sql)`,
`ensureTraceProcessorReady(tracePath)`, `disposeWarmEngine(tracePath)`.

Highlights of how it works:

- **Boots Google's prebuilt web/worker wasm under Node.** Installs a
minimal
worker scope (`self`, `WorkerGlobalScope`, `location`), reads the wasm
bytes,
patches the Emscripten glue (`useMemory64=false`, hand the bytes in
directly,
expose the bridge), and drives it over a `MessageChannel` + `EngineBase`
subclass. Glue patches are applied **by unique string anchors that throw
if they
  don't match** — the canary for glue-format drift on a Perfetto bump.
- **Warm-engine cache, one per trace path.** LRU with `MAX_WARM_ENGINES
= 3`
(bounds resident memory at ~26–76 MB trace + wasm heap each), 5-min idle
dispose
  (timer `unref()`'d), no failed-promise caching.
- **Fault containment (`fatal` promise).** `EngineBase.fail()` throws
synchronously
inside the `MessagePort.onmessage` handler (e.g. an RPC framing error);
left
unhandled it becomes a Node `uncaughtException` and would **kill the
entire
tool-server**, wiping every device + profiler session. Each engine
exposes a
`fatal: Promise<never>`; the handler try/catches, rejects `fatal`,
evicts the
engine, and every load/query is `Promise.race`'d against it — so a
contained
  fault is a clean rejection and the server stays up.
- **Chunked trace parse.** Perfetto's RPC ring buffer rejects any frame
> 64 MiB,
  so the trace is fed in 32 MiB chunks before `notifyEof()`.

### 2. Android native profiler + the shared/dispatch refactor

**Capture** (`utils/android-profiler/capture.ts`, `detect-app.ts`):
spawns
`adb shell perfetto --txt -c - --background-wait -o
/data/.../argent-<ts>.pftrace`,
piping the TraceConfig on **stdin** (SELinux denies `shell:s0` writes
under
`/data/misc/perfetto-traces/`, so the config can't be staged as a file),
waits for
the PID on stdout, then on stop sends `kill -TERM`, polls `/proc/<pid>`,
and
`adb pull`s the trace.

**Pipeline** (`utils/android-profiler/pipeline/`): PerfettoSQL does the
parsing and
aggregation, so the Android pipeline is intentionally **two files, not
iOS's four**.
The per-hang annotation pass is **batched** — `runBatchedHangFolds`
inlines all
hang windows as a `VALUES` table into one SQL script (two derived views
unioned in
a single terminal SELECT, because the engine returns only the final
statement's
rows) and runs it once against the warm engine.

**The platform-dispatch refactor** —
`native-profiler-start/stop/analyze` shrank
from monolithic iOS files (~160–330 lines each) into **thin routers**
(~60–110
lines) that branch on `api.platform`:

```
native-profiler-start ─┬─ ios?    → platforms/ios.ts      (xctrace)
                        └─ android → platforms/android.ts  (adb perfetto)
```

A new **`utils/profiler-shared/`** layer holds everything both backends
use:

| File | What was hoisted |
| --- | --- |
| `types.ts` | Unified `Bottleneck = CpuHotspot \| UiHang \| MemoryLeak
\| MemoryRssGrowth`, each now carrying a `platform` field; shared
`NativeProfilerAnalyzeResult`; `RECORDING_CAP_MS` |
| `aggregate.ts` | Generic `aggregateCpuHotspots(AggregatorInputRow[])`
— burst windowing (`BURST_GAP_MS=500`), severity banding (RED >15%,
YELLOW 3–15%, <3% dropped). iOS feeds it via a pre-pass; Android feeds
it precomputed SQL rows |
| `lifecycle.ts` | `shutdownChild` SIGINT→SIGTERM→SIGKILL ladder +
`waitForChildExit` (no PID-reuse hazard) |
| `thread.ts` | `normalizeThreadName` for both xctrace and Perfetto
thread names |
| `time-align.ts` | New `buildPerfettoAnchor()` + `windowsOverlap()`
alongside the existing iOS/React anchors |
| `format.ts` | `formatBytes` (moved out of the combined report) |

iOS was refactored to fit this shape: `ios-profiler/lifecycle.ts` and
`types.ts`
become thin re-exports; `pipeline/02-aggregate.ts` shrank from ~200 to
~60 lines
(keeps its iOS-only dominant-function pre-pass, delegates
grouping/bursting/
severity to the shared aggregator). **No iOS behavior change** — same
outputs,
shared internals.

**Session blueprint** (`native-profiler-session.ts`): generic
`capturePid` /
`captureProcess` (was `xctracePid` / `xctraceProcess`), new `platform`
and
`androidOnDeviceTracePath` fields, and **platform-branched dispose**
(iOS SIGKILLs
xctrace; Android `kill -KILL`s perfetto, `rm`s the device trace, and
disposes the
warm WASM engine).

**Drill-down tools**: `profiler-load.ts` learns to restore Android
`.pftrace`
sessions (with an optional metadata sidecar / `app_process` override);
`profiler-stack-query.ts` splits into iOS and Android branches. Unlike
iOS (which
caches `parsedData` in memory), Android **re-queries the `.pftrace`**
per
drill-down — the warm engine is the cache, so each query costs only SQL
execution
time.

### 3. Packaging & release pipeline

The WASM bundle's three third-party artifacts (`trace_processor.wasm`,
`engine_bundle.node.js`, `engine.mjs`) + `LICENSE` are **never
committed**
(`.gitignore` lists the generated files but not the dir). They're built
and
sha256-checksummed in `argent-private` CI, published to
`argent-private-releases`, and on our side:

- **`scripts/download-trace-processor.sh`** (+88, new) — `gh release
download` →
verify tarball sha256 (**FATAL on mismatch** — the blobs are unsigned) →
extract
  → re-verify via `SHA256SUMS` → assert all four present.
- **`scripts/pack-mcp.cjs`** (+60, new) — single pack entry point:
downloads
simulator-server, native binaries, **and** the trace-processor bundle,
then
builds and `npm pack`s `@swmansion/argent`. `package.json`'s `pack` /
`pack:mcp`
  now call this script.
- **`packages/argent/scripts/bundle-tools.cjs`** (heavily reworked,
+574/-...) —
copies `assets/trace-processor/`, `assets/queries/`, and
`argent.tracecfg.pbtxt`
into `packages/argent/assets/`, and regenerates `bundled-meta.ts` to
stamp the
  Perfetto version.
- **`publish.yml` / `publish-next.yml`** — run the download step and
then **verify**:
  all four WASM files present, the wasm magic-byte check
(`head -c4 … | grep $'\x00asm'`), plus the queries dir, TraceConfig,
manifest,
  and Android helper APK.

Asset reorg: `native-devtools-android` now ships `dist/`, `bin/`, and
`assets/`
(SQL queries, TraceConfig, manifest moved under `assets/`); `.gitignore`
swaps the
old per-file `packages/argent/manifest.json` entry for the whole
`packages/argent/assets/` dir.

---

## Testing

15 new test files under `packages/tool-server/test/android-perfetto/`
cover the
engine and pipeline, including:

- `dispatch.test.ts` — start/stop/analyze route to the right platform
backend.
- `aggregate-shared.test.ts` — the shared aggregator on both iOS and
Android-shaped input.
- `hang-folds-batched.test.ts` / `hang-fold.test.ts` — the batched
per-hang SQL fold.
- `hang-severity.test.ts` — jank-reason → RED/YELLOW classification.
- `dispose.test.ts` / `dispose-warm-engine.test.ts` — session dispose
kills the daemon, rms the device trace, and tears down the warm engine.
- `stop-recovery.test.ts` — `profilingActive` is forced false even if
`adb pull` fails (so a retry-start doesn't wedge).
- `run-tp.test.ts` — `renderSqlTemplate` token rendering + the "unused
substitution" guard.
- `manifest-hint.test.ts` — zero-callstack detection emits the manifest
hint.
- `profiler-load.test.ts` — `.pftrace` session restore with/without the
metadata sidecar.

Plus `native-profiler-analyze-failure.test.ts` for the
engine-unavailable banner,
and updated iOS tests for the shared-lifecycle refactor.
`@argent/native-devtools-android` gains its own vitest setup
(`vitest.config.ts`, `tsconfig.test.json`, `test/errors.test.ts`).

---

## Notes & follow-ups

- **Manifest requirement.** Perfetto's `linux.perf` data source needs
`/proc/<pid>/mem` access, granted only to a **debuggable** or
`<profileable
android:shell="true"/>` app. A release build without either silently
produces
zero callstacks; the pipeline detects this and emits a **manifest hint**
instead
  of an "All clear" report.
- **Version pinning lives in the `argent-private` submodule**
(`PERFETTO_VERSION`
/ `PERFETTO_WASM_TAG` / `LYNX_TRACE_PROCESSOR_VERSION`). Bumping is
documented in
`argent-private/docs/ANDROID_PERFETTO.md`. JS↔engine version skew is
structurally
  impossible (version-agnostic decoder + vendored wasm).
- **`disposeWarmEngine` is exported but not wired into session-stop** —
warm
engines are reclaimed only by the idle timer + LRU cap. Acceptable today
(bounded
memory); wire it into session dispose if explicit teardown is ever
needed.
- **Submodule bump.** This PR moves `packages/argent-private` to
`22e55f90` — see the companion `argent-private` PR description,
including its
merge-hygiene note (that branch should pick up latest `argent-private`
main
  before the pointer is finalized).

### Companion docs added in this branch
- `utils/android-profiler/ANDROID_PROFILER_REFERENCE.md` — stack,
capture, queries, manifest requirement.
- `utils/android-profiler/PIPELINE_DESIGN.md` — the "why" (two-file
pipeline, shared-aggregator hoist, re-query-don't-cache, batched fold).

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-09 16:06:24 +02:00
Ignacy Łątka 3d2d254004 fix(wayland-e2e): use ARGENT_PORT instead of PORT to start tool-server (#304)
## Summary
- The tool-server reads its port from `ARGENT_PORT` (index.ts:72), not
the generic `PORT` env var
- The CI step was setting `PORT=3033` which the process silently
ignored, causing it to bind on the default 3001
- The health-poll loop and every downstream curl targeted 3033, so
startup always timed out
2026-06-03 22:22:53 +02:00
Ignacy Łątka 80661fad8f feat: Linux support (#249)
This PR makes Linux work.

# AI Summary 

<details>
Brings Argent up on Linux as a host: per-platform npm bundle, renderer
selection that actually works on hybrid-GPU / Wayland / containerized
Linux, hot-boot guarding that survives the SwiftShader composite gap, a
real Linux preflight, and a Wayland-headless E2E job in CI. macOS stays
on
the path it was on before (no `-gpu` flag was passed; AVD config
decided);
nothing about the iOS Simulator behavior changes.

The diff is broader than "ship the Linux artifact" — calling it out
below
because several pieces affect macOS too and reviewers should be primed
for
that rather than skim past expecting "just packaging."

### What's actually in here

**npm packaging (the original framing — still load-bearing)**

| File | Change |
|---|---|
| `packages/argent/scripts/argent-simulator-server.cjs` (new) | Node
dispatcher exposed as the `argent-simulator-server` bin entry. Joins
`process.platform` into the bin path and execs. Forwards
SIGTERM/SIGINT/SIGHUP parent→child so non-TTY supervisors can't orphan
the binary. |
| `packages/argent/scripts/bundle-tools.cjs` | Copies per-platform
binaries from `packages/native-devtools-ios/bin/<platform>/` into
`packages/argent/bin/<platform>/`. darwin required, linux best-effort. |
| `packages/argent/package.json` | `bin.argent-simulator-server` points
at the dispatcher. |
| `packages/native-devtools-ios/src/index.ts` | Resolver joins
`process.platform` into the simulator-server bin path. iOS-only dylibs
and `ax-service` throw `"requires a macOS host"` on Linux callers so
they get the root cause, not "file not found". |
| `scripts/download-simulator-server.sh` | Downloads
`simulator-server-argent-{macos,linux}` into platform-keyed subdirs.
**Purges each platform dir before its download attempt** so a failed
download can't leave stale binaries in place from a prior run. |
| `scripts/dev.cjs` | Local dev copies the current host's binary into
`bin/<process.platform>/` to match the resolver layout. |
| `.github/workflows/publish{,-next}.yml` | Replaces single `test -x
darwin/...` with a per-platform inventory loop. darwin always required;
Linux gated by `ARGENT_REQUIRE_LINUX_BINARY=1` (flip once radon#118
lands). |

**Linux runtime — emulator boot path**

| File | Change |
|---|---|
| `packages/tool-server/src/tools/devices/boot-device.ts` |
`selectGpuMode()`: Linux defaults to `-gpu swiftshader` (`auto` lands on
lavapipe with ~10× cold-boot slowdown; `-gpu host` produces silent
black-window failures on Optimus / NVIDIA+libglvnd / Wayland-on-hybrid /
containers). macOS keeps `auto` (ANGLE→Metal).
`ARGENT_EMULATOR_GPU_MODE` overrides, **validated against `emulator
-help-gpu`'s whitelist** so a typoed value fails fast instead of burning
the whole boot budget. `ARGENT_EMULATOR_NO_WINDOW=1` appends
`-no-window` for headless contexts (CI / containers / Wayland sessions
with no Qt wayland plugin). |
| `packages/tool-server/src/tools/devices/boot-device.ts` (cont.) |
**Cold-boot:** `awaitFirstRealFrame` polls SwiftShader's lockscreen
composite (PNG byte-count via `screencap -p`); blocks `booted:true`
until a real frame shows up. Without this, callers chaining `boot-device
→ screenshot` get an all-black PNG because `sys.boot_completed=1` fires
5–60 s before the first composite. |
| `packages/tool-server/src/tools/devices/boot-device.ts` (cont.) |
**Hot-boot:** `assertScreencapAlive` polls within an 8 s budget instead
of single-probing. The earlier single-probe caught the sticky-blank
state but also killed the emulator on every transient snapshot-restore
blank, forcing "every boot is cold" cycles. Sticky vs transient is
discriminated by whether the budget exhausts. |
| `packages/tool-server/src/utils/linux-preflight.ts` (new) |
`linuxBootDiagnostics()` checks `/dev/kvm` access. `diagnoseAvdSizing()`
warns when a target AVD's `hw.ramSize`/`vm.heapSize` is below the floor
an aggressive RN/Expo app needs (2G/228M avdmanager defaults wedge under
load). |
| `packages/tool-server/src/utils/android-binary.ts` |
`defaultAndroidRoots()` probes typical SDK install locations when
`ANDROID_HOME`/`ANDROID_SDK_ROOT` are unset — **cross-platform**,
benefits macOS launches from GUI-launched MCP hosts (Claude Code Desktop
etc.) where shell rc env doesn't propagate. |

**Cross-platform fixes that landed alongside**

| File | Change |
|---|---|
| `packages/argent-installer/src/utils.ts` | `getLatestVersion()` now
redirects `npm view`'s stderr to `ignore` so `EBADDEVENGINES` warnings
from a consumer project's `package.json` (e.g. Bluesky's pnpm pin) don't
leak to the user's terminal. **Cross-platform fix**, not Linux-specific.
|

**CI**

| File | Change |
|---|---|
| `.github/workflows/wayland-e2e.yml` (new) | Boots an AVD through the
tool-server under headless Weston; asserts `hw.gpu.mode = swiftshader`
and that screenshots + gesture-tap work without a display. Currently
runs on `pull_request` for the affected paths + `workflow_dispatch`.
Pinned to `radon-daily` for the simulator-server until radon#118 ships a
Linux asset to `radon-main`. |

### Tests added in this PR

- `packages/argent/test/dispatcher.test.ts` — e2e against tmpdir-staged
dispatcher + fake `<platform>/simulator-server`: missing-binary error
path, exit-code passthrough, argv passthrough, SIGTERM forwarding.
- `packages/tool-server/test/native-devtools-ios-resolver.test.ts` —
`requireDarwin` gates for dylibs and `ax-service` on Linux, per-platform
`simulator-server` path resolution, missing-binary error,
`ARGENT_NATIVE_DEVTOOLS_DIR` override.
- `packages/tool-server/test/linux-preflight.test.ts` — KVM diagnostic
shape + `diagnoseAvdSizing` (ram low, heap low, both, neither, missing
keys).
- `packages/tool-server/test/boot-device-hotboot.test.ts` — extended
with `it.each([linux→swiftshader, darwin→auto])` so a single CI runner
exercises both GPU branches (was runner-platform-dependent, regressions
could pass on both runners individually). New cases for the wedged-frame
fallback (under fake timers because the polling budget is short but
real-time enough to exceed vitest's 5 s default), the GPU-mode whitelist
rejection, and the cold-boot composite-wait timeout.
- `packages/tool-server/test/android-binary.test.ts` — extended for
`defaultAndroidRoots` probe ordering and HOME pinning.

### Verification

- `tsc --build`: clean apart from pre-existing
`@argent/native-devtools-android` import errors unrelated to this
branch.
- `vitest run` in `packages/tool-server` and `packages/argent`: 689 + 11
= 700 tests passing; the 4 pre-existing test-file load failures
(native-devtools-android missing) reproduce on `main` and are out of
scope.
- `npm pack -w @swmansion/argent`: produces `swmansion-argent-0.8.0.tgz`
with the per-platform layout.
- Wayland-e2e: triggered on this branch — link will be in a PR comment
once the run completes.
- Manually verified end-to-end on a Wayland-on-hybrid-GPU developer
laptop: AVD boots through the tool-server with `-gpu swiftshader`,
screencap returns real frames, gesture tools work.

### Dependencies / what still gates this

- **radon#118** must land before the Linux artifact ships through the
default channel. The download script tolerates the asset being absent
today (best-effort), so this PR is technically safe to merge before —
Linux installs just won't get a working `simulator-server` until the
upstream artifact is published. Once it lands:
  - Drop the `radon-daily` arg in `.github/workflows/wayland-e2e.yml`.
  - Flip `ARGENT_REQUIRE_LINUX_BINARY` to `1` in both publish workflows.
- **wayland-e2e is not a required status check** today (no branch
protection on `main` requires it). Worth turning on before merging
anything else that touches the Linux boot path.

### Related

- radon#118 — produces the `simulator-server-argent-linux` artifact this
PR consumes.
- argent-private#11 — cross-builds the iOS Simulator dylibs on Linux.
Strictly orthogonal: those dylibs are macOS-runtime-only regardless of
where they're built, and this PR keeps them under `dylibs/` with a clean
error path on Linux callers.

</details>

Fixes #246
2026-06-03 15:55:39 +02:00
Ignacy Łątka 2180dd8e6a ci: typecheck test files in CI (#202)
We've had lots of type errors in our tests, scripts and other non-core
code despite all CI being green. This PR fixes that.

This PR also removes some redundant features like `@ts-check` inline
directives which have been replaced by proper ts config files.

<details>

## AI Summary

Audit of every CI workflow against every package's `package.json` and
`tsconfig` surfaced several gaps where CI did partial coverage. This PR
closes them and fixes every pre-existing type error the new gates
surfaced.

## Gaps closed

| # | Gap | Fix |
|---|---|---|
| 1 | `tsc --build` only covers `src/**`; test files (`test/**`,
`tests/**`) never typecheck. Vitest transforms tests with esbuild —
strips types instead of checking them. | New `tsconfig.test.json` per
test-bearing package (`composite: false`, `noEmit`, `rootDir: "."`,
includes `src/**` + `test/**` (or `tests/**`) + `vitest.config.ts`). New
`typecheck:tests` npm script per package. New CI step `npm run
typecheck:tests --workspaces --if-present`. |
| 2 | Build/publish scripts (`scripts/*.{cjs,mjs}`,
`packages/argent/scripts/*.cjs`, `packages/skills/scripts/install.js`) —
JS, never typechecked. `sync-readme.cjs` runs in `prepack`;
`postinstall.cjs` runs on every install; `bundle-tools.cjs` is
build-critical. A typo only surfaces at runtime. | Root
`tsconfig.scripts.json` with `allowJs` + `checkJs` + `noImplicitReturns`
covers all script paths. Root `typecheck:scripts` npm script. New CI
step. Per-file `// @ts-check` comments removed — tsconfig drives
inclusion. |
| 3 | `argent-cli` had no `typecheck:tests` script. When tests get added
there they'd silently bypass the gate. | Added `tsconfig.test.json` +
`typecheck:tests` script. `--if-present` would have skipped it anyway,
so this is future-proofing. |
| 4 | Local `prettier --check .` walked into the `argent-private`
submodule and reported violations there. CI didn't see this because
`actions/checkout@v4` doesn't init submodules — so local `prettier
--check` did not match CI behavior. | New `.prettierignore` excludes the
submodule plus `dist/`, `node_modules/`, lock files, `tsbuildinfo`.
No-op in CI; aligns local with remote. |

## Test type errors fixed

These were already present. The `npm test` passed because esbuild
stripped the offending types:

- **argent-installer**: widen `scope` literal type for
dead-code-elimination guard; non-null `addAllowlist!`/`removeAllowlist!`
(optional methods on adapter).
- **argent-mcp**: add `.js` extensions for NodeNext module resolution.
- **registry**: broaden `StaticBlueprintResult` blueprint api from `{
id; deps? }` to `Record<string, unknown>` so existing tests can pass
arbitrary api shapes.
- **tool-server**:
- non-null `zodSchema!` on tool defs that always carry one
(`launchAppTool`, `restartAppTool`, etc.)
- cast sentinel `"ignored"` strings to `DeviceInfo` in factory-rejection
tests
- match the 4-arg `dispatchByPlatform<IosServices, AndroidServices,
Params, Result>` signature (tests still passed the old 3-arg shape)
- `assertFlowRunResult` type guard for the `FlowRunResult |
FlowPrerequisiteNotice` union before `.steps` access
- swap broken `typeof import("supertest").default` for static `import
supertest` (supertest is `export = supertest`)
- fill in the 4 fields missing from a `NativeProfilerSessionApi` mock
(`xctraceProcess`, `recordingTimedOut`, `recordingExitedUnexpectedly`,
`lastExitInfo`)
- cast a vitest `Mock` to a plain function at one direct call site where
the `Procedure | Constructable` union loses callability
- fix `update-checker.test.ts` reading `../../package.json` (off-by-one
— went past tool-server; was relying on a Vite resolver quirk)
- replace one cross-package `../../../registry/src/index` import with
`@argent/registry` so registry's private `services` field isn't compared
between src and dist declarations

All fixes are type-level. Full `npm test --workspaces --if-present`
still reports **991 passed across 87 test files**.

</details>
2026-05-20 17:03:34 +02:00
Ignacy Łątka fbe7b087e7 chore(deps): batch-apply Dependabot updates (#214–#227) (#228)
This PR consolidates every open Dependabot PR that requires **no
source-code changes** into a single branch with one regenerated,
coherent lockfile.

| PR(s) | Update | Status |
|---|---|---|
| #214 | GitHub Actions group — checkout@v6, setup-node@v6,
setup-python@v6, github-script@v9, upload-artifact@v7 | ✅ Applied |
| #215 | prettier 3.8.3, @clack/prompts 1.4.0, semver 7.8.0, yaml 2.9.0,
@modelcontextprotocol/sdk 1.29.0, esbuild 0.28.0 | ✅ Applied |
| #216 / #221 / #224 / #227 | typescript 6.0.3 | ✅ Applied |
| #217 / #222 / #223 | @types/node 25.9.0 | ✅ Applied |
| #220 / #226 | vitest 4.1.6 | ✅ Applied |
| #218 / #225 | zod 4 | ⏸️ Excluded — requires code migration |
| #219 | express 5 | ⏸️ Excluded — requires code migration |
| #215 (partial) | tree-sitter 0.25.0 | ⏸️ Excluded — see below |

**tree-sitter 0.25.0** ships no prebuilt binaries and its `binding.gyp`
hard-codes `-std=c++17`, which fails to compile against Node 20+/24
C++20 `cppgc` headers — a hard `npm install` blocker (would also break
CI). Kept at `^0.21.1`; all other #215 updates applied.

zod 4 and express 5 are excluded here because they require real source
changes; tracked separately.

Verified: `tsc --build` clean, esbuild bundles, **1010 unit tests
pass**, **zero source files modified**.
2026-05-19 12:57:07 +02:00
filip131311 0dca6bbfef fix: build workspace deps before packing/publishing argent (#172)
## Summary
- The `publish` and `publish-next` workflows ran `npm run build -w
@swmansion/argent` directly, but after the recent CLI/MCP/main split,
`@swmansion/argent` imports types from `@argent/cli`, `@argent/mcp`,
`@argent/installer`, `@argent/tools-client`. Those packages expose types
from their own `dist/index.d.ts`, which doesn't exist until they're
built — so argent's `tsc` failed with `TS2307: Cannot find module
'@argent/...'` (e.g. [run
25161244218](https://github.com/software-mansion/argent/actions/runs/25161244218)).
- Added `npx tsc --build` before the per-workspace argent build in both
publish workflows so the sibling packages produce their `dist/` first.
This mirrors what `unit-tests.yml` already does, which is why the
regression didn't surface on PRs.
- Applied the same fix to the root `pack` script (`npm run pack`) since
it had the same latent bug for local packing.

## Test plan
- [x] Reproduced the failure locally by wiping every `dist/` and
`tsconfig.tsbuildinfo`, then running `npm run build -w
@swmansion/argent` — same four `TS2307` errors as CI.
- [x] Verified `npx tsc --build && npm run build -w @swmansion/argent`
succeeds from a clean state.
- [ ] Re-run the `Publish prerelease to npm (next)` workflow against
this branch (or after merge) to confirm green.
2026-04-30 12:57:28 +02:00
filip131311 e42308106c ci: add workflow to publish prereleases under npm next tag (#163)
## Summary
- Adds `.github/workflows/publish-next.yml`, a manual
`workflow_dispatch` workflow that publishes `@swmansion/argent` to npm
under the `next` dist-tag so users can opt into prereleases via `npm
install @swmansion/argent@next` without affecting `latest`.
- Mirrors the existing `publish.yml` (same checkout / native binaries
download / build / smoke checks); the only functional differences are
`npm publish --tag next` and a pre-publish guard that fails fast unless
`packages/argent/package.json` has a SemVer prerelease version (contains
`-`, e.g. `0.6.0-next.0`).

## Why
`npm publish` defaults to the `latest` dist-tag even for prerelease
SemVer versions. Without an explicit `--tag next`, a published
`0.6.0-next.0` would be served to anyone running `npm install
@swmansion/argent`. This workflow makes prerelease publishing safe and
explicit.

## Usage
1. On a release branch, bump `packages/argent/package.json` to e.g.
`0.6.0-next.0` and tag `v0.6.0-next.0` (the existing `release.yml` will
create a GitHub Release).
2. Run **Actions → Publish prerelease to npm (next) → Run workflow**
with `ref: v0.6.0-next.0`.
3. Verify with `npm dist-tag ls @swmansion/argent` — `latest` is
unchanged, `next` points at the new prerelease.

## Test plan
- [ ] Dry-run the workflow against a prerelease tag and confirm `npm
pack --dry-run` succeeds and the publish step runs `--tag next`.
- [ ] After a real prerelease publish, confirm `npm view
@swmansion/argent dist-tags` shows `next: <version>` and `latest` is
untouched.
- [ ] Sanity check the guard: trigger against a non-prerelease ref (e.g.
`v0.5.3`) and confirm the workflow fails at the "Verify package version
is a prerelease" step before running `npm publish`.
2026-04-28 08:41:09 +02:00
filip131311 6355620c4d refactor(mcp): split mcp package into argent, argent-cli, argent-installer, argent-mcp, argent-tools-client (#162)
## Summary

- Splits the monolithic `packages/mcp` package into five focused
packages:
- `argent` — the user-facing CLI entry (`argent` binary,
init/uninstall/update flows, bundled-paths, scripts).
- `argent-cli` — CLI runner internals (flag-parser, run, server, tools).
- `argent-installer` — `init`/`update`/`uninstall` flows, MCP config
adapters, skills installer.
- `argent-mcp` — MCP server itself (mcp-server, tool-mapping,
auto-screenshot, content adapters).
  - `argent-tools-client` — HTTP client + launcher for the tool-server.
- Adds Gemini agent definitions, VSCode MCP config, and per-package
`tsconfig.json` / `vitest.config.ts`.
- Updates root `tsconfig.json`, `scripts/dev.cjs`, CI workflows, and
`package.json` to wire the new packages together.

## Test plan

- [ ] `npm install` resolves the new workspaces cleanly
- [ ] `npm run build` succeeds across all packages
- [ ] `npm test` passes (renamed test files keep their assertions)
- [ ] `npx argent init` still produces the expected MCP config in a
sample project
- [ ] `npx argent update` / `argent uninstall` exercise the installer
package
- [ ] CI workflows (`publish.yml`, `unit-tests.yml`) run on this branch
2026-04-28 08:36:24 +02:00
filip131311 9fee899e5f chore: bump package versions to 0.5.3 for mcp, registry, skills, and tool-server (#149) 2026-04-20 17:51:14 +02:00
pFornagiel 066aad2452 fix: fix problematic CLI install, bump package versions to 0.5.2 for mcp, registry, skills, and tool-server 2026-04-16 17:47:25 +02:00
filip131311 1896097443 fix: pass GH_TOKEN to download steps in publish workflow (#142)
gh CLI requires GH_TOKEN to be set in GitHub Actions even for public
repos. Without it the download steps fail with exit code 4.
2026-04-16 17:10:55 +02:00
filip131311 3979e2780d bump version (#136)
* init

* chore: update package versions to 0.4.5 for registry, skills, and tool-server

---------

Co-authored-by: pFornagiel <pawel.fornagiel2@gmail.com>
2026-04-16 14:15:44 +02:00
filip131311 7db8305fff feat: pin native binaries to versioned release tags and publish to npm (#125)
- download-native-binaries.sh now requires an explicit release tag (e.g.
  argent-v0.4.3) and fails fast with a clear error if the release doesn't
  exist in argent-private-releases
- publish.yml is now manual-only (workflow_dispatch) with a ref input
  (branch/tag/SHA); derives the binaries tag as argent-{ref} and checks
  out the repo at that ref
- publish.yml now targets npm (registry.npmjs.org + NPM_TOKEN) instead
  of GitHub Packages
- download:native-binaries npm script auto-derives the tag from
  packages/mcp/package.json version for local pack:mcp usage
2026-04-15 16:26:55 +02:00
Filip131311 f30948fe46 feat: download native binaries from argent-private-releases instead of building locally 2026-04-15 11:41:10 +02:00
Filip131311 d082ea2fd2 feat: download simulator server 2026-04-14 15:09:58 +02:00
Ignacy Łątka 724ffc8ca5 ci: add prettier format check (#111)
* ci: add prettier format check workflow

* test: prettier err

* Revert "test: prettier err"

This reverts commit a5f7a18ddd.
2026-04-13 15:00:11 +02:00
Filip131311 faf6911801 Fix: removeing other dylibs injected into the simulator (simCam compatibility) 2026-04-10 16:38:55 +02:00
Paweł Fornagiel 82418eeb92 feat: AXService daemon, describe tool native-devtools path, and submodule bump (#98)
* feat: first implementation integration of ax-service for enhanced accessibility support

* feat: enhance ax-service with automation enablement and daemon management

* feat: export ensureAutomationEnabled function for improved accessibility automation in simulator server

* feat: add new build scripts for native development and update binary files

* feat: enhance describe tool to support native-devtools fallback and introduce DescribeResult interface

* chore: bump version to 0.4.1

* chore: bump argent-private to main; list ax-service in LICENSE

- Point packages/argent-private at current main and set submodule branch.
- Declare packages/native-devtools-ios/bin/ax-service as proprietary alongside simulator-server and dylibs.

Made-with: Cursor

* docs: document ax-service as proprietary across LICENSE and README

- Extend root README and CONTRIBUTING requirements (mcp README syncs from root at build).
- List bin/ax-service in @swmansion/argent and native-devtools-ios LICENSE.
- Assert ax-service is present and executable in publish workflow.

Made-with: Cursor

---------

Co-authored-by: Filip131311 <Filip.kaminski@swmansion.com>
2026-04-10 11:25:23 +02:00
filip131311 a1d2cf5b3b fix: restore GitHub Packages publishing fallback (#92)
Unblocks internal releases while npm private publishing is unavailable for the org by switching the publish workflow back to GitHub Packages.

Made-with: Cursor
2026-04-08 17:42:43 +02:00
filip131311 f65f2ce792 fix: use npm token for private npm publish (#91)
Bootstraps the first restricted npm release from GitHub Actions, which cannot complete interactive 2FA, and aligns the package version with the planned 0.4.0 tag.

Made-with: Cursor
2026-04-08 17:30:54 +02:00
filip131311 e8cb2e2d56 fix: publish private npm releases from GitHub Actions (#90)
Switch the release workflow from GitHub Packages to npm trusted publishing and validate the bundled native artifacts before publish.

Made-with: Cursor
2026-04-08 17:01:12 +02:00
Ignacy Łątka c41359937b fix: Rework descriptions to fix failing CIs (#80)
* rework descriptions

* add action guidance after restart required is returned

* change threshold to 9.0

* fix native devtools status desc
2026-04-07 19:12:39 +02:00
filip131311 d9dc17d0d5 fix: move describe to native devtools (#83)
* fix: move describe to native devtools

Replace the AX describe path with an app-scoped native hierarchy adapter so coordinate discovery stays on the supported injection flow.
Also add safer targeting and restart guidance to reduce ambiguous Home and cold-start recovery paths.

Made-with: Cursor

* init

* update sim server

* Delete NATIVE_DEVTOOLS_DESCRIBE_MIGRATION_NOTE.md
2026-04-07 17:36:56 +02:00
Filip131311 4e514c1435 chore: rename package from @software-mansion/argent to @swmansion/argent 2026-04-03 17:16:39 +02:00
Ignacy Łątka e8ed13bb51 ci: add unit test workflow for all TypeScript packages (#75)
* ci: add unit test workflow for all TypeScript packages

* fix: build only registry before running tests

The full tsc --build fails on CI due to pre-existing strict-mode
errors in tool-server source files. Vitest handles its own
transpilation, so we only need to build registry (the shared
dependency referenced via file: link) before running tests.

* fix: install rollup platform-specific binary for linux CI

npm ci has a known bug with optional dependencies where
platform-specific rollup binaries don't get installed.
Explicitly install the linux-x64-gnu binding as a workaround.

* fix: also build native-devtools-ios before running tests

The stop-tools test suite imports from @argent/native-devtools-ios
which is a local workspace package. Its dist/ must exist for Vitest
to resolve the import.
2026-04-03 15:19:51 +02:00
Filip131311 8c2a313c76 chore: format codebase with Prettier
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 14:53:58 +02:00
Ignacy Łątka 679c9b4300 ci: replace SpiderShield description score with custom weighted scoring (#71) 2026-04-01 22:22:52 +02:00
Ignacy Łątka 511b857cb6 ci: add MCP tool and SKILL description quality checks (#67)
* ci: add description quality workflow for tools and skills

Adds a GitHub Actions workflow that gates PRs on tool description quality
using SpiderShield (threshold 3.0/10 against current 3.3 baseline) and
informally grades skill SKILL.md frontmatter with a self-contained Node.js
grader. Includes extract-tools.mjs for converting ToolDefinition objects to
MCP tools/list JSON and grade-skills.mjs for scoring skill files.

* ci: fix profiler skill description and enforce 10.0 skill quality gate

* ci: split description quality into two separate scoped workflows

* ci: raise tool description quality gate to 10.0
2026-04-01 20:43:02 +02:00
pFornagiel 4224e39067 chore: add manual publish dispatch 2026-03-25 16:15:27 +01:00
Paweł Fornagiel 77dd289d78 feat: replace auto-postinstall with npx @software-mansion/argent install (#41)
* feat: add first implememntation of environment subagent

* chore: remove the irrelavnt skill from main project config

* feat: add rules support and enhance postinstall script for Argent tools (#23)

* feat: add first implememntation of environment subagent

* feat: enhance argent.md with environment inspection subagent details and workspace information retrieval guidelines

* feat: introduce argent.md with comprehensive guidelines for iOS simulator interactions and React Native workflows

* fix: fix postinstall script

* fix: fix Install Argent launch.json job

* feat: add environment inspector design document and research notes on MCP error signaling

* chore: update .gitignore to include MCP agents and rules directories

* fix: update `argent.md` rule with alwaysApply: true for cursor compatibility

* chore: remove mcp/rules from index

* feat: add basic npx flow

* feat: cicd for releasing the package as nmp through github

* fix: update package name references from @software-mansion-labs to @software-mansion in documentation and configuration files

* refactor: simplify postinstall script for @software-mansion/argent and update configuration instructions
2026-03-25 15:59:12 +01:00