@bjoernrochel/sevro 0.1.0-rc.2 → 0.1.0-rc.21
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 +170 -0
- package/LICENSE +63 -136
- package/README.md +83 -66
- package/docs/README.md +44 -0
- package/docs/acknowledgements.md +14 -0
- package/docs/architecture.md +146 -0
- package/docs/assets/README.md +27 -0
- package/docs/assets/sevro-logo.png +0 -0
- package/docs/assets/sevro-symbol.svg +1 -0
- package/docs/assets/sevro-wordmark.svg +1 -0
- package/docs/builtin-graders-v1.md +41 -13
- package/docs/codex-host.md +184 -52
- package/docs/contracts.md +19 -0
- package/docs/creating-cases.md +139 -0
- package/docs/development-cli.md +190 -30
- package/docs/documentation-quality.md +61 -0
- package/docs/evaluation-workflow.md +110 -0
- package/docs/evidence/code-mode-controls-71.md +64 -0
- package/docs/evidence/code-mode-programs-85.md +64 -0
- package/docs/evidence/codex-state-73/README.md +204 -0
- package/docs/evidence/codex-state-73/darrow-migration.patch +182 -0
- package/docs/evidence/codex-state-73/results.json +661 -0
- package/docs/evidence/local-http-74.md +104 -0
- package/docs/evidence/runtime-startup-30/README.md +185 -0
- package/docs/evidence/runtime-startup-30/after.json +319 -0
- package/docs/evidence/runtime-startup-30/baseline-timeout.jsonl +2 -0
- package/docs/evidence/runtime-startup-30/before.json +403 -0
- package/docs/evidence/runtime-startup-30/consumer-smoke.json +63 -0
- package/docs/evidence/runtime-startup-30/full-policy-diagnostic.jsonl +3 -0
- package/docs/evidence/runtime-startup-30/minimal-policy-diagnostic.jsonl +3 -0
- package/docs/evidence/runtime-startup-30/plugin-template-assessment.json +20 -0
- package/docs/evidence/runtime-startup-30/seedless-timeout.jsonl +2 -0
- package/docs/evidence/skill-reads-70/results.json +823 -0
- package/docs/evidence.md +21 -0
- package/docs/extension-protocol-v1.md +50 -16
- package/docs/fixture-cleanup-validation.md +3 -0
- package/docs/getting-started.md +102 -0
- package/docs/guide-evaluation.md +89 -0
- package/docs/guide-verification.json +239 -0
- package/docs/identity-v1.md +35 -1
- package/docs/installing.md +88 -0
- package/docs/licenses/BUSL-1.1-0.1.0-rc.2.txt +159 -0
- package/docs/licensing.md +42 -0
- package/docs/native-controls.md +76 -5
- package/docs/native-hosts.md +228 -0
- package/docs/reading-results.md +141 -0
- package/docs/recipes.md +489 -0
- package/docs/releases.md +81 -40
- package/docs/report-v1.md +29 -1
- package/docs/results-v1.md +180 -0
- package/docs/run-settings-v1.md +147 -0
- package/docs/running-evaluations.md +31 -0
- package/docs/runtime-v1.md +614 -0
- package/docs/specs/repository-guide.md +58 -0
- package/docs/troubleshooting.md +30 -0
- package/docs/typescript-quality.md +234 -0
- package/docs/usability-study.md +114 -0
- package/examples/basic/host.ts +2 -2
- 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 +39 -6
- package/schemas/report-v1.schema.json +9 -0
- package/schemas/run-evidence-v1.schema.json +2 -1
- package/schemas/runtime-v1.schema.json +193 -0
- package/src/advisory.ts +10 -5
- package/src/candidate-artifacts.ts +208 -0
- package/src/candidate-codex-state.ts +185 -0
- package/src/case-validation.ts +105 -0
- package/src/cli/cancellation.ts +20 -0
- package/src/cli/command.ts +81 -0
- package/src/cli/completion.ts +15 -0
- package/src/cli/demo.ts +59 -0
- package/src/cli/evaluation.ts +55 -0
- package/src/cli/extension.ts +79 -0
- package/src/cli/help.ts +222 -0
- package/src/cli/hosts.ts +59 -0
- package/src/cli/init-settings.ts +30 -0
- package/src/cli/init.ts +111 -0
- package/src/cli/invocation.ts +627 -0
- package/src/cli/loading.ts +151 -0
- package/src/cli/preparation.ts +163 -0
- package/src/cli/presentation.ts +91 -0
- package/src/cli/progress.ts +6 -0
- package/src/cli/run-manifest.ts +133 -0
- package/src/cli/run-options.ts +101 -0
- package/src/cli/run-overrides.ts +83 -0
- package/src/cli/settings.ts +160 -0
- package/src/cli/summary.ts +43 -0
- package/src/cli.ts +13 -843
- package/src/contract-types.ts +94 -0
- package/src/engine.ts +19 -2373
- package/src/evaluation/advisory.ts +150 -0
- package/src/evaluation/check-plan.ts +510 -0
- package/src/evaluation/collection.ts +88 -0
- package/src/evaluation/context.ts +10 -0
- package/src/evaluation/grading-host.ts +39 -0
- package/src/evaluation/grading.ts +258 -0
- package/src/evaluation/invocation-plan.ts +548 -0
- package/src/evaluation/plan.ts +736 -0
- package/src/evaluation/progress.ts +19 -0
- package/src/evaluation/resources.ts +241 -0
- package/src/evaluation/run.ts +206 -0
- package/src/{trial-scheduler.ts → evaluation/scheduler.ts} +3 -1
- package/src/evaluation/semantic.ts +312 -0
- package/src/evaluation/trial.ts +866 -0
- package/src/evaluation/types.ts +207 -0
- package/src/evidence/host-results.ts +92 -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 +228 -148
- package/src/extension-session.ts +326 -195
- package/src/fixtures/advisory.ts +338 -0
- package/src/fixtures/bin.ts +57 -0
- package/src/{fixture-cleanup.ts → fixtures/cleanup.ts} +13 -7
- package/src/fixtures/create.ts +187 -0
- package/src/fixtures/generated.ts +300 -0
- package/src/fixtures/git-hooks.ts +24 -0
- package/src/fixtures/preparation.ts +270 -0
- package/src/{repository-fixture.ts → fixtures/repository.ts} +207 -85
- package/src/fixtures/setup.ts +224 -0
- package/src/fixtures/tools.ts +88 -0
- package/src/fixtures/workspace-state.ts +212 -0
- package/src/generated/cli-result.cjs +2 -0
- package/src/generated/cli-result.d.cts +3 -0
- package/src/generated/extension.cjs +2 -0
- package/src/generated/extension.d.cts +3 -0
- package/src/generated/report.cjs +2 -0
- package/src/generated/report.d.cts +3 -0
- package/src/generated/run-evidence.cjs +2 -0
- package/src/generated/run-evidence.d.cts +3 -0
- package/src/generated/runtime.cjs +2 -0
- package/src/generated/runtime.d.cts +3 -0
- package/src/graders/artifact.ts +56 -23
- package/src/graders/git-head.ts +79 -75
- package/src/graders/output.ts +222 -140
- package/src/graders/semantic.ts +102 -43
- package/src/graders/shell.ts +379 -207
- package/src/host-diagnostic-redaction.ts +52 -0
- package/src/host-diagnostics.ts +319 -0
- package/src/hosts/claude-continuation.ts +63 -18
- package/src/hosts/claude-credential.ts +43 -62
- package/src/hosts/claude-events.ts +86 -51
- package/src/hosts/claude-keychain.ts +59 -0
- package/src/hosts/claude-native-goal.ts +57 -33
- package/src/hosts/claude-process.ts +111 -0
- package/src/hosts/claude-repository-invocation.ts +208 -117
- package/src/hosts/claude-settings.ts +240 -21
- package/src/hosts/claude-skill-activations.ts +166 -0
- package/src/hosts/claude-state.ts +403 -0
- package/src/hosts/claude-tool-calls.ts +171 -106
- package/src/hosts/claude.ts +561 -451
- package/src/hosts/codex-app-server.ts +326 -178
- package/src/hosts/codex-configuration.ts +44 -18
- package/src/hosts/codex-events.ts +97 -60
- package/src/hosts/codex-exec-controls.ts +516 -0
- package/src/hosts/codex-invocation.ts +70 -0
- package/src/hosts/codex-marketplace.ts +283 -0
- package/src/hosts/codex-native-calls.ts +546 -500
- package/src/hosts/codex-process.ts +202 -0
- package/src/hosts/codex-profile.ts +257 -28
- package/src/hosts/codex-session-files.ts +106 -0
- package/src/hosts/codex-state.ts +492 -0
- package/src/hosts/codex.ts +783 -832
- package/src/hosts/isolation-common.ts +94 -0
- package/src/hosts/isolation-roots.ts +54 -27
- package/src/hosts/isolation.ts +10 -0
- package/src/hosts/linux-sandbox.ts +159 -0
- package/src/hosts/mac-sandbox.ts +187 -61
- package/src/hosts/native-controls.ts +152 -62
- package/src/hosts/process-lifecycle.ts +37 -0
- package/src/hosts/protected-worktrees.ts +51 -19
- package/src/hosts/skill-hook-catalog.ts +131 -0
- package/src/hosts/skill-hook-handler.ts +374 -0
- package/src/hosts/skill-hooks.ts +580 -0
- package/src/hosts/workspace-fingerprint.ts +55 -35
- package/src/identity.ts +102 -48
- package/src/instrumentation.ts +109 -48
- package/src/native-transcript-state.ts +131 -0
- package/src/native-transcript-view.ts +90 -0
- package/src/native-transcripts.ts +286 -0
- package/src/process-lifecycle.ts +150 -0
- package/src/provenance.ts +161 -81
- package/src/prune.ts +215 -0
- package/src/report.ts +172 -140
- package/src/resolved-case.ts +33 -0
- package/src/results-lock.ts +29 -0
- package/src/results.ts +133 -86
- package/src/run-owner.ts +154 -63
- package/src/runtime/config.ts +456 -0
- package/src/runtime/discovery-apple.ts +90 -0
- package/src/runtime/discovery-providers.ts +63 -0
- package/src/runtime/discovery.ts +70 -0
- package/src/runtime/hook-processes.ts +97 -0
- package/src/runtime/hooks.ts +476 -0
- package/src/runtime/paths.ts +313 -0
- package/src/runtime/query.ts +85 -0
- package/src/runtime/seeds.ts +134 -0
- package/src/runtime/shared-cache.ts +143 -0
- package/src/runtime/state.ts +143 -0
- package/src/schema-types.ts +198 -0
- package/src/schema.ts +15 -19
- package/src/transcript-retention.ts +146 -0
- package/src/value-guards.ts +20 -0
- package/src/advisory-fixture.ts +0 -282
- package/src/fixture-bin.ts +0 -87
- package/src/fixture-setup.ts +0 -163
- package/src/generated-fixture.ts +0 -220
- package/src/git-hooks.ts +0 -63
- package/src/hosts/claude-nested-skills.ts +0 -218
- package/src/hosts/codex-command-output.ts +0 -399
- package/src/hosts/codex-executor-command.ts +0 -195
- package/src/hosts/codex-skill-reads.ts +0 -391
- package/src/preparation.ts +0 -211
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { runEvaluation } from "../engine";
|
|
2
|
+
import {
|
|
3
|
+
packageBuildDigest,
|
|
4
|
+
projectIdentityDigest,
|
|
5
|
+
projectProvenance,
|
|
6
|
+
} from "../provenance";
|
|
7
|
+
import { selectedCase } from "./extension";
|
|
8
|
+
import type { PreparedInvocation } from "./preparation";
|
|
9
|
+
import { assessmentSettings, effectiveSettings } from "./settings";
|
|
10
|
+
import { displayProgress } from "./progress";
|
|
11
|
+
|
|
12
|
+
export async function evaluateInvocation(
|
|
13
|
+
prepared: PreparedInvocation,
|
|
14
|
+
signal: AbortSignal,
|
|
15
|
+
) {
|
|
16
|
+
const { invocation, preparationSources, host, semanticHost, advisoryHost } =
|
|
17
|
+
prepared;
|
|
18
|
+
const { caseData, extension } = await selectedCase(prepared, signal);
|
|
19
|
+
return runEvaluation({
|
|
20
|
+
onProgress: displayProgress,
|
|
21
|
+
resolvedRunSettings: effectiveSettings(prepared),
|
|
22
|
+
assessmentSettings: assessmentSettings(prepared),
|
|
23
|
+
runtimePolicy: prepared.runtimePolicy,
|
|
24
|
+
projectRoot: invocation.projectRoot,
|
|
25
|
+
resultsRoot: invocation.resultsRoot,
|
|
26
|
+
runStateRoot: invocation.runStateRoot,
|
|
27
|
+
case: caseData,
|
|
28
|
+
extension,
|
|
29
|
+
preparationSources,
|
|
30
|
+
host,
|
|
31
|
+
semanticHost,
|
|
32
|
+
advisoryHost,
|
|
33
|
+
advisoryExcludedPaths: invocation.advisoryExcludedPaths,
|
|
34
|
+
shellIsolation: invocation.shellIsolation,
|
|
35
|
+
runnerBuildDigest:
|
|
36
|
+
invocation.runnerBuildDigest ?? (await packageBuildDigest()),
|
|
37
|
+
runnerCheckoutRoot: invocation.runnerCheckoutRoot,
|
|
38
|
+
projectDigest:
|
|
39
|
+
invocation.projectDigest ??
|
|
40
|
+
(await projectIdentityDigest(
|
|
41
|
+
invocation.projectRoot,
|
|
42
|
+
await projectProvenance(invocation.projectRoot, [
|
|
43
|
+
invocation.resultsRoot,
|
|
44
|
+
invocation.runStateRoot,
|
|
45
|
+
]),
|
|
46
|
+
[invocation.resultsRoot, invocation.runStateRoot],
|
|
47
|
+
)),
|
|
48
|
+
condition: invocation.condition,
|
|
49
|
+
trialCount: invocation.trialCount,
|
|
50
|
+
jobs: invocation.jobs,
|
|
51
|
+
passThreshold: invocation.passThreshold,
|
|
52
|
+
dry: invocation.dry,
|
|
53
|
+
signal,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
import type { ResolvedCase } from "../engine";
|
|
3
|
+
import { openExtensionSession, type ExtensionCase } from "../extension-session";
|
|
4
|
+
import { resolvedFixture } from "../resolved-case";
|
|
5
|
+
import { InvocationError, type Invocation } from "./invocation";
|
|
6
|
+
import { parseCase, loadExtensionOptions } from "./loading";
|
|
7
|
+
import type { PreparedInvocation } from "./preparation";
|
|
8
|
+
|
|
9
|
+
function selectExtensionCase(
|
|
10
|
+
cases: ExtensionCase[],
|
|
11
|
+
caseId: string,
|
|
12
|
+
): { caseData: ResolvedCase; resolvedCase: ExtensionCase } {
|
|
13
|
+
const resolvedCase = cases.find((item) => item.id === caseId);
|
|
14
|
+
if (!resolvedCase)
|
|
15
|
+
throw new InvocationError("extension did not resolve the selected case");
|
|
16
|
+
const caseData = parseCase({
|
|
17
|
+
...resolvedCase,
|
|
18
|
+
fixture: resolvedFixture(resolvedCase.fixture),
|
|
19
|
+
});
|
|
20
|
+
return { caseData, resolvedCase };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function resolveSelectedExtension(
|
|
24
|
+
prepared: PreparedInvocation,
|
|
25
|
+
selected: NonNullable<Invocation["extension"]>,
|
|
26
|
+
signal: AbortSignal,
|
|
27
|
+
) {
|
|
28
|
+
const { invocation, host } = prepared;
|
|
29
|
+
const options = await loadExtensionOptions(selected);
|
|
30
|
+
const hostCapabilities = [
|
|
31
|
+
...(host.instrumentation ?? []).map((item) => item.id),
|
|
32
|
+
...(host.hostCapabilities ?? []),
|
|
33
|
+
];
|
|
34
|
+
const session = await openExtensionSession({
|
|
35
|
+
...options,
|
|
36
|
+
sourceFiles: selected.sourceFiles,
|
|
37
|
+
engineCapabilities: [
|
|
38
|
+
"sevro.host.exec",
|
|
39
|
+
"sevro.fixture.setup",
|
|
40
|
+
"sevro.case.host-route",
|
|
41
|
+
],
|
|
42
|
+
hostCapabilities,
|
|
43
|
+
taskVerdictPolicy: selected.taskVerdictPolicy,
|
|
44
|
+
replaceBuiltinGraders: selected.replaceBuiltinGraders,
|
|
45
|
+
signal,
|
|
46
|
+
});
|
|
47
|
+
const chosen = selectExtensionCase(
|
|
48
|
+
await session.resolve(
|
|
49
|
+
pathToFileURL(invocation.projectRoot).href,
|
|
50
|
+
{ caseIds: [selected.caseId] },
|
|
51
|
+
{
|
|
52
|
+
id: host.id,
|
|
53
|
+
model: host.model,
|
|
54
|
+
effort: host.effort,
|
|
55
|
+
capabilities: hostCapabilities,
|
|
56
|
+
},
|
|
57
|
+
),
|
|
58
|
+
selected.caseId,
|
|
59
|
+
);
|
|
60
|
+
return {
|
|
61
|
+
caseData: chosen.caseData,
|
|
62
|
+
extension: { session, resolvedCase: chosen.resolvedCase },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function selectedCase(
|
|
67
|
+
prepared: PreparedInvocation,
|
|
68
|
+
signal: AbortSignal,
|
|
69
|
+
) {
|
|
70
|
+
if (prepared.invocation.extension)
|
|
71
|
+
return resolveSelectedExtension(
|
|
72
|
+
prepared,
|
|
73
|
+
prepared.invocation.extension,
|
|
74
|
+
signal,
|
|
75
|
+
);
|
|
76
|
+
if (!prepared.caseData)
|
|
77
|
+
throw new InvocationError("invalid resolved case file");
|
|
78
|
+
return { caseData: prepared.caseData, extension: undefined };
|
|
79
|
+
}
|
package/src/cli/help.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { version } from "../../package.json";
|
|
2
|
+
|
|
3
|
+
const TOP_LEVEL_HELP = `Usage: sevro <command> [options]
|
|
4
|
+
|
|
5
|
+
Examples:
|
|
6
|
+
sevro demo
|
|
7
|
+
sevro init --template response --directory ./my-evaluation
|
|
8
|
+
sevro run --case-file /absolute/case.json --adapter-module /absolute/adapter.ts \\
|
|
9
|
+
--project-root /absolute/project --results-root /absolute/results \\
|
|
10
|
+
--condition passive --trials 1 --threshold 1
|
|
11
|
+
sevro run --help
|
|
12
|
+
sevro report --result-file /absolute/results/run/result.json
|
|
13
|
+
sevro prune
|
|
14
|
+
|
|
15
|
+
Commands:
|
|
16
|
+
demo Run the packaged credential-free assessed example; use demo --help.
|
|
17
|
+
init Create a new evaluation project; use init --help.
|
|
18
|
+
run Evaluate one resolved case or extension case; use run --help.
|
|
19
|
+
report Summarize retained results; use report --help.
|
|
20
|
+
prune Remove retained results using a retention policy; use prune --help.
|
|
21
|
+
|
|
22
|
+
Options:
|
|
23
|
+
-h, --help Show help without preparing a run.
|
|
24
|
+
-v, --version Print the installed Sevro package version.
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
const RUN_HELP = `Usage: sevro run [options]
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
sevro run --case-file /absolute/case.json --adapter-module /absolute/adapter.ts \\
|
|
31
|
+
--project-root /absolute/project --results-root /absolute/results \\
|
|
32
|
+
--condition passive --trials 1 --threshold 1
|
|
33
|
+
Add --dry to prepare without calling the candidate or graders.
|
|
34
|
+
Add --json to save a sevro.cli-result.v1 result from stdout.
|
|
35
|
+
|
|
36
|
+
Required:
|
|
37
|
+
--case-file <path> OR --extension-command-file <path> Select one case source.
|
|
38
|
+
--adapter-module <path> OR --host <codex|claude> Select one candidate route.
|
|
39
|
+
|
|
40
|
+
Common options and defaults:
|
|
41
|
+
--run-manifest-file <path> Saved sevro.run.v1 settings; explicit flags override them.
|
|
42
|
+
Precedence: built-in defaults, saved settings, then explicit CLI options.
|
|
43
|
+
Manifest paths use its own directory; CLI paths use the current directory.
|
|
44
|
+
--no-dry, --no-shell-isolation and other --no-<boolean> flags override saved true.
|
|
45
|
+
--project-root <path> (default: current directory) Project identity; does not copy its files into the fixture.
|
|
46
|
+
--results-root <path> (default: <project-root>/.sevro/results) Retained evidence.
|
|
47
|
+
--condition <passive|enforced> (default: passive) Bundled hosts use passive.
|
|
48
|
+
--trials <integer> (default: 1) Positive number of trials.
|
|
49
|
+
--threshold <number> (default: 1) All assessed trials must pass; range (0, 1].
|
|
50
|
+
Relative run paths resolve from the current directory and are canonicalized before protection checks.
|
|
51
|
+
--jobs <integer> (default: 3) Maximum parallel trials, positive integer.
|
|
52
|
+
--config-root <path> (default: --project-root) Native concurrency configuration.
|
|
53
|
+
--run-state-root <path> (default: --results-root) Active records/checkpoints.
|
|
54
|
+
--runtime-config-file <path> Runtime policy; otherwise discover project sevro.json.
|
|
55
|
+
--dry Prepare only (default: false).
|
|
56
|
+
--json One versioned JSON result on stdout (default: false).
|
|
57
|
+
Human diagnostics go to stderr in both modes.
|
|
58
|
+
--retain-host-diagnostics Retain private native diagnostics (default: false).
|
|
59
|
+
--shell-isolation Isolate shell checks (default: false).
|
|
60
|
+
--protected-root <path> Extra protected source/private root; repeatable.
|
|
61
|
+
|
|
62
|
+
Bundled hosts:
|
|
63
|
+
--model <name> --effort <level> Required for a bundled candidate host.
|
|
64
|
+
--codex-bin <path> (default: codex on PATH) Explicit binary override.
|
|
65
|
+
--codex-auth-file <path> Required for every Codex route.
|
|
66
|
+
--codex-entrypoint <exec|app-server> Candidate transport (default: exec).
|
|
67
|
+
--codex-timeout-ms <integer> 1..1800000 milliseconds (default: 600000).
|
|
68
|
+
--claude-bin <path> (default: claude on PATH) Explicit binary override.
|
|
69
|
+
Native timeout defaults to 600000 ms; shell checks expect exit 0 within 30000 ms.
|
|
70
|
+
--claude-credential-file <path> Optional credential override; otherwise use native auth.
|
|
71
|
+
--claude-project-settings Allow fixture project settings (default: false).
|
|
72
|
+
|
|
73
|
+
Extension cases:
|
|
74
|
+
--case-id <id> Required with --extension-command-file.
|
|
75
|
+
--extension-source-file <path> Required source closure; repeatable.
|
|
76
|
+
--extension-configuration-file <path> Private JSON object; supply with
|
|
77
|
+
--extension-redacted-configuration-file <path> Redacted retained configuration.
|
|
78
|
+
--task-verdict-policy <id> Select an advertised namespaced extension policy.
|
|
79
|
+
--replace-builtin-grader <id> Explicit replacement; repeatable.
|
|
80
|
+
--case-source-root <path> --case-source-map-file <path> Supply both for mapped sources.
|
|
81
|
+
|
|
82
|
+
Optional grading routes (none selected by default):
|
|
83
|
+
--semantic-adapter-module <path> OR --semantic-host codex
|
|
84
|
+
--semantic-model <name> --semantic-effort <level> Required for native semantic route.
|
|
85
|
+
--advisory-adapter-module <path> OR --advisory-host codex
|
|
86
|
+
--advisory-model <name> --advisory-effort <level> Required for native advisory route.
|
|
87
|
+
--advisory-exclude <relative-path> Exclude an evaluator path; repeatable.
|
|
88
|
+
|
|
89
|
+
Provenance overrides (normally derived automatically):
|
|
90
|
+
--runner-build-digest <sha256> --project-digest <sha256> 64 lowercase hex characters.
|
|
91
|
+
--runner-checkout-root <path> Record the running checkout's revision/dirty digest.
|
|
92
|
+
|
|
93
|
+
Deprecated runtime options:
|
|
94
|
+
--toolchain-bin-dir <path> --claude-uv-cache-dir <path>
|
|
95
|
+
Migrate to sevro.json; these cannot be combined with a runtime policy.
|
|
96
|
+
|
|
97
|
+
-h, --help Show this help without preparing a run.
|
|
98
|
+
Reference: docs/development-cli.md, docs/run-settings-v1.md and docs/results-v1.md in the installed package.
|
|
99
|
+
`;
|
|
100
|
+
|
|
101
|
+
const DEMO_HELP = `Usage: sevro demo [--json]
|
|
102
|
+
|
|
103
|
+
Examples:
|
|
104
|
+
sevro demo
|
|
105
|
+
sevro demo --json
|
|
106
|
+
|
|
107
|
+
Run the packaged deterministic fixture and adapter without model credentials.
|
|
108
|
+
Shows an assessed verdict and retains evidence in .sevro/results beneath the current directory.
|
|
109
|
+
Caller project files, sevro.json and native configuration are not loaded.
|
|
110
|
+
|
|
111
|
+
Options:
|
|
112
|
+
--json Emit one sevro.cli-result.v1 document on stdout.
|
|
113
|
+
-h, --help Show this help without preparing a run.
|
|
114
|
+
`;
|
|
115
|
+
|
|
116
|
+
const REPORT_HELP = `Usage: sevro report [options]
|
|
117
|
+
|
|
118
|
+
Examples:
|
|
119
|
+
sevro report --latest
|
|
120
|
+
sevro report --result-file /absolute/results/run/result.json
|
|
121
|
+
sevro report --result-file /absolute/results/first/result.json \\
|
|
122
|
+
--result-file /absolute/results/second/result.json --json
|
|
123
|
+
|
|
124
|
+
Required:
|
|
125
|
+
--latest OR --result-file <path> A retained result; repeat paths for distinct runs.
|
|
126
|
+
Relative or absolute paths use the current directory.
|
|
127
|
+
Keep each result's referenced evidence available and unchanged.
|
|
128
|
+
|
|
129
|
+
Options and defaults:
|
|
130
|
+
--latest Read the last retained CLI result, including dry or failed runs.
|
|
131
|
+
--results-root <path> With --latest, override <cwd>/.sevro/results.
|
|
132
|
+
--json Emit sevro.report.v1 JSON; Markdown by default.
|
|
133
|
+
-h, --help Show this help without reading result files.
|
|
134
|
+
`;
|
|
135
|
+
|
|
136
|
+
const PRUNE_HELP = `Usage: sevro prune [options]
|
|
137
|
+
|
|
138
|
+
Examples:
|
|
139
|
+
sevro prune
|
|
140
|
+
sevro prune --results-root ./other-results --keep 5
|
|
141
|
+
sevro prune --older-than 30d
|
|
142
|
+
sevro prune --latest
|
|
143
|
+
sevro prune --native-transcripts --older-than 30d
|
|
144
|
+
|
|
145
|
+
Defaults: keep the newest 10 completed results under <cwd>/.sevro/results.
|
|
146
|
+
Select at most one explicit retention policy:
|
|
147
|
+
--keep <positive-integer> Keep this many newest results.
|
|
148
|
+
--latest Keep only the newest result (same as --keep 1).
|
|
149
|
+
--older-than <duration> Remove results older than a positive integer plus ms, s, m, h, d or w.
|
|
150
|
+
--results-root <path> Relative or absolute results root, resolved from cwd.
|
|
151
|
+
--native-transcripts Remove only native transcript bundles; keep results and hashes.
|
|
152
|
+
-h, --help Show help without reading or deleting results.
|
|
153
|
+
|
|
154
|
+
Age and ordering use result.json modification times; equal times sort by path.
|
|
155
|
+
Each retained attempt counts separately, including dry, failed and interrupted runs.
|
|
156
|
+
Active/unrecognized attempts and directories without result.json are preserved.
|
|
157
|
+
Evidence is permanently deleted. Remaining results stay usable by sevro report;
|
|
158
|
+
latest.json is updated, or removed when no completed results remain.
|
|
159
|
+
With --native-transcripts, no policy removes bundles from all completed results;
|
|
160
|
+
--keep/--latest preserve bundles for the newest results, and --older-than selects older results.
|
|
161
|
+
Result/evidence files and latest.json stay unchanged. Reports label removed bundles as pruned.
|
|
162
|
+
Missing or empty results roots are a successful no-op. Invalid or unreadable inputs exit 64.
|
|
163
|
+
Reference: docs/reading-results.md in the installed package.
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
const INIT_HELP = `Usage: sevro init [options]
|
|
167
|
+
|
|
168
|
+
Examples:
|
|
169
|
+
sevro init --template response --directory ./my-evaluation
|
|
170
|
+
cd my-evaluation
|
|
171
|
+
sevro run --run-manifest-file run.json --dry
|
|
172
|
+
sevro run --run-manifest-file run.json
|
|
173
|
+
sevro report --latest
|
|
174
|
+
|
|
175
|
+
Options and defaults:
|
|
176
|
+
--template <response|repository-skill|coding> Default: response.
|
|
177
|
+
--directory <new-path> Default: ./sevro-evaluation; refuses existing paths.
|
|
178
|
+
-h, --help Show this help without creating files.
|
|
179
|
+
|
|
180
|
+
Response and coding use deterministic adapters and real assertions, including negative controls.
|
|
181
|
+
Coding checks need sandbox-exec (macOS) or bubblewrap/socat (Linux).
|
|
182
|
+
Repository-skill uses native Codex and requires explicit --model, --effort and --codex-auth-file.
|
|
183
|
+
Read the generated README.md for prerequisites and live commands; dry preparation is not an assessment.
|
|
184
|
+
Reference: docs/evaluation-workflow.md in the installed package.
|
|
185
|
+
`;
|
|
186
|
+
|
|
187
|
+
const HELP_REQUESTS: Record<string, string> = {
|
|
188
|
+
"": TOP_LEVEL_HELP,
|
|
189
|
+
"--help": TOP_LEVEL_HELP,
|
|
190
|
+
"-h": TOP_LEVEL_HELP,
|
|
191
|
+
help: TOP_LEVEL_HELP,
|
|
192
|
+
"run --help": RUN_HELP,
|
|
193
|
+
"run -h": RUN_HELP,
|
|
194
|
+
"help run": RUN_HELP,
|
|
195
|
+
"demo --help": DEMO_HELP,
|
|
196
|
+
"demo -h": DEMO_HELP,
|
|
197
|
+
"help demo": DEMO_HELP,
|
|
198
|
+
"init --help": INIT_HELP,
|
|
199
|
+
"init -h": INIT_HELP,
|
|
200
|
+
"help init": INIT_HELP,
|
|
201
|
+
"report --help": REPORT_HELP,
|
|
202
|
+
"report -h": REPORT_HELP,
|
|
203
|
+
"help report": REPORT_HELP,
|
|
204
|
+
"prune --help": PRUNE_HELP,
|
|
205
|
+
"prune -h": PRUNE_HELP,
|
|
206
|
+
"help prune": PRUNE_HELP,
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
/** Handle informational commands before loading inputs or creating run state. */
|
|
210
|
+
export function informationCommand(argv: string[]): boolean {
|
|
211
|
+
const request = argv.join(" ");
|
|
212
|
+
if (["--version", "-v"].includes(request)) {
|
|
213
|
+
process.stdout.write(`sevro ${version}\n`);
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
const help = Object.hasOwn(HELP_REQUESTS, request)
|
|
217
|
+
? HELP_REQUESTS[request]
|
|
218
|
+
: undefined;
|
|
219
|
+
if (help === undefined) return false;
|
|
220
|
+
process.stdout.write(help);
|
|
221
|
+
return true;
|
|
222
|
+
}
|
package/src/cli/hosts.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { HostAdapter } from "../engine";
|
|
2
|
+
import { createClaudeHost } from "../hosts/claude";
|
|
3
|
+
import { createCodexHost } from "../hosts/codex";
|
|
4
|
+
import { codexAgentConcurrency } from "../hosts/codex-configuration";
|
|
5
|
+
import { InvocationError, type Invocation } from "./invocation";
|
|
6
|
+
import { loadHost } from "./loading";
|
|
7
|
+
|
|
8
|
+
export async function selectedConcurrency(
|
|
9
|
+
invocation: Invocation,
|
|
10
|
+
configRoot: string,
|
|
11
|
+
): Promise<number | null> {
|
|
12
|
+
return [
|
|
13
|
+
invocation.codex,
|
|
14
|
+
invocation.semanticCodex,
|
|
15
|
+
invocation.advisoryCodex,
|
|
16
|
+
].some(Boolean)
|
|
17
|
+
? codexAgentConcurrency(configRoot)
|
|
18
|
+
: null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export async function candidateHost(
|
|
22
|
+
invocation: Invocation,
|
|
23
|
+
agentConcurrencyLimit: number | null,
|
|
24
|
+
): Promise<HostAdapter> {
|
|
25
|
+
if (invocation.codex)
|
|
26
|
+
return retainExecutable(
|
|
27
|
+
createCodexHost({ ...invocation.codex, agentConcurrencyLimit }),
|
|
28
|
+
invocation.codex.binary,
|
|
29
|
+
);
|
|
30
|
+
if (invocation.claude)
|
|
31
|
+
return retainExecutable(
|
|
32
|
+
createClaudeHost(invocation.claude),
|
|
33
|
+
invocation.claude.binary,
|
|
34
|
+
);
|
|
35
|
+
if (!invocation.adapterModule)
|
|
36
|
+
throw new InvocationError("missing --adapter-module or --host");
|
|
37
|
+
return loadHost(invocation.adapterModule);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function secondaryHost(
|
|
41
|
+
module: string | undefined,
|
|
42
|
+
codex: Invocation["semanticCodex"],
|
|
43
|
+
agentConcurrencyLimit: number | null,
|
|
44
|
+
): Promise<HostAdapter | undefined> {
|
|
45
|
+
if (module) return loadHost(module);
|
|
46
|
+
if (codex)
|
|
47
|
+
return retainExecutable(
|
|
48
|
+
createCodexHost({ ...codex, agentConcurrencyLimit }),
|
|
49
|
+
codex.binary,
|
|
50
|
+
);
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function retainExecutable(host: HostAdapter, binary: string): HostAdapter {
|
|
55
|
+
return {
|
|
56
|
+
...host,
|
|
57
|
+
configuration: { ...host.configuration, "sevro.host.executable": binary },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
|
|
3
|
+
export function templateSettings(template: string) {
|
|
4
|
+
if (template === "repository-skill")
|
|
5
|
+
return {
|
|
6
|
+
"project-root": ".",
|
|
7
|
+
"extension-command-file": "command.json",
|
|
8
|
+
"extension-source-file": [
|
|
9
|
+
"extension.ts",
|
|
10
|
+
"extension-data.ts",
|
|
11
|
+
".agents/skills/startup-guide/SKILL.md",
|
|
12
|
+
],
|
|
13
|
+
"case-id": "repository-skill",
|
|
14
|
+
host: "codex",
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
"case-file": "case.json",
|
|
18
|
+
"adapter-module": "adapter.ts",
|
|
19
|
+
"project-root": ".",
|
|
20
|
+
...(template === "coding" ? { "shell-isolation": true } : {}),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function templateCommand(destination: string) {
|
|
25
|
+
return [process.execPath, join(destination, "extension.ts")];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function nativeReadme() {
|
|
29
|
+
return `# Repository skill evaluation\n\nThis template mounts the actual startup-guide skill and requires Codex's explicit invocation evidence plus assertions for the start command and port. Missing evidence remains not_assessed.\n\nPrerequisites: Bun, Git, Codex on PATH, supported native isolation (sandbox-exec on macOS or bubblewrap/socat on Linux), and a readable Codex authentication file. Choose the exact model and effort explicitly. Do not store credentials in run.json.\n\n\`\`\`sh\nsevro run --run-manifest-file run.json --model YOUR_MODEL --effort YOUR_EFFORT --codex-auth-file /absolute/auth.json --dry\nsevro run --run-manifest-file run.json --model YOUR_MODEL --effort YOUR_EFFORT --codex-auth-file /absolute/auth.json\nsevro report --latest\n\`\`\`\n\nDry preparation checks mounts and declarations without calling the model. No authenticated model execution or skill dispatch is established by dry preparation. Live execution may incur provider charges. To create a negative control, change the expected port in extension-data.ts to 9000 while leaving the fixture at 3000; rerun and inspect the failed port assertion. Model compliance and measurements are unknown until actually executed.\n\nEdit the copied skill and assertions, prepare again, then rerun the same model/effort/condition. Keep private .sevro evidence out of Git. command.json uses the initializer's absolute Bun and extension paths; regenerate it after moving this project.\n`;
|
|
30
|
+
}
|
package/src/cli/init.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { cp, mkdir, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { parseArgs } from "node:util";
|
|
4
|
+
import {
|
|
5
|
+
nativeReadme,
|
|
6
|
+
templateCommand,
|
|
7
|
+
templateSettings,
|
|
8
|
+
} from "./init-settings";
|
|
9
|
+
|
|
10
|
+
function initOptions(argv: string[]) {
|
|
11
|
+
const { values, positionals } = parseArgs({
|
|
12
|
+
args: argv,
|
|
13
|
+
strict: true,
|
|
14
|
+
allowPositionals: true,
|
|
15
|
+
options: {
|
|
16
|
+
template: { type: "string", default: "response" },
|
|
17
|
+
directory: { type: "string", default: "sevro-evaluation" },
|
|
18
|
+
},
|
|
19
|
+
});
|
|
20
|
+
if (
|
|
21
|
+
positionals.length ||
|
|
22
|
+
!["response", "coding", "repository-skill"].includes(values.template)
|
|
23
|
+
)
|
|
24
|
+
throw new Error(
|
|
25
|
+
"use --template response, coding or repository-skill; run sevro init --help",
|
|
26
|
+
);
|
|
27
|
+
if (!values.directory.trim())
|
|
28
|
+
throw new Error("--directory must name a new directory");
|
|
29
|
+
return { template: values.template, destination: resolve(values.directory) };
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function reserveDirectory(destination: string): Promise<void> {
|
|
33
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
34
|
+
try {
|
|
35
|
+
await mkdir(destination);
|
|
36
|
+
} catch (cause) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`init destination already exists or cannot be created: ${destination}; choose a new --directory`,
|
|
39
|
+
{ cause },
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function starterReadme(template: string) {
|
|
45
|
+
if (template === "repository-skill") return nativeReadme();
|
|
46
|
+
const assertion =
|
|
47
|
+
template === "coding"
|
|
48
|
+
? "positive, negative and zero addition assertions against edited add.sh"
|
|
49
|
+
: "an exact response assertion";
|
|
50
|
+
const prerequisites =
|
|
51
|
+
template === "coding"
|
|
52
|
+
? "Bun and sandbox-exec on macOS, or bubblewrap/socat on Linux"
|
|
53
|
+
: "Bun";
|
|
54
|
+
return `# ${template} evaluation\n\nThis deterministic adapter exercises ${assertion}, without model credentials. Prerequisites: ${prerequisites}.\n\n\`\`\`sh\nsevro run --run-manifest-file run.json --dry\nsevro run --run-manifest-file run.json\nsevro report --latest\nSEVRO_TEMPLATE_FAIL=1 sevro run --run-manifest-file run.json\n\`\`\`\n\nThe negative control must report task=failed and exit 1. Dry preparation is not an assessment.\nEdit case.json and adapter.ts, prepare, then run again. Keep private .sevro evidence out of Git.\nFor a native model, replace the adapter route explicitly with --host, --model and --effort; Codex also requires --codex-auth-file. No model execution or native skill dispatch is established by this adapter.\n`;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function initialize(template: string, destination: string) {
|
|
58
|
+
await reserveDirectory(destination);
|
|
59
|
+
try {
|
|
60
|
+
await cp(
|
|
61
|
+
join(import.meta.dir, "..", "..", "examples", "templates", template),
|
|
62
|
+
destination,
|
|
63
|
+
{ recursive: true, errorOnExist: true, force: false },
|
|
64
|
+
);
|
|
65
|
+
await writeFile(
|
|
66
|
+
join(destination, "run.json"),
|
|
67
|
+
JSON.stringify(
|
|
68
|
+
{ format: "sevro.run.v1", settings: templateSettings(template) },
|
|
69
|
+
null,
|
|
70
|
+
2,
|
|
71
|
+
) + "\n",
|
|
72
|
+
{ flag: "wx" },
|
|
73
|
+
);
|
|
74
|
+
if (template === "repository-skill")
|
|
75
|
+
await writeFile(
|
|
76
|
+
join(destination, "command.json"),
|
|
77
|
+
JSON.stringify(templateCommand(destination)) + "\n",
|
|
78
|
+
{ flag: "wx" },
|
|
79
|
+
);
|
|
80
|
+
await writeFile(join(destination, ".gitignore"), ".sevro/\n", {
|
|
81
|
+
flag: "wx",
|
|
82
|
+
});
|
|
83
|
+
await writeFile(join(destination, "README.md"), starterReadme(template), {
|
|
84
|
+
flag: "wx",
|
|
85
|
+
});
|
|
86
|
+
} catch (cause) {
|
|
87
|
+
await rm(destination, { recursive: true, force: true });
|
|
88
|
+
throw cause;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export async function initCommand(argv: string[]): Promise<number> {
|
|
93
|
+
try {
|
|
94
|
+
const { template, destination } = initOptions(argv);
|
|
95
|
+
await initialize(template, destination);
|
|
96
|
+
const quoted = `'${destination.replaceAll("'", "'\\''")}'`;
|
|
97
|
+
const native =
|
|
98
|
+
template === "repository-skill"
|
|
99
|
+
? " --model YOUR_MODEL --effort YOUR_EFFORT --codex-auth-file /absolute/auth.json"
|
|
100
|
+
: "";
|
|
101
|
+
process.stdout.write(
|
|
102
|
+
`Created ${template} evaluation at ${destination}\nOpen README.md, then:\n cd ${quoted}\n sevro run --run-manifest-file run.json${native} --dry\n sevro run --run-manifest-file run.json${native}\n`,
|
|
103
|
+
);
|
|
104
|
+
return 0;
|
|
105
|
+
} catch (error) {
|
|
106
|
+
process.stderr.write(
|
|
107
|
+
`sevro: ${error instanceof Error ? error.message : "initialization failed"}\n`,
|
|
108
|
+
);
|
|
109
|
+
return 64;
|
|
110
|
+
}
|
|
111
|
+
}
|