@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
|
@@ -1,21 +1,38 @@
|
|
|
1
1
|
import { lstat, readFile, realpath } from "node:fs/promises";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import type { ErrorObject } from "ajv";
|
|
3
4
|
import {
|
|
4
5
|
declaredRuntimeRoots,
|
|
5
6
|
optionalRuntimeRoots,
|
|
6
7
|
runtimePathDirectories,
|
|
7
8
|
runtimeInheritedPath,
|
|
8
9
|
requireRuntimeReadRoots,
|
|
9
|
-
} from "./
|
|
10
|
-
import validate from "
|
|
11
|
-
import {
|
|
10
|
+
} from "./paths";
|
|
11
|
+
import validate from "../generated/runtime.cjs";
|
|
12
|
+
import {
|
|
13
|
+
requireArtifactDirectories,
|
|
14
|
+
type RuntimeArtifactDirectory,
|
|
15
|
+
} from "../candidate-artifacts";
|
|
16
|
+
import { runtimeSeedDigest } from "./seeds";
|
|
17
|
+
import {
|
|
18
|
+
resolveSharedCaches,
|
|
19
|
+
requireSharedCachePolicy,
|
|
20
|
+
type SharedCacheDirectory,
|
|
21
|
+
} from "./shared-cache";
|
|
12
22
|
import {
|
|
13
23
|
discoverRuntimeSupport,
|
|
14
24
|
type RuntimeDiscoverySource,
|
|
15
|
-
} from "./
|
|
25
|
+
} from "./discovery";
|
|
16
26
|
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
/** Canonical roles; schemas:generate projects this list into the runtime schema. */
|
|
28
|
+
export const RUNTIME_ROLES = [
|
|
29
|
+
"candidate",
|
|
30
|
+
"checks",
|
|
31
|
+
"hooks",
|
|
32
|
+
"semantic",
|
|
33
|
+
"advisory",
|
|
34
|
+
] as const;
|
|
35
|
+
export type RuntimeRole = (typeof RUNTIME_ROLES)[number];
|
|
19
36
|
export interface RuntimeSeed {
|
|
20
37
|
source: string;
|
|
21
38
|
target: string;
|
|
@@ -23,15 +40,24 @@ export interface RuntimeSeed {
|
|
|
23
40
|
}
|
|
24
41
|
export interface RuntimeConfiguration {
|
|
25
42
|
format: "sevro.runtime.v1";
|
|
43
|
+
codexState?: boolean;
|
|
44
|
+
network?: { localHttp?: boolean };
|
|
26
45
|
nativeTranscripts?: boolean;
|
|
27
46
|
environment?: { inherit?: string[]; set?: Record<string, string> };
|
|
28
47
|
filesystem?: { readOnlyRoots?: string[]; optionalReadOnlyRoots?: string[] };
|
|
29
|
-
runtime?: {
|
|
48
|
+
runtime?: {
|
|
49
|
+
seedDirectories?: RuntimeSeed[];
|
|
50
|
+
sharedCacheDirectories?: SharedCacheDirectory[];
|
|
51
|
+
artifactDirectories?: RuntimeArtifactDirectory[];
|
|
52
|
+
};
|
|
30
53
|
hooks?: { nativeGoal?: boolean; plugins?: string[] };
|
|
31
54
|
}
|
|
32
55
|
|
|
33
56
|
export interface RuntimePolicy {
|
|
34
57
|
format: "sevro.runtime.v1";
|
|
58
|
+
codexState?: boolean;
|
|
59
|
+
network?: { localHttp?: boolean };
|
|
60
|
+
artifactDirectories?: RuntimeArtifactDirectory[];
|
|
35
61
|
nativeTranscripts?: boolean;
|
|
36
62
|
environment: Record<string, string>;
|
|
37
63
|
readOnlyRoots: string[];
|
|
@@ -40,9 +66,18 @@ export interface RuntimePolicy {
|
|
|
40
66
|
/** Original source denials retained when a derived role policy omits seeds. */
|
|
41
67
|
seedReadDenyRoots?: string[];
|
|
42
68
|
seeds?: (RuntimeSeed & { sha256: string })[];
|
|
69
|
+
sharedCacheDirectories?: SharedCacheDirectory[];
|
|
43
70
|
hooks?: { nativeGoal?: boolean; plugins?: string[] };
|
|
44
71
|
}
|
|
45
72
|
|
|
73
|
+
export function runtimeLocalHttpEnabled(
|
|
74
|
+
policy: RuntimePolicy | undefined,
|
|
75
|
+
role: RuntimeRole,
|
|
76
|
+
): boolean {
|
|
77
|
+
const network = policy?.network;
|
|
78
|
+
return network?.localHttp === true && ["candidate", "checks"].includes(role);
|
|
79
|
+
}
|
|
80
|
+
|
|
46
81
|
export function runtimeNativeGoalEnabled(
|
|
47
82
|
policy: RuntimePolicy | undefined,
|
|
48
83
|
): boolean {
|
|
@@ -50,27 +85,64 @@ export function runtimeNativeGoalEnabled(
|
|
|
50
85
|
return hooks?.nativeGoal === true;
|
|
51
86
|
}
|
|
52
87
|
|
|
88
|
+
const validatedPolicies = new WeakSet<RuntimePolicy>();
|
|
89
|
+
|
|
90
|
+
export function runtimePolicySnapshot(policy: RuntimePolicy): RuntimePolicy;
|
|
91
|
+
export function runtimePolicySnapshot(
|
|
92
|
+
policy: RuntimePolicy | undefined,
|
|
93
|
+
): RuntimePolicy | undefined;
|
|
53
94
|
export function runtimePolicySnapshot(
|
|
54
95
|
policy: RuntimePolicy | undefined,
|
|
55
96
|
): RuntimePolicy | undefined {
|
|
56
97
|
if (!policy) return undefined;
|
|
57
|
-
requireRuntimeEnvironment(policy.environment);
|
|
58
98
|
const snapshot = structuredClone(policy);
|
|
99
|
+
if (!validatedPolicies.has(policy)) requireRuntimePolicy(snapshot);
|
|
100
|
+
Object.freeze(snapshot.network);
|
|
101
|
+
freezeArtifactDirectories(snapshot);
|
|
59
102
|
Object.freeze(snapshot.environment);
|
|
60
103
|
Object.freeze(snapshot.readOnlyRoots);
|
|
61
104
|
freezeDiscovery(snapshot);
|
|
62
|
-
|
|
63
|
-
Object.freeze(seed.roles);
|
|
64
|
-
Object.freeze(seed);
|
|
65
|
-
}
|
|
66
|
-
Object.freeze(snapshot.seeds);
|
|
105
|
+
freezeRuntimeCaches(snapshot);
|
|
67
106
|
Object.freeze(snapshot.seedReadDenyRoots);
|
|
68
107
|
const hooks = snapshot.hooks;
|
|
69
108
|
if (hooks) {
|
|
70
109
|
Object.freeze(hooks.plugins);
|
|
71
110
|
Object.freeze(hooks);
|
|
72
111
|
}
|
|
73
|
-
|
|
112
|
+
Object.freeze(snapshot);
|
|
113
|
+
validatedPolicies.add(snapshot);
|
|
114
|
+
return snapshot;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Loaded snapshots are already validated; mutable direct API inputs still need validation. */
|
|
118
|
+
export function requireRuntimePolicy(policy: RuntimePolicy): void {
|
|
119
|
+
if (validatedPolicies.has(policy)) return;
|
|
120
|
+
snapshotEnvironment([], policy.environment);
|
|
121
|
+
requireRuntimeCaches(policy.seeds ?? [], policy.sharedCacheDirectories ?? []);
|
|
122
|
+
requireSharedCachePolicy(policy);
|
|
123
|
+
requireArtifactDirectories(policy.artifactDirectories ?? []);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function requireRuntimeCaches(
|
|
127
|
+
seeds: RuntimeSeed[],
|
|
128
|
+
caches: SharedCacheDirectory[],
|
|
129
|
+
): void {
|
|
130
|
+
requireRuntimeSeedTargets([...seeds, ...caches]);
|
|
131
|
+
for (const seed of seeds)
|
|
132
|
+
if (seed.roles !== undefined) requireRuntimeRoles(seed.roles, "seed");
|
|
133
|
+
for (const cache of caches) requireRuntimeRoles(cache.roles, "shared cache");
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function freezeRuntimeCaches(snapshot: RuntimePolicy): void {
|
|
137
|
+
for (const seed of [
|
|
138
|
+
...(snapshot.seeds ?? []),
|
|
139
|
+
...(snapshot.sharedCacheDirectories ?? []),
|
|
140
|
+
]) {
|
|
141
|
+
Object.freeze(seed.roles);
|
|
142
|
+
Object.freeze(seed);
|
|
143
|
+
}
|
|
144
|
+
Object.freeze(snapshot.seeds);
|
|
145
|
+
Object.freeze(snapshot.sharedCacheDirectories);
|
|
74
146
|
}
|
|
75
147
|
|
|
76
148
|
function freezeDiscovery(snapshot: RuntimePolicy): void {
|
|
@@ -82,14 +154,36 @@ function freezeDiscovery(snapshot: RuntimePolicy): void {
|
|
|
82
154
|
Object.freeze(snapshot.skippedOptionalReadOnlyRoots);
|
|
83
155
|
}
|
|
84
156
|
|
|
157
|
+
function freezeArtifactDirectories(snapshot: RuntimePolicy): void {
|
|
158
|
+
const directories = snapshot.artifactDirectories ?? [];
|
|
159
|
+
for (const directory of directories) Object.freeze(directory);
|
|
160
|
+
Object.freeze(snapshot.artifactDirectories);
|
|
161
|
+
}
|
|
162
|
+
|
|
85
163
|
function assertRuntimeConfiguration(
|
|
86
164
|
value: unknown,
|
|
87
165
|
): asserts value is RuntimeConfiguration {
|
|
88
|
-
if (!validate(value))
|
|
166
|
+
if (!validate(value)) {
|
|
167
|
+
// Ajv always populates errors when validation fails.
|
|
168
|
+
const issue = (validate.errors as [ErrorObject, ...ErrorObject[]])[0];
|
|
169
|
+
throw new Error(
|
|
170
|
+
`runtime configuration schema ${runtimeSchemaPath(issue)}: ${issue.message}`,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function runtimeSchemaPath(issue: ErrorObject): string {
|
|
176
|
+
const params = issue.params as Record<string, unknown>;
|
|
177
|
+
const property = params.additionalProperty ?? params.missingProperty;
|
|
178
|
+
const suffix =
|
|
179
|
+
typeof property === "string"
|
|
180
|
+
? "/" + property.replaceAll("~", "~0").replaceAll("/", "~1")
|
|
181
|
+
: "";
|
|
182
|
+
return safeFilesystemPath(issue.instancePath + suffix || "/");
|
|
89
183
|
}
|
|
90
184
|
|
|
91
185
|
const RESERVED_ENVIRONMENT =
|
|
92
|
-
/^(HOME|TMPDIR|TMP|TEMP|CODEX_HOME|CODEX_THREAD_ID|CLAUDE_CONFIG_DIR|CLAUDE_EFFORT|BASH_ENV|ENV|ZDOTDIR|NODE_OPTIONS|BUN_OPTIONS|UV_OFFLINE|GIT_CONFIG.*|LD_.*|DYLD_.*|CLAUDE_CODE_.*|SEVRO_NATIVE_.*|SEVRO_CANDIDATE_.*)$/i;
|
|
186
|
+
/^(HOME|TMPDIR|TMPPREFIX|TMP|TEMP|CODEX_HOME|CODEX_THREAD_ID|CLAUDE_CONFIG_DIR|CLAUDE_EFFORT|BASH_ENV|ENV|ZDOTDIR|NODE_OPTIONS|BUN_OPTIONS|UV_OFFLINE|GIT_CONFIG.*|LD_.*|DYLD_.*|CLAUDE_CODE_.*|SEVRO_CODEX_.*|SEVRO_NATIVE_.*|SEVRO_CANDIDATE_.*)$/i;
|
|
93
187
|
|
|
94
188
|
function requireEnvironmentName(name: string): void {
|
|
95
189
|
if (!/^[A-Za-z_][A-Za-z0-9_]{0,127}$/.test(name))
|
|
@@ -123,16 +217,7 @@ function snapshotEnvironment(
|
|
|
123
217
|
return environment;
|
|
124
218
|
}
|
|
125
219
|
|
|
126
|
-
|
|
127
|
-
environment: Record<string, string>,
|
|
128
|
-
): void {
|
|
129
|
-
snapshotEnvironment([], environment);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export function requireRuntimeSeedTargets(
|
|
133
|
-
seeds: NonNullable<RuntimePolicy["seeds"]>,
|
|
134
|
-
): void {
|
|
135
|
-
for (const seed of seeds) requireRuntimeSeedRoles(seed.roles);
|
|
220
|
+
function requireRuntimeSeedTargets(seeds: RuntimeSeed[]): void {
|
|
136
221
|
const targets = seeds.map((seed) => seed.target);
|
|
137
222
|
if (
|
|
138
223
|
targets.some(
|
|
@@ -159,13 +244,29 @@ export async function loadRuntimeConfiguration(
|
|
|
159
244
|
const source = await readFile(canonical, "utf8");
|
|
160
245
|
if (Buffer.byteLength(source) > 65536)
|
|
161
246
|
throw new Error("runtime configuration exceeds 64 KiB");
|
|
162
|
-
return
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
247
|
+
return runtimePolicySnapshot(
|
|
248
|
+
await resolveRuntimeConfiguration(
|
|
249
|
+
parseRuntimeConfiguration(source),
|
|
250
|
+
dirname(canonical),
|
|
251
|
+
protectedRoots,
|
|
252
|
+
),
|
|
166
253
|
);
|
|
167
254
|
} catch (cause) {
|
|
168
|
-
throw new Error(
|
|
255
|
+
throw new Error(
|
|
256
|
+
`${runtimeConfigurationDiagnostic(cause)} at ${safeFilesystemPath(path)}`,
|
|
257
|
+
{ cause },
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function parseRuntimeConfiguration(source: string): unknown {
|
|
263
|
+
try {
|
|
264
|
+
return JSON.parse(source);
|
|
265
|
+
} catch (cause) {
|
|
266
|
+
throw new Error(
|
|
267
|
+
"runtime configuration $: invalid JSON; check the JSON syntax",
|
|
268
|
+
{ cause },
|
|
269
|
+
);
|
|
169
270
|
}
|
|
170
271
|
}
|
|
171
272
|
|
|
@@ -240,7 +341,7 @@ async function resolvedSeeds(
|
|
|
240
341
|
environment: Record<string, string>,
|
|
241
342
|
base: string,
|
|
242
343
|
) {
|
|
243
|
-
|
|
344
|
+
return Promise.all(
|
|
244
345
|
seeds.map(async (seed) => {
|
|
245
346
|
const roots = await declaredRuntimeRoots(
|
|
246
347
|
[seed.source],
|
|
@@ -258,8 +359,6 @@ async function resolvedSeeds(
|
|
|
258
359
|
};
|
|
259
360
|
}),
|
|
260
361
|
);
|
|
261
|
-
requireRuntimeSeedTargets(resolved);
|
|
262
|
-
return resolved;
|
|
263
362
|
}
|
|
264
363
|
|
|
265
364
|
async function resolveRuntimeConfiguration(
|
|
@@ -292,18 +391,53 @@ async function resolveRuntimeConfiguration(
|
|
|
292
391
|
requireRuntimeReadRoots(readOnlyRoots, protectedRoots);
|
|
293
392
|
return {
|
|
294
393
|
format: value.format,
|
|
295
|
-
...(value
|
|
296
|
-
|
|
297
|
-
: { nativeTranscripts: value.nativeTranscripts }),
|
|
394
|
+
...selectedRuntimeCapabilities(value),
|
|
395
|
+
...artifactConfiguration(value.runtime),
|
|
298
396
|
environment,
|
|
299
397
|
readOnlyRoots: [...new Set(readOnlyRoots)].sort(),
|
|
300
398
|
discovery: discovery.sources,
|
|
301
399
|
skippedOptionalReadOnlyRoots: optional.skipped,
|
|
302
|
-
|
|
400
|
+
...(await resolvedRuntimeCaches(value, environment, base, [
|
|
401
|
+
...protectedRoots,
|
|
402
|
+
...readOnlyRoots,
|
|
403
|
+
])),
|
|
303
404
|
hooks: resolvedHooks(value.hooks),
|
|
304
405
|
};
|
|
305
406
|
}
|
|
306
407
|
|
|
408
|
+
async function resolvedRuntimeCaches(
|
|
409
|
+
value: RuntimeConfiguration,
|
|
410
|
+
environment: Record<string, string>,
|
|
411
|
+
base: string,
|
|
412
|
+
protectedRoots: string[],
|
|
413
|
+
) {
|
|
414
|
+
const seeds = await resolvedSeeds(
|
|
415
|
+
configurationSeeds(value),
|
|
416
|
+
environment,
|
|
417
|
+
base,
|
|
418
|
+
);
|
|
419
|
+
const caches = await resolveSharedCaches(
|
|
420
|
+
value.runtime?.sharedCacheDirectories ?? [],
|
|
421
|
+
environment,
|
|
422
|
+
base,
|
|
423
|
+
[...protectedRoots, ...seeds.map((seed) => seed.source)],
|
|
424
|
+
);
|
|
425
|
+
return {
|
|
426
|
+
seeds,
|
|
427
|
+
...(caches.length ? { sharedCacheDirectories: caches } : {}),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
function selectedRuntimeCapabilities(value: RuntimeConfiguration) {
|
|
432
|
+
return {
|
|
433
|
+
...(value.network === undefined ? {} : { network: value.network }),
|
|
434
|
+
...(value.codexState === undefined ? {} : { codexState: value.codexState }),
|
|
435
|
+
...(value.nativeTranscripts === undefined
|
|
436
|
+
? {}
|
|
437
|
+
: { nativeTranscripts: value.nativeTranscripts }),
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
307
441
|
async function resolvedRuntimeEnvironment(value: RuntimeConfiguration) {
|
|
308
442
|
const { inherit, set } = configurationEnvironment(value);
|
|
309
443
|
const environment = snapshotEnvironment(inherit, set);
|
|
@@ -318,6 +452,12 @@ function configurationEnvironment(value: RuntimeConfiguration) {
|
|
|
318
452
|
const environment = value.environment;
|
|
319
453
|
return { inherit: environment?.inherit ?? [], set: environment?.set ?? {} };
|
|
320
454
|
}
|
|
455
|
+
|
|
456
|
+
function artifactConfiguration(runtime: RuntimeConfiguration["runtime"]) {
|
|
457
|
+
const directories = runtime?.artifactDirectories;
|
|
458
|
+
if (directories === undefined) return {};
|
|
459
|
+
return { artifactDirectories: directories };
|
|
460
|
+
}
|
|
321
461
|
function configurationReadRoots(value: RuntimeConfiguration): string[] {
|
|
322
462
|
return value.filesystem?.readOnlyRoots ?? [];
|
|
323
463
|
}
|
|
@@ -332,20 +472,18 @@ function resolvedHooks(hooks: RuntimeConfiguration["hooks"]) {
|
|
|
332
472
|
};
|
|
333
473
|
}
|
|
334
474
|
|
|
335
|
-
function
|
|
336
|
-
if (roles === undefined) return;
|
|
337
|
-
const allowed = ["candidate", "checks", "hooks", "semantic", "advisory"];
|
|
475
|
+
function requireRuntimeRoles(roles: RuntimeRole[], kind: string): void {
|
|
338
476
|
if (
|
|
339
477
|
!validRoleArray(roles) ||
|
|
340
478
|
new Set(roles).size !== roles.length ||
|
|
341
|
-
roles.some((role) => !
|
|
479
|
+
roles.some((role) => !RUNTIME_ROLES.includes(role))
|
|
342
480
|
)
|
|
343
|
-
throw new Error(
|
|
481
|
+
throw new Error(`runtime ${kind} roles are invalid`);
|
|
344
482
|
}
|
|
345
483
|
|
|
346
484
|
export function runtimeRoleSeeds(policy: RuntimePolicy, role: RuntimeRole) {
|
|
347
485
|
return (policy.seeds ?? []).filter(
|
|
348
|
-
(seed) => seed.roles
|
|
486
|
+
(seed) => seed.roles?.includes(role) ?? role !== "checks",
|
|
349
487
|
);
|
|
350
488
|
}
|
|
351
489
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { realpath } from "node:fs/promises";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
|
-
import { RuntimeMetadataQueryError } from "./
|
|
4
|
-
import { optionalRuntimeRoots, requireRuntimeReadRoots } from "./
|
|
3
|
+
import { RuntimeMetadataQueryError } from "./query";
|
|
4
|
+
import { optionalRuntimeRoots, requireRuntimeReadRoots } from "./paths";
|
|
5
5
|
import {
|
|
6
6
|
providerExecutable,
|
|
7
7
|
query,
|
|
8
8
|
requireProvider,
|
|
9
9
|
type RuntimeDiscoverySource,
|
|
10
|
-
} from "./
|
|
10
|
+
} from "./discovery-providers";
|
|
11
11
|
|
|
12
12
|
export async function discoverApple(
|
|
13
13
|
path: string,
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { access, realpath } from "node:fs/promises";
|
|
2
2
|
import { constants } from "node:fs";
|
|
3
3
|
import { delimiter, isAbsolute, join } from "node:path";
|
|
4
|
-
import { runtimeMetadataQuery } from "./
|
|
5
|
-
import { requireRuntimeReadRoots } from "./
|
|
4
|
+
import { runtimeMetadataQuery } from "./query";
|
|
5
|
+
import { requireRuntimeReadRoots } from "./paths";
|
|
6
|
+
import { containsControl } from "../value-guards";
|
|
6
7
|
|
|
7
8
|
export interface RuntimeDiscoverySource {
|
|
8
9
|
provider: "homebrew" | "apple-developer";
|
|
@@ -45,13 +46,6 @@ export async function query(
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
function containsControl(value: string): boolean {
|
|
49
|
-
return Array.from(value).some(
|
|
50
|
-
(character) =>
|
|
51
|
-
character.charCodeAt(0) < 0x20 || character.charCodeAt(0) === 0x7f,
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
49
|
export async function requireProvider(
|
|
56
50
|
executable: string,
|
|
57
51
|
protectedRoots: string[],
|
|
@@ -4,14 +4,14 @@ import {
|
|
|
4
4
|
insideRuntimeRoot,
|
|
5
5
|
optionalRuntimeRoots,
|
|
6
6
|
requireRuntimeReadRoots,
|
|
7
|
-
} from "./
|
|
7
|
+
} from "./paths";
|
|
8
8
|
import {
|
|
9
9
|
providerExecutable,
|
|
10
10
|
query,
|
|
11
11
|
requireProvider,
|
|
12
12
|
type RuntimeDiscoverySource,
|
|
13
|
-
} from "./
|
|
14
|
-
export type { RuntimeDiscoverySource } from "./
|
|
13
|
+
} from "./discovery-providers";
|
|
14
|
+
export type { RuntimeDiscoverySource } from "./discovery-providers";
|
|
15
15
|
|
|
16
16
|
async function homebrew(
|
|
17
17
|
executable: string,
|
|
@@ -63,7 +63,7 @@ export async function discoverRuntimeSupport(
|
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
65
|
if (process.platform === "darwin") {
|
|
66
|
-
const { discoverApple } = await import("./
|
|
66
|
+
const { discoverApple } = await import("./discovery-apple");
|
|
67
67
|
await discoverApple(path, environment, sources, protectedRoots);
|
|
68
68
|
}
|
|
69
69
|
return { sources, excludedPrefixes };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFile, readdir, writeFile } from "node:fs/promises";
|
|
2
2
|
import { basename, dirname, join } from "node:path";
|
|
3
|
-
import { isRecord } from "
|
|
3
|
+
import { isRecord } from "../value-guards";
|
|
4
4
|
|
|
5
5
|
export async function hookExecutions(
|
|
6
6
|
receipts: string,
|
|
@@ -7,19 +7,21 @@ import {
|
|
|
7
7
|
writeFile,
|
|
8
8
|
} from "node:fs/promises";
|
|
9
9
|
import { join } from "node:path";
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
10
|
+
import { shellQuote as quote } from "../shell";
|
|
11
|
+
import type { RuntimePolicy } from "./config";
|
|
12
|
+
import { insideRuntimeRoot, requireRuntimeReadRoots } from "./paths";
|
|
13
|
+
import { runtimeSeedDigest } from "./seeds";
|
|
14
|
+
import { prepareRuntimeState } from "./state";
|
|
15
|
+
import { sharedCacheDenyRoots, sharedCacheRoots } from "./shared-cache";
|
|
16
|
+
import { macSandboxProfile } from "../hosts/mac-sandbox";
|
|
17
|
+
import type { IsolatedCommand } from "../hosts/mac-sandbox";
|
|
18
|
+
import { prepareLinuxSandboxCommand } from "../hosts/linux-sandbox";
|
|
19
|
+
import { isRecord, isUnknownArray } from "../value-guards";
|
|
20
|
+
import { hookExecutions, releaseHookProcesses } from "./hook-processes";
|
|
19
21
|
import {
|
|
20
22
|
nativeStateParent,
|
|
21
23
|
requireNativeHookRoots,
|
|
22
|
-
} from "
|
|
24
|
+
} from "../native-transcript-state";
|
|
23
25
|
|
|
24
26
|
export interface HookMounts {
|
|
25
27
|
directories: string[];
|
|
@@ -61,10 +63,6 @@ function object(value: unknown): Record<string, unknown> {
|
|
|
61
63
|
return value;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
|
-
function quote(value: string): string {
|
|
65
|
-
return `'${value.replaceAll("'", `'"'"'`)}'`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
66
|
/** Materialize immutable mounts; only declared plugin hooks reach the host. */
|
|
69
67
|
export async function prepareHookMounts(options: {
|
|
70
68
|
workspace: string;
|
|
@@ -156,7 +154,7 @@ function lazyHookExecution(
|
|
|
156
154
|
options,
|
|
157
155
|
index,
|
|
158
156
|
readRoots,
|
|
159
|
-
runtime
|
|
157
|
+
runtime,
|
|
160
158
|
);
|
|
161
159
|
if (boundary.isolation) isolation.push(boundary.isolation);
|
|
162
160
|
return {
|
|
@@ -175,30 +173,43 @@ async function prepareHookIsolation(
|
|
|
175
173
|
options: Parameters<typeof prepareHookMounts>[0],
|
|
176
174
|
index: number,
|
|
177
175
|
roots: { ordinary: string[]; curated: string[] },
|
|
178
|
-
|
|
176
|
+
runtime: Awaited<ReturnType<typeof prepareRuntimeState>>,
|
|
179
177
|
): Promise<{ profile?: string; isolation?: IsolatedCommand }> {
|
|
178
|
+
const cacheRoots = await sharedCacheRoots(
|
|
179
|
+
options.policy,
|
|
180
|
+
"hooks",
|
|
181
|
+
options.protectedRoots,
|
|
182
|
+
);
|
|
183
|
+
const protectedRoots = [
|
|
184
|
+
...options.protectedRoots,
|
|
185
|
+
...sharedCacheDenyRoots(options.policy, "hooks"),
|
|
186
|
+
];
|
|
180
187
|
if (process.platform === "linux")
|
|
181
188
|
return {
|
|
182
189
|
isolation: await prepareLinuxSandboxCommand({
|
|
183
190
|
argv: ["/bin/true"],
|
|
184
191
|
workspace: options.workspace,
|
|
185
|
-
protectedRoots
|
|
192
|
+
protectedRoots,
|
|
186
193
|
privateStateRoot: options.privateRoot,
|
|
187
194
|
denyNetwork: true,
|
|
188
195
|
readOnlyRoots: roots.ordinary,
|
|
189
196
|
hookReadRoots: roots.curated,
|
|
190
|
-
writableRuntimeRoot:
|
|
197
|
+
writableRuntimeRoot: runtime.root,
|
|
198
|
+
writableCacheRoots: cacheRoots,
|
|
191
199
|
}),
|
|
192
200
|
};
|
|
193
201
|
const profile = join(options.privateRoot, `hooks-${index}.sb`);
|
|
194
202
|
await writeFile(
|
|
195
203
|
profile,
|
|
196
204
|
macSandboxProfile(
|
|
197
|
-
|
|
205
|
+
protectedRoots,
|
|
198
206
|
true,
|
|
199
207
|
roots.ordinary,
|
|
200
|
-
|
|
208
|
+
runtime.root,
|
|
201
209
|
roots.curated,
|
|
210
|
+
options.workspace,
|
|
211
|
+
undefined,
|
|
212
|
+
cacheRoots,
|
|
202
213
|
) + "\n(deny process-info* (require-not (target self)))\n",
|
|
203
214
|
{ mode: 0o600 },
|
|
204
215
|
);
|
|
@@ -216,7 +227,7 @@ async function hookReadRoots(
|
|
|
216
227
|
];
|
|
217
228
|
const curated = trusted ? [root] : [];
|
|
218
229
|
requireRuntimeReadRoots(ordinary, options.protectedRoots);
|
|
219
|
-
await requireNativeHookRoots(curated);
|
|
230
|
+
await requireNativeHookRoots(curated, options.privateRoot);
|
|
220
231
|
return { ordinary, curated };
|
|
221
232
|
}
|
|
222
233
|
|
|
@@ -421,7 +432,7 @@ async function rewriteMarkdown(
|
|
|
421
432
|
else delete metadata.hooks;
|
|
422
433
|
await writeFile(
|
|
423
434
|
path,
|
|
424
|
-
`---\n${Bun.YAML.stringify(metadata)}---\n${body.slice(header[0].length)}`,
|
|
435
|
+
`---\n${Bun.YAML.stringify(metadata)}\n---\n${body.slice(header[0].length)}`,
|
|
425
436
|
);
|
|
426
437
|
}
|
|
427
438
|
|
|
@@ -8,26 +8,20 @@ import {
|
|
|
8
8
|
} from "node:fs/promises";
|
|
9
9
|
import { constants, lstatSync, readlinkSync, realpathSync } from "node:fs";
|
|
10
10
|
import { homedir, userInfo } from "node:os";
|
|
11
|
-
import { nativeStateProtectedRoots } from "
|
|
11
|
+
import { nativeStateProtectedRoots } from "../native-transcript-state";
|
|
12
|
+
import { workspaceStatePath } from "../fixtures/workspace-state";
|
|
13
|
+
import { insideRoot as insideRuntimeRoot } from "../paths";
|
|
14
|
+
import { containsControl } from "../value-guards";
|
|
15
|
+
export { insideRoot as insideRuntimeRoot } from "../paths";
|
|
12
16
|
import {
|
|
13
17
|
basename,
|
|
14
18
|
delimiter,
|
|
15
19
|
dirname,
|
|
16
20
|
isAbsolute,
|
|
17
21
|
join,
|
|
18
|
-
relative,
|
|
19
22
|
resolve,
|
|
20
|
-
sep,
|
|
21
23
|
} from "node:path";
|
|
22
24
|
|
|
23
|
-
export function insideRuntimeRoot(root: string, path: string): boolean {
|
|
24
|
-
const child = relative(root, path);
|
|
25
|
-
return (
|
|
26
|
-
child === "" ||
|
|
27
|
-
(!child.startsWith(`..${sep}`) && child !== ".." && !isAbsolute(child))
|
|
28
|
-
);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
25
|
export function isRuntimeHomeRoot(root: string): boolean {
|
|
32
26
|
return [homedir(), userInfo().homedir]
|
|
33
27
|
.map((home) => resolve(home))
|
|
@@ -42,6 +36,7 @@ export function requireRuntimeReadRoots(
|
|
|
42
36
|
...protectedRoots.filter((root) => !isRuntimeHomeRoot(root)),
|
|
43
37
|
...runtimeCredentialRoots(),
|
|
44
38
|
...nativeStateProtectedRoots(),
|
|
39
|
+
workspaceStatePath(),
|
|
45
40
|
];
|
|
46
41
|
for (const root of readRoots) {
|
|
47
42
|
if (root === "/" || isRuntimeHomeRoot(root))
|
|
@@ -193,13 +188,6 @@ export async function runtimePathDirectories(
|
|
|
193
188
|
return [...new Set(roots)].sort();
|
|
194
189
|
}
|
|
195
190
|
|
|
196
|
-
function containsControl(value: string): boolean {
|
|
197
|
-
return Array.from(value).some(
|
|
198
|
-
(character) =>
|
|
199
|
-
character.charCodeAt(0) < 0x20 || character.charCodeAt(0) === 0x7f,
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
191
|
function requirePathEntry(entry: string): void {
|
|
204
192
|
if (!isAbsolute(entry) || containsControl(entry))
|
|
205
193
|
throw new Error("runtime PATH entries must be absolute and nonempty");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawn, type ChildProcess } from "node:child_process";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
+
import { terminateOwnedProcessGroup } from "../process-lifecycle";
|
|
3
4
|
|
|
4
5
|
export class RuntimeMetadataQueryError extends Error {
|
|
5
6
|
constructor(
|
|
@@ -25,11 +26,10 @@ function exitError(
|
|
|
25
26
|
|
|
26
27
|
function stopQuery(child: ChildProcess): void {
|
|
27
28
|
if (child.pid === undefined) return;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
29
|
+
terminateOwnedProcessGroup(
|
|
30
|
+
{ pid: child.pid, kill: (signal) => child.kill(signal) },
|
|
31
|
+
{ alwaysGroup: true, fallbackError: "propagate" },
|
|
32
|
+
);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
/** Bound both output streams and stop every descendant of this metadata query. */
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
writeFile,
|
|
9
9
|
} from "node:fs/promises";
|
|
10
10
|
import { join } from "node:path";
|
|
11
|
-
import { hashJson, sha256 } from "
|
|
12
|
-
import type { RuntimePolicy } from "./
|
|
13
|
-
import { insideRuntimeRoot } from "./
|
|
11
|
+
import { hashJson, sha256 } from "../identity";
|
|
12
|
+
import type { RuntimePolicy } from "./config";
|
|
13
|
+
import { insideRuntimeRoot } from "./paths";
|
|
14
14
|
|
|
15
15
|
class SeedSnapshot {
|
|
16
16
|
private entries = 0;
|