## What
A new `tar-upload` file-input kind so a tool that reads a local file or
directory (e.g. `reinstall-app`'s app bundle) works when the tool-server
runs on a different machine than the caller.
## Why
`reinstall-app` assumes the bundle is on the tool-server's filesystem.
That breaks with a cloud-hosted simulator — the bundle is on your
machine, not the server's. The existing `file` kind inlines base64 and
is capped at 32 MB, too small for a real `.app`/`.apk`; `tar-upload`
streams instead.
## How
When you're not linked to a remote server, an existing local path is
used in place.
When you are (e.g. `argent link`), the client tars the path, streams it
to `POST /upload`, and the tool call carries `uploadId` plus a SHA-256
`contentHash`. The server always extracts from that upload — even if the
same path already exists on disk — verifies the hash, and vets tar
members before extracting.
The client only uploads when the path is on its own machine (a line on
stderr so you know it's working). Same command local or remote:
```
argent run reinstall-app --udid <udid> --bundleId <id> --appPath ./MyApp.app
```
## Shared extraction
Per review feedback, the tar pack/unpack logic is unified in a small
`@argent/archive` package used by **both** directions — this upload path
and the pre-existing artifact download (`streamDirectoryAsTarGz` /
`downloadAndExtractArchive`). The shared extractor rejects
path-traversal entries, symlinks whose target escapes the extract dir,
and non-file/dir members (hardlinks, devices) — while still allowing a
bundle's internal symlinks. This also hardens the artifact-download
path, which previously extracted without those checks.
## Tests
Client + server unit and HTTP round-trip tests: dir and file upload,
skip-when-not-local, co-located no-op, hash required, path-traversal /
escaping-symlink / hardlink rejection, sidecar handling, single-member
resolution, `/upload` auth + size caps, and artifact download
extraction. All suites pass.
---------
Co-authored-by: Filip131311 <contact@filipkaminski.com>
Adds a UI for proposing and choosing between multiple agent-generated
variants on a running app.
**MCP tools** (`packages/tool-server/src/tools/variants/`)
- `propose_variant` — non-blocking; agent stages a variant for an
on-screen element (text/label/identifier/role matcher).
- `await_user_selection` — one blocking call; parks until the human
submits, then returns the picks + free-form annotations + a global
comment.
**Preview UI** (`packages/ui`)
- Floating cards anchored to live element frames via the existing
`describe` tree, with connector lines.
- Comment-mode inspector: hover spotlight (blur+dim everything else),
right-click any element to pin a comment.
- Sticky padded hitbox + trajectory-aware dismissal so focus doesn't
drop on cursor jitter.
- Footbar [Complete] [Clear], confirm modal for destructive actions,
green toast on submit.
- Single source of feel constants in `theme.css`.
**Electron host** (`packages/preview-window`)
- New workspace package. Frameless transparent BrowserWindow at fixed
size; the squeeze open/close is a CSS `transform: scaleY` on `<html>`,
GPU-composited — no OS-level resize.
- Tool-server spawns it on `await_user_selection` park, reuses it across
re-awaits, and asks it to animate-close on submit (1s grace so the toast
is visible).
- Stdio-line IPC (no extra ports). Ephemeral throughout — the renderer
hits the tool-server's already-ephemeral `/preview/*` HTTP.
---------
Co-authored-by: Filip131311 <contact@filipkaminski.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
## Summary
- Introduces `@argent/configuration-core` as the shared source of truth
for feature-flag storage, the registry, and `isFlagEnabled`, so MCP and
CLI can import the same primitives without coupling runtime code to
CLI-only modules.
- Replaces `ARGENT_AUTO_SCREENSHOT` with the off-by-default
`disable-auto-screenshot` flag (auto-screenshot stays on unless enabled
via `argent enable disable-auto-screenshot`); renames
`ARGENT_AUTO_SHUTDOWN` to `ARGENT_TOOL_SERVER_SHUTDOWN_ON_MCP_EXIT`.
- Keeps `@argent/cli` as the command layer (`enable` / `disable` /
`flags`) with backward-compat re-exports, colored flag state output
(picocolors), and `--help` listings of available flags.
---------
Co-authored-by: Filip131311 <contact@filipkaminski.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
## Why
The tools-server shows an update reminder (a `note` appended to every
tool response) once a newer `@swmansion/argent` lands on npm. Two pain
points:
1. **No way to turn it off.** Suppression is in-memory only
(`dismiss-update`, 30-min auto), so it comes back on every server
restart.
2. **It nags about versions you can't install yet.** Registries with a
**minimum-release-age** (package-cooldown) security policy refuse to
install a version until it has been public for N days. Until then the
reminder repeats every day for the whole cooldown window with nothing
the user can do about it — exactly the "reminded for 5+ days" situation.
## What's in this PR
**1. A config option to disable the reminder**
- New env var **`ARGENT_DISABLE_UPDATE_NOTIFICATIONS=1`** (`"1"` or
`"true"`).
- When set, `startUpdateChecker()` is a no-op: **no registry request**
is made and **no note** is ever attached.
- The opt-out is also surfaced inside the reminder text itself, so the
agent can tell the user how to silence it permanently.
**2. Minimum-release-age awareness** (answers "detect the policy and
check the update is actually installable first")
- The checker now fetches the **npm packument**
(`registry.npmjs.org/@swmansion/argent`) instead of `/latest`, because
only the packument carries the `time` map of version → publish
timestamp.
- It detects the machine's policy and only reminds once the latest
version has **aged past** it. Notification is gated on a new
**`updateInstallable`** flag (newer **and** old enough) rather than
`updateAvailable`.
- `updateAvailable` keeps its pure version-comparison meaning; with no
policy, `updateInstallable === updateAvailable` (no behavior change for
users without a policy).
### Is detecting the user's min-age policy possible? Yes — partially.
Each package manager stores it differently, and the tools-server has no
reliable signal for *which* PM installed argent, so we probe every PM
present and take the **most restrictive** (largest) value. Erring toward
over-waiting is intentional: a slightly late reminder beats nagging
about a forbidden version.
| PM | Config key | Unit | Detect via | Min PM version |
|----|-----------|------|-----------|----------------|
| npm | `min-release-age` | days | `npm config get min-release-age` |
11.10.0 |
| pnpm | `minimumReleaseAge` | minutes | `pnpm config get
minimumReleaseAge` | 10.16 |
| yarn (berry) | `npmMinimalAgeGate` | minutes | `yarn config get
npmMinimalAgeGate` | 4.10 |
| bun | `minimumReleaseAge` (bunfig.toml `[install]`) | seconds | no
`config get` — not auto-probed | 1.3 |
| yarn classic | — (unsupported) | — | — | — |
Because bun has no `config get` for this and auto-detection is
best-effort, there's also an explicit override:
- **`ARGENT_MIN_RELEASE_AGE_DAYS`** — positive number of days; wins
outright and skips probing (useful for bun users, locked-down CI, or
pinning the value).
When a policy holds an update back, a single stderr line explains the
silence; no reminder reaches the agent.
## Conservative edge handling
- Network/registry failure → state unchanged (never crashes the server).
- Policy in effect but publish time missing/unparseable → treated as
**not** installable (stay silent rather than nag).
- PM probe errors / PM absent → treated as no policy (0).
- Probes shell out via PATH (`exec`, 3s timeout, constant commands only
— no caller input) so Windows `.cmd`/`.ps1` shims resolve.
## Tests
- `test/min-release-age.test.ts` (new): unit-level parsing, override
precedence, unit normalization, most-restrictive-wins, PM-absent.
- `test/update-checker.test.ts`: rewritten for the packument shape; new
cases for held-by-policy, aged-past-policy, unknown publish time, and
the disable flag (probe mocked so tests never spawn a real PM).
- `test/http-update-note.test.ts`: gate now keys off
`updateInstallable`; added a "available but held by policy → no note"
case.
- Full tool-server suite green (**732 tests**), `tsc --noEmit` and
`typecheck:tests` clean.
## Follow-up (not in this PR)
The env-var reference lives in the `argent-private` submodule
(`docs/environment-variables.md`), which is a separate repo — needs a
companion PR. Suggested rows for the tools-server table:
```
| `ARGENT_DISABLE_UPDATE_NOTIFICATIONS` | `"1"`/`"true"` or unset | disabled | When truthy, disables the update reminder entirely (no registry check, no note). |
| `ARGENT_MIN_RELEASE_AGE_DAYS` | number | _(auto-detect)_ | Minimum age (days) a newer version must reach before it is advertised. Overrides auto-detection of the npm/pnpm/yarn minimum-release-age policy. |
```
## Open questions for review
- **Most-restrictive-across-PMs** vs. detecting a single PM — is "max
wins" the behavior we want, or should it follow `npm_config_user_agent`?
- Should an update held by policy stay fully silent (current), or emit a
softened "available, installable in ~N days" note?
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
## Summary
- `formatDescribeTree` was branching on `source === "uiautomator"` to
pick nested rendering; the newer `android-devtools` source fell through
to flat mode and lost every node below depth 1. Extends the predicate to
cover both Android sources so the helper-service path renders with the
same hierarchy as the legacy `uiautomator dump` path.
- Bumps `packages/argent-private` to pick up the persistent Android
describe service that emits `source: "android-devtools"`, plus its
build-and-sign CI workflow.
- Wires the Android helper APK + `manifest.json` into the published
`@swmansion/argent` package via `bundle-tools.cjs`, and adds
`pack:mcp:local` / `build:android-binaries` so a local tarball can be
produced without going through `download:native-binaries`.
- Minor: tightens a couple of comments in `android-helper-install.ts`
and `format-tree.ts`.
This is connected to argent-private PR:
https://github.com/software-mansion/argent-private/pull/8
`tsc --build` fails to resolve `@argent/registry` and
`@argent/native-devtools-ios` because neither package was listed in the
root or tool-server tsconfig references. This broke `npm run build` and
`npm run pack:mcp` after native-devtools-ios was introduced.
- packages/mcp: thin MCP stdio bridge that discovers tools dynamically
from GET /tools and proxies calls; screenshot outputHint fetches PNG
and returns base64 image content to the MCP client
- packages/skills: 4 Claude Code skills for simulator setup, screenshot,
interaction, and UI test flow automation
- packages/tools: 7 new interaction tools (screenshot, tap, swipe,
gesture, button, paste, rotate) all using ensureServer() for
transparent auto-spawn
- simulator-registry.ts: unified process + WebSocket registry shared
across all tools
- Fix zodTypeToJsonSchema to preserve .describe() text and handle
ZodEnum/ZodObject; add outputHint to Tool interface and registry.list()
- .claude/mcp.json: registers radon-lite MCP server for Claude Code
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The tools server (port 3001) supersedes the original Express server.
packages/tools and packages/ui have no imports from packages/server,
and the vscode extension never used the dependency either.
- Delete packages/server/ (src, tests, openapi spec, duplicate binary)
- Remove build:server, start, dev scripts from root package.json
- Remove packages/server reference from root tsconfig.json
- Remove @radon-lite/server dependency from packages/vscode/package.json
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move server code to packages/server/, add placeholder packages for
packages/ui and packages/vscode. Add tsconfig.base.json with shared
compiler options and root tsconfig.json with project references.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Express/TypeScript HTTP server that wraps the simulator-server binary to
expose a clean REST API for controlling iOS simulators. Supports session
management, MJPEG screen streaming, screenshots, screen recording, replay
ring buffer, full input control (touch/key/button/rotate/paste/scroll),
JWT token management with Radon portal activation, and SSE event streams.
Configurable replay and showTouches features via CLI args or env vars.