@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
package/src/hosts/codex.ts
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
requireCandidateArtifactRoots,
|
|
5
|
-
} from "../candidate-artifacts";
|
|
6
|
-
import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
|
|
2
|
+
import { candidateCodexStateRetained } from "../candidate-codex-state";
|
|
3
|
+
import { lstat, mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
7
4
|
import { tmpdir } from "node:os";
|
|
8
5
|
import { isAbsolute, join } from "node:path";
|
|
9
6
|
import type { HostAdapter, HostResult } from "../engine";
|
|
10
|
-
import {
|
|
11
|
-
allocateNativeState,
|
|
12
|
-
requireNativeTranscriptView,
|
|
13
|
-
} from "../native-transcript-state";
|
|
7
|
+
import { allocateNativeState } from "../native-transcript-state";
|
|
14
8
|
import {
|
|
15
9
|
failedNativeTranscripts,
|
|
16
10
|
retainEnabledNativeTranscripts,
|
|
17
11
|
} from "../native-transcripts";
|
|
18
|
-
import { runtimeNativeGoalEnabled } from "../runtime
|
|
12
|
+
import { runtimeNativeGoalEnabled } from "../runtime/config";
|
|
19
13
|
import {
|
|
20
14
|
releaseRuntimeHooks,
|
|
21
15
|
runtimeHookObservation,
|
|
22
16
|
type HookMounts,
|
|
23
|
-
} from "../runtime
|
|
24
|
-
import { runtimeObservations } from "../runtime
|
|
25
|
-
import {
|
|
17
|
+
} from "../runtime/hooks";
|
|
18
|
+
import { runtimeObservations } from "../runtime/state";
|
|
19
|
+
import { validateNativeHostRequest, validHostTimeout } from "./native-request";
|
|
26
20
|
import { runCodexAppServer } from "./codex-app-server";
|
|
27
21
|
import { summarizeCodexEvents, type CodexEventSummary } from "./codex-events";
|
|
28
22
|
import { verifyCodexInvocation } from "./codex-invocation";
|
|
@@ -30,10 +24,8 @@ import { installCodexPlugins } from "./codex-marketplace";
|
|
|
30
24
|
import {
|
|
31
25
|
codexNativeCallObservation,
|
|
32
26
|
codexNativeSessionLastOrdinal,
|
|
33
|
-
codexNativeSkillReadRecovery,
|
|
34
27
|
} from "./codex-native-calls";
|
|
35
28
|
import { runCodexProcess, CodexProcessFailure } from "./codex-process";
|
|
36
|
-
import { codexSkillReadObservation } from "./codex-skill-reads";
|
|
37
29
|
import {
|
|
38
30
|
codexHookMounts,
|
|
39
31
|
prepareCodexState,
|
|
@@ -41,10 +33,23 @@ import {
|
|
|
41
33
|
} from "./codex-state";
|
|
42
34
|
import { codexNativeControls } from "./native-controls";
|
|
43
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";
|
|
44
51
|
export type { CodexHostOptions } from "./codex-state";
|
|
45
|
-
const MAX_EVENT_BYTES = 8 * 1024 * 1024;
|
|
46
52
|
const DEFAULT_TIMEOUT_MS = 10 * 60_000;
|
|
47
|
-
const MAX_TIMEOUT_MS = 30 * 60_000;
|
|
48
53
|
|
|
49
54
|
type Request = Parameters<HostAdapter["run"]>[0];
|
|
50
55
|
type ProcessResult = Pick<
|
|
@@ -63,8 +68,9 @@ interface ExecutionContext {
|
|
|
63
68
|
request: Request;
|
|
64
69
|
state: CodexState;
|
|
65
70
|
timeoutMs: number;
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
hooks: HookMounts;
|
|
72
|
+
skillTracking: SkillTracking;
|
|
73
|
+
diagnostics: HostDiagnostics;
|
|
68
74
|
}
|
|
69
75
|
interface TurnResult {
|
|
70
76
|
execution: ProcessResult;
|
|
@@ -73,7 +79,6 @@ interface TurnResult {
|
|
|
73
79
|
followUpSummary: CodexEventSummary | null;
|
|
74
80
|
appServer: AppServerResult | null;
|
|
75
81
|
continuation: Observation | undefined;
|
|
76
|
-
observedEvents: string;
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
function validCodexPaths(options: CodexHostOptions): boolean {
|
|
@@ -96,13 +101,7 @@ function validEntrypoint(entrypoint: CodexHostOptions["entrypoint"]): boolean {
|
|
|
96
101
|
entrypoint === undefined || ["exec", "app-server"].includes(entrypoint)
|
|
97
102
|
);
|
|
98
103
|
}
|
|
99
|
-
|
|
100
|
-
return (
|
|
101
|
-
Number.isSafeInteger(timeoutMs) &&
|
|
102
|
-
timeoutMs >= 1 &&
|
|
103
|
-
timeoutMs <= MAX_TIMEOUT_MS
|
|
104
|
-
);
|
|
105
|
-
}
|
|
104
|
+
|
|
106
105
|
function validCodexIdentity(
|
|
107
106
|
options: CodexHostOptions,
|
|
108
107
|
limit: number | null,
|
|
@@ -113,7 +112,7 @@ function validCodexIdentity(
|
|
|
113
112
|
!!options.effort &&
|
|
114
113
|
validEntrypoint(options.entrypoint) &&
|
|
115
114
|
validConcurrencyLimit(limit) &&
|
|
116
|
-
|
|
115
|
+
validHostTimeout(timeoutMs)
|
|
117
116
|
);
|
|
118
117
|
}
|
|
119
118
|
function codexCapabilities(
|
|
@@ -124,21 +123,24 @@ function codexCapabilities(
|
|
|
124
123
|
"sevro.host.runtime",
|
|
125
124
|
"sevro.host.native-transcripts",
|
|
126
125
|
"sevro.host.hooks",
|
|
126
|
+
"sevro.host.skill-activations",
|
|
127
|
+
"sevro.host.skill-activation-claims",
|
|
128
|
+
"sevro.host.skill-exposure-claims",
|
|
127
129
|
...(entrypoint === "app-server" ? ["sevro.host.native-goal"] : []),
|
|
128
130
|
"sevro.codex.plugin-marketplace",
|
|
129
131
|
"sevro.codex.explicit-invocation",
|
|
130
132
|
"sevro.codex.repository-invocation",
|
|
131
133
|
"sevro.codex.native-calls",
|
|
132
134
|
"sevro.host.native-controls",
|
|
133
|
-
"sevro.codex.initial-skill-reads",
|
|
134
|
-
"sevro.codex.follow-up-skill-reads",
|
|
135
135
|
];
|
|
136
136
|
}
|
|
137
137
|
function codexConfiguration(
|
|
138
138
|
limit: number | null,
|
|
139
139
|
entrypoint: CodexHostOptions["entrypoint"],
|
|
140
|
+
retainDiagnostics?: boolean,
|
|
140
141
|
) {
|
|
141
142
|
return {
|
|
143
|
+
...diagnosticConfiguration(retainDiagnostics),
|
|
142
144
|
"sevro.codex.agent-concurrency-limit": limit,
|
|
143
145
|
...(entrypoint === "app-server"
|
|
144
146
|
? { "sevro.codex.entrypoint": "app-server" }
|
|
@@ -160,30 +162,17 @@ export function createCodexHost(options: CodexHostOptions): HostAdapter {
|
|
|
160
162
|
hostCapabilities: codexCapabilities(options.entrypoint),
|
|
161
163
|
model: options.model,
|
|
162
164
|
effort: options.effort,
|
|
163
|
-
configuration: codexConfiguration(
|
|
165
|
+
configuration: codexConfiguration(
|
|
166
|
+
limit,
|
|
167
|
+
options.entrypoint,
|
|
168
|
+
options.retainHostDiagnostics,
|
|
169
|
+
),
|
|
164
170
|
run(request) {
|
|
165
171
|
return runCodexRequest(options, timeoutMs, limit, request);
|
|
166
172
|
},
|
|
167
173
|
};
|
|
168
174
|
}
|
|
169
175
|
|
|
170
|
-
function requireCodexFollowUp(request: Request): void {
|
|
171
|
-
if (!isOptionalNonblankString(request.followUpPrompt))
|
|
172
|
-
throw new Error("Codex follow-up prompt must be nonempty");
|
|
173
|
-
}
|
|
174
|
-
function requireCodexFixtureBin(request: Request): void {
|
|
175
|
-
if (
|
|
176
|
-
request.fixtureBinDir !== undefined &&
|
|
177
|
-
request.fixtureBinDir !== join(request.workspace, ".git", "fixture-bin")
|
|
178
|
-
)
|
|
179
|
-
throw new Error("fixture binary path is outside the workspace");
|
|
180
|
-
}
|
|
181
|
-
function requirePassiveCodexRequest(request: Request): void {
|
|
182
|
-
if (request.instrumentation?.length)
|
|
183
|
-
throw new Error("Codex instrumentation is unavailable");
|
|
184
|
-
if (request.condition !== "passive")
|
|
185
|
-
throw new Error("Codex enforcement instrumentation is unavailable");
|
|
186
|
-
}
|
|
187
176
|
function allocateCodexRequestState(request: Request): Promise<string> {
|
|
188
177
|
return allocateNativeState(
|
|
189
178
|
"codex-",
|
|
@@ -197,19 +186,27 @@ async function runCodexRequest(
|
|
|
197
186
|
limit: number | null,
|
|
198
187
|
request: Request,
|
|
199
188
|
): Promise<HostResult> {
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
request
|
|
204
|
-
request.runtimeRole,
|
|
189
|
+
const diagnostics = createHostDiagnostics(
|
|
190
|
+
"codex",
|
|
191
|
+
options.retainHostDiagnostics,
|
|
192
|
+
request,
|
|
205
193
|
);
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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";
|
|
213
210
|
const stateRoot = await allocateCodexRequestState(request);
|
|
214
211
|
const helperRoot =
|
|
215
212
|
process.platform === "linux"
|
|
@@ -217,6 +214,7 @@ async function runCodexRequest(
|
|
|
217
214
|
: undefined;
|
|
218
215
|
let activeHooks: HookMounts | undefined;
|
|
219
216
|
try {
|
|
217
|
+
diagnostics.stage = "state-preparation";
|
|
220
218
|
const state = await prepareCodexState(
|
|
221
219
|
stateRoot,
|
|
222
220
|
options,
|
|
@@ -229,29 +227,29 @@ async function runCodexRequest(
|
|
|
229
227
|
env: state.env,
|
|
230
228
|
pluginCacheRoot: state.pluginCacheRoot,
|
|
231
229
|
request,
|
|
230
|
+
diagnostics,
|
|
232
231
|
});
|
|
232
|
+
diagnostics.stage = "hooks-preparation";
|
|
233
233
|
const hooks = await codexHookMounts(request, state, installedPluginRoots);
|
|
234
234
|
activeHooks = hooks;
|
|
235
|
-
await
|
|
235
|
+
const skillTracking = await prepareCodexSkillTracking(
|
|
236
|
+
state,
|
|
237
|
+
request,
|
|
238
|
+
installedPluginRoots,
|
|
239
|
+
);
|
|
240
|
+
await codexPreflight(options, request, state, diagnostics);
|
|
236
241
|
const context: ExecutionContext = {
|
|
237
242
|
options,
|
|
238
243
|
request,
|
|
239
244
|
state,
|
|
240
245
|
timeoutMs,
|
|
241
|
-
installedPluginRoots,
|
|
242
246
|
hooks,
|
|
247
|
+
skillTracking,
|
|
248
|
+
diagnostics,
|
|
243
249
|
};
|
|
244
250
|
const turns = await new CodexTurnExecution(context).run();
|
|
245
|
-
|
|
246
|
-
await
|
|
247
|
-
result,
|
|
248
|
-
request.runtimePolicy,
|
|
249
|
-
join(state.codexHome, "sessions"),
|
|
250
|
-
"codex",
|
|
251
|
-
request.runtimeRole,
|
|
252
|
-
turns.summary.threadId,
|
|
253
|
-
);
|
|
254
|
-
return result;
|
|
251
|
+
if (turns.summary.complete) diagnostics.stage = "result-processing";
|
|
252
|
+
return await retainCodexResult(context, turns);
|
|
255
253
|
} catch (cause) {
|
|
256
254
|
return await failedNativeTranscripts(
|
|
257
255
|
cause,
|
|
@@ -259,14 +257,92 @@ async function runCodexRequest(
|
|
|
259
257
|
join(stateRoot, "codex-home", "sessions"),
|
|
260
258
|
"codex",
|
|
261
259
|
request.runtimeRole,
|
|
260
|
+
diagnostics,
|
|
262
261
|
);
|
|
263
262
|
} finally {
|
|
264
|
-
await
|
|
265
|
-
|
|
266
|
-
|
|
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
|
+
});
|
|
267
269
|
}
|
|
268
270
|
}
|
|
269
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
|
+
|
|
270
346
|
function requireCodexGoalRoute(
|
|
271
347
|
request: Request,
|
|
272
348
|
options: CodexHostOptions,
|
|
@@ -296,8 +372,10 @@ async function sandboxPreflight(
|
|
|
296
372
|
state: CodexState,
|
|
297
373
|
request: Request,
|
|
298
374
|
command: string[],
|
|
375
|
+
diagnostics: HostDiagnostics,
|
|
299
376
|
) {
|
|
300
377
|
return runCodexProcess({
|
|
378
|
+
diagnostics,
|
|
301
379
|
argv: sandboxArgs(state, request, command),
|
|
302
380
|
cwd: request.workspace,
|
|
303
381
|
env: state.env,
|
|
@@ -310,20 +388,33 @@ async function codexPreflight(
|
|
|
310
388
|
options: CodexHostOptions,
|
|
311
389
|
request: Request,
|
|
312
390
|
state: CodexState,
|
|
391
|
+
diagnostics: HostDiagnostics,
|
|
313
392
|
): Promise<void> {
|
|
393
|
+
diagnostics.stage = "isolation-preflight";
|
|
314
394
|
const probe = join(state.commandTemp, "isolation-probe");
|
|
315
395
|
await writeFile(probe, "probe\n", { flag: "wx", mode: 0o600 });
|
|
316
|
-
const checked = await sandboxPreflight(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
+
);
|
|
327
418
|
if (checked.code === 71)
|
|
328
419
|
throw new CodexProcessFailure("executable-preflight", checked);
|
|
329
420
|
if (checked.code !== 0)
|
|
@@ -342,7 +433,7 @@ function routeArgs(context: ExecutionContext): string[] {
|
|
|
342
433
|
"-c",
|
|
343
434
|
'approval_policy="never"',
|
|
344
435
|
"-c",
|
|
345
|
-
|
|
436
|
+
"features.hooks=true",
|
|
346
437
|
];
|
|
347
438
|
}
|
|
348
439
|
function initialTurnArgs(context: ExecutionContext): string[] {
|
|
@@ -357,7 +448,7 @@ function initialTurnArgs(context: ExecutionContext): string[] {
|
|
|
357
448
|
? []
|
|
358
449
|
: ["--ephemeral"]),
|
|
359
450
|
"--ignore-rules",
|
|
360
|
-
|
|
451
|
+
"--dangerously-bypass-hook-trust",
|
|
361
452
|
"-C",
|
|
362
453
|
context.request.workspace,
|
|
363
454
|
...routeArgs(context),
|
|
@@ -376,7 +467,7 @@ function followUpTurnArgs(
|
|
|
376
467
|
"--strict-config",
|
|
377
468
|
"--skip-git-repo-check",
|
|
378
469
|
"--ignore-rules",
|
|
379
|
-
|
|
470
|
+
"--dangerously-bypass-hook-trust",
|
|
380
471
|
...routeArgs(context),
|
|
381
472
|
threadId,
|
|
382
473
|
"-",
|
|
@@ -387,7 +478,9 @@ async function codexProcessTurn(
|
|
|
387
478
|
argv: string[],
|
|
388
479
|
input: string,
|
|
389
480
|
): Promise<ProcessResult> {
|
|
390
|
-
|
|
481
|
+
context.diagnostics.stage = "exec";
|
|
482
|
+
const result = await runCodexProcess({
|
|
483
|
+
diagnostics: context.diagnostics,
|
|
391
484
|
argv,
|
|
392
485
|
cwd: context.request.workspace,
|
|
393
486
|
env: context.state.env,
|
|
@@ -395,6 +488,7 @@ async function codexProcessTurn(
|
|
|
395
488
|
timeoutMs: context.timeoutMs,
|
|
396
489
|
signal: context.request.signal,
|
|
397
490
|
});
|
|
491
|
+
return result;
|
|
398
492
|
}
|
|
399
493
|
async function initialFingerprint(request: Request): Promise<string | null> {
|
|
400
494
|
return request.followUpPrompt
|
|
@@ -442,43 +536,26 @@ function requireFollowUpCompletion(
|
|
|
442
536
|
"Codex follow-up turn did not complete in the original thread",
|
|
443
537
|
);
|
|
444
538
|
}
|
|
445
|
-
|
|
446
|
-
result: AppServerResult,
|
|
447
|
-
workspace: string,
|
|
448
|
-
): Promise<CodexEventSummary> {
|
|
539
|
+
function appServerSummary(result: AppServerResult): CodexEventSummary {
|
|
449
540
|
return {
|
|
450
541
|
threadId: result.evidence.threadId ?? "",
|
|
451
542
|
complete: result.code === 0,
|
|
452
|
-
finalMessage:
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
: 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.
|
|
456
546
|
inputTokens: null,
|
|
457
547
|
outputTokens: null,
|
|
458
548
|
usageComplete: false,
|
|
459
549
|
};
|
|
460
550
|
}
|
|
461
|
-
|
|
551
|
+
function initialSummary(
|
|
462
552
|
appServer: AppServerResult | null,
|
|
463
553
|
execution: ProcessResult,
|
|
464
|
-
|
|
465
|
-
): Promise<CodexEventSummary> {
|
|
554
|
+
): CodexEventSummary {
|
|
466
555
|
return appServer
|
|
467
|
-
? appServerSummary(appServer
|
|
556
|
+
? appServerSummary(appServer)
|
|
468
557
|
: summarizeCodexEvents(execution.out, execution.code);
|
|
469
558
|
}
|
|
470
|
-
function combinedEvents(
|
|
471
|
-
execution: ProcessResult,
|
|
472
|
-
followUp: ProcessResult | null,
|
|
473
|
-
): string {
|
|
474
|
-
const out = followUp
|
|
475
|
-
? `${execution.out.trimEnd()}\n${followUp.out.trimStart()}`
|
|
476
|
-
: execution.out;
|
|
477
|
-
if (Buffer.byteLength(out, "utf8") > MAX_EVENT_BYTES)
|
|
478
|
-
throw new Error("Codex combined event stream exceeds the size limit");
|
|
479
|
-
return out;
|
|
480
|
-
}
|
|
481
|
-
|
|
482
559
|
class CodexTurnExecution {
|
|
483
560
|
private appServerContinuation?: Observation;
|
|
484
561
|
constructor(private context: ExecutionContext) {}
|
|
@@ -492,11 +569,7 @@ class CodexTurnExecution {
|
|
|
492
569
|
initialTurnArgs(this.context),
|
|
493
570
|
this.context.request.prompt,
|
|
494
571
|
));
|
|
495
|
-
const summary =
|
|
496
|
-
appServer,
|
|
497
|
-
execution,
|
|
498
|
-
this.context.request,
|
|
499
|
-
);
|
|
572
|
+
const summary = initialSummary(appServer, execution);
|
|
500
573
|
requireInitialCompletion(summary, appServer);
|
|
501
574
|
const follow = await this.maybeFollowUp(summary, appServer, fingerprint);
|
|
502
575
|
return {
|
|
@@ -504,7 +577,6 @@ class CodexTurnExecution {
|
|
|
504
577
|
summary,
|
|
505
578
|
appServer,
|
|
506
579
|
...follow,
|
|
507
|
-
observedEvents: combinedEvents(execution, follow.followUp),
|
|
508
580
|
};
|
|
509
581
|
}
|
|
510
582
|
|
|
@@ -513,7 +585,9 @@ class CodexTurnExecution {
|
|
|
513
585
|
): Promise<AppServerResult | null> {
|
|
514
586
|
const { options, request, state, timeoutMs } = this.context;
|
|
515
587
|
if (options.entrypoint !== "app-server") return null;
|
|
588
|
+
this.context.diagnostics.stage = "app-server";
|
|
516
589
|
return runCodexAppServer({
|
|
590
|
+
diagnostics: this.context.diagnostics,
|
|
517
591
|
argv: [
|
|
518
592
|
options.binary,
|
|
519
593
|
"app-server",
|
|
@@ -522,11 +596,11 @@ class CodexTurnExecution {
|
|
|
522
596
|
"-c",
|
|
523
597
|
`default_permissions=${JSON.stringify(state.profileId)}`,
|
|
524
598
|
"-c",
|
|
525
|
-
|
|
599
|
+
"features.hooks=true",
|
|
526
600
|
],
|
|
527
601
|
env: state.env,
|
|
528
602
|
permissionProfile: state.profileId,
|
|
529
|
-
vettedHooks:
|
|
603
|
+
vettedHooks: true,
|
|
530
604
|
request: {
|
|
531
605
|
repoDir: request.workspace,
|
|
532
606
|
prompt: request.prompt,
|
|
@@ -583,62 +657,20 @@ class CodexTurnExecution {
|
|
|
583
657
|
}
|
|
584
658
|
}
|
|
585
659
|
|
|
586
|
-
type SkillReads = Awaited<ReturnType<typeof codexSkillReadObservation>>;
|
|
587
|
-
async function phaseSkillReads(
|
|
588
|
-
context: ExecutionContext,
|
|
589
|
-
turns: TurnResult,
|
|
590
|
-
recovered: Awaited<ReturnType<typeof codexNativeSkillReadRecovery>>,
|
|
591
|
-
) {
|
|
592
|
-
if (!turns.followUp) return { initial: null, followUp: null };
|
|
593
|
-
const initial = {
|
|
594
|
-
...(await codexSkillReadObservation(
|
|
595
|
-
turns.execution.out,
|
|
596
|
-
context.request.workspace,
|
|
597
|
-
context.installedPluginRoots,
|
|
598
|
-
recovered,
|
|
599
|
-
)),
|
|
600
|
-
id: "sevro.codex.initial-skill-reads",
|
|
601
|
-
};
|
|
602
|
-
const followUp = {
|
|
603
|
-
...(await codexSkillReadObservation(
|
|
604
|
-
turns.followUp.out,
|
|
605
|
-
context.request.workspace,
|
|
606
|
-
context.installedPluginRoots,
|
|
607
|
-
recovered,
|
|
608
|
-
)),
|
|
609
|
-
id: "sevro.codex.follow-up-skill-reads",
|
|
610
|
-
};
|
|
611
|
-
return { initial, followUp };
|
|
612
|
-
}
|
|
613
660
|
function explicitInvocationReceipt(
|
|
614
661
|
selected: Request["explicitSkillInvocation"],
|
|
615
|
-
|
|
662
|
+
completed: boolean,
|
|
616
663
|
) {
|
|
617
664
|
if (!selected) return null;
|
|
618
665
|
return {
|
|
619
666
|
id: "sevro.codex.explicit-invocation",
|
|
620
|
-
completeness:
|
|
667
|
+
completeness: completed ? ("complete" as const) : ("partial" as const),
|
|
621
668
|
data: {
|
|
622
669
|
method: "explicit_invocation",
|
|
623
670
|
primarySkill: selected.skillName,
|
|
624
|
-
observedSkills: [
|
|
625
|
-
selected.skillName,
|
|
626
|
-
...reads.data.observedSkills.filter(
|
|
627
|
-
(skill) => skill !== selected.skillName,
|
|
628
|
-
),
|
|
629
|
-
],
|
|
630
671
|
},
|
|
631
672
|
};
|
|
632
673
|
}
|
|
633
|
-
function nativeSkillContext(context: ExecutionContext) {
|
|
634
|
-
return {
|
|
635
|
-
workspace: context.request.workspace,
|
|
636
|
-
installedPluginRoots: context.installedPluginRoots,
|
|
637
|
-
...(context.request.followUpPrompt
|
|
638
|
-
? { followUpPrompt: context.request.followUpPrompt }
|
|
639
|
-
: {}),
|
|
640
|
-
};
|
|
641
|
-
}
|
|
642
674
|
function appServerObservation(result: AppServerResult | null): Observation[] {
|
|
643
675
|
return result
|
|
644
676
|
? [
|
|
@@ -651,45 +683,40 @@ function appServerObservation(result: AppServerResult | null): Observation[] {
|
|
|
651
683
|
: [];
|
|
652
684
|
}
|
|
653
685
|
async function codexObservations(context: ExecutionContext, turns: TurnResult) {
|
|
654
|
-
const
|
|
655
|
-
context.
|
|
686
|
+
const tracking = await skillTrackingObservation(
|
|
687
|
+
context.skillTracking,
|
|
656
688
|
turns.summary.threadId,
|
|
689
|
+
turns.summary.complete,
|
|
657
690
|
);
|
|
658
|
-
const reads = await codexSkillReadObservation(
|
|
659
|
-
turns.observedEvents,
|
|
660
|
-
context.request.workspace,
|
|
661
|
-
context.installedPluginRoots,
|
|
662
|
-
recovered,
|
|
663
|
-
);
|
|
664
|
-
const phases = await phaseSkillReads(context, turns, recovered);
|
|
665
691
|
const native = await codexNativeCallObservation(
|
|
666
692
|
context.state.codexHome,
|
|
667
693
|
turns.summary.threadId,
|
|
668
|
-
|
|
694
|
+
{ followUpPrompt: context.request.followUpPrompt },
|
|
669
695
|
);
|
|
670
696
|
const explicit = explicitInvocationReceipt(
|
|
671
697
|
context.request.explicitSkillInvocation,
|
|
672
|
-
|
|
698
|
+
turns.summary.complete,
|
|
673
699
|
);
|
|
674
700
|
return [
|
|
675
|
-
...(await codexHookObservations(context
|
|
701
|
+
...(await codexHookObservations(context)),
|
|
676
702
|
...runtimeObservations(
|
|
677
703
|
context.request.runtimePolicy,
|
|
678
704
|
context.request.runtimeRole,
|
|
679
705
|
),
|
|
680
706
|
...appServerObservation(turns.appServer),
|
|
681
|
-
reads,
|
|
682
|
-
...(phases.initial ? [phases.initial] : []),
|
|
683
|
-
...(phases.followUp ? [phases.followUp] : []),
|
|
684
707
|
native,
|
|
685
708
|
codexNativeControls(native),
|
|
686
709
|
...(turns.continuation ? [turns.continuation] : []),
|
|
687
710
|
...(explicit ? [explicit] : []),
|
|
711
|
+
tracking,
|
|
712
|
+
...skillActivationClaims(tracking),
|
|
713
|
+
...skillExposureClaims(tracking),
|
|
688
714
|
];
|
|
689
715
|
}
|
|
690
716
|
|
|
691
|
-
async function codexHookObservations(
|
|
692
|
-
|
|
717
|
+
async function codexHookObservations(context: ExecutionContext) {
|
|
718
|
+
if (!context.request.runtimePolicy) return [];
|
|
719
|
+
return [await runtimeHookObservation(context.hooks)];
|
|
693
720
|
}
|
|
694
721
|
function codexArtifacts(turns: TurnResult) {
|
|
695
722
|
return [
|