@bjoernrochel/sevro 0.1.0-rc.8 → 1.0.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/CONTRIBUTING.md +22 -6
- package/README.md +5 -1
- package/docs/README.md +19 -15
- package/docs/architecture.md +138 -17
- package/docs/assets/README.md +5 -4
- package/docs/builtin-graders-v1.md +9 -2
- package/docs/codex-host.md +155 -57
- package/docs/contracts.md +2 -1
- package/docs/creating-cases.md +9 -2
- package/docs/development-cli.md +187 -19
- package/docs/documentation-quality.md +12 -2
- package/docs/evaluation-workflow.md +110 -0
- package/docs/extension-protocol-v1.md +26 -3
- package/docs/getting-started.md +23 -2
- package/docs/guide-evaluation.md +33 -1
- package/docs/identity-v1.md +25 -2
- package/docs/installing.md +11 -11
- package/docs/native-controls.md +76 -5
- package/docs/native-hosts.md +196 -7
- package/docs/reading-results.md +102 -0
- package/docs/recipes.md +489 -0
- package/docs/releases.md +31 -12
- package/docs/report-v1.md +29 -1
- package/docs/results-v1.md +122 -4
- package/docs/run-settings-v1.md +147 -0
- package/docs/runtime-v1.md +255 -22
- package/docs/troubleshooting.md +12 -12
- package/docs/typescript-quality.md +89 -26
- package/examples/recipes/candidate.ts +26 -0
- package/examples/recipes/cases/coding-change.json +21 -0
- package/examples/recipes/cases/host-tools.json +21 -0
- package/examples/recipes/cases/mise.json +21 -0
- package/examples/recipes/cases/node.json +21 -0
- package/examples/recipes/cases/python-uv.json +21 -0
- package/examples/recipes/cases/semantic.json +17 -0
- package/examples/recipes/coding-change/check.ts +23 -0
- package/examples/recipes/extension-artifacts.ts +65 -0
- package/examples/recipes/extension-methods.ts +174 -0
- package/examples/recipes/extension.ts +37 -0
- package/examples/recipes/repository-skill/.agents/skills/startup-guide/SKILL.md +7 -0
- package/examples/recipes/repository-skill/.claude/skills/startup-guide/SKILL.md +7 -0
- package/examples/recipes/repository-skill/README.md +3 -0
- package/examples/recipes/run-inputs.ts +188 -0
- package/examples/recipes/run-options.ts +131 -0
- package/examples/recipes/run.ts +63 -0
- package/examples/recipes/runtime/empty.json +1 -0
- package/examples/recipes/runtime/goals.json +1 -0
- package/examples/recipes/runtime/mise.json +6 -0
- package/examples/recipes/runtime/path.json +1 -0
- package/examples/recipes/runtime/plugins.json +4 -0
- package/examples/recipes/runtime/python-uv.json +10 -0
- package/examples/recipes/semantic-judge.ts +29 -0
- package/examples/templates/coding/adapter.ts +17 -0
- package/examples/templates/coding/case.json +15 -0
- package/examples/templates/repository-skill/.agents/skills/startup-guide/SKILL.md +6 -0
- package/examples/templates/repository-skill/extension-data.ts +64 -0
- package/examples/templates/repository-skill/extension.ts +31 -0
- package/examples/templates/response/adapter.ts +12 -0
- package/examples/templates/response/case.json +13 -0
- package/package.json +11 -5
- package/schemas/report-v1.schema.json +9 -0
- package/schemas/run-evidence-v1.schema.json +2 -1
- package/schemas/runtime-v1.schema.json +43 -7
- package/src/advisory.ts +2 -2
- package/src/candidate-artifacts.ts +42 -11
- package/src/candidate-codex-state.ts +185 -0
- package/src/case-validation.ts +73 -50
- package/src/cli/cancellation.ts +20 -0
- package/src/cli/command.ts +87 -0
- package/src/cli/completion.ts +15 -0
- package/src/cli/demo.ts +60 -0
- package/src/cli/evaluation.ts +55 -0
- package/src/cli/extension.ts +79 -0
- package/src/cli/help.ts +198 -0
- package/src/cli/hosts.ts +55 -0
- package/src/cli/init-settings.ts +30 -0
- package/src/cli/init.ts +111 -0
- package/src/{cli-invocation.ts → cli/invocation.ts} +214 -218
- package/src/cli/loading.ts +151 -0
- package/src/cli/preparation.ts +154 -0
- package/src/cli/presentation.ts +93 -0
- package/src/cli/progress.ts +6 -0
- package/src/cli/run-manifest.ts +128 -0
- package/src/cli/run-options.ts +403 -0
- package/src/cli/run-overrides.ts +69 -0
- package/src/cli/settings.ts +154 -0
- package/src/cli/summary.ts +43 -0
- package/src/cli.ts +13 -591
- package/src/contract-types.ts +94 -0
- package/src/engine.ts +9 -5
- package/src/evaluation/advisory.ts +150 -0
- package/src/{evaluation-check-plan.ts → evaluation/check-plan.ts} +103 -67
- package/src/evaluation/collection.ts +88 -0
- package/src/evaluation/context.ts +10 -0
- package/src/{evaluation-grading-host.ts → evaluation/grading-host.ts} +5 -5
- package/src/evaluation/grading.ts +235 -0
- package/src/{evaluation-invocation-plan.ts → evaluation/invocation-plan.ts} +147 -58
- package/src/{evaluation-plan.ts → evaluation/plan.ts} +208 -141
- package/src/evaluation/progress.ts +19 -0
- package/src/evaluation/resources.ts +241 -0
- package/src/evaluation/run.ts +206 -0
- package/src/{evaluation-semantic.ts → evaluation/semantic.ts} +77 -87
- package/src/evaluation/trial.ts +800 -0
- package/src/{evaluation-types.ts → evaluation/types.ts} +79 -29
- package/src/evidence/host-results.ts +85 -0
- package/src/evidence/retained-artifacts.ts +18 -0
- package/src/evidence/trial-writer.ts +203 -0
- package/src/evidence/usage.ts +17 -0
- package/src/extension-client.ts +34 -96
- package/src/extension-session.ts +24 -48
- package/src/{advisory-fixture.ts → fixtures/advisory.ts} +12 -72
- package/src/{fixture-bin.ts → fixtures/bin.ts} +1 -1
- package/src/{fixture-cleanup.ts → fixtures/cleanup.ts} +13 -7
- package/src/fixtures/create.ts +183 -0
- package/src/{generated-fixture.ts → fixtures/generated.ts} +10 -53
- package/src/{git-hooks.ts → fixtures/git-hooks.ts} +1 -1
- package/src/{preparation.ts → fixtures/preparation.ts} +6 -16
- package/src/{repository-fixture.ts → fixtures/repository.ts} +30 -64
- package/src/{fixture-setup.ts → fixtures/setup.ts} +33 -51
- package/src/{fixture-tools.ts → fixtures/tools.ts} +1 -1
- package/src/{workspace-state.ts → fixtures/workspace-state.ts} +5 -5
- package/src/generated/cli-result.d.cts +2 -1
- package/src/generated/extension.d.cts +2 -1
- package/src/generated/report.cjs +1 -1
- package/src/generated/report.d.cts +2 -1
- package/src/generated/run-evidence.cjs +1 -1
- package/src/generated/run-evidence.d.cts +2 -1
- package/src/generated/runtime.cjs +1 -1
- package/src/generated/runtime.d.cts +2 -1
- package/src/git.ts +93 -0
- package/src/graders/git-head.ts +29 -84
- package/src/graders/shell.ts +50 -68
- package/src/host-diagnostic-redaction.ts +52 -0
- package/src/host-diagnostics.ts +331 -0
- package/src/hosts/claude-continuation.ts +57 -40
- package/src/hosts/claude-credential.ts +160 -63
- package/src/hosts/claude-events.ts +34 -18
- package/src/hosts/claude-keychain.ts +78 -21
- package/src/hosts/claude-login-recovery.ts +85 -0
- package/src/hosts/claude-login-refresh.ts +178 -0
- package/src/hosts/claude-login-store.ts +162 -0
- package/src/hosts/claude-login.ts +107 -0
- package/src/hosts/claude-native-goal.ts +15 -12
- package/src/hosts/claude-process.ts +10 -50
- package/src/hosts/claude-refresh-lock.ts +81 -0
- package/src/hosts/claude-repository-invocation.ts +9 -34
- package/src/hosts/claude-settings.ts +46 -9
- package/src/hosts/claude-skill-activations.ts +169 -0
- package/src/hosts/claude-state.ts +28 -15
- package/src/hosts/claude-tool-calls.ts +13 -10
- package/src/hosts/claude.ts +121 -81
- package/src/hosts/codex-app-server.ts +78 -52
- package/src/hosts/codex-configuration.ts +5 -10
- package/src/hosts/codex-exec-controls.ts +516 -0
- package/src/hosts/codex-marketplace.ts +12 -10
- package/src/hosts/codex-native-calls.ts +15 -122
- package/src/hosts/codex-process.ts +10 -183
- package/src/hosts/codex-profile.ts +36 -21
- package/src/hosts/codex-session-files.ts +1 -9
- package/src/hosts/codex-state.ts +134 -18
- package/src/hosts/codex.ts +210 -183
- package/src/hosts/isolation-common.ts +8 -11
- package/src/hosts/isolation-roots.ts +2 -2
- package/src/hosts/linux-sandbox.ts +15 -2
- package/src/hosts/mac-sandbox.ts +87 -18
- package/src/hosts/native-controls.ts +72 -22
- package/src/hosts/native-request.ts +55 -0
- package/src/hosts/process-lifecycle.ts +216 -48
- package/src/hosts/protected-worktrees.ts +1 -1
- package/src/hosts/skill-hook-catalog.ts +131 -0
- package/src/hosts/skill-hook-handler.ts +374 -0
- package/src/hosts/skill-hooks.ts +577 -0
- package/src/instrumentation.ts +7 -8
- package/src/native-transcript-state.ts +22 -3
- package/src/native-transcript-view.ts +52 -13
- package/src/native-transcripts.ts +26 -11
- package/src/paths.ts +22 -0
- package/src/process-lifecycle.ts +150 -0
- package/src/provenance.ts +27 -7
- package/src/prune.ts +300 -0
- package/src/report.ts +63 -36
- package/src/resolved-case.ts +1 -1
- package/src/results-lock.ts +42 -0
- package/src/results.ts +14 -18
- package/src/{runtime-config.ts → runtime/config.ts} +160 -46
- package/src/{runtime-discovery-apple.ts → runtime/discovery-apple.ts} +3 -3
- package/src/{runtime-discovery-providers.ts → runtime/discovery-providers.ts} +3 -9
- package/src/{runtime-discovery.ts → runtime/discovery.ts} +4 -4
- package/src/{runtime-hook-processes.ts → runtime/hook-processes.ts} +1 -1
- package/src/{runtime-hooks.ts → runtime/hooks.ts} +32 -22
- package/src/{runtime-paths.ts → runtime/paths.ts} +5 -19
- package/src/{runtime-query.ts → runtime/query.ts} +5 -5
- package/src/{runtime-seeds.ts → runtime/seeds.ts} +3 -3
- package/src/runtime/shared-cache.ts +130 -0
- package/src/{runtime-state.ts → runtime/state.ts} +28 -11
- package/src/schema-types.ts +73 -161
- package/src/shell.ts +4 -0
- package/src/transcript-retention.ts +146 -0
- package/src/value-guards.ts +22 -0
- package/docs/assets/sevro-logo.png +0 -0
- package/docs/assets/sevro-symbol.svg +0 -1
- package/docs/assets/sevro-wordmark.svg +0 -1
- package/docs/cache-ownership-validation.md +0 -49
- package/docs/claude-continuation-validation.md +0 -47
- package/docs/concurrency-validation.md +0 -86
- package/docs/configuration-root-validation.md +0 -70
- package/docs/engine-slice.md +0 -114
- package/docs/evidence/runtime-startup-30/README.md +0 -185
- package/docs/evidence/runtime-startup-30/after.json +0 -319
- package/docs/evidence/runtime-startup-30/baseline-timeout.jsonl +0 -2
- package/docs/evidence/runtime-startup-30/before.json +0 -403
- package/docs/evidence/runtime-startup-30/consumer-smoke.json +0 -63
- package/docs/evidence/runtime-startup-30/full-policy-diagnostic.jsonl +0 -3
- package/docs/evidence/runtime-startup-30/minimal-policy-diagnostic.jsonl +0 -3
- package/docs/evidence/runtime-startup-30/plugin-template-assessment.json +0 -20
- package/docs/evidence/runtime-startup-30/seedless-timeout.jsonl +0 -2
- package/docs/evidence.md +0 -17
- package/docs/fixture-cleanup-validation.md +0 -73
- package/docs/guide-verification.json +0 -239
- package/src/evaluation-context.ts +0 -259
- package/src/evaluation-fixture.ts +0 -302
- package/src/evaluation-run.ts +0 -200
- package/src/evaluation-trial.ts +0 -1016
- package/src/hosts/claude-nested-skills.ts +0 -272
- package/src/hosts/codex-command-output.ts +0 -510
- package/src/hosts/codex-executor-command.ts +0 -291
- package/src/hosts/codex-skill-reads.ts +0 -783
- /package/src/{trial-scheduler.ts → evaluation/scheduler.ts} +0 -0
|
@@ -1,26 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import { validQualifiedId } from "../value-guards";
|
|
3
|
+
import { canonicalRuntimeRoot } from "../runtime/paths";
|
|
4
|
+
import {
|
|
5
|
+
PATH_OPTIONS,
|
|
6
|
+
PATH_LIST_OPTIONS,
|
|
7
|
+
EXTENSION_OPTIONS,
|
|
8
|
+
RUN_OPTIONS,
|
|
9
|
+
optionsWith,
|
|
10
|
+
runArguments,
|
|
11
|
+
} from "./run-options";
|
|
12
|
+
import { savedRunValues } from "./run-manifest";
|
|
3
13
|
|
|
4
14
|
export class InvocationError extends Error {}
|
|
5
15
|
|
|
6
16
|
function requiredOption(value: string | undefined, name: string): string {
|
|
7
|
-
if (!value)
|
|
17
|
+
if (!value)
|
|
18
|
+
throw new InvocationError(`missing ${name}; supply ${name} with a value`);
|
|
8
19
|
return value;
|
|
9
20
|
}
|
|
10
21
|
|
|
11
|
-
function absoluteOption(value: string | undefined, name: string): string {
|
|
12
|
-
const path = requiredOption(value, name);
|
|
13
|
-
if (!isAbsolute(path)) throw new InvocationError(`${name} must be absolute`);
|
|
14
|
-
return path;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function optionalAbsolute(
|
|
18
|
-
value: string | undefined,
|
|
19
|
-
name: string,
|
|
20
|
-
): string | undefined {
|
|
21
|
-
return value ? absoluteOption(value, name) : undefined;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
22
|
function optionalDigest(value: string | undefined, name: string) {
|
|
25
23
|
if (value !== undefined && !/^[a-f0-9]{64}$/.test(value))
|
|
26
24
|
throw new InvocationError(`${name} must be a 64-character SHA-256 digest`);
|
|
@@ -30,71 +28,16 @@ function optionalDigest(value: string | undefined, name: string) {
|
|
|
30
28
|
function conditionOption(value: string | undefined): "passive" | "enforced" {
|
|
31
29
|
const condition = requiredOption(value, "--condition");
|
|
32
30
|
if (condition !== "passive" && condition !== "enforced")
|
|
33
|
-
throw new InvocationError("invalid --condition");
|
|
31
|
+
throw new InvocationError("invalid --condition; use passive or enforced");
|
|
34
32
|
return condition;
|
|
35
33
|
}
|
|
36
34
|
|
|
37
|
-
const RUN_OPTIONS = {
|
|
38
|
-
json: { type: "boolean" },
|
|
39
|
-
dry: { type: "boolean" },
|
|
40
|
-
"case-file": { type: "string" },
|
|
41
|
-
"case-id": { type: "string" },
|
|
42
|
-
"extension-command-file": { type: "string" },
|
|
43
|
-
"extension-source-file": { type: "string", multiple: true },
|
|
44
|
-
"extension-configuration-file": { type: "string" },
|
|
45
|
-
"extension-redacted-configuration-file": { type: "string" },
|
|
46
|
-
"task-verdict-policy": { type: "string" },
|
|
47
|
-
"replace-builtin-grader": { type: "string", multiple: true },
|
|
48
|
-
"case-source-root": { type: "string" },
|
|
49
|
-
"case-source-map-file": { type: "string" },
|
|
50
|
-
"adapter-module": { type: "string" },
|
|
51
|
-
"semantic-adapter-module": { type: "string" },
|
|
52
|
-
"semantic-host": { type: "string" },
|
|
53
|
-
"semantic-model": { type: "string" },
|
|
54
|
-
"semantic-effort": { type: "string" },
|
|
55
|
-
"advisory-adapter-module": { type: "string" },
|
|
56
|
-
"advisory-host": { type: "string" },
|
|
57
|
-
"advisory-model": { type: "string" },
|
|
58
|
-
"advisory-effort": { type: "string" },
|
|
59
|
-
"advisory-exclude": { type: "string", multiple: true },
|
|
60
|
-
host: { type: "string" },
|
|
61
|
-
"codex-bin": { type: "string" },
|
|
62
|
-
"codex-entrypoint": { type: "string" },
|
|
63
|
-
"codex-timeout-ms": { type: "string" },
|
|
64
|
-
"codex-auth-file": { type: "string" },
|
|
65
|
-
"claude-bin": { type: "string" },
|
|
66
|
-
"claude-credential-file": { type: "string" },
|
|
67
|
-
"claude-uv-cache-dir": { type: "string" },
|
|
68
|
-
"claude-project-settings": { type: "boolean" },
|
|
69
|
-
"toolchain-bin-dir": { type: "string" },
|
|
70
|
-
model: { type: "string" },
|
|
71
|
-
effort: { type: "string" },
|
|
72
|
-
"shell-isolation": { type: "boolean" },
|
|
73
|
-
"protected-root": { type: "string", multiple: true },
|
|
74
|
-
"project-root": { type: "string" },
|
|
75
|
-
"config-root": { type: "string" },
|
|
76
|
-
"runtime-config-file": { type: "string" },
|
|
77
|
-
"results-root": { type: "string" },
|
|
78
|
-
"run-state-root": { type: "string" },
|
|
79
|
-
"runner-build-digest": { type: "string" },
|
|
80
|
-
"runner-checkout-root": { type: "string" },
|
|
81
|
-
"project-digest": { type: "string" },
|
|
82
|
-
condition: { type: "string" },
|
|
83
|
-
trials: { type: "string" },
|
|
84
|
-
jobs: { type: "string", default: "3" },
|
|
85
|
-
threshold: { type: "string" },
|
|
86
|
-
} as const;
|
|
87
|
-
|
|
88
35
|
function cliArguments(argv: string[]) {
|
|
89
36
|
try {
|
|
90
|
-
return
|
|
91
|
-
args: argv,
|
|
92
|
-
allowPositionals: true,
|
|
93
|
-
strict: true,
|
|
94
|
-
options: RUN_OPTIONS,
|
|
95
|
-
});
|
|
37
|
+
return runArguments(argv);
|
|
96
38
|
} catch (cause) {
|
|
97
|
-
|
|
39
|
+
const detail = cause instanceof Error ? `: ${cause.message}` : "";
|
|
40
|
+
throw new InvocationError(`invalid CLI arguments${detail}`, { cause });
|
|
98
41
|
}
|
|
99
42
|
}
|
|
100
43
|
|
|
@@ -112,24 +55,29 @@ function trialParameters(values: Values) {
|
|
|
112
55
|
passThreshold <= 0 ||
|
|
113
56
|
passThreshold > 1
|
|
114
57
|
)
|
|
115
|
-
throw new InvocationError(
|
|
58
|
+
throw new InvocationError(
|
|
59
|
+
"invalid --threshold; supply a number greater than 0 and at most 1",
|
|
60
|
+
);
|
|
116
61
|
return { condition, trialCount, jobs, passThreshold };
|
|
117
62
|
}
|
|
118
63
|
|
|
119
64
|
function positiveInteger(value: number, option: string): void {
|
|
120
65
|
if (!Number.isSafeInteger(value) || value < 1)
|
|
121
|
-
throw new InvocationError(`invalid ${option}`);
|
|
66
|
+
throw new InvocationError(`invalid ${option}; supply a positive integer`);
|
|
122
67
|
}
|
|
123
68
|
|
|
124
69
|
function hostRoutes(values: Values) {
|
|
125
70
|
const codex = values.host === "codex";
|
|
126
71
|
const claude = values.host === "claude";
|
|
72
|
+
const semanticCodex = values["semantic-host"] === "codex";
|
|
73
|
+
const advisoryCodex = values["advisory-host"] === "codex";
|
|
127
74
|
return {
|
|
128
75
|
codex,
|
|
129
76
|
claude,
|
|
130
77
|
builtinHost: codex || claude,
|
|
131
|
-
semanticCodex
|
|
132
|
-
advisoryCodex
|
|
78
|
+
semanticCodex,
|
|
79
|
+
advisoryCodex,
|
|
80
|
+
anyCodex: codex || semanticCodex || advisoryCodex,
|
|
133
81
|
};
|
|
134
82
|
}
|
|
135
83
|
|
|
@@ -147,15 +95,15 @@ const HOST_COMPATIBILITY: CompatibilityRule[] = [
|
|
|
147
95
|
},
|
|
148
96
|
{
|
|
149
97
|
invalid: (v, r) => v.host && !r.builtinHost,
|
|
150
|
-
message: "unsupported --host",
|
|
98
|
+
message: "unsupported --host; use codex or claude",
|
|
151
99
|
},
|
|
152
100
|
{
|
|
153
101
|
invalid: (v, r) => v["semantic-host"] && !r.semanticCodex,
|
|
154
|
-
message: "unsupported --semantic-host",
|
|
102
|
+
message: "unsupported --semantic-host; use codex",
|
|
155
103
|
},
|
|
156
104
|
{
|
|
157
105
|
invalid: (v, r) => v["advisory-host"] && !r.advisoryCodex,
|
|
158
|
-
message: "unsupported --advisory-host",
|
|
106
|
+
message: "unsupported --advisory-host; use codex",
|
|
159
107
|
},
|
|
160
108
|
{
|
|
161
109
|
invalid: (v, r) => r.semanticCodex && v["semantic-adapter-module"],
|
|
@@ -195,24 +143,11 @@ const HOST_COMPATIBILITY: CompatibilityRule[] = [
|
|
|
195
143
|
message: "--advisory-exclude requires an advisory route",
|
|
196
144
|
},
|
|
197
145
|
{
|
|
198
|
-
invalid: (v, r) =>
|
|
199
|
-
!r.codex &&
|
|
200
|
-
!r.semanticCodex &&
|
|
201
|
-
!r.advisoryCodex &&
|
|
202
|
-
[
|
|
203
|
-
v["codex-bin"],
|
|
204
|
-
v["codex-auth-file"],
|
|
205
|
-
v["codex-timeout-ms"] !== undefined,
|
|
206
|
-
].some(Boolean),
|
|
146
|
+
invalid: (v, r) => !r.anyCodex && hasRouteOptions(v, "codex"),
|
|
207
147
|
message: "Codex options require a Codex host route",
|
|
208
148
|
},
|
|
209
149
|
{
|
|
210
|
-
invalid: (v, r) =>
|
|
211
|
-
!r.claude &&
|
|
212
|
-
(v["claude-bin"] ||
|
|
213
|
-
v["claude-credential-file"] ||
|
|
214
|
-
v["claude-uv-cache-dir"] ||
|
|
215
|
-
v["claude-project-settings"]),
|
|
150
|
+
invalid: (v, r) => !r.claude && hasRouteOptions(v, "claude"),
|
|
216
151
|
message: "Claude options require --host claude",
|
|
217
152
|
},
|
|
218
153
|
{
|
|
@@ -226,6 +161,13 @@ const HOST_COMPATIBILITY: CompatibilityRule[] = [
|
|
|
226
161
|
},
|
|
227
162
|
];
|
|
228
163
|
|
|
164
|
+
function hasRouteOptions(values: Values, route: "codex" | "claude"): boolean {
|
|
165
|
+
return optionsWith("route", route).some((name) => {
|
|
166
|
+
if (RUN_OPTIONS[name].kind === "number") return values[name] !== undefined;
|
|
167
|
+
return Boolean(values[name]);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
229
171
|
function validateHostCompatibility(
|
|
230
172
|
values: Values,
|
|
231
173
|
routes: Routes,
|
|
@@ -237,24 +179,20 @@ function validateHostCompatibility(
|
|
|
237
179
|
}
|
|
238
180
|
|
|
239
181
|
function rootParameters(values: Values) {
|
|
240
|
-
const projectRoot =
|
|
182
|
+
const projectRoot = requiredOption(values["project-root"], "--project-root");
|
|
241
183
|
const configRoot =
|
|
242
184
|
values["config-root"] !== undefined
|
|
243
|
-
?
|
|
185
|
+
? requiredOption(values["config-root"], "--config-root")
|
|
244
186
|
: projectRoot;
|
|
245
|
-
const resultsRoot =
|
|
187
|
+
const resultsRoot = requiredOption(values["results-root"], "--results-root");
|
|
246
188
|
const runStateRoot = values["run-state-root"]
|
|
247
|
-
?
|
|
189
|
+
? requiredOption(values["run-state-root"], "--run-state-root")
|
|
248
190
|
: resultsRoot;
|
|
249
191
|
return { projectRoot, configRoot, resultsRoot, runStateRoot };
|
|
250
192
|
}
|
|
251
193
|
|
|
252
194
|
type Roots = ReturnType<typeof rootParameters>;
|
|
253
195
|
|
|
254
|
-
function validQualifiedId(id: string): boolean {
|
|
255
|
-
return /^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)+$/.test(id);
|
|
256
|
-
}
|
|
257
|
-
|
|
258
196
|
function validateExtensionSelection(values: Values): void {
|
|
259
197
|
const policy = values["task-verdict-policy"];
|
|
260
198
|
if (policy !== undefined && !validQualifiedId(policy))
|
|
@@ -280,24 +218,18 @@ function validateReplacements(replacements: string[]): void {
|
|
|
280
218
|
}
|
|
281
219
|
|
|
282
220
|
function hasExtensionArguments(values: Values): boolean {
|
|
283
|
-
return (
|
|
284
|
-
[
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
].some(Boolean) ||
|
|
290
|
-
values["task-verdict-policy"] !== undefined ||
|
|
291
|
-
(values["replace-builtin-grader"] ?? []).length > 0
|
|
292
|
-
);
|
|
221
|
+
return EXTENSION_OPTIONS.some((name) => {
|
|
222
|
+
const value = values[name];
|
|
223
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
224
|
+
if (name === "task-verdict-policy") return value !== undefined;
|
|
225
|
+
return Boolean(value);
|
|
226
|
+
});
|
|
293
227
|
}
|
|
294
228
|
|
|
295
229
|
function extensionSources(values: Values): string[] {
|
|
296
230
|
const sources = values["extension-source-file"];
|
|
297
231
|
if (!sources?.length)
|
|
298
232
|
throw new InvocationError("missing --extension-source-file");
|
|
299
|
-
if (sources.some((path) => !isAbsolute(path)))
|
|
300
|
-
throw new InvocationError("--extension-source-file must be absolute");
|
|
301
233
|
return sources;
|
|
302
234
|
}
|
|
303
235
|
|
|
@@ -334,42 +266,36 @@ function privateRootDeclarations(
|
|
|
334
266
|
return [
|
|
335
267
|
configRoot,
|
|
336
268
|
...protectedRoots,
|
|
337
|
-
values[
|
|
338
|
-
values["codex-auth-file"],
|
|
339
|
-
values["runtime-config-file"],
|
|
340
|
-
values["case-file"],
|
|
341
|
-
values["extension-command-file"],
|
|
342
|
-
...(values["extension-source-file"] ?? []),
|
|
343
|
-
values["extension-configuration-file"],
|
|
344
|
-
values["extension-redacted-configuration-file"],
|
|
345
|
-
values["case-source-root"],
|
|
346
|
-
values["case-source-map-file"],
|
|
347
|
-
values["semantic-adapter-module"],
|
|
348
|
-
values["advisory-adapter-module"],
|
|
269
|
+
...optionsWith("private", true).flatMap((name) => values[name] ?? []),
|
|
349
270
|
].filter((value): value is string => Boolean(value));
|
|
350
271
|
}
|
|
351
272
|
|
|
352
273
|
function commonCodexOptions(
|
|
353
274
|
values: Values,
|
|
354
|
-
routes: Routes,
|
|
355
275
|
roots: Roots,
|
|
356
276
|
privateRoots: string[],
|
|
357
277
|
) {
|
|
358
|
-
if (![routes.codex, routes.semanticCodex, routes.advisoryCodex].some(Boolean))
|
|
359
|
-
return undefined;
|
|
360
278
|
return {
|
|
361
|
-
binary:
|
|
362
|
-
authFile:
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
? undefined
|
|
366
|
-
: Number(values["codex-timeout-ms"]),
|
|
279
|
+
binary: requiredOption(values["codex-bin"], "--codex-bin"),
|
|
280
|
+
authFile: requiredOption(values["codex-auth-file"], "--codex-auth-file"),
|
|
281
|
+
retainHostDiagnostics: values["retain-host-diagnostics"] === true,
|
|
282
|
+
timeoutMs: codexTimeout(values["codex-timeout-ms"]),
|
|
367
283
|
projectRoot: roots.projectRoot,
|
|
368
284
|
resultsRoot: roots.resultsRoot,
|
|
369
285
|
additionalProtectedRoots: [...privateRoots, roots.runStateRoot],
|
|
370
286
|
};
|
|
371
287
|
}
|
|
372
288
|
|
|
289
|
+
function codexTimeout(value: string | undefined): number | undefined {
|
|
290
|
+
if (value === undefined) return undefined;
|
|
291
|
+
const timeout = Number(value);
|
|
292
|
+
if (!Number.isSafeInteger(timeout) || timeout < 1 || timeout > 30 * 60_000)
|
|
293
|
+
throw new InvocationError(
|
|
294
|
+
"invalid --codex-timeout-ms; supply a positive integer at most 1800000 (30 minutes)",
|
|
295
|
+
);
|
|
296
|
+
return timeout;
|
|
297
|
+
}
|
|
298
|
+
|
|
373
299
|
function claudeHostOptions(
|
|
374
300
|
values: Values,
|
|
375
301
|
routes: Routes,
|
|
@@ -379,10 +305,11 @@ function claudeHostOptions(
|
|
|
379
305
|
) {
|
|
380
306
|
if (!routes.claude) return undefined;
|
|
381
307
|
return {
|
|
382
|
-
|
|
308
|
+
retainHostDiagnostics: values["retain-host-diagnostics"] === true,
|
|
309
|
+
binary: requiredOption(values["claude-bin"], "--claude-bin"),
|
|
383
310
|
...(values["claude-credential-file"]
|
|
384
311
|
? {
|
|
385
|
-
credentialFile:
|
|
312
|
+
credentialFile: requiredOption(
|
|
386
313
|
values["claude-credential-file"],
|
|
387
314
|
"--claude-credential-file",
|
|
388
315
|
),
|
|
@@ -390,7 +317,7 @@ function claudeHostOptions(
|
|
|
390
317
|
: {}),
|
|
391
318
|
...(values["claude-uv-cache-dir"]
|
|
392
319
|
? {
|
|
393
|
-
uvCacheDir:
|
|
320
|
+
uvCacheDir: requiredOption(
|
|
394
321
|
values["claude-uv-cache-dir"],
|
|
395
322
|
"--claude-uv-cache-dir",
|
|
396
323
|
),
|
|
@@ -410,17 +337,11 @@ function extensionInvocation(values: Values) {
|
|
|
410
337
|
const command = values["extension-command-file"];
|
|
411
338
|
if (!command) return undefined;
|
|
412
339
|
return {
|
|
413
|
-
commandFile:
|
|
340
|
+
commandFile: requiredOption(command, "--extension-command-file"),
|
|
414
341
|
sourceFiles: extensionSources(values),
|
|
415
342
|
caseId: requiredOption(values["case-id"], "--case-id"),
|
|
416
|
-
configurationFile:
|
|
417
|
-
|
|
418
|
-
"--extension-configuration-file",
|
|
419
|
-
),
|
|
420
|
-
redactedConfigurationFile: optionalAbsolute(
|
|
421
|
-
values["extension-redacted-configuration-file"],
|
|
422
|
-
"--extension-redacted-configuration-file",
|
|
423
|
-
),
|
|
343
|
+
configurationFile: values["extension-configuration-file"],
|
|
344
|
+
redactedConfigurationFile: values["extension-redacted-configuration-file"],
|
|
424
345
|
taskVerdictPolicy: values["task-verdict-policy"],
|
|
425
346
|
replaceBuiltinGraders: values["replace-builtin-grader"] ?? [],
|
|
426
347
|
};
|
|
@@ -435,16 +356,15 @@ const CODEX_MODEL_KEYS = {
|
|
|
435
356
|
function codexRoleOptions(
|
|
436
357
|
values: Values,
|
|
437
358
|
common: ReturnType<typeof commonCodexOptions>,
|
|
438
|
-
enabled: boolean,
|
|
439
359
|
role: keyof typeof CODEX_MODEL_KEYS,
|
|
440
360
|
) {
|
|
441
|
-
if (!enabled) return undefined;
|
|
442
|
-
if (!common)
|
|
443
|
-
throw new InvocationError("Codex options require a Codex host route");
|
|
444
361
|
const [modelKey, effortKey] = CODEX_MODEL_KEYS[role];
|
|
445
362
|
return {
|
|
446
363
|
...(role === "candidate"
|
|
447
|
-
? {
|
|
364
|
+
? {
|
|
365
|
+
entrypoint: values["codex-entrypoint"] as
|
|
366
|
+
"exec" | "app-server" | undefined,
|
|
367
|
+
}
|
|
448
368
|
: {}),
|
|
449
369
|
...common,
|
|
450
370
|
model: requiredOption(values[modelKey], `--${modelKey}`),
|
|
@@ -452,15 +372,25 @@ function codexRoleOptions(
|
|
|
452
372
|
};
|
|
453
373
|
}
|
|
454
374
|
|
|
455
|
-
function
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
return
|
|
375
|
+
function selectedCodexOptions(
|
|
376
|
+
values: Values,
|
|
377
|
+
routes: Routes,
|
|
378
|
+
roots: Roots,
|
|
379
|
+
privateRoots: string[],
|
|
380
|
+
) {
|
|
381
|
+
if (!routes.anyCodex) return {};
|
|
382
|
+
const common = commonCodexOptions(values, roots, privateRoots);
|
|
383
|
+
return {
|
|
384
|
+
codex: routes.codex
|
|
385
|
+
? codexRoleOptions(values, common, "candidate")
|
|
386
|
+
: undefined,
|
|
387
|
+
semanticCodex: routes.semanticCodex
|
|
388
|
+
? codexRoleOptions(values, common, "semantic")
|
|
389
|
+
: undefined,
|
|
390
|
+
advisoryCodex: routes.advisoryCodex
|
|
391
|
+
? codexRoleOptions(values, common, "advisory")
|
|
392
|
+
: undefined,
|
|
393
|
+
};
|
|
464
394
|
}
|
|
465
395
|
|
|
466
396
|
function invocationInputs(
|
|
@@ -472,55 +402,30 @@ function invocationInputs(
|
|
|
472
402
|
roots,
|
|
473
403
|
privateRoots,
|
|
474
404
|
toolchainBinDir,
|
|
475
|
-
|
|
405
|
+
codexOptions,
|
|
476
406
|
claudeOptions,
|
|
477
407
|
trials,
|
|
478
408
|
} = context;
|
|
479
409
|
return {
|
|
480
410
|
json: values.json ?? false,
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
).filter(
|
|
484
|
-
|
|
485
|
-
runtimeConfigFile: optionalAbsolute(
|
|
486
|
-
values["runtime-config-file"],
|
|
487
|
-
"--runtime-config-file",
|
|
411
|
+
runManifestFile: values["run-manifest-file"],
|
|
412
|
+
protectedRoots: context.protectedRoots,
|
|
413
|
+
deprecatedRuntimeOptions: optionsWith("section", "deprecated").filter(
|
|
414
|
+
(name) => values[name] !== undefined,
|
|
488
415
|
),
|
|
489
|
-
|
|
416
|
+
dry: values.dry ?? false,
|
|
417
|
+
runtimeConfigFile: values["runtime-config-file"],
|
|
418
|
+
caseFile: values["case-file"],
|
|
490
419
|
extension: extensionInvocation(values),
|
|
491
|
-
caseSourceRoot:
|
|
492
|
-
|
|
493
|
-
"--case-source-root",
|
|
494
|
-
),
|
|
495
|
-
caseSourceMapFile: optionalAbsolute(
|
|
496
|
-
values["case-source-map-file"],
|
|
497
|
-
"--case-source-map-file",
|
|
498
|
-
),
|
|
420
|
+
caseSourceRoot: values["case-source-root"],
|
|
421
|
+
caseSourceMapFile: values["case-source-map-file"],
|
|
499
422
|
adapterModule: routes.builtinHost
|
|
500
423
|
? undefined
|
|
501
|
-
:
|
|
502
|
-
semanticAdapterModule:
|
|
503
|
-
|
|
504
|
-
"--semantic-adapter-module",
|
|
505
|
-
),
|
|
506
|
-
semanticCodex: codexRoleOptions(
|
|
507
|
-
values,
|
|
508
|
-
codexCommon,
|
|
509
|
-
routes.semanticCodex,
|
|
510
|
-
"semantic",
|
|
511
|
-
),
|
|
512
|
-
advisoryAdapterModule: optionalAbsolute(
|
|
513
|
-
values["advisory-adapter-module"],
|
|
514
|
-
"--advisory-adapter-module",
|
|
515
|
-
),
|
|
516
|
-
advisoryCodex: codexRoleOptions(
|
|
517
|
-
values,
|
|
518
|
-
codexCommon,
|
|
519
|
-
routes.advisoryCodex,
|
|
520
|
-
"advisory",
|
|
521
|
-
),
|
|
424
|
+
: requiredOption(values["adapter-module"], "--adapter-module"),
|
|
425
|
+
semanticAdapterModule: values["semantic-adapter-module"],
|
|
426
|
+
advisoryAdapterModule: values["advisory-adapter-module"],
|
|
522
427
|
advisoryExcludedPaths: values["advisory-exclude"] ?? [],
|
|
523
|
-
|
|
428
|
+
...codexOptions,
|
|
524
429
|
claude: claudeOptions,
|
|
525
430
|
shellIsolation: shellIsolationOptions(
|
|
526
431
|
values,
|
|
@@ -532,10 +437,7 @@ function invocationInputs(
|
|
|
532
437
|
values["runner-build-digest"],
|
|
533
438
|
"--runner-build-digest",
|
|
534
439
|
),
|
|
535
|
-
runnerCheckoutRoot:
|
|
536
|
-
values["runner-checkout-root"],
|
|
537
|
-
"--runner-checkout-root",
|
|
538
|
-
),
|
|
440
|
+
runnerCheckoutRoot: values["runner-checkout-root"],
|
|
539
441
|
projectDigest: optionalDigest(values["project-digest"], "--project-digest"),
|
|
540
442
|
...trials,
|
|
541
443
|
};
|
|
@@ -558,14 +460,8 @@ function shellIsolationOptions(
|
|
|
558
460
|
function invocationContext(values: Values) {
|
|
559
461
|
const trials = trialParameters(values);
|
|
560
462
|
const protectedRoots = values["protected-root"] ?? [];
|
|
561
|
-
|
|
562
|
-
throw new InvocationError("--protected-root must be absolute");
|
|
563
|
-
const toolchainBinDir = optionalAbsolute(
|
|
564
|
-
values["toolchain-bin-dir"],
|
|
565
|
-
"--toolchain-bin-dir",
|
|
566
|
-
);
|
|
463
|
+
const toolchainBinDir = values["toolchain-bin-dir"];
|
|
567
464
|
const routes = hostRoutes(values);
|
|
568
|
-
validateHostCompatibility(values, routes, protectedRoots);
|
|
569
465
|
const roots = rootParameters(values);
|
|
570
466
|
validateExtensionSelection(values);
|
|
571
467
|
const privateRoots = privateRootDeclarations(
|
|
@@ -573,7 +469,12 @@ function invocationContext(values: Values) {
|
|
|
573
469
|
roots.configRoot,
|
|
574
470
|
protectedRoots,
|
|
575
471
|
);
|
|
576
|
-
const
|
|
472
|
+
const codexOptions = selectedCodexOptions(
|
|
473
|
+
values,
|
|
474
|
+
routes,
|
|
475
|
+
roots,
|
|
476
|
+
privateRoots,
|
|
477
|
+
);
|
|
577
478
|
const claudeOptions = claudeHostOptions(
|
|
578
479
|
values,
|
|
579
480
|
routes,
|
|
@@ -584,18 +485,113 @@ function invocationContext(values: Values) {
|
|
|
584
485
|
return {
|
|
585
486
|
routes,
|
|
586
487
|
roots,
|
|
488
|
+
protectedRoots,
|
|
587
489
|
privateRoots,
|
|
588
490
|
toolchainBinDir,
|
|
589
|
-
|
|
491
|
+
codexOptions,
|
|
590
492
|
claudeOptions,
|
|
591
493
|
trials,
|
|
592
494
|
};
|
|
593
495
|
}
|
|
594
496
|
|
|
595
497
|
/** Decode CLI flags in their documented validation order. */
|
|
596
|
-
export function parseInvocation(argv: string[]) {
|
|
498
|
+
export async function parseInvocation(argv: string[]) {
|
|
499
|
+
if (argv[0] !== "run")
|
|
500
|
+
throw new InvocationError(
|
|
501
|
+
"unknown command; available commands: demo, init, run, report, prune; run sevro --help",
|
|
502
|
+
);
|
|
597
503
|
const parsed = cliArguments(argv);
|
|
598
|
-
if (parsed.positionals.length !== 1
|
|
504
|
+
if (parsed.positionals.length !== 1)
|
|
599
505
|
throw new InvocationError("expected the run command");
|
|
506
|
+
parsed.values = await savedRunValues(parsed.values);
|
|
507
|
+
applyRunDefaults(parsed.values);
|
|
508
|
+
validateHostCompatibility(
|
|
509
|
+
parsed.values,
|
|
510
|
+
hostRoutes(parsed.values),
|
|
511
|
+
parsed.values["protected-root"] ?? [],
|
|
512
|
+
);
|
|
513
|
+
applyRootDefaults(parsed.values);
|
|
514
|
+
resolveNativeBinaries(parsed.values);
|
|
515
|
+
await canonicalizePaths(parsed.values);
|
|
600
516
|
return invocationInputs(parsed.values, invocationContext(parsed.values));
|
|
601
517
|
}
|
|
518
|
+
|
|
519
|
+
function resolveNativeBinaries(values: Values): void {
|
|
520
|
+
const routes = hostRoutes(values);
|
|
521
|
+
if (routes.anyCodex) values["codex-bin"] ??= nativeBinary("codex");
|
|
522
|
+
if (routes.claude) values["claude-bin"] ??= nativeBinary("claude");
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function nativeBinary(host: "codex" | "claude"): string {
|
|
526
|
+
const binary = Bun.which(host);
|
|
527
|
+
if (!binary)
|
|
528
|
+
throw new InvocationError(
|
|
529
|
+
`selected ${host} executable was not found on PATH; install ${host} or supply --${host}-bin <path>`,
|
|
530
|
+
);
|
|
531
|
+
return binary;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
export type Invocation = Awaited<ReturnType<typeof parseInvocation>>;
|
|
535
|
+
|
|
536
|
+
/** Keep all selected native roles visible to protection and evidence callers. */
|
|
537
|
+
export function nativeRoutes(
|
|
538
|
+
invocation: Pick<
|
|
539
|
+
Invocation,
|
|
540
|
+
"codex" | "claude" | "semanticCodex" | "advisoryCodex"
|
|
541
|
+
>,
|
|
542
|
+
) {
|
|
543
|
+
return [
|
|
544
|
+
invocation.codex,
|
|
545
|
+
invocation.claude,
|
|
546
|
+
invocation.semanticCodex,
|
|
547
|
+
invocation.advisoryCodex,
|
|
548
|
+
].filter((host) => host !== undefined);
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
function applyRunDefaults(values: Values): void {
|
|
552
|
+
values.condition ??= "passive";
|
|
553
|
+
values.trials ??= "1";
|
|
554
|
+
values.jobs ??= "3";
|
|
555
|
+
values.threshold ??= "1";
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
function applyRootDefaults(values: Values): void {
|
|
559
|
+
values["project-root"] ??= process.cwd();
|
|
560
|
+
values["results-root"] ??= join(
|
|
561
|
+
resolve(values["project-root"]),
|
|
562
|
+
".sevro",
|
|
563
|
+
"results",
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
async function canonicalOption(path: string, option: string): Promise<string> {
|
|
568
|
+
try {
|
|
569
|
+
return await canonicalRuntimeRoot(resolve(path));
|
|
570
|
+
} catch (cause) {
|
|
571
|
+
const error = cause as NodeJS.ErrnoException;
|
|
572
|
+
throw new InvocationError(
|
|
573
|
+
`--${option} cannot be resolved at ${path}: filesystem ${error.syscall ?? "realpath"} failed (${error.code ?? "unknown"}); supply a usable file or directory path`,
|
|
574
|
+
{ cause },
|
|
575
|
+
);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
async function canonicalizePaths(values: Values): Promise<void> {
|
|
580
|
+
for (const name of PATH_OPTIONS) {
|
|
581
|
+
const value = values[name];
|
|
582
|
+
if (value !== undefined)
|
|
583
|
+
values[name] = await canonicalOption(
|
|
584
|
+
requiredOption(value, `--${name}`),
|
|
585
|
+
name,
|
|
586
|
+
);
|
|
587
|
+
}
|
|
588
|
+
for (const name of PATH_LIST_OPTIONS) {
|
|
589
|
+
const paths = values[name];
|
|
590
|
+
if (paths)
|
|
591
|
+
values[name] = await Promise.all(
|
|
592
|
+
paths.map((path) =>
|
|
593
|
+
canonicalOption(requiredOption(path, `--${name}`), name),
|
|
594
|
+
),
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
}
|