From 09886269e28db7c2c40566c1de737943d2fba8e1 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 6 Sep 2026 09:48:22 +0000 Subject: [PATCH 1/3] fix dev host teardown environment --- packages/agent-bundle/src/dev/host-install-manager.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agent-bundle/src/dev/host-install-manager.ts b/packages/agent-bundle/src/dev/host-install-manager.ts index 5c2731660..dd45116a2 100644 --- a/packages/agent-bundle/src/dev/host-install-manager.ts +++ b/packages/agent-bundle/src/dev/host-install-manager.ts @@ -346,7 +346,7 @@ export class DevHostInstallManager { constructor(options: DevHostInstallManagerOptions) { this.#adoption = options.adoption; this.#epochStore = options.epochStore; - this.#environment = options.environment ?? process.env; + this.#environment = Object.freeze({ ...(options.environment ?? process.env) }); this.#eventHub = options.eventHub; this.#home = options.home; this.#hosts = Object.freeze([...new Set(options.hosts)]); From 8b70eb3b03d0d5a586d3db97204f513916301847 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 6 Sep 2026 09:49:38 +0000 Subject: [PATCH 2/3] document dev cleanup environment fix --- .changeset/snapshot-dev-host-environment.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/snapshot-dev-host-environment.md diff --git a/.changeset/snapshot-dev-host-environment.md b/.changeset/snapshot-dev-host-environment.md new file mode 100644 index 000000000..3a19bdf0a --- /dev/null +++ b/.changeset/snapshot-dev-host-environment.md @@ -0,0 +1,5 @@ +--- +"agent-bundle": patch +--- + +Keep development host cleanup bound to the environment used when the host was installed. (#678) From 957df36e61648dc991302901693ab13363c126c4 Mon Sep 17 00:00:00 2001 From: ScriptedAlchemy Date: Sun, 6 Sep 2026 09:56:36 +0000 Subject: [PATCH 3/3] preserve host environment during cleanup --- .../src/dev/host-install-manager.ts | 19 +++++++++++++++++-- packages/agent-bundle/src/install/install.ts | 9 ++++++--- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/agent-bundle/src/dev/host-install-manager.ts b/packages/agent-bundle/src/dev/host-install-manager.ts index dd45116a2..550dac1d3 100644 --- a/packages/agent-bundle/src/dev/host-install-manager.ts +++ b/packages/agent-bundle/src/dev/host-install-manager.ts @@ -21,8 +21,10 @@ import { platformRunOf } from './platform-run.ts'; import type { DevPlatformRuntime } from './platform-runtime.ts'; import type { Diagnostic } from '../core/diagnostics.ts'; import { + defaultCommandRunner, installBundle as defaultInstallBundle, type InstallBundleOptions, + type InstallCommandRunner, type InstallHost, type InstallResult, } from '../install/install.ts'; @@ -329,6 +331,7 @@ const syncDiagnostic = (host: InstallHost, epochId: string, error: unknown): Dia /** Owns opt-in host development installs for one foreground dev session. */ export class DevHostInstallManager { readonly #adoption: EpochAdoptionSource | undefined; + readonly #commandRunner: InstallCommandRunner; readonly #epochStore: EpochReferenceSource; readonly #environment: Readonly; readonly #eventHub: ProjectEventHub; @@ -345,10 +348,20 @@ export class DevHostInstallManager { constructor(options: DevHostInstallManagerOptions) { this.#adoption = options.adoption; - this.#epochStore = options.epochStore; this.#environment = Object.freeze({ ...(options.environment ?? process.env) }); + this.#commandRunner = Object.freeze({ + run: ( + command: string, + args: readonly string[], + commandOptions: { readonly cwd: string; readonly environment?: Readonly }, + ) => defaultCommandRunner.run(command, args, { + ...commandOptions, + environment: this.#environment, + }), + }); + this.#epochStore = options.epochStore; this.#eventHub = options.eventHub; - this.#home = options.home; + this.#home = options.home ?? homedir(); this.#hosts = Object.freeze([...new Set(options.hosts)]); this.#installBundle = options.installBundle ?? defaultInstallBundle; this.#projectRoot = resolve(options.projectRoot); @@ -439,6 +452,7 @@ export class DevHostInstallManager { const root = stableDevBundle(this.#projectRoot, host); try { await this.#uninstallBundle({ + commandRunner: this.#commandRunner, environment: this.#environment, force: true, from: root, @@ -463,6 +477,7 @@ export class DevHostInstallManager { if (installed === undefined) { if (host !== 'cursor') await ensureStableDevBundle(prepared.root, source); const result = await this.#installBundle({ + commandRunner: this.#commandRunner, environment: this.#environment, from: source, ...(this.#home === undefined ? {} : { home: this.#home }), diff --git a/packages/agent-bundle/src/install/install.ts b/packages/agent-bundle/src/install/install.ts index dbe6b9e2f..8936a67c5 100644 --- a/packages/agent-bundle/src/install/install.ts +++ b/packages/agent-bundle/src/install/install.ts @@ -71,7 +71,7 @@ export interface InstallCommandRunner { run( command: string, args: readonly string[], - options: { readonly cwd: string }, + options: { readonly cwd: string; readonly environment?: Readonly }, ): Promise; } @@ -125,9 +125,12 @@ export const defaultCommandRunner: InstallCommandRunner = Object.freeze({ run: ( command: string, args: readonly string[], - options: { readonly cwd: string }, + options: { readonly cwd: string; readonly environment?: Readonly }, ): Promise => new Promise((resolvePromise, reject) => { - execFile(command, [...args], { cwd: options.cwd }, (error, stdout, stderr) => { + execFile(command, [...args], { + cwd: options.cwd, + ...(options.environment === undefined ? {} : { env: options.environment }), + }, (error, stdout, stderr) => { if (error !== null && isErrno(error, 'ENOENT')) { reject(error); return;