feat(acp): a reclamation primitive removes all but the kept managed runtime release (#28507)

* feat(acp): ACP agents can run with a private per-process temp folder

* feat(acp): a reclamation primitive removes all but the kept managed runtime release

The installer calls it while it owns the runtime's installs and launches; it answers the entries it
could not remove so that caller can report them. Nothing calls it from adapter construction.
This commit is contained in:
Brennan Benson
2026-10-15 18:13:57 -07:00
committed by GitHub
parent fb529aaa30
commit 48d080e971
2 changed files with 28 additions and 0 deletions
@@ -0,0 +1,13 @@
import { mkdir, mkdtemp, readdir, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { expect, it } from 'vitest'
import { reclaimRuntimeReleases } from './managed-runtime-release'
it('removes every release and leftover but the kept one', async () => {
const root = await mkdtemp(join(tmpdir(), 'orca-runtime-reclaim-'))
await Promise.all(['1.0', '0.9', '.download-1-left'].map((name) => mkdir(join(root, name))))
expect(await reclaimRuntimeReleases(root, '1.0')).toEqual([])
expect(await readdir(root)).toEqual(['1.0'])
await rm(root, { recursive: true, force: true })
})
@@ -3,6 +3,7 @@
// cheap enough for every launch: a full hash is only ever taken by an install.
import { lstatSync, readFileSync, readdirSync, realpathSync, statSync } from 'node:fs'
import { readdir, rm } from 'node:fs/promises'
import { basename, dirname, join } from 'node:path'
import { z } from 'zod'
import { isDefinitiveAbsence } from '../../shared/definitive-filesystem-absence'
@@ -107,6 +108,20 @@ export function copyBesidePinnedMembers(
}
}
/** Removes everything under `root` but the release named `keep`: called only while the caller
* owns every install and launch of this runtime, so nothing else runs from or publishes into it.
* Answers the entries it could not remove. */
export async function reclaimRuntimeReleases(root: string, keep: string | null): Promise<string[]> {
const names = await readdir(root).catch((error: NodeJS.ErrnoException) =>
error.code === 'ENOENT' ? [] : Promise.reject(error)
)
const stale = names.filter((name) => name !== keep)
const results = await Promise.allSettled(
stale.map((name) => rm(join(root, name), { recursive: true, force: true }))
)
return stale.filter((_, index) => results[index]?.status === 'rejected')
}
function readRelease(folder: string, version: string): ReleaseRead {
try {
const receiptPath = join(folder, RUNTIME_RELEASE_RECEIPT)