@robmclarty/volley 0.7.0 → 0.9.0
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/CHANGELOG.md +42 -0
- package/README.md +398 -38
- package/dist/cli.js +4469 -2930
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +260 -36
- package/dist/index.js +1296 -450
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/builder/presets/harness_append_acp.md +86 -0
- package/src/builder/presets/harness_append_local.md +2 -1
- package/src/critic/presets/harness_append.md +2 -1
- package/src/critic/presets/harness_append_acp.md +27 -0
- package/src/critic/presets/harness_append_local.md +4 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { Engine, FinishReason, StreamChunk, Throughput, UsageTotals } from "fascicle";
|
|
1
|
+
import { Engine, FinishReason, StreamChunk, Throughput, Tool, ToolApprovalHandler, TrajectoryLogger, UsageTotals } from "fascicle";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
//#region src/types.d.ts
|
|
4
4
|
type Verdict = 'approved' | 'changes_requested';
|
|
5
5
|
type CriticPreset = 'reviewer' | 'optimizer' | 'researcher';
|
|
6
6
|
/** Transport for the critic role. The critic is read-only + schema-constrained,
|
|
7
|
-
* so it has always been able to run on a local model.
|
|
8
|
-
|
|
7
|
+
* so it has always been able to run on a local model. `openrouter` reaches a
|
|
8
|
+
* hosted model over one API key and takes the local critic's tools and
|
|
9
|
+
* degradation ladder. */
|
|
10
|
+
type CriticProvider = 'claude_cli' | 'ollama' | 'lmstudio' | 'openrouter';
|
|
9
11
|
/** Transport for the builder role. `claude_cli` is a full agentic Claude Code
|
|
10
|
-
* session;
|
|
11
|
-
* (write/exec tools supplied by the harness)
|
|
12
|
-
*
|
|
13
|
-
|
|
14
|
-
type BuilderProvider = 'claude_cli' | 'ollama' | 'lmstudio';
|
|
12
|
+
* session; every other provider runs the builder as a volley-driven tool loop
|
|
13
|
+
* (write/exec tools supplied by the harness), whether its model is local
|
|
14
|
+
* (`ollama`, `lmstudio`) or hosted (`openrouter`). */
|
|
15
|
+
type BuilderProvider = 'claude_cli' | 'ollama' | 'lmstudio' | 'openrouter';
|
|
15
16
|
type BuilderPermissionMode = 'acceptEdits' | 'bypassPermissions';
|
|
16
17
|
/** `auto`, `none`, or any shell command (the `string & {}` keeps the literal
|
|
17
18
|
* hints in editor completions without collapsing the union). */
|
|
@@ -22,11 +23,22 @@ type CostSource = 'provider_reported' | 'engine_derived' | 'unknown';
|
|
|
22
23
|
* died. Recorded alongside a critic retry so a degraded run says
|
|
23
24
|
* *what* failed, not just that it retried. */
|
|
24
25
|
type CauseKind = 'provider_5xx' | 'network' | 'unknown';
|
|
26
|
+
/** Why a local critic's verdict came from the tool-less fallback:
|
|
27
|
+
* `stream_error`, the tool-bearing call kept dying on the provider's stream
|
|
28
|
+
* after the bounded retry; `step_exhaustion`, it spent its step budget (or
|
|
29
|
+
* stopped on a tool call) without producing a verdict. */
|
|
30
|
+
type DegradeCause = 'stream_error' | 'step_exhaustion';
|
|
25
31
|
type RunStatus = 'running' | 'success' | 'budget_exhausted' | 'cost_cap_reached' |
|
|
26
32
|
/** The builder edited the gate that judges it, under `--fail-on-gate-edit`:
|
|
27
33
|
* the run halts on the spot rather than iterating, because a check the builder
|
|
28
34
|
* can rewrite is not evidence the work is done. */
|
|
29
|
-
'gate_edit_blocked' |
|
|
35
|
+
'gate_edit_blocked' |
|
|
36
|
+
/** A critique's other outcome: the critic requested changes, or the check
|
|
37
|
+
* failed, on the one change it reviewed. A run never ends this way. */
|
|
38
|
+
'rejected' | 'interrupted' | 'error';
|
|
39
|
+
/** What a run does: the builder/critic loop (`run`), or one check and one
|
|
40
|
+
* critique of a change already made, with no builder at all (`critique`). */
|
|
41
|
+
type RunMode = 'run' | 'critique';
|
|
30
42
|
/** User-facing configuration, before resolution (config file / flags). */
|
|
31
43
|
type VolleyConfig = {
|
|
32
44
|
prompt: string;
|
|
@@ -37,6 +49,7 @@ type VolleyConfig = {
|
|
|
37
49
|
builder_provider?: BuilderProvider;
|
|
38
50
|
builder_url?: string;
|
|
39
51
|
builder_max_steps?: number;
|
|
52
|
+
builder_max_tool_calls?: number;
|
|
40
53
|
allow_unsandboxed_builder?: boolean;
|
|
41
54
|
critic_model?: string;
|
|
42
55
|
critic_provider?: CriticProvider;
|
|
@@ -51,17 +64,25 @@ type VolleyConfig = {
|
|
|
51
64
|
gate_paths?: string[];
|
|
52
65
|
fail_on_gate_edit?: boolean;
|
|
53
66
|
sandbox_image?: string;
|
|
67
|
+
state_dir?: string;
|
|
54
68
|
verbose?: boolean;
|
|
55
69
|
quiet?: boolean;
|
|
56
70
|
json?: boolean;
|
|
57
71
|
show_thinking?: boolean;
|
|
58
72
|
dry_run?: boolean;
|
|
59
73
|
};
|
|
60
|
-
/** Fully resolved run configuration;
|
|
74
|
+
/** Fully resolved run configuration; the run's `config.json` mirrors this. */
|
|
61
75
|
type ResolvedConfig = {
|
|
62
76
|
version: 2;
|
|
63
77
|
run_id: string;
|
|
64
78
|
started_at: string;
|
|
79
|
+
/** A run, or a critique (`volley critique`). A critique's builder fields
|
|
80
|
+
* hold the defaults, untouched by flags and the environment, since no
|
|
81
|
+
* builder is ever constructed, and its loop settings are one round with
|
|
82
|
+
* nothing isolated or committed. */
|
|
83
|
+
mode: RunMode;
|
|
84
|
+
/** The task. A critique needs none, since a critic judges against the
|
|
85
|
+
* criteria alone, so it's empty unless one was given to record. */
|
|
65
86
|
prompt: string;
|
|
66
87
|
criteria: string;
|
|
67
88
|
check: CheckMode;
|
|
@@ -72,12 +93,18 @@ type ResolvedConfig = {
|
|
|
72
93
|
* It is normalized, and crossed to the host LLM endpoint when contained, only
|
|
73
94
|
* where it is used, because the crossing depends on where the run executes.
|
|
74
95
|
* Null falls back to the provider's env var (`VOLLEY_OLLAMA_URL` /
|
|
75
|
-
* `VOLLEY_LMSTUDIO_URL`), then its default, never to
|
|
76
|
-
* a provider volley reaches at a base URL (ollama,
|
|
96
|
+
* `VOLLEY_LMSTUDIO_URL` / `VOLLEY_OPENROUTER_URL`), then its default, never to
|
|
97
|
+
* the critic's URL. Only a provider volley reaches at a base URL (ollama,
|
|
98
|
+
* lmstudio, openrouter) takes one. */
|
|
77
99
|
builder_url: string | null;
|
|
78
100
|
builder_max_steps: number;
|
|
79
|
-
/**
|
|
80
|
-
*
|
|
101
|
+
/** How many tool calls a tool-loop builder may make in one turn; fascicle
|
|
102
|
+
* runs the first that many, in order, and drops the rest. 1 by default,
|
|
103
|
+
* since some model and runtime pairs return parallel calls badly; raise it
|
|
104
|
+
* for a pair that handles them. Ignored by the `claude_cli` builder. */
|
|
105
|
+
builder_max_tool_calls: number;
|
|
106
|
+
/** Operator opt-out permitting a non-`claude_cli` builder to run without a
|
|
107
|
+
* sandbox — it gets a real host bash. Refused by default. */
|
|
81
108
|
allow_unsandboxed_builder: boolean;
|
|
82
109
|
critic_model: string;
|
|
83
110
|
critic_provider: CriticProvider;
|
|
@@ -92,7 +119,7 @@ type ResolvedConfig = {
|
|
|
92
119
|
git_checkpoints: boolean;
|
|
93
120
|
/** Isolate the builder run's effects in a per-run git worktree: the
|
|
94
121
|
* builder/critic file tools' containment root moves to the worktree, while
|
|
95
|
-
*
|
|
122
|
+
* the run's state stays where `state_dir` puts it (the control plane). Off by
|
|
96
123
|
* default; requires the workspace to be a git repository. */
|
|
97
124
|
worktree: boolean;
|
|
98
125
|
/** Throw a `--worktree` run's effects away at teardown even when it converged:
|
|
@@ -119,6 +146,13 @@ type ResolvedConfig = {
|
|
|
119
146
|
* `VOLLEY_SANDBOX_IMAGE` override it. Meaningful only for a local builder —
|
|
120
147
|
* the `claude_cli` path never uses Docker. */
|
|
121
148
|
sandbox_image: string;
|
|
149
|
+
/** The root that holds each run's state at `<state_dir>/<run_id>/`, as an
|
|
150
|
+
* absolute path: `--state-dir`, else the default root,
|
|
151
|
+
* `$XDG_STATE_HOME/volley` or `~/.local/state/volley`. `resolve_config`
|
|
152
|
+
* always sets one. Null is the layout older runs used, `<workspace>/.volley/`,
|
|
153
|
+
* rotated aside by the next fresh run: a run an older volley started
|
|
154
|
+
* resumes in it, and a hand-built config can still ask for it. */
|
|
155
|
+
state_dir: string | null;
|
|
122
156
|
workspace: string;
|
|
123
157
|
verbose: boolean;
|
|
124
158
|
quiet: boolean;
|
|
@@ -209,12 +243,15 @@ type PhaseRecord = {
|
|
|
209
243
|
retry_cause_kind?: CauseKind;
|
|
210
244
|
/** This local-critic verdict was rendered by the tool-less fallback rung:
|
|
211
245
|
* the tool-bearing critique kept dying on the provider's stream
|
|
212
|
-
* even after the bounded retry,
|
|
213
|
-
* grounded only by the criteria, the raw
|
|
214
|
-
* inventory. Set (true) on a degraded
|
|
215
|
-
* critique and on the builder. Additive, and a
|
|
216
|
-
* marked so it never passes silently as a full
|
|
246
|
+
* even after the bounded retry, or ran out of steps before its verdict, so the
|
|
247
|
+
* critic judged with no read access — grounded only by the criteria, the raw
|
|
248
|
+
* check artifacts, and a workspace file inventory. Set (true) on a degraded
|
|
249
|
+
* critic record; absent on a full critique and on the builder. Additive, and a
|
|
250
|
+
* degraded verdict is *always* marked so it never passes silently as a full
|
|
251
|
+
* one. */
|
|
217
252
|
critic_degraded?: boolean;
|
|
253
|
+
/** Why the verdict degraded, set with `critic_degraded`. Additive. */
|
|
254
|
+
degrade_cause?: DegradeCause;
|
|
218
255
|
/** Output tokens per second over the model's own turns (tool execution and
|
|
219
256
|
* retry backoff excluded), from fascicle's per-step timing. `basis` is
|
|
220
257
|
* `decode` when every turn streamed, `blended` when any round trip counted
|
|
@@ -255,7 +292,7 @@ type LoopState = {
|
|
|
255
292
|
halt: HaltReason;
|
|
256
293
|
cost_warned: boolean;
|
|
257
294
|
};
|
|
258
|
-
/** Projection of final loop state;
|
|
295
|
+
/** Projection of final loop state; the run's `summary.json` mirrors this. */
|
|
259
296
|
type RunResult = {
|
|
260
297
|
run_id: string;
|
|
261
298
|
status: RunStatus;
|
|
@@ -273,8 +310,15 @@ type RunResult = {
|
|
|
273
310
|
* other copy of its effects, so teardown commits them onto `volley/<run id>`
|
|
274
311
|
* and keeps the branch instead of force-deleting it. Null whenever nothing
|
|
275
312
|
* survived — every non-worktree run, every integrated run, every discarded
|
|
276
|
-
* one. `--json` consumers read it here;
|
|
313
|
+
* one. `--json` consumers read it here; the run's `summary.json` mirrors it. */
|
|
277
314
|
salvaged_branch: string | null;
|
|
315
|
+
/** A run, or a critique, which runs no builder. */
|
|
316
|
+
mode: RunMode;
|
|
317
|
+
/** Where this run keeps its config, summary, trajectory, feedback, verdict,
|
|
318
|
+
* and iterations: `<state_dir>/<run_id>/` under a state root, else the
|
|
319
|
+
* workspace's `.volley/`. Inside the sandbox container it is the container's
|
|
320
|
+
* path, which a harness maps back to the directory it mounted. */
|
|
321
|
+
run_state_dir: string;
|
|
278
322
|
};
|
|
279
323
|
//#endregion
|
|
280
324
|
//#region src/config.d.ts
|
|
@@ -287,12 +331,104 @@ type ResolveOptions = {
|
|
|
287
331
|
run_id?: string;
|
|
288
332
|
started_at?: string;
|
|
289
333
|
env?: Record<string, string | undefined>;
|
|
334
|
+
/** What happens to a tool-loop builder with nothing between its commands
|
|
335
|
+
* and the host (`unguarded_builder`): the CLI `refuse`s it, the default,
|
|
336
|
+
* while under `volley acp` each of its commands `ask`s a person first, which
|
|
337
|
+
* takes the container's place. */
|
|
338
|
+
uncontained_builder?: 'refuse' | 'ask';
|
|
339
|
+
/** Where the run's state goes, in place of what the config says: `volley
|
|
340
|
+
* resume` passes the root it found the run under, or null for a run an older
|
|
341
|
+
* volley kept in the workspace's `.volley/`, which resumes there. */
|
|
342
|
+
state_dir?: string | null;
|
|
343
|
+
/** A run (the default), or a critique, which has no builder or loop. */
|
|
344
|
+
mode?: RunMode;
|
|
290
345
|
};
|
|
291
346
|
/** Merge, expand, and validate a raw `VolleyConfig` into a `ResolvedConfig`.
|
|
292
347
|
* `check_resolved` comes from check detection against the workspace, so the
|
|
293
348
|
* SDK and the CLI resolve `auto` and a command check the same way. */
|
|
294
349
|
export declare function resolve_config(raw: VolleyConfig, options?: ResolveOptions): ResolvedConfig;
|
|
295
350
|
//#endregion
|
|
351
|
+
//#region src/builder/tools.d.ts
|
|
352
|
+
/** The raw outcome of running one bash command, before the model-facing
|
|
353
|
+
* truncation + timeout marker the `bash` tool applies. `status` is the exit code
|
|
354
|
+
* (null when the process was killed by a signal — e.g. the timeout SIGKILL);
|
|
355
|
+
* `timed_out` marks the timeout path. */
|
|
356
|
+
type BashOutcome = {
|
|
357
|
+
status: number | null;
|
|
358
|
+
stdout: string;
|
|
359
|
+
stderr: string;
|
|
360
|
+
timed_out: boolean;
|
|
361
|
+
};
|
|
362
|
+
/** How the `bash` tool runs a command: the local `host_bash_executor`
|
|
363
|
+
* (`spawnSync`) — which under whole-process containment runs *inside*
|
|
364
|
+
* volley's own hardened container, no `docker exec` hop. The executor runs one
|
|
365
|
+
* command to completion and returns its raw outcome; the `bash` tool owns the
|
|
366
|
+
* truncation + timeout marker. Kept as an injectable seam so tests can supply a
|
|
367
|
+
* fake and a future shape could re-point it (the `docker exec` executor was
|
|
368
|
+
* retired). */
|
|
369
|
+
type BashExecutor = (command: string, options: {
|
|
370
|
+
timeout_ms: number;
|
|
371
|
+
max_capture_bytes: number;
|
|
372
|
+
}) => BashOutcome;
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/workspace_tools.d.ts
|
|
375
|
+
/** Which tool set a seat holds, so its prompt names the tools it has: volley's
|
|
376
|
+
* own (`'volley'`), or fascicle's workspace tools under `volley acp`
|
|
377
|
+
* (`'acp'`). */
|
|
378
|
+
type ToolSet = 'volley' | 'acp';
|
|
379
|
+
//#endregion
|
|
380
|
+
//#region src/builder.d.ts
|
|
381
|
+
type BuilderDeps = {
|
|
382
|
+
engine: Engine;
|
|
383
|
+
config: ResolvedConfig;
|
|
384
|
+
on_chunk: (chunk: StreamChunk) => void;
|
|
385
|
+
/** The `bash` executor for a sandboxed local builder (`docker exec` against
|
|
386
|
+
* the run's container), or null to use the host `spawnSync` default (the
|
|
387
|
+
* unsandboxed escape hatch, or `claude_cli` which supplies no volley tools). */
|
|
388
|
+
bash_executor?: BashExecutor | null;
|
|
389
|
+
/** Tools to hand the builder in place of volley's own set; absent, it gets
|
|
390
|
+
* that set. A `claude_cli` builder brings its own tools and never takes
|
|
391
|
+
* these. */
|
|
392
|
+
tools?: ReadonlyArray<Tool>;
|
|
393
|
+
/** Which set `tools` is, so the prompt names the tools the builder holds;
|
|
394
|
+
* absent, volley's own. */
|
|
395
|
+
tool_set?: ToolSet;
|
|
396
|
+
/** Answers each call to a tool that asks first (`needs_approval`). Like
|
|
397
|
+
* `tools`, it reaches every builder but `claude_cli`. Absent, such a call
|
|
398
|
+
* fails closed. */
|
|
399
|
+
on_tool_approval?: ToolApprovalHandler;
|
|
400
|
+
};
|
|
401
|
+
//#endregion
|
|
402
|
+
//#region src/critic/run.d.ts
|
|
403
|
+
/** A critic that holds tools isn't constrain-decoded, so nothing stops it
|
|
404
|
+
* answering null for the feedback or the unmet list, as GLM did on approving.
|
|
405
|
+
* Both fields allow null and read it as empty, so that answer is a verdict
|
|
406
|
+
* rather than a schema failure that ends the run. fascicle sends the schema's
|
|
407
|
+
* input side, so the model sees each field as its type or null, still
|
|
408
|
+
* required; `.describe()` comes last so the description stays on the field. */
|
|
409
|
+
export declare const verdict_schema: z.ZodObject<{
|
|
410
|
+
verdict: z.ZodEnum<{
|
|
411
|
+
approved: "approved";
|
|
412
|
+
changes_requested: "changes_requested";
|
|
413
|
+
}>;
|
|
414
|
+
feedback: z.ZodPipe<z.ZodNullable<z.ZodString>, z.ZodTransform<string, string | null>>;
|
|
415
|
+
unmet_criteria: z.ZodPipe<z.ZodNullable<z.ZodArray<z.ZodString>>, z.ZodTransform<string[], string[] | null>>;
|
|
416
|
+
}, z.core.$strip>;
|
|
417
|
+
type VerdictOutput = z.infer<typeof verdict_schema>;
|
|
418
|
+
type CriticDeps = {
|
|
419
|
+
engine: Engine;
|
|
420
|
+
config: ResolvedConfig;
|
|
421
|
+
on_chunk: (chunk: StreamChunk) => void;
|
|
422
|
+
/** Tools to hand the critic's tool-bearing call in place of volley's reads;
|
|
423
|
+
* absent, it gets those. A `claude_cli` critic reads through the CLI's own
|
|
424
|
+
* tools and never takes these. The critic takes no approval handler, since
|
|
425
|
+
* nothing it reads with should ever ask. */
|
|
426
|
+
tools?: ReadonlyArray<Tool>;
|
|
427
|
+
/** Which set `tools` is, so the harness append names the reads the critic
|
|
428
|
+
* holds; absent, volley's own. */
|
|
429
|
+
tool_set?: ToolSet;
|
|
430
|
+
};
|
|
431
|
+
//#endregion
|
|
296
432
|
//#region src/render/format.d.ts
|
|
297
433
|
type Role = 'builder' | 'critic' | 'check';
|
|
298
434
|
//#endregion
|
|
@@ -303,6 +439,9 @@ type RendererOptions = {
|
|
|
303
439
|
show_thinking: boolean;
|
|
304
440
|
color: boolean;
|
|
305
441
|
max_cost_usd: number | null;
|
|
442
|
+
/** Where the run's trajectory is written, named when verbose output is cut
|
|
443
|
+
* short (default: "the run's trajectory.jsonl"). */
|
|
444
|
+
trajectory_path?: string;
|
|
306
445
|
write?: (text: string) => void;
|
|
307
446
|
};
|
|
308
447
|
type Renderer = {
|
|
@@ -318,6 +457,30 @@ type Renderer = {
|
|
|
318
457
|
};
|
|
319
458
|
export declare function create_renderer(options: RendererOptions): Renderer;
|
|
320
459
|
//#endregion
|
|
460
|
+
//#region src/phases.d.ts
|
|
461
|
+
/** How the check runs when the caller sets it, as `volley acp` does. Left
|
|
462
|
+
* out, the check inherits volley's environment and runs unasked, as on the
|
|
463
|
+
* CLI. */
|
|
464
|
+
type CheckGate = {
|
|
465
|
+
/** The whole environment the check runs with, in place of volley's own. */
|
|
466
|
+
env?: Readonly<Record<string, string>>;
|
|
467
|
+
/** Asked on the check's card before each check, the way a model call asks
|
|
468
|
+
* before a gated tool runs. Anything short of an allow keeps the check from
|
|
469
|
+
* running, and it's recorded as failed. */
|
|
470
|
+
on_approval?: ToolApprovalHandler;
|
|
471
|
+
};
|
|
472
|
+
//#endregion
|
|
473
|
+
//#region src/flow.d.ts
|
|
474
|
+
/** The builder seat: the engine its calls go through, and, when the caller
|
|
475
|
+
* injects them, the tools that replace volley's own set, the name of that set
|
|
476
|
+
* (which its prompt names), and the handler that answers their approval
|
|
477
|
+
* requests. */
|
|
478
|
+
type BuilderSeat = Pick<BuilderDeps, 'engine' | 'tools' | 'tool_set' | 'on_tool_approval'>;
|
|
479
|
+
/** The critic seat: its engine and, when injected, the tools that replace its
|
|
480
|
+
* reads and the name of their set. It takes no approval handler, since its
|
|
481
|
+
* reads never ask. */
|
|
482
|
+
type CriticSeat = Pick<CriticDeps, 'engine' | 'tools' | 'tool_set'>;
|
|
483
|
+
//#endregion
|
|
321
484
|
//#region src/orchestrator.d.ts
|
|
322
485
|
type OrchestratorDeps = {
|
|
323
486
|
renderer: Renderer;
|
|
@@ -325,10 +488,45 @@ type OrchestratorDeps = {
|
|
|
325
488
|
* config. It serves both seats as-is, so the seat URLs then steer only
|
|
326
489
|
* volley's own requests (prewarm and the context probe), not model calls. */
|
|
327
490
|
engine?: Engine;
|
|
491
|
+
/** What to hand each seat in place of volley's own wiring: the builder's
|
|
492
|
+
* tools and the handler that answers their approval requests, and the
|
|
493
|
+
* critic's tools. A seat or a field left out keeps today's wiring, and a
|
|
494
|
+
* `claude_cli` seat, which brings its own tools, takes none of it. */
|
|
495
|
+
seats?: {
|
|
496
|
+
builder?: Omit<BuilderSeat, 'engine'>;
|
|
497
|
+
critic?: Omit<CriticSeat, 'engine'>;
|
|
498
|
+
};
|
|
499
|
+
/** A second sink for the run's trajectory, beside the run's
|
|
500
|
+
* `trajectory.jsonl`. With one, the flow runs through `run.stream`, so the
|
|
501
|
+
* sink also receives each model call's streamed chunks as `model_chunk`
|
|
502
|
+
* events, which the file never keeps. */
|
|
503
|
+
trajectory?: TrajectoryLogger;
|
|
504
|
+
/** The environment the check runs with and the approval it asks first, in
|
|
505
|
+
* place of inheriting volley's environment and running unasked. */
|
|
506
|
+
check?: CheckGate;
|
|
328
507
|
abort?: AbortSignal;
|
|
329
508
|
install_signal_handlers?: boolean;
|
|
330
509
|
};
|
|
331
510
|
export declare function run_volley(config: ResolvedConfig, deps: OrchestratorDeps, resume_from?: LoopState | null): Promise<RunResult>;
|
|
511
|
+
/** What a critique runs with: what a run does, less the builder's seat, plus
|
|
512
|
+
* the revision its change is measured from. */
|
|
513
|
+
type CritiqueDeps = Omit<OrchestratorDeps, 'seats'> & {
|
|
514
|
+
/** The revision the change under review is measured from (`--baseline`):
|
|
515
|
+
* everything that differs from it, committed or not, untracked files
|
|
516
|
+
* included. HEAD when absent, so the uncommitted edits are the change. */
|
|
517
|
+
baseline?: string;
|
|
518
|
+
/** The critic's tools in place of volley's reads, as for a run's critic. */
|
|
519
|
+
critic?: Omit<CriticSeat, 'engine'>;
|
|
520
|
+
};
|
|
521
|
+
/**
|
|
522
|
+
* `volley critique`: the check and the critic, once, over a change already
|
|
523
|
+
* made. No builder is constructed, and the engine serves the critic's seat
|
|
524
|
+
* alone, so a critic can be measured on fixed, labeled changes without paying
|
|
525
|
+
* for builder turns. It writes the state a one-round run does, with the mode
|
|
526
|
+
* recorded, and ends `success` on approval over a green check, else
|
|
527
|
+
* `rejected`.
|
|
528
|
+
*/
|
|
529
|
+
export declare function run_critique(config: ResolvedConfig, deps: CritiqueDeps): Promise<RunResult>;
|
|
332
530
|
//#endregion
|
|
333
531
|
//#region src/loop_state.d.ts
|
|
334
532
|
export declare function initial_state(): LoopState;
|
|
@@ -346,18 +544,14 @@ export declare function gate(config: ResolvedConfig, state: LoopState): {
|
|
|
346
544
|
};
|
|
347
545
|
export declare function status_of(value: LoopState, converged: boolean): RunStatus;
|
|
348
546
|
//#endregion
|
|
349
|
-
//#region src/critic/run.d.ts
|
|
350
|
-
export declare const verdict_schema: z.ZodObject<{
|
|
351
|
-
verdict: z.ZodEnum<{
|
|
352
|
-
approved: "approved";
|
|
353
|
-
changes_requested: "changes_requested";
|
|
354
|
-
}>;
|
|
355
|
-
feedback: z.ZodString;
|
|
356
|
-
unmet_criteria: z.ZodArray<z.ZodString>;
|
|
357
|
-
}, z.core.$strip>;
|
|
358
|
-
type VerdictOutput = z.infer<typeof verdict_schema>;
|
|
359
|
-
//#endregion
|
|
360
547
|
//#region src/sandbox.d.ts
|
|
548
|
+
/** Where volley inside the container keeps each run's state when no
|
|
549
|
+
* `--state-dir` names a root: the default root under the pinned `HOME`, since
|
|
550
|
+
* the image sets no `XDG_STATE_HOME`. `sandbox_run_args`'s `run_state` binds one
|
|
551
|
+
* run's host directory at that run's directory under it, so the state outlives
|
|
552
|
+
* the `--rm` container. Exported so a harness can map a contained run's
|
|
553
|
+
* `run_state_dir` back to the directory it mounted. */
|
|
554
|
+
export declare const SANDBOX_STATE_ROOT: string;
|
|
361
555
|
/** Canonical identity of the allowlist bridge the examples create (`docker
|
|
362
556
|
* network create --subnet <SANDBOX_NETWORK_SUBNET> <SANDBOX_NETWORK_NAME>`) and
|
|
363
557
|
* the host `DOCKER-USER` rules scope to. Exported so the blessed examples
|
|
@@ -403,7 +597,7 @@ export declare function network_run_args(network: SandboxNetwork, network_name:
|
|
|
403
597
|
/**
|
|
404
598
|
* The hardened `docker run` argv that launches volley inside its container.
|
|
405
599
|
* Pure and exported so the flag set is unit-testable without a
|
|
406
|
-
* daemon and the blessed examples
|
|
600
|
+
* daemon and the blessed examples and a parent harness can render it.
|
|
407
601
|
*
|
|
408
602
|
* A one-shot, foreground `--rm` container — the whole run *is* this
|
|
409
603
|
* container (an earlier design ran a detached `-d … sleep infinity` daemon volley
|
|
@@ -415,6 +609,25 @@ export declare function network_run_args(network: SandboxNetwork, network_name:
|
|
|
415
609
|
* the image entrypoint (the opt-in real-docker isolation test runs a raw `sh`
|
|
416
610
|
* this way).
|
|
417
611
|
*
|
|
612
|
+
* `run_state` binds the run's own state directory on the host,
|
|
613
|
+
* `<root>/<run_id>/`, at `<SANDBOX_STATE_ROOT>/<run_id>/`, where volley inside
|
|
614
|
+
* keeps that run's state when no `--state-dir` names a root, so it outlives the
|
|
615
|
+
* container at the path a run on the host would use. Only the one directory
|
|
616
|
+
* is mounted, never the root: the builder inside runs arbitrary commands, so
|
|
617
|
+
* it can rewrite its own run's state but can't read another run's trajectory
|
|
618
|
+
* or plant a check in another run's config. Its own run's state is still the
|
|
619
|
+
* builder's to rewrite, config.json included, so a host-side resume refuses
|
|
620
|
+
* that config, which volley signs only outside the sandbox (`./trust.ts`), and
|
|
621
|
+
* a directory holding a symlink: resume a contained run inside the container,
|
|
622
|
+
* with the same mount. Create the
|
|
623
|
+
* directory on the host first, empty (Docker on Linux makes a missing bind
|
|
624
|
+
* source owned by root, which the container's user can't write), and pass the
|
|
625
|
+
* same id to volley as `--run-id`. Keep it outside `build_root`, so the check
|
|
626
|
+
* never reads it, and pass no `XDG_STATE_HOME` in `env`, which would move the
|
|
627
|
+
* root off the mount. Omit it and no state is mounted: a contained run keeping
|
|
628
|
+
* its state under the default root then stops before spending (exit 5),
|
|
629
|
+
* since the read-only root filesystem leaves it nowhere to write.
|
|
630
|
+
*
|
|
418
631
|
* `store_volume` mounts the named volume as the pnpm store; omit it and no store
|
|
419
632
|
* is mounted. A store is shared by every run that mounts it, so a caller that
|
|
420
633
|
* installs dependencies in a separate container first can keep the builder's
|
|
@@ -424,13 +637,17 @@ export declare function network_run_args(network: SandboxNetwork, network_name:
|
|
|
424
637
|
* Never emits `--privileged` and refuses `--user 0`: volley must not hand
|
|
425
638
|
* the sandbox root or full capabilities. Everything writable under the
|
|
426
639
|
* `--read-only` rootfs is an explicit tmpfs or volume; the bind-mounted worktree
|
|
427
|
-
* is the
|
|
640
|
+
* and, when one is named, the state root are the host-visible write paths.
|
|
428
641
|
*/
|
|
429
642
|
export declare function sandbox_run_args(options: {
|
|
430
643
|
image: string;
|
|
431
644
|
build_root: string;
|
|
432
645
|
uid: number | null;
|
|
433
646
|
gid: number | null;
|
|
647
|
+
run_state?: {
|
|
648
|
+
root: string;
|
|
649
|
+
run_id: string;
|
|
650
|
+
} | null;
|
|
434
651
|
store_volume?: string | null;
|
|
435
652
|
network: SandboxNetwork;
|
|
436
653
|
network_name: string;
|
|
@@ -441,6 +658,13 @@ export declare function sandbox_run_args(options: {
|
|
|
441
658
|
command?: ReadonlyArray<string>;
|
|
442
659
|
}): string[];
|
|
443
660
|
//#endregion
|
|
661
|
+
//#region src/workspace.d.ts
|
|
662
|
+
/** The root each run's state sits under when `--state-dir` names none:
|
|
663
|
+
* `$XDG_STATE_HOME/volley`, else `<home>/.local/state/volley`. A relative
|
|
664
|
+
* `XDG_STATE_HOME` is ignored, as the XDG spec says. `home` is the host's by
|
|
665
|
+
* default; the sandbox passes its container's to spell the same root inside. */
|
|
666
|
+
export declare function default_state_root(env: Readonly<Record<string, string | undefined>>, home?: string): string;
|
|
667
|
+
//#endregion
|
|
444
668
|
//#region src/exit_codes.d.ts
|
|
445
669
|
export declare const EXIT_SUCCESS = 0;
|
|
446
670
|
export declare const EXIT_BUDGET_EXHAUSTED = 2;
|
|
@@ -453,5 +677,5 @@ export declare const EXIT_INTERRUPTED = 130;
|
|
|
453
677
|
export declare function exit_code_for_status(status: RunStatus): number;
|
|
454
678
|
export declare function exit_code_for_error(err: unknown): number;
|
|
455
679
|
//#endregion
|
|
456
|
-
export type { BuilderPermissionMode, CheckArtifact, CheckMode, CheckResult, CheckRunnerKind, CostSource, CriticPreset, CriticProvider, HaltReason, LoopState, PhaseRecord, RenderMode, Renderer, RendererOptions, ResolvedConfig, RunResult, RunStatus, SandboxNetwork, Verdict, VerdictOutput, VolleyConfig };
|
|
680
|
+
export type { BuilderPermissionMode, CheckArtifact, CheckMode, CheckResult, CheckRunnerKind, CostSource, CriticPreset, CriticProvider, CritiqueDeps, HaltReason, LoopState, PhaseRecord, RenderMode, Renderer, RendererOptions, ResolvedConfig, RunMode, RunResult, RunStatus, SandboxNetwork, Verdict, VerdictOutput, VolleyConfig };
|
|
457
681
|
//# sourceMappingURL=index.d.ts.map
|