mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
fix/docs-high-severity
73 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c2324f052d |
feat(telemetry): project-scope opt-out (restrictive merge) + init --local --no-telemetry (#952)
## Why
Teams that must not send usage data to a third party (a
strict-compliance customer asked) had no way to turn telemetry off for a
repository. `telemetry.enabled` was global-only
(`~/.argent/config.json`), so a committed local install (`init --local`)
still defaulted every teammate to **on** — `--no-telemetry` only opted
out the machine that ran `init`.
## What
- **`telemetry.enabled` accepts the project scope.** `consent.ts` now
reads both `~/.argent/config.json` and
`<project-root>/.argent/config.json` (root resolved from `cwd`, per-file
cache keyed by path) and merges **restrictively**: `false` in either
document wins. A committed project opt-out holds on every clone, and a
project file can never re-enable a global opt-out. Env overrides
(`DO_NOT_TRACK`, `ARGENT_TELEMETRY`) still outrank both.
- **`argent telemetry enable|disable --scope global|project`** (default
`global`). `status` names the document that decided (`config.json
(project)`, `(global)`, `(project and global)`). `enable` at one scope
while the other still opts out reports that telemetry stays disabled
instead of claiming success. Unknown scope / argument → exit 2, nothing
written.
- **`argent init --local --no-telemetry`** also writes
`telemetry.enabled: false` to `.argent/config.json`, and the "commit
these files" checklist lists it. Global mode is unchanged.
- `argent config set/unset telemetry.enabled` stays delegated to `argent
telemetry` (`manageCommand`), so the lifecycle work (draining the live
client) is still done by the dedicated command.
## Tests
Unit: `telemetry` (+8 project-scope cases: single-scope opt-out, both
restrictive directions, both-off, env precedence, live re-read of the
project file, malformed project file), `configuration-core` (schema
scopes), new `argent-cli/test/telemetry-command.test.ts` (real-fs, 6
cases), `argent-installer` — all green; eslint, prettier, knip,
`docusaurus build` green.
Live, from a real `npm pack` tarball of this branch (sandboxed `HOME`):
1. Fresh project → `init --local --yes --no-telemetry --from <tgz>`:
writes `.argent/config.json` `{telemetry:{enabled:false}}` + global
opt-out; summary lists `.argent/config.json` to commit.
2. `telemetry status` → `disabled`, source `config.json (project and
global)`. `telemetry enable` (global) → "stays disabled: config.json
(project) still opts out"; from `~` (no project) → `enabled`. `enable
--scope project` → enabled; `disable --scope project` → disabled.
`--scope team` → exit 2.
3. **Teammate simulation**: copied only the committed files to a fresh
clone with a fresh `HOME` (no global opt-out), bundle built with a dummy
OTLP token, `ARGENT_TELEMETRY_DEBUG=1`, drove `argent mcp` (initialize →
tools/list → `list-devices` call). Control clone without
`.argent/config.json`: tool-server emitted `toolserver:start`,
`tool:invoke`, `tool:complete`, `toolserver:stop`. Clone with the
committed opt-out: **0 events**, and the first-run telemetry notice is
not printed.
## Caveat (documented)
The project file is resolved from the working directory of the process.
Editors start the MCP server in the workspace root, so it and the
tool-server it launches read it. The tool-server is shared by every
editor on the machine and reads the project file of the workspace that
started it; the global opt-out or `DO_NOT_TRACK` still covers the
machine-wide case.
## Docs
Updated in this PR: `reference/configuration.mdx` (scopes + merge
wording), `reference/telemetry.mdx` (new "Opt out for a whole
repository" section), `reference/cli.mdx` (`init`, `telemetry` rows),
`fundamentals/installation.mdx` (`--no-telemetry` in local mode).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01BkkAihA8Kp26hHS4uhkNGu
|
||
|
|
50c9580e30 |
fix(tools): make a schema failure name the parameter that was sent (#718)
> Stacked on #717. ## The problem An invalid tool call returned Zod's raw issue array. Someone who wrote `flow_name` instead of `name` got back, depending on the tool: ``` Invalid params for tool "flow-start-recording": [{"expected":"string","code":"invalid_type","path":["name"]}] Invalid params for tool "flow-execute": [{"code":"custom","path":["flow_path"],"message":"Pass exactly one flow source: name or flow_path."}] ``` The first names the parameter the tool **wanted** and never the one the caller **sent**. The second — flow-execute's, whose `name` is optional so `flow_path` can stand in — names neither: it is anchored on the one source field the caller had no reason to send. Either way the mistake is invisible, and working it out costs a whole turn. ## What changes **1. `describeParamIssues` — one sentence per bad parameter.** Missing fields read as `` `name` is required (string) and was not provided`` rather than as a type error about `undefined`. Unknown keys are named and path-qualified, so a key nested in `selector` is not reported as a bare name that contradicts the top-level list printed beside it. The message closes with the caller's own keys — `You sent: \`flow_name\`, \`project_root\`.` — which is what makes the mistake self-evident. Key names only, never values: this string reaches logs, telemetry and the agent transcript, and a params object can carry a secret. Wired into both entry points: the registry's `invokeTool` and the HTTP boundary. **2. `flow-execute` accepts `flow_name` as an alias for `name`.** The tool is called `flow-execute`, so "the flow's name" spells itself that way; this is a mistake worth absorbing rather than rejecting. The name is resolved in code rather than by the schema — a Zod `required` failure would once again name only the field it wanted — and the error text names the spellings that are silently discarded (`flowName`, `flow`, `flow_file`), because by then Zod has already stripped them and the caller has no other way to learn their key was dropped. **3. A flow DIRECTIVE passed as `command` points at the tool that records it.** `command: "echo"` used to come back as a bare "Tool not found". It now names `flow-add-echo` — and says to call it **directly**, since routing it through the recorder would write the echo *and* a `tool: flow-add-echo` step that fails on every replay. The hint distinguishes directives the recorder **rewrites** from those it stores **raw** for the polish pass, because promising a rewrite that does not happen sends the author looking for a directive that is not in the file. `wait` and `long-press` get their own answers: neither has a recording tool at all. Only a genuine not-found is rewritten — a tool that ran and failed still reports its own error. **4. A recorder tool as `command` is refused.** `flow-add-echo`, `flow-add-step`, `flow-start-recording`, `flow-finish-recording` each mutate the recording itself, and nesting one reported success either way. Each is refused for its own reason: `flow-add-echo` would write the echo **and** a replay-breaking `tool:` step, `flow-start-recording` would **erase** this flow at replay, `flow-finish-recording` would end the take it is a step in, and `flow-add-step` cannot record itself. Now nothing is executed and nothing is written. --------- Co-authored-by: Hubert Gancarczyk <claude-hubert.gancarczyk@swmansion.com> |
||
|
|
b232114422 |
docs: audit every comment in src against the code it describes (#931)
Audits every comment in `src/` and `scripts/` against the code it
describes.
**462 files, 57 commits, net −8,194 lines.** Comment text only — the
whole branch is code-identical to `main`.
## Method
One subagent per file, strictly sequential. Scope was `src/` +
`scripts/` (459 files); three more files were added at the end because
they carried dead references of the same kind — two test headers citing
design docs that do not exist, and `publish-npm.yml` citing a retired
workflow. Each agent verified every comment — line, block, JSDoc, file
header, trailing — against the surrounding code and the rest of the
repo, following identifiers, paths, tool ids, config keys, env vars and
issue links to see whether they still exist and still behave as
described. Rules:
- **A false or misleading comment is deleted, not reworded.** If a claim
could not be confirmed by reading the source, it went. That is why the
deletion count is so much larger than the rewrite count.
- Survivors are cut to the shortest form carrying something the code
does not already say. Restatement, preamble, hedging, changelog prose
and ASCII banners are gone; the non-obvious *why* stays.
- Preserved byte-identical: license headers, pragmas and directives
(`@ts-*`, `eslint-disable`, shebangs, `/// <reference>`), JSDoc tag
tokens, everything inside a string or template literal, and the sole
comment inside an otherwise empty block (ESLint `no-empty` counts a
comment-bearing block as non-empty).
## Verification
Every file passed two independent gates before being recorded as done:
1. `comments-only` — the required check.
2. A second comment-stripping comparator with a proper mode stack,
written for this pass because `comments-only`'s flat scanner desyncs on
nested template literals and quote-bearing regex literals and then
reports comment lines as code changes. Two files hit that false FAIL
(`utils/android-profiler/pipeline/index.ts`,
`scripts/extract-tools.mjs`); in both the "changed code" it printed was
literally `//` lines, and the second checker confirmed the code was
byte-identical.
After the last file, all 462 changed files were re-checked against
`main` with the same comparator, rather than trusting any agent's
self-report. **459 code-identical; 2 are non-code (`.svg`, `.md`); 1
intentional.**
The intentional one is `packages/argent/scripts/bundle-tools.cjs`: the
changed template literal *is* the comment header of the file it
generates, `packages/native-devtools-android/src/bundled-meta.ts`.
Fixing only the generated file would have been reverted by the next
build, so the generator changed too — and it has been verified to
reproduce the committed generated file byte-for-byte.
## Representative false claims removed
Not wording nits — statements a reader would have acted on:
- **Reversed directions.** `proxyStart`'s JSDoc had the tunnel backwards
(it is a reverse tunnel: the host binds first and the simulator dials
in). A `paste()` doc had the pasteboard copy direction reversed.
- **Contradicted by the code below it.** A timeout budget multiplied by
three where the probes run concurrently — the same comment said so six
lines later. A "warn once" that warns on every call. A "binary search"
that is a linear scan.
- **Named things that do not exist.** A `vega-fast-cli` binary, a
`finish-recording.ts`, a `publish-next.yml` workflow, two
`profiler-react19-*.md` design docs, a `DebuggerTarget.ts`, a commit
hash git does not know, two tool ids, an `ensureEnv` cycle.
- **Wrong by construction.** "Welford accumulators" across four files
where the code keeps naive `n`/`sum`/`sumSq`; `sum`/`sumSq` documented
over `actualDuration` when reduce sums `selfDuration`; a strict-mode
halving written `n/2` where the code ceils; field docs listing enum
values the producers never emit.
- **Guarantees the code does not make.** A validation matrix claiming to
cover "EVERY tool" that skips flagless ones; a Pareto cutoff that
`slice(0, 20)` makes inert; an idempotence claim where the real rule is
at-or-ahead; a capability note describing a clean 400 the shape-based
device resolver can never produce.
- **Unverifiable assertions** about prebuilt binaries, external CLIs and
the cloud SDK — deleted rather than kept as folklore, since nothing in
the repo can confirm them.
- **Stale numbers**: invented Android tool versions, hard-coded tool
counts and description lengths that had drifted.
## Review
A Fable agent reviewed both halves adversarially for over-deletion,
misread code, `no-empty` hazards and byte-identity violations.
Second-half verdict: **SHIP**, with two one-line restores, both applied
in the final commit — the `npm view ""` rationale behind a blank-token
guard, and the note that `argent-mcp` keeps a copy of
`SECRET_PLACEHOLDER_MARKER` it cannot import.
## Code issues surfaced but deliberately not fixed
This pass changes comments only. Eight genuine findings are logged for a
follow-up:
1. `telemetry/src/consent.ts` — a non-ENOENT read error returns null and
falls through to the default-on path, so file errors *can* silently flip
telemetry on.
2. `chromium-server/navigation.ts` — `navigate()` is reachable from
`POST /api/navigate` with only a `typeof === "string"` check; open-url's
schema is a bare `z.string()`, so the "already validated by zod" premise
never held.
3. `http.ts` — `constantTimeEqual` returns early on a length mismatch,
so the auth token's length is observable.
4. `describe/index.ts:~114` — the ios-remote branch passes `{ isTvOs:
false }` unconditionally, so a remote tvOS simulator takes the iOS
ax-service path, though `isRemoteTvOsSimulator` exists and shake/paste
do use it.
5. `devices/boot-device.ts` — `-crash-report-mode never` is passed
unconditionally *and* appended again by the feature-detecting path, so
every emulator spawn passes it twice.
6. `react-profiler/pipeline/04-rank.ts` — `PARETO_THRESHOLD_PCT` is
dead: `slice(0, 20)` always wins.
7. `reaped-sessions.ts` — a user-facing hint string tells the agent that
`react-profiler-start { force: true }` disposes the debugger and
profiler session; it does not. Left byte-identical because it is a
string literal, not a comment.
8. `utils/simctl-backend.ts` — `localSimctl` is exported with no
importers anywhere.
## Docs
No documentation change is needed: this pass touches only source
comments, and no user-facing capability, tool, CLI flag, config key or
flow-file behaviour changed.
---------
Co-authored-by: filip131311 <f.kaminski2000@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
||
|
|
366f17c619 |
chore: bump version to 0.22.0 (#891)
Bumps every workspace package, `package-lock.json`, and both `server.json` version fields from 0.21.0 to 0.22.0 (18 files). Lockfile regenerated on Node 24 / npm 11 so the diff is version-only; `npm run check:versions` passes. Covers everything on main since `v0.21.0`: `paste` tool (#879), rotation-aware Android capture (#693), 0.25 default screenshot scale (#878), no-reboot describe on externally booted sims (#583/#877), NDJSON flow progress (#855), OTLP telemetry (#570), native-devtools restart_required derivation (#560), Android profiler empty-CPU explanation (#669), plus test/CI fixes. Full-surface live QA of this main (tgz vs npm 0.21.0) on iOS, Android, tvOS, Electron, CLI and Linux/remote found zero regressions. Two release notes: the published artifact must be built with `ARGENT_OTEL_INGEST_TOKEN` set (a local tgz without it compiles `readIngestToken()` to an empty string, making telemetry a silent no-op), and remember to push the `v0.22.0` git tag so online `init` skills installs resolve. No docs update needed: version-only change. |
||
|
|
dd5d823833 |
feat(flow): stream run progress as NDJSON (#855)
## Summary - add `argent flow run --json-stream` - stream flow progress as JSON lines - finish with a JSON result or error ## Why `--json` prints only after a flow finishes. `--json-stream` lets scripts and CI see live progress. ## Why this is a separate PR This is useful without the custom-tools feature in #856. ## Validation - `npm test -w @argent/cli -- flow.test.ts` — 106 tests passed - `npm run typecheck:tests -w @argent/cli` - `npm run build -w @argent/cli` --------- Co-authored-by: Filip131311 <contact@filipkaminski.com> |
||
|
|
5d8fc10799 |
test: stop tests binding machine-wide resources they do not own (#714)
## Why Three flaky or failing tests were diagnosed separately this week, and all three turned out to be one defect wearing different clothes: **a test binding a machine-wide resource it does not own**, so a second concurrent run — another checkout, a CI matrix cell, a developer's own app — perturbs it. Those three are fixed in #707, #709 and #711. Each of those was found by chasing a symptom, and each audit covered only its own resource type. This is the systematic sweep: all **448 test files across 13 packages**, plus the 4 `node --test` scripts. (The sweep itself ran over the 400 files that existed when it started; merging `main` brought the count to 448, and every category below was re-run over the full set — 25 files assign `env.HOME` and none omit `USERPROFILE`, one test file calls `pkill`/`pgrep` (`vega-cli-timeout.test.ts`, scoped out to #711 below), and no `listen()` names a fixed port.) ## Findings | Category | Files checked | Real findings | |---|---|---| | Network endpoints (bind / probe / unix socket) | 448 | 4 | | Filesystem — shared temp namespace (`os.tmpdir()` and literal `/tmp`) | 448 | 8 | | Filesystem — real `$HOME` / `~/.argent` | 448 | 4 (28 files) | | Ambient environment | 448 + all `src` readers | 12 | | Device / emulator / SDK state | 448 | 2 | | Process table (`pgrep` / `pkill` / fixed-pattern sweeps) | 448 | **0** | | In-process globals leaking across files | 13 packages × 13 modes | **0** | Every finding was reproduced with a concrete instrument before being touched, and the instrument re-run after. Representative: - **`stop-tools.test.ts`** ran the real `stop-metro` against port 59999, which `lsof`s and **SIGTERMs whatever it finds**. With a squatter there: `16 passed` → `1 failed`, and the squatter logged `received SIGTERM #1`. Now port 1. - **`bind-failure-telemetry` / `lens-relay-telemetry`** were gated on the real `~/.argent/flags.json`. Enabling the documented `tool-server-event-log` flag: `4 passed` → **`4 failed`**, and records were appended to the developer's real event log. - **LogFileWriter (12 files)** — its constructor `mkdir -p`s `os.homedir()/.argent/tmp`. Instrument: run each of the 16 test files that reference a writer, or a blueprint that builds one, under a scratch `HOME`/`USERPROFILE`, then test `$HOME/.argent/tmp` for existence. 4 created it; the 12 that actually construct a writer now all call `scopeTempHome`, and none creates it. - **`screen-recording.test.ts`** — the device ids are fixtures and `vi.useFakeTimers()` seeds its clock from the real time, so only the millisecond a run starts in separates two runs' `.mp4` paths, and each test deletes the path it derived. Self-concurrent: **2 of 3 rounds failed** → 0 of 4. Scoping `TMPDIR` removes the window rather than narrowing it. - **`DO_NOT_TRACK=1`** → telemetry `282 passed` → **`13 failed`**. **`npm_config_user_agent=pnpm|yarn|bun`** → installer `535 passed` → 4/5/3 failed. **19 tests required a real `adb`** — PATH shadow + empty HOME: `30 passed` → **`19 failed`**. - A fixed `/tmp/argent-nd-<udid8>.sock` **destroyed a concurrent holder's live socket** (proven by inode) in **3** files that run the native-devtools factory. Two of them also fail outright: `native-devtools-app-state` lost **3 of 3** rounds of two concurrent runs on `expected 'unregistered' to be 'connected'`. All three now derive the UDID from `process.pid`. - `flow-visual`, `react-profiler/dump`, `file-inputs`, `http-upload` — shared `/tmp` paths and prefix scans, each reproduced with a squatter. In `http-upload` the collision surfaced *as a timeout*, inside `vi.waitFor`. (`flow-chromium-boot` was fixed on this branch too, but main's #585 rewrote that file afterwards and the merge kept main's copy, so it is byte-identical to `origin/main` here and carries no fix.) ## Clean, with the evidence - **Process table** — an `LD_PRELOAD` exec interposer over a full run (507 execs) plus all 12 other suites. Excluding `vega-cli-timeout.test.ts`, which is #711's and does sweep the table (`pkill -f '^sleep 6910[0-9]$'` at line 134): no `pgrep`/`pkill`/`killall`/fixed-pattern sweep anywhere, and **no test signals a pid it did not spawn**. - **Real device state** — **zero** exec attempts of real `adb` / `simctl` / `emulator` / `avdmanager` / `vega`; no test asserts a device list. That list was too narrow: `workspace-reader-integration` spawned the real `yarn` / `pnpm` / `bun` / `pod` / `eas` / `expo`, which is the second finding in this row. - **Cross-file in-process leakage** — structurally impossible: vitest 4.1.9 resolves `pool: "forks"` / `isolate: true`, confirmed by a scratch experiment (distinct pids, no env leak, module `Map` = 1,1,1). 120 default-mode runs across 12 packages produced 1 failure. - **`scripts/`** — 4 files, 86 tests: `mkdtemp` throughout, no ports, no sweeps, writes nothing. ## Verification Each fix was mutated back and killed by a **named** test under its instrument — e.g. `× reads a plain absolute path`, `× returns null when only the extensionless binary exists`, `× pins both names os.homedir() consults, at the same directory`. Restores verified with `git diff` / `git status`, never a substring grep. **Pinned by an instrument only:** the socket fix for `ios-only-blueprint-gate`, the `~/.argent/tmp` and `~/.argent/flags.json` fixes, the `/tmp` fixture cleanup, the `stop-metro` port change (the test asserts `stopped: false` / `pids: []`, which hold for either port whenever nothing is listening) and the `workspace-reader` `PATH` pin (only `node` is asserted; the other seven probes are not) are not pinned by any suite assertion — reverting them still passes, and only the external squatter / scratch-`HOME` instruments catch them. They are pollution fixes. The `native-devtools-app-state` socket fix is the exception in the other direction: reverting it turns two concurrent runs red. Gates, unpiped and read by exit code: `eslint .` 0, `prettier --check .` 0, `tsc --build` 0, `typecheck:tests` 0. Suite, run as six shards: tool-server **4287 passed, 1 skipped, 0 failed**; argent-cli 462; telemetry 306; argent-tools-client 191; configuration-core 122; argent-mcp 80; argent-installer 555. All other packages and `test:scripts` green, identical to baseline. `lens-tools-platform-gate.test.ts` times out at the 5s default under full-suite load and passes at `--testTimeout=30000` (24.7s, almost all of it transform). It predates this branch and is untouched by it. ## Scope This branch is **test-only** — no `src/` file is touched. Both production defects the sweep turned up are separated out, so each can be reviewed as the user-facing fix it is: `ps` without `-ww` orphaning live tool-servers is #713, and #852 is `ensureToolsServer` respawning on every call when `ARGENT_HOST` is exported — `buildToolsServerEnv` passes the inherited value to the child while the state records the literal `127.0.0.1` the health check then probes. The second surfaced here as eight stranded `fake-tool-server` processes, and pinning the environment in this branch removes that signal, which is why it is filed rather than merely worked around. A third, outside this branch entirely, is #853: ten `tool-server` test servers omit the host on `listen(0)`, binding every interface where twenty-two sibling sites pass `127.0.0.1`. It is hardening, not a live exposure — `createHttpApp`'s Host allow-list answers a LAN-addressed request with 403, and only a raw client forging `Host: 127.0.0.1` reaches the stub registry behind it, inside the ~100 ms one `it()` holds the socket. It is also not a collision risk: ephemeral ports are kernel-assigned and never reissued while in use, which is why the fixed-port audit above is unaffected. All ten predate this branch. Left untouched on purpose: `boot-electron-spawn-error.test.ts`, `chromium-discovery.test.ts` and `vega-cli-timeout.test.ts` — owned by the still-open #709 and #711, and all three still carrying their defects on this base. (#707 has since merged into this base, so `boot-device-hotboot.test.ts` and `vitest.config.ts` carry its fix rather than a defect; `test/setup/clear-argent-env.ts` is its work, and this branch relies on it.) **Not fixed, deliberately** — an adjacent class (test-*order* dependence, not machine-global resources), reproducible if wanted: `link-config.test.ts` (deterministic: `-t "returns null when required field"` → 4 failed), `network/network-integration.test.ts` and `android-perfetto/dispatch.test.ts` (fail under `--sequence.shuffle` seeds). **Also observed, not addressed:** one green tool-server run leaves **56** entries behind in a scratch `TMPDIR` — **30** in the `argent-screenshot-diff*` family, 4 `argent-events-*`, 3 `argent-flow-crop-*`, 3 `argent-tar-upload-*`, 2 `argent-flow-diff-*`, 2 `argent-file-input-*`, and 12 assorted singletons (`ast-index-*`, `component-source-*`, `argent-profiler-cwd`, `argent-chromium-media`, …). Measured per run against a scoped temp dir, so it ranks the contributors rather than counting one machine's accumulated history — screenshot-diff, not flow-crop, is the dominant one. A separate leak. That instrument is blind to a *literal* path, which is how it missed the two `/tmp/native-profiler-*-report.md` writers the fourth pass found. Re-run across all 13 packages, `argent-mcp` is the only one outside `tool-server` that leaves anything — two entries per run, filed as #854. ## Second pass A review of this branch re-ran every category above with its own instrument rather than reading the diff, and found the sweep had pinned four resources in one file while leaving a sibling that does the same thing live. Fixed in `4289e3d8f` and `8164955b4`; the table and bullets above are the corrected totals. - **`tool-server-event-log`** was mocked off in 2 of the 4 files that call the real `start()`. With the flag on, `startup-telemetry` and `tool-fail-invalid-params-emission` failed 3 tests in `attachRegistryEventLogger` and truncated the real `~/.argent/tool-server-events.jsonl` to 0 bytes first. `ARGENT_EVENT_LOG` cannot redirect that: `test/setup/clear-argent-env.ts` strips every `ARGENT_*` var before the module graph loads. - **`scopeTempHome`** reached 8 files; 4 more built a real `LogFileWriter` through the JS-runtime-debugger blueprint. - **`os.homedir()` on Windows** reads `USERPROFILE`, not `HOME`. `android-binary-windows` and `adb-resolve-avd-path` pinned only `HOME`, and both run on a real windows-latest host. Proven by running the resolver under a `node:os` mock that reproduces the Windows lookup: with `HOME` alone the stock Studio SDK under the profile resolves; with both pinned it misses. `update-checker` had the same gap. - **`getConsentState`** honours a falsy `ARGENT_TELEMETRY` at the same precedence as `DO_NOT_TRACK`, ahead of the config override the suite writes. Only `DO_NOT_TRACK` was pinned: `ARGENT_TELEMETRY=0` gave `17 failed | 6 passed`. - **`workspace-reader-integration`** let the version probe spawn the real package managers off `PATH`; their shims self-install, so the file pulled **~44 MB** into `~/.cache/node/corepack` and `~/Library/Caches/eas-cli`. `PATH` is now a directory holding only `node`, the one version the test asserts — 44 MB → 4 KB. - **`argent-mcp`** snapshotted `ARGENT_AUTO_SCREENSHOT_DELAY_MS` without clearing it, and that package has no `ARGENT_*`-stripping setup file, so 3 tests asserted the developer's exported value. Smaller items in the same commits: the `/tmp` socket fixtures now remove the directories they create per run; `http-upload`'s pre-scan snapshot is gone, since scoping `TMPDIR` to a fresh directory made it permanently empty and its filter inert, as its two siblings already did; and two `detectProjectPackageManager` assertions that enumerated the entire return union are pinned to a single value. The confirmation pass also caught a defect the first round of fixes introduced: pinning `HOME`/`USERPROFILE` to the fixture root in `android-binary-windows` let `<home>/Android/Sdk` shadow the `%LOCALAPPDATA%` root the two positive tests are named after, so deleting `roots.push(join(localAppData, …))` from the resolver left all three green. Home has its own directory in `6aee3ee7a`, and that mutation now fails both tests. A third pass, running the nearest-twin move repo-wide, found the `os.homedir()`-on-Windows gap in one more package: eight `argent-tools-client` test files redirect only `HOME`, and four of them recursively delete `STATE_DIR` — two before each test, two after — which on Windows is the developer's real `%USERPROFILE%\.argent`. Fixed in `139447d4a`, together with the same gap in `avd-snapshot`. Nothing runs that package on Windows CI today, so no current run fires it. ## Fourth pass A fourth pass audited the three fix commits and re-ran the sweep with two instruments the earlier ones did not have. Both holes were in the *measurement*, not the diff — which is why three passes missed what they found. Fixed in `a67c43f8d`. - **`os.tmpdir()` does not read the same variable on every platform.** POSIX takes `TMPDIR`, `TMP`, `TEMP` in that order; Windows takes `TEMP`, then `TMP`, and never looks at `TMPDIR`. The five pins this branch added set `TMPDIR` alone, so on Windows production still materialized into the machine-wide `%TEMP%` while the test scanned a scratch directory nothing ever wrote to — and `file-inputs`, `http-upload` and `flow-visual` each end in a leak assertion over that listing, which then passes whatever the code does. Against `origin/main`, which diffed a before/after listing of the real tmpdir, that is a regression rather than a wash. `redirectTmpdir` (`test/helpers/tmpdir-env.ts`) sets all three and returns the restore; the **7** files that scope a tmpdir use it, including the two `android-perfetto` ones that predate this branch. `test/tmpdir-env.test.ts` pins both lookup chains — reverting the helper to `TMPDIR` alone fails two of its three tests. All three leak assertions were re-confirmed live on POSIX by mutating the production cleanup each one covers. - **A hardcoded absolute path is invisible to a `TMPDIR`-scoped instrument.** `session-correctness` and `ios-instruments/analyze-freshness` passed a literal `/tmp/native-profiler-{x,ios}.trace` as the session's trace file, and the renderer writes its report beside it (`deriveReportPath` = `dirname(traceFile)/<base>-report.md`). Every run left `native-profiler-x-report.md` and `native-profiler-ios-report.md` in the shared `/tmp`; nothing removed them, and two concurrent runs write the same names. Reproduced with `TMPDIR` pointed at a scratch dir — the files still landed in `/tmp`, which is exactly why the `os.tmpdir()` row and the leftover census below both read clean here. Both tests now own the directory. - **A prefix-scanned env var is invisible to a grep for variable names.** `secretSources` enumerates `process.env` by the `ARGENT_SECRET_` prefix and ranks it *above* every file the test writes, so `secrets-command.test.ts` — which already pins `HOME`, `USERPROFILE` and cwd — still read the developer's shell. `ARGENT_SECRET_FOO=bar`, argent's own documented way to supply a secret: `6 passed` → **`3 failed | 3 passed`**, deterministic. `argent-cli` has no `ARGENT_*`-stripping setup file, so the prefix is cleared per test. Its sibling `configuration-core/tests/secrets.test.ts` was already immune — it threads an explicit `env: NO_ENV` into every call. - **`android-binary` and `vega-cli-fallback`** were the last two files redirecting `HOME` without `USERPROFILE` — the former the direct twin of `android-binary-windows`, in the same directory, driving the same resolver. Under a `node:os` mock reproducing the Windows lookup with an SDK planted in the profile, it loses **5 of 11** tests. No test file in the repo redirects `HOME` alone any more. (`6fbb66ce1` later skipped both of this file's describes on win32 — its fixtures are extensionless and the win32 resolver only takes `.exe` — so its own `USERPROFILE` pin is now symmetry with the sibling files that do run there, not a live guard.) Two smaller items in the same commit. `native-devtools-socket-bind`'s ENOENT fixture still rooted at `os.tmpdir()` while the comment three screens above explains why the others do not: with a 142-character ambient `$TMPDIR` that path exceeds `sun_path` and `listen` rejects it for *that* reason, which the assertions cannot tell from the missing-directory one they were written for. And `<home>\AppData\Local\Android\Sdk` — the resolver's fallback for a GUI-spawned server that never inherited `%LOCALAPPDATA%` — could be deleted with the whole suite green; it now has a test, and deleting either win32 root fails exactly the tests named for it. ## Fifth pass A fifth pass took the platform-branch shape the fourth pass exposed and ran it as its own move: *for every function that branches on `process.platform`, does the test's guard cover every arm, or only the one the author's machine takes?* Fixed in `e08b466b6`. - **`init-stale-config.test.ts` deletes the developer's real VS Code MCP config on Windows.** The file mocks `os.homedir()` and says it does so "so hidden-scope probes (`~/.claude.json`, VS Code user profile) never touch the real home directory". `vscodeUserDirs()` branches `darwin → homedir()/Library/Application Support`, `win32 → %APPDATA%`, `else → homedir()/.config` — the win32 arm never calls `homedir()`, so the mock is inert there, and the test's own `userMcpJsonPath()` mirrors the same branch. Both user-profile tests then write a one-entry fixture over `%APPDATA%\Code\User\mcp.json` with a whole-file `writeFileSync`, and assert that `remove()` deleted it. Reproduced by forcing `process.platform` to `win32` with a two-server `mcp.json` planted at a probe `%APPDATA%`: **`3 passed`, and the file and its directory were gone.** With `APPDATA` pinned, the whole file passes under the same instrument — 31 tests — and the planted config is byte-identical. - **`argent-tools-client` hands its ambient `ARGENT_*` to a real spawned child.** The launcher spawns an actual tool-server, and `buildToolsServerEnv` overrides only the keys it is given — everything else rides in on `...baseEnv`. `ARGENT_HOST` is the one that bites: the fixture binds the host it names while the launcher records and health-checks `127.0.0.1`, so reuse misses and a second server is spawned. With six overrides exported: **`10 failed | 181 passed`, and eight stray `fake-tool-server` processes still holding TCP listen sockets after the run.** With the prefix stripped: `191 passed`, none surviving. The package now carries the same setup file `tool-server` has, for the same reason — and it is the second of the two packages whose missing `ARGENT_*` strip this review found. ## Later passes A sixth pass audited the fix commits themselves and bounded the SDK probe (`6fbb66ce1`); a seventh ran the moves against the diff one more time and turned up the two below, plus the `listen(0)` defect filed as #853. - **The `PATH` pin made `workspace-reader-integration` POSIX-only without the guard its siblings got.** The shim it puts on `PATH` is an extensionless `node`, and `symlink()` to a file needs an elevated process or Developer Mode on Windows, so `beforeAll` throws `EPERM` there before any assertion runs; a copy in place of the symlink would not rescue it either, since a bare command name resolves through `PATHEXT`. This sweep already skips `android-binary` and `native-devtools-socket-bind` on win32 for exactly this class, and the Windows job runs a curated list of seven `tool-server` files that excludes this one, so nothing was catching it. Fixed in `095d75bd8` — verified POSIX `2 passed`, and under a forced win32 platform `2 skipped` with the top-level `beforeAll` never entered. - **A rationale that rested on a case the file excludes.** `android-binary`'s header justified pinning `USERPROFILE` by what `os.homedir()` reads on Windows, two sentences before noting that both describes skip on win32. Fixed in `f37b3605e`; the variable stays in the snapshot list, the justification no longer claims a platform this file never reaches. A seventh pass also re-ran the sweep against a hostile machine: every feature flag on in a scratch `~/.argent/flags.json`, no `adb` on `PATH`, and a `TMPDIR` long enough to overrun the 104-byte `sun_path` limit. It found one resource this branch had not closed. - **A red `launcher-version-gate` run strands a real tool-server.** `ensureToolsServer` spawns a fixture server, but its pid only reached the reaper after three or four assertions on the state it returned; any of those throwing left the pid unrecorded, and the same `afterEach` then deleted `STATE_DIR`, the only other record of what to kill. **Eight such processes were alive on the development machine**, spread from 14:33 to 18:23, every one from an `argent-version-gate-test-*` fixture and none from any other family — each still holding a TCP listen socket with its fixture directory long gone. Forcing one assertion to fail took the `tool-server.cjs start` count from 10 to 11. The nearest twin, `launcher-duplicate-spawn`, guards this twice: it records the pid straight after the null check and sets `FAKE_TTL_MS` so an escaped server self-exits. Fixed in `26c2c60ec` with both, the TTL also covering the window between the spawn and the state read where no pid exists yet — the same forced failure now leaves **zero** strays. An eighth pass audited the seventh's own fixes, and found the version-gate fix had been applied to one file when the defect was a property of four. - **Three more files strand a real tool-server on a red run.** `launcher-spawn` and `launcher-exit` set `FAKE_TTL_MS` nowhere; `launcher-duplicate-spawn` — the file `26c2c60ec` cites as the model — armed it inside one test's `try/finally`, so eight of its nine spawns ran without it and the `finally` disarmed it for the remainder of that test. Reproduced per file by forcing a failure before the pid is recorded: a detached node process survives, reparented to init, holding a listening socket, with its `TEST_HOME` removed and its state record already cleared. Fixed in `3bb69ded6` by moving the net to a file-wide `beforeEach` in all three. Verified end to end — the child carries `FAKE_TTL_MS=60000`, and a stranded server spawned at 21:28:36 exited by itself at 21:29:36 with nothing signalling it; three consecutive green runs stay at 191 passed. - **A 29th file writes the real `~/.argent`.** `boot-electron-spawn-error`'s success-path test completes a boot, and a completed boot calls `trackChromiumPort`, persisting to `os.homedir()/.argent/chromium-cdp-ports.json`. The real file on the development machine had accumulated **106 dead ephemeral ports**. Its two siblings in the same directory already mock `chromium-discovery` for exactly this reason; this was the third, with no mock. Fixed in `3306b6f40`. - **`scopeTempHome` was itself unpinned.** Deleting its `USERPROFILE` line — the Windows half, the same property the sibling helper's test pins — left all twelve consumers green at 48 passed. `3306b6f40` adds the missing test; it kills that mutation plus dropping the `HOME` pin and replacing the per-test `mkdtemp` with one shared directory. Two findings from that pass were refuted on verification and are recorded rather than acted on: the tool-server tmpdir leftovers (mechanism real, but they are the separate leak this body already scopes out) and a claim that `26c2c60ec`'s message overstated its twin. Four comments were also corrected against their code: `deriveReportPath` joins `<base>-report.md` *inside* the trace's directory rather than appending to the directory's name, which is what makes the `rm(traceDir)` added in `a67c43f8d` cover it; two `android-perfetto` comments still named `TMPDIR` as the mechanism after the switch to `redirectTmpdir`; and `android-binary`'s header claimed the home pin lets its two positive tests resolve "on either platform", though its fixtures are extensionless and the win32 resolver only accepts `.exe`. |
||
|
|
aa9ee0a5d6 |
chore: bump version to 0.21.0 (#810)
Bumps the monorepo from 0.20.0 to 0.21.0 across the full 18-file set: - all 16 `packages/*/package.json` (via `npm version --workspaces`) - `package-lock.json` regenerated with `npm install --package-lock-only --ignore-scripts` on Node 24 / npm 11 (version-only diff, matching the lockfile CI job) - `server.json` — both the top-level `version` and `packages[0].version` `npm run check:versions` passes: all workspace packages and server.json are at 0.21.0. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
abe5ff3c56 |
refactor(flow): generalize when's block machinery so a second block directive can't miss a site (#748)
`when` is the only directive with a sibling `steps:` list, and four runner sites asked `kind === "when"` directly to decide whether a step has authored children to expand as skip lines. A second block directive would have had to remember all four, and a forgotten one silently drops a whole block from the report — exactly the invariant `reportBlockSkipped` exists to hold. This introduces `blockSteps(step)` as the single runtime predicate and `BLOCK_DIRECTIVE_KEYS` as its parse-time counterpart, and extracts the parse-side block plumbing (`assertBlockDepth`, `parseBlockSteps`) that a second directive must share — notably the depth cap, renamed `MAX_BLOCK_DEPTH`, which has to be ONE counter across directives or an alternating nesting chain evades it and reopens the cyclic-YAML-alias hole it was added to close. No behavior change, with one deliberate exception: the depth-cap message now reads `block directives nest deeper than 20 levels` where it said `when blocks nest deeper than 20 levels` — the cap stopped being `when`'s the moment it became shared, and a message naming only `when` would misdirect an author who hit it through a different directive. Every other error message, their ordering, and the report shapes are untouched. 559 flow tests pass unchanged. --- **Stack** 1. **#748 — you are here** · `refactor(flow)`: generalize when's block machinery → `main` 2. #749 · `feat(flow)`: add `repeat:` blocks → #748 |
||
|
|
4a11317706 |
chore: bump to 0.20.0 (#765)
Version-only bump of the workspace to 0.20.0, same shape as #741 (the 0.19.0 bump). ## What changed - All 16 packages under `packages/*` → `0.20.0` - `package-lock.json` — regenerated with `npm install --package-lock-only --ignore-scripts` on Node 24, matching what the Lockfile job runs. Version-only: 16 insertions, 16 deletions, nothing else. - `server.json` — the MCP registry manifest, in **both** places it carries a version: the top-level `version` and `packages[0].version`. It lives outside `packages/*`, so a workspace sweep leaves it behind and the registry then rejects the publish because `packages[].version` names a version npm has never seen. ## Verification - `npm run check:versions` → "All workspace packages and server.json are at 0.20.0." - `npx prettier --check` clean on every touched file - No `"0.19.0"` string left anywhere in the repo No code changes. |
||
|
|
96ea94f87a |
feat(flow): add an idle condition that waits for the screen to stop moving (#728)
> Stacked on #574. Replaces the route-fingerprint approach that #727 and #729 carried; both are closed. > > Rebased off the #715-#726 chain so it can merge on #574 alone. That chain owns `DirectiveOutcome.warning` / `StepReport.warning` and the `indeterminate` scoring rule; the small amount of each that this condition needs is carried here, scoped to `idle`, and will conflict textually with #724/#725 for whichever lands second. ## One check a selector cannot express ```yaml - await: { idle: true } ``` Has the screen stopped moving? Flows were substituting fixed `wait:` steps for it, which either wait too long on every run or too little on the run that mattered. ## Why it reads pixels as well as the tree Each signal is blind to what the other sees. The tree cannot see presentation-layer motion. An iOS push or modal dismissal commits its hierarchy up front and then animates a layer for a few hundred milliseconds; a cross-fade or a scrim moves no node at all. Measured on a real Android emulator: a page animating a large element continuously reads as a single static `WebView` node, and the existing `await-screen-idle` tool called it settled in **465 ms, five times out of five**. On a deterministic Chromium page whose DOM is byte-identical across the animation, that tool returned `settled: true` in **407 ms** while this condition failed 8/8. Pixels alone would not do either: they cannot see a tree still churning behind an unchanged surface, and anything animated forever (a video, a shimmer) would make a pixel-only settle unsatisfiable on a screen the tree calls ready. Unlike that tool, this cannot be silently stepped over. Readiness is not an acceptance criterion — the verdict belongs to the identity and outcome checks around it — so a screen that never settles still **passes**, carrying a `warning` that says what the green actually bought. That is what makes it safe to persist in a flow: it reports on every run without ever failing one over a video or a shimmer. The only thing that stops a run is a tree source that cannot be read. ## The rule the design follows The absence of evidence is never evidence. - A capture that did not arrive cannot complete the hold. - Neither can a single agreeing pair. Every animation that reverses has a turning point, and two samples straddling it come back identical while the screen is moving. On a live 3 s cross-fade that passed a default-shaped step on roughly **one run in three**; settling now takes two consecutive still intervals, so `minStableMs: 0` still means three reads. - A round is never started without the budget to observe it with. A round begun with nothing left neither captures nor reads, and both absences were otherwise recorded as facts about the device. - No verdict comes from a latch. A screen that settles and then moves again, or goes blank, has not settled. ## `timeout:` is a real bound No describe path takes an abort signal, so the tree read is raced against what is left of the budget. Without that, a wedged ViewInspector RPC ran 2.25 s past an 8000 ms budget, and a busy Android screen ran 5.4-6.0 s against a 3000 ms one. A read that runs out of step budget is the step ending, not the source failing, and only the latter is reported as an environment problem. ## Failure modes stay apart They call for opposite responses. A screen that never stopped moving is a verdict about the app. A tree that could not be read is not, and it names the foreground check first, because a backgrounded app reads identically to an uninstrumented one and relaunching is the wrong repair. A run whose captures never produced a comparable pair still settles on the tree and says so in a warning, rather than passing off half a proof as the whole one. ## Capture routing and tolerance Captures route exactly as the `screenshot` tool routes them, so tvOS and Vega, which have no simulator-server backend but are perfectly screenshottable through `xcrun` and the emulator console, are covered rather than written off. The pixel comparison owns its tolerance rather than borrowing `screenshot-diff`'s. That one holds a baseline stored across sessions, machines and OS versions against a live capture and must absorb real drift; this one holds two captures one poll apart from a single session, where a static screen reads back byte-identical (measured: zero changed pixels across five consecutive pairs on an idle simulator). The margin is load-bearing, because uniform change is all-or-nothing: at the baseline tolerance any cross-fade slower than ~2 s counted zero changed pixels and read as settled mid-animation. ## Not a screen check A dropped tap leaves the source screen perfectly idle. It belongs after the element check that names the destination, never instead of one. #730 documents the pairing. ## Verification - 3307 tests pass; typecheck, `typecheck:tests`, lint and prettier clean. Eleven mutations applied to the source, all eleven caught by tests. - Driven end to end against a real iOS simulator, a real Android emulator, and a Chromium app through a tool-server built from this branch: static screens pass with no warning (proving captures ran), animating screens pass carrying the warning that names the motion, and the pre-existing tool disagrees exactly where it should. --------- Co-authored-by: Hubert Gancarczyk <claude-hubert.gancarczyk@swmansion.com> |
||
|
|
afd722924f |
feat(flow): support concurrent flow recordings (#574)
## Problem
Only one flow could be recorded at a time, anywhere on the machine.
Recording state was three module globals in `flow-utils.ts` — harmless
in a per-client process, but the tool-server is a **host-wide singleton
per install bundle**. Every MCP client, every subagent sharing a
parent's connection, every `argent` CLI call and every project on the
machine attaches to the same process, the same `Registry`, and those
same three globals. HTTP requests are served concurrently with no
serialization.
Three failures followed, all reproduced against the pre-change code:
1. **A second recording clobbered the first.** `startRecordingSession`
just overwrote, so the first agent's next `flow-add-step` silently
appended into the *other* agent's flow file — in a different project.
2. **Any agent could finish any agent's recording.**
`flow-finish-recording`'s schema was literally `z.object({})`.
3. **Replay stomped recording.** `resolveFlowFilePath` called
`setActiveProjectRoot`, so a `flow-execute` in project B rebound the
global root mid-recording of project A. Already worked around, locally
only, in `flow-add-step`.
## Approach
Recording state is now a `Map` keyed by the resolved flow file path,
`<project_root>/.argent/flows/<name>.yaml` — the identity of the
artifact being built, so "same key" means "same output file" and two
sessions on one key are a genuine collision rather than an accident of
scoping. `flow-add-step`, `flow-add-echo` and `flow-finish-recording`
each take `name` + `project_root`, so every call is self-contained;
required rather than optional-with-fallback, since a fallback would
succeed while an agent is alone and fail only once a second recording
exists.
`resolveFlowFilePath` is pure, which fixes defect 3 and retires
`FLOW_PROJECT_ROOT_REQUIRED` (the state it guarded can no longer exist).
Rejected alternatives — keying by device udid (flows are deliberately
device-portable, and `flow-add-echo`/`flow-finish-recording` have no
device at all), an opaque `recordingId` (an agent that loses the token
cannot recover), and per-caller identity from the transport
(`ToolContext` carries no caller identity, and subagents share their
parent's MCP connection, so it would fail the exact scenario being
fixed).
### Locking, and why readers needed more than a lock
Every mutation of one flow file runs under a lock keyed by that path —
appends, `flow-start-recording`'s truncate-and-register, and
`flow-finish-recording`'s read-summarize-clear. Keyed by file rather
than owned by the session, because a restart *replaces* the session: a
session-owned lock cannot exclude the operation that supersedes it. Per
file, not global, so two recordings never queue behind each other. An
append whose session was finished, restarted or evicted meanwhile fails
with `FLOW_NO_ACTIVE_RECORDING` rather than writing into a different
take.
The lock serializes writers only, and no reader of a flow YAML can join
it — `flow-execute`'s own load, its `run:` fragment load,
`flow-read-prerequisite`, `flow-add-step`'s sibling-fragment check, and
the `argent` CLI reading from another process entirely, where an
in-process lock cannot reach. Both writers used a plain `fs.writeFile`,
which opens `O_TRUNC`, so a reader could land between the truncate and
the write. That case is silent: `parseFlow("")` returns `{ steps: [] }`
with no error and `summarize` derives `ok` from "no failures", so a
`flow-execute` racing an append reports a **top-level PASS having
replayed zero steps**. Both writes now go through a sibling temp file
and a rename, so a reader sees either the whole old file or the whole
new one — and unlike the lock, that also holds cross-process.
### `stop-all-simulator-servers` gets a `devices` scope
Every agent is told to call this at session end, and unscoped it walked
the whole registry — so agent A wrapping up tore down agent B's devtools
mid-recording, degrading B's flow to brittle coordinate taps. It now
takes an optional `devices` scope and reports `unmatched` ids, so a
mistyped id doesn't read as a clean machine.
Which namespaces count as "owned by a device" turned out to be the
load-bearing part, because nothing cascades to most of them and
`unmatched` turns any omission into an actively wrong diagnosis — a
correct device id reported as a typo. The set now covers `AXService`
(the in-sim ax daemon, spawned `--timeout 3600`; an iOS session that
only ran boot/launch/describe owns this and nothing else),
`ScreenRecordingSession` (an ffmpeg child plus the touch-visualizer
overlay it enabled on the device), `NativeProfilerSession` (an xctrace
child, or an on-device perfetto process and its trace file) and
`JsRuntimeDebugger` (a bound loopback server, the CDP socket to Metro, a
log handle). The debugger URNs interpose the Metro port —
`<ns>:<port>:<deviceId>` — so the matcher understands both shapes,
consuming only the first colon so a wireless adb serial after the port
still compares whole.
`stop-simulator-server` shared none of this and had drifted: it looked
URNs up with an exact, case-sensitive `services.get()`, so a lower-cased
UDID silently no-op'd there while the scoped stop-all reaped it. Both
tools now share one matcher. Their namespace *sets* stay deliberately
different, documented where they are defined — `stop-simulator-server`
is also the documented recovery for a wedged transport, and widening it
to devtools/AX would make a routine retry drop the native-devtools
connection another agent's recording depends on, which is the hazard the
`devices` scope exists to prevent.
## Verification
**End-to-end, three devices, one shared tool-server** (iPhone 16 Pro,
iPhone 17 Pro, Pixel 3a): three interleaved recordings, plus an
unrelated `flow-execute` in a fourth project while all three were live.
Both iOS devices held their own live native-devtools concurrently (two
per-UDID sockets, `connected: true`). Each YAML contained exactly its
own steps in order, taps captured as selectors rather than coordinates,
and neither picked up another's or the third root's path. All three
replayed green — also through the **released 0.17.0 CLI** against the
modified server, which checks wire compatibility. A device-scoped
teardown of sim 1 left sim 2 and the emulator running.
Re-run against the final build:
- Two interleaved recordings across two project roots on one device,
with a **separate process** polling one of the flow files as fast as it
could for the duration. Zero empty or truncated observations; each YAML
held exactly its own steps; both replayed green (6/6 and 5/5). Against
the pre-change in-place write the same reader observes zero-step reads
interleaved among the real ones — the silent-PASS input.
- A scoped teardown of the iPhone reaped `AXService` and
`NativeDevtools` for that UDID only, reported no `unmatched`, and left
the second sim and the emulator running. Lower-casing the UDID matched;
a genuinely bogus id was still reported.
- With a screen recording live on the Pixel 3a, a scoped teardown reaped
`ScreenRecordingSession` and the **ffmpeg child actually exited** (1 →
0). Before the fix it survived to the 180 s cap while the tool called
the correct serial a typo.
The pre-change repros were re-run afterwards to confirm observed
behavior changed, not just the tests.
`npx vitest run` in `packages/tool-server` (295 files, 3154 tests) and
`packages/argent-cli` (280), `tsc --build`, `tsc --noEmit` on both test
projects, eslint and prettier — all green.
## Review notes
Several rounds of review found real defects in this change; each was
reproduced before fixing and re-verified after. Worth knowing when
reading the diff, since the tests exist to pin them:
- `flow-start-recording` truncated the `.yaml` outside any lock, so a
step from the take being discarded landed in the freshly reset file and
was reported as success (26-29 of 200 runs).
- `flow-finish-recording` never took the lock; its `await fs.readFile`
was a yield during which a concurrent append committed, leaving the
reported summary disagreeing with disk (11-16 of 200).
- A failed finish destroyed the recording. Hand-editing the `.yaml`
mid-recording is a documented workflow, so `parseFlow` can legitimately
throw — and the error told the agent to call `flow-start-recording`,
which truncates the very take it would recover.
- `unmatched` reported a device this session had just stopped, because
`disposeService` returns a node to IDLE and keeps it.
- A bare IP claimed every wireless-adb device at that address, since an
adb serial is itself `ip:port`.
- The eviction backstop stamped with `Date.now()`; ties at millisecond
resolution let it drop the session that was just used.
- `requireRecordingSession` ended with "Call flow-start-recording first"
— reached for a key that was finished, superseded or evicted as well as
one never started, and on those branches the file on disk is fully
populated while that call truncates it and reports no `restarted`.
- The atomic write regressed twice on its own terms: its scratch name
was derived from the flow file's basename, which has no length cap, so a
long flow name that appended fine before failed `ENAMETOOLONG`; and the
cleanup guard began after the temp file was created, leaking a scratch
file into a committed directory on any write that failed after opening.
- Two tests passed against implementations they claimed to reject: the
`stop-simulator-server` narrowness guard used a udid that classifies as
*android*, where the iOS-only services it guards can never appear, so
widening the iOS branch kept it green; and the client-mode finish
asserted only the *shape* of `savedTo`, never its content, though that
directive is the only thing that lands the file in client mode.
## Notes for reviewers
- Client/remote persist mode is the least-exercised path, and now has
its own concurrency tests (overlapping appends, and a restart
superseding an in-flight one) — it previously had none. The
`project_root` key is byte-stable across the file boundary (`kind:
"probe"` passes it through unchanged), which is what keeps a remote
recording addressable from `flow-add-step`, which declares no file
input.
- Two spellings of one flow file still mint two sessions — and two
independent locks — over one file, which bypasses every guarantee here.
Two ways in: the root spelled two ways (a symlink, or a case variant on
APFS), and the likelier one, the *name* cased two ways on a
case-insensitive volume. Neither is normalized away because the correct
normalization is the filesystem's: case-folding the key would wrongly
merge two distinct flows on ext4, and resolving symlinks is impossible
in client mode, where the root does not exist on this host. Documented
at `getFlowPath`.
- No recording tool can detect that another agent took its key.
`flow-add-step`, `flow-add-echo` and `flow-finish-recording` all
re-resolve the key on every call, so after a takeover they act on
whichever take is now live and report success: an append lands in the
other agent's file, and a finish finishes and clears it. The only case
that fails loudly is the narrow one the liveness check covers - an
append already IN FLIGHT when the restart lands. There is no caller
identity to key ownership on (see the rejected alternatives above), so
this is spelled out for the agent under "Pick a name unique to your
task" in `argent-create-flow` rather than mechanized.
- Skew hazard in one direction only: a *new* client against an *older*
tool-server. Zod strips the undeclared `name`/`project_root`, and the
old server falls back to its module globals — so concurrent recordings
silently collapse onto one session. The other direction (released 0.17.0
CLI against this server) was verified end-to-end.
- `packages/argent-private/docs/reference.md` still describes
`flow-add-step` as appending to "the current recording", and names two
tool ids that do not exist (`flow-insert-echo`/`flow-run` are file
names; the ids are `flow-add-echo`/`flow-execute`). It is a submodule,
so the fix cannot ride on this branch.
- A restart reported `discardedSteps` from the superseded session's
in-memory flow while it truncates the *file*. Hand-editing the `.yaml`
mid-recording is documented, so the two diverge: four steps wiped, one
reported. It now counts the file, and reports no number at all when that
file cannot be read or parsed - 0 is the answer a genuinely empty take
gives. Client mode still counts from memory (this host cannot see the
client's file), and the description now says which mode it is promising.
- `ChromiumJsRuntimeDebugger` cascades from `ChromiumCdp` and was
therefore already being torn down - silently, while `NetworkInspector`
and `ReactProfilerSession` cascade the same way and were named.
`stopped` is documented as the services that were live and got shut
down, so it is listed now too.
- The client-mode case named for a superseded in-flight append restarted
*between* calls, so the next append re-resolved the key and succeeded -
the guard was never reached, and neutering it left the whole file green.
It now parks an append in its live sub-tool call across the restart.
- `stop-tools.test.ts`' mock handed the tool the live service map where
the real `getSnapshot` copies, so a cascade rewrote the state the sweep
was still reading and the answer depended on map insertion order. The
mock copies and recurses like `_teardown` now, and the cascade case runs
under both orders.
- Prose the code contradicted, each verified against source before
rewriting: Vega owns `JsRuntimeDebugger`/`NetworkInspector` once the
debugger has run (and can match anything at all through an ERROR node);
"nothing here cascades" was denied twice in its own file; an iOS
boot/launch/describe session owns `NativeDevtools` too; `:tcp` is
mintable but unreached in production; the tool-server is a singleton
*per install bundle*, not per machine; `argent flow list` does enumerate
`.argent/flows`; the stop-tools comments narrated a "before" that only
existed on this branch.
Found while verifying, out of scope, worth their own issues: a `tool:
flow-execute` self-reference recurses past both cycle guards (`run:` is
guarded, a nested `flow-execute` reseeds the stack); react-profiler
artifacts collide host-wide on a second-resolution filename;
`stop-metro` is port-scoped and kills another agent's bundler;
`debugger-reload-metro`'s HTTP fallback broadcasts to every attached
client. A tool's `capability` is enforced only by the HTTP layer, not by
`registry.invokeTool`, so a call that reaches the registry another way -
`flow-add-step` takes `command` as a bare string - can resolve a service
the tool declares it does not support, leaving an ERROR node behind
(e.g. `SimulatorServer:<vega serial>`).
---------
Co-authored-by: Hubert Gancarczyk <claude-hubert.gancarczyk@swmansion.com>
|
||
|
|
6d907cc86b |
feat(flow): boot a Chromium instance per launch step (#585)
A `launch:` on Chromium now starts its own Electron instance, so nested e2e flows and mid-flow relaunches work as they do on iOS/Android. Previously the runner booted one app per run and rejected any second chromium launch. A chromium device id _is_ its CDP port, so a launch that starts an app from scratch has to boot one and move the run onto it: `state.device` became reassignable (steps already read it per call), and `state.owned` tracks what the runner booted, torn down in reverse at run end. An instance the runner did not boot — pinned via `--device`, or auto-detected — is attached to, never killed. Relaunching the same app kills its instance and waits for the process to actually exit, or the replacement loses a race against the app's single-instance lock. The runner needs a device before step 1, so `resolveRunDevice` follows a leading `run:` chain to find the launch the run _begins_ with: a fragment composing a chromium e2e flow now boots instead of failing with "No booted chromium device found". A launch declaring no app id for the run's platform stays an error — the run's platform is fixed start to finish. Also fixes a pre-existing teardown leak: the spawned handle is the npm `electron` node wrapper, not Electron, so signalling it left the app and its helpers running (reparented to launchd, still in the dock). Teardown now sweeps the child's process group. **Behavior change:** a fragment leading with `run:` into a chromium e2e flow now boots a fresh instance where it previously attached to a running one; pass `--device` to keep attaching. ## Tests Cover the boot/attach/settle three-way, teardown ordering and the group sweep, device rebinding after a nested launch, same-app retire ordering, cancellation mid-boot, both "no chromium app declared" guards, and the leading-`run:` chain (multi-hop, cyclic, no-launch). The guard, exit-wait and sweep tests are mutation-checked. |
||
|
|
566663bde4 |
chore: bump to 0.19.0 (#741)
Version-only bump of the workspace to 0.19.0, same shape as #603 (the 0.18.1 bump). ## What changed - All 16 packages under `packages/*` → `0.19.0` - `package-lock.json` — regenerated with `npm install --package-lock-only --ignore-scripts` on Node 24, matching what the Lockfile job runs. Version-only: 16 insertions, 16 deletions, nothing else. - `server.json` — the MCP registry manifest, in **both** places it carries a version: the top-level `version` and `packages[0].version`. It lives outside `packages/*`, so a workspace sweep leaves it behind and the registry then rejects the publish because `packages[].version` names a version npm has never seen. ## Verification - `npm run check:versions` → "All workspace packages and server.json are at 0.19.0." - `npx prettier --check` clean on every touched file - No `"0.18.1"` string left anywhere in the repo No code changes. |
||
|
|
22033e1418 |
feat(flow): allow to run every flow in a directory from flow run (#576)
`argent flow run` now accepts a directory and runs every flow in it sequentially: ``` argent flow run .argent/flows --recursive ``` Discovery uses the same acceptance rules as `flow list` (lowercase `.yaml`, safe stem, readable file), sorted for a deterministic run order. `-r`/`--recursive` walks subdirectories too, skipping dot-directories and `node_modules` and never following directory symlinks. A directory named `foo.yaml` still batches (stat wins over extension). Batch output is failures-only: each flow prints a `[i/n] <path>` header, its failing/errored steps — numbered exactly as a single-mode rerun would number them — and a per-flow summary; the run ends with a `PASS/FAIL — N flows: X passed, Y failed, Z skipped` verdict. `--json` prints one aggregate object with per-flow reports. Exit code reflects the batch (0 pass, 1 any failure, 2 discovery/config errors). `--output` exports keep the single-run `<output>/<flow>/` layout, keyed by subdirectory in recursive runs so same-stem flows in different directories can't clobber each other's snapshots. **Failure semantics:** a flow failing its steps — or one the tool-server rejects as invalid (bad YAML, unparseable step) — fails alone and the batch continues. An infra error (transport death, unclassified failure) stops the batch and counts the remaining flows skipped. To make that distinction possible, tool-error responses now carry the server's failure signal (`error_code`/`error_kind`) on the wire — on the streaming terminal error line and on JSON error bodies — and the tools client surfaces server-answered errors as a typed `ToolInvocationError`. Against a pre-signal server this degrades to stopping on any throw. Not breaking: single-file runs behave exactly as before. |
||
|
|
cc2f907ce9 |
feat(flows): resolve run: directives from explicit YAML paths (#567)
A `run:` value is now a YAML path resolved against the directory of the flow file that contains the step, matching the CLI cutover: ```yaml - run: login.yaml - run: ../shared/login.yaml # cross-directory composition now works ``` Bare names fail at parse with a migration hint (`run: login` → `run: login.yaml`). The filename stem stays the fragment's report attribution; reports also carry the as-written path as `target`. Cycle detection compares realpath-canonical paths (same stem in two dirs ≠ cycle; same file via symlink/spelling = cycle). Snapshot baselines are unchanged — keyed by and stored beside the root flow. An uploaded root flow with `run:` steps is now rejected up front with a contract error instead of a mid-run temp-dir ENOENT (its referenced files stayed on the client, and relative resolution in the temp dir could reach host files); same for a relative chromium app path. The recorder emits the sibling form (`run: <name>.yaml`). **Breaking:** existing `run: <name>` directives fail at parse until renamed to `run: <name>.yaml`. Snapshot baselines for a saved flow whose YAML is a symlink now anchor beside the real file (the symlink target's directory) — move any committed `.argent/flows/__baselines__/<flow>/` set beside the real file once, or the next run fails with a missing baseline. A `run:` target must also resolve inside the project root or beside/below the flow file that references it (arbitrary host YAML is no longer reachable), and an uploaded flow with a `snapshot` step is rejected up front (its baselines cannot anchor to the per-call temp dir). |
||
|
|
a644d52d39 |
feat(flows): run CLI flows from explicit paths (#568)
`argent flow run` now takes an explicit YAML path instead of a saved-flow name: ``` argent flow run .argent/flows/checkout.yaml --platform ios ``` The path may point anywhere on the local filesystem; the filename stem names the run's report/artifacts, so it must be `[A-Za-z0-9_-]+` with a lowercase `.yaml` extension. A bare name fails with the exact replacement command, and `argent flow list` prints paths instead of names. Because sibling `run:` files and `__baselines__` resolve beside the YAML, the CLI now requires the auto-started local tool server and refuses `ARGENT_TOOLS_URL` / `argent link` routing. The `flow-execute` tool stays remotely callable via `name` + `project_root`, and gains a `flow_path` parameter (exactly one of `name`/`flow_path`) that is only honored when the file-input boundary verified it as a real host path — uploads and boundary bypasses are rejected, so it can't execute arbitrary server YAML. Also: the flow-name pattern is now a single shared export from `@argent/registry`, and the recorder composes a `flow_path` call into a `run:` step when it targets a sibling of the recording. |
||
|
|
19782f4e1a |
feat(secrets): resolve {{secret:…}} from .env files, not just the environment (#734)
## Why
A credential could only reach a typing tool through an
`ARGENT_SECRET_<NAME>` environment variable. That is the right CI
contract — and stays the highest-priority source — but interactively it
is poor ergonomics: an editor-hosted tool-server inherits the
environment its editor was launched with, so changing a credential means
restarting the editor, and there is nowhere to write one down that
survives a reboot. "Is loading these from a `.env` file on the roadmap?"
is the recurring ask.
## What
`{{secret:NAME}}` now resolves through an ordered chain, first match
wins, re-read on every resolution — so editing a file applies to the
next keystroke with **no server restart** (the same runtime-read design
`ios.additionalDeviceSets` already uses).
| # | Source | Which keys it exposes |
| - | ------ | --------------------- |
| 1 | `ARGENT_SECRET_<NAME>` in the environment | prefixed variables
only — unchanged, still wins |
| 2 | `<project>/.argent/secrets.env` | every key (gitignore it) |
| 3 | `<project>/.env.local`, then `<project>/.env` | **only
`ARGENT_SECRET_`-prefixed keys** |
| 4 | `~/.argent/secrets.env` | every key, any project |
Covers `keyboard`, `paste`, `run-sequence` keyboard steps, and flow
`type:` steps — all four already funnel through the same resolution
point, so nothing else changed.
Also adds `argent secrets [list] [--json]` so a setup is verifiable
without an agent: names only, never values, shadowed names marked, and a
warning when a linked remote tool-server means resolution happens on a
different machine.
## The one design decision worth reviewing
**Row 3 is why this isn't just "read the `.env`".** An agent composes
the tool call, so anything reachable through `{{secret:…}}` is
exfiltratable by a prompt-injected one — type it into a field, then read
the field back. "Which values may argent type" has to stay an allowlist
the user wrote deliberately.
So: a *dedicated* argent secrets file exists for no other purpose and
therefore **is** the allowlist; a file the app *shares* keeps the prefix
as the allowlist, exactly as the process environment does. Your
`STRIPE_SECRET_KEY` sitting in the same `.env` stays unreachable —
verified live, not just asserted. Adding `ARGENT_SECRET_` to one line is
the deliberate act that exposes it.
Two smaller calls, both reversible:
- The chain lives in `@argent/configuration-core`, not the tool-server,
so the CLI reads the same code; the tool-server keeps only the
placeholder engine.
- The project scope is discovered by the **cwd walk-up every other
project-scoped configuration uses**. A per-request project root (header
→ `ToolContext`) was considered and rejected as new protocol surface
across two client paths; reusing flows' module-global
`setActiveProjectRoot` was rejected as a cross-project leak on a reused
server. The cost is that a tool-server whose cwd sits outside the
project skips project files — mitigated by the failure now listing every
path it consulted, and by `~/.argent/secrets.env` needing no project at
all.
## Verification
Unit + integration: tool-server 3122, configuration-core 122 (19 new),
argent-cli 370 (6 new). Lint and prettier clean. All four publish
bundles build.
Live, driving this branch's tool-server on :3001 against iPhone 17 Pro /
iOS 26.4 and the Electron testbed:
- global `~/.argent/secrets.env` → typed correctly; the response echoed
only the placeholder
- prefixed key in the project `.env` → typed; **unprefixed
`STRIPE_SECRET_KEY` in that same file → rejected**
- `.argent/secrets.env` beat `.env`; the environment variable beat both
- edited a secrets file mid-session → applied on the very next call,
same server pid
- a chromium flow with `type: { text: "{{secret:APP_PASSWORD}}" }` → 3/3
pass, asserting on the greeting the app rendered, so the *correct value*
provably landed
- an undefined name inside a flow surfaces the full source list in the
step report
Sample of the failure output (no value ever appears):
```
Unknown secret "LOGIN_PASSWORD" — no source on the machine running the tool-server defines
LOGIN_PASSWORD. Available secrets: APP_USER.
Sources consulted, first match wins:
1. environment (ARGENT_SECRET_*) — 0 secrets
2. /path/to/project/.argent/secrets.env — found, 1 secret
3. /path/to/project/.env.local — not found
4. /path/to/project/.env — found, 1 secret
5. /Users/me/.argent/secrets.env — not found
To make it available, ask the user to add `LOGIN_PASSWORD=…` to …
```
## Out of scope
No general flow variable/parameter system — a non-secret external value
(a test account's email, a staging tenant id) can use the same
placeholder, but argent treats every such value as a secret: redacted
from errors, never echoed, so it is not for something a report should
show. No config key pointing at an arbitrary secrets file. Remote
(`argent link`) still resolves on the remote host, which the CLI now
says out loud.
|
||
|
|
2278115028 |
fix(flow): run a device-less flow without a device, and say why its counts are zero (#649)
Fixes #644. ## Before ``` $ argent flow run echo-only # .argent/flows/echo-only.yaml: two `echo` steps [Tool:flow-execute] No booted device found. Pass a device id or platform explicitly. Available devices: 18BE573F-… (ios, Shutdown), <70 more> ``` and when a device *was* booted: ``` PASS on 18BE573F-… — 0 passed, 0 failed, 0 errored, 0 skipped ``` ## After ``` $ argent flow run echo-only # nothing booted Flow "echo-only" › first step › second step PASS — 0 passed, 0 failed, 0 errored, 0 skipped (no test steps) ``` ## Symptom 1 — the device Whether a device is needed is decided from the flow's own steps, before resolution. Classification is **per step kind and defaults to needing one**, so a kind added later inherits today's behaviour instead of silently running against no device — and the `never` binding makes leaving a new kind unclassified a compile error, backed by a test keyed on the step union so it fails to build rather than to run. Two classifications worth calling out: - **`when` always needs a device**, whatever its body contains, because the guard reads one itself (its platform, or its view tree). A `when: {platform: ios}` block containing only narration still resolves. - **`run` needs one without the fragment being read here.** The named flow is resolved at run time; resolving it a second time would duplicate that lookup and could disagree with it if the file changed in between. A deliberate over-approximation: composing a narration-only fragment still resolves a device. Stated in the code and in the tool description. For `tool:` steps the tool's own schema decides, via a superset of the keys the runner injects — `device` is included because a nested `flow-execute` step drives a device without being handed the run's own. A tool that declares no input at all (`stop-all-simulator-servers`) is device-free, and reading its absent schema must not throw — it previously would have. `ExecState.device` is nullable, which is the safety mechanism rather than just typing: the compiler enumerates every site that acts on a device, each of which now says so via one `deviceEnv()` narrowing. `flow-actions.ts`, `flow-visual.ts` and `ActionEnv` are untouched. The executor also re-checks each step against the **same predicate**, so if the scan and the executor ever disagree the step reports it instead of failing obscurely deeper in. A run that resolved no device reports `device: ""`, and neither renderer claims it ran somewhere. ## Symptom 2 — the counters Reproducing this showed the issue's framing is slightly off: `--json` doesn't only disagree with the text, it disagrees with **itself** — counters all zero while its own `steps[]` marks both steps `"pass"`. So the CLI text was a faithful rendering of the server's counters. **The counters are right and stay as they are.** Narration is deliberately excluded, and it should be: after a hard stop every remaining step *including narration* is reported skipped, so counting it would inflate `skipped` on every real failing run — a worse and far more common lie than the vacuous one being reported here. It would also contradict the JUnit model in #578, where echo is `<system-out>` and not a `<testcase>`. What was missing was saying *why* zero. Both the CLI and the MCP renderer now append `(no test steps)`, and only on a pass — a cancelled run can be a FAIL with all four counters zero, where "no test steps" would read as though the failure had no cause. No wire format changes: `steps[].kind === "echo"` already distinguishes counted from uncounted steps, so the JSON is self-describing without widening the status enum. ## Conflicts, for whoever lands second This is a hot area — seven open PRs touch `flow-run.ts`. - **#578** rewrites the CLI summary line I also change (one hunk, one 7-line function, semantically independent — resolution is keep-both), and its `attachFailureDiagnostics` dereferences `env.device.platform`. **It will need a null-device guard**, or every failure in a device-less flow silently degrades to `read-failed` diagnostics. Happy to rebase onto it rather than the reverse. - **#585** rewrites `resolveRunDevice` at the same seam and edits the same description sentence. - **#538** rewrites `flow-device.ts`. Worth noting it makes `resolveFlowDevice` reject a physical iPhone for flows — skipping resolution means a narration-only flow now passes on a physical-iPhone-only host, which I think is desirable but is a second behaviour change on this seam. All new tests are in new files, since every existing flow test file in the blast radius is rewritten by an open PR. ## Behaviour changes a reviewer should weigh - A device-free flow no longer prints `PASS on <id>` **even when a device is booted**. That is the point: otherwise an identical flow reports differently in CI (no simulator) than on a laptop with one open. An explicit `--device` is still honoured and still named. - `--platform` is ignored for a device-free flow, where it previously errored with nothing booted. - A 0.18.1 CLI against a newer server would print `Flow "x" on ` — cosmetic version skew. ## Verification Live against the built CLI: device-less flow with nothing booted (the reported bug) and with a device booted (identical output, no ambient attribution); `--json` showing `device: ""`; explicit `--device` still naming it; a mixed flow and a composed flow both still demanding a device; a mixed flow with a device booted still reporting `PASS on <id> — 1 passed`. 24 new tests. tool-server 3103 passed, CLI 284 passed, MCP 78 passed — no existing test modified. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- > **#697 is stacked on this branch** — it conflicts with this one in `flow-run.ts`'s import block, so it was rebased on top. Merge this first. |
||
|
|
81de9f66a6 |
fix(config): say what a rejected value should have been, and prune the group it left behind (#650)
Fixes #643. ## Before / after ``` $ argent config set ios.additionalDeviceSets "~/Library/Developer/Radon/Devices" --scope project Error: Invalid value for config key "ios.additionalDeviceSets". # ← the whole message ``` ``` $ argent config set ios.additionalDeviceSets "~/Library/Developer/Radon/Devices" --scope project Error: Invalid value for config key "ios.additionalDeviceSets": expected an array of strings. Did you mean: argent config set ios.additionalDeviceSets '["~/Library/Developer/Radon/Devices"]' --scope project Run `argent config list` to see each key's expected value. ``` ``` $ argent config unset ios.additionalDeviceSets --scope project $ cat .argent/config.json { "ios": {} } → {} ``` ## Symptom 1 — the message The issue names three gaps: no expected type, no example, no pointer to `config list`. All three are closed, plus one the issue didn't ask for and I think is the actual fix. **The suggestion carries the user's own value.** A generic `Example: … '["~/DeviceSets/ci"]'` would hand someone a path they have never heard of and expect them to spot the difference. Where the correction is mechanical — a single item offered to a list-valued key — the error offers back what they typed, wrapped, shell-quoted, and **on the scope they asked for**. Pasting it works; verified live that it lands in project scope, not global. Nothing is coerced. The issue floated accepting a bare string and storing it wrapped; I didn't, because `config set` persists, gets committed, and is read by other machines, so a value silently stored in a shape the user didn't type is expensive to debug and `coerceCliValue` already has one silent fallback. Showing the corrected command costs the user one keystroke and keeps the store honest. If a reviewer prefers coercion, this is the smaller change to build on. **The expected shape comes from the validator, not a per-key string** — `asStringArray` *is* "an array of strings", so swapping a key's `parse` swaps its description with it and the two cannot drift. A bespoke validator can override via a new optional `expected`, and degrades to today's exact message if it says nothing. **`config list` states it too.** The issue notes `list` doesn't close the gap either — its description describes the *elements* but never says the value is a list. It now shows `value: an array of strings, e.g. ["~/DeviceSets/ci"]`, and `list --json` carries both fields. `telemetry.enabled` deliberately gets no example: `setConfigValue` refuses it before validating (it's managed by `argent telemetry`), so a "here's how to set it" hint would point at a command you may not run. A schema guard test keeps that honest as keys are added — and asserts every example **actually round-trips through its own validator**, so an example can never ship that reproduces the error it exists to fix. ## Symptom 2 — the empty group Deleting a key now removes any container the delete emptied, stopping at the first ancestor that still holds something. **This is file hygiene, not a behaviour change.** I traced every raw reader of the document — `readConfigObject`, and telemetry's `consent.ts` and `notice.ts`, which each do their own read — and an empty parent is already indistinguishable from an absent one: `getAtPath` returns `undefined` either way, before `parse`, so the merge layer never sees a container at all. The only observable difference is the bytes on disk, which is exactly the complaint. Guards worth noting: - **The root always survives** — an emptied config is `{}`, never a deleted file. `.argent/` is itself a project-root marker, so removing the file wouldn't restore the prior state anyway, and `updateConfig` is a shared publish path with a lock/rename protocol that has no defined meaning for file removal. - **A no-op unset still doesn't touch the file.** That fast path exists so an unset that removes nothing can't materialise a project config and dirty git status; pruning lives inside the mutate callback, which the fast path returns before reaching. So a group someone deliberately left empty by hand is never tidied away — pinned by a test asserting the file stays byte-identical. - Siblings at any level stop the unwind, including an empty array value, which is preserved. **Two existing tests asserted the old behaviour and now assert the new one** — `config-access.test.ts:47` and `config.test.ts:109` (the latter is `clearRememberedAgent`'s sibling-preservation test, so it doubles as proof siblings survive). ## Known same-class case, not fixed here `resetFirstRunNotice` (`packages/telemetry/src/notice.ts`) does its own inline delete and still leaves `{"notices":{}}`. It doesn't go through `deleteAtPath`, so it doesn't inherit this. It's a one-line change to route it through the same function — happy to do it here or as a follow-up, but it pulls the telemetry package into a config PR so I left it out by default. ## Verification Live against the built CLI: the reported case; pasting the suggestion back and confirming it lands in **project** scope; unset leaving `{}`; a sibling key surviving; a non-array key correctly getting the generic example and *no* bogus "Did you mean"; `config list` output; `telemetry.enabled` still delegating unchanged. configuration-core 103 passed, argent-cli 285 passed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
3fff176a32 |
fix(cli): let a boolean flag take the value you typed (#699)
Fixes #586. ## The bug `--includeChildren false` left the flag **true** and silently dropped the word, so the tool ran with the opposite of what was asked. The reporter spent a while chasing a filter bug that did not exist — the output was simply the unfiltered kind. Reproduced on 0.18.1, device-free, with a discriminator that shows the flag's value directly: ``` $ argent run screenshot-diff --udid U --baselinePath A.png --currentPath B.png --captureCurrent=false { "summary": "Screenshot diff summary … pixel_mismatch: 1.79% …" <-- false, diff runs $ argent run screenshot-diff --udid U --baselinePath A.png --currentPath B.png --captureCurrent false [Tool:screenshot-diff] Provide either currentPath or captureCurrent, not both. <-- stayed TRUE ``` That message is the whole problem in one line: the user typed `false`, and the tool refuses on the grounds that they asked to capture. ## Why the old behaviour existed, and why it does not need to The parser deliberately declined to look ahead: > `// Bare boolean flag: true. Don't consume next argv to avoid surprising behavior when a positional follows.` That protects a case which does not exist. `parseFlags` has exactly one caller, and **`positional` is never read anywhere in the repo** — every bare token is collected and dropped, for booleans and for every other type. There is no positional to steal. The module header had documented the space form as legal all along: ``` // --name value (string / number / integer / boolean-with-value) ``` This matters because several tool booleans **default to true**, so `false` is the only way to say what you mean: `screenshot.includeImageInContext`, `network-request.includeBody`, `debugger-component-tree.onScreenOnly`, `debugger-inspect-element.resolveSourceMaps`. ## What changed A boolean flag consumes a following token when it is exactly the word `true`/`false`, case-insensitively. `1`/`0` and everything else are left alone — a bare number after a switch is more likely an unrelated argument than a value, and guessing at an ambiguous token is what caused this bug. `--flag -- false` still keeps the word positional. Three consequences are handled here rather than left to bite later: - **`argent run` now reports arguments it ignored.** This is what stops `--flag 0` and `--flag yes` being the same silent inversion, in a syntax users are now being taught works. stderr, so `--json` stays parseable. - **`--no-flag true` / `--no-flag false` now name the positive form** instead of quietly meaning false. One is a contradiction, the other a double negative. - **`--flag=True` used to throw** while `--flag True` would now work — the inline coercion was case-sensitive and did not trim. Both paths now share one helper, so a single word cannot get two answers one function apart. The **flow** and **lens** parsers take switches that accept no value at all, and would have silently ignored the syntax their users just learned elsewhere. They now refuse it — in the flow parser that also stops `false` being swallowed as the flow name, since its first bare token is the flow to run. `--help` gains **one legend line** for tools with a boolean field, rather than widening the flag column on every field of every tool: ``` Booleans: --flag or --flag true sets true; --flag false, --flag=false, or --no-flag sets false. ``` It deliberately does not begin with `--`. `scripts/e2e-full/lib/discover-tools.sh` reads any such line in the `Flags:` section as a flag row and takes the first `--token` as its name, so a legend starting with a flag would inject a phantom flag into every tool model it builds. **There is a test pinning that shape**, verified live: running the harness's awk over the new help output yields exactly the real flags and no legend row. ## Verified live ``` --captureCurrent false -> diff runs (was: "Provide either currentPath or captureCurrent, not both.") --captureCurrent=false -> unchanged --captureCurrent 0 -> "Note: ignoring unused argument(s): 0. Pass values as --flag <value> or --flag=<value>." screenshot --help -> legend present; harness awk parses only the real flags ``` 25 new tests; 8 confirmed to fail before and pass after. The rest pin what deliberately did *not* change: bare flag still true, a following flag or non-boolean word left alone, `1`/`0` still positional in the space form, `--` escape, string and unknown fields untouched, `--no-flag` semantics, boolean arrays, last-write-wins. The parser had **zero** boolean coverage before — which is why this survived. Full CLI suite 298 passing; lint, prettier and `typecheck:tests` clean. ## Scope and neighbours Only `flag-parser.ts` (the schema-driven parser for `argent run`) changes semantics. The other CLI parsers take fixed, default-off switches where `false` has no coherent meaning; three of them already reject a stray token outright, and the two that did not now do. `flow.ts`'s deliberate rejection of `--flag=value` is untouched. **#648** also edits `flag-parser.ts` (rewrites `renderFlagName`, inserts helpers at the same anchor). Behaviourally compatible — it keeps boolean → bare `--name` — so this is a textual conflict only, and either order works. ## Found while here, not fixed `scripts/e2e-full/lib/discover-tools.sh:60-64` detects flag kinds with `\bboolean\b` in awk, where `\b` is **backspace**, not a word boundary — so it never matches and every non-enum flag is typed `unknown`. That makes the `bad-type` validation case downstream unreachable. Pre-existing and unrelated to this fix; filing separately. --- > **Stacked on #648** (`filip/run-cli-validation-messages`). Both rewrite the same region of `packages/argent-cli/src/flag-parser.ts` — #648 factors out `flagNameFor`/`isJsonField` and rewrites `renderFlagName`, this one adds `booleanWord` beside them and a boolean legend to `formatSchemaUsage`. Merging them independently conflicts; this branch is rebased on #648, so review only the top commit. GitHub retargets it to `main` when #648 merges. --------- Co-authored-by: Filip131311 <f.kaminski2000@gmail.com> |
||
|
|
a6f1bef632 |
fix(cli): stop argent mcp --help starting the server, and argent tools --help dumping the catalogue (#656)
Fixes #638. ## The report understated it The issue says `argent mcp --help` "does not hang and does not start the server — it simply prints nothing". Reproducing it showed the opposite: ``` $ argent mcp --help < /dev/null ; echo $? 0 # 0 bytes ← what the reporter saw $ argent mcp --help # stdin open (a pipe, an editor, a CI step) # HANGS — I hit a 300s timeout ``` `--help` **starts the MCP stdio server**, which blocks reading JSON-RPC from stdin. The "prints nothing, exit 0" is just the server getting an immediate EOF from a closed stdin. So this is the same "`--help` runs the real command" bug that was fixed for the installers — `mcp` was missed. `startMcpServer` takes no argv at all (`mcp-server.ts:96` — its only parameter is `{ paths }`), so a help flag was *structurally* unreachable; there was nowhere downstream that could have handled it. ## Fix `mcp` joins the existing guarded set rather than growing a second help path. That set's defining property is "the handler never inspects its argv", and `mcp` qualifies more strongly than the installers do — it isn't merely ignoring `rest`, it is never handed it. **It cannot fire on a real launch.** The guard tests `rest`, which is `[]` for every generated editor config (all four shapes end at `mcp`, and `isArgentManagedEntry` requires exactly that), and `[].some(...)` evaluates no predicate. This is pinned in both directions, because a guard that *did* fire here would print usage onto the JSON-RPC channel and break every editor at handshake — the highest-cost regression in this file, and it was untested. The top-level table's `mcp` row now reads the same metadata as its own help, so the two cannot drift. **No rename.** An earlier draft renamed the module and six identifiers (`installer-help` → `command-help`, etc.) on the grounds that its comments had become false. They hadn't quite: fixing `mcp` *and* `tools` makes "every other subcommand parses `--help` itself" true again — I checked all ten siblings. Since #530 and #568 both edit `cli.ts`, a rename would have forced them through churn for no behavioural gain. Prose-only. ## Second commit: `argent tools --help` The issue mentions it in passing; it's a different mechanism and a genuinely dead branch. `argv.filter((a) => !a.startsWith("--"))` dropped `--help` before the subcommand was read, so it fell through to listing all 77 tools — **contacting the tool-server, starting one if none was running**, to do it. Only `-h` ever reached the existing help branch. Scoped to the subcommand position on purpose: a global check would have broken `argent tools describe <name> --help`, which today prints *that tool's* flags. It still does — there is a test. Separate commit so it can be reverted alone. ## Verification Live, against the built CLI: | | before | after | |---|---|---| | `mcp --help`, stdin open | hangs indefinitely | usage, returns immediately | | `mcp --help`, stdin closed | 0 bytes, exit 0 | 849 bytes of help, exit 0 | | `mcp` (real launch) | works | works — verified with an actual `initialize` handshake, server replies with its capabilities | | `mcp --metro-port 8082` | starts server | starts server (guard keys on help, not on "any argv") | | `tools --help` | 77-line catalogue | usage | | `tools describe gesture-tap --help` | tool's flags | tool's flags | | `argent --help` `mcp` row | — | byte-identical | argent 80 passed, argent-cli 284 passed. ## Note on the help text Every claim in it is sourced (stdio/JSON-RPC transport, stdout ownership, the `~/.argent/mcp-calls.log` default and `ARGENT_MCP_LOG` override, auto-spawn vs `ARGENT_TOOLS_URL`/`argent link`). It deliberately does **not** suggest running `argent mcp` by hand to check an install — that is the reported hang — and instead says it will look like it has hung and why. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
d08c3a3cfc |
fix(cli): name the missing flag instead of printing a Zod dump (#648)
Fixes #645. ## Before ``` $ argent run gesture-tap [ { "expected": "string", "code": "invalid_type", "path": ["udid"], "message": "Invalid input: expected string, received undefined" }, ... two more ] ``` ## After ``` $ argent run gesture-tap Error: missing required flags --udid, --x, --y argent run gesture-tap [flags] ...full per-flag help... ``` ## Scope The issue names the missing-flag case. Reproducing it showed the same raw dump has a second trigger: any constraint the tool itself rejects, which the CLI cannot know in advance. | invocation | before | after | |---|---|---| | `gesture-tap` (no flags) | raw issue array | `missing required flags --udid, --x, --y` | | `screenshot --scale 99` | raw issue array | `--scale Too big: expected number to be <=1` | | `gesture-scroll --udid X --x .5 --y .5` (zero deltas) | raw issue array | `Pass a non-zero deltaX and/or deltaY …` | | `run-sequence --udid X` | raw issue array | `missing required flag --steps-json` | | `gesture-tap --x abc` | already good | unchanged | | runtime failure | plain message, exit 1 | unchanged | Fixing only the first row would have left the CLI's error voice less predictable than before, so both go through the same renderer. ## How it works Two sources, one output. Missing flags are found locally from the tool's published schema — a **presence** check only, never a type or range judgement, which stays exclusively the server's. That is sound because the schema generator excludes defaulted fields from `required` (`debugger-connect` requires `device_id`, not `port`), so it cannot reject a call the server would have accepted. Everything else is read off the rejection the tool-server already returns. Both produce one report rendered by one function and reported through one call site, so the wording, the output channel and the exit code cannot drift between them. Recognition of a rejection is **structural** — the shape of the issue list plus the tool's own schema — never the wording of a message, which is not ours to depend on and changes between Zod releases. Four gates must all hold, and any failure leaves the existing handling untouched. Details worth a reviewer's attention: - **A rule spanning the whole payload reports no field.** `gesture-scroll` and `gesture-rotate` validate at the object level, and `screenshot-diff` is `.strict()`. Treating those as field-scoped would print `Error: --undefined …`; they are stated on their own instead. - **A rule firing on an *optional* field is not called a missing required flag.** `await-ui-element` refines on `expectedText`, which it does not require — reporting that as missing would contradict the help block printed directly underneath, where the field carries no `(required)` marker. - **The check runs after `--args` is merged**, so `argent run gesture-tap --args '{...}'` is not falsely reported as missing everything. Verified live: it reaches the device and taps. - Presence uses own-key semantics, so a required field named e.g. `constructor` is not treated as supplied by the prototype chain. ## Behaviour changes a reviewer should weigh - **A tool-rejected value now exits 2 instead of 1.** `run.ts` already uses 2 for bad input and 1 for a failed run; a Zod 400 means the tool never ran. No in-repo consumer tests for a specific code — `scripts/e2e-full` only checks zero/non-zero. Note this does **not** make 2 universal: an unknown tool name still exits 1, which is untouched here. - **`--json` gains a defined failure shape** (it had none — the blob printed regardless). One object on stderr, nothing on stdout, so `--json | jq` on a failed run reads an empty stream and a non-zero status: ```json { "error": "missing required flags --udid, --x, --y", "missing": ["--udid", "--x", "--y"], "issues": [] } ``` `issues` carries the tool's list verbatim, which is the raw data the issue asked to keep. - **One adjacent fix**, called out because it is not the reported bug: the global-option parse ran *outside* the error handler, so `argent run screenshot --out` printed a raw stack trace. Same bad-input-to-ugly-output defect, one line above the fix. ## Not done - The unknown-flag hole (`argent run gesture-tap --bogusflag 1` is silently accepted and the tool runs). The pass-through is deliberate — see the comment in `flag-parser.ts` — and belongs with #586, the same CLI-argument family. - `argent flow` builds its own payload and has its own required check; it cannot reach this path. - The server still returns the issue list verbatim, so MCP and other clients are unaffected. All prettifying is CLI-side. ## Verification Live against the built CLI for every row of the table above, plus: `debugger-connect` asks only for `--device_id` and never `--port`; `--args '{...}'` reaches the device and taps; a thrown runtime error still prints its bare message with no `Error:` prefix, no help block, exit 1. 43 new tests. `run-telemetry.test.ts` passes **unedited** — it already asserted the non-Zod passthrough, which makes it the regression guard for the untouched path. Full CLI suite 320 passed, registry 87 passed. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --- > **#699 is stacked on this branch** — it conflicts with this one in `flag-parser.ts`, so it was rebased on top rather than left to collide at merge time. Merge this first. |
||
|
|
23b9ae5c87 |
chore: bump to 0.18.1 (#603)
Patch bump. First release whose npm tarball carries `mcpName` (added in #598), which unblocks the MCP registry publish (`mcp-publisher publish` rejects `0.18.0` because its manifest predates the field). `server.json` is bumped alongside `packages/*` for the first time — `scripts/check-workspace-versions.mjs` now enforces it (`All workspace packages and server.json are at 0.18.1` locally). | Commit | Change | | --- | --- | | `eea6c27c` | `style`: fix prettier formatting on main (#604) | | `7e4ece69` | `chore`: server.json for the official MCP registry (#598) | | `fc09612f` | `feat(config)`: `recordings.directory` — configurable save location for screen recordings (#601) | | `cccda92d` | `feat(config)`: `ios.additionalDeviceSets` — additive array of extra CoreSimulator device sets (#542) | Version-only diff, rebased on main as of #604. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
cccda92d15 |
feat(config): ios.additionalDeviceSets — additive array of extra CoreSimulator device sets (#542)
## Summary **Stacked on #534.** Adds the first *additive* configuration entry on the new schema — `ios.additionalDeviceSets`, a list of extra CoreSimulator device-set directories — delivering the config side of the #401 discussion on the #534 machinery. ### The schema entry One registry entry in `config-schema.ts`: - key `ios.additionalDeviceSets`, scopes `project` + `global`, `parse: asStringArray`, **`merge: "union"`** Unlike `lens.agent` (project *shadows* global), this is additive: the effective value is the **union of both scopes** — the global baseline first, the project's extras appended, deduplicated. A repo can commit the device sets its tooling needs to `.argent/config.json` and they *extend* (never replace) the user's global list. `argent config list/get/set/unset` handle the array key with zero command changes — arrays already round-trip through the JSON value coercion. ### The runtime reader `getAdditionalIosDeviceSets(options): string[]` in `config-access.ts` — the surface iOS tooling should call. It reads each scope separately so paths normalize against the base the author meant: - `~` / `~/…` expands to the home directory (honoring the sandbox `homeDir` override) - relative **project** entries resolve against the **project root**, relative **global** entries against **home** - output order matches the `union` preset (global first), with **post-normalization** duplicates dropped — `~/DeviceSets/ci` in global and its absolute spelling in the project file collapse to one entry - empty array when unset Support refactor: `resolveHomeDir()` extracted in `paths.ts` (the HOME/USERPROFILE + override logic previously inlined in `argentHomeDir`/`configDir`). ### Out of scope (follow-up) Actually pointing simctl at the extra sets. There is no central simctl wrapper today (~25 call sites build `xcrun simctl …` argv inline, and `ax-prefs.ts` hardcodes the default set's `CoreSimulator/Devices` path), so consuming this reader in `list-devices`/boot/etc. is its own change — the runtime-read-off-disk design here means that consumer needs no CLI/env threading, matching how #534's description framed the split. ## Testing - `configuration-core`: 5 new tests (82 total, green) — additive union across scopes + per-scope file isolation, non-array rejection + entry normalization, reader `~`/relative resolution per scope, post-normalization dedup, empty-when-unset - `argent-cli`: new real-filesystem CLI round-trip (274 total, green) — `config set` an array at each scope, effective `get` shows the union while `get --scope` shows only that scope's entries - `tsc` build + `typecheck:tests` + eslint clean on touched packages |
||
|
|
646f726bc4 |
chore: bump to 0.18.0 (#596)
bump debated myself whether this should be a QoL patch or a minor release and i think the latter makes more sense | Commit | Change | | --- | --- | | `7189333a` | `feat(tool-server)`: human-readable log message (#582) | | `5ac69349` | `feat(flow)`: CSS combinator scopes for flow selectors (#569) | | `e23f0e28` | `feat(flow)`: snapshot `cropOn` for single-element visual diffs (#516) | | `6a53e66a` | `feat(flow)`: rotate directive (#546) | | `68ceb314` | `ci`: cut over npm publishing to the unified trusted-publishing workflow (#571) | | `2546788a` | `ci`: unified publish-npm workflow (#565) | |
||
|
|
a0460eeefe |
chore: bump workspace packages to 0.17.0 (#554)
## What
Lockstep-bump all 16 `packages/*` workspace packages (and the matching
`package-lock.json` entries) from `0.16.1` → **0.17.0**.
Diff is exactly 32 version-field swaps across 17 files — no formatting
or
dependency churn.
## Verification
- **Lockfile CI gate reproduced locally on the exact CI toolchain**
(Node
24.14.1 / npm 11.11.0, matching `lockfile.yml`'s `node-version: "24"`):
`npm install --package-lock-only --ignore-scripts` on top of the commit,
then `git diff --exit-code -- package-lock.json` → **clean**. npm's own
regeneration reproduced the hand-edit byte-for-byte, so none of the
`"peer": true` churn that #513/#539 had to keep out reappears here.
- `node scripts/check-workspace-versions.mjs` → `All workspace packages
are
at 0.17.0.`
- Remaining `repo-hygiene.yml` checks pass: no conflict markers, no
focused
tests.
- `prettier --check` on all 17 changed files → `All matched files use
Prettier code style!`
- **Runtime version actually reports 0.17.0**: `getInstalledVersion()`
(`argent-installer/src/utils.ts:384`) and
`getGloballyInstalledVersion()`
(`topology.ts:94`) both read `version` straight out of the resolved
package
root's `package.json` at runtime, so the bump is the whole mechanism —
no
generated constant or second version file to keep in sync. Exercised
that
resolution against the bumped tree: `PACKAGE_ROOT` → `packages/argent`
(`@swmansion/argent`) → `0.17.0`.
- Verified all 16 lockfile hits belong to workspace packages (parsed the
lockfile's `packages{}` and matched every `0.16.1` entry to a
`packages/*` path) — no unrelated dependency happened to sit at 0.16.1.
- No test asserts a release version string; the only `0.1x.x` matches
under
`*.test.ts` are historical references inside comments.
## Note
`packages/argent-private` needs no pin change here. Its release version
is
carried purely as a git tag — the repo has no version field on the
release
line (its only `package.json` is a `private: true` research CLI on an
independent `0.1.0` line) — and `v0.17.0` is now tagged at `2d6c292`,
which
is **already** the commit this superproject pins. `v0.16.0` and
`v0.16.1`
sit on that same commit, so the submodule entry is correct as-is and
stays
out of this diff.
|
||
|
|
2251c7cf46 |
feat(screen-recording): screen-recording-start/stop tools with per-call stop reminders (#517)
## What Adds a `screen-recording-start` / `screen-recording-stop` tool pair (naming follows `native-profiler-start/stop`) that records the device screen to an mp4 and returns it as a downloadable artifact. Capture runs through **simulator-server** — the same backend `screenshot` and every interaction tool already drive. simulator-server publishes the device screen as an MJPEG stream (`/stream.mjpeg`), so recording needs no platform-specific recorder: the tool-server subscribes to that stream, paces the frames onto a fixed 30 fps timeline, and pipes them into a single ffmpeg process that encodes — and watermarks — straight to the final mp4. The stream is multi-subscriber, so a preview window can stay open on the same device while recording. - **One path for every device simulator-server drives** — iOS simulators, Android emulators, and physical Android devices. - **Native resolution, constant 30 fps** — h264, `+faststart`, no post-processing pass. - Session state lives in a per-device `ScreenRecordingSession` blueprint (mirrors the native-profiler session): time-limit cap with auto-finalize, unexpected-exit recovery (a capture that ended on its own is still retrievable via stop), always-startable state reset on stop, and dispose-on-shutdown cleanup through the registry. ## Why the frames are paced host-side A device only emits a frame when the screen **changes**. Pointing ffmpeg straight at the stream therefore produces a video whose length is the sum of the moments something moved — a still screen collapses to a fraction of a second — and an ffmpeg blocked on a silent socket does not answer a stop signal promptly either (measured: 12 s late). Re-emitting the last frame on a wall-clock schedule fixes both: **video duration always equals real elapsed time**, and stop is a stdin EOF that finalizes in ~60 ms. Duplicate frames cost almost nothing once encoded (a 10 s recording of a static screen is ~1 MB). ## Finishing pass folded into capture The Argent watermark (logo + `By @swmansion`, bottom-left, sized relative to the frame) is stamped by the same ffmpeg invocation that encodes the capture, so there is no second encode and no temp intermediate. Its colour is chosen **per pixel** from the background luma underneath it — the white logo over dark areas, a runtime-derived near-black copy over light areas — so it keeps maximum contrast against whatever is behind it. It sits at 20 % opacity and is opt-out via `argent disable video-watermark` (read when the recording starts). Frame geometry comes from the first JPEG's SOF header, so no `ffprobe` is needed. ffmpeg is now the recorder rather than an optional finisher, so a missing ffmpeg fails `screen-recording-start` up front with an install hint instead of silently degrading the output at stop time. ## Reminder plumbing While a recording is running — or ended on its own but was never retrieved — **every** tool result carries a `note` telling the agent the recording is still going and how to stop it. It rides the same `note` field as the update reminder but is per-call and unsuppressed; both notes compose when they coincide. The note text switches to "already ended, retrieve the file" once the cap fires or the capture dies. ## Skill New `argent-screen-recording` skill (+ routing stanza in `rules/argent.md`): documents the start → interact → stop workflow and instructs the agent to schedule its own reminder/wakeup for the expected end of the recording immediately after starting one (harness reminder tool if available, otherwise a background `sleep` whose completion notification pulls it back). Scores 10/10 on `scripts/grade-skills.mjs`. ## Verification - Unit: 45 tests across `screen-recording.test.ts`, `mjpeg-stream.test.ts`, `watermark.test.ts`, `http-recording-note.test.ts`; full tool-server suite **2808 tests / 280 files green**; `tsc --noEmit -p tsconfig.test.json`, root `tsc --build`, eslint, prettier all clean. - E2E on a live tool-server (`POST /tools/...`), driving real interactions between start and stop: - **iOS sim** (iPhone 16 Pro Max, iOS 18.5): 1320×2868 h264, `r_frame_rate=30/1`, 338 frames, container duration 11.27 s vs reported `durationMs` 11314 — **within 50 ms of wall clock**. Extracted frames show real screen content (mid app-switcher animation) with the watermark rendered light-over-dark. - **Android emulator** (Pixel 3a, API 34): 1080×2220 h264, 30 fps, 353 frames, duration 11.77 s vs `durationMs` 11793 — within 30 ms. 512 KB for a mostly-static home screen. - **Static screen** (no interaction at all, 10 s): 300 frames, duration exactly 10.000 s — the case the previous `recordVideo` implementation reduced to ~0.03 s. - **Long silence then activity** (15 s untouched, then an app launch): stream survived, no warning, frames after the silence show the new screen. This caught a real bug during review — the connect timeout was also acting as a socket *inactivity* timeout and tore the stream down at 10 s of stillness; fixed and covered by a regression test that fails without the fix. - **Time-limit cap**: `timeLimitSeconds: 5` self-finalized at 4.97 s / 149 frames, the per-call note flipped to "already ended (it hit its 5s time limit)", and a stop issued 11 s later still returned the video with the matching warning. ## Not supported (capability-gated with clear errors) tvOS simulators, physical iPhones, Chromium apps, Vega, and remote (`remote:`-prefixed) simulators — none of them expose a readable frame stream. --------- Co-authored-by: Ignacy Łątka <claude-hubert.gancarczyk@swmansion.com> |
||
|
|
8d2a499eaf |
Project-scope configuration with schema-driven merge + argent config (#534)
## Summary Adds a general, **scoped** configuration system on top of the shared `config.json`, plus a universal `argent config` command to manage it. Motivated by the discussion on #401 (iOS device set): config that needs to work naturally with the MCP server should be read off disk at runtime like telemetry consent is — not threaded through CLI flags/env and a kill-and-respawn dance. This lands the reusable machinery; the device-set becomes a one-line schema entry + a runtime reader on top of it. Four pieces, matching the requirements: ### 1. Project-scope config files `config.json` now resolves at two scopes: - `~/.argent/config.json` (**global**, default) - `<project-root>/.argent/config.json` (**project**, resolved by the same `.argent`/`.git`/`package.json` marker walk as feature flags) `configFilePath` / `readConfigObject` / `updateConfig` take an optional `scope` (default `global`), so **every existing caller is unchanged** (telemetry, notices, lens). Per-scope lock + atomic write are preserved. ### 2. Schema-driven merged reads `getConfigValue(def)` reads each scope the value's schema entry allows, merges them under the entry's policy, and falls back to the entry's default. This is the reader consumers should call instead of poking at a single global file. The existing **lens** getters (`getRememberedAgent` etc.) are migrated onto it as the first live consumer — a repo can now pin its lens agent, falling back to the user's global choice. ### 3. A registration file for configurations (`config-schema.ts`) Adding a configuration is a one-liner: `key`, `description`, allowed `scopes`, a `parse` validator, and a `merge` policy. Merge presets: - `prioritize-local` (project wins) · `prioritize-global` (global wins) - `prioritize-restrictive` (booleans/numbers — opt-out/stricter wins) - `union` / `intersection` (arrays) - …plus an escape hatch: pass your **own** `(inputs) => value` function for a bespoke rule. ### 4. `argent config` — one universal command `argent config <list | get | set | unset>` with `--scope global|project` and `--json`. New configs are added as **schema entries**, not new top-level `argent` commands, to avoid bloat. **Telemetry stays backward-compatible** on its dedicated `argent telemetry` command (which also drains/resets the live client). It's surfaced *read-only* under `argent config` via a `manageCommand` guard — so `argent config set telemetry.enabled` refuses and points at `argent telemetry`, and a committed project file can never re-enable a global opt-out (`prioritize-restrictive`, global-only). ## Testing - **Unit / integration**: 71 configuration-core tests (merge presets + custom fn, dotted-path + prototype-pollution guards, scope merge, scope/validation/manage-command errors, `listConfig`, `coerceCliValue`) and 11 real-filesystem CLI tests driving the actual `config()` entry point across sandboxed HOME + project cwd. Full suites green: configuration-core 71, argent-cli 268, telemetry 281, argent 60. - **Live, on the built binary** (`node packages/argent/dist/cli.js …`): set global + project (from a deep subdir) → effective get returns the project value; per-scope gets return each file; both files land in the right place; `argent telemetry disable/enable` writes `config.json` and `argent config get telemetry.enabled` reflects it read-only; unknown-key / invalid-value / bad-scope errors exit non-zero with hints. - `tsc --build` across the workspace, prettier, and eslint (`--max-warnings 0`) all clean. ## Notes / follow-ups - Config-file reads are not yet fingerprint-cached the way telemetry's consent read is; a long-lived tool-server re-reads on each `getConfigValue`. Fine for CLI/low-frequency use; a hot runtime consumer (e.g. a future device-set reader) may want the same mtime/inode cache. |
||
|
|
1f5b155229 |
chore: bump workspace packages to 0.16.1 (#539)
## What Lockstep-bump all 16 `packages/*` workspace packages (and the matching `package-lock.json` entries) from `0.16.0` → **0.16.1**. ## Verification - `node scripts/check-workspace-versions.mjs` → `All workspace packages are at 0.16.1.` - Lockfile diff is exactly 16 version-field swaps — no unrelated churn (the `"peer": true` regeneration noise from a newer npm was again kept out, same as #513). The one remaining `0.16.0` in the lockfile is the unrelated `@humanfs/types` dev dependency. - `packages/argent-private` submodule left pinned at `v0.16.0` — no `v0.16.1` tag exists there yet. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
a0d1bbb1e7 |
feat(flow): indent nested steps in reports by block depth (#524)
Flow reports rendered every step flat, hiding which steps ran inside a `when:` block or a `run:` fragment. The tool-server now stamps `StepReport.depth` (+1 per block directive, omitted at top level) and the CLI/MCP renderers indent step labels and under-step lines by it: ``` ✓ 1 launch ✓ 2 when visible "What's new" — condition met ✓ 3 tap "Skip" ✓ 4 run dismiss [dismiss] ✓ 5 tap "OK" [dismiss] ``` Invariants: - **Wire-compatible both ways** — a flow with no block directives reports byte-identical to the pre-depth shape; a pre-depth server renders flat as before. - **Skipped ≡ entered** — skipped/errored/aborted blocks report the same depths as entered ones, keeping reports comparable run-to-run. - **Untrusted wire data** — renderers clamp depth (display cap, not a producer bound): hostile values render flat or at the cap, never throw or allocate huge strings. Also fixes a pre-existing bug: under-step warning/artifact lines now stay aligned past 99 steps. Tests pin depth on every producer path (entered/skipped/errored/aborted blocks, `run:` success/failure markers, `run:`-in-`when:`) and renderer alignment incl. the clamp boundary. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
3f602a7a9b |
feat(flow): conditional when blocks (#498)
## What
A `when:` block runs a step list only when one condition holds — a UI
condition (`exists`/`visible`/`hidden`/`text`, the await/assert shapes)
or a static `platform` test. **No else**, by design: a block exists to
restore determinism (dismiss an interstitial, reconverge), never to
test two paths. Tap-if-present is a one-step block:
`when: { visible: "Got it" }` + `steps: [tap: "Got it"]`.
No per-step `optional:` — `when:` covers every directive once. The key
is rejected at parse with a pointer to `when:`, not silently dropped (a
Maestro habit that would leave a "can't fail" step hard-stopping the
flow).
## How
- The guard reuses the assert engine at the 1s grace (`timeout` is a
parse error), so a skipped block barely costs a clean run.
- Verdicts are evidence-based: no trustworthy read in the window →
indeterminate → the step **errors** ("could not evaluate" is not
"condition false"); a transient read failure after trusted reads showed
the condition false stays a clean skip.
- `platform` folds `ios-remote` into `ios` — the parser rejects that
spelling, so the fold is the only way a guard matches a remote sim.
- A skipped block reports one line per authored step, same shape for
unmet guard, hard stop, or cancellation; everything goes through
`pushReport`, so when lines stream live. Failures inside an entered
block hard-stop as usual.
- Results carry an explicit `aborted` flag; `ok` keys off
fail/error/cancel, not skip lines.
- Nesting is capped at 20, so a cyclic YAML alias is a structured parse
error, not a stack overflow.
## Testing
`vitest` 2546 pass (17 when-specific); `tsc --noEmit` (tool-server,
argent-mcp, argent-cli), eslint, prettier clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
b50d51a2de |
chore: bump workspace packages to 0.16.0 (#513)
## What Lockstep-bump all 16 `packages/*` workspace packages (and the matching `package-lock.json` entries) from `0.15.0` → **0.16.0**. ## Why The `packages/argent-private` submodule is already pinned at **v0.16.0**, while the workspace packages sat at 0.15.0. This aligns the whole repo on the single 0.16.0 version. ## Verification - `node scripts/check-workspace-versions.mjs` → `All workspace packages are at 0.16.0.` - `git submodule status` → clean (no `+`), pinned at `v0.16.0`. - Lockfile diff is exactly 17 version-field swaps (no unrelated churn — a full `npm install --package-lock-only` regeneration was rejected because it introduced unrelated `"peer": true` churn from a newer npm). |
||
|
|
07427917e2 |
fix(launcher,lens): drop the npm postinstall — its jobs move to runtime (#510)
## Why Shipping *any* `postinstall` makes pnpm 10+ wall the install behind its build gate: `ERR_PNPM_IGNORED_BUILDS`, `pnpm install` exits 1, and `pnpm exec argent` is unusable until the user runs `pnpm approve-builds` — their first experience of argent is a bricked CLI. The same script is also silently skipped by `--ignore-scripts`, Yarn PnP, and locked-down CI, so anything correctness-relevant in it was already unreliable (the codebase says as much in several places, e.g. `runTrustingDisk`). Live-verified during the 0.15.0 QA: with **all builds declined** in pnpm 11, argent installs, inits, and serves MCP fine — the postinstall was never load-bearing for install correctness. Removing it means pnpm users never see the approve-builds wall for argent itself. ## What the postinstall did, and where it went | Job | New home | |---|---| | SIGTERM a tool-server stranded by an upgrade that replaced its bundle dir (pnpm/yarn version-pinned layouts) | `sweepDeadStateFiles` in the launcher's slow path now retires **live** servers whose recorded bundle is gone from disk, with the same pid-identity guard as `killToolServerForInstallDir` (never signal a recycled pid; keep unidentifiable live records reachable for `server stop`). Same-bundle in-place bumps were already self-healed by the disk-authoritative version gate. | | `chmod +x` node-pty's macOS `spawn-helper` prebuilds (shipped without the exec bit; first `pty.spawn` otherwise fails `posix_spawnp`) | `ensureSpawnHelperExecutable()` in `lens-pty.ts`, run when the module loads, best-effort with the AppleScript fallback intact. | | Print the `argent init` hint | Dropped — init flows drive the install, and the hint never printed on pnpm/PnP anyway. | `ARGENT_SKIP_POSTINSTALL` in `update.ts` is kept deliberately: downgrades and pinned installs fetch older versions whose postinstall still exists and honors it. ## Testing - New `launcher-sweep.test.ts` (6 tests) exercises the sweep against **real processes**: live-server-with-deleted-bundle is terminated and its record unlinked; live server with intact bundle untouched; recycled-pid record kept, not signalled; dead-pid record unlinked; legacy slot untouched; a SIGTERM-trapping orphan doesn't hold the sweep (and the spawn lock above it) hostage for its kill grace window — the record is unlinked and the SIGKILL escalation runs in the background. - New `ensureSpawnHelperExecutable` tests (real fs, darwin-gated) verify the +x restore and silent failure; a regression test pins that `loadNodePty` tolerates req seams without `resolve`. - Full suites green in all touched packages: tools-client 154, installer 535, cli 248, mcp 76, argent 60. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
551c781fb0 |
feat(flow): support running end-to-end flows without agent (#429)
# Flow E2E
This PR turns flows from replayable tool-call recordings into a
declarative, portable e2e test system that runs headlessly via `argent
flow run <name>` — no LLM in the loop, non-zero exit on failure,
suitable for CI.
Agents can still replay flows via `flow-execute` and get the full output
from each step after it finishes.
## Flow format
Flows are YAML files in `.argent/flows/`, now built from **directives**
interpreted by the runner rather than raw tool calls:
- `launch` — terminate + relaunch the app under test (per-platform app
id map supported); its presence marks a flow as **e2e** (controls its
own start state) vs. a **fragment** (runs against current state,
declares an `executionPrerequisite`, composable via `run:` with
cycle/depth guards).
- `tap`, `type` (focus handshake + optional submit), `scroll-to`
(momentum-free, increments by half the container, `within:` for nested
scrollers), `await`/`assert` (`visible`/`exists`/`hidden`/`text`
conditions), `wait`, `snapshot`, `echo`, and raw `tool:` as escape hatch
— still fully supported, so previously recorded flows keep working
unchanged.
- **Selectors** are `{ text, identifier, role }`; a bare string is a
loose selector resolving identifier-first, then visible text. Any
directive failure hard-stops the flow; later steps report `skip`.
## Execution engine
- Flows store no device id — the runner binds a device at replay
(explicit `--device`/`--platform` or the single booted one).
- Selector resolution runs against **platform-unified UI trees**: iOS
native view hierarchy (full testID coverage, gated on native-devtools
connecting), Android full accessibility hierarchy (full resource-id
coverage), Chromium CDP DOM, and the Vega automation toolkit. A shared
flatten/text-hoisting pass lets `text` assertions read what an
identified container visibly shows. Vega is remote-driven, so touch
directives fail with guidance to use `tv-remote`/`keyboard`.
- Steps wait for the tree to **settle** (two consecutive identical
reads) before acting; `launch` additionally gates on platform
tree-source readiness instead of silently degrading.
## Visual snapshots
`snapshot` diffs a full-resolution screenshot against baselines in
`.argent/flows/__baselines__/<flow>/`, keyed by platform + resolution,
with configurable `maxMismatch` and `--update-baselines`. The status bar
is pinned for the whole run (iOS `simctl status_bar`, Android demo mode)
so clocks/battery don't drive diffs. Baseline/current/diff images are
returned as artifacts on failure (and the written baseline on first
capture/update); a clean pass carries none, keeping reports and agent
context lean.
## Recording
The record-live workflow (`flow-start-recording` → `flow-add-step` →
`flow-finish-recording`) now emits directives automatically: coordinate
taps are rewritten to portable selector `tap:` steps (selector captured
from the pre-tap tree), a leading `restart-app` becomes `launch:`,
`flow-execute` of a sibling fragment becomes `run:`, and device ids are
stripped. The skill instructs the agent to polish the saved YAML
afterwards (fold tap+keyboard into `type:`, swipes-to-reach into
`scroll-to:`, awaits into sugar form).
## Also included
- `argent flow run` / `argent flow list` CLI with per-step report
rendering, artifact materialization, and `--json` output.
- New structured failure codes for flow validation, device resolution,
composition, and devtools readiness.
- Extensive unit test coverage (tree adapters, selector matching,
scrolling, composition, type focus, snapshots, status bar).
|
||
|
|
2a01e407b3 |
chore: release 0.15.0 (submodule + workspace bump) (#484)
## What - Bump the `packages/argent-private` submodule pointer from `v0.11.0-8-g2953e89` to **v0.15.0** (`41484e4`). The superproject pin had drifted ~4 releases behind the checked-out submodule. - Lockstep-bump all `packages/*` workspace packages from `0.14.0` → **0.15.0** (and the matching `package-lock.json` entries) to line up with the submodule. ## Why The submodule and the workspace were out of sync: the working tree had `argent-private` checked out at v0.15.0 while the superproject still pinned the v0.11 era, and the JS packages sat at 0.14.0. This adopts v0.15.0 as the single, consistent version across the repo. ## Verification - `node scripts/check-workspace-versions.mjs` → `All workspace packages are at 0.15.0.` - `git submodule status` → clean (no `+`), pinned at `v0.15.0`. - Lockfile diff is exactly 15 version-field swaps (no unrelated churn). |
||
|
|
7bd017a796 |
feat(installer): committable repo-local (--local) install mode (#428)
## Summary Adds an opt-in **committable / repo-local** install mode so a team can version Argent _with the repo_. `argent init --local` installs `@swmansion/argent` as a project **devDependency** and writes MCP configs that launch the project-local copy — so after `git clone && npm install`, every teammate has the same Argent version and MCP wiring with **no global install and no per-developer `argent init`**. **Global mode stays the default** and is unchanged; everything here is additive and backward-compatible. Motivation: the workflow some users already do by hand (#207). Supersedes the earlier, since-closed #232 — this version is Windows-safe (`node`, not the `.bin` shim), handles Yarn PnP, and closes the cross-install tool-server hazards rather than leaving them. ## What changed **`init`** - `--local` / `--global` flags + an interactive "How should argent be installed?" prompt. Mutually exclusive; non-interactive (`--yes`) defaults to **global**. - Local mode installs the devDependency with the package manager detected from the project's **lockfile** (run with `cwd = projectRoot`). - MCP entry points at the local copy: `node node_modules/@swmansion/argent/dist/cli.js mcp` (the bin path is derived from the installed `package.json` `bin` and existence-checked — forward slashes, committable, Windows-safe). Yarn PnP → `yarn argent mcp`; an `npx --no-install argent mcp` fallback is used only when the bin can't be resolved. - Records the mode in a committed `<root>/.argent/install.json`. - Drops global-only adapters (Windsurf/Hermes) in local mode; prints team-setup / commit guidance. **`update`** — detects the project's mode; in local mode reads the installed version from `node_modules` (not the global binary / npx cache) and bumps the **devDependency + lockfile**, then re-emits the local MCP command. **`uninstall`** — scoped to the project's mode: a local-mode uninstall removes the **local devDependency only and never the shared global install**, and prunes `.argent/install.json`. Global-mode behavior is unchanged. **Cross-install hardening (the gate that makes per-project pinning safe)** - `launcher`: a tool-server is reused only when its `bundlePath` matches the caller's — a repo-local pin never silently runs against (or kills) a different version's server. - `postinstall`: only stops a tool-server spawned from *this package's own* bundle, so a devDependency install can't tear down an unrelated editor session. **Telemetry** — adds an `install_mode` dimension to init/update/uninstall events. ## Testing - New unit tests: install-mode helpers + record (`utils`), mode-aware `getMcpEntry`/`resolveLocalCommandMode` incl. the opencode array form (`mcp-configs`), local-only uninstall guard (`uninstall`), and bundlePath-gated tool-server reuse (`launcher`). - All existing suites green (installer 346, tools-client 115, telemetry 191, registry 83, argent 13, tool-server 1621). Build + lint clean. - **Live end-to-end** in an isolated sandbox: `init --local` → real MCP stdio handshake serves **69 tools from `node_modules`**; `update --local` reads the local version; `uninstall --local` removes the local install and **leaves the global install intact**; `init --global` unchanged; flag conflict rejected. ## Notes / known limitations - Recommended on mainstream platforms (macOS, Linux x64, Windows x64) with prebuilt native binaries; Linux arm64 / Windows arm need a C/C++ toolchain to build `tree-sitter` on `npm install` (documented in the README). - Concurrent sessions of two *different* Argent versions on one machine each spawn their own tool-server; an orphaned one idle-times-out (no session is ever broken). 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
3393d22edd |
feat(telemetry): derive distinct_id from a stable host fingerprint (#444)
## Summary Replaces the random-UUID telemetry `distinct_id` with a stable per-machine id derived from the host fingerprint, so PostHog's native "Unique users" counts machines (funnels / retention / breakdowns work with no HogQL). Every Argent entry point - installer, CLI, tool-server, MCP - derives the id from one shared code path, so a given machine reports a single identity across every event and across install / uninstall / reinstall. ## What changed - `distinct_id = uuidv5(hostFingerprint, NAMESPACE)`, where the fingerprint comes from `simulator-server fingerprint`. Deterministic, keeps the UUID shape, and never stores the raw hardware value in PostHog (only the SHA-1-derived UUID leaves the process). - The fingerprint is resolved in `buildPayload` - the single `capture()` path shared by every entry point - so installer / CLI / tool-server / MCP all produce the same id. Resolved lazily, once per process, memoized. - One-time, local-only migration: the first time a fingerprint resolves, `~/.argent/telemetry-id` is rewritten from the legacy random UUID to the derived id. No PostHog `alias` / `$identify` event is emitted. - Fallback: if the fingerprint can't be resolved (unsupported platform, binary absent), the stored or a fresh random UUID is used - identically for every entry point on that machine, self-healing to the derived id on the next successful resolve. - Hardening: never throws; the fingerprint is validated (exactly 64 hex, case-insensitive) before hashing; corrupt / empty / unreadable id files self-heal; the binary is spawned at most once per process. ## Why the id is stable across install -> uninstall -> reinstall Uninstall deletes `~/.argent/telemetry-id`. Because the id is `uuidv5(fingerprint)` and the fingerprint is deterministic per machine, a fresh install recomputes the identical id. Previously only the tool-server resolved the fingerprint while the installer emitted under a random UUID, so this cycle produced a different random id each time. ## Bundling note for reviewers `@argent/telemetry` now depends on `@argent/native-devtools-ios` to locate the binary. That package computes its bin dir from `__dirname` at module load, which is undefined in an ES module. The installer / CLI / MCP ship as ESM bundles, so `bundle-tools.cjs`'s ESM banner is extended to shim `__dirname` / `__filename` (the CJS tool-server bundle already has them natively). Without this shim those bundles would crash on load, so the banner change is load-bearing. ## Testing - Unit: 219 telemetry tests - RFC 4122 v5 vectors, migration, idempotency, case/length validation, corrupt-file self-heal, spawn-at-most-once, and all fallbacks. - E2E on a real machine + booted iPhone 16 Pro: installer, CLI, and tool-server runtimes all emit the same derived id; the id is stable across a delete/recreate (uninstall/reinstall) cycle; a legacy v4 id migrates locally with no alias/identify emitted; verified from an ESM bundle placed in the real install's `dist/` so the binary resolves via the bundled `__dirname` with no env override; tool calls against the device carry the same id. |
||
|
|
c5bab2a83d |
fix(cli): let a tool's own --args field win over the whole-payload flag (#458)
## Bug
`argent run flow-add-step` declares its own `args` field — a JSON string
holding the recorded step's tool arguments. But the CLI flag parser
hardcoded `--args` as a whole-payload escape hatch, so `--args` shadowed
the tool's own `args` field. The documented per-flag form
```
argent run flow-add-step --command gesture-tap --args '{"udid":"...","x":0.5,"y":0.5}'
```
silently dropped the step arguments: the `--args` JSON was consumed as
the whole payload and the tool's `args` field stayed `undefined`,
producing a misleading downstream validation error. Only the nested
full-payload form worked.
## Fix
Make `--args` schema-aware in `parseFlags()`:
- When the tool's schema declares a property named `args`
(`schema.properties.args`), `--args <value>` is routed through the
normal per-field handling and coerced by its declared type (a `string`
for flow-add-step, so the raw JSON string passes straight into the
`args` field). Both `--args value` and `--args=value` forms are
supported.
- When the schema does NOT declare `args`, the existing whole-payload
behavior is preserved exactly, including the `--args -` stdin sentinel.
`printToolHelp()` no longer prints the global whole-payload `--args
<json>` / `--args -` lines for tools that declare their own `args`
field, so the help stops contradicting the per-field `--args` shown in
the schema flags.
The change is general: any tool with an `args` field benefits, with no
special-casing by tool name.
## Verification
- `npm run build` (root tsc) — clean.
- `npm test -w @argent/cli` — 172 passed, including 6 new `parseFlags`
cases covering schema-with-`args` (space-separated + inline forms, plus
sibling fields) and schema-without-`args` (whole-payload preserved,
`--args -` sentinel, no-schema fallback).
- Prettier + ESLint (`--max-warnings 0`) clean on the touched files.
Full CLI end-to-end (running `flow-add-step` against a live tool-server
with an active flow recording) was not exercised here; the added unit
tests prove the parser behavior.
Fixes #452
---
### CLI end-to-end verification
Ran the documented per-flag form against a live tool-server with an
active flow recording:
- **Before (global argent 0.13.0):** `argent run flow-add-step --command
gesture-tap --args '{"udid":"...","x":0.5,"y":0.35}'` → `Invalid params
for tool "gesture-tap": udid expected string, received undefined ...`
(args dropped).
- **After (this branch):** same command → `{ "message": "Step added to
\"colltest\" flow", "toolResult": { "tapped": true } }`, and the
recorded YAML contains the step **with** its args (`udid`/`x`/`y`). The
per-flag form now works as documented.
|
||
|
|
a7722df8a2 |
fix(cli): reject empty numeric flags and array/-json interleave crash (#432)
Fixes two related defects in `packages/argent-cli/src/flag-parser.ts`,
the argv-to-JSON flag parser used by `argent run`. The package
previously had no dedicated test file for it; this PR adds one covering
both fixes.
## Defect A: empty/whitespace numeric values coerced to 0
`coerceScalar` validates number/integer fields with `Number.isNaN` /
`Number.isInteger`, but `Number("")` and `Number(" ")` both evaluate to
`0`, so those guards pass. An empty or whitespace-only value was
therefore silently accepted as `0` instead of being rejected.
Reachable via `--x=` (empty inline), `--x ""`, and `--x " "`.
- Observed: `parseFlags(["--x="], { type: "object", properties: { x: {
type: "number" } } })` returned `{ x: 0 }`.
- Expected: rejected, the same way a non-numeric string like `"abc"`
already is.
Fix: reject an empty or whitespace-only value up front for
number/integer types, throwing the same `FlagParseException` the
function already throws for `"abc"` (`--<flag> expected a
number/integer, got "<raw>"`). Valid numbers are unaffected.
## Defect B: array + `-json` interleave throws a raw TypeError
`seenArrayFields` is only populated by the array branch, but the
`--field-json` escape hatch writes `args[fieldName]` directly and can
set it to a non-array. If a field was already seen as an array, a later
array-form occurrence ran `(args[flag] as unknown[]).push(...)` on a
non-array value and threw a raw `TypeError`. `run.ts` only catches
`FlagParseException` and re-throws anything else, so the user got an
uncaught stack trace instead of a clean error.
Repro:
```
parseFlags(
["--tags", "a", "--tags-json", '"b"', "--tags", "c"],
{ type: "object", properties: { tags: { type: "array", items: { type: "string" } } } }
)
```
- Observed: throws `TypeError: args[flag].push is not a function`
(uncaught, surfaces as a stack trace through `run.ts`).
- Expected: a clean validation error.
Fix: in the array branch, when `args[flag]` is not actually an array
(because `--field-json` replaced it), throw a `FlagParseException`
explaining the `--field` and `--field-json` forms cannot be mixed for
the same field, never a raw `TypeError`.
## Tests
Adds `packages/argent-cli/test/flag-parser.test.ts`. The new tests fail
before the fix (4 failures) and pass after; the full `argent-cli` suite
stays green (90 passed). Behavior for valid inputs is unchanged.
|
||
|
|
c5b9857fa5 |
chore: bump all workspace packages to 0.14.0 (#454)
Bumps every package under `packages/*` from 0.13.0 → 0.14.0 in lockstep. - All 14 workspace packages bumped to `0.14.0`. - `package-lock.json` regenerated to match (also picks up npm's `"peer": true` normalization). - `npm run check:versions` passes: *All workspace packages are at 0.14.0.* Internal deps use `file:../` references, so no dependency version specifiers needed changing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
a92c859d07 |
feat(argent-lens): argent lens — bind a claude session to the preview window (#416)
## What Adds `argent lens` — open Argent Lens bound to a fresh `claude` session. ## Why The Lens preview window and the agent communicate through a shared, process-wide tool-server that carries **no per-agent identity** (only a coarse telemetry header). So when the user requests changes in the window, there's no reliable way to route them to the *specific* agent that opened it. `argent lens` sidesteps the problem by inverting ownership: the human launches Lens, and Lens spawns (and therefore owns) exactly one `claude` terminal. The binding is 1:1 by construction — no identity plumbing required. ## How it works 1. `argent lens` ensures a tool-server and **begins a CLI Lens session**, which opens the preview window up front (no `await_user_selection` needed) and keeps it open across rounds. 2. It spawns a tracked `claude` terminal in the current directory — a TypeScript port of the macOS applet's `osascript` spawn/track mechanism — seeded to propose variants without blocking. 3. A watcher polls `GET /preview/outcome`; on each submitted round it types a one-line feedback summary into that terminal, queuing it to the agent as its next prompt. Requesting changes therefore "talks back" to the bound agent instead of closing the window. macOS only (drives Terminal/iTerm via `osascript`); off-darwin it exits with a clear message. ## Changes - **CLI** `lens-terminal.ts` — `osascript` spawn/track + a new write-into-running-session path (the "outputting" channel; injects input into the running TUI, which a tty write cannot do). - **CLI** `lens.ts` — the command + feedback formatter. - **tool-server** — a `cliSession` flag in the variant store (opens the window, suppresses auto-close on submit); `POST /preview/cli-session` and `GET /preview/outcome` routes. - **UI** — relabels the submit action to "Request changes" while a CLI session is active. Behind the existing `argent-lens` feature flag. ## Verification - Build + typecheck across the workspace; ESLint (`--max-warnings 0`) + Prettier clean. - 34 new unit tests; full `@argent/cli` suite **118 passing**, tool-server variant/preview suites **46 passing**. - **E2E (observed on this machine):** - **tool-server HTTP** — `cli-session` toggles `cliSession` true/false; submitted feedback round-trips through `/preview/outcome`. - **terminal injection** — spawned a window running `cat`, confirmed `writeToSession` lands text in the running program's **stdin** (both iTerm and Terminal), with embedded newlines flattened. - **full relay** — the real `watchAndRelay` loop against a real tool-server typed two distinct submission rounds' feedback into a stand-in agent terminal (dedup on `completedAt` verified). - `argent lens --help` and the feature-flag gate (exit 1 with guidance, no spawn). Note: a real end-to-end with a live `claude` agent was not run (it would drive a paid interactive session); the agent-facing channel is proven by injecting into a stand-in process's stdin via the exact same code path. --------- Co-authored-by: Filip131311 <contact@filipkaminski.com> |
||
|
|
6bc5376746 |
fix(tool-server): stop list-devices from hanging - wedged-VVD stall and CLI socket leak (#419)
## Summary
`list-devices` (an `alwaysLoad` tool called at session start and
frequently after)
could appear to **hang**. Investigation found **two independent
causes**, both fixed here:
1. **Server-side (Vega):** a wedged Vega VVD turned `list-devices` into
a ~40s stall
and leaked `vega` CLI subprocesses.
2. **Client-side (CLI):** every `argent run …` lingered a constant **~6s
after it had
already printed its result**, because a health-check `fetch` never
drained its
response body and kept an undici keep-alive socket ref'd until the
server closed it.
Net effect for `argent run list-devices`: **6.15s → 0.91s**, and the
worst-case
wedged-VVD stall drops from ~40s to a bounded short call.
---
## Problem 1 — wedged Vega VVD stalls `list-devices` (~40s) and leaks
processes
On a host with the Vega SDK installed and a **running-but-unresponsive
VVD**,
`list-devices`' Vega discovery path made **two serial 20s CLI calls**
that both hung:
- `vega device list` → SIGKILL at 20s
- then (recovery) `vega device info` → SIGKILL at another 20s → **~40s
total**
Three compounding defects:
- `execFileAsync` resolves on stdio **close**, not child **exit**. The
`vega` launcher
forks a `python3 → node → vda` worker tree; an orphaned worker holds the
stdout pipe
open, so the call stayed pending for the full timeout even after the
launcher was
killed.
- The `device info` recovery fired even when `device list` had **hung**,
doubling the
cost and spawning a second hanging subprocess.
- On timeout we killed only the **direct child**, so the `python3 → node
→ vda` worker
tree was **orphaned, not reaped** — leaking a process tree per call (a
wedged host had
accumulated ~269 of them).
### Fix
- **`runVega` (`vega-cli.ts`):** switched from `execFileAsync` to
`spawn` with
**`detached: true`**, making the launcher its own **process-group
leader**, and on
timeout SIGKILL the **whole process group** (`process.kill(-pid)`) —
which reaps the
entire `python3 → node → vda` tree, **not just the launcher**. We also
destroy our
stdio stream ends so a pipe-holding worker can't keep the call pending.
(`execFile`
silently drops `detached`, which is why the switch to `spawn` was
required.)
- **Success path doesn't depend on stdio EOF either:** we prefer `close`
(fully
drained), but if a grandchild holds the stdout pipe open after a **clean
exit**, we
fall back to `exit` + a short (~1s) drain grace and resolve with the
captured
output — so a finished call can't be stalled into the timeout and then
rejected,
discarding valid data. The output cap is measured in real UTF-8 bytes.
For that
guarantee to hold at the boundary, the `exit` handler **disarms the main
timeout
timer**: once the child has terminated the wall-clock deadline is moot,
so a clean
exit landing within the drain grace of the deadline resolves with its
output instead
of being mis-rejected as a `timeout` (which would also wrongly suppress
the
`listVegaDevices` recovery for a still-running VVD).
- **Belt-and-suspenders for a worker that escapes the group:** an
earlier
investigation reported the worker tree `setsid()`-ing into its own
session (which
would defeat a group-only SIGKILL). To be safe regardless of which is
true, on
timeout we **snapshot the launcher's descendants from the process table
*before*
killing** (a setsid'd worker keeps its `ppid` pointing at the launcher
until the
launcher dies, so a `ppid` tree-walk still reaches it) and SIGKILL those
pids
individually after the group kill. The snapshot is **precise** — only
this
launcher's own descendants, by pid, so a concurrent `vega` call's
workers are never
touched — and bounded, and the group kill runs regardless of whether it
succeeds.
- A real-subprocess test confirms **0 orphans** after a timeout,
including a worker
deliberately spawned into its **own** process group (so the group kill
alone cannot
reach it — the test fails without the descendant sweep).
- **`listVegaDevices` (`vega-devices.ts`):** skip the `device info`
recovery only when
`device list` **timed out** (a wedged agent — keyed off the failure's
`error_kind: "timeout"`), so a hung list no longer pays for a second
timeout wait. A
*fast* (non-timeout) list failure still recovers a genuinely-running VVD
rather than
mis-reporting it as stopped. Tightened discovery timeouts (20s → 6s/4s —
a generous
multiple of the ~1s healthy time so a cold-start `vega` launcher isn't
spuriously
timed out, with their sum (10s) kept under the 15s branch deadline with
margin).
- **`list-devices.ts`:** added a 15s `withDeadline` backstop around the
Android and Vega
branches so no single branch can stall the whole fan-out (returns
partial results +
logs a note). Sized to sit ~5s above the Vega branch's ~10s worst case,
so the
backstop never truncates a slow-but-completing branch (which would drop
a real
device); an invariant test guards that ordering.
- **`readAvdName` (`adb.ts`):** run the two `getprop` probes
concurrently so a wedged
emulator costs 5s, not 10s.
---
## Problem 2 — `argent run` hangs ~6s after printing output (CLI socket
leak)
Independent of Vega. The tool-server returns `list-devices` in <1s, but
the CLI process
took a **constant ~6s** to exit. Any path that calls `process.exit()`
was instant; any
path that returned naturally (`argent run …`, `argent run … --help`,
`argent tools`)
lingered ~6s.
**Root cause:** `isToolsServerHealthy` (`launcher.ts`) did
`const res = await fetch('/tools'); return res.ok;` and **never drained
the body**.
`/tools` is a large (~112KB) payload, so undici keeps the keep-alive
socket **ref'd**
until the tool-server's idle `keepAliveTimeout` (~5s) closes it.
`ensureToolsServer`
runs this health check on every invocation, and `run()`'s success path
has no
`process.exit(0)`, so the ref'd socket holds the event loop open.
(Confirmed
telemetry-independent — `DO_NOT_TRACK` made no difference.) The same
undrained-body
pattern existed in `link.ts` (`argent link`).
### Fix
Drain the response body before returning in both health-check-style
fetches:
```ts
await res.body?.cancel().catch(() => {});
return res.ok;
```
(`fetchTools`/`callTool` were already fine — they `await res.json()`.)
---
## Testing
**Empirical, end-to-end** (on a machine reproducing the wedged VVD):
| Command | Before | After |
| --- | --- | --- |
| `argent run list-devices` | 6.15s | **0.91s** |
| `argent run list-devices --help` | 6.14s | **0.16s** |
| `argent tools` | 6.15s | **0.16s** |
| handle probe after run | 2 sockets ref'd for ~6s | **none — immediate
exit** |
- Raw `POST /tools/list-devices` was ~0.7s throughout — confirming the
~5.4s was pure
CLI teardown, not tool work.
- **Process-group reap proven empirically:** the live `vega → bash →
python3 → node`
tree all shares the detached launcher's PGID; a group-SIGKILL left **0
survivors**.
A real-subprocess test (unmocked `runVega` vs. a fake hanging `vega` on
`PATH`) confirms
it settles at its deadline **and** leaves **0 orphaned processes**.
**Automated:**
- `vega-cli-timeout.test.ts` (real-subprocess test) — `runVega` rejects
on its deadline,
**reaps the entire worker tree (0 orphans)** — the fake's hung worker is
spawned into its
**own** process group, so the test fails without the descendant sweep —
and returns
normally when the CLI responds. Also covers the boundary case: a **clean
exit whose
drain grace outlasts the deadline** resolves with its captured output
rather than being
rejected as a `timeout` (guards the `exit`-handler timer disarm above).
- `vega-adb-connect-recovery.test.ts` — a *timed-out* `device list` does
not trigger a
second `device info` call (no stacking); a *fast, non-timeout* failure
**still** recovers
a running VVD.
- `list-devices-deadline.test.ts` — `withDeadline` returns the branch
value on the happy
path and the fallback (with a logged note) when a branch exceeds the
deadline.
- `list-devices.test.ts` — added a `spawn` mock (vega moved off
`execFile`).
- `launcher-helpers.test.ts` — `isToolsServerHealthy` cancels (drains)
its response body.
- Suites green: **tool-server (1610), argent-tools-client (109),
argent-cli (84)**.
- eslint (`--max-warnings 0`), prettier, and `tsc` clean.
---
|
||
|
|
5f9dd48e2a |
fix(tool-server): prevent duplicate tool-servers after an nvm node switch (#385)
## Problem Switching Node versions with **nvm** can leave **two (or more) `tool-server` processes alive at once** while `~/.argent/tool-server.json` tracks only one. The extra servers are orphaned (untracked, on leaked ports) until their 30‑minute idle timeout. This was reproduced live: a machine had **three** `node …/dist/tool-server.cjs start` processes running, all spawned within the same minute, with state tracking only the last one. ## Root cause `@argent/tools-client` `ensureToolsServer()` ran a non-atomic `read state → check alive+healthy → clearState → spawn → writeState` sequence with: 1. **No cross-process serialization.** An nvm switch relaunches `argent mcp` under the new Node while the *previous* MCP's 30s health monitor reconnects — several launchers run `ensureToolsServer()` at nearly the same time, all observe "no healthy server", and each spawns its own **detached** server on a fresh free port. Last‑writer‑wins on the state file orphans the rest. 2. **No kill-before-respawn.** When the tracked server was alive but unhealthy, the old code just `clearState()`d and spawned a new one, leaving the old detached process running untracked. ## Fix (`packages/argent-tools-client/src/launcher.ts`) - **O_EXCL spawn lock** (`~/.argent/tool-server.lock`) serialises the spawn decision across processes: per-acquisition nonce, stale‑steal (dead holder / aged lock), bounded wait, and a hot‑spin‑proof reclaim loop. Inside the lock, `ensureToolsServer` **double‑checks** for a peer‑spawned healthy server before spawning, so a burst of concurrent launches collapses to a single server. - **Kill-before-respawn** terminates a wedged server we own before spawning its replacement, with three guards so it can never signal the wrong process: - `managed === "autospawn"` — a user's `argent server start` server is now tagged `managed: "cli"` and is **never** killed by the auto‑spawn path; - a **structural** `node <bundlePath> start` command-line identity match (not a bare substring); - a re-check of that identity immediately before each signal (covers PID reuse across the SIGTERM grace window). - **`spawnToolsServer` reaps its detached child on every reject path**, so a readiness timeout can no longer leak a child that binds its port moments later as an untracked second server. The lock-free fast path (reuse a healthy tracked server) is unchanged, so steady‑state behaviour and latency are unaffected; the lock is only taken when a spawn is actually needed. ## Tests New `packages/argent-tools-client/test/launcher-duplicate-spawn.test.ts`: - a 5× concurrent launch burst collapses to **one** server; - an alive‑but‑unhealthy `autospawn` server is terminated (not orphaned) on respawn; - a recycled pid whose command line doesn't match is **never** signalled; - a `managed: "cli"` server is left alive instead of being killed; - a readiness timeout reaps the spawned child (no orphan). Each case was verified to **fail against the pre-fix code** and pass with the fix. Existing `launcher-spawn` / `launcher-state` suites are unchanged and green. > Note: the `@swmansion/argent` `dispatcher › forwards SIGTERM to the child binary` unit test is a pre-existing flake (alternates pass/fail independent of this change, which doesn't touch that package). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Radoniusz Cloudiusz <radoniusz@radoniusz.local> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
0718e622ab |
chore(deps)(deps): bump the npm-minor-patch group across 2 directories with 9 updates (#422)
Bumps the npm-minor-patch group with 9 updates in the / directory: | Package | From | To | | --- | --- | --- | | [globals](https://github.com/sindresorhus/globals) | `17.6.0` | `17.7.0` | | [prettier](https://github.com/prettier/prettier) | `3.8.4` | `3.8.5` | | [semver](https://github.com/npm/node-semver) | `7.8.4` | `7.8.5` | | [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) | `8.61.1` | `8.62.0` | | [@clack/prompts](https://github.com/bombshell-dev/clack/tree/HEAD/packages/prompts) | `1.5.1` | `1.6.0` | | [posthog-node](https://github.com/PostHog/posthog-js/tree/HEAD/packages/node) | `5.35.0` | `5.38.6` | | [smol-toml](https://github.com/squirrelchat/smol-toml) | `1.6.1` | `1.7.0` | | [electron](https://github.com/electron/electron) | `42.4.1` | `42.5.0` | | [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) | `5.9.2` | `5.9.3` | Bumps the npm-minor-patch group with 1 update in the /packages/telemetry directory: [posthog-node](https://github.com/PostHog/posthog-js/tree/HEAD/packages/node). Updates `globals` from 17.6.0 to 17.7.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/sindresorhus/globals/releases">globals's releases</a>.</em></p> <blockquote> <h2>v17.7.0</h2> <ul> <li>Update globals (2026-06-22) (<a href="https://redirect.github.com/sindresorhus/globals/issues/345">#345</a>) 33b75f9</li> </ul> <hr /> <p><a href="https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0">https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/sindresorhus/globals/commit/a19670cc86c1218e915657c55ea02ba3e7623834"><code>a19670c</code></a> 17.7.0</li> <li><a href="https://github.com/sindresorhus/globals/commit/9611620bad0ea45531ae0261b986ce694374e42c"><code>9611620</code></a> Update actions (<a href="https://redirect.github.com/sindresorhus/globals/issues/346">#346</a>)</li> <li><a href="https://github.com/sindresorhus/globals/commit/33b75f9ddeb6f9ddd81251b043667eb8104a8d15"><code>33b75f9</code></a> Update globals (2026-06-22) (<a href="https://redirect.github.com/sindresorhus/globals/issues/345">#345</a>)</li> <li><a href="https://github.com/sindresorhus/globals/commit/887dd529bde24486b7f9e31d1b2c515df2b7cf5c"><code>887dd52</code></a> Fix build script (<a href="https://redirect.github.com/sindresorhus/globals/issues/344">#344</a>)</li> <li>See full diff in <a href="https://github.com/sindresorhus/globals/compare/v17.6.0...v17.7.0">compare view</a></li> </ul> </details> <br /> Updates `prettier` from 3.8.4 to 3.8.5 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/releases">prettier's releases</a>.</em></p> <blockquote> <h2>3.8.5</h2> <ul> <li>Fix Flow variance annotation print (<a href="https://redirect.github.com/prettier/prettier/pull/19022">#19022</a> by <a href="https://github.com/marcoww6"><code>@marcoww6</code></a>)</li> </ul> <p>🔗 <a href="https://github.com/prettier/prettier/blob/3.8.5/CHANGELOG.md#385">Changelog</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/prettier/prettier/blob/main/CHANGELOG.md">prettier's changelog</a>.</em></p> <blockquote> <h1>3.8.5</h1> <p><a href="https://github.com/prettier/prettier/compare/3.8.4...3.8.5">diff</a></p> <h4>Flow: Support <code>readonly</code> as a variance annotation (<a href="https://redirect.github.com/prettier/prettier/pull/19022">#19022</a> by <a href="https://github.com/marcoww6"><code>@marcoww6</code></a>)</h4> <p>Flow now accepts <code>readonly</code> as a property variance annotation, equivalent to <code>+</code> (covariant/read-only).</p> <!-- raw HTML omitted --> <pre lang="jsx"><code>// Input type T = { readonly foo: string, }; <p>// Prettier 3.8.4<br /> SyntaxError</p> <p>// Prettier 3.8.5<br /> type T = {<br /> readonly foo: string,<br /> };<br /> </code></pre></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/prettier/prettier/commit/1ce8c47015ab1e9dfa99f6238df60ff1e70e1498"><code>1ce8c47</code></a> Release 3.8.5</li> <li><a href="https://github.com/prettier/prettier/commit/74923fa8316cd78f8461e77290915155efbcd714"><code>74923fa</code></a> Fix variance annotation</li> <li><a href="https://github.com/prettier/prettier/commit/8b4eb339d43edba35a509ff324d4cdb4416b3efc"><code>8b4eb33</code></a> Bump Prettier dependency to 3.8.4</li> <li><a href="https://github.com/prettier/prettier/commit/e9cbdfa1b755e68ea6f97b0b321524a5169a85d1"><code>e9cbdfa</code></a> Clean changelog_unreleased</li> <li>See full diff in <a href="https://github.com/prettier/prettier/compare/3.8.4...3.8.5">compare view</a></li> </ul> </details> <br /> Updates `semver` from 7.8.4 to 7.8.5 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/npm/node-semver/releases">semver's releases</a>.</em></p> <blockquote> <h2>v7.8.5</h2> <h2><a href="https://github.com/npm/node-semver/compare/v7.8.4...v7.8.5">7.8.5</a> (2026-06-19)</h2> <h3>Bug Fixes</h3> <ul> <li><a href="https://github.com/npm/node-semver/commit/9c8692ae05416e9dbe88d95ffe2b80e6964550fe"><code>9c8692a</code></a> <a href="https://redirect.github.com/npm/node-semver/pull/878">#878</a> include prereleases in tilde range lower bound with includePrerelease (<a href="https://redirect.github.com/npm/node-semver/issues/878">#878</a>) (<a href="https://github.com/chatman-media"><code>@chatman-media</code></a>)</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/npm/node-semver/blob/main/CHANGELOG.md">semver's changelog</a>.</em></p> <blockquote> <h2><a href="https://github.com/npm/node-semver/compare/v7.8.4...v7.8.5">7.8.5</a> (2026-06-19)</h2> <h3>Bug Fixes</h3> <ul> <li><a href="https://github.com/npm/node-semver/commit/9c8692ae05416e9dbe88d95ffe2b80e6964550fe"><code>9c8692a</code></a> <a href="https://redirect.github.com/npm/node-semver/pull/878">#878</a> include prereleases in tilde range lower bound with includePrerelease (<a href="https://redirect.github.com/npm/node-semver/issues/878">#878</a>) (<a href="https://github.com/chatman-media"><code>@chatman-media</code></a>)</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/npm/node-semver/commit/6e05b7637396ac66522cff8731f07cfe0ef49a29"><code>6e05b76</code></a> chore: release 7.8.5 (<a href="https://redirect.github.com/npm/node-semver/issues/879">#879</a>)</li> <li><a href="https://github.com/npm/node-semver/commit/9c8692ae05416e9dbe88d95ffe2b80e6964550fe"><code>9c8692a</code></a> fix: include prereleases in tilde range lower bound with includePrerelease (#...</li> <li>See full diff in <a href="https://github.com/npm/node-semver/compare/v7.8.4...v7.8.5">compare view</a></li> </ul> </details> <br /> Updates `typescript-eslint` from 8.61.1 to 8.62.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/releases">typescript-eslint's releases</a>.</em></p> <blockquote> <h2>v8.62.0</h2> <h2>8.62.0 (2026-06-22)</h2> <h3>🚀 Features</h3> <ul> <li>remove redundant package.json "files" (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444">#12444</a>)</li> </ul> <h3>🩹 Fixes</h3> <ul> <li>add "files" to rule-schema-to-typescript-types (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12441">#12441</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md">typescript-eslint's changelog</a>.</em></p> <blockquote> <h2>8.62.0 (2026-06-22)</h2> <h3>🚀 Features</h3> <ul> <li>remove redundant package.json "files" (<a href="https://redirect.github.com/typescript-eslint/typescript-eslint/pull/12444">#12444</a>)</li> </ul> <h3>❤️ Thank You</h3> <ul> <li>Kirk Waiblinger <a href="https://github.com/kirkwaiblinger"><code>@kirkwaiblinger</code></a></li> </ul> <p>See <a href="https://github.com/typescript-eslint/typescript-eslint/releases/tag/v8.62.0">GitHub Releases</a> for more information.</p> <p>You can read about our <a href="https://typescript-eslint.io/users/versioning">versioning strategy</a> and <a href="https://typescript-eslint.io/users/releases">releases</a> on our website.</p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/54e285728e5d8cb83fadb8041189f0c3b4ab436a"><code>54e2857</code></a> chore(release): publish 8.62.0</li> <li><a href="https://github.com/typescript-eslint/typescript-eslint/commit/81e4c2654c3f4d923766a888691add2c45b5d64a"><code>81e4c26</code></a> feat: remove redundant package.json "files" (<a href="https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint/issues/12444">#12444</a>)</li> <li>See full diff in <a href="https://github.com/typescript-eslint/typescript-eslint/commits/v8.62.0/packages/typescript-eslint">compare view</a></li> </ul> </details> <br /> Updates `@clack/prompts` from 1.5.1 to 1.6.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/bombshell-dev/clack/releases">@clack/prompts's releases</a>.</em></p> <blockquote> <h2><code>@clack/prompts</code><a href="https://github.com/1"><code>@1</code></a>.6.0</h2> <h3>Minor Changes</h3> <ul> <li> <p><a href="https://redirect.github.com/bombshell-dev/clack/pull/568">#568</a> <a href="https://github.com/bombshell-dev/clack/commit/f87933fb7b3f4c401b9e51a152b95cb8e7200fe5"><code>f87933f</code></a> Thanks <a href="https://github.com/florian-lefebvre"><code>@florian-lefebvre</code></a>! - Updates default formatter of <code>note()</code> to note dim lines anymore</p> <p>If you want the old behavior, provide a <code>format()</code> function:</p> <pre lang="diff"><code>import { note } from '@clack/prompts'; +import { styleText } from 'node:util'; <p>note( 'You can edit the file src/index.jsx', 'Next steps.'</p> <ul> <li>{ format: (text) => styleText('dim', text) } ); </code></pre></li> </ul> </li> <li> <p><a href="https://redirect.github.com/bombshell-dev/clack/pull/567">#567</a> <a href="https://github.com/bombshell-dev/clack/commit/cc6aab50186cff8a02dc98e9cfd3897c29a33b15"><code>cc6aab5</code></a> Thanks <a href="https://github.com/dreyfus92"><code>@dreyfus92</code></a>! - Add keyboard instruction footers to <code>select</code>, <code>multiselect</code>, and <code>groupMultiselect</code> in the active state, matching autocomplete. No option — always shown.</p> </li> </ul> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [<a href="https://github.com/bombshell-dev/clack/commit/2f2b52f77cbfa9af618c6d929249ab8395fc37a1"><code>2f2b52f</code></a>, <a href="https://github.com/bombshell-dev/clack/commit/e1b6ee71a76e17a3c33ba7ee6e5fb34e886233bb"><code>e1b6ee7</code></a>]: <ul> <li><code>@clack/core</code><a href="https://github.com/1"><code>@1</code></a>.4.2</li> </ul> </li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/bombshell-dev/clack/blob/main/packages/prompts/CHANGELOG.md">@clack/prompts's changelog</a>.</em></p> <blockquote> <h2>1.6.0</h2> <h3>Minor Changes</h3> <ul> <li> <p><a href="https://redirect.github.com/bombshell-dev/clack/pull/568">#568</a> <a href="https://github.com/bombshell-dev/clack/commit/f87933fb7b3f4c401b9e51a152b95cb8e7200fe5"><code>f87933f</code></a> Thanks <a href="https://github.com/florian-lefebvre"><code>@florian-lefebvre</code></a>! - Updates default formatter of <code>note()</code> to note dim lines anymore</p> <p>If you want the old behavior, provide a <code>format()</code> function:</p> <pre lang="diff"><code>import { note } from '@clack/prompts'; +import { styleText } from 'node:util'; <p>note( 'You can edit the file src/index.jsx', 'Next steps.'</p> <ul> <li>{ format: (text) => styleText('dim', text) } ); </code></pre></li> </ul> </li> <li> <p><a href="https://redirect.github.com/bombshell-dev/clack/pull/567">#567</a> <a href="https://github.com/bombshell-dev/clack/commit/cc6aab50186cff8a02dc98e9cfd3897c29a33b15"><code>cc6aab5</code></a> Thanks <a href="https://github.com/dreyfus92"><code>@dreyfus92</code></a>! - Add keyboard instruction footers to <code>select</code>, <code>multiselect</code>, and <code>groupMultiselect</code> in the active state, matching autocomplete. No option — always shown.</p> </li> </ul> <h3>Patch Changes</h3> <ul> <li>Updated dependencies [<a href="https://github.com/bombshell-dev/clack/commit/2f2b52f77cbfa9af618c6d929249ab8395fc37a1"><code>2f2b52f</code></a>, <a href="https://github.com/bombshell-dev/clack/commit/e1b6ee71a76e17a3c33ba7ee6e5fb34e886233bb"><code>e1b6ee7</code></a>]: <ul> <li><code>@clack/core</code><a href="https://github.com/1"><code>@1</code></a>.4.2</li> </ul> </li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/bombshell-dev/clack/commit/0e700562dfb54bd693d98c5b7e28d34213fcb226"><code>0e70056</code></a> [ci] release (<a href="https://github.com/bombshell-dev/clack/tree/HEAD/packages/prompts/issues/562">#562</a>)</li> <li><a href="https://github.com/bombshell-dev/clack/commit/f87933fb7b3f4c401b9e51a152b95cb8e7200fe5"><code>f87933f</code></a> fix(prompts): do not dim note contents (<a href="https://github.com/bombshell-dev/clack/tree/HEAD/packages/prompts/issues/568">#568</a>)</li> <li><a href="https://github.com/bombshell-dev/clack/commit/cc6aab50186cff8a02dc98e9cfd3897c29a33b15"><code>cc6aab5</code></a> feat(prompts): add instructions footer for <code>select</code>, <code>multi-select</code> & `group-...</li> <li>See full diff in <a href="https://github.com/bombshell-dev/clack/commits/@clack/prompts@1.6.0/packages/prompts">compare view</a></li> </ul> </details> <br /> Updates `posthog-node` from 5.35.0 to 5.38.6 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-js/releases">posthog-node's releases</a>.</em></p> <blockquote> <h2>posthog-node@5.38.6</h2> <h2>5.38.6</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3896">#3896</a> <a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> Thanks <a href="https://github.com/GauthierPLM"><code>@GauthierPLM</code></a>! - Only stamp $groups from the top-level <code>groups</code> when present (2026-06-26)</li> </ul> <h2>posthog-node@5.38.5</h2> <h2>5.38.5</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3955">#3955</a> <a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Dedupe feature flag called events per returned flag value. (2026-06-24)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.3</li> </ul> </li> </ul> <h2>posthog-node@5.38.4</h2> <h2>5.38.4</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3938">#3938</a> <a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> Thanks <a href="https://github.com/dustinbyrne"><code>@dustinbyrne</code></a>! - Respect <code>disable_capture_url_hashes</code> when capturing Express and NestJS request URLs. (2026-06-23)</li> </ul> <h2>posthog-node@5.38.3</h2> <h2>5.38.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3937">#3937</a> <a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Deprecate the Node SDK Sentry integration and point users to PostHog Error Tracking for Node. (2026-06-23)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/440e370fda48d629352f3280471a228ee973dcb0"><code>440e370</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.0</li> </ul> </li> </ul> <h2>posthog-node@5.38.2</h2> <h2>5.38.2</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3903">#3903</a> <a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Validate custom event UUID overrides and generate new UUIDs when invalid. (2026-06-19)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.3</li> </ul> </li> </ul> <h2>posthog-node@5.38.1</h2> <h2>5.38.1</h2> <h3>Patch Changes</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-js/blob/main/packages/node/CHANGELOG.md">posthog-node's changelog</a>.</em></p> <blockquote> <h2>5.38.6</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3896">#3896</a> <a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> Thanks <a href="https://github.com/GauthierPLM"><code>@GauthierPLM</code></a>! - Only stamp $groups from the top-level <code>groups</code> when present (2026-06-26)</li> </ul> <h2>5.38.5</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3955">#3955</a> <a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Dedupe feature flag called events per returned flag value. (2026-06-24)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.3</li> </ul> </li> </ul> <h2>5.38.4</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3938">#3938</a> <a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> Thanks <a href="https://github.com/dustinbyrne"><code>@dustinbyrne</code></a>! - Respect <code>disable_capture_url_hashes</code> when capturing Express and NestJS request URLs. (2026-06-23)</li> </ul> <h2>5.38.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3937">#3937</a> <a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Deprecate the Node SDK Sentry integration and point users to PostHog Error Tracking for Node. (2026-06-23)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/440e370fda48d629352f3280471a228ee973dcb0"><code>440e370</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.0</li> </ul> </li> </ul> <h2>5.38.2</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3903">#3903</a> <a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Validate custom event UUID overrides and generate new UUIDs when invalid. (2026-06-19)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.3</li> </ul> </li> </ul> <h2>5.38.1</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3886">#3886</a> <a href="https://github.com/PostHog/posthog-js/commit/e6d7fe2a5f10d29b3df69392f584970e7a7a4561"><code>e6d7fe2</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Stop sending deprecated no-op top-level <code>type</code>, <code>library</code>, and <code>library_version</code> fields in event batch payloads. Use <code>properties.$lib</code> and <code>properties.$lib_version</code> for SDK metadata; legacy queued <code>library</code> and <code>library_version</code> values are used as fallbacks when the official <code>$</code> properties are missing. (2026-06-18)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/e6d7fe2a5f10d29b3df69392f584970e7a7a4561"><code>e6d7fe2</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.2</li> </ul> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/PostHog/posthog-js/commit/d2faa824af1af2cb50b47178fb953bfc8812b389"><code>d2faa82</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> fix: preserve $groups passed via properties (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3896">#3896</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/5c4838f1671ece80d153aaeb6d946bb3e8c8240a"><code>5c4838f</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> fix: Dedupe feature flag called events by response (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3955">#3955</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/2a60c21134dd118c2367e56129bc9427079c3841"><code>2a60c21</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> fix(node): respect URL hash capture config (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3938">#3938</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/a3136c6de3114ee3d58e59a0c86f2b9c4f59a2b0"><code>a3136c6</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/bf6947d3e12ac512c99185be9b8b134c04eb563a"><code>bf6947d</code></a> feat(react-native): support session replay event triggers (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3932">#3932</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/2628a1af5f06f73cb2252de002e0da4b2d1a25a5"><code>2628a1a</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> chore(node): mark Sentry integration deprecated (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3937">#3937</a>)</li> <li>Additional commits viewable in <a href="https://github.com/PostHog/posthog-js/commits/posthog-node@5.38.6/packages/node">compare view</a></li> </ul> </details> <br /> Updates `smol-toml` from 1.6.1 to 1.7.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/squirrelchat/smol-toml/releases">smol-toml's releases</a>.</em></p> <blockquote> <h2>v1.7.0</h2> <p>This version slightly changes the behaviour of stringify: integers beyond the safe range are always emitted as float numbers.</p> <p>String decode logic has been rewritten, it is a bit faster now and uses a single-pass approach instead of a dual-pass approach as it did previously. The code should be a bit smaller too, though I didn't actually measure that.</p> <p>The package is now published with source-maps, declaration-maps, and a copy of the original TypeScript source files. This will improve your DX if you're like me and like Ctrl+Click'ing things a lot. ;)</p> <h2>What's Changed</h2> <ul> <li>improve performance of the string decode logic by <a href="https://github.com/cyyynthia"><code>@cyyynthia</code></a></li> <li>fix(stringify): emit integer-valued numbers beyond the safe-integer range as floats by <a href="https://github.com/spokodev"><code>@spokodev</code></a> in <a href="https://redirect.github.com/squirrelchat/smol-toml/pull/56">squirrelchat/smol-toml#56</a></li> <li>publish source-maps, declaration-maps, and original source files by <a href="https://github.com/cyyynthia"><code>@cyyynthia</code></a></li> <li>miscellaneous repository maintenance tasks by <a href="https://github.com/cyyynthia"><code>@cyyynthia</code></a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/spokodev"><code>@spokodev</code></a> made their first contribution in <a href="https://redirect.github.com/squirrelchat/smol-toml/pull/56">squirrelchat/smol-toml#56</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/squirrelchat/smol-toml/compare/v1.6.1...v1.7.0">https://github.com/squirrelchat/smol-toml/compare/v1.6.1...v1.7.0</a></p> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/squirrelchat/smol-toml/commit/a62f06faf4e45ab0a581def86c116f9706edc9df"><code>a62f06f</code></a> revert: keep using vite 7</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/89aa9a394ffc544dce77ab0ff24dfd8204e1f091"><code>89aa9a3</code></a> chore: remove prepare script</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/17c797475f1516da6614e31a1be9f4958bf296c0"><code>17c7974</code></a> chore: make devEngine more lax w/ node version</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/e5280a34630eb25086dca746bedda28ea21ec3d9"><code>e5280a3</code></a> ci: checkout repo first</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/241c256ebda07b2d225c91b7468ed8c90d0e71df"><code>241c256</code></a> chore: version bump</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/0bfe7f4667fa46122663b7b6114d9514dbd1a91f"><code>0bfe7f4</code></a> chore: build cjs with rolldown instead of esbuild</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/e0620ab2ac89c40d291f33df41b110277b1acedf"><code>e0620ab</code></a> chore: fmt</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/96114cb58312084286ae61470ba0f017b87b8023"><code>96114cb</code></a> test: add tests for large integers</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/f4537b6b3763e761069efdd7d688711c8409645c"><code>f4537b6</code></a> fix: handle missed edge-cases in string parse</li> <li><a href="https://github.com/squirrelchat/smol-toml/commit/7b39aed388cdc811189a6a3683fbee2f8d344244"><code>7b39aed</code></a> chore: include source files in published package</li> <li>Additional commits viewable in <a href="https://github.com/squirrelchat/smol-toml/compare/v1.6.1...v1.7.0">compare view</a></li> </ul> </details> <br /> Updates `electron` from 42.4.1 to 42.5.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/electron/electron/releases">electron's releases</a>.</em></p> <blockquote> <h2>electron v42.5.0</h2> <h1>Release Notes for v42.5.0</h1> <h2>Fixes</h2> <ul> <li>Fixed Windows edge case in <code>NativeWindowViews::MoveBehindTaskBarIfNeeded()</code>. <a href="https://redirect.github.com/electron/electron/pull/52022">#52022</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52023">41</a>, <a href="https://redirect.github.com/electron/electron/pull/52021">43</a>)<!-- raw HTML omitted --></li> <li>Fixed an issue where clicking the maximize button could progressively shrink the window in some Wayland environments. <a href="https://redirect.github.com/electron/electron/pull/52045">#52045</a> <!-- raw HTML omitted -->(Also in <a href="https://redirect.github.com/electron/electron/pull/52039">43</a>)<!-- raw HTML omitted --></li> </ul> <h2>Other Changes</h2> <ul> <li>Backported fixes from upstream Chromium. <a href="https://redirect.github.com/electron/electron/pull/51975">#51975</a></li> <li>Updated Chromium to 148.0.7778.271. <a href="https://redirect.github.com/electron/electron/pull/52038">#52038</a></li> <li>Updated Node.js to v24.17.0. <a href="https://redirect.github.com/electron/electron/pull/52066">#52066</a></li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/electron/electron/commit/d7bccf5b2f27969b4e7f34cf877f55cf0813be7a"><code>d7bccf5</code></a> fix: UAF in api::UtilityProcessWrapper (<a href="https://redirect.github.com/electron/electron/issues/52094">#52094</a>)</li> <li><a href="https://github.com/electron/electron/commit/fb151dcdf1ef7685cb5254b571d9ec50a480c1ae"><code>fb151dc</code></a> chore: bump chromium to 148.0.7778.271 (42-x-y) (<a href="https://redirect.github.com/electron/electron/issues/52038">#52038</a>)</li> <li><a href="https://github.com/electron/electron/commit/526fa0df025b50aea9a8011efa52753db8e7839a"><code>526fa0d</code></a> chore: bump node to v24.17.0 (42-x-y) (<a href="https://redirect.github.com/electron/electron/issues/52066">#52066</a>)</li> <li><a href="https://github.com/electron/electron/commit/22b84b5c304c512005c55569f6344d3e0db12fad"><code>22b84b5</code></a> fix: frameless window shrinks on maximize() when compositor declines (<a href="https://redirect.github.com/electron/electron/issues/52045">#52045</a>)</li> <li><a href="https://github.com/electron/electron/commit/15e8d1cf5db75ed5db00d2f4889deca1ee2c1004"><code>15e8d1c</code></a> docs: fix heap dump screenshot in contentTracing (<a href="https://redirect.github.com/electron/electron/issues/52031">#52031</a>)</li> <li><a href="https://github.com/electron/electron/commit/8902c75dca77c80793fe69971d53b7226d921bf9"><code>8902c75</code></a> build: bump <code>@electron/docs-parser</code> to 3.0.1 (<a href="https://redirect.github.com/electron/electron/issues/52052">#52052</a>)</li> <li><a href="https://github.com/electron/electron/commit/30bf7db164d941ee167cbc2f42f7629b1a6fe452"><code>30bf7db</code></a> test: use node16 moduleResolution in tsconfig and clean up imports (<a href="https://redirect.github.com/electron/electron/issues/52040">#52040</a>)</li> <li><a href="https://github.com/electron/electron/commit/d251baeeb3b0c92a66eaca6ab76542b4bb02e46a"><code>d251bae</code></a> ci: bump linux 64k kernel version (<a href="https://redirect.github.com/electron/electron/issues/52037">#52037</a>)</li> <li><a href="https://github.com/electron/electron/commit/ad73d520595a149149ef60bfbee16fd520b68ee7"><code>ad73d52</code></a> fix: win: check for valid taskbar handle (<a href="https://redirect.github.com/electron/electron/issues/52022">#52022</a>)</li> <li><a href="https://github.com/electron/electron/commit/6abd0348c9ec3fdd8eef4ca4029fbd8747000815"><code>6abd034</code></a> ci: replace dorny/paths-filter usage (reland) (<a href="https://redirect.github.com/electron/electron/issues/52033">#52033</a>)</li> <li>Additional commits viewable in <a href="https://github.com/electron/electron/compare/v42.4.1...v42.5.0">compare view</a></li> </ul> </details> <br /> Updates `fast-xml-parser` from 5.9.2 to 5.9.3 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/NaturalIntelligence/fast-xml-parser/releases">fast-xml-parser's releases</a>.</em></p> <blockquote> <h2>v5.9.3</h2> <h2>What's Changed</h2> <ul> <li>Harden GitHub Actions workflows by <a href="https://github.com/martincostello"><code>@martincostello</code></a> in <a href="https://redirect.github.com/NaturalIntelligence/fast-xml-parser/pull/841">NaturalIntelligence/fast-xml-parser#841</a></li> <li>GitHub Actions workflow fixes by <a href="https://github.com/martincostello"><code>@martincostello</code></a> in <a href="https://redirect.github.com/NaturalIntelligence/fast-xml-parser/pull/844">NaturalIntelligence/fast-xml-parser#844</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/martincostello"><code>@martincostello</code></a> made their first contribution in <a href="https://redirect.github.com/NaturalIntelligence/fast-xml-parser/pull/841">NaturalIntelligence/fast-xml-parser#841</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.9.2...v5.9.3">https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.9.2...v5.9.3</a></p> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md">fast-xml-parser's changelog</a>.</em></p> <blockquote> <p><!-- raw HTML omitted -->Note: If you find missing information about particular minor version, that version must have been changed without any functional change in this library.<!-- raw HTML omitted --></p> <p>Note: Due to some last quick changes on v4, detail of v4.5.3 & v4.5.4 are not updated here. v4.5.4x is the last tag of v4 in github repository. I'm extremely sorry for the confusion</p> <p>*<em>5.9.3 / 2026-06-19</em></p> <ul> <li>update strnum</li> </ul> <p>*<em>5.9.2 / 2026-06-17</em></p> <ul> <li>dummy release to test changes in github action</li> </ul> <p>*<em>5.9.1 / 2026-06-17</em></p> <ul> <li>dummy release to test release from github action</li> </ul> <p>*<em>5.9.0 / 2026-06-15</em></p> <ul> <li>update strnum to 2.3.0 <ul> <li>you can set hex, binary, enotation, infinity, unicode</li> </ul> </li> <li>validate unsafe HTML or XML data in doctype entities unsing 'is-unsafe' library. User can override rules by overriding EntityDecoder.</li> </ul> <p>*<em>5.8.0 / 2026-05-12</em></p> <ul> <li>integrate xml-naming to validate DOCTYPE entity name and notation name (using qname becaue of backward compatibility) <ul> <li>This will consider xml-version as well. '1.0' is default</li> </ul> </li> <li>update strnum to 2.3.0 <ul> <li>You can set octal and binary parsing which is bydeault off</li> </ul> </li> <li>update fast-xml-builder to 1.2.0 <ul> <li>can sanitize tag names if found invalid</li> <li>fix format output</li> </ul> </li> </ul> <p><strong>5.7.3 / 2006-05-05</strong></p> <ul> <li>fix: alwaysCreateTextNode should create text node when attributes are present for self closing node</li> <li>fix stop node expression when ns prefix is removed (found by <a href="https://github.com/iruizsalinas">iruizsalinas</a>)</li> <li>update XML Builder to 1.1.7</li> <li>mark addEntity deprecated</li> </ul> <p><strong>5.7.2 / 2026-04-25</strong></p> <ul> <li>allow numerical external entity for backward compatibility</li> <li>fix <a href="https://redirect.github.com/NaturalIntelligence/fast-xml-parser/issues/705">#705</a>: attributesGroupName working with preserveOrder</li> <li>fix <a href="https://redirect.github.com/NaturalIntelligence/fast-xml-parser/issues/817">#817</a>: stackoverflow when tag expression is very long</li> </ul> <p><strong>5.7.1 / 2026-04-20</strong></p> <ul> <li>fix typo in CJS typing file</li> </ul> <p><strong>5.7.0 / 2026-04-17</strong></p> <ul> <li>Use <code>@nodable/entities</code> v2.1.0 <ul> <li>breaking changes <ul> <li>single entity scan. You're not allowed to user entity value to form another entity name.</li> <li>you cant add numeric external entity</li> <li>entity error message when expantion limit is crossed might change</li> </ul> </li> </ul> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/commit/93a09f108d6f457a84e607a6806a7bfd6abc3e55"><code>93a09f1</code></a> 5.9.3</li> <li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/commit/9c1905edd7ea28db70770f758e293fcf079060c5"><code>9c1905e</code></a> update strnum</li> <li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/commit/8d71292a9aaaa8f4a24294e636bd191cfbf4d8a7"><code>8d71292</code></a> GitHub Actions workflow fixes (<a href="https://redirect.github.com/NaturalIntelligence/fast-xml-parser/issues/844">#844</a>)</li> <li><a href="https://github.com/NaturalIntelligence/fast-xml-parser/commit/784a0442b697e1498e1f3c3fc1a057ad57424858"><code>784a044</code></a> Harden GitHub Actions workflows (<a href="https://redirect.github.com/NaturalIntelligence/fast-xml-parser/issues/841">#841</a>)</li> <li>See full diff in <a href="https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.9.2...v5.9.3">compare view</a></li> </ul> </details> <br /> Updates `posthog-node` from 5.35.0 to 5.38.6 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-js/releases">posthog-node's releases</a>.</em></p> <blockquote> <h2>posthog-node@5.38.6</h2> <h2>5.38.6</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3896">#3896</a> <a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> Thanks <a href="https://github.com/GauthierPLM"><code>@GauthierPLM</code></a>! - Only stamp $groups from the top-level <code>groups</code> when present (2026-06-26)</li> </ul> <h2>posthog-node@5.38.5</h2> <h2>5.38.5</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3955">#3955</a> <a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Dedupe feature flag called events per returned flag value. (2026-06-24)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.3</li> </ul> </li> </ul> <h2>posthog-node@5.38.4</h2> <h2>5.38.4</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3938">#3938</a> <a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> Thanks <a href="https://github.com/dustinbyrne"><code>@dustinbyrne</code></a>! - Respect <code>disable_capture_url_hashes</code> when capturing Express and NestJS request URLs. (2026-06-23)</li> </ul> <h2>posthog-node@5.38.3</h2> <h2>5.38.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3937">#3937</a> <a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Deprecate the Node SDK Sentry integration and point users to PostHog Error Tracking for Node. (2026-06-23)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/440e370fda48d629352f3280471a228ee973dcb0"><code>440e370</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.0</li> </ul> </li> </ul> <h2>posthog-node@5.38.2</h2> <h2>5.38.2</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3903">#3903</a> <a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Validate custom event UUID overrides and generate new UUIDs when invalid. (2026-06-19)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.3</li> </ul> </li> </ul> <h2>posthog-node@5.38.1</h2> <h2>5.38.1</h2> <h3>Patch Changes</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-js/blob/main/packages/node/CHANGELOG.md">posthog-node's changelog</a>.</em></p> <blockquote> <h2>5.38.6</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3896">#3896</a> <a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> Thanks <a href="https://github.com/GauthierPLM"><code>@GauthierPLM</code></a>! - Only stamp $groups from the top-level <code>groups</code> when present (2026-06-26)</li> </ul> <h2>5.38.5</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3955">#3955</a> <a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Dedupe feature flag called events per returned flag value. (2026-06-24)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.3</li> </ul> </li> </ul> <h2>5.38.4</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3938">#3938</a> <a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> Thanks <a href="https://github.com/dustinbyrne"><code>@dustinbyrne</code></a>! - Respect <code>disable_capture_url_hashes</code> when capturing Express and NestJS request URLs. (2026-06-23)</li> </ul> <h2>5.38.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3937">#3937</a> <a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Deprecate the Node SDK Sentry integration and point users to PostHog Error Tracking for Node. (2026-06-23)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/440e370fda48d629352f3280471a228ee973dcb0"><code>440e370</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.0</li> </ul> </li> </ul> <h2>5.38.2</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3903">#3903</a> <a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Validate custom event UUID overrides and generate new UUIDs when invalid. (2026-06-19)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.3</li> </ul> </li> </ul> <h2>5.38.1</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3886">#3886</a> <a href="https://github.com/PostHog/posthog-js/commit/e6d7fe2a5f10d29b3df69392f584970e7a7a4561"><code>e6d7fe2</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Stop sending deprecated no-op top-level <code>type</code>, <code>library</code>, and <code>library_version</code> fields in event batch payloads. Use <code>properties.$lib</code> and <code>properties.$lib_version</code> for SDK metadata; legacy queued <code>library</code> and <code>library_version</code> values are used as fallbacks when the official <code>$</code> properties are missing. (2026-06-18)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/e6d7fe2a5f10d29b3df69392f584970e7a7a4561"><code>e6d7fe2</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.2</li> </ul> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/PostHog/posthog-js/commit/d2faa824af1af2cb50b47178fb953bfc8812b389"><code>d2faa82</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> fix: preserve $groups passed via properties (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3896">#3896</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/5c4838f1671ece80d153aaeb6d946bb3e8c8240a"><code>5c4838f</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> fix: Dedupe feature flag called events by response (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3955">#3955</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/2a60c21134dd118c2367e56129bc9427079c3841"><code>2a60c21</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> fix(node): respect URL hash capture config (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3938">#3938</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/a3136c6de3114ee3d58e59a0c86f2b9c4f59a2b0"><code>a3136c6</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/bf6947d3e12ac512c99185be9b8b134c04eb563a"><code>bf6947d</code></a> feat(react-native): support session replay event triggers (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3932">#3932</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/2628a1af5f06f73cb2252de002e0da4b2d1a25a5"><code>2628a1a</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> chore(node): mark Sentry integration deprecated (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3937">#3937</a>)</li> <li>Additional commits viewable in <a href="https://github.com/PostHog/posthog-js/commits/posthog-node@5.38.6/packages/node">compare view</a></li> </ul> </details> <br /> Updates `posthog-node` from 5.35.0 to 5.38.6 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-js/releases">posthog-node's releases</a>.</em></p> <blockquote> <h2>posthog-node@5.38.6</h2> <h2>5.38.6</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3896">#3896</a> <a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> Thanks <a href="https://github.com/GauthierPLM"><code>@GauthierPLM</code></a>! - Only stamp $groups from the top-level <code>groups</code> when present (2026-06-26)</li> </ul> <h2>posthog-node@5.38.5</h2> <h2>5.38.5</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3955">#3955</a> <a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Dedupe feature flag called events per returned flag value. (2026-06-24)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.3</li> </ul> </li> </ul> <h2>posthog-node@5.38.4</h2> <h2>5.38.4</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3938">#3938</a> <a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> Thanks <a href="https://github.com/dustinbyrne"><code>@dustinbyrne</code></a>! - Respect <code>disable_capture_url_hashes</code> when capturing Express and NestJS request URLs. (2026-06-23)</li> </ul> <h2>posthog-node@5.38.3</h2> <h2>5.38.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3937">#3937</a> <a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Deprecate the Node SDK Sentry integration and point users to PostHog Error Tracking for Node. (2026-06-23)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/440e370fda48d629352f3280471a228ee973dcb0"><code>440e370</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.0</li> </ul> </li> </ul> <h2>posthog-node@5.38.2</h2> <h2>5.38.2</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3903">#3903</a> <a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Validate custom event UUID overrides and generate new UUIDs when invalid. (2026-06-19)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.3</li> </ul> </li> </ul> <h2>posthog-node@5.38.1</h2> <h2>5.38.1</h2> <h3>Patch Changes</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-js/blob/main/packages/node/CHANGELOG.md">posthog-node's changelog</a>.</em></p> <blockquote> <h2>5.38.6</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3896">#3896</a> <a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> Thanks <a href="https://github.com/GauthierPLM"><code>@GauthierPLM</code></a>! - Only stamp $groups from the top-level <code>groups</code> when present (2026-06-26)</li> </ul> <h2>5.38.5</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3955">#3955</a> <a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Dedupe feature flag called events per returned flag value. (2026-06-24)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.3</li> </ul> </li> </ul> <h2>5.38.4</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3938">#3938</a> <a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> Thanks <a href="https://github.com/dustinbyrne"><code>@dustinbyrne</code></a>! - Respect <code>disable_capture_url_hashes</code> when capturing Express and NestJS request URLs. (2026-06-23)</li> </ul> <h2>5.38.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3937">#3937</a> <a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Deprecate the Node SDK Sentry integration and point users to PostHog Error Tracking for Node. (2026-06-23)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/440e370fda48d629352f3280471a228ee973dcb0"><code>440e370</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.0</li> </ul> </li> </ul> <h2>5.38.2</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3903">#3903</a> <a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Validate custom event UUID overrides and generate new UUIDs when invalid. (2026-06-19)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.3</li> </ul> </li> </ul> <h2>5.38.1</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3886">#3886</a> <a href="https://github.com/PostHog/posthog-js/commit/e6d7fe2a5f10d29b3df69392f584970e7a7a4561"><code>e6d7fe2</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Stop sending deprecated no-op top-level <code>type</code>, <code>library</code>, and <code>library_version</code> fields in event batch payloads. Use <code>properties.$lib</code> and <code>properties.$lib_version</code> for SDK metadata; legacy queued <code>library</code> and <code>library_version</code> values are used as fallbacks when the official <code>$</code> properties are missing. (2026-06-18)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/e6d7fe2a5f10d29b3df69392f584970e7a7a4561"><code>e6d7fe2</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.2</li> </ul> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/PostHog/posthog-js/commit/d2faa824af1af2cb50b47178fb953bfc8812b389"><code>d2faa82</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> fix: preserve $groups passed via properties (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3896">#3896</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/5c4838f1671ece80d153aaeb6d946bb3e8c8240a"><code>5c4838f</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> fix: Dedupe feature flag called events by response (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3955">#3955</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/2a60c21134dd118c2367e56129bc9427079c3841"><code>2a60c21</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> fix(node): respect URL hash capture config (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3938">#3938</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/a3136c6de3114ee3d58e59a0c86f2b9c4f59a2b0"><code>a3136c6</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/bf6947d3e12ac512c99185be9b8b134c04eb563a"><code>bf6947d</code></a> feat(react-native): support session replay event triggers (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3932">#3932</a>)</li> <li><a href="https://github.com/PostHog/posthog-js/commit/2628a1af5f06f73cb2252de002e0da4b2d1a25a5"><code>2628a1a</code></a> chore: update versions and lockfile [version bump]</li> <li><a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> chore(node): mark Sentry integration deprecated (<a href="https://github.com/PostHog/posthog-js/tree/HEAD/packages/node/issues/3937">#3937</a>)</li> <li>Additional commits viewable in <a href="https://github.com/PostHog/posthog-js/commits/posthog-node@5.38.6/packages/node">compare view</a></li> </ul> </details> <br /> Updates `posthog-node` from 5.35.0 to 5.38.6 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-js/releases">posthog-node's releases</a>.</em></p> <blockquote> <h2>posthog-node@5.38.6</h2> <h2>5.38.6</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3896">#3896</a> <a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> Thanks <a href="https://github.com/GauthierPLM"><code>@GauthierPLM</code></a>! - Only stamp $groups from the top-level <code>groups</code> when present (2026-06-26)</li> </ul> <h2>posthog-node@5.38.5</h2> <h2>5.38.5</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3955">#3955</a> <a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Dedupe feature flag called events per returned flag value. (2026-06-24)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.3</li> </ul> </li> </ul> <h2>posthog-node@5.38.4</h2> <h2>5.38.4</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3938">#3938</a> <a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> Thanks <a href="https://github.com/dustinbyrne"><code>@dustinbyrne</code></a>! - Respect <code>disable_capture_url_hashes</code> when capturing Express and NestJS request URLs. (2026-06-23)</li> </ul> <h2>posthog-node@5.38.3</h2> <h2>5.38.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3937">#3937</a> <a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Deprecate the Node SDK Sentry integration and point users to PostHog Error Tracking for Node. (2026-06-23)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/440e370fda48d629352f3280471a228ee973dcb0"><code>440e370</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.0</li> </ul> </li> </ul> <h2>posthog-node@5.38.2</h2> <h2>5.38.2</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3903">#3903</a> <a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Validate custom event UUID overrides and generate new UUIDs when invalid. (2026-06-19)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.3</li> </ul> </li> </ul> <h2>posthog-node@5.38.1</h2> <h2>5.38.1</h2> <h3>Patch Changes</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/PostHog/posthog-js/blob/main/packages/node/CHANGELOG.md">posthog-node's changelog</a>.</em></p> <blockquote> <h2>5.38.6</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3896">#3896</a> <a href="https://github.com/PostHog/posthog-js/commit/606ef43d69fd09a00a67df2a404d8739cc50c654"><code>606ef43</code></a> Thanks <a href="https://github.com/GauthierPLM"><code>@GauthierPLM</code></a>! - Only stamp $groups from the top-level <code>groups</code> when present (2026-06-26)</li> </ul> <h2>5.38.5</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3955">#3955</a> <a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Dedupe feature flag called events per returned flag value. (2026-06-24)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/8e9689a9018d184b80f32fc4874686d7243970e2"><code>8e9689a</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.3</li> </ul> </li> </ul> <h2>5.38.4</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3938">#3938</a> <a href="https://github.com/PostHog/posthog-js/commit/6391106fd4bcbddb9a63a13338929a4c1918a70a"><code>6391106</code></a> Thanks <a href="https://github.com/dustinbyrne"><code>@dustinbyrne</code></a>! - Respect <code>disable_capture_url_hashes</code> when capturing Express and NestJS request URLs. (2026-06-23)</li> </ul> <h2>5.38.3</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3937">#3937</a> <a href="https://github.com/PostHog/posthog-js/commit/4d59d0e10f92ad3444e14dc171997c21aba57929"><code>4d59d0e</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Deprecate the Node SDK Sentry integration and point users to PostHog Error Tracking for Node. (2026-06-23)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/440e370fda48d629352f3280471a228ee973dcb0"><code>440e370</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.37.0</li> </ul> </li> </ul> <h2>5.38.2</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3903">#3903</a> <a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Validate custom event UUID overrides and generate new UUIDs when invalid. (2026-06-19)</li> <li>Updated dependencies [<a href="https://github.com/PostHog/posthog-js/commit/6b21f77291aeea64ce8229eb28196d1acacc20ce"><code>6b21f77</code></a>]: <ul> <li><code>@posthog/core</code><a href="https://github.com/1"><code>@1</code></a>.35.3</li> </ul> </li> </ul> <h2>5.38.1</h2> <h3>Patch Changes</h3> <ul> <li><a href="https://redirect.github.com/PostHog/posthog-js/pull/3886">#3886</a> <a href="https://github.com/PostHog/posthog-js/commit/e6d7fe2a5f10d29b3df69392f584970e7a7a4561"><code>e6d7fe2</code></a> Thanks <a href="https://github.com/marandaneto"><code>@marandaneto</code></a>! - Stop sending deprecated no-op top-level <code>type<... _Description has been truncated_ Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
02695e6704 |
chore(deps)(deps): bump the npm-major group across 1 directory with 3 updates (#413)
Bumps the npm-major group with 3 updates in the / directory: [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node), [dotenv](https://github.com/motdotla/dotenv) and [ini](https://github.com/npm/ini). Updates `@types/node` from 25.9.3 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li> </ul> </details> <br /> Updates `dotenv` from 16.6.1 to 17.4.2 <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md">dotenv's changelog</a>.</em></p> <blockquote> <h2><a href="https://github.com/motdotla/dotenv/compare/v17.4.1...v17.4.2">17.4.2</a> (2026-04-12)</h2> <h3>Changed</h3> <ul> <li>Improved skill files - tightened up details (<a href="https://redirect.github.com/motdotla/dotenv/pull/1009">#1009</a>)</li> </ul> <h2><a href="https://github.com/motdotla/dotenv/compare/v17.4.0...v17.4.1">17.4.1</a> (2026-04-05)</h2> <h3>Changed</h3> <ul> <li>Change text <code>injecting</code> to <code>injected</code> (<a href="https://redirect.github.com/motdotla/dotenv/pull/1005">#1005</a>)</li> </ul> <h2><a href="https://github.com/motdotla/dotenv/compare/v17.3.1...v17.4.0">17.4.0</a> (2026-04-01)</h2> <h3>Added</h3> <ul> <li>Add <code>skills/</code> folder with focused agent skills: <code>skills/dotenv/SKILL.md</code> (core usage) and <code>skills/dotenvx/SKILL.md</code> (encryption, multiple environments, variable expansion) for AI coding agent discovery via the skills.sh ecosystem (<code>npx skills add motdotla/dotenv</code>)</li> </ul> <h3>Changed</h3> <ul> <li>Tighten up logs: <code>◇ injecting env (14) from .env</code> (<a href="https://redirect.github.com/motdotla/dotenv/pull/1003">#1003</a>)</li> </ul> <h2><a href="https://github.com/motdotla/dotenv/compare/v17.3.0...v17.3.1">17.3.1</a> (2026-02-12)</h2> <h3>Changed</h3> <ul> <li>Fix as2 example command in README and update spanish README</li> </ul> <h2><a href="https://github.com/motdotla/dotenv/compare/v17.2.4...v17.3.0">17.3.0</a> (2026-02-12)</h2> <h3>Added</h3> <ul> <li>Add a new README section on dotenv’s approach to the agentic future.</li> </ul> <h3>Changed</h3> <ul> <li>Rewrite README to get humans started more quickly with less noise while simultaneously making more accessible for llms and agents to go deeper into details.</li> </ul> <h2><a href="https://github.com/motdotla/dotenv/compare/v17.2.3...v17.2.4">17.2.4</a> (2026-02-05)</h2> <h3>Changed</h3> <ul> <li>Make <code>DotenvPopulateInput</code> accept <code>NodeJS.ProcessEnv</code> type (<a href="https://redirect.github.com/motdotla/dotenv/pull/915">#915</a>)</li> </ul> <ul> <li>Give back to dotenv by checking out my newest project <a href="https://github.com/vestauth/vestauth">vestauth</a>. It is auth for agents. Thank you for using my software.</li> </ul> <h2><a href="https://github.com/motdotla/dotenv/compare/v17.2.2...v17.2.3">17.2.3</a> (2025-09-29)</h2> <h3>Changed</h3> <ul> <li>Fixed typescript error definition (<a href="https://redirect.github.com/motdotla/dotenv/pull/912">#912</a>)</li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/motdotla/dotenv/commit/f116f70310abab44fbfddbaeb833698b5bf84a9b"><code>f116f70</code></a> 17.4.2</li> <li><a href="https://github.com/motdotla/dotenv/commit/3a8161274fdd745239b86e604f4a7e972a1d3902"><code>3a81612</code></a> fix visual order of faq</li> <li><a href="https://github.com/motdotla/dotenv/commit/13f55a89e136b2024e68d277b836dd5260fc16cf"><code>13f55a8</code></a> Merge branch 'skill'</li> <li><a href="https://github.com/motdotla/dotenv/commit/4bbbf73f0906bd69975c48bf310a84b686e5b1b4"><code>4bbbf73</code></a> reorganize faq</li> <li><a href="https://github.com/motdotla/dotenv/commit/c3da64bb2ba1d0e02f8b9b2b7ccb7e6f7a51d56c"><code>c3da64b</code></a> Merge pull request <a href="https://redirect.github.com/motdotla/dotenv/issues/1009">#1009</a> from motdotla/skill</li> <li><a href="https://github.com/motdotla/dotenv/commit/6f743b173fbd6c26f7eab7040d251f9a6c8b977d"><code>6f743b1</code></a> update source</li> <li><a href="https://github.com/motdotla/dotenv/commit/fc2c6247e858a32d4024cb06a5b0c79aa35851f5"><code>fc2c624</code></a> update skill</li> <li><a href="https://github.com/motdotla/dotenv/commit/972315ba74bb2bbba4483d112e853fd26006ef8a"><code>972315b</code></a> Tighten up skill</li> <li><a href="https://github.com/motdotla/dotenv/commit/2795fce3d1ed07b4c570f1e06ab1c0d533c86997"><code>2795fce</code></a> reorganize faq</li> <li><a href="https://github.com/motdotla/dotenv/commit/d5495d4ae8e4e41ef9a682c9e00c81552794274e"><code>d5495d4</code></a> adjust skill</li> <li>Additional commits viewable in <a href="https://github.com/motdotla/dotenv/compare/v16.6.1...v17.4.2">compare view</a></li> </ul> </details> <br /> Updates `ini` from 4.1.3 to 7.0.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/npm/ini/releases">ini's releases</a>.</em></p> <blockquote> <h2>v7.0.0</h2> <h2><a href="https://github.com/npm/ini/compare/v6.0.0...v7.0.0">7.0.0</a> (2026-05-08)</h2> <h3>⚠️ BREAKING CHANGES</h3> <ul> <li><code>ini</code> now supports node <code>^22.22.2 || ^24.15.0 || >=26.0.0</code></li> <li>template-oss-apply</li> </ul> <h3>Features</h3> <ul> <li><a href="https://github.com/npm/ini/commit/55b6841261aad580ce979c1ada97885a0617b965"><code>55b6841</code></a> <a href="https://redirect.github.com/npm/ini/pull/301">#301</a> bump to new node engine range (<a href="https://github.com/owlstronaut"><code>@owlstronaut</code></a>)</li> <li><a href="https://github.com/npm/ini/commit/2b11ba8283afa33211844be6fa29794970ccf7b7"><code>2b11ba8</code></a> <a href="https://redirect.github.com/npm/ini/pull/301">#301</a> template-oss-apply (<a href="https://github.com/owlstronaut"><code>@owlstronaut</code></a>)</li> </ul> <h3>Chores</h3> <ul> <li><a href="https://github.com/npm/ini/commit/f6ed5bee3d7b1c175b687c703213217b23df9199"><code>f6ed5be</code></a> <a href="https://redirect.github.com/npm/ini/pull/301">#301</a> template-oss-apply (<a href="https://github.com/owlstronaut"><code>@owlstronaut</code></a>)</li> <li><a href="https://github.com/npm/ini/commit/a2c835ec4690c5e67651a403d0f952aaff018f42"><code>a2c835e</code></a> <a href="https://redirect.github.com/npm/ini/pull/293">#293</a> bump <code>@npmcli/eslint-config</code> from 5.1.0 to 6.0.0 (<a href="https://redirect.github.com/npm/ini/issues/293">#293</a>) (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot])</li> <li><a href="https://github.com/npm/ini/commit/3661dce193f03675ec6ddc0938e2483d0ab41f38"><code>3661dce</code></a> <a href="https://redirect.github.com/npm/ini/pull/296">#296</a> bump <code>@npmcli/template-oss</code> from 4.28.0 to 4.28.1 (<a href="https://redirect.github.com/npm/ini/issues/296">#296</a>) (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot], <a href="https://github.com/npm-cli-bot"><code>@npm-cli-bot</code></a>)</li> </ul> <h2>v6.0.0</h2> <h2><a href="https://github.com/npm/ini/compare/v5.0.0...v6.0.0">6.0.0</a> (2025-10-22)</h2> <h3>⚠️ BREAKING CHANGES</h3> <ul> <li><code>ini</code> now supports node <code>^20.17.0 || >=22.9.0</code></li> </ul> <h3>Bug Fixes</h3> <ul> <li><a href="https://github.com/npm/ini/commit/6d395a4aaf7d7a5e32e250809cb7bd04c6a27b66"><code>6d395a4</code></a> <a href="https://redirect.github.com/npm/ini/pull/291">#291</a> align to npm 11 node engine range (<a href="https://redirect.github.com/npm/ini/issues/291">#291</a>) (<a href="https://github.com/owlstronaut"><code>@owlstronaut</code></a>)</li> </ul> <h3>Chores</h3> <ul> <li><a href="https://github.com/npm/ini/commit/23a36a9ca194d97486ed367f63d13a2cde1d1ce5"><code>23a36a9</code></a> <a href="https://redirect.github.com/npm/ini/pull/290">#290</a> bump <code>@npmcli/template-oss</code> from 4.26.0 to 4.27.1 (<a href="https://redirect.github.com/npm/ini/issues/290">#290</a>) (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot], <a href="https://github.com/npm-cli-bot"><code>@npm-cli-bot</code></a>)</li> </ul> <h2>v5.0.0</h2> <h2><a href="https://github.com/npm/ini/compare/v4.1.3...v5.0.0">5.0.0</a> (2024-09-03)</h2> <h3>⚠️ BREAKING CHANGES</h3> <ul> <li><code>ini</code> now supports node <code>^18.17.0 || >=20.5.0</code></li> </ul> <h3>Bug Fixes</h3> <ul> <li><a href="https://github.com/npm/ini/commit/3eca645de8586b8349acd79211b01a9199d8fd32"><code>3eca645</code></a> <a href="https://redirect.github.com/npm/ini/pull/279">#279</a> align to npm 10 node engine range (<a href="https://github.com/hashtagchris"><code>@hashtagchris</code></a>)</li> </ul> <h3>Chores</h3> <ul> <li><a href="https://github.com/npm/ini/commit/c89e2090d7989bb91255ec46eaaf5f8cb1c34b34"><code>c89e209</code></a> <a href="https://redirect.github.com/npm/ini/pull/279">#279</a> run template-oss-apply (<a href="https://github.com/hashtagchris"><code>@hashtagchris</code></a>)</li> <li><a href="https://github.com/npm/ini/commit/fc447500efe6523746fd9db9d3123485eed14b76"><code>fc44750</code></a> <a href="https://redirect.github.com/npm/ini/pull/276">#276</a> bump <code>@npmcli/eslint-config</code> from 4.0.5 to 5.0.0 (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot])</li> <li><a href="https://github.com/npm/ini/commit/21c20bb1729005ab46e0f248cea1a881c6ab5b49"><code>21c20bb</code></a> <a href="https://redirect.github.com/npm/ini/pull/277">#277</a> postinstall for dependabot template-oss PR (<a href="https://github.com/hashtagchris"><code>@hashtagchris</code></a>)</li> <li><a href="https://github.com/npm/ini/commit/44b3b503fdd923fb230b6a4d859014b9364ee466"><code>44b3b50</code></a> <a href="https://redirect.github.com/npm/ini/pull/277">#277</a> bump <code>@npmcli/template-oss</code> from 4.23.1 to 4.23.3 (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot])</li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/npm/ini/blob/main/CHANGELOG.md">ini's changelog</a>.</em></p> <blockquote> <h2><a href="https://github.com/npm/ini/compare/v6.0.0...v7.0.0">7.0.0</a> (2026-05-08)</h2> <h3>⚠️ BREAKING CHANGES</h3> <ul> <li><code>ini</code> now supports node <code>^22.22.2 || ^24.15.0 || >=26.0.0</code></li> <li>template-oss-apply</li> </ul> <h3>Features</h3> <ul> <li><a href="https://github.com/npm/ini/commit/55b6841261aad580ce979c1ada97885a0617b965"><code>55b6841</code></a> <a href="https://redirect.github.com/npm/ini/pull/301">#301</a> bump to new node engine range (<a href="https://github.com/owlstronaut"><code>@owlstronaut</code></a>)</li> <li><a href="https://github.com/npm/ini/commit/2b11ba8283afa33211844be6fa29794970ccf7b7"><code>2b11ba8</code></a> <a href="https://redirect.github.com/npm/ini/pull/301">#301</a> template-oss-apply (<a href="https://github.com/owlstronaut"><code>@owlstronaut</code></a>)</li> </ul> <h3>Chores</h3> <ul> <li><a href="https://github.com/npm/ini/commit/f6ed5bee3d7b1c175b687c703213217b23df9199"><code>f6ed5be</code></a> <a href="https://redirect.github.com/npm/ini/pull/301">#301</a> template-oss-apply (<a href="https://github.com/owlstronaut"><code>@owlstronaut</code></a>)</li> <li><a href="https://github.com/npm/ini/commit/a2c835ec4690c5e67651a403d0f952aaff018f42"><code>a2c835e</code></a> <a href="https://redirect.github.com/npm/ini/pull/293">#293</a> bump <code>@npmcli/eslint-config</code> from 5.1.0 to 6.0.0 (<a href="https://redirect.github.com/npm/ini/issues/293">#293</a>) (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot])</li> <li><a href="https://github.com/npm/ini/commit/3661dce193f03675ec6ddc0938e2483d0ab41f38"><code>3661dce</code></a> <a href="https://redirect.github.com/npm/ini/pull/296">#296</a> bump <code>@npmcli/template-oss</code> from 4.28.0 to 4.28.1 (<a href="https://redirect.github.com/npm/ini/issues/296">#296</a>) (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot], <a href="https://github.com/npm-cli-bot"><code>@npm-cli-bot</code></a>)</li> </ul> <h2><a href="https://github.com/npm/ini/compare/v5.0.0...v6.0.0">6.0.0</a> (2025-10-22)</h2> <h3>⚠️ BREAKING CHANGES</h3> <ul> <li><code>ini</code> now supports node <code>^20.17.0 || >=22.9.0</code></li> </ul> <h3>Bug Fixes</h3> <ul> <li><a href="https://github.com/npm/ini/commit/6d395a4aaf7d7a5e32e250809cb7bd04c6a27b66"><code>6d395a4</code></a> <a href="https://redirect.github.com/npm/ini/pull/291">#291</a> align to npm 11 node engine range (<a href="https://redirect.github.com/npm/ini/issues/291">#291</a>) (<a href="https://github.com/owlstronaut"><code>@owlstronaut</code></a>)</li> </ul> <h3>Chores</h3> <ul> <li><a href="https://github.com/npm/ini/commit/23a36a9ca194d97486ed367f63d13a2cde1d1ce5"><code>23a36a9</code></a> <a href="https://redirect.github.com/npm/ini/pull/290">#290</a> bump <code>@npmcli/template-oss</code> from 4.26.0 to 4.27.1 (<a href="https://redirect.github.com/npm/ini/issues/290">#290</a>) (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot], <a href="https://github.com/npm-cli-bot"><code>@npm-cli-bot</code></a>)</li> </ul> <h2><a href="https://github.com/npm/ini/compare/v4.1.3...v5.0.0">5.0.0</a> (2024-09-03)</h2> <h3>⚠️ BREAKING CHANGES</h3> <ul> <li><code>ini</code> now supports node <code>^18.17.0 || >=20.5.0</code></li> </ul> <h3>Bug Fixes</h3> <ul> <li><a href="https://github.com/npm/ini/commit/3eca645de8586b8349acd79211b01a9199d8fd32"><code>3eca645</code></a> <a href="https://redirect.github.com/npm/ini/pull/279">#279</a> align to npm 10 node engine range (<a href="https://github.com/hashtagchris"><code>@hashtagchris</code></a>)</li> </ul> <h3>Chores</h3> <ul> <li><a href="https://github.com/npm/ini/commit/c89e2090d7989bb91255ec46eaaf5f8cb1c34b34"><code>c89e209</code></a> <a href="https://redirect.github.com/npm/ini/pull/279">#279</a> run template-oss-apply (<a href="https://github.com/hashtagchris"><code>@hashtagchris</code></a>)</li> <li><a href="https://github.com/npm/ini/commit/fc447500efe6523746fd9db9d3123485eed14b76"><code>fc44750</code></a> <a href="https://redirect.github.com/npm/ini/pull/276">#276</a> bump <code>@npmcli/eslint-config</code> from 4.0.5 to 5.0.0 (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot])</li> <li><a href="https://github.com/npm/ini/commit/21c20bb1729005ab46e0f248cea1a881c6ab5b49"><code>21c20bb</code></a> <a href="https://redirect.github.com/npm/ini/pull/277">#277</a> postinstall for dependabot template-oss PR (<a href="https://github.com/hashtagchris"><code>@hashtagchris</code></a>)</li> <li><a href="https://github.com/npm/ini/commit/44b3b503fdd923fb230b6a4d859014b9364ee466"><code>44b3b50</code></a> <a href="https://redirect.github.com/npm/ini/pull/277">#277</a> bump <code>@npmcli/template-oss</code> from 4.23.1 to 4.23.3 (<a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot])</li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/npm/ini/commit/847941ced4fb8465f0ccb383fd8b15c7e5aa09fc"><code>847941c</code></a> chore: release 7.0.0 (<a href="https://redirect.github.com/npm/ini/issues/302">#302</a>)</li> <li><a href="https://github.com/npm/ini/commit/f6ed5bee3d7b1c175b687c703213217b23df9199"><code>f6ed5be</code></a> chore: template-oss-apply</li> <li><a href="https://github.com/npm/ini/commit/55b6841261aad580ce979c1ada97885a0617b965"><code>55b6841</code></a> feat!: bump to new node engine range</li> <li><a href="https://github.com/npm/ini/commit/2b11ba8283afa33211844be6fa29794970ccf7b7"><code>2b11ba8</code></a> feat!: template-oss-apply</li> <li><a href="https://github.com/npm/ini/commit/e8d16cbbbb91d503fe14163024bd2a01a0446d32"><code>e8d16cb</code></a> deps & engine update</li> <li><a href="https://github.com/npm/ini/commit/3661dce193f03675ec6ddc0938e2483d0ab41f38"><code>3661dce</code></a> chore: bump <code>@npmcli/template-oss</code> from 4.28.0 to 4.28.1 (<a href="https://redirect.github.com/npm/ini/issues/296">#296</a>)</li> <li><a href="https://github.com/npm/ini/commit/5d67f4b487a00aa3e2119776192030356e0161ba"><code>5d67f4b</code></a> chore: bump <code>@npmcli/template-oss</code> from 4.27.1 to 4.28.0 (<a href="https://redirect.github.com/npm/ini/issues/294">#294</a>)</li> <li><a href="https://github.com/npm/ini/commit/a2c835ec4690c5e67651a403d0f952aaff018f42"><code>a2c835e</code></a> chore: bump <code>@npmcli/eslint-config</code> from 5.1.0 to 6.0.0 (<a href="https://redirect.github.com/npm/ini/issues/293">#293</a>)</li> <li><a href="https://github.com/npm/ini/commit/180a8d5c72d7f13ed70c53619132f3a8ee5ac6ed"><code>180a8d5</code></a> chore: release 6.0.0 (<a href="https://redirect.github.com/npm/ini/issues/292">#292</a>)</li> <li><a href="https://github.com/npm/ini/commit/6d395a4aaf7d7a5e32e250809cb7bd04c6a27b66"><code>6d395a4</code></a> fix!: align to npm 11 node engine range (<a href="https://redirect.github.com/npm/ini/issues/291">#291</a>)</li> <li>Additional commits viewable in <a href="https://github.com/npm/ini/compare/v4.1.3...v7.0.0">compare view</a></li> </ul> </details> <details> <summary>Maintainer changes</summary> <p>This version was pushed to npm by <a href="https://www.npmjs.com/~GitHub%20Actions">GitHub Actions</a>, a new releaser for ini since your current version.</p> </details> <br /> Updates `@types/node` from 25.9.3 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li> </ul> </details> <br /> Updates `@types/node` from 25.9.3 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li> </ul> </details> <br /> Updates `@types/node` from 25.9.3 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li> </ul> </details> <br /> Updates `@types/node` from 25.9.3 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li> </ul> </details> <br /> Updates `@types/node` from 25.9.3 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li> </ul> </details> <br /> Updates `@types/node` from 25.9.3 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">compare view</a></li> </ul> </details> <br /> Updates `@types/node` from 25.9.3 to 26.0.1 <details> <summary>Commits</summary> <ul> <li>See full diff in <a href="https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node">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> |
||
|
|
270c9a158a |
chore: bump to 0.13.0 (#412)
as per title |
||
|
|
31bb59fb60 |
chore: bump all workspace packages to 0.12.1 (#381)
Bumps every workspace package under `packages/*` from `0.12.0` → `0.12.1`, keeping the monorepo's lockstep versioning intact. ## Changes - `version` bumped to `0.12.1` in all 15 workspace `package.json` files - `package-lock.json` workspace entries synced to match ## Verification - `npm run check:versions` → `All workspace packages are at 0.12.1.` 🤖 Generated with [Claude Code](https://claude.com/claude-code) |
||
|
|
8483fe23f9 |
feat: add telemetry (#274)
## Summary Adds anonymous, opt-out telemetry for Argent installer, update/uninstall flows, CLI telemetry controls, tool-server lifecycle, and tool invocation health signals. ## What Changed - Added a new private `@argent/telemetry` package - Introduced typed telemetry events with runtime property allowlisting/sanitization. - Added lazy anonymous identity creation in `~/.argent/telemetry-id`. - Added consent handling via: `argent telemetry enable`, `argent telemetry disable`, `argent telemetry status` - Added local debug logging with `ARGENT_TELEMETRY_DEBUG=1`. - Tracks installer funnel events for init, global install/update decisions, editor selection, allowlist decisions, skill installation, rules/agents copy, update, and uninstall. - Tracks tool-server start/stop and tool invocation/complete/fail events. - Adds per-tool invocation IDs so request metadata can be correlated without relying on ordering. - Records only coarse platform metadata (`ios` / `android`) for device tools - Ensures short-lived commands drain telemetry with bounded shutdown before exit. - Wires telemetry package into bundling and injects full Argent CLI version metadata at build time. - Added central `FAILURE_CODES` and `FailureSignal` helpers in `@argent/registry`. - Attached structured, sanitized failure metadata across registry errors, tool-server tools/services, HTTP validation/dependency gates, installer flows, and `argent run`. - Added telemetry allowlisting for safe failure fields only: static error codes/stages, coarse area/kind/command, bounded exit codes, allowlisted signals/spawn codes, and coarse network failure classes. - Split CLI-local `argent run` failures into `cli:run_fail` so they are not double-counted as tool failures. - Added installer telemetry for failed package actions, update/uninstall failures, rules/agents copy results, and skill refresh results. - Made telemetry consent writes atomic and kept telemetry status side-effect free via `peekAnonId()`. - Adds a coarse, anonymous signal to tool telemetry: which AI coding tool is driving the MCP server (Claude Code, Codex, Cursor, Gemini, VS Code, Windsurf, Zed, opencode, Copilot, or other). ## Tests Added / Updated - Telemetry unit coverage for consent precedence, identity creation, base props, sanitization, PostHog config, debug logging, shutdown, opt-out, and forget behavior. - Registry/tool-server tests for invocation IDs, platform metadata boundaries, startup failure flushing, and tool lifecycle telemetry. - Installer tests for final telemetry drain, update action classification, and uninstall identity cleanup ordering. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
02e500884f |
chore(deps): npm-minor-patch group excluding tree-sitter (fixes #348) (#355)
## What Applies the safe updates from dependabot #348 (`npm-minor-patch` group) and **excludes the one bump that breaks the build**, `tree-sitter`. | Package | From | To | | --- | --- | --- | | prettier | 3.8.3 | 3.8.4 | | @clack/prompts | 1.1.0 / 1.4.0 | 1.5.1 | | @types/node | 25.9.0 | 25.9.3 | | esbuild | 0.28.0 | 0.28.1 | | semver | 7.7.4 / 7.8.0 | 7.8.4 | | vitest | 4.1.6 | 4.1.9 | | tree-sitter | 0.21.1 | **held at 0.21.1** | (`ws` was part of #348's group but is already at 8.21.0 on `main`, so it's untouched here.) ## Why tree-sitter is excluded `tree-sitter@0.25.0` ships **no Node 24 prebuilds**, and its `binding.gyp` forces `-std=c++17` while Node 22+ v8 (cppgc) headers require C++20, so the native build fails `npm ci`/`npm install` on current Node. That's exactly why #348's `ESLint` job (Node 24) fails at install: ``` .../node_modules/tree-sitter ... node-gyp-build .../include/node/v8config.h:13:2: error: #error "C++20 or later required." ``` (#348's `Unit tests` job is pinned to Node 20, where it still compiles — which is why that PR looks half-green.) There is no tree-sitter release between 0.22.4 and 0.25.0, so there's no newer working version. `^0.21.1` ships N-API prebuilds (no compile) and installs cleanly on Node 20 / 22 / 24. This PR also adds a Dependabot `ignore` for tree-sitter minor/major so the group stops re-proposing the broken bump. Patch updates stay allowed; drop the ignore once upstream restores prebuilt binaries. ## Verification (local) - Lockfile regenerated on **Node 20 / npm 10.8.2** (`npm install --package-lock-only --ignore-scripts`), idempotent under a re-run — won't trip the strict lockfile check. tree-sitter resolves to 0.21.1 (prebuilt, no native compile). - Full CI-equivalent on **Node 20**: `tsc --build`, `eslint --max-warnings 0`, `prettier --check`, `typecheck:tests`/`typecheck:scripts`, full unit suite incl. **1250 tool-server tests** — all green. - `npm ci` from the committed lockfile succeeds. - **Live device E2E**: ran the built tool-server with the bumped deps, captured a real screenshot of a booted iPhone 16 Pro Max (`simulator-client` uses `ws`), then downloaded the PNG artifact over HTTP — `200`, 331 KB PNG. Supersedes #348 (Dependabot auto-closes it once the safe bumps land and tree-sitter is ignored). |
||
|
|
c832109573 |
chore: bump versions to 0.12.0 (#358)
Bumps the package suite from `0.11.0` to **`0.12.0`**. ## Changed - All release packages `0.11.0 → 0.12.0`: `@swmansion/argent`, `@argent/cli`, `@argent/installer`, `@argent/mcp`, `@argent/tools-client`, `@argent/native-devtools-android`, `@argent/native-devtools-ios`, `@argent/registry`, `@argent/skills`, `@argent/tool-server`, `@argent/update-core`, `@argent/configuration-core`. - `@argent/preview-window` `0.9.0 → 0.12.0` — aligned to the suite (was lagging a release behind; `private`/unpublished). - Regenerated the matching `package-lock.json` workspace version entries. ## Not changed - `@argent/ui` stays at `0.0.1` (separate pre-release track). - The private workspace root has no version. - Internal deps use `file:../` specifiers, so no dependency ranges needed updating. No source/runtime changes — `argent --version` reads from `package.json` at runtime. |