@vostride/agent-qa-runner-local 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +78 -0
- package/dist/index.cjs +78 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +14 -31
- package/dist/index.d.ts +14 -31
- package/dist/index.js +79 -24
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/fs-action-cache.ts","../src/branch-resolver.ts","../src/write-policy.ts","../src/storage-state-store.ts","../src/event-log.ts","../src/handoff-store.ts","../src/run-artifact-store.ts","../src/evidence-artifact-store.ts","../src/screenshot-compressor.ts","../src/build-ordinal.ts","../src/build-tag-map.ts","../src/hook-executor.ts"],"sourcesContent":["// Barrel for @vostride/agent-qa-runner-local.\n//\n// The storageImplementation home for the concrete filesystem + git-branch\n// action-plan cache store behind the runner ActionPlanCache port (Phase 356).\n\n// Neutral port + key types this package's store implements. These type\n// re-exports also anchor the runner + schema workspace dependencies the\n// ownership contract declares.\nexport type { ActionPlanCache, StorageStatePort, StorageStateReference, StorageStateBlob } from '@vostride/agent-qa-runner'\nexport type { CacheKey } from '@vostride/agent-qa-schema'\n\n// Concrete filesystem store + its bumped on-disk schema version (D-03/D-06/D-14).\nexport { FsActionCache, CACHE_SCHEMA_VERSION } from './fs-action-cache.js'\nexport type { FsActionCacheConfig } from './fs-action-cache.js'\n\n// Concrete filesystem storage-state store (D-14) — raw-but-local auth persistence.\nexport { FsStorageStateStore, STORAGE_STATES_SUBDIR } from './storage-state-store.js'\nexport type { FsStorageStateStoreConfig } from './storage-state-store.js'\n\n// Injectable git-branch resolver + slug sanitizer (security V5).\nexport { resolveBranch, slugBranch } from './branch-resolver.js'\nexport type { BranchResolverOptions, ResolvedBranch } from './branch-resolver.js'\n\n// Branch write-skip policy (D-14).\nexport { shouldWrite } from './write-policy.js'\nexport type { CachePolicy } from './write-policy.js'\n\n// Runner-local persistence tier (Phase 361, D-05/D-06/D-17/D-18/D-19).\n// JSONL event log + completed-run handoff store + per-product buildOrdinal counter,\n// each behind a runner-declared port (EventLogPort/HandoffStorePort) or a thin fs leg.\nexport { FsEventLog, RUNS_SUBDIR, EVENTS_FILE } from './event-log.js'\nexport type { FsEventLogConfig } from './event-log.js'\nexport { FsHandoffStore, loadCompletedRunHandoff, HANDOFF_FILE } from './handoff-store.js'\nexport type { FsHandoffStoreConfig } from './handoff-store.js'\n\n// Phase 363 D-08 — the fs run-artifact store behind the runner RunArtifactStorePort. Writes one\n// artifact.json into the SAME <root>/runs/<slug(runId)>/ family as events.jsonl / handoff.json.\nexport { FsRunArtifactStore, ARTIFACT_FILE } from './run-artifact-store.js'\nexport type { FsRunArtifactStoreConfig } from './run-artifact-store.js'\n\n// Phase 367 CASS-02 — the content-addressed evidence artifact store behind the runner\n// EvidenceArtifactStorePort. Writes decision-screenshot bytes to blobs/<sha> in the SAME\n// <root>/runs/<slug(runId)>/ family as events.jsonl / handoff.json / artifact.json.\nexport { FsEvidenceArtifactStore, RUN_EVIDENCE_BLOBS_SUBDIR } from './evidence-artifact-store.js'\nexport type { FsEvidenceArtifactStoreConfig } from './evidence-artifact-store.js'\n\n// Phase 363 D-08 / Q10 — the sharp screenshot compressor behind the runner ScreenshotCompressor\n// port (sharp's host-adapter home; banned in the storage-neutral runner). `alignToWindow` /\n// `getImageDimensions` are host-side sharp utilities the mobile adapters call directly.\nexport {\n SharpScreenshotCompressor,\n alignToWindow,\n flattenOntoWhite,\n getImageDimensions,\n} from './screenshot-compressor.js'\nexport type {\n AlignOptions,\n CompressOptions,\n CompressResult,\n ImageDimensions,\n ScreenshotCompressorLogger,\n} from './screenshot-compressor.js'\nexport {\n BuildOrdinalReservationError,\n nextBuildOrdinal,\n reserveBuildOrdinalForProducts,\n BUILD_ORDINALS_FILE,\n} from './build-ordinal.js'\nexport type {\n BuildOrdinalReservation,\n BuildOrdinalReservationErrorCode,\n NextBuildOrdinalOptions,\n ReserveBuildOrdinalForProductsOptions,\n ReserveBuildOrdinalForProductsResult,\n} from './build-ordinal.js'\n// Phase 375 D-14/D-16/D-17 — sibling durable tag truth uses first-seen ordinals; latest ordinal is\n// exposed as a pure read so derived-index consumers never advance the run-start counter.\nexport {\n BUILD_TAGS_FILE,\n latestBuildOrdinal,\n readBuildTagMap,\n recordBuildTag,\n resolveBuildTag,\n} from './build-tag-map.js'\nexport type { BuildTagMap } from './build-tag-map.js'\n\n// Phase 363 D-06 — the Docker hook-execution impl behind the runner HookExecutorPort.\n// The sandbox-runner body (node:child_process + node:fs) lives here; the runner stays\n// storageNeutral. `checkDockerAvailable` is re-homed from core for the CLI doctor command.\nexport { DockerHookExecutor, checkDockerAvailable } from './hook-executor.js'\nexport type { DockerHookExecutorConfig } from './hook-executor.js'\n","// Concrete filesystem action-plan cache store (CACHE-04).\n//\n// Implements the storage-neutral `ActionPlanCache` port from\n// @vostride/agent-qa-runner. This is the storageImplementation home for\n// node:fs/promises + node:path (D-01/D-02). On-disk layout:\n//\n// <root>/<slug(branch)>/<cacheKey>.json\n//\n// The 16-hex CacheKey is the WHOLE filename (D-06) — no raw step text or secret\n// can appear on disk. Writes go only to the current-branch namespace; reads fall\n// back current-branch -> default-branch. An entry stamped with any other\n// CACHE_SCHEMA_VERSION is never read as valid.\n\nimport { mkdir, readFile, unlink, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nimport type { ActionPlanCache, CachedPlanValue } from '@vostride/agent-qa-runner'\nimport type { CacheKey } from '@vostride/agent-qa-schema'\n\nimport { slugBranch } from './branch-resolver.js'\nimport { shouldWrite, type CachePolicy } from './write-policy.js'\n\n/** Envelopes live under <root>/<branchSlug>/<key>.json; any other stamp reads as a miss. */\nexport const CACHE_SCHEMA_VERSION = 2\n\ninterface CacheEnvelope {\n schemaVersion: number\n value: CachedPlanValue\n}\n\nexport interface FsActionCacheConfig {\n /** Cache root (e.g. DEFAULT_AGENT_QA_CACHE_DIR = '.agent-qa/cache'). */\n root: string\n /** Resolved branch context + write policy (branch + CI + flags). */\n policy: CachePolicy\n}\n\nexport class FsActionCache implements ActionPlanCache {\n private readonly root: string\n private readonly policy: CachePolicy\n\n constructor(config: FsActionCacheConfig) {\n this.root = config.root\n this.policy = config.policy\n }\n\n async get(key: CacheKey): Promise<CachedPlanValue | null> {\n // --disable-cache short-circuits reads (D-15).\n if (this.policy.disableCache) return null\n\n const onCurrent = await this.readEntry(this.policy.currentBranch, key)\n if (onCurrent !== null) return onCurrent\n\n // branch -> default read fallback (D-14). Never the other direction.\n if (this.policy.currentBranch !== this.policy.defaultBranch) {\n return this.readEntry(this.policy.defaultBranch, key)\n }\n return null\n }\n\n async set(key: CacheKey, value: CachedPlanValue): Promise<void> {\n // No-op when the write policy forbids it (protected branch, disable, etc.).\n if (!shouldWrite(this.policy)) return\n\n // Writes go only to the current-branch namespace — a feature branch never\n // overwrites the default branch's entries (D-14).\n const dir = this.branchDir(this.policy.currentBranch)\n await mkdir(dir, { recursive: true })\n const envelope: CacheEnvelope = { schemaVersion: CACHE_SCHEMA_VERSION, value }\n await writeFile(this.entryPath(dir, key), `${JSON.stringify(envelope, null, 2)}\\n`, 'utf-8')\n }\n\n async invalidate(key: CacheKey): Promise<void> {\n const dir = this.branchDir(this.policy.currentBranch)\n try {\n await unlink(this.entryPath(dir, key))\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT') throw err\n }\n }\n\n private branchDir(branch: string): string {\n return join(this.root, slugBranch(branch))\n }\n\n private entryPath(dir: string, key: CacheKey): string {\n // The hex CacheKey is the whole filename (D-06).\n return join(dir, `${key}.json`)\n }\n\n private async readEntry(branch: string, key: CacheKey): Promise<CachedPlanValue | null> {\n let raw: string\n try {\n raw = await readFile(this.entryPath(this.branchDir(branch), key), 'utf-8')\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return null\n throw err\n }\n\n let envelope: CacheEnvelope\n try {\n envelope = JSON.parse(raw) as CacheEnvelope\n } catch {\n return null // corrupt/partial entry is a miss, never a crash\n }\n\n if (envelope?.schemaVersion !== CACHE_SCHEMA_VERSION) return null\n return envelope.value ?? null\n }\n}\n","// Injectable git-branch resolver for the local cache store.\n//\n// This is the ONLY sanctioned home for node:fs / node:child_process git reads\n// (storageImplementation, D-01/D-02). The resolver degrades gracefully in a\n// git-less directory — every step falls back to the configured default rather\n// than throwing. Detection method (per 356-RESEARCH Git-Branch Detection):\n// current branch : .git/HEAD fast path (no subprocess)\n// remote default : git symbolic-ref refs/remotes/origin/HEAD\n// final fallback : configured default -> main\n//\n// It never imports @vostride/agent-qa-safety-local — peer storage-impls must not\n// cross-import; isCI is resolved in the CLI and passed via CachePolicy.\n\nimport { execFileSync } from 'node:child_process'\nimport { readFileSync, statSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\n\nimport { slugBranch } from '@vostride/agent-qa-schema'\n\n// Preserve runner-local's public surface while schema owns the ONE pure sanitizer.\nexport { slugBranch }\n\nconst HEAD_REF_RE = /^ref:\\s*refs\\/heads\\/(.+?)\\s*$/m\nconst GITDIR_RE = /^gitdir:\\s*(.+)$/m\n\nexport interface ResolvedBranch {\n /** The branch the run is on; falls back to defaultBranch when undetectable. */\n currentBranch: string\n /** The remote default branch; falls back to the configured default -> main. */\n defaultBranch: string\n}\n\nexport interface BranchResolverOptions {\n /** Directory to resolve git state from (default process.cwd()). */\n cwd?: string\n /** Configured default branch, used when the remote default is undetectable. */\n configuredDefault?: string\n /** Injected .git/HEAD reader — returns raw file content or null. */\n readHead?: (cwd: string) => string | null\n /** Injected `git symbolic-ref refs/remotes/origin/HEAD` reader — raw or null. */\n runSymbolicRef?: (cwd: string) => string | null\n}\n\n/**\n * Resolve the current + default branch names. Both are returned raw (un-slugged);\n * the fs store slugs each before it becomes a path segment. Never throws.\n */\nexport function resolveBranch(opts: BranchResolverOptions = {}): ResolvedBranch {\n const cwd = opts.cwd ?? process.cwd()\n const readHead = opts.readHead ?? defaultReadHead\n const runSymbolicRef = opts.runSymbolicRef ?? defaultRunSymbolicRef\n\n const defaultBranch =\n parseSymbolicRef(safe(() => runSymbolicRef(cwd))) ?? opts.configuredDefault ?? 'main'\n const currentBranch = parseHeadBranch(safe(() => readHead(cwd))) ?? defaultBranch\n\n return { currentBranch, defaultBranch }\n}\n\nfunction parseHeadBranch(head: string | null): string | null {\n if (head === null) return null\n const match = HEAD_REF_RE.exec(head)\n return match ? match[1] : null // detached HEAD (a raw sha) yields null\n}\n\nfunction parseSymbolicRef(output: string | null): string | null {\n if (output === null) return null\n const trimmed = output.trim()\n if (trimmed === '') return null\n const name = trimmed.slice(trimmed.lastIndexOf('/') + 1)\n return name.length > 0 ? name : null\n}\n\nfunction defaultReadHead(cwd: string): string | null {\n try {\n const gitPath = join(cwd, '.git')\n const stat = statSync(gitPath)\n if (stat.isDirectory()) {\n return readFileSync(join(gitPath, 'HEAD'), 'utf-8')\n }\n // .git is a file (submodule / worktree): `gitdir: <path>`.\n const pointer = readFileSync(gitPath, 'utf-8')\n const match = GITDIR_RE.exec(pointer)\n if (match === null) return null\n const gitdir = resolve(cwd, match[1].trim())\n return readFileSync(join(gitdir, 'HEAD'), 'utf-8')\n } catch {\n return null\n }\n}\n\n/** Default git ABI: the 5s bound below caps the synchronous subprocess. */\nconst DEFAULT_GIT_SYMBOLIC_REF_TIMEOUT_MS = 5000\n\ntype GitExec = (\n command: string,\n args: string[],\n options: {\n cwd: string\n encoding: 'utf-8'\n stdio: ['ignore', 'pipe', 'ignore']\n timeout: number\n },\n) => string\n\ninterface RunGitSymbolicRefOptions {\n /** Bound (ms) on the synchronous git subprocess; ETIMEDOUT degrades to null. */\n timeoutMs?: number\n /** Injected exec seam for tests — defaults to node:child_process execFileSync. */\n exec?: GitExec\n}\n\n/**\n * Read `git symbolic-ref refs/remotes/origin/HEAD` with a finite timeout so the\n * synchronous subprocess can never wedge pre-run branch resolution (RUNX-02 / D1\n * secondary hazard). Any failure — including an ETIMEDOUT or kill-by-signal —\n * degrades to null so the resolver falls back to the configured default branch.\n */\nexport function runGitSymbolicRef(\n cwd: string,\n options: RunGitSymbolicRefOptions = {},\n): string | null {\n const exec = options.exec ?? (execFileSync as unknown as GitExec)\n const timeout = options.timeoutMs ?? DEFAULT_GIT_SYMBOLIC_REF_TIMEOUT_MS\n try {\n return exec('git', ['symbolic-ref', 'refs/remotes/origin/HEAD'], {\n cwd,\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n timeout,\n })\n } catch {\n return null\n }\n}\n\nfunction defaultRunSymbolicRef(cwd: string): string | null {\n return runGitSymbolicRef(cwd)\n}\n\nfunction safe(read: () => string | null): string | null {\n try {\n return read()\n } catch {\n return null\n }\n}\n","// Branch write-skip policy for the local action-plan cache store (D-14/D-15).\n//\n// Branch is a storage namespace, never a cache-key component. The policy is\n// resolved in the CLI / runner-local composition root (branch + CI + flags) and\n// passed to the store; the key builder in `@vostride/agent-qa-runner` never sees\n// a branch. Reads are always allowed (the store handles branch -> default\n// fallback); this predicate governs writes only.\n\nexport interface CachePolicy {\n /** The branch the current run executes on (raw, un-slugged). */\n currentBranch: string\n /** The repo's default branch (raw, un-slugged) — the read-fallback namespace. */\n defaultBranch: string\n /** default branch ∪ any configured protected branches. */\n protectedBranches: readonly string[]\n /** Resolved in the CLI (reusing the CI vendor-var set), passed in here. */\n isCI: boolean\n /** `--save-cache` — force writes even on a protected branch. */\n saveCache: boolean\n /** `--disable-cache` — short-circuit both reads and writes. */\n disableCache: boolean\n}\n\n/**\n * Writes are skipped when the current branch is protected (default ∪ configured)\n * unless `--save-cache` or CI; `--disable-cache` forbids all writes. Reads are not\n * governed here (D-14).\n */\nexport function shouldWrite(policy: CachePolicy): boolean {\n if (policy.disableCache) return false\n const protectedNow = policy.protectedBranches.includes(policy.currentBranch)\n return !protectedNow || policy.saveCache || policy.isCI\n}\n","// Concrete filesystem storage-state store (Phase 360, D-14 / STORAGE-STATE).\n//\n// Implements the storage-neutral `StorageStatePort` from @vostride/agent-qa-runner. This is a\n// storageImplementation home for node:fs/promises + node:path (the same boundary as\n// FsActionCache) — ALL storage-state fs writes live here, never in the runner (validate:arch\n// storageNeutral). On-disk layout:\n//\n// <root>/storage-states/<slug(name)>.json\n//\n// D-14 raw-but-local: the RAW adapter storage-state blob (auth material) is written verbatim so\n// it can be restored, under the gitignored `.agent-qa` runtime dir. It is never masked and never\n// enters evidence — `save` returns only a `{ name, fingerprint }` reference. The name is slugged\n// traversal-safe (the 356 `slugBranch` idiom) so a planner-supplied `../..`-shaped name can never\n// escape the storage-states root (T-360-03). Durability is independent of the action-cache schema\n// version — storage states persist across runs per the spec's auth-reuse intent.\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nimport { sha256hex16 } from '@vostride/agent-qa-schema'\nimport type { StorageStateBlob, StorageStatePort, StorageStateReference } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\n\n/** Subdirectory under the runtime root holding the raw storage-state blobs. */\nexport const STORAGE_STATES_SUBDIR = 'storage-states'\n\nexport interface FsStorageStateStoreConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n}\n\nexport class FsStorageStateStore implements StorageStatePort {\n private readonly root: string\n\n constructor(config: FsStorageStateStoreConfig) {\n this.root = config.root\n }\n\n async save(name: string, state: StorageStateBlob): Promise<StorageStateReference> {\n const dir = this.storageStatesDir()\n await mkdir(dir, { recursive: true })\n // Deterministic JSON so an identical blob fingerprints identically across runs.\n const serialized = JSON.stringify(state)\n await writeFile(this.entryPath(name), `${serialized}\\n`, 'utf-8')\n // 343 fingerprint() idiom — the shipped sha256hex16 determinism primitive, never hand-rolled.\n return { name, fingerprint: sha256hex16(serialized) }\n }\n\n async load(name: string): Promise<StorageStateBlob | undefined> {\n let raw: string\n try {\n raw = await readFile(this.entryPath(name), 'utf-8')\n } catch (err) {\n // A missing slot is never an error (D-14) — undefined, no throw.\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw err\n }\n try {\n return JSON.parse(raw) as StorageStateBlob\n } catch {\n // A corrupt/partial blob reads as absent rather than crashing the run.\n return undefined\n }\n }\n\n private storageStatesDir(): string {\n return join(this.root, STORAGE_STATES_SUBDIR)\n }\n\n private entryPath(name: string): string {\n // slugBranch neutralizes `..`, path separators, and leading/trailing dots so the slug is a\n // single safe path segment that can never traverse out of storage-states/ (T-360-03).\n return join(this.storageStatesDir(), `${slugBranch(name)}.json`)\n }\n}\n","// Concrete filesystem event-log sink (Phase 361, D-05/D-06 / SESSION-02).\n//\n// Implements the storage-neutral `EventLogPort` from @vostride/agent-qa-runner. This is a\n// storageImplementation home for node:fs + node:path (the same boundary as FsActionCache /\n// FsStorageStateStore) — ALL run-event fs writes live here, never in the runner\n// (validate:arch storageNeutral). On-disk layout:\n//\n// <root>/runs/<slug(runId)>/events.jsonl\n//\n// D-06 append discipline: synchronous, fsync-free, mkdir-recursive then one appendFileSync of\n// exactly one JSON line per envelope — the file is crash-safe up to the last completed append.\n// The runId directory component is slugged traversal-safe (the T-360-03 `slugBranch` idiom) so a\n// planner-supplied `../..`-shaped runId can never escape the runs root (T-361-01). The read leg\n// (deep replay for the bus) tolerates a torn final line: a corrupt/partial row is dropped and the\n// read still succeeds (the storage-state never-crash-the-reader posture — the bus layer, not this\n// leg, reports incompleteness via ReplayIncompleteError; T-361-06 / D-07).\n\nimport { appendFileSync, mkdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { RunEventEnvelope } from '@vostride/agent-qa-schema'\nimport type { EventLogPort } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\n\n/** Subdirectory under the runtime root holding per-run event logs. */\nexport const RUNS_SUBDIR = 'runs'\n\n/** The single JSONL file name each run appends its event stream to. */\nexport const EVENTS_FILE = 'events.jsonl'\n\nexport interface FsEventLogConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The run this log belongs to; slugged before it becomes a path segment. */\n runId: string\n}\n\nexport class FsEventLog implements EventLogPort {\n private readonly dir: string\n private readonly file: string\n\n constructor(config: FsEventLogConfig) {\n // slugBranch neutralizes `..`, path separators, and leading/trailing dots so the slug is a\n // single safe path segment that can never traverse out of runs/ (T-361-01 / V5).\n this.dir = join(config.root, RUNS_SUBDIR, slugBranch(config.runId))\n this.file = join(this.dir, EVENTS_FILE)\n }\n\n append(envelope: RunEventEnvelope): void {\n // D-06: mkdir-recursive then a single synchronous appendFileSync of one line.\n mkdirSync(this.dir, { recursive: true })\n appendFileSync(this.file, `${JSON.stringify(envelope)}\\n`)\n }\n\n read(fromSeq: number): RunEventEnvelope[] {\n let raw: string\n try {\n raw = readFileSync(this.file, 'utf-8')\n } catch (err) {\n // No log yet ⇒ empty replay, never an error (D-06).\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n const out: RunEventEnvelope[] = []\n for (const line of raw.split('\\n')) {\n if (line.length === 0) continue\n let parsed: RunEventEnvelope\n try {\n parsed = JSON.parse(line) as RunEventEnvelope\n } catch {\n // A torn/partial final line is dropped — the reader never throws on garbage (D-07).\n continue\n }\n if (parsed.seq >= fromSeq) out.push(parsed)\n }\n return out\n }\n}\n","// Concrete filesystem completed-run handoff store (Phase 361, D-05/D-17/D-19 / SESSION-05).\n//\n// Implements the storage-neutral `HandoffStorePort` from @vostride/agent-qa-runner. This is a\n// storageImplementation home for node:fs + node:path (the FsActionCache / FsStorageStateStore\n// boundary) — the durable handoff fs write lives here, never in the runner (validate:arch\n// storageNeutral). On-disk layout — one JSON document beside the run's events.jsonl (D-17):\n//\n// <root>/runs/<slug(runId)>/handoff.json\n//\n// The read side (`loadCompletedRunHandoff`) is deliberately thin: read → JSON.parse → delegate to\n// the schema package's ONE `guardCompletedRunHandoff` version rule. The refusal (any schemaVersion\n// other than the current one ⇒ typed HandoffVersionError) is never re-implemented here; the\n// version discipline lives in exactly one place.\n\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { guardCompletedRunHandoff } from '@vostride/agent-qa-schema'\nimport type { CompletedRunHandoff } from '@vostride/agent-qa-schema'\nimport type { HandoffStorePort } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\nimport { RUNS_SUBDIR } from './event-log.js'\n\n/** The single JSON document each run writes its completed-run handoff to. */\nexport const HANDOFF_FILE = 'handoff.json'\n\nexport interface FsHandoffStoreConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The run this handoff belongs to; slugged before it becomes a path segment. */\n runId: string\n}\n\nexport class FsHandoffStore implements HandoffStorePort {\n private readonly dir: string\n private readonly file: string\n\n constructor(config: FsHandoffStoreConfig) {\n // Same slugged run dir as FsEventLog so handoff.json lands beside events.jsonl (D-17).\n this.dir = join(config.root, RUNS_SUBDIR, slugBranch(config.runId))\n this.file = join(this.dir, HANDOFF_FILE)\n }\n\n save(handoff: CompletedRunHandoff): void {\n mkdirSync(this.dir, { recursive: true })\n writeFileSync(this.file, `${JSON.stringify(handoff)}\\n`, 'utf-8')\n }\n}\n\n/**\n * The fs read leg of the handoff version discipline (D-19): read the single document, parse it,\n * and delegate to the schema package's `guardCompletedRunHandoff`. A newer-than-known schemaVersion\n * surfaces the schema's typed `HandoffVersionError` — this leg re-implements no version rule.\n */\nexport function loadCompletedRunHandoff(filePath: string): CompletedRunHandoff {\n const raw = readFileSync(filePath, 'utf-8')\n return guardCompletedRunHandoff(JSON.parse(raw))\n}\n","// Concrete filesystem run-artifact store (Phase 363, D-08).\n//\n// Implements the storage-neutral `RunArtifactStorePort` from @vostride/agent-qa-runner. This is a\n// storageImplementation home for node:fs + node:path (the FsEventLog / FsHandoffStore boundary) —\n// the durable artifact fs write lives here, never in the runner (validate:arch storageNeutral).\n// On-disk layout — one JSON document beside the run's events.jsonl / handoff.json (D-08, one\n// self-contained run directory):\n//\n// <root>/runs/<slug(runId)>/artifact.json\n//\n// The runId directory component is slugged traversal-safe (the T-360-03 `slugBranch` idiom, shared\n// with FsEventLog via `RUNS_SUBDIR`) so a planner-supplied `../..`-shaped runId can never escape\n// the runs root (T-363-12) — the path is NEVER re-minted here.\n//\n// Per the RESEARCH Q5 keep/drop table the FILE artifact keeps ONLY the config snapshot, the\n// test/suite source snapshot, terminal errors, and metadata. The top-level `runtime` section is\n// DROPPED from new documents (it is derivable from events.jsonl / handoff.json), so `stage`/\n// `finalize` strip any incoming top-level `runtime` before writing. `stage` persists config+source\n// once after runStarted; `finalize` merges terminal errors + `finalizedAt` before runFinished\n// (the dashboard staged/finalize idiom — a crashed run still leaves a staged artifact.json).\n\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { RUN_ARTIFACT_SCHEMA_VERSION } from '@vostride/agent-qa-schema'\nimport type {\n RunArtifactFinalizeInput,\n RunArtifactPayload,\n RunArtifactStageInput,\n} from '@vostride/agent-qa-schema'\nimport type { RunArtifactStorePort } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\nimport { RUNS_SUBDIR } from './event-log.js'\n\n/** The single JSON document each run writes its run artifact to. */\nexport const ARTIFACT_FILE = 'artifact.json'\n\nexport interface FsRunArtifactStoreConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The run this artifact belongs to; slugged before it becomes a path segment. */\n runId: string\n}\n\n/** The persisted artifact document shape (schema-stamped, runtime-free). */\ntype PersistedArtifact = Omit<RunArtifactPayload, 'runtime'> & { finalizedAt?: string }\n\nexport class FsRunArtifactStore implements RunArtifactStorePort {\n private readonly dir: string\n private readonly file: string\n\n constructor(config: FsRunArtifactStoreConfig) {\n // Same slugged run dir as FsEventLog so artifact.json lands beside events.jsonl (D-08).\n this.dir = join(config.root, RUNS_SUBDIR, slugBranch(config.runId))\n this.file = join(this.dir, ARTIFACT_FILE)\n }\n\n stage(document: RunArtifactStageInput): void {\n const persisted = this.merge({ schemaVersion: RUN_ARTIFACT_SCHEMA_VERSION }, document)\n this.write(persisted)\n }\n\n finalize(patch: RunArtifactFinalizeInput): void {\n const base = this.readExisting() ?? { schemaVersion: RUN_ARTIFACT_SCHEMA_VERSION }\n const persisted = this.merge(base, patch)\n this.write(persisted)\n }\n\n /** Shallow-merge a stage/finalize input onto the base, always dropping the top-level runtime. */\n private merge(base: PersistedArtifact, input: RunArtifactStageInput | RunArtifactFinalizeInput): PersistedArtifact {\n const { runtime: _dropRuntime, ...rest } = input as RunArtifactStageInput & { runtime?: unknown }\n const merged: PersistedArtifact = {\n ...base,\n ...rest,\n schemaVersion: RUN_ARTIFACT_SCHEMA_VERSION,\n }\n delete (merged as { runtime?: unknown }).runtime\n return merged\n }\n\n private readExisting(): PersistedArtifact | undefined {\n try {\n return JSON.parse(readFileSync(this.file, 'utf-8')) as PersistedArtifact\n } catch (err) {\n // No staged artifact yet (crash before stage) ⇒ start fresh, never throw on the read leg.\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw err\n }\n }\n\n private write(document: PersistedArtifact): void {\n mkdirSync(this.dir, { recursive: true })\n writeFileSync(this.file, `${JSON.stringify(document)}\\n`, 'utf-8')\n }\n}\n","// Concrete filesystem content-addressed evidence artifact store (Phase 367, CASS-02).\n//\n// Implements the storage-neutral `EvidenceArtifactStorePort` from @vostride/agent-qa-runner. This\n// is a storageImplementation home for node:crypto + node:fs + node:path (the FsHandoffStore /\n// FsRunArtifactStore boundary) — the sha-keyed screenshot-byte writes live here, never in the\n// runner (validate:arch storageNeutral). On-disk layout, in the SAME run family as\n// events.jsonl / handoff.json / artifact.json:\n//\n// <root>/runs/<slug(runId)>/blobs/<sha>\n//\n// The runId directory component is slugged traversal-safe (the shared `slugBranch` idiom via\n// RUNS_SUBDIR) so a planner-supplied `../..`-shaped runId can never escape the runs root; the path\n// is never re-minted here. Filenames ARE the lowercase SHA-256 of their exact bytes, so a repeat\n// write of identical bytes overwrites the same file and stays idempotent. `getBlob` validates the\n// lowercase 64-hex shape before any path use so a malformed/traversal-shaped sha can never address\n// an arbitrary file (T-367-16); ENOENT is honest absence, other host failures surface.\n//\n// PRESENCE IS A STAT, NOT A READ (Phase 406, D-17). `hasBlob` answers whether a run still holds\n// the bytes behind an artifact ref so a durable read can annotate a whole run's refs without\n// loading a single screenshot; it runs the SAME regex guard first, for the same reason, and\n// touches the filesystem only after the shape is known good.\n\nimport { createHash, randomUUID } from 'node:crypto'\nimport {\n closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync,\n unlinkSync, writeFileSync,\n} from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { chmodSync, copyFileSync, fstatSync, readSync, realpathSync, statSync } from 'node:fs'\nimport { isAbsolute, relative, resolve, sep } from 'node:path'\nimport { RECORDING_REF_PREFIX } from '@vostride/agent-qa-schema'\nimport type { PersistedRecording } from '@vostride/agent-qa-runner'\n\nimport type { ArtifactRef, EvidenceDocument } from '@vostride/agent-qa-schema'\nimport { EvidenceArtifactRefSchema, EvidenceDocumentSchema } from '@vostride/agent-qa-schema'\nimport type { EvidenceArtifactStorePort } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\nimport { RUNS_SUBDIR } from './event-log.js'\n\n/** Subdirectory under each slugged run dir holding the content-addressed evidence blobs. */\nexport const RUN_EVIDENCE_BLOBS_SUBDIR = 'blobs'\n\nconst SHA256_HEX_RE = /^[0-9a-f]{64}$/\n\nconst DIRECTORY_SYNC_TOLERATED_CODES = ['EINVAL', 'EPERM', 'ENOTSUP', 'EOPNOTSUPP', 'EBADF', 'EISDIR'] as const\n\nexport interface FsEvidenceArtifactStoreConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The run these blobs belong to; slugged before it becomes a path segment. */\n runId: string\n}\n\nexport class FsEvidenceArtifactStore implements EvidenceArtifactStorePort {\n private readonly dir: string\n private readonly durabilityRoot: string\n\n constructor(config: FsEvidenceArtifactStoreConfig) {\n this.dir = join(config.root, RUNS_SUBDIR, slugBranch(config.runId), RUN_EVIDENCE_BLOBS_SUBDIR)\n this.durabilityRoot = dirname(join(config.root, '.'))\n }\n\n persistDecisionScreenshot(bytes: Uint8Array): ArtifactRef {\n const sha = createHash('sha256').update(bytes).digest('hex')\n mkdirSync(this.dir, { recursive: true })\n writeFileSync(join(this.dir, sha), bytes)\n return { id: `decision-screenshot:${sha}`, sha }\n }\n\n persistEvidenceDocument(document: Exclude<EvidenceDocument, { kind: 'variables' }>): ArtifactRef {\n // Validate the actual serialization, but retain its exact property/record order. Parsing\n // and reserializing a Zod object would reorder keys and change the content address.\n const bytes = Buffer.from(JSON.stringify(document))\n const parsed = EvidenceDocumentSchema.parse(JSON.parse(bytes.toString('utf8')))\n if (parsed.kind === 'variables') throw new Error('Variable evidence is stored inline')\n const sha = createHash('sha256').update(bytes).digest('hex')\n const prefix = parsed.kind === 'aria' ? 'aria-state:' : `${parsed.kind}-evidence:`\n const ref = EvidenceArtifactRefSchema.parse({ id: `${prefix}${sha}`, sha })\n mkdirSync(this.dir, { recursive: true })\n const target = join(this.dir, sha)\n const existing = this.getBlob(sha)\n if (existing !== undefined && Buffer.from(existing).equals(bytes)) {\n // A competing writer may have renamed but not synced its directory yet. Confirm both\n // the complete file and directory ourselves before returning the deduplicated ref.\n this.syncPath(target)\n this.syncDirectories()\n return ref\n }\n const temporary = join(this.dir, `.${sha}.${randomUUID()}.tmp`)\n const fd = openSync(temporary, 'wx', 0o600)\n let opened = true\n try {\n writeFileSync(fd, bytes)\n fsyncSync(fd)\n closeSync(fd)\n opened = false\n // Concurrent identical documents have identical complete bytes. Replacing either\n // complete inode is safe; a reader can never observe the temporary partial content.\n renameSync(temporary, target)\n this.syncDirectories()\n return ref\n } finally {\n if (opened) closeSync(fd)\n try {\n unlinkSync(temporary)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n }\n }\n\n private syncDirectories(): void {\n // mkdir(recursive) may have created any part of the run family. Sync each parent\n // entry as well, including when a competing writer created it before this call.\n for (let path = this.dir; ; path = dirname(path)) {\n try {\n this.syncPath(path)\n } catch (error) {\n // The file bytes were synced before rename. Some filesystems refuse directory fsync,\n // and that refusal is not data loss.\n const code = (error as NodeJS.ErrnoException).code\n if (!DIRECTORY_SYNC_TOLERATED_CODES.some(tolerated => tolerated === code)) throw error\n }\n if (path === this.durabilityRoot || dirname(path) === path) return\n }\n }\n\n private syncPath(path: string): void {\n const fd = openSync(path, 'r')\n try {\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n }\n\n hasBlob(sha: string): boolean {\n if (!SHA256_HEX_RE.test(sha)) return false\n return existsSync(join(this.dir, sha))\n }\n\n persistRecording(stagingPath: string): PersistedRecording {\n this.assertRecordingStagingPath(stagingPath)\n let recordingTemp: string | undefined\n try {\n const byteLength = statSync(stagingPath).size\n if (byteLength === 0) throw new Error('Cannot persist an empty recording')\n const hash = createHash('sha256')\n const fd = openSync(stagingPath, 'r')\n try {\n const chunk = Buffer.allocUnsafe(1024 * 1024)\n let total = 0\n for (;;) {\n const count = readSync(fd, chunk, 0, chunk.length, null)\n if (count === 0) break\n total += count\n hash.update(chunk.subarray(0, count))\n }\n if (total !== byteLength) throw new Error('Recording changed while hashing')\n } finally {\n closeSync(fd)\n }\n const sha = hash.digest('hex')\n const result: PersistedRecording = {\n ref: { id: `${RECORDING_REF_PREFIX}${sha}`, sha }, byteLength,\n }\n mkdirSync(this.dir, { recursive: true })\n const target = join(this.dir, sha)\n if (this.blobSize(sha) !== undefined) {\n this.syncPath(target)\n this.syncDirectories()\n return result\n }\n recordingTemp = join(this.dir, `.${sha}.${randomUUID()}.tmp`)\n try {\n renameSync(stagingPath, recordingTemp)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EXDEV') throw error\n copyFileSync(stagingPath, recordingTemp)\n }\n chmodSync(recordingTemp, 0o600)\n this.syncPath(recordingTemp)\n renameSync(recordingTemp, target)\n this.syncDirectories()\n return result\n } finally {\n try {\n if (recordingTemp !== undefined) this.unlinkRecordingStaging(recordingTemp)\n } finally {\n this.unlinkRecordingStaging(stagingPath)\n }\n }\n }\n\n blobSize(sha: string): number | undefined {\n if (!SHA256_HEX_RE.test(sha)) return undefined\n try {\n return statSync(join(this.dir, sha)).size\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw error\n }\n }\n\n readBlobRange(sha: string, start: number, end: number): Uint8Array | undefined {\n if (!SHA256_HEX_RE.test(sha)) return undefined\n if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start) return undefined\n let fd: number\n try {\n fd = openSync(join(this.dir, sha), 'r')\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw error\n }\n try {\n const size = fstatSync(fd).size\n if (start >= size) return undefined\n const length = Math.min(end, size - 1) - start + 1\n const bytes = new Uint8Array(length)\n let offset = 0\n while (offset < length) {\n const count = readSync(fd, bytes, offset, length - offset, start + offset)\n if (count === 0) throw new Error('Recording blob ended before the requested range')\n offset += count\n }\n return bytes\n } finally {\n closeSync(fd)\n }\n }\n\n discardRecording(stagingPath: string): void {\n this.assertRecordingStagingPath(stagingPath)\n this.unlinkRecordingStaging(stagingPath)\n }\n\n private assertRecordingStagingPath(stagingPath: string): void {\n const inside = (dir: string, path: string) => {\n const tail = relative(dir, path)\n return tail === '' || (tail !== '..' && !tail.startsWith(`..${sep}`) && !isAbsolute(tail))\n }\n if (inside(resolve(this.dir), resolve(stagingPath))) {\n throw new Error('Recording staging path must be outside the evidence blob directory')\n }\n try {\n if (inside(realpathSync(this.dir), realpathSync(stagingPath))) {\n throw new Error('Recording staging path must be outside the evidence blob directory')\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n }\n\n private unlinkRecordingStaging(path: string): void {\n try {\n unlinkSync(path)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n }\n\n getBlob(sha: string): Uint8Array | undefined {\n if (!SHA256_HEX_RE.test(sha)) return undefined\n try {\n return new Uint8Array(readFileSync(join(this.dir, sha)))\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw err\n }\n }\n}\n","// Concrete sharp-based screenshot compressor + image utilities (Phase 363, D-08 / Q10).\n//\n// This is the host-adapter home for `sharp` (the runner is storageNeutral / storage-agnostic and\n// bans native image codecs by construction, Pitfall 9). Phase 356's ownership ledger claimed the\n// compression pipeline would move out of core \"by Phase 356\"; RESEARCH Q10 found that claim STALE —\n// the pipeline was still core-side. This module makes the truthful end-state real: `sharp` leaves\n// core and lands here, behind the runner's `ScreenshotCompressor` port. `SharpScreenshotCompressor`\n// is constructed once at the CLI composition root and injected into `runTest` (the injected-host-impl\n// shape the member-runner keeps), so no core code constructs a compressor.\n//\n// `alignToWindow` + `getImageDimensions` are exported alongside the port impl because the mobile\n// adapters (`@vostride/agent-qa-android`, `@vostride/agent-qa-ios`) call them directly for\n// action-space alignment / drift assertions — they are host-side sharp utilities with the same\n// storageImplementation home, not part of the `ScreenshotCompressor` port surface.\n\nimport sharp from 'sharp'\nimport type { CompressedScreenshot, ScreenshotCompressor } from '@vostride/agent-qa-runner'\n\n/** Minimal structural debug-logger seam (a core `ScopedLogger` satisfies it; no core dependency). */\nexport interface ScreenshotCompressorLogger {\n debug(message: string, meta?: Record<string, unknown>): void\n}\n\nconst STARTING_QUALITY = 70\nconst QUALITY_REDUCTION = 0.8\nconst MIN_QUALITY = 10\n\nexport interface CompressOptions {\n effectiveResolution: number\n maxBytes?: number\n actionSpaceWidth: number\n}\n\nexport interface CompressResult {\n buffer: Buffer\n imageWidth: number\n imageHeight: number\n}\n\n/**\n * Resize + optional JPEG-quality compression of a screenshot buffer (v1 pipeline, verbatim).\n * D-01/D-02: fit:'inside' constrains both dimensions preserving AR (longer edge becomes eR);\n * D-04: withoutEnlargement avoids upscaling small images. The JPEG pass only runs when a byte\n * budget is set, iterating quality down to a graceful minimum-quality fallback (Pitfall 4 — never\n * re-resize inside the loop).\n */\nasync function compressScreenshot(\n buffer: Buffer,\n opts: CompressOptions,\n logger?: ScreenshotCompressorLogger,\n): Promise<CompressResult> {\n const originalKB = (buffer.length / 1024).toFixed(1)\n const meta = await sharp(buffer).metadata()\n const srcWidth = meta.width ?? opts.actionSpaceWidth\n const srcHeight = meta.height ?? 0\n const targetEdge = opts.effectiveResolution\n\n let resizePipeline = sharp(buffer)\n if (srcWidth > targetEdge || srcHeight > targetEdge) {\n resizePipeline = resizePipeline.resize({\n width: targetEdge,\n height: targetEdge,\n fit: 'inside',\n withoutEnlargement: true,\n kernel: 'lanczos3',\n })\n }\n const afterResize = await resizePipeline.toBuffer({ resolveWithObject: true })\n const resizedWidth = afterResize.info.width\n const resizedHeight = afterResize.info.height\n\n // Skip JPEG pass if no byte budget set (D-21).\n if (!opts.maxBytes) {\n return { buffer: afterResize.data, imageWidth: resizedWidth, imageHeight: resizedHeight }\n }\n\n const maxBytes = opts.maxBytes\n const targetKB = (maxBytes / 1024).toFixed(1)\n\n let quality = STARTING_QUALITY\n while (quality > MIN_QUALITY) {\n const { data, info } = await sharp(afterResize.data)\n .jpeg({ quality, mozjpeg: true })\n .toBuffer({ resolveWithObject: true })\n\n if (info.size <= maxBytes) {\n logger?.debug('Compressed screenshot', {\n originalKB: parseFloat(originalKB),\n compressedKB: parseFloat((info.size / 1024).toFixed(1)),\n targetKB: parseFloat(targetKB),\n quality,\n })\n return { buffer: data, imageWidth: resizedWidth, imageHeight: resizedHeight }\n }\n quality = Math.max(MIN_QUALITY, Math.round(quality * QUALITY_REDUCTION))\n }\n\n // Graceful fallback: return best-effort at minimum quality.\n const { data, info } = await sharp(afterResize.data)\n .jpeg({ quality: MIN_QUALITY, mozjpeg: true })\n .toBuffer({ resolveWithObject: true })\n logger?.debug('Compressed screenshot (exceeded target)', {\n originalKB: parseFloat(originalKB),\n compressedKB: parseFloat(((info as { size: number }).size / 1024).toFixed(1)),\n targetKB: parseFloat(targetKB),\n quality: MIN_QUALITY,\n })\n return { buffer: data, imageWidth: resizedWidth, imageHeight: resizedHeight }\n}\n\n/**\n * The runner `ScreenshotCompressor` port impl (D-08 / Q10). `compress` covers the LLM-planner\n * compression call site; `dimensions` covers the action-space-width metadata fallback done inline\n * via `sharp(screenshot).metadata()` at v1 loop.ts. The loop applies `stampCaptureMode` itself\n * (runner-owned since 352), so this stays purely pixel-level and returns v1's CompressResult shape.\n */\nexport class SharpScreenshotCompressor implements ScreenshotCompressor {\n constructor(private readonly logger?: ScreenshotCompressorLogger) {}\n\n async compress(\n screenshot: Buffer,\n options: { effectiveResolution: number; maxBytes?: number; actionSpaceWidth: number },\n ): Promise<CompressedScreenshot> {\n return compressScreenshot(screenshot, options, this.logger)\n }\n\n async dimensions(screenshot: Buffer): Promise<{ width: number; height: number }> {\n const meta = await sharp(screenshot).metadata()\n return { width: meta.width ?? 0, height: meta.height ?? 0 }\n }\n}\n\nexport interface AlignOptions {\n width: number\n height: number\n}\n\n/** Resize buffer to exact window dimensions. Used by mobile adapters for action-space alignment\n * (e.g., iOS physical pixels → logical points). */\nexport async function alignToWindow(buffer: Buffer, opts: AlignOptions): Promise<Buffer> {\n return sharp(buffer)\n .resize({ width: opts.width, height: opts.height, kernel: 'lanczos3', fit: 'fill' })\n .png()\n .toBuffer()\n}\n\nexport interface ImageDimensions {\n width: number\n height: number\n}\n\n/** Read image buffer width/height without decoding pixels. Used by mobile adapters for\n * action-space drift assertions (D-06/D-07). */\nexport async function getImageDimensions(buffer: Buffer): Promise<ImageDimensions | undefined> {\n const meta = await sharp(buffer).metadata()\n if (!meta.width || !meta.height) return undefined\n return { width: meta.width, height: meta.height }\n}\n\nexport async function flattenOntoWhite(buffer: Buffer): Promise<Buffer> {\n const meta = await sharp(buffer).metadata()\n if (!meta.hasAlpha) return buffer\n return sharp(buffer).flatten({ background: '#ffffff' }).png().toBuffer()\n}\n","// Concrete per-product buildOrdinal counter (Phase 361, D-18 / SESSION-05).\n//\n// A storageImplementation home for node:fs + node:path (the FsActionCache / FsStorageStateStore\n// boundary) — this project-local counter fs write lives here, never in the runner. On-disk layout:\n//\n// <root>/build-ordinals.json ({ [product]: number })\n//\n// D-18 derivation (spec/v2/eval-and-core-types.md §A8): buildOrdinal is a per-product run counter\n// incremented at run start. The complete read/validate/increment/replace unit is serialized across\n// processes and durably replaced, so run starts and maintenance reservations share one monotonic\n// authority without lost updates or fixed-temp collisions.\n\nimport { randomUUID } from 'node:crypto'\nimport {\n closeSync,\n fsyncSync,\n linkSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { dirname, join } from 'node:path'\n\n/** The project-local state file holding the per-product ordinal map. */\nexport const BUILD_ORDINALS_FILE = 'build-ordinals.json'\n\nexport interface NextBuildOrdinalOptions {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The product whose counter to advance. */\n product: string\n}\n\nexport interface BuildOrdinalReservation {\n /** Canonical, sorted, duplicate-free product axes advanced by the reservation. */\n products: readonly string[]\n /** One ordinal strictly later than every affected product's current counter. */\n ordinal: number\n}\n\nexport type BuildOrdinalReservationErrorCode =\n | 'invalid-state'\n | 'missing-counter'\n | 'invalid-counter'\n | 'counter-exhausted'\n\n/** Typed pre-persistence refusal for an unsafe maintenance ordinal reservation. */\nexport class BuildOrdinalReservationError extends Error {\n readonly name = 'BuildOrdinalReservationError'\n readonly code: BuildOrdinalReservationErrorCode\n readonly product: string\n readonly value?: unknown\n\n constructor(\n code: BuildOrdinalReservationErrorCode,\n product: string,\n value?: unknown,\n ) {\n const message =\n code === 'invalid-state'\n ? `${BUILD_ORDINALS_FILE} must contain a JSON object`\n : code === 'missing-counter'\n ? `Missing build ordinal counter for product ${JSON.stringify(product)}`\n : code === 'invalid-counter'\n ? `Build ordinal counter for product ${JSON.stringify(product)} must be a non-negative safe integer`\n : `Build ordinal counter for product ${JSON.stringify(product)} is exhausted`\n super(message)\n this.code = code\n this.product = product\n this.value = value\n }\n}\n\nexport interface ReserveBuildOrdinalForProductsOptions {\n /** Runtime root containing build-ordinals.json. */\n root: string\n /** Product axes whose counters must advance together. Duplicates and order are ignored. */\n products: Iterable<string>\n /**\n * Synchronous authority fence invoked after the complete temp file is prepared and immediately\n * before the atomic rename. Throwing refuses persistence and removes the temp file.\n */\n beforePersist?: (reservation: BuildOrdinalReservation) => void\n}\n\n/** Undefined is the explicit no-op result for an empty affected-product set. */\nexport type ReserveBuildOrdinalForProductsResult = number | undefined\n\ninterface CounterLockOwner {\n pid: number\n token: string\n}\n\nconst BUILD_ORDINALS_LOCK_FILE = '.build-ordinals.lock'\nconst COUNTER_LOCK_POLL_MS = 5\nconst COUNTER_LOCK_WAIT = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT))\n\nfunction fsyncDirectory(dir: string): void {\n let fd: number | undefined\n try {\n fd = openSync(dir, 'r')\n fsyncSync(fd)\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code\n if (code !== 'EINVAL' && code !== 'EISDIR' && code !== 'EPERM' && code !== 'ENOTSUP') {\n throw error\n }\n } finally {\n if (fd !== undefined) closeSync(fd)\n }\n}\n\nfunction durableExclusiveFile(file: string, text: string): void {\n const fd = openSync(file, 'wx')\n try {\n writeFileSync(fd, text, 'utf8')\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n}\n\nfunction parsedLockOwner(file: string): CounterLockOwner | undefined {\n try {\n const value = JSON.parse(readFileSync(file, 'utf8')) as unknown\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const owner = value as Record<string, unknown>\n return typeof owner.pid === 'number'\n && Number.isSafeInteger(owner.pid)\n && owner.pid > 0\n && typeof owner.token === 'string'\n && owner.token !== ''\n ? { pid: owner.pid, token: owner.token }\n : undefined\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw error\n }\n}\n\nfunction processIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code\n if (code === 'ESRCH') return false\n if (code === 'EPERM') return true\n throw error\n }\n}\n\nfunction withCounterLock<T>(root: string, operation: () => T): T {\n mkdirSync(root, { recursive: true })\n const lock = join(root, BUILD_ORDINALS_LOCK_FILE)\n const owner: CounterLockOwner = { pid: process.pid, token: randomUUID() }\n const ownerFile = `${lock}.owner-${owner.token}`\n durableExclusiveFile(ownerFile, `${JSON.stringify(owner)}\\n`)\n\n let acquired = false\n try {\n while (!acquired) {\n try {\n // Linking a complete, fsynced owner document makes lock acquisition atomic. A crash\n // before this point leaves only a uniquely named non-authoritative candidate file.\n linkSync(ownerFile, lock)\n fsyncDirectory(root)\n acquired = true\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error\n const current = parsedLockOwner(lock)\n if (current !== undefined && !processIsAlive(current.pid)) {\n // A dead PID is the only stale-lock recovery authority. The unique quarantine name\n // prevents one recovery attempt from recursively deleting another owner's lock bytes.\n const quarantine = `${lock}.dead-${current.token}-${randomUUID()}`\n try {\n renameSync(lock, quarantine)\n fsyncDirectory(root)\n rmSync(quarantine, { force: true })\n fsyncDirectory(root)\n continue\n } catch (recoveryError) {\n if ((recoveryError as NodeJS.ErrnoException).code === 'ENOENT') continue\n throw recoveryError\n }\n }\n Atomics.wait(COUNTER_LOCK_WAIT, 0, 0, COUNTER_LOCK_POLL_MS)\n }\n }\n\n return operation()\n } finally {\n if (acquired && parsedLockOwner(lock)?.token === owner.token) {\n rmSync(lock, { force: true })\n fsyncDirectory(root)\n }\n rmSync(ownerFile, { force: true })\n }\n}\n\nfunction persistOrdinals(\n file: string,\n map: Readonly<Record<string, number>>,\n beforePersist?: () => void,\n): void {\n const temporary = `${file}.tmp-${randomUUID()}`\n let fd: number | undefined\n try {\n fd = openSync(temporary, 'wx')\n writeFileSync(fd, `${JSON.stringify(map)}\\n`, 'utf8')\n fsyncSync(fd)\n closeSync(fd)\n fd = undefined\n beforePersist?.()\n renameSync(temporary, file)\n fsyncDirectory(dirname(file))\n } finally {\n if (fd !== undefined) closeSync(fd)\n rmSync(temporary, { force: true })\n }\n}\n\nexport async function nextBuildOrdinal(opts: NextBuildOrdinalOptions): Promise<number> {\n return withCounterLock(opts.root, () => {\n const file = join(opts.root, BUILD_ORDINALS_FILE)\n const map = readOrdinals(file, opts.product, true)\n const current = Object.hasOwn(map, opts.product) ? map[opts.product]! : 0\n if (current === Number.MAX_SAFE_INTEGER) {\n throw new BuildOrdinalReservationError('counter-exhausted', opts.product, current)\n }\n const next = current + 1\n map[opts.product] = next\n persistOrdinals(file, map)\n return next\n })\n}\n\n/**\n * Reserve one strictly-later maintenance ordinal across every affected product axis.\n *\n * Unlike the best-effort run-start counter above, maintenance reservation is fail-closed: every\n * required counter must already exist and be a non-negative safe integer. The complete map is\n * persisted with one same-directory atomic replacement only after all validation succeeds.\n */\nexport async function reserveBuildOrdinalForProducts(\n opts: ReserveBuildOrdinalForProductsOptions,\n): Promise<ReserveBuildOrdinalForProductsResult> {\n const products = Object.freeze([...new Set(opts.products)].sort())\n if (products.length === 0) return undefined\n\n return withCounterLock(opts.root, () => {\n const file = join(opts.root, BUILD_ORDINALS_FILE)\n const map = readOrdinals(file, products[0]!, false)\n let maximum = 0\n\n for (const product of products) {\n if (!Object.hasOwn(map, product)) {\n throw new BuildOrdinalReservationError('missing-counter', product)\n }\n const current = map[product]!\n if (current === Number.MAX_SAFE_INTEGER) {\n throw new BuildOrdinalReservationError('counter-exhausted', product, current)\n }\n maximum = Math.max(maximum, current)\n }\n\n const ordinal = maximum + 1\n for (const product of products) map[product] = ordinal\n const reservation = Object.freeze({ products, ordinal })\n persistOrdinals(file, map, () => opts.beforePersist?.(reservation))\n return ordinal\n })\n}\n\nfunction readOrdinals(\n file: string,\n product: string,\n missingIsEmpty: boolean,\n): Record<string, number> {\n let raw: string\n try {\n raw = readFileSync(file, 'utf-8')\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n if (missingIsEmpty) return Object.create(null) as Record<string, number>\n throw new BuildOrdinalReservationError('missing-counter', product)\n }\n throw error\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n throw new BuildOrdinalReservationError('invalid-state', product)\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new BuildOrdinalReservationError('invalid-state', product, parsed)\n }\n\n const map = Object.create(null) as Record<string, number>\n for (const [key, value] of Object.entries(parsed)) {\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {\n throw new BuildOrdinalReservationError('invalid-counter', key, value)\n }\n map[key] = value\n }\n return map\n}\n","// Durable per-product build-tag resolution (Phase 375, D-14/D-16/D-17).\n//\n// The mapping lives beside build-ordinals.json at <root>/build-tags.json and records the\n// first buildOrdinal observed for each product/tag pair (spec/v2/eval-and-core-types.md §A8).\n// It deliberately mirrors the ordinal counter's lock-free, write-temp + same-dir rename\n// persistence. Concurrent writers can lose a write, but a repeated observation restores it;\n// an existing tag is never overwritten by a later ordinal. This truth is persisted because it\n// cannot be reconstructed reliably from retained evidence bundles after pruning or corruption.\n\nimport { readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { BUILD_ORDINALS_FILE } from './build-ordinal.js'\n\n/** The project-local state file holding product -> tag -> first-seen ordinal. */\nexport const BUILD_TAGS_FILE = 'build-tags.json'\n\nexport type BuildTagMap = Record<string, Record<string, number>>\n\nexport async function recordBuildTag(opts: {\n root: string\n product: string\n tag: string\n ordinal: number\n}): Promise<void> {\n const map = readBuildTagMap({ root: opts.root })\n const productTags = Object.prototype.hasOwnProperty.call(map, opts.product)\n ? map[opts.product]\n : undefined\n\n if (productTags && Object.prototype.hasOwnProperty.call(productTags, opts.tag)) return\n\n const nextMap: BuildTagMap = {\n ...map,\n [opts.product]: {\n ...productTags,\n [opts.tag]: opts.ordinal,\n },\n }\n const file = join(opts.root, BUILD_TAGS_FILE)\n const tmp = `${file}.tmp`\n writeFileSync(tmp, `${JSON.stringify(nextMap)}\\n`, 'utf-8')\n renameSync(tmp, file)\n}\n\nexport function resolveBuildTag(opts: {\n root: string\n product: string\n tag: string\n}): number | undefined {\n return readBuildTagMap({ root: opts.root })[opts.product]?.[opts.tag]\n}\n\n/** Pure read of the current per-product ordinal; never advances build-ordinals.json. */\nexport function latestBuildOrdinal(opts: { root: string; product: string }): number {\n const parsed = readJsonRecord(join(opts.root, BUILD_ORDINALS_FILE))\n const value = parsed?.[opts.product]\n return typeof value === 'number' && Number.isFinite(value) ? value : 0\n}\n\n/** Best-effort, sanitized read: missing, corrupt, and non-object state starts empty. */\nexport function readBuildTagMap(opts: { root: string }): BuildTagMap {\n const parsed = readJsonRecord(join(opts.root, BUILD_TAGS_FILE))\n if (!parsed) return {}\n\n const products: Array<[string, Record<string, number>]> = []\n for (const [product, tags] of Object.entries(parsed)) {\n if (!isRecord(tags)) continue\n\n const validTags = Object.fromEntries(\n Object.entries(tags).filter(\n (entry): entry is [string, number] =>\n typeof entry[1] === 'number' && Number.isFinite(entry[1]),\n ),\n )\n products.push([product, validTags])\n }\n\n return Object.fromEntries(products)\n}\n\nfunction readJsonRecord(file: string): Record<string, unknown> | undefined {\n try {\n const parsed: unknown = JSON.parse(readFileSync(file, 'utf-8'))\n return isRecord(parsed) ? parsed : undefined\n } catch {\n return undefined\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n","// DockerHookExecutor (Phase 363 D-06) — the runner-local storageImplementation of\n// the runner `HookExecutorPort`. The sandbox-runner body moved VERBATIM from\n// core/src/hooks/sandbox-runner.ts: image pull policy, tmpdir workdir copy of\n// file + deps + packageFile, authState mount, env + secret injection, container\n// limits (512m / 1cpu / pids256 / read-only), network-none unless hook.network,\n// /tmp/agent-qa.env variable extraction, secret-valued output-variable filtering,\n// stdout/stderr redaction, and timeout→exit-124. This is the ONLY home for\n// node:child_process / node:fs on the hook path — the runner stays storageNeutral\n// (Pitfall 3: ALL sandbox-side redaction/filtering preserved; the sink mask is\n// additive, never a replacement).\n\nimport { execFile, type ChildProcess } from 'node:child_process'\nimport { readFile, mkdtemp, mkdir, rm, cp } from 'node:fs/promises'\nimport { join, basename } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport type {\n HookDefinition,\n HookResult,\n HookRuntime,\n HookExecutorPort,\n HookExecuteOptions,\n RuntimeAuthStateConfig,\n} from '@vostride/agent-qa-runner'\nimport {\n RUNTIME_IMAGE_MAP,\n parseEnvFile,\n AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,\n AUTH_STATE_HOOK_STORAGE_STATE_FILENAME,\n AUTH_STATE_HOOK_WORKSPACE_DIR,\n buildAuthStateHookEnv,\n stripReservedAuthStateHookEnv,\n redactSecretValue,\n} from '@vostride/agent-qa-runner'\n\nconst DEFAULT_DOCKER_BIN = 'docker'\n\nexport interface DockerHookExecutorConfig {\n dockerBin?: string\n pullPolicy?: 'always' | 'if-not-present' | 'never'\n}\n\n/**\n * The D-06 hook-execution impl. Constructed once at the CLI composition root and threaded\n * into the runner `runHooks` orchestration behind the {@link HookExecutorPort}. A per-hook\n * timeout resolves a FAILED {@link HookResult} (exit-124-style error), never a throw.\n */\nexport class DockerHookExecutor implements HookExecutorPort {\n private readonly dockerBin: string\n private readonly pullPolicy: 'always' | 'if-not-present' | 'never'\n\n constructor(config: DockerHookExecutorConfig = {}) {\n this.dockerBin = config.dockerBin ?? DEFAULT_DOCKER_BIN\n this.pullPolicy = config.pullPolicy ?? 'if-not-present'\n }\n\n async execute(hook: HookDefinition, opts: HookExecuteOptions): Promise<HookResult> {\n const dockerBin = this.dockerBin\n const pullPolicy = this.pullPolicy\n const start = Date.now()\n\n const image = RUNTIME_IMAGE_MAP[hook.runtime]\n\n if (pullPolicy === 'always' || pullPolicy === 'if-not-present') {\n const needsPull = pullPolicy === 'always' || !(await imageExists(dockerBin, image))\n if (needsPull) {\n await pullImage(dockerBin, image)\n }\n }\n\n let workDir: string | undefined\n try {\n workDir = await mkdtemp(join(tmpdir(), 'agent-qa-hook-'))\n await mkdir(join(workDir, 'tmp'), { recursive: true })\n\n await cp(hook.file, join(workDir, basename(hook.file)))\n\n for (const dep of hook.deps) {\n await cp(dep, join(workDir, basename(dep)))\n }\n\n if (hook.packageFile) {\n await cp(hook.packageFile, join(workDir, basename(hook.packageFile)))\n }\n\n if (opts.authState) {\n const authStateDir = join(workDir, AUTH_STATE_HOOK_WORKSPACE_DIR)\n await mkdir(authStateDir, { recursive: true })\n await cp(opts.authState.storageStatePath, join(authStateDir, AUTH_STATE_HOOK_STORAGE_STATE_FILENAME))\n }\n\n const args = buildDockerArgs({\n image,\n workDir,\n hook,\n env: opts.env,\n secretEnv: opts.secretEnv,\n authState: opts.authState,\n })\n\n const cmd = getHookCommand(hook.runtime, basename(hook.file))\n args.push(...cmd)\n\n const { stdout, stderr, exitCode } = await execDocker(dockerBin, args, hook.timeout)\n\n let variables: Record<string, string> = {}\n try {\n const envContent = await readFile(join(workDir, 'tmp', 'agent-qa.env'), 'utf-8')\n variables = parseEnvFile(envContent)\n } catch {\n // Hook did not write .env file -- no variables to extract\n }\n variables = stripReservedAuthStateHookEnv(filterSecretVariables(variables, opts.secretEnv))\n const redactedStdout = redactSecretValue(stdout, opts.secretRedactor)\n const redactedStderr = redactSecretValue(stderr, opts.secretRedactor)\n const output = redactedStdout.trim()\n\n return {\n success: exitCode === 0,\n variables,\n output: output || redactedStderr,\n stdout: redactedStdout,\n stderr: redactedStderr,\n duration: Date.now() - start,\n error: exitCode !== 0\n ? redactSecretValue(`Hook exited with code ${exitCode}: ${stderr}`, opts.secretRedactor)\n : undefined,\n }\n } catch (err) {\n return {\n success: false,\n variables: {},\n output: '',\n stdout: '',\n stderr: '',\n duration: Date.now() - start,\n error: redactSecretValue((err as Error).message, opts.secretRedactor),\n }\n } finally {\n if (workDir) {\n await rm(workDir, { recursive: true, force: true }).catch(() => {})\n }\n }\n }\n}\n\n/**\n * Docker availability probe (re-homed from core/src/hooks/sandbox-runner.ts). The CLI\n * `doctor` command consumes this to report whether the hook sandbox can run.\n */\nexport async function checkDockerAvailable(dockerBin = DEFAULT_DOCKER_BIN): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(dockerBin, ['info', '--format', '{{.ID}}'], { timeout: 5000 }, (err) => {\n resolve(!err)\n })\n })\n}\n\nfunction getHookCommand(runtime: HookRuntime, entryFile: string): string[] {\n switch (runtime) {\n case 'node': return ['node', entryFile]\n case 'bun': return ['bun', entryFile]\n case 'python': return ['python3', entryFile]\n case 'bash': return ['bash', entryFile]\n }\n}\n\ninterface DockerArgsInput {\n image: string\n workDir: string\n hook: HookDefinition\n env: Record<string, string>\n secretEnv: Record<string, string>\n authState?: RuntimeAuthStateConfig\n}\n\nfunction buildDockerArgs(input: DockerArgsInput): string[] {\n const args = [\n 'run',\n '--rm',\n '--init',\n '-v', `${input.workDir}:/workspace`,\n '-w', '/workspace',\n '--memory', '512m',\n '--cpus', '1',\n '--pids-limit', '256',\n '--read-only',\n '-v', `${input.workDir}/tmp:/tmp`,\n ]\n\n if (!input.hook.network) {\n args.push('--network', 'none')\n }\n\n const envVars: Record<string, string> = { ...input.env }\n // Secret values overlay normal env vars in the container (already-resolved by the\n // composition root; the runner-local impl never touches the SecretStore, D-06).\n Object.assign(envVars, input.secretEnv)\n Object.assign(envVars, buildAuthStateHookEnv(\n input.authState,\n AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,\n ))\n\n for (const [k, v] of Object.entries(envVars)) {\n args.push('-e', `${k}=${v}`)\n }\n\n args.push(input.image)\n return args\n}\n\nfunction filterSecretVariables(\n variables: Record<string, string>,\n secretEnv: Record<string, string>,\n): Record<string, string> {\n const secretValues = new Set(Object.values(secretEnv))\n if (secretValues.size === 0) return variables\n return Object.fromEntries(\n Object.entries(variables).filter(([_key, value]) => !secretValues.has(value)),\n )\n}\n\nfunction imageExists(dockerBin: string, image: string): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(dockerBin, ['image', 'inspect', image], { timeout: 10000 }, (err) => {\n resolve(!err)\n })\n })\n}\n\nfunction pullImage(dockerBin: string, image: string): Promise<void> {\n return new Promise((resolve, reject) => {\n execFile(dockerBin, ['pull', image], { timeout: 120000 }, (err) => {\n if (err) reject(new Error(`Failed to pull image ${image}: ${err.message}`))\n else resolve()\n })\n })\n}\n\ninterface ExecResult {\n stdout: string\n stderr: string\n exitCode: number\n}\n\nfunction execDocker(dockerBin: string, args: string[], timeout: number): Promise<ExecResult> {\n return new Promise((resolve) => {\n let stdout = ''\n let stderr = ''\n let resolved = false\n\n const _proc: ChildProcess = execFile(dockerBin, args, { timeout, maxBuffer: 4 * 1024 * 1024 }, (err, out, errOut) => {\n if (resolved) return\n resolved = true\n\n stdout = out ?? ''\n stderr = errOut ?? ''\n\n if (err && 'killed' in err && (err as { killed?: boolean }).killed) {\n resolve({ stdout, stderr: `Hook timed out after ${timeout}ms`, exitCode: 124 })\n return\n }\n\n const exitCode = (err as { code?: number } | null)?.code ?? 0\n resolve({ stdout, stderr, exitCode: typeof exitCode === 'number' ? exitCode : 1 })\n })\n void _proc\n })\n}\n"],"mappings":"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","names":["import_node_path","import_promises","import_node_path","import_agent_qa_schema","import_node_fs","import_node_path","import_node_fs","import_node_path","import_agent_qa_schema","import_node_fs","import_node_path","import_agent_qa_schema","import_node_fs","import_node_path","import_agent_qa_schema","sharp","data","info","import_node_crypto","import_node_fs","import_node_path","import_node_fs","import_node_path","import_node_child_process","import_promises","import_node_path","resolve"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/fs-action-cache.ts","../src/branch-resolver.ts","../src/write-policy.ts","../src/storage-state-store.ts","../src/event-log.ts","../src/handoff-store.ts","../src/run-artifact-store.ts","../src/evidence-artifact-store.ts","../src/screenshot-compressor.ts","../src/build-ordinal.ts","../src/build-tag-map.ts","../src/hook-executor.ts"],"sourcesContent":["// Neutral port + key types this package's store implements. These type\n// re-exports also anchor the runner + schema workspace dependencies the\n// ownership contract declares.\nexport type { ActionPlanCache, StorageStatePort, StorageStateReference, StorageStateBlob } from '@vostride/agent-qa-runner'\nexport type { CacheKey } from '@vostride/agent-qa-schema'\n\n// Concrete filesystem store and its on-disk schema version.\nexport { FsActionCache, CACHE_SCHEMA_VERSION, purgeActionCache } from './fs-action-cache.js'\nexport type { FsActionCacheConfig } from './fs-action-cache.js'\n\n// Concrete filesystem storage-state store — raw-but-local auth persistence.\nexport { FsStorageStateStore, STORAGE_STATES_SUBDIR } from './storage-state-store.js'\nexport type { FsStorageStateStoreConfig } from './storage-state-store.js'\n\n// Injectable git-branch resolver + slug sanitizer (security V5).\nexport { resolveBranch, slugBranch } from './branch-resolver.js'\nexport type { BranchResolverOptions, ResolvedBranch } from './branch-resolver.js'\n\n// Branch write-skip policy.\nexport { shouldWrite } from './write-policy.js'\nexport type { CachePolicy } from './write-policy.js'\n\n// Runner-local persistence: event log, handoff store and build-ordinal counter.\nexport { FsEventLog, RUNS_SUBDIR, EVENTS_FILE } from './event-log.js'\nexport type { FsEventLogConfig } from './event-log.js'\nexport { FsHandoffStore, loadCompletedRunHandoff, HANDOFF_FILE } from './handoff-store.js'\nexport type { FsHandoffStoreConfig } from './handoff-store.js'\n\n// Writes `artifact.json` into the same run dir as `events.jsonl` and `handoff.json`.\nexport { FsRunArtifactStore, ARTIFACT_FILE } from './run-artifact-store.js'\nexport type { FsRunArtifactStoreConfig } from './run-artifact-store.js'\n\n// Writes decision-screenshot bytes to `blobs/<sha>` in the same run dir.\nexport { FsEvidenceArtifactStore, RUN_EVIDENCE_BLOBS_SUBDIR } from './evidence-artifact-store.js'\nexport type { FsEvidenceArtifactStoreConfig } from './evidence-artifact-store.js'\n\n// The sharp compressor and the image utilities the mobile adapters call directly.\nexport {\n SharpScreenshotCompressor,\n alignToWindow,\n flattenOntoWhite,\n getImageDimensions,\n} from './screenshot-compressor.js'\nexport type {\n AlignOptions,\n CompressOptions,\n CompressResult,\n ImageDimensions,\n ScreenshotCompressorLogger,\n} from './screenshot-compressor.js'\nexport {\n BuildOrdinalReservationError,\n nextBuildOrdinal,\n reserveBuildOrdinalForProducts,\n BUILD_ORDINALS_FILE,\n} from './build-ordinal.js'\nexport type {\n BuildOrdinalReservation,\n BuildOrdinalReservationErrorCode,\n NextBuildOrdinalOptions,\n ReserveBuildOrdinalForProductsOptions,\n ReserveBuildOrdinalForProductsResult,\n} from './build-ordinal.js'\n// Tags keep first-seen ordinals; the latest ordinal is a pure read that never advances the counter.\nexport {\n BUILD_TAGS_FILE,\n latestBuildOrdinal,\n readBuildTagMap,\n recordBuildTag,\n resolveBuildTag,\n} from './build-tag-map.js'\nexport type { BuildTagMap } from './build-tag-map.js'\n\n// The Docker hook executor; `checkDockerAvailable` serves the CLI doctor command.\nexport { DockerHookExecutor, checkDockerAvailable } from './hook-executor.js'\nexport type { DockerHookExecutorConfig } from './hook-executor.js'\n","// Concrete filesystem action-plan cache store.\n//\n// Implements the storage-neutral `ActionPlanCache` port from\n// @vostride/agent-qa-runner. On-disk layout:\n//\n// <root>/<slug(branch)>/<cacheKey>.json\n//\n// The 16-hex CacheKey is the whole filename, so no raw step text or secret can\n// appear on disk. Writes go only to the current-branch namespace. Reads fall back\n// from the current branch to the default branch unless the current branch holds a\n// suppression marker for the key. An entry stamped with any other\n// CACHE_SCHEMA_VERSION is never read as valid.\n\nimport { mkdir, readdir, readFile, rmdir, unlink, writeFile } from 'node:fs/promises'\nimport type { Dirent } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { ActionPlanCache, CachedPlanValue } from '@vostride/agent-qa-runner'\nimport type { CacheKey } from '@vostride/agent-qa-schema'\n\nimport { slugBranch } from './branch-resolver.js'\nimport { shouldWrite, type CachePolicy } from './write-policy.js'\n\n// An entry stamped with any other version reads as a miss.\nexport const CACHE_SCHEMA_VERSION = 3\n\nconst CACHE_ENTRY_FILE_RE = /^[0-9a-f]{16}\\.json$/\n\ntype CacheEnvelope =\n { schemaVersion: number; value: CachedPlanValue } | { schemaVersion: number; suppressed: true }\n\ntype ReadResult = { kind: 'value'; value: CachedPlanValue } | { kind: 'suppressed' } | null\n\nexport interface FsActionCacheConfig {\n /** Cache root (e.g. DEFAULT_AGENT_QA_CACHE_DIR = '.agent-qa/cache'). */\n root: string\n /** Resolved branch context + write policy (branch + CI + flags). */\n policy: CachePolicy\n}\n\nexport class FsActionCache implements ActionPlanCache {\n private readonly root: string\n private readonly policy: CachePolicy\n private readonly skipped = new Set<CacheKey>()\n\n constructor(config: FsActionCacheConfig) {\n this.root = config.root\n this.policy = config.policy\n }\n\n async get(key: CacheKey): Promise<CachedPlanValue | null> {\n if (this.policy.disableCache || this.skipped.has(key)) return null\n\n const onCurrent = await this.readEntry(this.policy.currentBranch, key)\n if (onCurrent?.kind === 'suppressed') return null\n if (onCurrent?.kind === 'value') return onCurrent.value\n\n if (this.policy.currentBranch !== this.policy.defaultBranch) {\n const onDefault = await this.readEntry(this.policy.defaultBranch, key)\n return onDefault?.kind === 'value' ? onDefault.value : null\n }\n return null\n }\n\n async set(key: CacheKey, value: CachedPlanValue): Promise<void> {\n if (!shouldWrite(this.policy)) return\n await this.writeEnvelope(key, { schemaVersion: CACHE_SCHEMA_VERSION, value })\n }\n\n async invalidate(key: CacheKey): Promise<void> {\n // A run that may not write the cache never deletes or marks an entry; it skips the key\n // for the rest of this store's life, and the next run that may write replaces the entry.\n if (!shouldWrite(this.policy)) {\n this.skipped.add(key)\n return\n }\n const { currentBranch, defaultBranch } = this.policy\n // The default branch's entry is never changed from another branch: a marker on the\n // current branch hides it instead.\n if (currentBranch !== defaultBranch) {\n const onDefault = await this.readEntry(defaultBranch, key)\n if (onDefault?.kind === 'value') {\n await this.writeEnvelope(key, { schemaVersion: CACHE_SCHEMA_VERSION, suppressed: true })\n return\n }\n }\n try {\n await unlink(this.entryPath(this.branchDir(currentBranch), key))\n } catch (err) {\n if (!isMissing(err)) throw err\n }\n }\n\n private async writeEnvelope(key: CacheKey, envelope: CacheEnvelope): Promise<void> {\n const dir = this.branchDir(this.policy.currentBranch)\n await mkdir(dir, { recursive: true })\n await writeFile(this.entryPath(dir, key), `${JSON.stringify(envelope, null, 2)}\\n`, 'utf-8')\n }\n\n private branchDir(branch: string): string {\n return join(this.root, slugBranch(branch))\n }\n\n private entryPath(dir: string, key: CacheKey): string {\n return join(dir, `${key}.json`)\n }\n\n private async readEntry(branch: string, key: CacheKey): Promise<ReadResult> {\n let raw: string\n try {\n raw = await readFile(this.entryPath(this.branchDir(branch), key), 'utf-8')\n } catch (err) {\n if (isMissing(err)) return null\n throw err\n }\n\n let envelope: Partial<{ schemaVersion: number; value: CachedPlanValue; suppressed: boolean }>\n try {\n envelope = JSON.parse(raw) as typeof envelope\n } catch {\n return null // corrupt/partial entry is a miss, never a crash\n }\n\n if (envelope?.schemaVersion !== CACHE_SCHEMA_VERSION) return null\n if (envelope.suppressed === true) return { kind: 'suppressed' }\n return envelope.value ? { kind: 'value', value: envelope.value } : null\n }\n}\n\nfunction isMissing(err: unknown): boolean {\n return (err as NodeJS.ErrnoException).code === 'ENOENT'\n}\n\n/**\n * Removes every `<root>/<branch-slug>/<16-hex>.json` entry, and a branch directory only when that\n * leaves it empty. Nothing else under `root` is touched, so a cache root that also holds other\n * files keeps them. Returns the number of entries removed.\n */\nexport async function purgeActionCache(root: string): Promise<number> {\n let branches: Dirent[]\n try {\n branches = await readdir(root, { withFileTypes: true })\n } catch (err) {\n if (isMissing(err)) return 0\n throw err\n }\n\n let purged = 0\n for (const branch of branches) {\n if (!branch.isDirectory() || slugBranch(branch.name) !== branch.name) continue\n const dir = join(root, branch.name)\n const entries = await readdir(dir, { withFileTypes: true })\n let removed = 0\n for (const entry of entries) {\n if (!entry.isFile() || !CACHE_ENTRY_FILE_RE.test(entry.name)) continue\n try {\n await unlink(join(dir, entry.name))\n } catch (err) {\n if (!isMissing(err)) throw err\n }\n removed++\n }\n purged += removed\n if (removed > 0 && removed === entries.length) {\n await rmdir(dir).catch(() => {})\n }\n }\n return purged\n}\n","// Degrades to the configured default in a git-less directory; it never imports safety-local.\n\nimport { execFileSync } from 'node:child_process'\nimport { readFileSync, statSync } from 'node:fs'\nimport { join, resolve } from 'node:path'\n\nimport { slugBranch } from '@vostride/agent-qa-schema'\n\n// Preserve runner-local's public surface while schema owns the ONE pure sanitizer.\nexport { slugBranch }\n\nconst HEAD_REF_RE = /^ref:\\s*refs\\/heads\\/(.+?)\\s*$/m\nconst GITDIR_RE = /^gitdir:\\s*(.+)$/m\n\nexport interface ResolvedBranch {\n /** The branch the run is on; falls back to defaultBranch when undetectable. */\n currentBranch: string\n /** The remote default branch; falls back to the configured default -> main. */\n defaultBranch: string\n}\n\nexport interface BranchResolverOptions {\n /** Directory to resolve git state from (default process.cwd()). */\n cwd?: string\n /** Configured default branch, used when the remote default is undetectable. */\n configuredDefault?: string\n /** Injected .git/HEAD reader — returns raw file content or null. */\n readHead?: (cwd: string) => string | null\n /** Injected `git symbolic-ref refs/remotes/origin/HEAD` reader — raw or null. */\n runSymbolicRef?: (cwd: string) => string | null\n}\n\n/**\n * Resolve the current + default branch names. Both are returned raw (un-slugged);\n * the fs store slugs each before it becomes a path segment. Never throws.\n */\nexport function resolveBranch(opts: BranchResolverOptions = {}): ResolvedBranch {\n const cwd = opts.cwd ?? process.cwd()\n const readHead = opts.readHead ?? defaultReadHead\n const runSymbolicRef = opts.runSymbolicRef ?? defaultRunSymbolicRef\n\n const defaultBranch =\n parseSymbolicRef(safe(() => runSymbolicRef(cwd))) ?? opts.configuredDefault ?? 'main'\n const currentBranch = parseHeadBranch(safe(() => readHead(cwd))) ?? defaultBranch\n\n return { currentBranch, defaultBranch }\n}\n\nfunction parseHeadBranch(head: string | null): string | null {\n if (head === null) return null\n const match = HEAD_REF_RE.exec(head)\n return match ? match[1] : null // detached HEAD (a raw sha) yields null\n}\n\nfunction parseSymbolicRef(output: string | null): string | null {\n if (output === null) return null\n const trimmed = output.trim()\n if (trimmed === '') return null\n const name = trimmed.slice(trimmed.lastIndexOf('/') + 1)\n return name.length > 0 ? name : null\n}\n\nfunction defaultReadHead(cwd: string): string | null {\n try {\n const gitPath = join(cwd, '.git')\n const stat = statSync(gitPath)\n if (stat.isDirectory()) {\n return readFileSync(join(gitPath, 'HEAD'), 'utf-8')\n }\n // .git is a file (submodule / worktree): `gitdir: <path>`.\n const pointer = readFileSync(gitPath, 'utf-8')\n const match = GITDIR_RE.exec(pointer)\n if (match === null) return null\n const gitdir = resolve(cwd, match[1].trim())\n return readFileSync(join(gitdir, 'HEAD'), 'utf-8')\n } catch {\n return null\n }\n}\n\n/** Default git ABI: the 5s bound below caps the synchronous subprocess. */\nconst DEFAULT_GIT_SYMBOLIC_REF_TIMEOUT_MS = 5000\n\ntype GitExec = (\n command: string,\n args: string[],\n options: {\n cwd: string\n encoding: 'utf-8'\n stdio: ['ignore', 'pipe', 'ignore']\n timeout: number\n },\n) => string\n\ninterface RunGitSymbolicRefOptions {\n /** Bound (ms) on the synchronous git subprocess; ETIMEDOUT degrades to null. */\n timeoutMs?: number\n /** Injected exec seam for tests — defaults to node:child_process execFileSync. */\n exec?: GitExec\n}\n\n// A finite timeout so the subprocess never wedges branch resolution; any failure answers `null`.\nexport function runGitSymbolicRef(\n cwd: string,\n options: RunGitSymbolicRefOptions = {},\n): string | null {\n const exec = options.exec ?? (execFileSync as unknown as GitExec)\n const timeout = options.timeoutMs ?? DEFAULT_GIT_SYMBOLIC_REF_TIMEOUT_MS\n try {\n return exec('git', ['symbolic-ref', 'refs/remotes/origin/HEAD'], {\n cwd,\n encoding: 'utf-8',\n stdio: ['ignore', 'pipe', 'ignore'],\n timeout,\n })\n } catch {\n return null\n }\n}\n\nfunction defaultRunSymbolicRef(cwd: string): string | null {\n return runGitSymbolicRef(cwd)\n}\n\nfunction safe(read: () => string | null): string | null {\n try {\n return read()\n } catch {\n return null\n }\n}\n","// Branch is a storage namespace, never a cache-key component; this governs writes only.\n\nexport interface CachePolicy {\n /** The branch the current run executes on (raw, un-slugged). */\n currentBranch: string\n /** The repo's default branch (raw, un-slugged) — the read-fallback namespace. */\n defaultBranch: string\n /** default branch ∪ any configured protected branches. */\n protectedBranches: readonly string[]\n /** Resolved in the CLI (reusing the CI vendor-var set), passed in here. */\n isCI: boolean\n /** `--save-cache` — force writes even on a protected branch. */\n saveCache: boolean\n /** `--disable-cache` — short-circuit both reads and writes. */\n disableCache: boolean\n}\n\n// Skipped on a protected branch unless `--save-cache` or CI; `--disable-cache` forbids all writes.\nexport function shouldWrite(policy: CachePolicy): boolean {\n if (policy.disableCache) return false\n const protectedNow = policy.protectedBranches.includes(policy.currentBranch)\n return !protectedNow || policy.saveCache || policy.isCI\n}\n","// Raw auth material, written verbatim and never masked; `save` returns only name and fingerprint.\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { join } from 'node:path'\n\nimport { sha256hex16 } from '@vostride/agent-qa-schema'\nimport type { StorageStateBlob, StorageStatePort, StorageStateReference } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\n\n/** Subdirectory under the runtime root holding the raw storage-state blobs. */\nexport const STORAGE_STATES_SUBDIR = 'storage-states'\n\nexport interface FsStorageStateStoreConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n}\n\nexport class FsStorageStateStore implements StorageStatePort {\n private readonly root: string\n\n constructor(config: FsStorageStateStoreConfig) {\n this.root = config.root\n }\n\n async save(name: string, state: StorageStateBlob): Promise<StorageStateReference> {\n const dir = this.storageStatesDir()\n await mkdir(dir, { recursive: true })\n // Deterministic JSON so an identical blob fingerprints identically across runs.\n const serialized = JSON.stringify(state)\n await writeFile(this.entryPath(name), `${serialized}\\n`, 'utf-8')\n // 343 fingerprint() idiom — the shipped sha256hex16 determinism primitive, never hand-rolled.\n return { name, fingerprint: sha256hex16(serialized) }\n }\n\n async load(name: string): Promise<StorageStateBlob | undefined> {\n let raw: string\n try {\n raw = await readFile(this.entryPath(name), 'utf-8')\n } catch (err) {\n // A missing slot is never an error — undefined, no throw.\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw err\n }\n try {\n return JSON.parse(raw) as StorageStateBlob\n } catch {\n // A corrupt/partial blob reads as absent rather than crashing the run.\n return undefined\n }\n }\n\n private storageStatesDir(): string {\n return join(this.root, STORAGE_STATES_SUBDIR)\n }\n\n private entryPath(name: string): string {\n // `slugBranch` makes the name one safe path segment inside `storage-states/`.\n return join(this.storageStatesDir(), `${slugBranch(name)}.json`)\n }\n}\n","// One synchronous append per envelope; the reader drops a torn final line instead of failing.\n\nimport { appendFileSync, mkdirSync, readFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport type { RunEventEnvelope } from '@vostride/agent-qa-schema'\nimport type { EventLogPort } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\n\n/** Subdirectory under the runtime root holding per-run event logs. */\nexport const RUNS_SUBDIR = 'runs'\n\n/** The single JSONL file name each run appends its event stream to. */\nexport const EVENTS_FILE = 'events.jsonl'\n\nexport interface FsEventLogConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The run this log belongs to; slugged before it becomes a path segment. */\n runId: string\n}\n\nexport class FsEventLog implements EventLogPort {\n private readonly dir: string\n private readonly file: string\n\n constructor(config: FsEventLogConfig) {\n // `slugBranch` makes the run id one safe path segment that never leaves `runs/`.\n this.dir = join(config.root, RUNS_SUBDIR, slugBranch(config.runId))\n this.file = join(this.dir, EVENTS_FILE)\n }\n\n append(envelope: RunEventEnvelope): void {\n // mkdir-recursive then a single synchronous appendFileSync of one line.\n mkdirSync(this.dir, { recursive: true })\n appendFileSync(this.file, `${JSON.stringify(envelope)}\\n`)\n }\n\n read(fromSeq: number): RunEventEnvelope[] {\n let raw: string\n try {\n raw = readFileSync(this.file, 'utf-8')\n } catch (err) {\n // No log yet ⇒ empty replay, never an error.\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return []\n throw err\n }\n const out: RunEventEnvelope[] = []\n for (const line of raw.split('\\n')) {\n if (line.length === 0) continue\n let parsed: RunEventEnvelope\n try {\n parsed = JSON.parse(line) as RunEventEnvelope\n } catch {\n // A torn/partial final line is dropped — the reader never throws on garbage.\n continue\n }\n if (parsed.seq >= fromSeq) out.push(parsed)\n }\n return out\n }\n}\n","// The read side delegates to the schema's one handoff version rule and re-implements none.\n\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { guardCompletedRunHandoff } from '@vostride/agent-qa-schema'\nimport type { CompletedRunHandoff } from '@vostride/agent-qa-schema'\nimport type { HandoffStorePort } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\nimport { RUNS_SUBDIR } from './event-log.js'\n\n/** The single JSON document each run writes its completed-run handoff to. */\nexport const HANDOFF_FILE = 'handoff.json'\n\nexport interface FsHandoffStoreConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The run this handoff belongs to; slugged before it becomes a path segment. */\n runId: string\n}\n\nexport class FsHandoffStore implements HandoffStorePort {\n private readonly dir: string\n private readonly file: string\n\n constructor(config: FsHandoffStoreConfig) {\n // Same slugged run dir as FsEventLog so handoff.json lands beside events.jsonl.\n this.dir = join(config.root, RUNS_SUBDIR, slugBranch(config.runId))\n this.file = join(this.dir, HANDOFF_FILE)\n }\n\n save(handoff: CompletedRunHandoff): void {\n mkdirSync(this.dir, { recursive: true })\n writeFileSync(this.file, `${JSON.stringify(handoff)}\\n`, 'utf-8')\n }\n}\n\n// A newer schema version surfaces the schema's typed `HandoffVersionError`.\nexport function loadCompletedRunHandoff(filePath: string): CompletedRunHandoff {\n const raw = readFileSync(filePath, 'utf-8')\n return guardCompletedRunHandoff(JSON.parse(raw))\n}\n","// Only config, source, terminal errors and metadata; incoming top-level `runtime` is stripped.\n\nimport { mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { RUN_ARTIFACT_SCHEMA_VERSION } from '@vostride/agent-qa-schema'\nimport type {\n RunArtifactFinalizeInput,\n RunArtifactPayload,\n RunArtifactStageInput,\n} from '@vostride/agent-qa-schema'\nimport type { RunArtifactStorePort } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\nimport { RUNS_SUBDIR } from './event-log.js'\n\n/** The single JSON document each run writes its run artifact to. */\nexport const ARTIFACT_FILE = 'artifact.json'\n\nexport interface FsRunArtifactStoreConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The run this artifact belongs to; slugged before it becomes a path segment. */\n runId: string\n}\n\n/** The persisted artifact document shape (schema-stamped, runtime-free). */\ntype PersistedArtifact = Omit<RunArtifactPayload, 'runtime'> & { finalizedAt?: string }\n\nexport class FsRunArtifactStore implements RunArtifactStorePort {\n private readonly dir: string\n private readonly file: string\n\n constructor(config: FsRunArtifactStoreConfig) {\n // Same slugged run dir as FsEventLog so artifact.json lands beside events.jsonl.\n this.dir = join(config.root, RUNS_SUBDIR, slugBranch(config.runId))\n this.file = join(this.dir, ARTIFACT_FILE)\n }\n\n stage(document: RunArtifactStageInput): void {\n const persisted = this.merge({ schemaVersion: RUN_ARTIFACT_SCHEMA_VERSION }, document)\n this.write(persisted)\n }\n\n finalize(patch: RunArtifactFinalizeInput): void {\n const base = this.readExisting() ?? { schemaVersion: RUN_ARTIFACT_SCHEMA_VERSION }\n const persisted = this.merge(base, patch)\n this.write(persisted)\n }\n\n /** Shallow-merge a stage/finalize input onto the base, always dropping the top-level runtime. */\n private merge(base: PersistedArtifact, input: RunArtifactStageInput | RunArtifactFinalizeInput): PersistedArtifact {\n const { runtime: _dropRuntime, ...rest } = input as RunArtifactStageInput & { runtime?: unknown }\n const merged: PersistedArtifact = {\n ...base,\n ...rest,\n schemaVersion: RUN_ARTIFACT_SCHEMA_VERSION,\n }\n delete (merged as { runtime?: unknown }).runtime\n return merged\n }\n\n private readExisting(): PersistedArtifact | undefined {\n try {\n return JSON.parse(readFileSync(this.file, 'utf-8')) as PersistedArtifact\n } catch (err) {\n // No staged artifact yet (crash before stage) ⇒ start fresh, never throw on the read leg.\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw err\n }\n }\n\n private write(document: PersistedArtifact): void {\n mkdirSync(this.dir, { recursive: true })\n writeFileSync(this.file, `${JSON.stringify(document)}\\n`, 'utf-8')\n }\n}\n","// Filenames are the SHA-256 of their bytes; the sha shape is checked before any path use.\n\nimport { createHash, randomUUID } from 'node:crypto'\nimport {\n closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync,\n unlinkSync, writeFileSync,\n} from 'node:fs'\nimport { dirname, join } from 'node:path'\nimport { chmodSync, copyFileSync, fstatSync, readSync, realpathSync, statSync } from 'node:fs'\nimport { isAbsolute, relative, resolve, sep } from 'node:path'\nimport { RECORDING_REF_PREFIX } from '@vostride/agent-qa-schema'\nimport type { PersistedRecording } from '@vostride/agent-qa-runner'\n\nimport type { ArtifactRef, EvidenceDocument } from '@vostride/agent-qa-schema'\nimport { EvidenceArtifactRefSchema, EvidenceDocumentSchema } from '@vostride/agent-qa-schema'\nimport type { EvidenceArtifactStorePort } from '@vostride/agent-qa-runner'\n\nimport { slugBranch } from './branch-resolver.js'\nimport { RUNS_SUBDIR } from './event-log.js'\n\n/** Subdirectory under each slugged run dir holding the content-addressed evidence blobs. */\nexport const RUN_EVIDENCE_BLOBS_SUBDIR = 'blobs'\n\nconst SHA256_HEX_RE = /^[0-9a-f]{64}$/\n\nconst DIRECTORY_SYNC_TOLERATED_CODES = ['EINVAL', 'EPERM', 'ENOTSUP', 'EOPNOTSUPP', 'EBADF', 'EISDIR'] as const\n\nexport interface FsEvidenceArtifactStoreConfig {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The run these blobs belong to; slugged before it becomes a path segment. */\n runId: string\n}\n\nexport class FsEvidenceArtifactStore implements EvidenceArtifactStorePort {\n private readonly dir: string\n private readonly durabilityRoot: string\n\n constructor(config: FsEvidenceArtifactStoreConfig) {\n this.dir = join(config.root, RUNS_SUBDIR, slugBranch(config.runId), RUN_EVIDENCE_BLOBS_SUBDIR)\n this.durabilityRoot = dirname(join(config.root, '.'))\n }\n\n persistDecisionScreenshot(bytes: Uint8Array): ArtifactRef {\n const sha = createHash('sha256').update(bytes).digest('hex')\n mkdirSync(this.dir, { recursive: true })\n writeFileSync(join(this.dir, sha), bytes)\n return { id: `decision-screenshot:${sha}`, sha }\n }\n\n persistEvidenceDocument(document: Exclude<EvidenceDocument, { kind: 'variables' }>): ArtifactRef {\n // Validate the actual serialization, but retain its exact property/record order. Parsing\n // and reserializing a Zod object would reorder keys and change the content address.\n const bytes = Buffer.from(JSON.stringify(document))\n const parsed = EvidenceDocumentSchema.parse(JSON.parse(bytes.toString('utf8')))\n if (parsed.kind === 'variables') throw new Error('Variable evidence is stored inline')\n const sha = createHash('sha256').update(bytes).digest('hex')\n const prefix = parsed.kind === 'aria' ? 'aria-state:' : `${parsed.kind}-evidence:`\n const ref = EvidenceArtifactRefSchema.parse({ id: `${prefix}${sha}`, sha })\n mkdirSync(this.dir, { recursive: true })\n const target = join(this.dir, sha)\n const existing = this.getBlob(sha)\n if (existing !== undefined && Buffer.from(existing).equals(bytes)) {\n // A competing writer may have renamed but not synced its directory yet. Confirm both\n // the complete file and directory ourselves before returning the deduplicated ref.\n this.syncPath(target)\n this.syncDirectories()\n return ref\n }\n const temporary = join(this.dir, `.${sha}.${randomUUID()}.tmp`)\n const fd = openSync(temporary, 'wx', 0o600)\n let opened = true\n try {\n writeFileSync(fd, bytes)\n fsyncSync(fd)\n closeSync(fd)\n opened = false\n // Concurrent identical documents have identical complete bytes. Replacing either\n // complete inode is safe; a reader can never observe the temporary partial content.\n renameSync(temporary, target)\n this.syncDirectories()\n return ref\n } finally {\n if (opened) closeSync(fd)\n try {\n unlinkSync(temporary)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n }\n }\n\n private syncDirectories(): void {\n // mkdir(recursive) may have created any part of the run family. Sync each parent\n // entry as well, including when a competing writer created it before this call.\n for (let path = this.dir; ; path = dirname(path)) {\n try {\n this.syncPath(path)\n } catch (error) {\n // The file bytes were synced before rename. Some filesystems refuse directory fsync,\n // and that refusal is not data loss.\n const code = (error as NodeJS.ErrnoException).code\n if (!DIRECTORY_SYNC_TOLERATED_CODES.some(tolerated => tolerated === code)) throw error\n }\n if (path === this.durabilityRoot || dirname(path) === path) return\n }\n }\n\n private syncPath(path: string): void {\n const fd = openSync(path, 'r')\n try {\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n }\n\n hasBlob(sha: string): boolean {\n if (!SHA256_HEX_RE.test(sha)) return false\n return existsSync(join(this.dir, sha))\n }\n\n persistRecording(stagingPath: string): PersistedRecording {\n this.assertRecordingStagingPath(stagingPath)\n let recordingTemp: string | undefined\n try {\n const byteLength = statSync(stagingPath).size\n if (byteLength === 0) throw new Error('Cannot persist an empty recording')\n const hash = createHash('sha256')\n const fd = openSync(stagingPath, 'r')\n try {\n const chunk = Buffer.allocUnsafe(1024 * 1024)\n let total = 0\n for (;;) {\n const count = readSync(fd, chunk, 0, chunk.length, null)\n if (count === 0) break\n total += count\n hash.update(chunk.subarray(0, count))\n }\n if (total !== byteLength) throw new Error('Recording changed while hashing')\n } finally {\n closeSync(fd)\n }\n const sha = hash.digest('hex')\n const result: PersistedRecording = {\n ref: { id: `${RECORDING_REF_PREFIX}${sha}`, sha }, byteLength,\n }\n mkdirSync(this.dir, { recursive: true })\n const target = join(this.dir, sha)\n if (this.blobSize(sha) !== undefined) {\n this.syncPath(target)\n this.syncDirectories()\n return result\n }\n recordingTemp = join(this.dir, `.${sha}.${randomUUID()}.tmp`)\n try {\n renameSync(stagingPath, recordingTemp)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EXDEV') throw error\n copyFileSync(stagingPath, recordingTemp)\n }\n chmodSync(recordingTemp, 0o600)\n this.syncPath(recordingTemp)\n renameSync(recordingTemp, target)\n this.syncDirectories()\n return result\n } finally {\n try {\n if (recordingTemp !== undefined) this.unlinkRecordingStaging(recordingTemp)\n } finally {\n this.unlinkRecordingStaging(stagingPath)\n }\n }\n }\n\n blobSize(sha: string): number | undefined {\n if (!SHA256_HEX_RE.test(sha)) return undefined\n try {\n return statSync(join(this.dir, sha)).size\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw error\n }\n }\n\n readBlobRange(sha: string, start: number, end: number): Uint8Array | undefined {\n if (!SHA256_HEX_RE.test(sha)) return undefined\n if (!Number.isSafeInteger(start) || !Number.isSafeInteger(end) || start < 0 || end < start) return undefined\n let fd: number\n try {\n fd = openSync(join(this.dir, sha), 'r')\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw error\n }\n try {\n const size = fstatSync(fd).size\n if (start >= size) return undefined\n const length = Math.min(end, size - 1) - start + 1\n const bytes = new Uint8Array(length)\n let offset = 0\n while (offset < length) {\n const count = readSync(fd, bytes, offset, length - offset, start + offset)\n if (count === 0) throw new Error('Recording blob ended before the requested range')\n offset += count\n }\n return bytes\n } finally {\n closeSync(fd)\n }\n }\n\n discardRecording(stagingPath: string): void {\n this.assertRecordingStagingPath(stagingPath)\n this.unlinkRecordingStaging(stagingPath)\n }\n\n private assertRecordingStagingPath(stagingPath: string): void {\n const inside = (dir: string, path: string) => {\n const tail = relative(dir, path)\n return tail === '' || (tail !== '..' && !tail.startsWith(`..${sep}`) && !isAbsolute(tail))\n }\n if (inside(resolve(this.dir), resolve(stagingPath))) {\n throw new Error('Recording staging path must be outside the evidence blob directory')\n }\n try {\n if (inside(realpathSync(this.dir), realpathSync(stagingPath))) {\n throw new Error('Recording staging path must be outside the evidence blob directory')\n }\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n }\n\n private unlinkRecordingStaging(path: string): void {\n try {\n unlinkSync(path)\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error\n }\n }\n\n getBlob(sha: string): Uint8Array | undefined {\n if (!SHA256_HEX_RE.test(sha)) return undefined\n try {\n return new Uint8Array(readFileSync(join(this.dir, sha)))\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw err\n }\n }\n}\n","// The host home for `sharp`, which the storage-neutral runner bans.\n\nimport sharp from 'sharp'\nimport type { CompressedScreenshot, ScreenshotCompressor } from '@vostride/agent-qa-runner'\n\n/** Minimal structural debug-logger seam (a core `ScopedLogger` satisfies it; no core dependency). */\nexport interface ScreenshotCompressorLogger {\n debug(message: string, meta?: Record<string, unknown>): void\n}\n\nconst STARTING_QUALITY = 70\nconst QUALITY_REDUCTION = 0.8\nconst MIN_QUALITY = 10\n\nexport interface CompressOptions {\n effectiveResolution: number\n maxBytes?: number\n actionSpaceWidth: number\n}\n\nexport interface CompressResult {\n buffer: Buffer\n imageWidth: number\n imageHeight: number\n}\n\n// `fit: 'inside'` keeps aspect ratio; the JPEG pass only lowers quality and never re-resizes.\nasync function compressScreenshot(\n buffer: Buffer,\n opts: CompressOptions,\n logger?: ScreenshotCompressorLogger,\n): Promise<CompressResult> {\n const originalKB = (buffer.length / 1024).toFixed(1)\n const meta = await sharp(buffer).metadata()\n const srcWidth = meta.width ?? opts.actionSpaceWidth\n const srcHeight = meta.height ?? 0\n const targetEdge = opts.effectiveResolution\n\n let resizePipeline = sharp(buffer)\n if (srcWidth > targetEdge || srcHeight > targetEdge) {\n resizePipeline = resizePipeline.resize({\n width: targetEdge,\n height: targetEdge,\n fit: 'inside',\n withoutEnlargement: true,\n kernel: 'lanczos3',\n })\n }\n const afterResize = await resizePipeline.toBuffer({ resolveWithObject: true })\n const resizedWidth = afterResize.info.width\n const resizedHeight = afterResize.info.height\n\n // Skip JPEG pass if no byte budget set.\n if (!opts.maxBytes) {\n return { buffer: afterResize.data, imageWidth: resizedWidth, imageHeight: resizedHeight }\n }\n\n const maxBytes = opts.maxBytes\n const targetKB = (maxBytes / 1024).toFixed(1)\n\n let quality = STARTING_QUALITY\n while (quality > MIN_QUALITY) {\n const { data, info } = await sharp(afterResize.data)\n .jpeg({ quality, mozjpeg: true })\n .toBuffer({ resolveWithObject: true })\n\n if (info.size <= maxBytes) {\n logger?.debug('Compressed screenshot', {\n originalKB: parseFloat(originalKB),\n compressedKB: parseFloat((info.size / 1024).toFixed(1)),\n targetKB: parseFloat(targetKB),\n quality,\n })\n return { buffer: data, imageWidth: resizedWidth, imageHeight: resizedHeight }\n }\n quality = Math.max(MIN_QUALITY, Math.round(quality * QUALITY_REDUCTION))\n }\n\n // Graceful fallback: return best-effort at minimum quality.\n const { data, info } = await sharp(afterResize.data)\n .jpeg({ quality: MIN_QUALITY, mozjpeg: true })\n .toBuffer({ resolveWithObject: true })\n logger?.debug('Compressed screenshot (exceeded target)', {\n originalKB: parseFloat(originalKB),\n compressedKB: parseFloat(((info as { size: number }).size / 1024).toFixed(1)),\n targetKB: parseFloat(targetKB),\n quality: MIN_QUALITY,\n })\n return { buffer: data, imageWidth: resizedWidth, imageHeight: resizedHeight }\n}\n\n// Pixel-level only: the loop stamps the capture mode itself.\nexport class SharpScreenshotCompressor implements ScreenshotCompressor {\n constructor(private readonly logger?: ScreenshotCompressorLogger) {}\n\n async compress(\n screenshot: Buffer,\n options: { effectiveResolution: number; maxBytes?: number; actionSpaceWidth: number },\n ): Promise<CompressedScreenshot> {\n return compressScreenshot(screenshot, options, this.logger)\n }\n\n async dimensions(screenshot: Buffer): Promise<{ width: number; height: number }> {\n const meta = await sharp(screenshot).metadata()\n return { width: meta.width ?? 0, height: meta.height ?? 0 }\n }\n}\n\nexport interface AlignOptions {\n width: number\n height: number\n}\n\n/** Resize buffer to exact window dimensions. Used by mobile adapters for action-space alignment\n * (e.g., iOS physical pixels → logical points). */\nexport async function alignToWindow(buffer: Buffer, opts: AlignOptions): Promise<Buffer> {\n return sharp(buffer)\n .resize({ width: opts.width, height: opts.height, kernel: 'lanczos3', fit: 'fill' })\n .png()\n .toBuffer()\n}\n\nexport interface ImageDimensions {\n width: number\n height: number\n}\n\n// Reads width and height without decoding pixels.\nexport async function getImageDimensions(buffer: Buffer): Promise<ImageDimensions | undefined> {\n const meta = await sharp(buffer).metadata()\n if (!meta.width || !meta.height) return undefined\n return { width: meta.width, height: meta.height }\n}\n\nexport async function flattenOntoWhite(buffer: Buffer): Promise<Buffer> {\n const meta = await sharp(buffer).metadata()\n if (!meta.hasAlpha) return buffer\n return sharp(buffer).flatten({ background: '#ffffff' }).png().toBuffer()\n}\n","// Increments are serialized across processes and durably replaced, so no update is lost.\n\nimport { randomUUID } from 'node:crypto'\nimport {\n closeSync,\n fsyncSync,\n linkSync,\n mkdirSync,\n openSync,\n readFileSync,\n renameSync,\n rmSync,\n writeFileSync,\n} from 'node:fs'\nimport { dirname, join } from 'node:path'\n\n/** The project-local state file holding the per-product ordinal map. */\nexport const BUILD_ORDINALS_FILE = 'build-ordinals.json'\n\nexport interface NextBuildOrdinalOptions {\n /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */\n root: string\n /** The product whose counter to advance. */\n product: string\n}\n\nexport interface BuildOrdinalReservation {\n /** Canonical, sorted, duplicate-free product axes advanced by the reservation. */\n products: readonly string[]\n /** One ordinal strictly later than every affected product's current counter. */\n ordinal: number\n}\n\nexport type BuildOrdinalReservationErrorCode =\n | 'invalid-state'\n | 'missing-counter'\n | 'invalid-counter'\n | 'counter-exhausted'\n\n/** Typed pre-persistence refusal for an unsafe maintenance ordinal reservation. */\nexport class BuildOrdinalReservationError extends Error {\n readonly name = 'BuildOrdinalReservationError'\n readonly code: BuildOrdinalReservationErrorCode\n readonly product: string\n readonly value?: unknown\n\n constructor(\n code: BuildOrdinalReservationErrorCode,\n product: string,\n value?: unknown,\n ) {\n const message =\n code === 'invalid-state'\n ? `${BUILD_ORDINALS_FILE} must contain a JSON object`\n : code === 'missing-counter'\n ? `Missing build ordinal counter for product ${JSON.stringify(product)}`\n : code === 'invalid-counter'\n ? `Build ordinal counter for product ${JSON.stringify(product)} must be a non-negative safe integer`\n : `Build ordinal counter for product ${JSON.stringify(product)} is exhausted`\n super(message)\n this.code = code\n this.product = product\n this.value = value\n }\n}\n\nexport interface ReserveBuildOrdinalForProductsOptions {\n /** Runtime root containing build-ordinals.json. */\n root: string\n /** Product axes whose counters must advance together. Duplicates and order are ignored. */\n products: Iterable<string>\n /**\n * Synchronous authority fence invoked after the complete temp file is prepared and immediately\n * before the atomic rename. Throwing refuses persistence and removes the temp file.\n */\n beforePersist?: (reservation: BuildOrdinalReservation) => void\n}\n\n/** Undefined is the explicit no-op result for an empty affected-product set. */\nexport type ReserveBuildOrdinalForProductsResult = number | undefined\n\ninterface CounterLockOwner {\n pid: number\n token: string\n}\n\nconst BUILD_ORDINALS_LOCK_FILE = '.build-ordinals.lock'\nconst COUNTER_LOCK_POLL_MS = 5\nconst COUNTER_LOCK_WAIT = new Int32Array(new SharedArrayBuffer(Int32Array.BYTES_PER_ELEMENT))\n\nfunction fsyncDirectory(dir: string): void {\n let fd: number | undefined\n try {\n fd = openSync(dir, 'r')\n fsyncSync(fd)\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code\n if (code !== 'EINVAL' && code !== 'EISDIR' && code !== 'EPERM' && code !== 'ENOTSUP') {\n throw error\n }\n } finally {\n if (fd !== undefined) closeSync(fd)\n }\n}\n\nfunction durableExclusiveFile(file: string, text: string): void {\n const fd = openSync(file, 'wx')\n try {\n writeFileSync(fd, text, 'utf8')\n fsyncSync(fd)\n } finally {\n closeSync(fd)\n }\n}\n\nfunction parsedLockOwner(file: string): CounterLockOwner | undefined {\n try {\n const value = JSON.parse(readFileSync(file, 'utf8')) as unknown\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return undefined\n const owner = value as Record<string, unknown>\n return typeof owner.pid === 'number'\n && Number.isSafeInteger(owner.pid)\n && owner.pid > 0\n && typeof owner.token === 'string'\n && owner.token !== ''\n ? { pid: owner.pid, token: owner.token }\n : undefined\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return undefined\n throw error\n }\n}\n\nfunction processIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code\n if (code === 'ESRCH') return false\n if (code === 'EPERM') return true\n throw error\n }\n}\n\nfunction withCounterLock<T>(root: string, operation: () => T): T {\n mkdirSync(root, { recursive: true })\n const lock = join(root, BUILD_ORDINALS_LOCK_FILE)\n const owner: CounterLockOwner = { pid: process.pid, token: randomUUID() }\n const ownerFile = `${lock}.owner-${owner.token}`\n durableExclusiveFile(ownerFile, `${JSON.stringify(owner)}\\n`)\n\n let acquired = false\n try {\n while (!acquired) {\n try {\n // Linking a complete, fsynced owner document makes lock acquisition atomic. A crash\n // before this point leaves only a uniquely named non-authoritative candidate file.\n linkSync(ownerFile, lock)\n fsyncDirectory(root)\n acquired = true\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error\n const current = parsedLockOwner(lock)\n if (current !== undefined && !processIsAlive(current.pid)) {\n // A dead PID is the only stale-lock recovery authority. The unique quarantine name\n // prevents one recovery attempt from recursively deleting another owner's lock bytes.\n const quarantine = `${lock}.dead-${current.token}-${randomUUID()}`\n try {\n renameSync(lock, quarantine)\n fsyncDirectory(root)\n rmSync(quarantine, { force: true })\n fsyncDirectory(root)\n continue\n } catch (recoveryError) {\n if ((recoveryError as NodeJS.ErrnoException).code === 'ENOENT') continue\n throw recoveryError\n }\n }\n Atomics.wait(COUNTER_LOCK_WAIT, 0, 0, COUNTER_LOCK_POLL_MS)\n }\n }\n\n return operation()\n } finally {\n if (acquired && parsedLockOwner(lock)?.token === owner.token) {\n rmSync(lock, { force: true })\n fsyncDirectory(root)\n }\n rmSync(ownerFile, { force: true })\n }\n}\n\nfunction persistOrdinals(\n file: string,\n map: Readonly<Record<string, number>>,\n beforePersist?: () => void,\n): void {\n const temporary = `${file}.tmp-${randomUUID()}`\n let fd: number | undefined\n try {\n fd = openSync(temporary, 'wx')\n writeFileSync(fd, `${JSON.stringify(map)}\\n`, 'utf8')\n fsyncSync(fd)\n closeSync(fd)\n fd = undefined\n beforePersist?.()\n renameSync(temporary, file)\n fsyncDirectory(dirname(file))\n } finally {\n if (fd !== undefined) closeSync(fd)\n rmSync(temporary, { force: true })\n }\n}\n\nexport async function nextBuildOrdinal(opts: NextBuildOrdinalOptions): Promise<number> {\n return withCounterLock(opts.root, () => {\n const file = join(opts.root, BUILD_ORDINALS_FILE)\n const map = readOrdinals(file, opts.product, true)\n const current = Object.hasOwn(map, opts.product) ? map[opts.product]! : 0\n if (current === Number.MAX_SAFE_INTEGER) {\n throw new BuildOrdinalReservationError('counter-exhausted', opts.product, current)\n }\n const next = current + 1\n map[opts.product] = next\n persistOrdinals(file, map)\n return next\n })\n}\n\n/**\n * Reserve one strictly-later maintenance ordinal across every affected product axis.\n *\n * Unlike the best-effort run-start counter above, maintenance reservation is fail-closed: every\n * required counter must already exist and be a non-negative safe integer. The complete map is\n * persisted with one same-directory atomic replacement only after all validation succeeds.\n */\nexport async function reserveBuildOrdinalForProducts(\n opts: ReserveBuildOrdinalForProductsOptions,\n): Promise<ReserveBuildOrdinalForProductsResult> {\n const products = Object.freeze([...new Set(opts.products)].sort())\n if (products.length === 0) return undefined\n\n return withCounterLock(opts.root, () => {\n const file = join(opts.root, BUILD_ORDINALS_FILE)\n const map = readOrdinals(file, products[0]!, false)\n let maximum = 0\n\n for (const product of products) {\n if (!Object.hasOwn(map, product)) {\n throw new BuildOrdinalReservationError('missing-counter', product)\n }\n const current = map[product]!\n if (current === Number.MAX_SAFE_INTEGER) {\n throw new BuildOrdinalReservationError('counter-exhausted', product, current)\n }\n maximum = Math.max(maximum, current)\n }\n\n const ordinal = maximum + 1\n for (const product of products) map[product] = ordinal\n const reservation = Object.freeze({ products, ordinal })\n persistOrdinals(file, map, () => opts.beforePersist?.(reservation))\n return ordinal\n })\n}\n\nfunction readOrdinals(\n file: string,\n product: string,\n missingIsEmpty: boolean,\n): Record<string, number> {\n let raw: string\n try {\n raw = readFileSync(file, 'utf-8')\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n if (missingIsEmpty) return Object.create(null) as Record<string, number>\n throw new BuildOrdinalReservationError('missing-counter', product)\n }\n throw error\n }\n\n let parsed: unknown\n try {\n parsed = JSON.parse(raw)\n } catch {\n throw new BuildOrdinalReservationError('invalid-state', product)\n }\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new BuildOrdinalReservationError('invalid-state', product, parsed)\n }\n\n const map = Object.create(null) as Record<string, number>\n for (const [key, value] of Object.entries(parsed)) {\n if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {\n throw new BuildOrdinalReservationError('invalid-counter', key, value)\n }\n map[key] = value\n }\n return map\n}\n","// Lock-free like the ordinal counter: a lost write is restored on the next observation.\n\nimport { readFileSync, renameSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\n\nimport { BUILD_ORDINALS_FILE } from './build-ordinal.js'\n\n/** The project-local state file holding product -> tag -> first-seen ordinal. */\nexport const BUILD_TAGS_FILE = 'build-tags.json'\n\nexport type BuildTagMap = Record<string, Record<string, number>>\n\nexport async function recordBuildTag(opts: {\n root: string\n product: string\n tag: string\n ordinal: number\n}): Promise<void> {\n const map = readBuildTagMap({ root: opts.root })\n const productTags = Object.prototype.hasOwnProperty.call(map, opts.product)\n ? map[opts.product]\n : undefined\n\n if (productTags && Object.prototype.hasOwnProperty.call(productTags, opts.tag)) return\n\n const nextMap: BuildTagMap = {\n ...map,\n [opts.product]: {\n ...productTags,\n [opts.tag]: opts.ordinal,\n },\n }\n const file = join(opts.root, BUILD_TAGS_FILE)\n const tmp = `${file}.tmp`\n writeFileSync(tmp, `${JSON.stringify(nextMap)}\\n`, 'utf-8')\n renameSync(tmp, file)\n}\n\nexport function resolveBuildTag(opts: {\n root: string\n product: string\n tag: string\n}): number | undefined {\n return readBuildTagMap({ root: opts.root })[opts.product]?.[opts.tag]\n}\n\n/** Pure read of the current per-product ordinal; never advances build-ordinals.json. */\nexport function latestBuildOrdinal(opts: { root: string; product: string }): number {\n const parsed = readJsonRecord(join(opts.root, BUILD_ORDINALS_FILE))\n const value = parsed?.[opts.product]\n return typeof value === 'number' && Number.isFinite(value) ? value : 0\n}\n\n/** Best-effort, sanitized read: missing, corrupt, and non-object state starts empty. */\nexport function readBuildTagMap(opts: { root: string }): BuildTagMap {\n const parsed = readJsonRecord(join(opts.root, BUILD_TAGS_FILE))\n if (!parsed) return {}\n\n const products: Array<[string, Record<string, number>]> = []\n for (const [product, tags] of Object.entries(parsed)) {\n if (!isRecord(tags)) continue\n\n const validTags = Object.fromEntries(\n Object.entries(tags).filter(\n (entry): entry is [string, number] =>\n typeof entry[1] === 'number' && Number.isFinite(entry[1]),\n ),\n )\n products.push([product, validTags])\n }\n\n return Object.fromEntries(products)\n}\n\nfunction readJsonRecord(file: string): Record<string, unknown> | undefined {\n try {\n const parsed: unknown = JSON.parse(readFileSync(file, 'utf-8'))\n return isRecord(parsed) ? parsed : undefined\n } catch {\n return undefined\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n","// The only child-process and fs home on the hook path; the sink mask adds to sandbox redaction.\n\nimport { execFile, type ChildProcess } from 'node:child_process'\nimport { readFile, mkdtemp, mkdir, rm, cp } from 'node:fs/promises'\nimport { join, basename } from 'node:path'\nimport { tmpdir } from 'node:os'\nimport type {\n HookDefinition,\n HookResult,\n HookRuntime,\n HookExecutorPort,\n HookExecuteOptions,\n RuntimeAuthStateConfig,\n} from '@vostride/agent-qa-runner'\nimport {\n hookRunnerImage,\n parseEnvFile,\n AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,\n AUTH_STATE_HOOK_STORAGE_STATE_FILENAME,\n AUTH_STATE_HOOK_WORKSPACE_DIR,\n buildAuthStateHookEnv,\n stripReservedAuthStateHookEnv,\n redactSecretValue,\n} from '@vostride/agent-qa-runner'\n\nconst DEFAULT_DOCKER_BIN = 'docker'\n\nexport interface DockerHookExecutorConfig {\n version: string\n dockerBin?: string\n pullPolicy?: 'always' | 'if-not-present' | 'never'\n}\n\n// One executor per host composition root. A per-hook timeout resolves a failed result,\n// never a throw.\nexport class DockerHookExecutor implements HookExecutorPort {\n private readonly version: string\n private readonly dockerBin: string\n private readonly pullPolicy: 'always' | 'if-not-present' | 'never'\n\n constructor(config: DockerHookExecutorConfig) {\n this.version = config.version\n this.dockerBin = config.dockerBin ?? DEFAULT_DOCKER_BIN\n this.pullPolicy = config.pullPolicy ?? 'if-not-present'\n }\n\n async execute(hook: HookDefinition, opts: HookExecuteOptions): Promise<HookResult> {\n const dockerBin = this.dockerBin\n const pullPolicy = this.pullPolicy\n const start = Date.now()\n\n const image = hookRunnerImage(hook.runtime, this.version)\n\n let workDir: string | undefined\n try {\n if (pullPolicy === 'always' || pullPolicy === 'if-not-present') {\n const needsPull = pullPolicy === 'always' || !(await imageExists(dockerBin, image))\n if (needsPull) {\n await pullImage(dockerBin, image)\n }\n }\n\n workDir = await mkdtemp(join(tmpdir(), 'agent-qa-hook-'))\n await mkdir(join(workDir, 'tmp'), { recursive: true })\n\n await cp(hook.file, join(workDir, basename(hook.file)))\n\n for (const dep of hook.deps) {\n await cp(dep, join(workDir, basename(dep)))\n }\n\n if (hook.packageFile) {\n await cp(hook.packageFile, join(workDir, basename(hook.packageFile)))\n }\n\n if (opts.authState) {\n const authStateDir = join(workDir, AUTH_STATE_HOOK_WORKSPACE_DIR)\n await mkdir(authStateDir, { recursive: true })\n await cp(opts.authState.storageStatePath, join(authStateDir, AUTH_STATE_HOOK_STORAGE_STATE_FILENAME))\n }\n\n const args = buildDockerArgs({\n image,\n workDir,\n hook,\n env: opts.env,\n secretEnv: opts.secretEnv,\n authState: opts.authState,\n })\n\n const cmd = getHookCommand(hook.runtime, basename(hook.file))\n args.push(...cmd)\n\n const { stdout, stderr, exitCode } = await execDocker(dockerBin, args, hook.timeout)\n\n let variables: Record<string, string> = {}\n try {\n const envContent = await readFile(join(workDir, 'tmp', 'agent-qa.env'), 'utf-8')\n variables = parseEnvFile(envContent)\n } catch {\n // Hook did not write .env file -- no variables to extract\n }\n variables = stripReservedAuthStateHookEnv(filterSecretVariables(variables, opts.secretEnv))\n const redactedStdout = redactSecretValue(stdout, opts.secretRedactor)\n const redactedStderr = redactSecretValue(stderr, opts.secretRedactor)\n const output = redactedStdout.trim()\n\n return {\n success: exitCode === 0,\n variables,\n output: output || redactedStderr,\n stdout: redactedStdout,\n stderr: redactedStderr,\n duration: Date.now() - start,\n error: exitCode !== 0\n ? redactSecretValue(`Hook exited with code ${exitCode}: ${stderr}`, opts.secretRedactor)\n : undefined,\n }\n } catch (err) {\n return {\n success: false,\n variables: {},\n output: '',\n stdout: '',\n stderr: '',\n duration: Date.now() - start,\n error: redactSecretValue((err as Error).message, opts.secretRedactor),\n }\n } finally {\n if (workDir) {\n await rm(workDir, { recursive: true, force: true }).catch(() => {})\n }\n }\n }\n}\n\n/** Docker availability probe; `doctor` reports from it whether the hook sandbox can run. */\nexport async function checkDockerAvailable(dockerBin = DEFAULT_DOCKER_BIN): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(dockerBin, ['info', '--format', '{{.ID}}'], { timeout: 5000 }, (err) => {\n resolve(!err)\n })\n })\n}\n\nfunction getHookCommand(runtime: HookRuntime, entryFile: string): string[] {\n switch (runtime) {\n case 'node': return ['node', entryFile]\n case 'bun': return ['bun', entryFile]\n case 'python': return ['python3', entryFile]\n case 'bash': return ['bash', entryFile]\n }\n}\n\ninterface DockerArgsInput {\n image: string\n workDir: string\n hook: HookDefinition\n env: Record<string, string>\n secretEnv: Record<string, string>\n authState?: RuntimeAuthStateConfig\n}\n\nfunction buildDockerArgs(input: DockerArgsInput): string[] {\n const args = [\n 'run',\n '--rm',\n '--init',\n '-v', `${input.workDir}:/workspace`,\n '-w', '/workspace',\n '--memory', '512m',\n '--cpus', '1',\n '--pids-limit', '256',\n '--read-only',\n '-v', `${input.workDir}/tmp:/tmp`,\n ]\n\n if (!input.hook.network) {\n args.push('--network', 'none')\n }\n\n const envVars: Record<string, string> = { ...input.env }\n // Secret values overlay normal env vars; this package never touches the SecretStore.\n Object.assign(envVars, input.secretEnv)\n Object.assign(envVars, buildAuthStateHookEnv(\n input.authState,\n AUTH_STATE_HOOK_CONTAINER_STORAGE_STATE_PATH,\n ))\n\n for (const [k, v] of Object.entries(envVars)) {\n args.push('-e', `${k}=${v}`)\n }\n\n args.push(input.image)\n return args\n}\n\nfunction filterSecretVariables(\n variables: Record<string, string>,\n secretEnv: Record<string, string>,\n): Record<string, string> {\n const secretValues = new Set(Object.values(secretEnv))\n if (secretValues.size === 0) return variables\n return Object.fromEntries(\n Object.entries(variables).filter(([_key, value]) => !secretValues.has(value)),\n )\n}\n\nfunction imageExists(dockerBin: string, image: string): Promise<boolean> {\n return new Promise((resolve) => {\n execFile(dockerBin, ['image', 'inspect', image], { timeout: 10000 }, (err) => {\n resolve(!err)\n })\n })\n}\n\nfunction pullImage(dockerBin: string, image: string): Promise<void> {\n return new Promise((resolve, reject) => {\n execFile(dockerBin, ['pull', image], { timeout: 120000 }, (err) => {\n if (err) reject(new Error(`Failed to pull image ${image}: ${err.message}`))\n else resolve()\n })\n })\n}\n\ninterface ExecResult {\n stdout: string\n stderr: string\n exitCode: number\n}\n\nfunction execDocker(dockerBin: string, args: string[], timeout: number): Promise<ExecResult> {\n return new Promise((resolve) => {\n let stdout = ''\n let stderr = ''\n let resolved = false\n\n const _proc: ChildProcess = execFile(dockerBin, args, { timeout, maxBuffer: 4 * 1024 * 1024 }, (err, out, errOut) => {\n if (resolved) return\n resolved = true\n\n stdout = out ?? ''\n stderr = errOut ?? ''\n\n if (err && 'killed' in err && (err as { killed?: boolean }).killed) {\n resolve({ stdout, stderr: `Hook timed out after ${timeout}ms`, exitCode: 124 })\n return\n }\n\n const exitCode = (err as { code?: number } | null)?.code ?? 0\n resolve({ stdout, stderr, exitCode: typeof exitCode === 'number' ? exitCode : 1 })\n })\n void _proc\n })\n}\n"],"mappings":"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","names":["import_node_path","import_promises","import_node_path","import_agent_qa_schema","import_node_fs","import_node_path","import_node_fs","import_node_path","import_agent_qa_schema","import_node_fs","import_node_path","import_agent_qa_schema","import_node_fs","import_node_path","import_agent_qa_schema","sharp","data","info","import_node_crypto","import_node_fs","import_node_path","import_node_fs","import_node_path","import_node_child_process","import_promises","import_node_path","resolve"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -17,15 +17,9 @@ interface CachePolicy {
|
|
|
17
17
|
/** `--disable-cache` — short-circuit both reads and writes. */
|
|
18
18
|
disableCache: boolean;
|
|
19
19
|
}
|
|
20
|
-
/**
|
|
21
|
-
* Writes are skipped when the current branch is protected (default ∪ configured)
|
|
22
|
-
* unless `--save-cache` or CI; `--disable-cache` forbids all writes. Reads are not
|
|
23
|
-
* governed here (D-14).
|
|
24
|
-
*/
|
|
25
20
|
declare function shouldWrite(policy: CachePolicy): boolean;
|
|
26
21
|
|
|
27
|
-
|
|
28
|
-
declare const CACHE_SCHEMA_VERSION = 2;
|
|
22
|
+
declare const CACHE_SCHEMA_VERSION = 3;
|
|
29
23
|
interface FsActionCacheConfig {
|
|
30
24
|
/** Cache root (e.g. DEFAULT_AGENT_QA_CACHE_DIR = '.agent-qa/cache'). */
|
|
31
25
|
root: string;
|
|
@@ -35,14 +29,22 @@ interface FsActionCacheConfig {
|
|
|
35
29
|
declare class FsActionCache implements ActionPlanCache {
|
|
36
30
|
private readonly root;
|
|
37
31
|
private readonly policy;
|
|
32
|
+
private readonly skipped;
|
|
38
33
|
constructor(config: FsActionCacheConfig);
|
|
39
34
|
get(key: CacheKey): Promise<CachedPlanValue | null>;
|
|
40
35
|
set(key: CacheKey, value: CachedPlanValue): Promise<void>;
|
|
41
36
|
invalidate(key: CacheKey): Promise<void>;
|
|
37
|
+
private writeEnvelope;
|
|
42
38
|
private branchDir;
|
|
43
39
|
private entryPath;
|
|
44
40
|
private readEntry;
|
|
45
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Removes every `<root>/<branch-slug>/<16-hex>.json` entry, and a branch directory only when that
|
|
44
|
+
* leaves it empty. Nothing else under `root` is touched, so a cache root that also holds other
|
|
45
|
+
* files keeps them. Returns the number of entries removed.
|
|
46
|
+
*/
|
|
47
|
+
declare function purgeActionCache(root: string): Promise<number>;
|
|
46
48
|
|
|
47
49
|
/** Subdirectory under the runtime root holding the raw storage-state blobs. */
|
|
48
50
|
declare const STORAGE_STATES_SUBDIR = "storage-states";
|
|
@@ -113,11 +115,6 @@ declare class FsHandoffStore implements HandoffStorePort {
|
|
|
113
115
|
constructor(config: FsHandoffStoreConfig);
|
|
114
116
|
save(handoff: CompletedRunHandoff): void;
|
|
115
117
|
}
|
|
116
|
-
/**
|
|
117
|
-
* The fs read leg of the handoff version discipline (D-19): read the single document, parse it,
|
|
118
|
-
* and delegate to the schema package's `guardCompletedRunHandoff`. A newer-than-known schemaVersion
|
|
119
|
-
* surfaces the schema's typed `HandoffVersionError` — this leg re-implements no version rule.
|
|
120
|
-
*/
|
|
121
118
|
declare function loadCompletedRunHandoff(filePath: string): CompletedRunHandoff;
|
|
122
119
|
|
|
123
120
|
/** The single JSON document each run writes its run artifact to. */
|
|
@@ -182,12 +179,6 @@ interface CompressResult {
|
|
|
182
179
|
imageWidth: number;
|
|
183
180
|
imageHeight: number;
|
|
184
181
|
}
|
|
185
|
-
/**
|
|
186
|
-
* The runner `ScreenshotCompressor` port impl (D-08 / Q10). `compress` covers the LLM-planner
|
|
187
|
-
* compression call site; `dimensions` covers the action-space-width metadata fallback done inline
|
|
188
|
-
* via `sharp(screenshot).metadata()` at v1 loop.ts. The loop applies `stampCaptureMode` itself
|
|
189
|
-
* (runner-owned since 352), so this stays purely pixel-level and returns v1's CompressResult shape.
|
|
190
|
-
*/
|
|
191
182
|
declare class SharpScreenshotCompressor implements ScreenshotCompressor {
|
|
192
183
|
private readonly logger?;
|
|
193
184
|
constructor(logger?: ScreenshotCompressorLogger | undefined);
|
|
@@ -212,8 +203,6 @@ interface ImageDimensions {
|
|
|
212
203
|
width: number;
|
|
213
204
|
height: number;
|
|
214
205
|
}
|
|
215
|
-
/** Read image buffer width/height without decoding pixels. Used by mobile adapters for
|
|
216
|
-
* action-space drift assertions (D-06/D-07). */
|
|
217
206
|
declare function getImageDimensions(buffer: Buffer): Promise<ImageDimensions | undefined>;
|
|
218
207
|
declare function flattenOntoWhite(buffer: Buffer): Promise<Buffer>;
|
|
219
208
|
|
|
@@ -288,24 +277,18 @@ declare function readBuildTagMap(opts: {
|
|
|
288
277
|
}): BuildTagMap;
|
|
289
278
|
|
|
290
279
|
interface DockerHookExecutorConfig {
|
|
280
|
+
version: string;
|
|
291
281
|
dockerBin?: string;
|
|
292
282
|
pullPolicy?: 'always' | 'if-not-present' | 'never';
|
|
293
283
|
}
|
|
294
|
-
/**
|
|
295
|
-
* The D-06 hook-execution impl. Constructed once at the CLI composition root and threaded
|
|
296
|
-
* into the runner `runHooks` orchestration behind the {@link HookExecutorPort}. A per-hook
|
|
297
|
-
* timeout resolves a FAILED {@link HookResult} (exit-124-style error), never a throw.
|
|
298
|
-
*/
|
|
299
284
|
declare class DockerHookExecutor implements HookExecutorPort {
|
|
285
|
+
private readonly version;
|
|
300
286
|
private readonly dockerBin;
|
|
301
287
|
private readonly pullPolicy;
|
|
302
|
-
constructor(config
|
|
288
|
+
constructor(config: DockerHookExecutorConfig);
|
|
303
289
|
execute(hook: HookDefinition, opts: HookExecuteOptions): Promise<HookResult>;
|
|
304
290
|
}
|
|
305
|
-
/**
|
|
306
|
-
* Docker availability probe (re-homed from core/src/hooks/sandbox-runner.ts). The CLI
|
|
307
|
-
* `doctor` command consumes this to report whether the hook sandbox can run.
|
|
308
|
-
*/
|
|
291
|
+
/** Docker availability probe; `doctor` reports from it whether the hook sandbox can run. */
|
|
309
292
|
declare function checkDockerAvailable(dockerBin?: string): Promise<boolean>;
|
|
310
293
|
|
|
311
|
-
export { ARTIFACT_FILE, type AlignOptions, BUILD_ORDINALS_FILE, BUILD_TAGS_FILE, type BranchResolverOptions, type BuildOrdinalReservation, BuildOrdinalReservationError, type BuildOrdinalReservationErrorCode, type BuildTagMap, CACHE_SCHEMA_VERSION, type CachePolicy, type CompressOptions, type CompressResult, DockerHookExecutor, type DockerHookExecutorConfig, EVENTS_FILE, FsActionCache, type FsActionCacheConfig, FsEventLog, type FsEventLogConfig, FsEvidenceArtifactStore, type FsEvidenceArtifactStoreConfig, FsHandoffStore, type FsHandoffStoreConfig, FsRunArtifactStore, type FsRunArtifactStoreConfig, FsStorageStateStore, type FsStorageStateStoreConfig, HANDOFF_FILE, type ImageDimensions, type NextBuildOrdinalOptions, RUNS_SUBDIR, RUN_EVIDENCE_BLOBS_SUBDIR, type ReserveBuildOrdinalForProductsOptions, type ReserveBuildOrdinalForProductsResult, type ResolvedBranch, STORAGE_STATES_SUBDIR, type ScreenshotCompressorLogger, SharpScreenshotCompressor, alignToWindow, checkDockerAvailable, flattenOntoWhite, getImageDimensions, latestBuildOrdinal, loadCompletedRunHandoff, nextBuildOrdinal, readBuildTagMap, recordBuildTag, reserveBuildOrdinalForProducts, resolveBranch, resolveBuildTag, shouldWrite };
|
|
294
|
+
export { ARTIFACT_FILE, type AlignOptions, BUILD_ORDINALS_FILE, BUILD_TAGS_FILE, type BranchResolverOptions, type BuildOrdinalReservation, BuildOrdinalReservationError, type BuildOrdinalReservationErrorCode, type BuildTagMap, CACHE_SCHEMA_VERSION, type CachePolicy, type CompressOptions, type CompressResult, DockerHookExecutor, type DockerHookExecutorConfig, EVENTS_FILE, FsActionCache, type FsActionCacheConfig, FsEventLog, type FsEventLogConfig, FsEvidenceArtifactStore, type FsEvidenceArtifactStoreConfig, FsHandoffStore, type FsHandoffStoreConfig, FsRunArtifactStore, type FsRunArtifactStoreConfig, FsStorageStateStore, type FsStorageStateStoreConfig, HANDOFF_FILE, type ImageDimensions, type NextBuildOrdinalOptions, RUNS_SUBDIR, RUN_EVIDENCE_BLOBS_SUBDIR, type ReserveBuildOrdinalForProductsOptions, type ReserveBuildOrdinalForProductsResult, type ResolvedBranch, STORAGE_STATES_SUBDIR, type ScreenshotCompressorLogger, SharpScreenshotCompressor, alignToWindow, checkDockerAvailable, flattenOntoWhite, getImageDimensions, latestBuildOrdinal, loadCompletedRunHandoff, nextBuildOrdinal, purgeActionCache, readBuildTagMap, recordBuildTag, reserveBuildOrdinalForProducts, resolveBranch, resolveBuildTag, shouldWrite };
|