Skip to content

Consume Claude ACP as a pinned npm runtime dependency - #451

Merged
jsgrrchg merged 9 commits into
mainfrom
zeron/convertir-claude-acp-a-dependencia
Sep 13, 2026
Merged

jsgrrchg merged 9 commits into
mainfrom
zeron/convertir-claude-acp-a-dependencia

Conversation

@jsgrrchg

@jsgrrchg jsgrrchg commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Problem

Desktop development and release packaging currently depend on a committed snapshot of @agentclientprotocol/claude-agent-acp, including upstream source, generated dist, tests, configuration, and a separate lockfile. This keeps release inputs reproducible, but it also commits more than 111,000 lines of third-party code and makes upstream updates a manual source-vendor refresh.

This PR replaces that snapshot with an isolated, lockfile-pinned npm runtime while preserving the runtime layout and NeverWrite behavior expected by the native backend and packaged app.

Resulting behavior

  • Pin @agentclientprotocol/claude-agent-acp exactly to 0.76.0 in apps/desktop/runtimes/claude/.
  • Keep its production dependency graph and integrity metadata isolated from the desktop application lockfile.
  • Generate .cache/claude-runtime/<rust-target>/ through one preparer shared by local development and release staging.
  • Continue packaging an autonomous runtime at native-backend/embedded/claude-agent-acp alongside the embedded Node runtime.
  • Preserve the existing executable override precedence and the serialized local runtime source value used by saved UI state.
  • Validate explicit NEVERWRITE_CLAUDE_EMBEDDED_DIR and apps/desktop/embedded/claude-agent-acp inputs as complete prepared runtimes instead of modifying those directories during staging.
  • Remove vendor/Claude-agent-acp-upstream/ and update architecture, licensing, runtime setup, CI, packaging, and upstream-watch documentation.

The migration commits preserve behavior first, and the final dependency-promotion commit updates Claude ACP from 0.75.1 to the stable 0.76.0 release tracked by #442. The release adds capability-gated recommended model/effort metadata and updates the locked fast-uri transitive dependency from 3.1.6 to 3.1.7. NeverWrite does not advertise the AIR recommendedValue capability, so its selected configuration remains unchanged. Native Claude resume, persisted runtime identity, and Claude subagent/steering extensions remain unchanged.

Closes #442.

Runtime preparation

The new preparer performs an immutable, target-aware installation:

  1. Hashes the runtime manifest, lockfile, baseline, patch, preparer, architecture validator, and requested target to form the cache identity.
  2. Runs a clean production-only npm install with optional dependencies included and package lifecycle scripts disabled.
  3. For cross-target builds, downloads the exact platform package URL recorded in the lockfile, verifies its SHA-512 integrity, and extracts it into the temporary installation.
  4. Applies the local Claude ACP patch explicitly and verifies the published input and patched output with SHA-256 checksums.
  5. Materializes the complete dependency tree under the runtime, removes unrelated host native packages, validates production versions and native executable architecture, and atomically publishes the cache generation.

The target matrix covers Linux x64/ARM64, Windows x64/ARM64, macOS x64/ARM64, and macOS universal. A lock directory prevents concurrent writers from publishing partial generations.

Preserved TaskList hardening

The npm 0.76.0 release still uses an ambiguous regex in the textual TaskList fallback. NeverWrite previously carried a source-level fix that replaces it with linear string parsing. Dropping the vendor without carrying this delta forward would restore the potential excessive-backtracking/CPU-stall behavior reported in:

This PR preserves that fix as a narrowly scoped patch to the published dist/tools.js. The preparer refuses to apply it unless both the package version and original file checksum match the expected 0.76.0 release, and refuses to publish the runtime unless the patched checksum and compatibility baseline match.

The regression contracts exercise the installed runtime parser itself, including structured JSON, textual task lists, owners, dependency lists, empty output, malformed suffixes, and adversarial oversized input. They import the runtime from an isolated temporary copy, and the adversarial case runs in a child process with a parent-enforced timeout so a synchronous parser stall cannot hang CI indefinitely.

The patch should be removed only after an upstream release includes an equivalent fix and these contracts pass against the unmodified published artifact.

Runtime and package validation

The new real-runtime smoke starts the published adapter and its native Claude CLI against a deterministic local Anthropic-compatible server. It uses a temporary profile and workspace with synthetic credentials and verifies:

  • adapter --version;
  • delegated native CLI --cli --version;
  • ACP initialize and session/new;
  • a real native Read tool call against a fixture file;
  • the tool result reaching the local API server;
  • completed ACP tool activity and the final assistant response;
  • cancellation of a pending inference request; and
  • cleanup of the adapter and native subprocess tree.

The packaged-sidecar smoke runs this against the embedded runtime and embedded Node. The package workflow also runs the real runtime natively on Linux and Windows x64/ARM64 and both macOS architectures. The Intel macOS job downloads the universal runtime created by the ARM packaging job and exercises its other Node slice.

Electron's after-pack validation now checks the full patched JavaScript baseline, production package versions, and required native Claude CLI architectures in addition to checking that required files exist.

Compatibility retained

  • Runtime ID claude-acp, persisted history, configuration, queue behavior, model/effort/mode mapping, authentication probes, and provider routing remain unchanged.
  • Form and URL elicitation remain enabled; native subagent sessions, AIR async tasks, legacy subagent transcripts, steering, and native Claude resume remain disabled.
  • Runtime titles continue to be consumed while manual NeverWrite renames remain authoritative.
  • NeverWrite filesystem/diff tracking remains authoritative for inline review and file/hunk accept/reject flows.
  • Provider routing remains applied before session creation, retaining the upstream settings-tier enforcement against competing project/user Claude settings.
  • Claude ACP 0.76.0 advertises support for recommended configuration values, but only emits them when the client opts in; NeverWrite does not opt in and retains the legacy model/effort option contract.

Commits

  1. test(claude): capture runtime compatibility baseline
  2. build(claude): prepare a locked npm runtime with the TaskList patch
  3. refactor(claude): use the prepared dependency in development and releases
  4. test(claude): exercise the packaged runtime across release targets
  5. chore(claude): remove vendored sources and track the npm runtime
  6. docs(claude): align runtime dependency documentation
  7. fix(claude): normalize patch line endings on Windows
  8. ci(release): prepare Claude runtime before packaging
  9. chore(claude): upgrade runtime dependency to 0.76.0

Validation performed locally

  • cargo test --locked -p neverwrite-native-backend — 372 passed.
  • npm test — 2,606 passed, 2 existing TODOs.
  • npm run lint — passed.
  • npm run electron:build — passed; existing large-chunk warnings remain.
  • npm run electron:ai-runtime:smoke — passed after removing the vendor.
  • npm run test:claude-preparation — 8 passed against the 0.76.0 manifest, lockfile, patch, and watcher.
  • npm run test:claude-runtime — 2 passed against the generated isolated runtime.
  • Electron Builder configuration/resource tests — 8 passed.
  • npm run claude:smoke — passed on 0.76.0 with the host Node; the earlier migration validation also passed with the official Node 22.23.1 distribution used by packaging.
  • Forced clean preparation without the vendor — passed.
  • Target preparation and native executable architecture validation from Linux — passed for Linux x64/ARM64, Windows x64/ARM64, and macOS universal.
  • GitHub workflow YAML parsing and final operational-reference search — passed.
  • Runtime-only npm audit --omit=dev — zero known vulnerabilities after locking fast-uri 3.1.7.

The cross-platform native execution and full packaged application jobs are configured in CI and have not yet run on this branch. No real Claude account login or paid external service was used during local validation.

Update and rollback notes

Future Claude ACP releases remain deliberate version promotions: update the exact dependency and isolated lockfile, compare the production graph and runtime baseline, decide whether the TaskList patch is still needed, and rerun the contracts and packaged smoke matrix. Patch input discovery now follows the exact manifest version, avoiding a second hard-coded version in the preparer. The upstream watcher now reads this exact dependency pin and reports newer stable tags.

Rollback should revert the dependency manifest/lockfile, patch, preparer, resolver, packaging, workflow, documentation, and vendor removal as one unit. This change introduces no persisted-data migration.

@jsgrrchg jsgrrchg linked an issue Sep 12, 2026 that may be closed by this pull request
@jsgrrchg
jsgrrchg merged commit 8924acd into main Sep 13, 2026
21 checks passed
@jsgrrchg
jsgrrchg deleted the zeron/convertir-claude-acp-a-dependencia branch September 13, 2026 02:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Upstream claude-agent-acp released v0.76.0

1 participant