mirror of
https://github.com/software-mansion/argent.git
synced 2026-09-14 19:27:14 +08:00
fix/native-devtools-dyld-skip-terminal
39 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1a7e97fb14 |
feat(flows): run a local script in a bounded child process (#864)
Adds the executor a flow `script:` step runs on: a fresh Node child per step, a protocol over its IPC channel, and the two watchdogs that make a hung or runaway script the runner's problem rather than the host's. The step itself is not here. This branch stops at the executor and its unit tests; `feat/flow-script-step` stacks the YAML directive, the runner integration, and the reference docs on top. ## What it does - **One child per step.** Spawned with an old-space heap limit, an explicit working directory, and an environment built from an allowlist rather than copied from the tool server. - **A deadline and a lifeline.** A separate watchdog holds the deadline, so a script that wedges the event loop still dies on time; a second one reaps the whole process tree when the parent goes away, so a grandchild cannot outlive the run. - **A concurrency queue.** Slots are bounded per server. A step that never gets one is refused with a message that says so, and an aborted run frees its slot immediately. - **Log budgets.** 64 KiB per step and 256 KiB per run, counted on the bytes the report keeps: redaction and V8 frame collapsing both run before anything is counted, so what the limits bound is the size of the report rather than the size of the script's writes. - **Secret hold-back.** The scrub walks a chunk and stops where a value could still begin, so neither half of a value split across two chunks is released on its own, and a shorter value is never taken where the longer one containing it has not arrived yet. - **A failure taxonomy.** Twelve kinds, split into what the script did (it threw, it did not load, it exited non-zero, it wrote an unusable `output`) and what the host did to it (a limit, a signal, a spawn that failed, a queue slot it never got). ## Docs `packages/docs/docs/reference/configuration.mdx` lists the two configuration keys this branch adds, `scripts.maxTimeoutMs` and `scripts.heapLimitMb`. The `script:` step itself is documented with the step, on `feat/flow-script-step`. ## Verification `npm run build`, `npx eslint . --max-warnings 0`, `npx prettier --check .`, `npm run knip`, `npm run typecheck:scripts`, the test typecheck across every workspace, the tool-server suite (4719 passed, 1 skipped) and `npm run test:scripts` (92 tests) are green, as is `npx docusaurus build`. The executor's own behaviour is covered by the eight `test/flows/script/` files added here, against real child processes, and the compiled `dist/` executor was driven against its copied runner assets over every path the review reached. Each review fix carries the run that reproduced it before the change and the mutation that proves the new test fails without it: the prefix-secret leak and all three npm `node-options` routes were reproduced end to end through the executor against real child processes, and the five coverage findings were confirmed by re-applying the exact mutation each thread named. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added reliable execution of trusted flow scripts with concurrency control, cancellation, timeouts, memory limits, logging, and detailed failure reporting. * Added safeguards for process cleanup, watchdog termination, output validation, and secret redaction. * Added global configuration for maximum script runtime and memory usage. * **Bug Fixes** * Improved handling of script failures, stalled processes, malformed output, and child-process termination. * **Documentation** * Documented script resource limits and global configuration behavior. * **Chores** * Updated builds and packaging to include required flow-script runtime assets. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Hubert Gancarczyk <claude-hubert.gancarczyk@swmansion.com> |
||
|
|
2740a3ec38 |
chore(knip): clear the parked dead-code backlog and drop the ceiling to 0 (#770)
> Built on top of #769, so this PR carries that commit too — the workflows only run for PRs targeting `main`, which is why it is based there rather than on the branch. #769 on its own is the minimal, low-risk fix for the currently-red job; if it merges first this shrinks to its own commit, and if this one merges first it closes #769 as well. ## What this does #572 landed the gate with 215 findings parked under `--max-issues`. That bounded the backlog but left it in place, and the first thing to touch it (#663) pushed the total to 218 and turned the job red. This clears the backlog and sets the ceiling to **0**, so the next unused export fails the job instead of consuming headroom nobody knew was there. | | before | after | | --- | ---: | ---: | | Unused exports | 47 | 0 | | Unused exported types | 156 | 0 | | Unused exported class members | 12 | 0 | | `--max-issues` | 215 | **0** | ## Scope check first Every workspace holding a finding is `private: true`. `@swmansion/argent` — the one published package — had **zero**, so nothing here moves a public API. ## Two shapes of fix **Still referenced inside its own file → drop `export`** (146 types, 36 exports). The declaration stays put; it just leaves the module's public surface. `tsc` keeps emitting these into the `.d.ts` as local declarations that the exported signatures reference. For the 146 **types** that is the whole story: they are erased, so the emitted `.js` is byte-identical. For the 36 **values** it is not. Dropping `export` from a `const`/`function`/`class` removes its `exports.X` binding from the emitted `dist/*.js` — 36 declarations across 26 files here. `packages/tool-server/dist/utils/device-info.js` no longer carries `exports.REMOTE_PREFIX` or `exports.VEGA_SERIAL_PREFIX`; `telemetry/dist/posthog.js` loses `exports.POSTHOG_PROJECT_TOKEN`; in the ESM-emitting `argent-installer`, `isTempRunnerPath` / `resolveLocalArgentDir` / `PACKAGE_ROOT` leave the module namespace object entirely. Nothing in the repo or in the `packages/argent-private` submodule at the pinned revision reads any of them by path, so nothing breaks. Flagging it because a `require()` of a built `dist/*.js` loses a dropped `export` exactly the way it lost the deleted `__resetAndroidDevtoolsInstallCache` this branch had to restore — so this half of the diff does deserve runtime scrutiny, not a skim. **Referenced nowhere → delete.** Orphaned test seams (`__test`, `_testValidators`), stale compatibility re-exports, and a few real orphans. The ones worth a reviewer's eye: - **`localSimctl`** — the `SimctlBackend` strategy is only ever constructed with `remoteSimctl`. What keeps the local iOS impl off it is the handler signature: `buildIosLaunchHandler` / `buildIosRestartHandler` read `services.nativeDevtools`, and `ios-remote` is the only platform that declares that service, so the local impl — which resolves native-devtools per device inside its own handler — has nothing to hand them and shells out to `xcrun` itself. - **`sendCharInsert`** — removing the `__sendCharInsert` test alias exposed the underlying helper as unreferenced. It is superseded, not unwired: the Chromium keyboard impl dispatches its own `type: "char"` event inline (`keyboard/platforms/chromium.ts:58`), which is exactly what this helper did. Chromium typing is unaffected. - **Error metadata fields** — `ServiceNotFoundError.serviceId`, `ToolNotFoundError.toolId` and their two siblings were never read. The `e.serviceId` in `registry-error-events.test.ts` is a field on the event object the handler pushes, not on the error class; the `err.toolId` in `http.ts` is `NotImplementedOnPlatformError`, a different class that keeps its fields. Flagging these in case they are wanted as deliberate diagnostics. Deleting `SourceMapsRegistry.toGeneratedPosition` / `findMatchingSource` cascaded into their only helper (`buildSourceCandidates`) and then into `projectRoot`, which had no remaining reader — so the constructor parameter goes too. `StubSourceMapsRegistry` existed only to pass `super("")`, so it goes with it. ## The three cross-workspace members `ArtifactStore.register`, `ArtifactStore.list` and `TypedEventEmitter.off` are all called from other workspaces — the artifact route and screenshot tools in `tool-server`, and `registry-listener` in `telemetry`. They are reported unused anyway, and the reason is the **unbuilt tree** the gate runs against: every workspace resolves `main`/`types` to a `dist/` that does not exist, so `@argent/registry` resolves to nothing and the cross-workspace edge never forms. Build the tree and all three findings disappear on their own; a control member that really is dead is still reported in the built run, so the pass is live either way. Nothing about this is specific to `classMembers` — every cross-workspace reference is invisible the same way. Each is exempted at the declaration with a `@public` JSDoc tag rather than by name in `knip.jsonc`, for one reason: **scope**. `ignoreMembers` matches a name across the whole workspace, so it would also hide a future dead `register`/`list`/`off` on any other class in `packages/registry`; `@public` binds to the member it is written on. What `@public` does **not** buy is a staleness check, and neither does `ignoreMembers`. Measured on a clean unbuilt worktree: a bogus `ignoreMembers` name and a redundant `@public` each leave the run at exit 0 with no hint, while a bogus `ignoreDependencies` name exits 1 with `Remove from ignoreDependencies`. `treatConfigHintsAsErrors` is live and simply has no producer for either exemption style — so when one of the three stops being earned, nothing says so, and the JSDoc at each member is the only record a re-audit has. Each one names its callers, and `off` records how to re-derive them (rename the member and read the `Property 'off' does not exist` errors; grepping `.off(` over-reports, since 14 of the 38 call-site hits are Node `EventEmitter`s). One correction to the commit message on that change: it says 35 hits where the exact count is 38 — 14 Node `EventEmitter`, 24 `TypedEventEmitter` (21 production, 3 in a test). The 14 and the 21 are right. `knip.jsonc`, `CONTRIBUTING.md` step 5 and the workflow's failure-explanation step all described a parked backlog and a ceiling to stay under. All three are rewritten for a gate that must simply come back empty, and all three now name the `@public` escape hatch — the remedy for a symbol whose only caller is out of knip's reach. ## Verification Run against a clean worktree with **no build output**, the way CI counts: - `npm run knip` — **exit 0, prints nothing**. Both passes empty, no config hints. - `npx tsc --build` — clean. - `npm run lint` (`eslint . --max-warnings 0`) — clean. - `npx prettier --check .` — clean. - `npm test --workspaces` — tool-server 329 files / 3857 passed; registry, telemetry, update-core, tools-client, mcp, cli green. - `npm run typecheck:tests --workspaces` — 13 workspaces define the script and all 13 are clean, but **the command itself exits 1**: npm errors `Missing script: "typecheck:tests"` for the three that do not define it rather than skipping them. Worth knowing before re-running this bullet and reading the exit code as a failure. End-to-end on a tool-server built from this branch, driven over its HTTP API: - **Chromium** (Electron smoke app) — `describe`, `screenshot`, `gesture-tap` (counter advanced 0 → 1), `POST /api/clipboard/text` read back out of the renderer, the WS `clipboardSync` command, and `debugger-connect` / `debugger-status` / `debugger-evaluate` (`sourceMapReady: true` with `StubSourceMapsRegistry` gone). - **iOS** — `boot-device`, `launch-app`, `describe` via ax-service, `screenshot`. - **tvOS** — `boot-device`, `launch-app` on an Apple TV udid, focus-driven `describe`. The registry snapshot then carries `NativeDevtools:<tvOS udid>`, confirming injection **is** resolved on tvOS through the local impl. - **Android** — `boot-device` on a dedicated AVD, `describe` via android-devtools, `gesture-tap`. - **Metro source maps** — the registry driven against a real 12.5 MB Metro `.map` over loopback, the way `Debugger.scriptParsed` drives it: allowlist passes and `waitForPending()` resolves on both, while retained heap after gc drops from 17.3 MB to 3.6 MB. ## Review follow-ups Five commits on top, one per finding. The base is back on `main`, so the workflows run again. - **`docs(launch-app)`** — the services comment explained the empty shape through `LaunchAppAndroidServices`, deleted here, and skipped `LaunchAppVegaServices`, which is still there. Same edit in `restart-app/types.ts`. - **`docs(registry)`** — the `@public` tag on `ArtifactStore.register` named 2 of 7 callers. Derived the full set the way the sibling tag on `off` prescribes: renamed the member, read the 16 `TS2339` errors `tsc --build` reports across flow-visual (5), screenshot (4), native-profiler-stop (2), screenshot-diff (2), native-profiler-analyze, react-profiler-analyze and screen-recording-stop. The re-derivation recipe is recorded too — `.register(` greps as badly as `.off(`. - **`docs(knip)`** — "the build, the tests and this gate all stay green on a wrong delete" held for argent-private and not for the cross-workspace case that justifies three of the four `@public` tags. Deleting `ArtifactStore.register` gives 16 `TS2339` errors and `9 failed | 2 passed` in `test/artifacts.test.ts`; only the gate stays green. Split in the workflow comment, the failure annotation and `CONTRIBUTING.md` step 5. - **`perf(debugger)`** — `doRegister`'s `data:` branch still base64-decoded and `JSON.parse`d a payload it dropped, inside a `catch` that swallows. Both arms returned the same `void`, so the branch collapses to an early return; `scriptUrl` / `scriptId` go with it, since their last reader was the deleted `this.maps.push(...)` and `doRegister` is private. - **`test(debugger)`** — the allowlist check moved to a top-level early return with nothing pinning it: delete the line and both SSRF files still pass 17/17. Two tests now assert `doRegister` consults it — four rejected URLs reach no `fetch`, and the loopback `*.map` Metro emits still does. Re-verified after: `npm run knip` exit 0 and empty on a `tsc --build --clean` tree, `tsc --build`, `eslint . --max-warnings 0`, `prettier --check .` all clean, and `npm test --workspaces` with tool-server at 329 files / 3854 passed. The one red test, `argent-installer`'s `globalPath returns ~/.config/opencode/opencode.json`, fails identically with these commits stashed — it reads the real `~/.config/opencode`, which holds a `.jsonc` on this machine. End-to-end on a tool-server run from this branch over its HTTP API, on every platform: - **Chromium** — `launch-app`, `describe`, `screenshot` (returned an artifact handle, `GET /artifacts/<id>` served the 137542-byte PNG back), `gesture-tap` (counter 0 → 1), `debugger-connect` / `debugger-status` (`sourceMapReady: true`) / `debugger-evaluate` (read `taps: 1` out of the page). - **iOS** — `launch-app`, `describe` via native-devtools, `restart-app`, `screenshot`. - **tvOS** — `launch-app`, focus-driven `describe` (12 focusables in TVSettings), `tv-remote`, `restart-app`. - **Android** — `launch-app`, `describe` via android-devtools, `restart-app`, `screenshot`. - **Vega** — `boot-device` on the `tv` VVD, `describe` via the automation toolkit. - **Metro** — the real `debugger-connect` / `debugger-status` / `debugger-evaluate` tools against a stand-in Metro (HTTP `/json/list` + CDP WebSocket) emitting three `Debugger.scriptParsed` events: a loopback `*.map` on a counting server, a 1.4 MB inline `data:` map, and `http://169.254.169.254/latest.map`. `sourceMapReady: true`, `loadedScripts: 3`, evaluate 42, the loopback map fetched exactly once and the metadata URL never. A malformed inline payload gives byte-identical output, which is the finding. ### Merge with `main` Putting the base back on `main` made CI resolve the merge, and the Unit Tests job went red on a conflict no side could see on its own: `#771` fixed the same red gate this branch's first commit did, the other way round — it made `component-names.test.ts` import `StrippedName`, `ComponentAnnotation` and `ComponentNameResolution` instead of dropping their `export`. Merged `main` in, reproduced it (`tsc --noEmit -p tsconfig.test.json` → three `TS2459`s) and took main's resolution: the three exports are back. The gate stays green because knip treats test files as entry points, so a type a test imports is not an unused export. All nine workflows are green on the head commit. |
||
|
|
36aa14a5fc |
docs: add Argent documentation (#814)
Adds the Argent documentation site, published to [docs.swmansion.com/argent](https://docs.swmansion.com/argent): a branded Docusaurus project under `packages/docs/`, the full first set of pages, and the CI that checks and deploys it. <img width="1512" height="945" alt="Screenshot 2026-08-21 at 13 05 04" src="https://github.com/user-attachments/assets/4607e143-4359-49a8-93a2-aaa3af4c9534" /> ## Site A standalone Docusaurus 3.9 project, built on the shared Software Mansion docs theme ([`@swmansion/t-rex-ui`](https://www.npmjs.com/package/@swmansion/t-rex-ui)) and restyled for Argent: - **Palette** from [argent.swmansion.com](https://argent.swmansion.com): dark `#0D0F26`, blue `#99DAFF`, lavender `#E4E1FF`, light `#FEFEFE`, mist `#F1F1F1`. The `--swm-*` token names stay, since the shared theme resolves against them. - **Typography**: DM Sans and DM Mono, matching the landing page. - **Sidebar** with lucide icons on every page entry (`sidebar_custom_props.icon` in the front matter, registered in `src/theme/SidebarIcon`), the logo kept on the page background and the panel inset from the edge. - **Video component** for embedded screen recordings, with `scripts/encode-video.sh` producing a web-sized MP4 and a poster frame for each clip in `static/video/`. - **Copy page button** and a few theme fixes: inline code badges in tables, paginator hover. - **No landing page.** That stays at argent.swmansion.com. The root route redirects to Getting started. ## Content Three sections in `docs/`: - **Fundamentals**: getting started, installation, supported platforms. - **Features**: interacting with apps, flows, network, screen recording, lens, visual regression, profiling, debugging. Conceptual overviews with recordings, each linking to the tools reference. - **Reference**: tools, CLI, configuration, flow YAML, editors, telemetry. Prose follows Simplified Technical English. The conventions (style, front matter, icons, checks) are written down in `packages/docs/CLAUDE.md`, and a root `CLAUDE.md` adds a checklist so that code changes to tools, CLI, configuration or flows update the matching docs page in the same pull request. ## CI and deploy - `Docs build` runs `format:check`, `lint`, `typecheck` and `build` on every pull request that touches `packages/docs/`. The build has `onBrokenLinks: "throw"`, so it catches links left dangling by a moved page. - `Docs publish` deploys `packages/docs/build` through the GitHub Actions Pages source on every push to `main` that touches the docs. The repository Pages source needs to be set to **GitHub Actions** for the first run. ## Notes for review - The site is excluded from the root `packages/*` workspaces (`!packages/docs`) and keeps its own `package.json` and `package-lock.json`, so its dependency tree stays out of the toolkit's lockfile. Root Prettier, ESLint and knip ignore it; it formats and lints itself with the repo `.prettierrc` and its own `eslint.config.mjs`. `check-workspace-versions.mjs` skips it so its `0.0.0` version is not read as drift. - `webpack` is pinned to `5.105.4` and `@docusaurus/plugin-content-docs` / `theme-common` to `3.9.2` via `overrides`. Newer webpack fails Docusaurus 3.9's ProgressPlugin option validation, and a hoisted `plugin-content-docs@3.10.2` produced a duplicate React context that crashed SSR. - **Search is not wired up yet.** The shared theme always mounts a DocSearch bar, so an `algolia` block has to be present. It reads `ALGOLIA_APP_ID` / `ALGOLIA_API_KEY` / `ALGOLIA_INDEX_NAME` from the environment and the bar stays hidden until Argent has its own DocSearch application. Follow-up PR. ## Testing - `npm run format:check`, `npm run lint`, `npm run typecheck` and `npm run build` pass in `packages/docs/`. - Root `prettier --check`, `eslint` and `npm run knip` pass. - Walked the served production build in the browser in light and dark themes while iterating: root redirect, docs pages, sidebar icons, videos, TOC, footer. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
c876fe8dbc |
ci: add knip anti-dead-code gate (#572)
## What Adds a CI gate for dead code, using [Knip](https://knip.dev). We didn't have one. ESLint's `no-unused-vars` only sees unused locals inside a module, so whole files nobody imports, exports nobody uses, and dependencies declared but never required all slipped through. Knip covers that gap in one tool (roughly `ts-prune` + `depcheck` + `unimported` combined). The new `.github/workflows/knip.yml` workflow ("Dead Code", job `Knip`) runs `npm run knip` on push and PR to `main`. `CONTRIBUTING.md`'s pull-request checklist gains it as a step, with the reason it has to run against a tree with no build output. Knip reads source directly, mapping each package's `dist` entry back to `src`, so the job needs no workspace build. It installs with `--ignore-scripts`: an analysis that only reads `package.json` and source gains nothing from the seven packages here that carry a native install script, six of which reach this runner (`fsevents` is darwin-only). Five try a prebuilt binary before compiling, and `dtrace-provider` always runs node-gyp but ends in `|| node suppress-error.js` — and off mac/solaris/freebsd its `binding.gyp` picks a stub target with no sources, so on ubuntu-latest node-gyp builds nothing for it and `node-pty` is the only package that reaches a compiler at all — an `optionalDependency`, whose failure npm ignores. The exposure is a bump that leaves a package with no prebuild for the runner, which is exactly what `dependabot.yml` pins `tree-sitter` against (0.25.0 ships no Node 24 prebuild and its compile breaks `npm ci`). While adding it I checked whether any other installed checker was missing a gate. None were: ESLint (`lint.yml`), Prettier (`format.yml`), `tsc` build + `typecheck:tests` + `typecheck:scripts` + vitest (`unit-tests.yml`), the workspace-version / focused-test / merge-marker checks (`repo-hygiene.yml`) and lockfile sync (`lockfile.yml`) are all already enforced. Dead code was the only gap. ## How it's enforced `npm run knip` is two invocations: ``` knip --exclude exports,types && knip --include exports,types,classMembers,nsExports,nsTypes --max-issues 206 ``` Every issue type knip reports is an error — that is its default severity, so `knip.jsonc` sets no `rules` block at all. The pre-existing backlog is bounded by the `--max-issues` ceiling on the second pass instead of being hidden behind a non-failing severity: it cannot grow unnoticed, and the number comes down as follow-up passes pay it off. When a change legitimately adds an export nothing imports yet, the number moves up in the same commit — that bump is what review should see, rather than the contributor deleting someone else's backlog to make room. Two PRs making that identical one-line edit merge without conflicting, so `main` lands one short of the truth and its push-triggered run is what catches it. Splitting the passes also keeps a real failure out from under the backlog — the enforced classes report on their own, and the second pass only runs once the first is clean. The second pass names `classMembers`, `nsExports` and `nsTypes` explicitly because they sit in knip's own `defaultExcludedIssueTypes`: `--exclude exports,types` never covered them and `--include exports,types` did not ask for them, so a new unused class member cost nothing and moving an export behind opaque namespace use took it out of the ceiling's scope entirely. `classMembers` has 12 findings on the unbuilt tree the ceiling counts (9 on a built one); the other two have none today. None of the three is gated at zero — all five parked classes share the one ceiling, so a new `nsExports` finding passes if something else in the backlog is retired in the same PR. Naming `classMembers` also turns knip's `isSkipLibs` off (`create-options.js:122`), which makes it search declaration files for external references and **suppresses** 44 export/type findings the same run reports without it — 57/181 becomes 44/150. That, not the 12 findings it adds, is why the ceiling is lower than the two counts alone would suggest; `--include-libs` with no `classMembers` reproduces 44/150 exactly. The ceiling counts what CI counts, against a tree with no build output. Whether a workspace's `main`/`types` path resolves to an existing file changes the result, and not by way of anything in that file — a zero-byte `packages/registry/dist/index.js` moves the count just as a real build does, while a zero-byte `dist/zzz.js` does nothing. A built tree reports fewer issues — 43/147/9 = 199 built, against 44/150/12 = 206 unbuilt — so `npm run knip` passing after a local `tsc --build` is not evidence the job will pass, which is how the Knip job first went red on 199. The ceiling is 206 and it is exact: 206 passes, 205 fails. Remove every `dist/` before trusting a number from it. The ceiling is one total across those classes, so it bounds the backlog rather than each class: paying off one parked export licences one new one elsewhere in the same PR. Knip has no per-class ceiling. `treatConfigHintsAsErrors` is on, so an exemption that stops suppressing anything fails the job rather than printing a hint below the backlog. ## Config `knip.jsonc` documents the false positives so the gate is both green and meaningful. - **`@swmansion/argent`** is a thin dispatcher whose real payload is an esbuild bundle of the other workspaces (`packages/argent/scripts/bundle-tools.cjs`). Knip can't follow imports across that boundary, so packages consumed only by the bundled-in code read as unused; 11 are exempted by name here, though not all for that reason — the http3-quiche transport is pulled in by `@fails-components/webtransport` itself at runtime, and no first-party file imports it. They're exempted **by name**, not behind a catch-all: `ignoreDependencies` also suppresses `unlisted`, and a pattern that matches everything would take this workspace's own `src/` and `scripts/` out of that check — where an import with no matching declaration is a genuine bug rather than a bundler artifact. (It reaches `unresolved` only nominally: knip matches the list against a package name parsed out of the specifier, and an unresolvable relative path yields none, so even a catch-all leaves those reported. `ignoreUnresolved` is the option that does silence them.) - **`tool-server`** reaches a few packages in ways static analysis can't see. The exemptions cover two distinct classes, kept apart in the config so each stated reason matches the finding it silences: - *declared but loaded too dynamically to detect* (would be reported as **unused dependencies**): `tree-sitter` / `tree-sitter-typescript` via dynamic `_require`, and the http3-quiche transport as a runtime companion of `@fails-components/webtransport`; - *imported but deliberately absent from that `package.json`* (would be reported as **unlisted dependencies**): `sharp` (kept out so the ~30 MB native binary isn't a cost every consumer pays) and `electron` (an `optionalDependency` of the published package at one call site, the Electron main-process API at the other). - Root `scripts/`: knip resolves those from `package.json` scripts **and** from `run:` steps in `.github/workflows` via its github-actions plugin — multi-line `run: |` blocks included. What the plugin doesn't parse is a PowerShell body, so `scripts/ci/windows-chromium-e2e.mjs` — invoked at `windows-e2e.yml:176`, in the `windows-latest` job where PowerShell is the default shell — is the one entry declared by hand. ### Known limits - `ignoreDependencies` exempts a package **name across its whole workspace**, in both directions; knip has nothing narrower. While `sharp` is listed for `tool-server`, an undeclared `import "sharp"` anywhere in that workspace passes too. The list is held to packages that genuinely cannot be declared, for exactly that reason. - Knip analyzes JavaScript and TypeScript only (`DEFAULT_EXTENSIONS`), so **only 11 of the 30 files under `scripts/` are in the gate at all**. The other 19 — 15 `.sh` files, `e2e-full/lib/report.py`, `ci/e2e-chromium-page.html`, and e2e-full's `README.md` and `results/.gitignore` — are invisible to it however they are reached — including the whole `scripts/e2e-full/` harness (13 files), invoked from nothing outside its own directory, its only mention elsewhere being a `.prettierignore` entry. - Reachability's widest hole is the workspace entry. Whatever `src/index.ts` re-exports is reached, so a single `export { x } from "./dead-module";` takes that module out of `files` altogether — verified against a module reported as an unused file one run earlier. The same line applied to parked exports retires them from the count without deleting anything: re-exporting `equalsCI`, `includesCI` and `Settled` from `tool-server`'s entry takes 206 to 203 and frees three ceiling slots. The ceiling bounds what knip can see, not what is dead. - Test files are entry points, so a production module kept alive only by its own test still passes `files`. Being reached by a test says nothing about being reachable in production, which is what the check approximates, and two modules sit in exactly that gap: `tools/paste` is imported by two test files and registered by nothing, so it is unreachable over MCP and HTTP, and `utils/ios-profiler/lifecycle.ts` is a re-export barrel whose header keeps it "for source compatibility with existing imports", of which its own test is now the only one — its four production consumers all import `profiler-shared/lifecycle` directly. That single test import is exactly what keeps `files` from reporting it: repoint it and knip returns `Unused files (1)`. `knip --production` is the lens that reports the class; the repo isn't clean under it — 13 unused files (those two, seven root scripts, `packages/argent/scripts/{bundle-tools,observe,sync-readme}.cjs` and `packages/registry/tests/helpers.ts`) with the export/type backlog at 227/206 — measured with `classMembers` off, so comparable to the 57/181 above rather than to the ceiling's 44/150 — so a production-mode pass is a follow-up of its own. - The same entry treatment hides the test trees themselves. Root `package.json`'s `test:scripts` runs `node --test`, which is what makes knip's node plugin contribute its test entries, and that plugin registers four entry patterns in **every** workspace: `**/test/**`, plus `*{.,-,_}test.<ext>`, `test-*.<ext>` and `test.<ext>` matched anywhere. So none of the **380** JS/TS files under `packages/*/test/` can be reported unused, and under `packages/*/tests/` only a name none of those three match can — of today's 15 that is `registry/tests/helpers.ts` alone, which is why it is the lone `tests/` entry in the `--production` list above. A `tests/test-utils.ts` or `tests/test.ts` would be just as invisible. A dead `zz.test.ts` planted in `packages/registry/tests/` passes; a dead `zz-helper.ts` in the same directory fails. - `knip@5.88.1` is the last 5.x release ever published — 6.0.0 landed the next day and `latest` is now 6.x. The pin is deliberate: knip 6 removed the `classMembers` issue type outright, and the shipped script hard-errors on it (`ERROR: Invalid issue type: classMembers`, exit 2). Upgrading is therefore not a version bump — it means re-deriving the ceiling, rewriting the paragraph that explains it, and resolving the pass-1 findings knip 6 adds (six unlisted binaries: `tail`, `plutil`, `xctrace`, `netstat`, `pkill`, `pgrep`; two unresolved imports: `/usr/bin/osascript`, `/usr/libexec/PlistBuddy`). Dependabot's `npm-minor-patch` group cannot move it, since no 5.x exists above 5.88.1; the `npm-major` group will keep offering the 6.x jump. - Knip folds `optionalDependencies` into the declared set, so importing `electron` or `node-pty` is not `unlisted` — they pass because it read them. What it never reports is an optionalDependency nothing uses, so only that direction is outside the gate, along with `argent-cli`'s runtime `req("node-pty")`, resolved through a `createRequire(import.meta.url)` in `lens-pty.ts`, which knip can't see either. ## Dead code this found - `@types/semver` and `@argent/telemetry` from `packages/argent` — both were being suppressed by exemptions whose stated bundler-boundary reason could not apply. esbuild strips types and never resolves `@types/*`, and `packages/argent` names `semver` nowhere; `@argent/telemetry` is aliased to an absolute source path by `bundle-tools.cjs`, so the declaration bought nothing. Removing them is proved safe by building: four of the five bundles still emit and telemetry is inlined in each with no runtime `require` of it. The fifth, preview-window's main, sits behind a downloaded native asset absent from a script-free install, so it is covered by mechanism rather than observation — `bundle-tools.cjs` passes the same `alias` map to every build, and esbuild's `alias` bypasses node resolution entirely: deleting `node_modules/@argent/telemetry` outright leaves all four emitted bundles byte-identical. Removed alongside, but **not** gate-reported: the `benchmark` npm script in `packages/argent`, whose `scripts/benchmark.cjs` does not exist. A dangling script target is a blind spot of this gate — restoring the script leaves knip at exit 0. - Four files with no importers: the `render-hook` injected script, react-profiler's `source-map` + `snippet-extractor`, and `scripts/setup-in-workspace.cjs` (referenced nowhere, and its own usage string names a `scripts/setup-project.cjs` that doesn't exist). - `superagent` in `tool-server`'s `test/http-streaming.test.ts` — imported for a type but declared in no manifest in the repo, resolving only through npm hoisting of supertest's own dependency. Reverting that import to `superagent` reports `Unlisted dependencies (1) … :3:32` and exits 1; `@types/supertest/index.d.ts:10` re-exports the identical type (`type Response = superagent.Response`). - `@clack/prompts` and `@moq/lite` from `tool-server`'s `package.json` — declared, imported nowhere. (`@moq/net` is the one actually used; `@moq/lite` isn't a peer of it.) Also deleted here, but **not** something this gate reported: `src/tools/simulator/simulator-server.ts`. It sat in the `files` blind spot above — `interaction-messages.test.ts` imported it, which is enough to count as reached. `setup-registry.ts` never registers it, so it was unreachable over MCP and HTTP, and that catalog roll-call was its only reference; the import and the catalog count (77 → 76) went with it. ## Lockfile Adding knip moves two transitive packages: `@napi-rs/wasm-runtime` 1.1.5 → 1.1.6 and `@tybys/wasm-util` 0.10.2 → 0.10.3. Knip pulls in `@oxc-resolver/binding-wasm32-wasi`, which floors `@napi-rs/wasm-runtime` at `^1.1.6`, lifting the hoisted entry that had resolved to 1.1.5 for `@rolldown/binding-wasm32-wasi`'s `^1.1.4`, which then cascades to `@tybys/wasm-util`. No runtime impact — both are support packages for the wasm32-wasi fallback bindings, which don't get installed where a native binding exists; `npm ls` reports both extraneous on darwin-arm64. Those two are the only resolved versions that change in the diff; the rest is knip's own tree (49 packages added) and `@moq/lite` removed. ## Verification - `npm run knip` exits 0. - **Coverage of the enforced set.** With no `rules` block, knip's included set is 15 issue types: ten enforced at zero tolerance by the first pass, plus the five the second pass names under the ceiling. Eleven mutations cover all ten, each flipping the gate to exit 1 and back to 0 on revert: | class | mutation | | --- | --- | | `files` | a throwaway `.mjs` in `scripts/`; a throwaway `.ts` in `packages/argent/src` | | `dependencies` | a bogus declared dep in `packages/tool-server/package.json` | | `devDependencies` | a bogus declared devDep in the same manifest | | `optionalPeerDependencies` | `bytes` moved to an optional `peerDependency` there | | `unlisted` | an undeclared import in `packages/argent/src/cli.ts` | | `unresolved` | an unresolvable relative specifier in the same file | | `binaries` | a root `package.json` script invoking a nonexistent binary | | `duplicates` | `export default sleep` alongside the existing named export in `utils/timing.ts` | | `enumMembers` | an unused member on an enum a second module imports and uses | | `catalog` | a `catalog` block in the root `package.json` naming a package nothing uses | One nuance worth recording: `duplicates` is narrower than it looks. It reports a symbol exported both by name and as `default` (`sleep|default`); a second *named* alias of the same symbol is not a duplicate, and a freshly added symbol nothing references is not reported at all — so several naive probes read as a miss. `enumMembers` needed a shape the repo does not currently contain, not an unreachable one. The only exported enum here, `ServiceState`, is re-exported through `@argent/registry`'s entry, where knip counts exports as used, so an unused member added to it is **not** reported — but an enum in a non-entry module that another module imports and uses does report one (`Blue ZzColor …/zz-enum.ts:3:3`, exit 1; deleting the unused member returns exit 0). That is the ninth of the ten covered. `catalog` is reachable here despite the repo using npm workspaces: knip's catalog loader falls back to `manifest.catalog` when there is no pnpm or yarn workspace file, so a `catalog` block in the root `package.json` reports `Unused catalog entries (1)` and exits 1. - The two new mechanisms discriminate as well: one extra unused export takes the backlog to 207 and fails the ceiling, and a stale `ignoreDependencies` entry produces `Configuration hints (1) … Remove from ignoreDependencies` and exit 1. - `npm ci --ignore-scripts` in a clean worktree, followed by `npx knip`, is green — the job doesn't need any of the postinstalls it now skips. - `tsc --build`, `typecheck:tests` (all workspaces), `typecheck:scripts`, `test:scripts`, `eslint . --max-warnings 0`, `prettier --check .` and the full workspace vitest suite (4711 passed, 3 skipped across 13 workspaces; 3070 of those are `@argent/tool-server` alone) are green; `package-lock.json` is untouched by the review pass. |
||
|
|
7e4ece697d |
chore: add server.json for the official MCP registry (#598)
Adds the two files the official MCP registry
(`registry.modelcontextprotocol.io`) needs in order to list argent.
Argent is not in that registry today
(`?search=io.github.software-mansion` returns 0 servers).
The registry is metadata-only — it points at the npm package rather than
hosting anything.
### `server.json`
Describes the server and how a client starts it: `npx @swmansion/argent
mcp`. The `mcp` positional is the dispatcher case in
`packages/argent/src/cli.ts:137`, and it is the same subcommand `argent
init` writes into every client config —
`packages/argent-installer/src/mcp-configs.ts:130-141` spells it four
ways (`node <path> mcp`, `yarn argent mcp`, `npx --no-install argent
mcp`, and the global `{ command: MCP_BINARY_NAME, args: ["mcp"] }`,
where `MCP_BINARY_NAME` is `"argent"`). None of them is literally the
npx-by-package-name form in `server.json`, which is the form the
registry expects a client to construct from `identifier` + `runtimeHint`
— so it is verified below by running it, not by matching a string.
`repository.id` is the GitHub repo id (`1164885639`); the schema
recommends it so a registry can detect a delete-and-recreate of the
repo.
### `mcpName` in `packages/argent/package.json`
The ownership proof. The registry fetches the npm package and requires
`mcpName` to equal the server name in `server.json` before it will
accept a publish under `io.github.software-mansion`. It is the field the
registry's own quickstart names for npm packages. Nothing in the publish
path drops it: `scripts/pack-mcp.cjs` shells out to `npm pack` without
rewriting the manifest, and the canary path's
`scripts/next-canary-version.mjs --write` round-trips the JSON and only
sets `version`.
### Namespace
`io.github.software-mansion/argent` — GitHub OAuth auth. The registry
grants an org namespace only to org **Owners**; plain membership is no
longer enough. If no Owner is available to run the publish, the
alternative is DNS auth via an apex TXT record on `swmansion.com`, which
changes the name to `com.swmansion/argent` (and the `mcpName` value with
it).
### Version sync
`server.json` sits at the repo root, outside `packages/*`, so a release
bump would have left its two `0.18.0`s untouched — and the registry
rejects a publish whose `packages[].version` names a version npm has
never seen. `scripts/check-workspace-versions.mjs` (already run by the
Static checks job) also holds `server.json` to the version in
`packages/argent/package.json` — the package it names — and pins the two
cross-file links a publish depends on: `name` == `mcpName`, `identifier`
== the published package name. Both halves are reported in one run, so a
half-finished bump doesn't cost a CI round-trip per file.
### Not in this PR
- **Publishing.** Nothing has been published; this is just the manifest.
Publishing is `mcp-publisher login github && mcp-publisher publish`, and
it can only succeed **after** a release whose npm tarball carries
`mcpName` — i.e. not against `0.18.0`, which is `latest` (published
2026-07-30) and predates `mcpName` — `curl
registry.npmjs.org/@swmansion%2Fargent/0.18.0 | jq .mcpName` → `null`.
The first publishable release is the next bump.
- **`github.com/mcp`.** A separate, manual step. Onboarding a new server
there is hand-curated: per
[github/github-mcp-server#1257](https://github.com/github/github-mcp-server/discussions/1257)
(trent-j, a collaborator on that repo, 19 May 2026) "onboarding a new
server is still a manual curation process today. Once a server has been
onboarded, newly published versions from the OSS registry should sync
from there." The nomination channel is `partnerships@github.com`, from
GitHub's [registry how-to
post](https://github.blog/ai-and-ml/generative-ai/how-to-find-install-and-manage-mcp-servers-with-the-github-mcp-registry/)
(24 Oct 2025) — that address does not appear anywhere in the discussion
thread.
### Verification
- `mcp-publisher validate` (v1.8.0, which posts the file to the live
registry) → `server.json is valid`. Mutation-checked what that actually
covers: removing `transport` fails it and removing `$schema` is a 422,
but a foreign namespace (`io.github.anthropics/argent`), a nonexistent
npm identifier and a `99.0.0` package version all still pass — so it
checks shape only, and the ownership/existence checks happen at publish
time. Also validated offline against the pinned `2025-12-11` schema.
- Ran the entrypoint the file declares. `npx -y @swmansion/argent@latest
mcp` fed an `initialize` over stdio answered
`{"protocolVersion":"2024-11-05","capabilities":{"tools":{}},"serverInfo":{"name":"argent","version":"0.18.0"},"instructions":"…"}`,
with stderr empty.
- Mutation-checked the new version guard: drifting `server.json`
`version`, drifting `packages[0].version`, deleting `mcpName`, and
typo-ing `identifier` each fail `check-workspace-versions.mjs` with the
specific line; the pre-existing packages/* drift check still fires on
its own.
- Asserted across the two files: `mcpName` == `server.json` `name`,
`identifier` == package `name`, all three versions equal, description 89
chars (registry limit is 100).
- `prettier --check` and `eslint` clean on both changed files.
- Mutation-checked the guard as a whole — 22 mutants, 1 survivor.
Killed: reverting the self-invocation guard to a raw `argv[1]` compare
and making it never match; `exit(1)` → `exit(0)` on the failure path;
dropping either `failed = true`; exiting early on `packages/*` drift
instead of collecting; `packages.slice(0, 1)`; hardcoding `packages[0]`
in either message; dropping the no-packages-array guard, the
non-object-entry guard, the non-object-JSON guard, and the presence
checks for `version`, `name` and `mcpName`; `continue` → `break` in the
`packages/*` scan (both arms) and in the entry loop; dropping the
on-message read, the `git checkout` hint, and the per-version name
accumulator. The survivor is the `packages/*` readdir sort: it fixes the
scan order rather than any output, so no single run can observe it — it
is there so a scan that stops early drops the same packages on every
machine instead of a filesystem-dependent set.
- Reproduced the symlink no-op on the real repo: with
`packages/registry` at `9.9.9` and `server.json` at `0.17.0`, `node
/tmp/argent-alias/scripts/check-workspace-versions.mjs` now exits 1 and
prints both problems, where before it exited 0 with no output at all.
- Closed the vacuous-pass class in `serverJsonMismatches`: all four
comparisons it makes were bare `!==`, so a field absent from *both*
sides compared equal and passed. A `packages/argent/package.json` with
no `version` printed `All workspace packages and server.json are at
undefined.` and exited 0; with no `name`, a `server.json` naming nothing
installable was reported in sync. `version` and `name` now require
presence, as `mcpName` already did.
- `readTrackedJson` guarantees an object, not just parseable bytes — a
`server.json` holding `null` used to reach the field reads and throw,
and `"0.18.0"` or `[]` produced mismatch lines that never said the file
was the wrong shape.
- Full CI parity locally: `test:scripts` 85/85, `tsc -p
tsconfig.scripts.json`, `eslint --max-warnings 0`, `prettier --check`.
|
||
|
|
78d3184ba8 |
fix(scripts): stop extract-tools dropping tools with long descriptions (#436)
## Defect
`scripts/extract-tools.mjs` extracts MCP tool definitions by regex to
feed the downstream `spidershield scan --tools-json` security scan. For
each `id:` match it scanned only the next 2000 chars (`const descWindow
= afterId.slice(0, 2000)`) for the `description:` value, and the
description regexes require the string's closing delimiter to fall
inside that window.
Any tool whose description's closing delimiter sits past ~2000 chars is
therefore matched as `null` and **silently dropped** - never emitted,
never security-scanned. Two shipping tools hit this:
- `run-sequence`
(`packages/tool-server/src/tools/run-sequence/index.ts`) - a ~4285-char
multi-line template-literal description whose closing backtick sits
~4324 chars past its `id:`.
- `describe` (`packages/tool-server/src/tools/describe/index.ts`) - a
~2195-char description whose closing backtick sits ~2252 chars past its
`id:`.
**Security impact:** `describe` is the accessibility / DOM tree tool,
exactly the kind of tool a `spidershield` scan should cover, and it was
being silently excluded alongside `run-sequence`. A dropped tool is not
a scan finding, so the gap was invisible.
### Repro (before)
```
$ node scripts/extract-tools.mjs | grep -c '"run-sequence"'
0
$ node scripts/extract-tools.mjs | grep -c '"describe"'
0
$ node scripts/extract-tools.mjs | grep -c '"gesture-tap"'
1
# total tools emitted: 70 (run-sequence AND describe both missing)
```
### After
```
$ node scripts/extract-tools.mjs | grep -c '"run-sequence"'
1
$ node scripts/extract-tools.mjs | grep -c '"describe"'
1
# total tools emitted: 72 (both captured, run-sequence's full 4285-char description intact)
```
## Fix
- Drop the fixed 2000-char lookahead. Each tool's `description:` is
resolved at the **same object-literal brace level** as its `id:` by a
forward scan that tracks brace depth over real code only: comments,
string literals, template literals (with `${...}` interpolations skipped
opaquely, recursively), and regex literals (prev-token heuristic incl.
regex-permitting keywords like `return`) are skipped whole, so nothing
inside them can open a fake string, shift the depth, or match as a
`description:`/`id:` token. The value is then parsed to its actual
closing delimiter, so a description of any length is captured in full.
- Because matching is by brace scope rather than raw position, a stray
`id:`/`description:` token can't corrupt extraction: a description-less
tool can't borrow the next tool's description, an `id:` appearing inside
description text or a comment can't truncate or overwrite anything, and
an `id:` key nested inside a value object (e.g. `defaultPayload: { id:
"example" }`) is neither emitted as a spurious tool nor allowed to drop
the real one.
- Captured text follows full JS cooked-string semantics: named escapes,
`\xNN`, `\uNNNN`, `\u{...}`, identity escapes, line continuations, and
template `\r\n`/`\r` -> `\n` normalization - the emitted (and
security-scanned) text is the string the runtime renders.
- A description value that is not a single plain literal - a
concatenation, a `${...}` interpolation, a method/operator suffix
(`"...".slice(0, 3)`), `as const` - is never emitted as a
truncated/wrong literal: it warn-skips on **stderr** (stdout stays valid
JSON for the scanner). Non-interpolated template-literal ids (`` id: `x`
``) are extracted; interpolated ids stay out of scope like
const-reference ids.
- Duplicate ids keep the first occurrence and warn (exported as a pure,
unit-tested function).
- The extractor stays dependency-free (node: builtins only): the
tool-description-quality workflow runs it on a bare checkout without
`npm ci`.
- Output JSON shape is unchanged.
## CI guard
Adds `scripts/extract-tools.test.mjs` (node's built-in test runner,
wired into `npm run test:scripts`; 36 tests). Ground truth: the
real-tree tests parse every tool source file with the actual
**TypeScript parser** (a root devDependency, test-only) and require the
extractor's output to equal the AST **exactly - names and descriptions
byte-for-byte**. Any drop, corruption, or fabrication on a shape that
enters the tree fails CI loudly, with no reliance on stderr warning
formats and no false red from `id:`-like text in comments or strings.
Two policy gates keep un-extractable shapes out of the tree instead of
letting them silently leave the scan: a `description` that cannot be
read statically (non-literal value, shorthand/getter/method/computed
member, or a spread sibling that may carry/override it) and a
plain-literal description written **before** its `id:` (the scan is
forward-only) each fail with an actionable, file-naming message.
Fixture tests pin the parsing rules independent of any real tool's
wording - long descriptions (>4000-char value, >2000 chars of siblings
between `id:` and `description:`), embedded `id:`/`description:` tokens,
comments, keyword-position and sibling regex literals, division, nested
templates and interpolation content, template/`as const` ids, the full
escape suite, CRLF cooking, single-quoted forms, trim, warn-skip
classes, and the duplicate-id warning. Each new fixture was verified to
fail under a targeted mutation of the extractor.
Note: tools registered with a const-reference / dynamic id (e.g. `id:
AWAIT_UI_ELEMENT_TOOL_ID`) rather than a static literal stay out of
scope for this extractor - a separate, pre-existing limitation unrelated
to the description window, and one this static/lexical extractor cannot
close soundly (it has no tool-scope knowledge, so a blanket warning on
every `id: <identifier>` would also fire on legitimate nested non-tool
keys like `{ id: someVar }` in a payload/example object). The full set
currently taken out of the scan this way is `app-map-crawl`,
`app-map-export`, `app-map-navigate`, `app-map-query`,
`await-screen-idle`, and `await-ui-element`. A proper fix is a follow-up
covering const-ref id resolution plus a real-tree emit-count and
empty-stderr assertion so this silent-omission class trips CI if it ever
regresses.
## Verification
- `node scripts/extract-tools.mjs` -> 72 tools, `run-sequence` and
`describe` both present (total 70 -> 72), byte-identical to the
TypeScript-AST parse of the tree, no stderr warnings
- `npm run test:scripts` -> all pass (`extract-tools.test.mjs`: 36
tests)
- mutation checks: window-bounding, depth-anchor removal, trim removal,
dedup neutralization, single-quote-branch neutralization each fail the
suite
- `npm run typecheck:scripts` -> clean
- `prettier` + `eslint` on changed files -> 0 problems
- lockfile: `npm install --package-lock-only --ignore-scripts` -> no
diff (idempotent)
|
||
|
|
b90970ffa8 |
ci: ship TCP-transport iOS binaries in the published package (#487)
## Why
argent's `ios-remote` (sim-remote) support drives **ax-service** and
**native-devtools** over a TCP socket, resolving them from
`bin/darwin/tcp/ax-service` and `dylibs/tcp/*.dylib`. `bundle-tools.cjs`
already stages those into the published package **when present**, but
`download-native-binaries.sh` never fetched them — so
`@swmansion/argent` 0.15.0 shipped with no TCP variant at all, and every
`ios-remote` `describe` / `native-*` call failed with "not found".
## What
- **`download-native-binaries.sh`** — fetch the TCP dylibs tarball into
`dylibs/tcp/` and `tcp-ax-service` into `bin/darwin/tcp/ax-service`
(best-effort: skipped with a warning on pre-sim-remote release tags),
with the same Mach-O platform + codesign verification applied to the
iOS/tvOS assets.
- **`publish.yml` / `publish-next.yml`** — hard `test -x`/`test -f`
gates for the four TCP files so a missing build fails the publish loudly
instead of silently regressing (mirrors the existing tvOS gates).
- **`package.json`** — add `build:ios-binaries:tcp` and wire it into
`pack:mcp:local` so local packs match CI.
`bundle-tools.cjs` needs no change — its `ax-service (tcp)` asset entry
and recursive `dylibs/` copy already handle the `tcp/` slot.
## Verified locally
- `npm pack --dry-run -w @swmansion/argent` now lists
`bin/darwin/tcp/ax-service` +
`dylibs/tcp/{libArgentInjectionBootstrap,libKeyboardPatch,libNativeDevtoolsIos}.dylib`.
- `package-manifest.test.ts` (download↔bundle-tools path agreement) and
`native-devtools-ios/index.test.ts` (TCP path resolution) pass.
- End-to-end against a real sim-remote device: with the TCP binaries in
place, `describe` returns the full ax tree and `native-describe-screen`
/ `native-find-views` / `native-full-hierarchy` all return `status: ok`.
## Paired PR
The producer side — the workflow that builds, signs, and uploads these
TCP release assets — is **software-mansion/argent-private#26**. Both
must land for a release to ship the TCP binaries.
## Known follow-up (out of scope here)
`axServiceBinaryPathTcp()` resolves
`bin/<hostPlatformKey()>/tcp/ax-service`, and `bundle-tools.cjs` stages
the TCP ax-service **darwin-only**. So `describe` via ios-remote works
from a macOS argent host (verified), but a **Linux** host would hit "not
found" at `bin/linux/tcp/`. The TCP dylibs are fine cross-host (flat
`dylibs/tcp/`, un-gated). Full Linux-host support means staging the
darwin TCP ax-service into each host's `tcp/` dir, modeled on the
per-platform `simulator-server` loop — left as a follow-up.
|
||
|
|
c4a9f0bd8a |
ci: publish a "next" canary on every push to main (#423)
**Update after team discussion:** the open question from the original
version of this PR ("should we fire `next` on every push to main?") got
a yes, so this now does exactly that — continuous canary publishing from
`main`. Original tag-sync wiring is still here too. Branch is merged up
to current `main`.
### what it does
every push to main publishes a canary prerelease under the `next`
dist-tag, so `next` always tracks the tip of main.
- **"Publish prerelease to npm (next)"** now also triggers on `push:
branches: [main]`. on that path it derives a version, stamps it into
`packages/argent/package.json`, and publishes `--tag next`. the manual
`workflow_dispatch` path is untouched (gated behind `if:
github.event_name == 'workflow_dispatch'`).
- **version scheme** = `<patch-bump of the highest published
version>-next.<counter>`. a prerelease of the next patch still outranks
the current `latest` (so `next` lands above it) but stays under the
eventual stable. the **counter resets per base**: next index after the
highest `<base>-next.<k>` already on npm, or 0 if the base has no
canaries yet — so each patch line starts at `.0`:
```
0.13.1-next.0, 0.13.1-next.1, ... ← latest is 0.13.0
... 0.13.1 ships stable ...
0.13.2-next.0, 0.13.2-next.1, ... ← counter restarts
```
lives in `scripts/next-canary-version.mjs` (+ tests) as a pure function
of the published-versions list, reusing the semver helpers from the sync
script.
- **`argent -v` reports the right thing.** the CLI reads its version
from `package.json` at runtime, so stamping is enough — and there's an
in-pipeline step that runs the built `argent --version` and fails the
publish if it doesn't match the version about to ship. verified
end-to-end against the real registry: computed `0.13.1-next.0`, stamped,
built, `argent --version` → `0.13.1-next.0`.
- **collisions self-heal.** the counter is registry-derived, so canary
publishes are serialized (a `concurrency` group) to kill the concurrent
race; the publish step additionally retries a version-exists collision
(npm read-after-write lag on back-to-back runs) by recomputing. any
other publish failure still fails fast.
- canary builds pull the floating `argent-main` / `radon-main` signed
binaries. sync workflow still fires after every publish (self-heals
`next`, and still does the real work after a *stable* release).
### stuff to sanity-check before merge
- this publishes to npm on **every** merge to main — a lot of versions +
a full build/publish run each time. fine if that's the intent (it's the
whole point), just calling it out.
- **native binaries on the canary path are the floating `argent-main`
tag** — if radon's binary build lags a native-source change on main, a
canary can ship fresh JS against slightly-older signed
dylibs/ax-service/APK with no signal (the *missing* case fails loud +
safe; the *stale* case is silent). there's no per-commit signed-binary
build to pin against, so this is inherent to canary-from-main rather
than something this PR can fix — flagging it as the one real "preview
channel can be skewed" caveat.
- during a rapid burst of merges, GitHub's concurrency supersedes
intermediate queued runs — published `-next.N` stay contiguous from 0,
but not literally every commit in a burst gets its own canary.
- like any push trigger, it only goes live once this is on main.
|
||
|
|
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> |
||
|
|
10ecc9e53d |
fix(release): auto-sync the npm 'next' dist-tag to the highest published version (#357)
Auto-sync the npm `next` dist-tag to the highest published version (prerelease or stable) so it stops drifting behind `latest`. - New dependency-free `scripts/sync-next-dist-tag.mjs` (SemVer comparator verified against the `semver` lib in `scripts/sync-next-dist-tag.test.mjs`). - Runs as a post-publish step in `publish.yml` and `publish-next.yml` (with `continue-on-error` so a transient registry blip never fails an already-successful release), plus a manual `Sync 'next' dist-tag` workflow with a dry-run toggle. - Only ever advances `next` (never regresses it) to survive a stale post-publish packument read. - Package-name arg parsing rejects flag/blank tokens so the scoped `@swmansion/argent` default reliably wins. |
||
|
|
dc0930d50c |
ci: prevent package-lock drift + add repo-hygiene checks (#362)
## Why We hit a mismatch between a locally-generated `package-lock.json` and the one on `main`. `npm ci` validates the lockfile loosely and accepts a stale lock that a fresh `npm install` would rewrite, so the drift slipped through. This adds CI to catch that, plus a few related common-mistake guards. ## What **`Lockfile` workflow** (Node 20) — runs `npm install --package-lock-only --ignore-scripts` and fails if `package-lock.json` changes. This is the gap `npm ci` leaves: it asserts the lock is exactly what npm produces, not merely "consistent enough". **`Repo Hygiene` workflow** — three fast static guards: - **Merge-conflict markers** — fail on any `<<<<<<<` / `=======` / `>>>>>>>` left in a tracked file. - **Focused tests** — fail on `describe/it/test/bench.only` in `*.test.ts(x)` / `*.spec.ts(x)`. Uses a POSIX-ERE word-boundary pattern so it actually fires under `git grep -E` (a `\b` pattern silently matches nothing there). - **Workspace version sync** — fail when `packages/*` versions drift, via `scripts/check-workspace-versions.mjs` (also `npm run check:versions`). To make versions consistent, `@argent/ui` is bumped `0.0.1 → 0.12.0` (it is `private`, so no publish impact). ## Verification (Node 20 / npm 10.8.2, matching CI) - Lockfile check: no false positive on `main`; idempotent; catches a tampered lock. - Merge-marker & `.only` greps: proven to catch real violations and reject lookalikes (`await.only`, `audit.only`, `foo.it.only`); clean across the repo. - `check-workspace-versions.mjs`: reports all packages at `0.12.0`; passes `eslint` and `typecheck:scripts`. - All new/changed files pass `prettier --check`; both workflow YAMLs parse. ## Note: npm version coupling The check runs on Node 20 (npm 10.8.2), matching the committed lock's format. npm 11 (Node 24) regenerates the same lock minus cosmetic `"peer": true` markers — no resolution change, but a contributor who regenerates on npm 11 would trip the strict diff. The repo pins no toolchain today (CI mixes Node 20 and 24). Pinning npm/Node repo-wide would fully close this; left out of scope here — happy to add it as a follow-up. |
||
|
|
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). |
||
|
|
7d6e5fe466 |
chore(eslint): fail CI on warnings and unused disable directives (#352)
Small follow-up to #349 (which added the ESLint gate). Makes the gate strict so it can't be silently bypassed or accumulate dead suppressions: - **`reportUnusedDisableDirectives: "error"`** — a stale or unjustified `eslint-disable` is now a hard failure. (The tree had dead directives before the gate existed; #349's `--fix` removed them — this stops them creeping back.) - **`--max-warnings 0`** in the `lint` script — a future `"warn"`-level rule can't pass CI silently. Both are no-ops against the current tree (0 disable directives, 0 warnings) — pure guardrails. Verified locally: `npm run lint` (strict), `tsc --build`, and `prettier --check` all pass. |
||
|
|
acfe80ab6b |
chore: add ESLint with typescript-eslint (#349)
## What Adds type-aware linting to the workspace. Until now the only static gate on JS/TS was Prettier (formatting) and `tsc` — there was no linter, so the whole class of bugs `tsc` doesn't catch (floating promises, misused promises, throwing non-Errors, unsafe stringification, dead code) went unguarded across ~450 TS files. - **`eslint.config.mjs`** — flat config. `recommendedTypeChecked` runs on the TS sources via an explicit `project` list (each package keeps tests in a separate `tsconfig.test.json` that `projectService` can't auto-discover, so it's listed explicitly). Type-checked rules are disabled for the loosely-typed plain-JS build/dev scripts. The `argent-private` submodule and build artifacts are ignored (mirrors `.prettierignore`). - **`lint` / `lint:fix`** npm scripts. - **`.github/workflows/lint.yml`** — builds the workspace (type-aware rules need the referenced projects' declarations) then runs `eslint .`. Node 24 (ESLint 10 requires `^20.19 || ^22.13 || >=24`). ## Rule calibration This is an adoption PR, so it's deliberately calibrated rather than maximal: - **Kept on (bug-catchers):** `no-floating-promises`, `no-misused-promises` (with `checksVoidReturn: false` to drop the noisy callback variant), `only-throw-error`, `no-base-to-string`, `prefer-promise-reject-errors`, `no-unused-vars` (`_`-prefix escape hatch), plus the ESLint recommended set. - **Parked off as documented debt:** the high-volume style/`any`-family rules — `no-unsafe-*`, `require-await`, `no-unnecessary-type-assertion`, `restrict-template-expressions`, `unbound-method`, `no-explicit-any`, etc. These flag broad classes of pre-existing code and are out of scope here; each is commented as a ratchet target for follow-up passes. All findings from the kept-on rules are fixed in this PR (dead code/imports, error-cause chaining, **3 genuine floating promises**, non-Error throws, unsafe stringification). Stale unused `eslint-disable` directives left over in the tree were removed by `--fix`. ## Verification Locally, all green: `eslint .` (0 errors), `tsc --build`, `typecheck:tests`/`typecheck:scripts`, the full `vitest` suite (no behavior change from the fixes), and `prettier --check`. ## Not included (intentionally) Other static-analysis gates discussed (CodeQL, dependency-audit, ShellCheck, actionlint) are out of scope for this PR. |
||
|
|
3ccd89f333 |
feat: add native android profiling (#275)
# Android native profiling via in-process Perfetto WASM Connected with: https://github.com/software-mansion/argent-private/pull/16 ## TL;DR Adds **Android** to the native profiler (previously iOS-only) and does it with a brand-new engine: instead of shipping Perfetto's `trace_processor_shell` native binary and forking it per query, we now run **Perfetto's trace-processor compiled to WebAssembly, in-process** inside the tool-server. - **One ~13 MB `trace_processor.wasm`** runs on every OS/arch — no per-platform binary, no subprocess, fully offline. - The native profiler is refactored from an iOS-only implementation into a **platform-dispatch facade** (`platforms/ios.ts` + `platforms/android.ts`) over a new **`profiler-shared/`** layer, so iOS and Android share the aggregator, types, lifecycle, and time-alignment code. - New **release/pack pipeline** fetches + sha256-verifies the WASM bundle from `argent-private-releases`, and bundles it (plus SQL queries and the Perfetto TraceConfig) into the published `@swmansion/argent` package. End-to-end on a 76 MB trace with 1013 jank rows: **6.3 s** total analyze (the older per-hang-subprocess approach was projected at ~47 minutes and never finished within the tool-call deadline). --- ## TESTING MANUALLY To test manually run the following packing command checked-out on this branch: ``` npm run pack:mcp -- argent-@pFornagiel-native-android-devtools-perfetto ``` This will bundle the package with the new binaries. After this PR is fixed and the binaries are resolved from the main release, the `argent-@pFornagiel-native-android-devtools-perfetto` release can be deleted. ## Why Android needed native CPU/hang/memory profiling to reach parity with iOS. The natural engine is Perfetto's trace-processor, but the obvious ways to ship it are both bad: - **`trace_processor_shell` binary** — per-platform (a mac-arm64 pack shipped a mac-arm64-only tarball), pinned an OS/arch matrix, and cost a fresh ~1.3 s subprocess fork **per query**. With one subprocess forked per detected hang, a large trace projected to ~47 minutes. - **`get.perfetto.dev/trace_processor` Python launcher** — adds a runtime Python 3 dependency, resolves "latest" at first run (defeats version pinning), and makes the first analyze slow via a network fetch. The WASM engine is one cross-platform artifact, in-process and warm-cached: the trace is parsed **once** and reused across the whole analyze run plus every drill-down query. --- ## The three big pieces ### 1. In-process Perfetto WASM engine New package surface in `@argent/native-devtools-android`: | File | Role | | --- | --- | | `src/wasm-trace-processor.ts` (+476) | The whole engine: boot, glue patching, warm-cache, fault containment, chunked parse, cell decoding | | `src/perfetto-engine.d.ts` (+49) | Hand-written types for the version-agnostic RPC decoder (imported by path, so tsc can't see its own `.d.ts`) | | `src/errors.ts` (+68) | `TraceProcessorUnavailableError` (`wasm_load_failed` / `wasm_path_invalid`) | | `src/bundled-meta.ts` (+12) | `PERFETTO_VERSION` stamp, regenerated at pack time | | `src/index.ts` | Re-exports + package-root accessors (`traceProcessorQueriesDir`, `traceConfigPath`) | Public surface: `resolveTraceProcessorAssets()`, `queryWarm<Row>(tracePath, sql)`, `ensureTraceProcessorReady(tracePath)`, `disposeWarmEngine(tracePath)`. Highlights of how it works: - **Boots Google's prebuilt web/worker wasm under Node.** Installs a minimal worker scope (`self`, `WorkerGlobalScope`, `location`), reads the wasm bytes, patches the Emscripten glue (`useMemory64=false`, hand the bytes in directly, expose the bridge), and drives it over a `MessageChannel` + `EngineBase` subclass. Glue patches are applied **by unique string anchors that throw if they don't match** — the canary for glue-format drift on a Perfetto bump. - **Warm-engine cache, one per trace path.** LRU with `MAX_WARM_ENGINES = 3` (bounds resident memory at ~26–76 MB trace + wasm heap each), 5-min idle dispose (timer `unref()`'d), no failed-promise caching. - **Fault containment (`fatal` promise).** `EngineBase.fail()` throws synchronously inside the `MessagePort.onmessage` handler (e.g. an RPC framing error); left unhandled it becomes a Node `uncaughtException` and would **kill the entire tool-server**, wiping every device + profiler session. Each engine exposes a `fatal: Promise<never>`; the handler try/catches, rejects `fatal`, evicts the engine, and every load/query is `Promise.race`'d against it — so a contained fault is a clean rejection and the server stays up. - **Chunked trace parse.** Perfetto's RPC ring buffer rejects any frame > 64 MiB, so the trace is fed in 32 MiB chunks before `notifyEof()`. ### 2. Android native profiler + the shared/dispatch refactor **Capture** (`utils/android-profiler/capture.ts`, `detect-app.ts`): spawns `adb shell perfetto --txt -c - --background-wait -o /data/.../argent-<ts>.pftrace`, piping the TraceConfig on **stdin** (SELinux denies `shell:s0` writes under `/data/misc/perfetto-traces/`, so the config can't be staged as a file), waits for the PID on stdout, then on stop sends `kill -TERM`, polls `/proc/<pid>`, and `adb pull`s the trace. **Pipeline** (`utils/android-profiler/pipeline/`): PerfettoSQL does the parsing and aggregation, so the Android pipeline is intentionally **two files, not iOS's four**. The per-hang annotation pass is **batched** — `runBatchedHangFolds` inlines all hang windows as a `VALUES` table into one SQL script (two derived views unioned in a single terminal SELECT, because the engine returns only the final statement's rows) and runs it once against the warm engine. **The platform-dispatch refactor** — `native-profiler-start/stop/analyze` shrank from monolithic iOS files (~160–330 lines each) into **thin routers** (~60–110 lines) that branch on `api.platform`: ``` native-profiler-start ─┬─ ios? → platforms/ios.ts (xctrace) └─ android → platforms/android.ts (adb perfetto) ``` A new **`utils/profiler-shared/`** layer holds everything both backends use: | File | What was hoisted | | --- | --- | | `types.ts` | Unified `Bottleneck = CpuHotspot \| UiHang \| MemoryLeak \| MemoryRssGrowth`, each now carrying a `platform` field; shared `NativeProfilerAnalyzeResult`; `RECORDING_CAP_MS` | | `aggregate.ts` | Generic `aggregateCpuHotspots(AggregatorInputRow[])` — burst windowing (`BURST_GAP_MS=500`), severity banding (RED >15%, YELLOW 3–15%, <3% dropped). iOS feeds it via a pre-pass; Android feeds it precomputed SQL rows | | `lifecycle.ts` | `shutdownChild` SIGINT→SIGTERM→SIGKILL ladder + `waitForChildExit` (no PID-reuse hazard) | | `thread.ts` | `normalizeThreadName` for both xctrace and Perfetto thread names | | `time-align.ts` | New `buildPerfettoAnchor()` + `windowsOverlap()` alongside the existing iOS/React anchors | | `format.ts` | `formatBytes` (moved out of the combined report) | iOS was refactored to fit this shape: `ios-profiler/lifecycle.ts` and `types.ts` become thin re-exports; `pipeline/02-aggregate.ts` shrank from ~200 to ~60 lines (keeps its iOS-only dominant-function pre-pass, delegates grouping/bursting/ severity to the shared aggregator). **No iOS behavior change** — same outputs, shared internals. **Session blueprint** (`native-profiler-session.ts`): generic `capturePid` / `captureProcess` (was `xctracePid` / `xctraceProcess`), new `platform` and `androidOnDeviceTracePath` fields, and **platform-branched dispose** (iOS SIGKILLs xctrace; Android `kill -KILL`s perfetto, `rm`s the device trace, and disposes the warm WASM engine). **Drill-down tools**: `profiler-load.ts` learns to restore Android `.pftrace` sessions (with an optional metadata sidecar / `app_process` override); `profiler-stack-query.ts` splits into iOS and Android branches. Unlike iOS (which caches `parsedData` in memory), Android **re-queries the `.pftrace`** per drill-down — the warm engine is the cache, so each query costs only SQL execution time. ### 3. Packaging & release pipeline The WASM bundle's three third-party artifacts (`trace_processor.wasm`, `engine_bundle.node.js`, `engine.mjs`) + `LICENSE` are **never committed** (`.gitignore` lists the generated files but not the dir). They're built and sha256-checksummed in `argent-private` CI, published to `argent-private-releases`, and on our side: - **`scripts/download-trace-processor.sh`** (+88, new) — `gh release download` → verify tarball sha256 (**FATAL on mismatch** — the blobs are unsigned) → extract → re-verify via `SHA256SUMS` → assert all four present. - **`scripts/pack-mcp.cjs`** (+60, new) — single pack entry point: downloads simulator-server, native binaries, **and** the trace-processor bundle, then builds and `npm pack`s `@swmansion/argent`. `package.json`'s `pack` / `pack:mcp` now call this script. - **`packages/argent/scripts/bundle-tools.cjs`** (heavily reworked, +574/-...) — copies `assets/trace-processor/`, `assets/queries/`, and `argent.tracecfg.pbtxt` into `packages/argent/assets/`, and regenerates `bundled-meta.ts` to stamp the Perfetto version. - **`publish.yml` / `publish-next.yml`** — run the download step and then **verify**: all four WASM files present, the wasm magic-byte check (`head -c4 … | grep $'\x00asm'`), plus the queries dir, TraceConfig, manifest, and Android helper APK. Asset reorg: `native-devtools-android` now ships `dist/`, `bin/`, and `assets/` (SQL queries, TraceConfig, manifest moved under `assets/`); `.gitignore` swaps the old per-file `packages/argent/manifest.json` entry for the whole `packages/argent/assets/` dir. --- ## Testing 15 new test files under `packages/tool-server/test/android-perfetto/` cover the engine and pipeline, including: - `dispatch.test.ts` — start/stop/analyze route to the right platform backend. - `aggregate-shared.test.ts` — the shared aggregator on both iOS and Android-shaped input. - `hang-folds-batched.test.ts` / `hang-fold.test.ts` — the batched per-hang SQL fold. - `hang-severity.test.ts` — jank-reason → RED/YELLOW classification. - `dispose.test.ts` / `dispose-warm-engine.test.ts` — session dispose kills the daemon, rms the device trace, and tears down the warm engine. - `stop-recovery.test.ts` — `profilingActive` is forced false even if `adb pull` fails (so a retry-start doesn't wedge). - `run-tp.test.ts` — `renderSqlTemplate` token rendering + the "unused substitution" guard. - `manifest-hint.test.ts` — zero-callstack detection emits the manifest hint. - `profiler-load.test.ts` — `.pftrace` session restore with/without the metadata sidecar. Plus `native-profiler-analyze-failure.test.ts` for the engine-unavailable banner, and updated iOS tests for the shared-lifecycle refactor. `@argent/native-devtools-android` gains its own vitest setup (`vitest.config.ts`, `tsconfig.test.json`, `test/errors.test.ts`). --- ## Notes & follow-ups - **Manifest requirement.** Perfetto's `linux.perf` data source needs `/proc/<pid>/mem` access, granted only to a **debuggable** or `<profileable android:shell="true"/>` app. A release build without either silently produces zero callstacks; the pipeline detects this and emits a **manifest hint** instead of an "All clear" report. - **Version pinning lives in the `argent-private` submodule** (`PERFETTO_VERSION` / `PERFETTO_WASM_TAG` / `LYNX_TRACE_PROCESSOR_VERSION`). Bumping is documented in `argent-private/docs/ANDROID_PERFETTO.md`. JS↔engine version skew is structurally impossible (version-agnostic decoder + vendored wasm). - **`disposeWarmEngine` is exported but not wired into session-stop** — warm engines are reclaimed only by the idle timer + LRU cap. Acceptable today (bounded memory); wire it into session dispose if explicit teardown is ever needed. - **Submodule bump.** This PR moves `packages/argent-private` to `22e55f90` — see the companion `argent-private` PR description, including its merge-hygiene note (that branch should pick up latest `argent-private` main before the pointer is finalized). ### Companion docs added in this branch - `utils/android-profiler/ANDROID_PROFILER_REFERENCE.md` — stack, capture, queries, manifest requirement. - `utils/android-profiler/PIPELINE_DESIGN.md` — the "why" (two-file pipeline, shared-aggregator hoist, re-query-don't-cache, batched fold). --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
a96f1f1578 |
feat: refactor android describe to not rely on uiautomator (#237)
## Summary - `formatDescribeTree` was branching on `source === "uiautomator"` to pick nested rendering; the newer `android-devtools` source fell through to flat mode and lost every node below depth 1. Extends the predicate to cover both Android sources so the helper-service path renders with the same hierarchy as the legacy `uiautomator dump` path. - Bumps `packages/argent-private` to pick up the persistent Android describe service that emits `source: "android-devtools"`, plus its build-and-sign CI workflow. - Wires the Android helper APK + `manifest.json` into the published `@swmansion/argent` package via `bundle-tools.cjs`, and adds `pack:mcp:local` / `build:android-binaries` so a local tarball can be produced without going through `download:native-binaries`. - Minor: tightens a couple of comments in `android-helper-install.ts` and `format-tree.ts`. This is connected to argent-private PR: https://github.com/software-mansion/argent-private/pull/8 |
||
|
|
2180dd8e6a |
ci: typecheck test files in CI (#202)
We've had lots of type errors in our tests, scripts and other non-core
code despite all CI being green. This PR fixes that.
This PR also removes some redundant features like `@ts-check` inline
directives which have been replaced by proper ts config files.
<details>
## AI Summary
Audit of every CI workflow against every package's `package.json` and
`tsconfig` surfaced several gaps where CI did partial coverage. This PR
closes them and fixes every pre-existing type error the new gates
surfaced.
## Gaps closed
| # | Gap | Fix |
|---|---|---|
| 1 | `tsc --build` only covers `src/**`; test files (`test/**`,
`tests/**`) never typecheck. Vitest transforms tests with esbuild —
strips types instead of checking them. | New `tsconfig.test.json` per
test-bearing package (`composite: false`, `noEmit`, `rootDir: "."`,
includes `src/**` + `test/**` (or `tests/**`) + `vitest.config.ts`). New
`typecheck:tests` npm script per package. New CI step `npm run
typecheck:tests --workspaces --if-present`. |
| 2 | Build/publish scripts (`scripts/*.{cjs,mjs}`,
`packages/argent/scripts/*.cjs`, `packages/skills/scripts/install.js`) —
JS, never typechecked. `sync-readme.cjs` runs in `prepack`;
`postinstall.cjs` runs on every install; `bundle-tools.cjs` is
build-critical. A typo only surfaces at runtime. | Root
`tsconfig.scripts.json` with `allowJs` + `checkJs` + `noImplicitReturns`
covers all script paths. Root `typecheck:scripts` npm script. New CI
step. Per-file `// @ts-check` comments removed — tsconfig drives
inclusion. |
| 3 | `argent-cli` had no `typecheck:tests` script. When tests get added
there they'd silently bypass the gate. | Added `tsconfig.test.json` +
`typecheck:tests` script. `--if-present` would have skipped it anyway,
so this is future-proofing. |
| 4 | Local `prettier --check .` walked into the `argent-private`
submodule and reported violations there. CI didn't see this because
`actions/checkout@v4` doesn't init submodules — so local `prettier
--check` did not match CI behavior. | New `.prettierignore` excludes the
submodule plus `dist/`, `node_modules/`, lock files, `tsbuildinfo`.
No-op in CI; aligns local with remote. |
## Test type errors fixed
These were already present. The `npm test` passed because esbuild
stripped the offending types:
- **argent-installer**: widen `scope` literal type for
dead-code-elimination guard; non-null `addAllowlist!`/`removeAllowlist!`
(optional methods on adapter).
- **argent-mcp**: add `.js` extensions for NodeNext module resolution.
- **registry**: broaden `StaticBlueprintResult` blueprint api from `{
id; deps? }` to `Record<string, unknown>` so existing tests can pass
arbitrary api shapes.
- **tool-server**:
- non-null `zodSchema!` on tool defs that always carry one
(`launchAppTool`, `restartAppTool`, etc.)
- cast sentinel `"ignored"` strings to `DeviceInfo` in factory-rejection
tests
- match the 4-arg `dispatchByPlatform<IosServices, AndroidServices,
Params, Result>` signature (tests still passed the old 3-arg shape)
- `assertFlowRunResult` type guard for the `FlowRunResult |
FlowPrerequisiteNotice` union before `.steps` access
- swap broken `typeof import("supertest").default` for static `import
supertest` (supertest is `export = supertest`)
- fill in the 4 fields missing from a `NativeProfilerSessionApi` mock
(`xctraceProcess`, `recordingTimedOut`, `recordingExitedUnexpectedly`,
`lastExitInfo`)
- cast a vitest `Mock` to a plain function at one direct call site where
the `Procedure | Constructable` union loses callability
- fix `update-checker.test.ts` reading `../../package.json` (off-by-one
— went past tool-server; was relying on a Vite resolver quirk)
- replace one cross-package `../../../registry/src/index` import with
`@argent/registry` so registry's private `services` field isn't compared
between src and dist declarations
All fixes are type-level. Full `npm test --workspaces --if-present`
still reports **991 passed across 87 test files**.
</details>
|
||
|
|
fbe7b087e7 |
chore(deps): batch-apply Dependabot updates (#214–#227) (#228)
This PR consolidates every open Dependabot PR that requires **no source-code changes** into a single branch with one regenerated, coherent lockfile. | PR(s) | Update | Status | |---|---|---| | #214 | GitHub Actions group — checkout@v6, setup-node@v6, setup-python@v6, github-script@v9, upload-artifact@v7 | ✅ Applied | | #215 | prettier 3.8.3, @clack/prompts 1.4.0, semver 7.8.0, yaml 2.9.0, @modelcontextprotocol/sdk 1.29.0, esbuild 0.28.0 | ✅ Applied | | #216 / #221 / #224 / #227 | typescript 6.0.3 | ✅ Applied | | #217 / #222 / #223 | @types/node 25.9.0 | ✅ Applied | | #220 / #226 | vitest 4.1.6 | ✅ Applied | | #218 / #225 | zod 4 | ⏸️ Excluded — requires code migration | | #219 | express 5 | ⏸️ Excluded — requires code migration | | #215 (partial) | tree-sitter 0.25.0 | ⏸️ Excluded — see below | **tree-sitter 0.25.0** ships no prebuilt binaries and its `binding.gyp` hard-codes `-std=c++17`, which fails to compile against Node 20+/24 C++20 `cppgc` headers — a hard `npm install` blocker (would also break CI). Kept at `^0.21.1`; all other #215 updates applied. zod 4 and express 5 are excluded here because they require real source changes; tracked separately. Verified: `tsc --build` clean, esbuild bundles, **1010 unit tests pass**, **zero source files modified**. |
||
|
|
0dca6bbfef |
fix: build workspace deps before packing/publishing argent (#172)
## Summary - The `publish` and `publish-next` workflows ran `npm run build -w @swmansion/argent` directly, but after the recent CLI/MCP/main split, `@swmansion/argent` imports types from `@argent/cli`, `@argent/mcp`, `@argent/installer`, `@argent/tools-client`. Those packages expose types from their own `dist/index.d.ts`, which doesn't exist until they're built — so argent's `tsc` failed with `TS2307: Cannot find module '@argent/...'` (e.g. [run 25161244218](https://github.com/software-mansion/argent/actions/runs/25161244218)). - Added `npx tsc --build` before the per-workspace argent build in both publish workflows so the sibling packages produce their `dist/` first. This mirrors what `unit-tests.yml` already does, which is why the regression didn't surface on PRs. - Applied the same fix to the root `pack` script (`npm run pack`) since it had the same latent bug for local packing. ## Test plan - [x] Reproduced the failure locally by wiping every `dist/` and `tsconfig.tsbuildinfo`, then running `npm run build -w @swmansion/argent` — same four `TS2307` errors as CI. - [x] Verified `npx tsc --build && npm run build -w @swmansion/argent` succeeds from a clean state. - [ ] Re-run the `Publish prerelease to npm (next)` workflow against this branch (or after merge) to confirm green. |
||
|
|
6355620c4d |
refactor(mcp): split mcp package into argent, argent-cli, argent-installer, argent-mcp, argent-tools-client (#162)
## Summary - Splits the monolithic `packages/mcp` package into five focused packages: - `argent` — the user-facing CLI entry (`argent` binary, init/uninstall/update flows, bundled-paths, scripts). - `argent-cli` — CLI runner internals (flag-parser, run, server, tools). - `argent-installer` — `init`/`update`/`uninstall` flows, MCP config adapters, skills installer. - `argent-mcp` — MCP server itself (mcp-server, tool-mapping, auto-screenshot, content adapters). - `argent-tools-client` — HTTP client + launcher for the tool-server. - Adds Gemini agent definitions, VSCode MCP config, and per-package `tsconfig.json` / `vitest.config.ts`. - Updates root `tsconfig.json`, `scripts/dev.cjs`, CI workflows, and `package.json` to wire the new packages together. ## Test plan - [ ] `npm install` resolves the new workspaces cleanly - [ ] `npm run build` succeeds across all packages - [ ] `npm test` passes (renamed test files keep their assertions) - [ ] `npx argent init` still produces the expected MCP config in a sample project - [ ] `npx argent update` / `argent uninstall` exercise the installer package - [ ] CI workflows (`publish.yml`, `unit-tests.yml`) run on this branch |
||
|
|
09eadbbfd8 | fix: download:native-binaries should not derive version locally (#126) | ||
|
|
7db8305fff |
feat: pin native binaries to versioned release tags and publish to npm (#125)
- download-native-binaries.sh now requires an explicit release tag (e.g.
argent-v0.4.3) and fails fast with a clear error if the release doesn't
exist in argent-private-releases
- publish.yml is now manual-only (workflow_dispatch) with a ref input
(branch/tag/SHA); derives the binaries tag as argent-{ref} and checks
out the repo at that ref
- publish.yml now targets npm (registry.npmjs.org + NPM_TOKEN) instead
of GitHub Packages
- download:native-binaries npm script auto-derives the tag from
packages/mcp/package.json version for local pack:mcp usage
|
||
|
|
bad7049f87 | feat: add download:native-binaries script and include it in pack:mcp (#124) | ||
|
|
d082ea2fd2 | feat: download simulator server | ||
|
|
4e514c1435 | chore: rename package from @software-mansion/argent to @swmansion/argent | ||
|
|
8c2a313c76 |
chore: format codebase with Prettier
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
47b66b3eed |
feat: add native devtools iOS — view hierarchy, network inspection, passive simulator watcher
- Adds native-devtools-ios package with pre-built dylibs (libNativeDevtoolsIos, libKeyboardPatch, libInjectionBootstrap) - Passive simulator watcher injects dylibs into all booted simulators on tool-server startup, eliminating manual restart requirement - Lazy network activation: NSURLProtocol interception is opt-in per bundleId via Control socket command, re-activated on reconnect - New tools: native-find-views, native-full-hierarchy, native-network-logs, native-devtools-status - dev script: non-fatal argent-private submodule (uses pre-built dylibs when source unavailable) - Adds Prettier config and format script - Updates CONTRIBUTING.md with npm run dev workflow and project structure Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
2ba7ab6bba |
feat: add dev mode script for local development without packing (#72)
Adds `npm run dev` which: - Builds MCP TypeScript (tsc only, skips esbuild tool-server bundle) - Copies simulator-server binary and skills/rules/agents into mcp package - Patches ~/.claude.json to point argent MCP at the local dist/cli.js - Starts tool-server from source via ts-node, writes ~/.argent/tool-server.json - On exit: restores ~/.claude.json and stops the tool-server |
||
|
|
da707875b1 |
feat: deprecate UI package (#45)
* feat: delete ui package * feat: delete left tsconfig.buildinfo |
||
|
|
77dd289d78 |
feat: replace auto-postinstall with npx @software-mansion/argent install (#41)
* feat: add first implememntation of environment subagent * chore: remove the irrelavnt skill from main project config * feat: add rules support and enhance postinstall script for Argent tools (#23) * feat: add first implememntation of environment subagent * feat: enhance argent.md with environment inspection subagent details and workspace information retrieval guidelines * feat: introduce argent.md with comprehensive guidelines for iOS simulator interactions and React Native workflows * fix: fix postinstall script * fix: fix Install Argent launch.json job * feat: add environment inspector design document and research notes on MCP error signaling * chore: update .gitignore to include MCP agents and rules directories * fix: update `argent.md` rule with alwaysApply: true for cursor compatibility * chore: remove mcp/rules from index * feat: add basic npx flow * feat: cicd for releasing the package as nmp through github * fix: update package name references from @software-mansion-labs to @software-mansion in documentation and configuration files * refactor: simplify postinstall script for @software-mansion/argent and update configuration instructions |
||
|
|
c86378e6c4 | feat: change radon-lite references to argent | ||
|
|
99076bb1ed | Merge branch 'main' into @Filip131311/packageTheToolForDistribution | ||
|
|
576ef03a1f | init | ||
|
|
2578e9def8 | feat: update docs, package.json, etc. | ||
|
|
dc3d4ec000 | feat: rename tools package to tool-server, minor functionalities renamings | ||
|
|
5820a9b898 | feat: add metro tools | ||
|
|
b862a93dcf |
Remove packages/server in favour of packages/tools
The tools server (port 3001) supersedes the original Express server. packages/tools and packages/ui have no imports from packages/server, and the vscode extension never used the dependency either. - Delete packages/server/ (src, tests, openapi spec, duplicate binary) - Remove build:server, start, dev scripts from root package.json - Remove packages/server reference from root tsconfig.json - Remove @radon-lite/server dependency from packages/vscode/package.json Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
757ffb03bc |
Restructure into npm workspaces monorepo
Move server code to packages/server/, add placeholder packages for packages/ui and packages/vscode. Add tsconfig.base.json with shared compiler options and root tsconfig.json with project references. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
e428281b06 |
Add iOS simulator control server (radon-lite)
Express/TypeScript HTTP server that wraps the simulator-server binary to expose a clean REST API for controlling iOS simulators. Supports session management, MJPEG screen streaming, screenshots, screen recording, replay ring buffer, full input control (touch/key/button/rotate/paste/scroll), JWT token management with Radon portal activation, and SSE event streams. Configurable replay and showTouches features via CLI args or env vars. |