@vostride/agent-qa-runner-local 0.0.1 → 0.2.2

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.
@@ -0,0 +1,311 @@
1
+ import { ActionPlanCache, CachedPlanValue, StorageStatePort, StorageStateBlob, StorageStateReference, EventLogPort, HandoffStorePort, RunArtifactStorePort, EvidenceArtifactStorePort, PersistedRecording, ScreenshotCompressor, CompressedScreenshot, HookExecutorPort, HookDefinition, HookExecuteOptions, HookResult } from '@vostride/agent-qa-runner';
2
+ export { ActionPlanCache, StorageStateBlob, StorageStatePort, StorageStateReference } from '@vostride/agent-qa-runner';
3
+ import { CacheKey, RunEventEnvelope, CompletedRunHandoff, RunArtifactStageInput, RunArtifactFinalizeInput, ArtifactRef, EvidenceDocument } from '@vostride/agent-qa-schema';
4
+ export { CacheKey, slugBranch } from '@vostride/agent-qa-schema';
5
+
6
+ interface CachePolicy {
7
+ /** The branch the current run executes on (raw, un-slugged). */
8
+ currentBranch: string;
9
+ /** The repo's default branch (raw, un-slugged) — the read-fallback namespace. */
10
+ defaultBranch: string;
11
+ /** default branch ∪ any configured protected branches. */
12
+ protectedBranches: readonly string[];
13
+ /** Resolved in the CLI (reusing the CI vendor-var set), passed in here. */
14
+ isCI: boolean;
15
+ /** `--save-cache` — force writes even on a protected branch. */
16
+ saveCache: boolean;
17
+ /** `--disable-cache` — short-circuit both reads and writes. */
18
+ disableCache: boolean;
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
+ declare function shouldWrite(policy: CachePolicy): boolean;
26
+
27
+ /** Envelopes live under <root>/<branchSlug>/<key>.json; any other stamp reads as a miss. */
28
+ declare const CACHE_SCHEMA_VERSION = 2;
29
+ interface FsActionCacheConfig {
30
+ /** Cache root (e.g. DEFAULT_AGENT_QA_CACHE_DIR = '.agent-qa/cache'). */
31
+ root: string;
32
+ /** Resolved branch context + write policy (branch + CI + flags). */
33
+ policy: CachePolicy;
34
+ }
35
+ declare class FsActionCache implements ActionPlanCache {
36
+ private readonly root;
37
+ private readonly policy;
38
+ constructor(config: FsActionCacheConfig);
39
+ get(key: CacheKey): Promise<CachedPlanValue | null>;
40
+ set(key: CacheKey, value: CachedPlanValue): Promise<void>;
41
+ invalidate(key: CacheKey): Promise<void>;
42
+ private branchDir;
43
+ private entryPath;
44
+ private readEntry;
45
+ }
46
+
47
+ /** Subdirectory under the runtime root holding the raw storage-state blobs. */
48
+ declare const STORAGE_STATES_SUBDIR = "storage-states";
49
+ interface FsStorageStateStoreConfig {
50
+ /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */
51
+ root: string;
52
+ }
53
+ declare class FsStorageStateStore implements StorageStatePort {
54
+ private readonly root;
55
+ constructor(config: FsStorageStateStoreConfig);
56
+ save(name: string, state: StorageStateBlob): Promise<StorageStateReference>;
57
+ load(name: string): Promise<StorageStateBlob | undefined>;
58
+ private storageStatesDir;
59
+ private entryPath;
60
+ }
61
+
62
+ interface ResolvedBranch {
63
+ /** The branch the run is on; falls back to defaultBranch when undetectable. */
64
+ currentBranch: string;
65
+ /** The remote default branch; falls back to the configured default -> main. */
66
+ defaultBranch: string;
67
+ }
68
+ interface BranchResolverOptions {
69
+ /** Directory to resolve git state from (default process.cwd()). */
70
+ cwd?: string;
71
+ /** Configured default branch, used when the remote default is undetectable. */
72
+ configuredDefault?: string;
73
+ /** Injected .git/HEAD reader — returns raw file content or null. */
74
+ readHead?: (cwd: string) => string | null;
75
+ /** Injected `git symbolic-ref refs/remotes/origin/HEAD` reader — raw or null. */
76
+ runSymbolicRef?: (cwd: string) => string | null;
77
+ }
78
+ /**
79
+ * Resolve the current + default branch names. Both are returned raw (un-slugged);
80
+ * the fs store slugs each before it becomes a path segment. Never throws.
81
+ */
82
+ declare function resolveBranch(opts?: BranchResolverOptions): ResolvedBranch;
83
+
84
+ /** Subdirectory under the runtime root holding per-run event logs. */
85
+ declare const RUNS_SUBDIR = "runs";
86
+ /** The single JSONL file name each run appends its event stream to. */
87
+ declare const EVENTS_FILE = "events.jsonl";
88
+ interface FsEventLogConfig {
89
+ /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */
90
+ root: string;
91
+ /** The run this log belongs to; slugged before it becomes a path segment. */
92
+ runId: string;
93
+ }
94
+ declare class FsEventLog implements EventLogPort {
95
+ private readonly dir;
96
+ private readonly file;
97
+ constructor(config: FsEventLogConfig);
98
+ append(envelope: RunEventEnvelope): void;
99
+ read(fromSeq: number): RunEventEnvelope[];
100
+ }
101
+
102
+ /** The single JSON document each run writes its completed-run handoff to. */
103
+ declare const HANDOFF_FILE = "handoff.json";
104
+ interface FsHandoffStoreConfig {
105
+ /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */
106
+ root: string;
107
+ /** The run this handoff belongs to; slugged before it becomes a path segment. */
108
+ runId: string;
109
+ }
110
+ declare class FsHandoffStore implements HandoffStorePort {
111
+ private readonly dir;
112
+ private readonly file;
113
+ constructor(config: FsHandoffStoreConfig);
114
+ save(handoff: CompletedRunHandoff): void;
115
+ }
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
+ declare function loadCompletedRunHandoff(filePath: string): CompletedRunHandoff;
122
+
123
+ /** The single JSON document each run writes its run artifact to. */
124
+ declare const ARTIFACT_FILE = "artifact.json";
125
+ interface FsRunArtifactStoreConfig {
126
+ /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */
127
+ root: string;
128
+ /** The run this artifact belongs to; slugged before it becomes a path segment. */
129
+ runId: string;
130
+ }
131
+ declare class FsRunArtifactStore implements RunArtifactStorePort {
132
+ private readonly dir;
133
+ private readonly file;
134
+ constructor(config: FsRunArtifactStoreConfig);
135
+ stage(document: RunArtifactStageInput): void;
136
+ finalize(patch: RunArtifactFinalizeInput): void;
137
+ /** Shallow-merge a stage/finalize input onto the base, always dropping the top-level runtime. */
138
+ private merge;
139
+ private readExisting;
140
+ private write;
141
+ }
142
+
143
+ /** Subdirectory under each slugged run dir holding the content-addressed evidence blobs. */
144
+ declare const RUN_EVIDENCE_BLOBS_SUBDIR = "blobs";
145
+ interface FsEvidenceArtifactStoreConfig {
146
+ /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */
147
+ root: string;
148
+ /** The run these blobs belong to; slugged before it becomes a path segment. */
149
+ runId: string;
150
+ }
151
+ declare class FsEvidenceArtifactStore implements EvidenceArtifactStorePort {
152
+ private readonly dir;
153
+ private readonly durabilityRoot;
154
+ constructor(config: FsEvidenceArtifactStoreConfig);
155
+ persistDecisionScreenshot(bytes: Uint8Array): ArtifactRef;
156
+ persistEvidenceDocument(document: Exclude<EvidenceDocument, {
157
+ kind: 'variables';
158
+ }>): ArtifactRef;
159
+ private syncDirectories;
160
+ private syncPath;
161
+ hasBlob(sha: string): boolean;
162
+ persistRecording(stagingPath: string): PersistedRecording;
163
+ blobSize(sha: string): number | undefined;
164
+ readBlobRange(sha: string, start: number, end: number): Uint8Array | undefined;
165
+ discardRecording(stagingPath: string): void;
166
+ private assertRecordingStagingPath;
167
+ private unlinkRecordingStaging;
168
+ getBlob(sha: string): Uint8Array | undefined;
169
+ }
170
+
171
+ /** Minimal structural debug-logger seam (a core `ScopedLogger` satisfies it; no core dependency). */
172
+ interface ScreenshotCompressorLogger {
173
+ debug(message: string, meta?: Record<string, unknown>): void;
174
+ }
175
+ interface CompressOptions {
176
+ effectiveResolution: number;
177
+ maxBytes?: number;
178
+ actionSpaceWidth: number;
179
+ }
180
+ interface CompressResult {
181
+ buffer: Buffer;
182
+ imageWidth: number;
183
+ imageHeight: number;
184
+ }
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
+ declare class SharpScreenshotCompressor implements ScreenshotCompressor {
192
+ private readonly logger?;
193
+ constructor(logger?: ScreenshotCompressorLogger | undefined);
194
+ compress(screenshot: Buffer, options: {
195
+ effectiveResolution: number;
196
+ maxBytes?: number;
197
+ actionSpaceWidth: number;
198
+ }): Promise<CompressedScreenshot>;
199
+ dimensions(screenshot: Buffer): Promise<{
200
+ width: number;
201
+ height: number;
202
+ }>;
203
+ }
204
+ interface AlignOptions {
205
+ width: number;
206
+ height: number;
207
+ }
208
+ /** Resize buffer to exact window dimensions. Used by mobile adapters for action-space alignment
209
+ * (e.g., iOS physical pixels → logical points). */
210
+ declare function alignToWindow(buffer: Buffer, opts: AlignOptions): Promise<Buffer>;
211
+ interface ImageDimensions {
212
+ width: number;
213
+ height: number;
214
+ }
215
+ /** Read image buffer width/height without decoding pixels. Used by mobile adapters for
216
+ * action-space drift assertions (D-06/D-07). */
217
+ declare function getImageDimensions(buffer: Buffer): Promise<ImageDimensions | undefined>;
218
+ declare function flattenOntoWhite(buffer: Buffer): Promise<Buffer>;
219
+
220
+ /** The project-local state file holding the per-product ordinal map. */
221
+ declare const BUILD_ORDINALS_FILE = "build-ordinals.json";
222
+ interface NextBuildOrdinalOptions {
223
+ /** Runtime root (e.g. DEFAULT_AGENT_QA_DIR = '.agent-qa'). */
224
+ root: string;
225
+ /** The product whose counter to advance. */
226
+ product: string;
227
+ }
228
+ interface BuildOrdinalReservation {
229
+ /** Canonical, sorted, duplicate-free product axes advanced by the reservation. */
230
+ products: readonly string[];
231
+ /** One ordinal strictly later than every affected product's current counter. */
232
+ ordinal: number;
233
+ }
234
+ type BuildOrdinalReservationErrorCode = 'invalid-state' | 'missing-counter' | 'invalid-counter' | 'counter-exhausted';
235
+ /** Typed pre-persistence refusal for an unsafe maintenance ordinal reservation. */
236
+ declare class BuildOrdinalReservationError extends Error {
237
+ readonly name = "BuildOrdinalReservationError";
238
+ readonly code: BuildOrdinalReservationErrorCode;
239
+ readonly product: string;
240
+ readonly value?: unknown;
241
+ constructor(code: BuildOrdinalReservationErrorCode, product: string, value?: unknown);
242
+ }
243
+ interface ReserveBuildOrdinalForProductsOptions {
244
+ /** Runtime root containing build-ordinals.json. */
245
+ root: string;
246
+ /** Product axes whose counters must advance together. Duplicates and order are ignored. */
247
+ products: Iterable<string>;
248
+ /**
249
+ * Synchronous authority fence invoked after the complete temp file is prepared and immediately
250
+ * before the atomic rename. Throwing refuses persistence and removes the temp file.
251
+ */
252
+ beforePersist?: (reservation: BuildOrdinalReservation) => void;
253
+ }
254
+ /** Undefined is the explicit no-op result for an empty affected-product set. */
255
+ type ReserveBuildOrdinalForProductsResult = number | undefined;
256
+ declare function nextBuildOrdinal(opts: NextBuildOrdinalOptions): Promise<number>;
257
+ /**
258
+ * Reserve one strictly-later maintenance ordinal across every affected product axis.
259
+ *
260
+ * Unlike the best-effort run-start counter above, maintenance reservation is fail-closed: every
261
+ * required counter must already exist and be a non-negative safe integer. The complete map is
262
+ * persisted with one same-directory atomic replacement only after all validation succeeds.
263
+ */
264
+ declare function reserveBuildOrdinalForProducts(opts: ReserveBuildOrdinalForProductsOptions): Promise<ReserveBuildOrdinalForProductsResult>;
265
+
266
+ /** The project-local state file holding product -> tag -> first-seen ordinal. */
267
+ declare const BUILD_TAGS_FILE = "build-tags.json";
268
+ type BuildTagMap = Record<string, Record<string, number>>;
269
+ declare function recordBuildTag(opts: {
270
+ root: string;
271
+ product: string;
272
+ tag: string;
273
+ ordinal: number;
274
+ }): Promise<void>;
275
+ declare function resolveBuildTag(opts: {
276
+ root: string;
277
+ product: string;
278
+ tag: string;
279
+ }): number | undefined;
280
+ /** Pure read of the current per-product ordinal; never advances build-ordinals.json. */
281
+ declare function latestBuildOrdinal(opts: {
282
+ root: string;
283
+ product: string;
284
+ }): number;
285
+ /** Best-effort, sanitized read: missing, corrupt, and non-object state starts empty. */
286
+ declare function readBuildTagMap(opts: {
287
+ root: string;
288
+ }): BuildTagMap;
289
+
290
+ interface DockerHookExecutorConfig {
291
+ dockerBin?: string;
292
+ pullPolicy?: 'always' | 'if-not-present' | 'never';
293
+ }
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
+ declare class DockerHookExecutor implements HookExecutorPort {
300
+ private readonly dockerBin;
301
+ private readonly pullPolicy;
302
+ constructor(config?: DockerHookExecutorConfig);
303
+ execute(hook: HookDefinition, opts: HookExecuteOptions): Promise<HookResult>;
304
+ }
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
+ */
309
+ declare function checkDockerAvailable(dockerBin?: string): Promise<boolean>;
310
+
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 };