@bjoernrochel/sevro 0.1.0-rc.7 → 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 +17 -3
- package/docs/codex-host.md +155 -49
- 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 +141 -4
- package/docs/run-settings-v1.md +147 -0
- package/docs/runtime-v1.md +307 -18
- 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 +63 -7
- package/src/advisory.ts +2 -2
- package/src/candidate-artifacts.ts +206 -0
- 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 +13 -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} +133 -115
- package/src/evaluation/trial.ts +800 -0
- package/src/evaluation/types.ts +207 -0
- 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} +15 -76
- 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/fixtures/workspace-state.ts +212 -0
- 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 +57 -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 +91 -14
- package/src/hosts/claude-skill-activations.ts +169 -0
- package/src/hosts/claude-state.ts +46 -16
- package/src/hosts/claude-tool-calls.ts +13 -10
- package/src/hosts/claude.ts +122 -73
- 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 -54
- package/src/hosts/codex-profile.ts +50 -21
- package/src/hosts/codex-session-files.ts +1 -9
- package/src/hosts/codex-state.ts +141 -19
- package/src/hosts/codex.ts +221 -179
- package/src/hosts/isolation-common.ts +15 -11
- package/src/hosts/isolation-roots.ts +13 -20
- package/src/hosts/linux-sandbox.ts +27 -3
- package/src/hosts/mac-sandbox.ts +111 -18
- package/src/hosts/native-controls.ts +72 -22
- package/src/hosts/native-request.ts +55 -0
- package/src/hosts/process-lifecycle.ts +221 -45
- 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 +34 -15
- 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/run-owner.ts +4 -4
- package/src/{runtime-config.ts → runtime/config.ts} +182 -44
- 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} +33 -22
- package/src/{runtime-paths.ts → runtime/paths.ts} +6 -18
- 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 -70
- package/docs/guide-verification.json +0 -239
- package/src/evaluation-context.ts +0 -257
- package/src/evaluation-fixture.ts +0 -313
- package/src/evaluation-run.ts +0 -198
- package/src/evaluation-trial.ts +0 -946
- package/src/evaluation-types.ts +0 -149
- 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 -609
- /package/src/{trial-scheduler.ts → evaluation/scheduler.ts} +0 -0
package/src/hosts/codex.ts
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
2
|
+
import { candidateCodexStateRetained } from "../candidate-codex-state";
|
|
3
|
+
import { lstat, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
3
4
|
import { tmpdir } from "node:os";
|
|
4
5
|
import { isAbsolute, join } from "node:path";
|
|
5
6
|
import type { HostAdapter, HostResult } from "../engine";
|
|
6
|
-
import {
|
|
7
|
-
allocateNativeState,
|
|
8
|
-
requireNativeTranscriptView,
|
|
9
|
-
} from "../native-transcript-state";
|
|
7
|
+
import { allocateNativeState } from "../native-transcript-state";
|
|
10
8
|
import {
|
|
11
9
|
failedNativeTranscripts,
|
|
12
10
|
retainEnabledNativeTranscripts,
|
|
13
11
|
} from "../native-transcripts";
|
|
14
|
-
import { runtimeNativeGoalEnabled } from "../runtime
|
|
12
|
+
import { runtimeNativeGoalEnabled } from "../runtime/config";
|
|
15
13
|
import {
|
|
16
14
|
releaseRuntimeHooks,
|
|
17
15
|
runtimeHookObservation,
|
|
18
16
|
type HookMounts,
|
|
19
|
-
} from "../runtime
|
|
20
|
-
import { runtimeObservations } from "../runtime
|
|
21
|
-
import {
|
|
17
|
+
} from "../runtime/hooks";
|
|
18
|
+
import { runtimeObservations } from "../runtime/state";
|
|
19
|
+
import { validateNativeHostRequest, validHostTimeout } from "./native-request";
|
|
22
20
|
import { runCodexAppServer } from "./codex-app-server";
|
|
23
21
|
import { summarizeCodexEvents, type CodexEventSummary } from "./codex-events";
|
|
24
22
|
import { verifyCodexInvocation } from "./codex-invocation";
|
|
@@ -26,10 +24,8 @@ import { installCodexPlugins } from "./codex-marketplace";
|
|
|
26
24
|
import {
|
|
27
25
|
codexNativeCallObservation,
|
|
28
26
|
codexNativeSessionLastOrdinal,
|
|
29
|
-
codexNativeSkillReadRecovery,
|
|
30
27
|
} from "./codex-native-calls";
|
|
31
|
-
import { runCodexProcess } from "./codex-process";
|
|
32
|
-
import { codexSkillReadObservation } from "./codex-skill-reads";
|
|
28
|
+
import { runCodexProcess, CodexProcessFailure } from "./codex-process";
|
|
33
29
|
import {
|
|
34
30
|
codexHookMounts,
|
|
35
31
|
prepareCodexState,
|
|
@@ -37,13 +33,29 @@ import {
|
|
|
37
33
|
} from "./codex-state";
|
|
38
34
|
import { codexNativeControls } from "./native-controls";
|
|
39
35
|
import { workspaceFingerprint } from "./workspace-fingerprint";
|
|
36
|
+
import { codexSkillCatalogRoots } from "./skill-hook-catalog";
|
|
37
|
+
import {
|
|
38
|
+
prepareSkillTracking,
|
|
39
|
+
skillTrackingObservation,
|
|
40
|
+
skillActivationClaims,
|
|
41
|
+
skillExposureClaims,
|
|
42
|
+
type SkillTracking,
|
|
43
|
+
} from "./skill-hooks";
|
|
44
|
+
import {
|
|
45
|
+
cleanupNativeState,
|
|
46
|
+
createHostDiagnostics,
|
|
47
|
+
diagnoseHostRequest,
|
|
48
|
+
diagnosticConfiguration,
|
|
49
|
+
type HostDiagnostics,
|
|
50
|
+
} from "../host-diagnostics";
|
|
40
51
|
export type { CodexHostOptions } from "./codex-state";
|
|
41
|
-
const MAX_EVENT_BYTES = 8 * 1024 * 1024;
|
|
42
52
|
const DEFAULT_TIMEOUT_MS = 10 * 60_000;
|
|
43
|
-
const MAX_TIMEOUT_MS = 30 * 60_000;
|
|
44
53
|
|
|
45
54
|
type Request = Parameters<HostAdapter["run"]>[0];
|
|
46
|
-
type ProcessResult =
|
|
55
|
+
type ProcessResult = Pick<
|
|
56
|
+
Awaited<ReturnType<typeof runCodexProcess>>,
|
|
57
|
+
"code" | "out"
|
|
58
|
+
>;
|
|
47
59
|
type AppServerResult = Awaited<ReturnType<typeof runCodexAppServer>>;
|
|
48
60
|
type Observation = {
|
|
49
61
|
id: string;
|
|
@@ -56,8 +68,9 @@ interface ExecutionContext {
|
|
|
56
68
|
request: Request;
|
|
57
69
|
state: CodexState;
|
|
58
70
|
timeoutMs: number;
|
|
59
|
-
|
|
60
|
-
|
|
71
|
+
hooks: HookMounts;
|
|
72
|
+
skillTracking: SkillTracking;
|
|
73
|
+
diagnostics: HostDiagnostics;
|
|
61
74
|
}
|
|
62
75
|
interface TurnResult {
|
|
63
76
|
execution: ProcessResult;
|
|
@@ -66,7 +79,6 @@ interface TurnResult {
|
|
|
66
79
|
followUpSummary: CodexEventSummary | null;
|
|
67
80
|
appServer: AppServerResult | null;
|
|
68
81
|
continuation: Observation | undefined;
|
|
69
|
-
observedEvents: string;
|
|
70
82
|
}
|
|
71
83
|
|
|
72
84
|
function validCodexPaths(options: CodexHostOptions): boolean {
|
|
@@ -89,13 +101,7 @@ function validEntrypoint(entrypoint: CodexHostOptions["entrypoint"]): boolean {
|
|
|
89
101
|
entrypoint === undefined || ["exec", "app-server"].includes(entrypoint)
|
|
90
102
|
);
|
|
91
103
|
}
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
Number.isSafeInteger(timeoutMs) &&
|
|
95
|
-
timeoutMs >= 1 &&
|
|
96
|
-
timeoutMs <= MAX_TIMEOUT_MS
|
|
97
|
-
);
|
|
98
|
-
}
|
|
104
|
+
|
|
99
105
|
function validCodexIdentity(
|
|
100
106
|
options: CodexHostOptions,
|
|
101
107
|
limit: number | null,
|
|
@@ -106,7 +112,7 @@ function validCodexIdentity(
|
|
|
106
112
|
!!options.effort &&
|
|
107
113
|
validEntrypoint(options.entrypoint) &&
|
|
108
114
|
validConcurrencyLimit(limit) &&
|
|
109
|
-
|
|
115
|
+
validHostTimeout(timeoutMs)
|
|
110
116
|
);
|
|
111
117
|
}
|
|
112
118
|
function codexCapabilities(
|
|
@@ -117,21 +123,24 @@ function codexCapabilities(
|
|
|
117
123
|
"sevro.host.runtime",
|
|
118
124
|
"sevro.host.native-transcripts",
|
|
119
125
|
"sevro.host.hooks",
|
|
126
|
+
"sevro.host.skill-activations",
|
|
127
|
+
"sevro.host.skill-activation-claims",
|
|
128
|
+
"sevro.host.skill-exposure-claims",
|
|
120
129
|
...(entrypoint === "app-server" ? ["sevro.host.native-goal"] : []),
|
|
121
130
|
"sevro.codex.plugin-marketplace",
|
|
122
131
|
"sevro.codex.explicit-invocation",
|
|
123
132
|
"sevro.codex.repository-invocation",
|
|
124
133
|
"sevro.codex.native-calls",
|
|
125
134
|
"sevro.host.native-controls",
|
|
126
|
-
"sevro.codex.initial-skill-reads",
|
|
127
|
-
"sevro.codex.follow-up-skill-reads",
|
|
128
135
|
];
|
|
129
136
|
}
|
|
130
137
|
function codexConfiguration(
|
|
131
138
|
limit: number | null,
|
|
132
139
|
entrypoint: CodexHostOptions["entrypoint"],
|
|
140
|
+
retainDiagnostics?: boolean,
|
|
133
141
|
) {
|
|
134
142
|
return {
|
|
143
|
+
...diagnosticConfiguration(retainDiagnostics),
|
|
135
144
|
"sevro.codex.agent-concurrency-limit": limit,
|
|
136
145
|
...(entrypoint === "app-server"
|
|
137
146
|
? { "sevro.codex.entrypoint": "app-server" }
|
|
@@ -153,30 +162,17 @@ export function createCodexHost(options: CodexHostOptions): HostAdapter {
|
|
|
153
162
|
hostCapabilities: codexCapabilities(options.entrypoint),
|
|
154
163
|
model: options.model,
|
|
155
164
|
effort: options.effort,
|
|
156
|
-
configuration: codexConfiguration(
|
|
165
|
+
configuration: codexConfiguration(
|
|
166
|
+
limit,
|
|
167
|
+
options.entrypoint,
|
|
168
|
+
options.retainHostDiagnostics,
|
|
169
|
+
),
|
|
157
170
|
run(request) {
|
|
158
171
|
return runCodexRequest(options, timeoutMs, limit, request);
|
|
159
172
|
},
|
|
160
173
|
};
|
|
161
174
|
}
|
|
162
175
|
|
|
163
|
-
function requireCodexFollowUp(request: Request): void {
|
|
164
|
-
if (!isOptionalNonblankString(request.followUpPrompt))
|
|
165
|
-
throw new Error("Codex follow-up prompt must be nonempty");
|
|
166
|
-
}
|
|
167
|
-
function requireCodexFixtureBin(request: Request): void {
|
|
168
|
-
if (
|
|
169
|
-
request.fixtureBinDir !== undefined &&
|
|
170
|
-
request.fixtureBinDir !== join(request.workspace, ".git", "fixture-bin")
|
|
171
|
-
)
|
|
172
|
-
throw new Error("fixture binary path is outside the workspace");
|
|
173
|
-
}
|
|
174
|
-
function requirePassiveCodexRequest(request: Request): void {
|
|
175
|
-
if (request.instrumentation?.length)
|
|
176
|
-
throw new Error("Codex instrumentation is unavailable");
|
|
177
|
-
if (request.condition !== "passive")
|
|
178
|
-
throw new Error("Codex enforcement instrumentation is unavailable");
|
|
179
|
-
}
|
|
180
176
|
function allocateCodexRequestState(request: Request): Promise<string> {
|
|
181
177
|
return allocateNativeState(
|
|
182
178
|
"codex-",
|
|
@@ -190,14 +186,27 @@ async function runCodexRequest(
|
|
|
190
186
|
limit: number | null,
|
|
191
187
|
request: Request,
|
|
192
188
|
): Promise<HostResult> {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
189
|
+
const diagnostics = createHostDiagnostics(
|
|
190
|
+
"codex",
|
|
191
|
+
options.retainHostDiagnostics,
|
|
192
|
+
request,
|
|
193
|
+
);
|
|
194
|
+
return diagnoseHostRequest(diagnostics, async () => {
|
|
195
|
+
diagnostics.stage = "request-validation";
|
|
196
|
+
await diagnostics.readCredentials(options.authFile);
|
|
197
|
+
return executeCodexRequest(options, timeoutMs, limit, request, diagnostics);
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async function executeCodexRequest(
|
|
202
|
+
options: CodexHostOptions,
|
|
203
|
+
timeoutMs: number,
|
|
204
|
+
limit: number | null,
|
|
205
|
+
request: Request,
|
|
206
|
+
diagnostics: HostDiagnostics,
|
|
207
|
+
): Promise<HostResult> {
|
|
208
|
+
await validateCodexRequest(options, request);
|
|
209
|
+
diagnostics.stage = "state-allocation";
|
|
201
210
|
const stateRoot = await allocateCodexRequestState(request);
|
|
202
211
|
const helperRoot =
|
|
203
212
|
process.platform === "linux"
|
|
@@ -205,6 +214,7 @@ async function runCodexRequest(
|
|
|
205
214
|
: undefined;
|
|
206
215
|
let activeHooks: HookMounts | undefined;
|
|
207
216
|
try {
|
|
217
|
+
diagnostics.stage = "state-preparation";
|
|
208
218
|
const state = await prepareCodexState(
|
|
209
219
|
stateRoot,
|
|
210
220
|
options,
|
|
@@ -217,29 +227,29 @@ async function runCodexRequest(
|
|
|
217
227
|
env: state.env,
|
|
218
228
|
pluginCacheRoot: state.pluginCacheRoot,
|
|
219
229
|
request,
|
|
230
|
+
diagnostics,
|
|
220
231
|
});
|
|
232
|
+
diagnostics.stage = "hooks-preparation";
|
|
221
233
|
const hooks = await codexHookMounts(request, state, installedPluginRoots);
|
|
222
234
|
activeHooks = hooks;
|
|
223
|
-
await
|
|
235
|
+
const skillTracking = await prepareCodexSkillTracking(
|
|
236
|
+
state,
|
|
237
|
+
request,
|
|
238
|
+
installedPluginRoots,
|
|
239
|
+
);
|
|
240
|
+
await codexPreflight(options, request, state, diagnostics);
|
|
224
241
|
const context: ExecutionContext = {
|
|
225
242
|
options,
|
|
226
243
|
request,
|
|
227
244
|
state,
|
|
228
245
|
timeoutMs,
|
|
229
|
-
installedPluginRoots,
|
|
230
246
|
hooks,
|
|
247
|
+
skillTracking,
|
|
248
|
+
diagnostics,
|
|
231
249
|
};
|
|
232
250
|
const turns = await new CodexTurnExecution(context).run();
|
|
233
|
-
|
|
234
|
-
await
|
|
235
|
-
result,
|
|
236
|
-
request.runtimePolicy,
|
|
237
|
-
join(state.codexHome, "sessions"),
|
|
238
|
-
"codex",
|
|
239
|
-
request.runtimeRole,
|
|
240
|
-
turns.summary.threadId,
|
|
241
|
-
);
|
|
242
|
-
return result;
|
|
251
|
+
if (turns.summary.complete) diagnostics.stage = "result-processing";
|
|
252
|
+
return await retainCodexResult(context, turns);
|
|
243
253
|
} catch (cause) {
|
|
244
254
|
return await failedNativeTranscripts(
|
|
245
255
|
cause,
|
|
@@ -247,14 +257,92 @@ async function runCodexRequest(
|
|
|
247
257
|
join(stateRoot, "codex-home", "sessions"),
|
|
248
258
|
"codex",
|
|
249
259
|
request.runtimeRole,
|
|
260
|
+
diagnostics,
|
|
250
261
|
);
|
|
251
262
|
} finally {
|
|
252
|
-
await
|
|
253
|
-
|
|
254
|
-
|
|
263
|
+
await cleanupNativeState(diagnostics, async () => {
|
|
264
|
+
await releaseRuntimeHooks(activeHooks);
|
|
265
|
+
if (!candidateCodexStateRetained(request.candidateRuntimeRoot, stateRoot))
|
|
266
|
+
await rm(stateRoot, { recursive: true, force: true });
|
|
267
|
+
if (helperRoot) await rm(helperRoot, { recursive: true, force: true });
|
|
268
|
+
});
|
|
255
269
|
}
|
|
256
270
|
}
|
|
257
271
|
|
|
272
|
+
async function retainCodexResult(context: ExecutionContext, turns: TurnResult) {
|
|
273
|
+
const result = await codexHostResult(context, turns);
|
|
274
|
+
await context.diagnostics.retainFailure(
|
|
275
|
+
result,
|
|
276
|
+
"Codex host execution did not complete",
|
|
277
|
+
);
|
|
278
|
+
await retainEnabledNativeTranscripts(
|
|
279
|
+
result,
|
|
280
|
+
context.request.runtimePolicy,
|
|
281
|
+
join(context.state.codexHome, "sessions"),
|
|
282
|
+
"codex",
|
|
283
|
+
context.request.runtimeRole,
|
|
284
|
+
turns.summary.threadId,
|
|
285
|
+
);
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
async function prepareCodexSkillTracking(
|
|
290
|
+
state: CodexState,
|
|
291
|
+
request: Request,
|
|
292
|
+
pluginRoots: string[],
|
|
293
|
+
): Promise<SkillTracking> {
|
|
294
|
+
const roots = await codexSkillCatalogRoots(request.workspace, pluginRoots, [
|
|
295
|
+
{ directory: join(state.codexHome, "skills"), boundary: state.codexHome },
|
|
296
|
+
{
|
|
297
|
+
directory: join(state.parentHome, ".agents/skills"),
|
|
298
|
+
boundary: state.parentHome,
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
directory: join(state.commandHome, ".agents/skills"),
|
|
302
|
+
boundary: state.commandHome,
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
directory: join(state.commandHome, ".codex/skills"),
|
|
306
|
+
boundary: state.commandHome,
|
|
307
|
+
},
|
|
308
|
+
]);
|
|
309
|
+
const tracking = await prepareSkillTracking({
|
|
310
|
+
privateRoot: state.codexHome,
|
|
311
|
+
host: "codex",
|
|
312
|
+
roots,
|
|
313
|
+
});
|
|
314
|
+
await writeFile(
|
|
315
|
+
join(state.codexHome, "hooks.json"),
|
|
316
|
+
JSON.stringify({ hooks: tracking.hooks }),
|
|
317
|
+
{
|
|
318
|
+
flag: "wx",
|
|
319
|
+
mode: 0o600,
|
|
320
|
+
},
|
|
321
|
+
);
|
|
322
|
+
return tracking;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async function validateCodexRequest(
|
|
326
|
+
options: CodexHostOptions,
|
|
327
|
+
request: Request,
|
|
328
|
+
): Promise<void> {
|
|
329
|
+
await validateNativeHostRequest(request, "Codex");
|
|
330
|
+
requireCodexGoalRoute(request, options);
|
|
331
|
+
await verifyCodexInvocation(request);
|
|
332
|
+
await requireCodexFixtureConfiguration(request);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
async function requireCodexFixtureConfiguration(
|
|
336
|
+
request: Request,
|
|
337
|
+
): Promise<void> {
|
|
338
|
+
const path = join(request.workspace, ".codex");
|
|
339
|
+
if (!existsSync(path)) return;
|
|
340
|
+
if (request.runtimePolicy?.codexState !== true)
|
|
341
|
+
throw new Error("fixture Codex configuration is unsupported");
|
|
342
|
+
if (!(await lstat(path)).isDirectory())
|
|
343
|
+
throw new Error("fixture Codex configuration must be a physical directory");
|
|
344
|
+
}
|
|
345
|
+
|
|
258
346
|
function requireCodexGoalRoute(
|
|
259
347
|
request: Request,
|
|
260
348
|
options: CodexHostOptions,
|
|
@@ -284,12 +372,15 @@ async function sandboxPreflight(
|
|
|
284
372
|
state: CodexState,
|
|
285
373
|
request: Request,
|
|
286
374
|
command: string[],
|
|
375
|
+
diagnostics: HostDiagnostics,
|
|
287
376
|
) {
|
|
288
377
|
return runCodexProcess({
|
|
378
|
+
diagnostics,
|
|
289
379
|
argv: sandboxArgs(state, request, command),
|
|
290
380
|
cwd: request.workspace,
|
|
291
381
|
env: state.env,
|
|
292
382
|
timeoutMs: 60_000,
|
|
383
|
+
phase: "isolation-preflight",
|
|
293
384
|
signal: request.signal,
|
|
294
385
|
});
|
|
295
386
|
}
|
|
@@ -297,22 +388,37 @@ async function codexPreflight(
|
|
|
297
388
|
options: CodexHostOptions,
|
|
298
389
|
request: Request,
|
|
299
390
|
state: CodexState,
|
|
391
|
+
diagnostics: HostDiagnostics,
|
|
300
392
|
): Promise<void> {
|
|
393
|
+
diagnostics.stage = "isolation-preflight";
|
|
301
394
|
const probe = join(state.commandTemp, "isolation-probe");
|
|
302
395
|
await writeFile(probe, "probe\n", { flag: "wx", mode: 0o600 });
|
|
303
|
-
const checked = await sandboxPreflight(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
396
|
+
const checked = await sandboxPreflight(
|
|
397
|
+
state,
|
|
398
|
+
request,
|
|
399
|
+
[
|
|
400
|
+
"/bin/sh",
|
|
401
|
+
"-c",
|
|
402
|
+
'/bin/cat "$1" >/dev/null && ! /bin/ls "$2" >/dev/null 2>&1 && ! /bin/cat "$3" >/dev/null 2>&1 && ! /bin/cat "$4" >/dev/null 2>&1 || exit 70; "$5" --version >/dev/null 2>&1 || exit 71',
|
|
403
|
+
"sevro-probe",
|
|
404
|
+
probe,
|
|
405
|
+
options.projectRoot,
|
|
406
|
+
join(state.codexHome, "auth.json"),
|
|
407
|
+
// The opt-in config read is tested separately; credentials always stay denied.
|
|
408
|
+
join(
|
|
409
|
+
state.codexHome,
|
|
410
|
+
request.runtimePolicy?.codexState === true
|
|
411
|
+
? "auth.json"
|
|
412
|
+
: "config.toml",
|
|
413
|
+
),
|
|
414
|
+
state.sandboxBinary,
|
|
415
|
+
],
|
|
416
|
+
diagnostics,
|
|
417
|
+
);
|
|
418
|
+
if (checked.code === 71)
|
|
419
|
+
throw new CodexProcessFailure("executable-preflight", checked);
|
|
420
|
+
if (checked.code !== 0)
|
|
421
|
+
throw new CodexProcessFailure("isolation-preflight", checked);
|
|
316
422
|
await rm(probe);
|
|
317
423
|
}
|
|
318
424
|
|
|
@@ -327,7 +433,7 @@ function routeArgs(context: ExecutionContext): string[] {
|
|
|
327
433
|
"-c",
|
|
328
434
|
'approval_policy="never"',
|
|
329
435
|
"-c",
|
|
330
|
-
|
|
436
|
+
"features.hooks=true",
|
|
331
437
|
];
|
|
332
438
|
}
|
|
333
439
|
function initialTurnArgs(context: ExecutionContext): string[] {
|
|
@@ -342,7 +448,7 @@ function initialTurnArgs(context: ExecutionContext): string[] {
|
|
|
342
448
|
? []
|
|
343
449
|
: ["--ephemeral"]),
|
|
344
450
|
"--ignore-rules",
|
|
345
|
-
|
|
451
|
+
"--dangerously-bypass-hook-trust",
|
|
346
452
|
"-C",
|
|
347
453
|
context.request.workspace,
|
|
348
454
|
...routeArgs(context),
|
|
@@ -361,7 +467,7 @@ function followUpTurnArgs(
|
|
|
361
467
|
"--strict-config",
|
|
362
468
|
"--skip-git-repo-check",
|
|
363
469
|
"--ignore-rules",
|
|
364
|
-
|
|
470
|
+
"--dangerously-bypass-hook-trust",
|
|
365
471
|
...routeArgs(context),
|
|
366
472
|
threadId,
|
|
367
473
|
"-",
|
|
@@ -372,7 +478,9 @@ async function codexProcessTurn(
|
|
|
372
478
|
argv: string[],
|
|
373
479
|
input: string,
|
|
374
480
|
): Promise<ProcessResult> {
|
|
375
|
-
|
|
481
|
+
context.diagnostics.stage = "exec";
|
|
482
|
+
const result = await runCodexProcess({
|
|
483
|
+
diagnostics: context.diagnostics,
|
|
376
484
|
argv,
|
|
377
485
|
cwd: context.request.workspace,
|
|
378
486
|
env: context.state.env,
|
|
@@ -380,6 +488,7 @@ async function codexProcessTurn(
|
|
|
380
488
|
timeoutMs: context.timeoutMs,
|
|
381
489
|
signal: context.request.signal,
|
|
382
490
|
});
|
|
491
|
+
return result;
|
|
383
492
|
}
|
|
384
493
|
async function initialFingerprint(request: Request): Promise<string | null> {
|
|
385
494
|
return request.followUpPrompt
|
|
@@ -427,43 +536,26 @@ function requireFollowUpCompletion(
|
|
|
427
536
|
"Codex follow-up turn did not complete in the original thread",
|
|
428
537
|
);
|
|
429
538
|
}
|
|
430
|
-
|
|
431
|
-
result: AppServerResult,
|
|
432
|
-
workspace: string,
|
|
433
|
-
): Promise<CodexEventSummary> {
|
|
539
|
+
function appServerSummary(result: AppServerResult): CodexEventSummary {
|
|
434
540
|
return {
|
|
435
541
|
threadId: result.evidence.threadId ?? "",
|
|
436
542
|
complete: result.code === 0,
|
|
437
|
-
finalMessage:
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
: null,
|
|
543
|
+
finalMessage: result.finalMessage,
|
|
544
|
+
// App-server reports cumulative thread totals, not per-turn usage. Keep
|
|
545
|
+
// usage unknown rather than count continuations or feedback more than once.
|
|
441
546
|
inputTokens: null,
|
|
442
547
|
outputTokens: null,
|
|
443
548
|
usageComplete: false,
|
|
444
549
|
};
|
|
445
550
|
}
|
|
446
|
-
|
|
551
|
+
function initialSummary(
|
|
447
552
|
appServer: AppServerResult | null,
|
|
448
553
|
execution: ProcessResult,
|
|
449
|
-
|
|
450
|
-
): Promise<CodexEventSummary> {
|
|
554
|
+
): CodexEventSummary {
|
|
451
555
|
return appServer
|
|
452
|
-
? appServerSummary(appServer
|
|
556
|
+
? appServerSummary(appServer)
|
|
453
557
|
: summarizeCodexEvents(execution.out, execution.code);
|
|
454
558
|
}
|
|
455
|
-
function combinedEvents(
|
|
456
|
-
execution: ProcessResult,
|
|
457
|
-
followUp: ProcessResult | null,
|
|
458
|
-
): string {
|
|
459
|
-
const out = followUp
|
|
460
|
-
? `${execution.out.trimEnd()}\n${followUp.out.trimStart()}`
|
|
461
|
-
: execution.out;
|
|
462
|
-
if (Buffer.byteLength(out, "utf8") > MAX_EVENT_BYTES)
|
|
463
|
-
throw new Error("Codex combined event stream exceeds the size limit");
|
|
464
|
-
return out;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
559
|
class CodexTurnExecution {
|
|
468
560
|
private appServerContinuation?: Observation;
|
|
469
561
|
constructor(private context: ExecutionContext) {}
|
|
@@ -477,11 +569,7 @@ class CodexTurnExecution {
|
|
|
477
569
|
initialTurnArgs(this.context),
|
|
478
570
|
this.context.request.prompt,
|
|
479
571
|
));
|
|
480
|
-
const summary =
|
|
481
|
-
appServer,
|
|
482
|
-
execution,
|
|
483
|
-
this.context.request,
|
|
484
|
-
);
|
|
572
|
+
const summary = initialSummary(appServer, execution);
|
|
485
573
|
requireInitialCompletion(summary, appServer);
|
|
486
574
|
const follow = await this.maybeFollowUp(summary, appServer, fingerprint);
|
|
487
575
|
return {
|
|
@@ -489,7 +577,6 @@ class CodexTurnExecution {
|
|
|
489
577
|
summary,
|
|
490
578
|
appServer,
|
|
491
579
|
...follow,
|
|
492
|
-
observedEvents: combinedEvents(execution, follow.followUp),
|
|
493
580
|
};
|
|
494
581
|
}
|
|
495
582
|
|
|
@@ -498,7 +585,9 @@ class CodexTurnExecution {
|
|
|
498
585
|
): Promise<AppServerResult | null> {
|
|
499
586
|
const { options, request, state, timeoutMs } = this.context;
|
|
500
587
|
if (options.entrypoint !== "app-server") return null;
|
|
588
|
+
this.context.diagnostics.stage = "app-server";
|
|
501
589
|
return runCodexAppServer({
|
|
590
|
+
diagnostics: this.context.diagnostics,
|
|
502
591
|
argv: [
|
|
503
592
|
options.binary,
|
|
504
593
|
"app-server",
|
|
@@ -507,11 +596,11 @@ class CodexTurnExecution {
|
|
|
507
596
|
"-c",
|
|
508
597
|
`default_permissions=${JSON.stringify(state.profileId)}`,
|
|
509
598
|
"-c",
|
|
510
|
-
|
|
599
|
+
"features.hooks=true",
|
|
511
600
|
],
|
|
512
601
|
env: state.env,
|
|
513
602
|
permissionProfile: state.profileId,
|
|
514
|
-
vettedHooks:
|
|
603
|
+
vettedHooks: true,
|
|
515
604
|
request: {
|
|
516
605
|
repoDir: request.workspace,
|
|
517
606
|
prompt: request.prompt,
|
|
@@ -568,62 +657,20 @@ class CodexTurnExecution {
|
|
|
568
657
|
}
|
|
569
658
|
}
|
|
570
659
|
|
|
571
|
-
type SkillReads = Awaited<ReturnType<typeof codexSkillReadObservation>>;
|
|
572
|
-
async function phaseSkillReads(
|
|
573
|
-
context: ExecutionContext,
|
|
574
|
-
turns: TurnResult,
|
|
575
|
-
recovered: Awaited<ReturnType<typeof codexNativeSkillReadRecovery>>,
|
|
576
|
-
) {
|
|
577
|
-
if (!turns.followUp) return { initial: null, followUp: null };
|
|
578
|
-
const initial = {
|
|
579
|
-
...(await codexSkillReadObservation(
|
|
580
|
-
turns.execution.out,
|
|
581
|
-
context.request.workspace,
|
|
582
|
-
context.installedPluginRoots,
|
|
583
|
-
recovered,
|
|
584
|
-
)),
|
|
585
|
-
id: "sevro.codex.initial-skill-reads",
|
|
586
|
-
};
|
|
587
|
-
const followUp = {
|
|
588
|
-
...(await codexSkillReadObservation(
|
|
589
|
-
turns.followUp.out,
|
|
590
|
-
context.request.workspace,
|
|
591
|
-
context.installedPluginRoots,
|
|
592
|
-
recovered,
|
|
593
|
-
)),
|
|
594
|
-
id: "sevro.codex.follow-up-skill-reads",
|
|
595
|
-
};
|
|
596
|
-
return { initial, followUp };
|
|
597
|
-
}
|
|
598
660
|
function explicitInvocationReceipt(
|
|
599
661
|
selected: Request["explicitSkillInvocation"],
|
|
600
|
-
|
|
662
|
+
completed: boolean,
|
|
601
663
|
) {
|
|
602
664
|
if (!selected) return null;
|
|
603
665
|
return {
|
|
604
666
|
id: "sevro.codex.explicit-invocation",
|
|
605
|
-
completeness:
|
|
667
|
+
completeness: completed ? ("complete" as const) : ("partial" as const),
|
|
606
668
|
data: {
|
|
607
669
|
method: "explicit_invocation",
|
|
608
670
|
primarySkill: selected.skillName,
|
|
609
|
-
observedSkills: [
|
|
610
|
-
selected.skillName,
|
|
611
|
-
...reads.data.observedSkills.filter(
|
|
612
|
-
(skill) => skill !== selected.skillName,
|
|
613
|
-
),
|
|
614
|
-
],
|
|
615
671
|
},
|
|
616
672
|
};
|
|
617
673
|
}
|
|
618
|
-
function nativeSkillContext(context: ExecutionContext) {
|
|
619
|
-
return {
|
|
620
|
-
workspace: context.request.workspace,
|
|
621
|
-
installedPluginRoots: context.installedPluginRoots,
|
|
622
|
-
...(context.request.followUpPrompt
|
|
623
|
-
? { followUpPrompt: context.request.followUpPrompt }
|
|
624
|
-
: {}),
|
|
625
|
-
};
|
|
626
|
-
}
|
|
627
674
|
function appServerObservation(result: AppServerResult | null): Observation[] {
|
|
628
675
|
return result
|
|
629
676
|
? [
|
|
@@ -636,45 +683,40 @@ function appServerObservation(result: AppServerResult | null): Observation[] {
|
|
|
636
683
|
: [];
|
|
637
684
|
}
|
|
638
685
|
async function codexObservations(context: ExecutionContext, turns: TurnResult) {
|
|
639
|
-
const
|
|
640
|
-
context.
|
|
686
|
+
const tracking = await skillTrackingObservation(
|
|
687
|
+
context.skillTracking,
|
|
641
688
|
turns.summary.threadId,
|
|
689
|
+
turns.summary.complete,
|
|
642
690
|
);
|
|
643
|
-
const reads = await codexSkillReadObservation(
|
|
644
|
-
turns.observedEvents,
|
|
645
|
-
context.request.workspace,
|
|
646
|
-
context.installedPluginRoots,
|
|
647
|
-
recovered,
|
|
648
|
-
);
|
|
649
|
-
const phases = await phaseSkillReads(context, turns, recovered);
|
|
650
691
|
const native = await codexNativeCallObservation(
|
|
651
692
|
context.state.codexHome,
|
|
652
693
|
turns.summary.threadId,
|
|
653
|
-
|
|
694
|
+
{ followUpPrompt: context.request.followUpPrompt },
|
|
654
695
|
);
|
|
655
696
|
const explicit = explicitInvocationReceipt(
|
|
656
697
|
context.request.explicitSkillInvocation,
|
|
657
|
-
|
|
698
|
+
turns.summary.complete,
|
|
658
699
|
);
|
|
659
700
|
return [
|
|
660
|
-
...(await codexHookObservations(context
|
|
701
|
+
...(await codexHookObservations(context)),
|
|
661
702
|
...runtimeObservations(
|
|
662
703
|
context.request.runtimePolicy,
|
|
663
704
|
context.request.runtimeRole,
|
|
664
705
|
),
|
|
665
706
|
...appServerObservation(turns.appServer),
|
|
666
|
-
reads,
|
|
667
|
-
...(phases.initial ? [phases.initial] : []),
|
|
668
|
-
...(phases.followUp ? [phases.followUp] : []),
|
|
669
707
|
native,
|
|
670
708
|
codexNativeControls(native),
|
|
671
709
|
...(turns.continuation ? [turns.continuation] : []),
|
|
672
710
|
...(explicit ? [explicit] : []),
|
|
711
|
+
tracking,
|
|
712
|
+
...skillActivationClaims(tracking),
|
|
713
|
+
...skillExposureClaims(tracking),
|
|
673
714
|
];
|
|
674
715
|
}
|
|
675
716
|
|
|
676
|
-
async function codexHookObservations(
|
|
677
|
-
|
|
717
|
+
async function codexHookObservations(context: ExecutionContext) {
|
|
718
|
+
if (!context.request.runtimePolicy) return [];
|
|
719
|
+
return [await runtimeHookObservation(context.hooks)];
|
|
678
720
|
}
|
|
679
721
|
function codexArtifacts(turns: TurnResult) {
|
|
680
722
|
return [
|