@kitman-sh/cli 0.6.0 → 0.7.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/dist/{chunk-tfr74ays.js → chunk-226sychh.js} +142 -33
- package/dist/{chunk-brp7cekg.js → chunk-6f4anyec.js} +1 -1
- package/dist/{chunk-fc0v325q.js → chunk-6kdj8psf.js} +9 -10
- package/dist/{chunk-txyq8r41.js → chunk-704ws2q7.js} +1230 -442
- package/dist/chunk-ae7gx971.js +78 -0
- package/dist/{chunk-hw7qkap1.js → chunk-dwgta18y.js} +22 -361
- package/dist/{chunk-dsefng1v.js → chunk-epdajq63.js} +5 -6
- package/dist/{chunk-6h8ghah0.js → chunk-gzhxsb25.js} +3 -4
- package/dist/{chunk-h8ctzn91.js → chunk-hrd7xmax.js} +9 -12
- package/dist/{chunk-3j7sewn0.js → chunk-vjnae06n.js} +780 -613
- package/dist/{chunk-n32jhswz.js → chunk-ztmwmk8t.js} +21 -23
- package/dist/index.js +341 -95
- package/package.json +1 -1
- package/dist/chunk-hrvcz0m4.js +0 -211
- package/dist/chunk-xdk488qp.js +0 -364
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
isNone,
|
|
15
15
|
isSome,
|
|
16
16
|
getOrUndefined,
|
|
17
|
-
|
|
17
|
+
Service,
|
|
18
18
|
get,
|
|
19
19
|
merge,
|
|
20
20
|
succeed,
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
isSuccess,
|
|
25
25
|
ensure,
|
|
26
26
|
map2,
|
|
27
|
+
infinity,
|
|
27
28
|
millis,
|
|
28
29
|
seconds,
|
|
29
30
|
TaggedError,
|
|
@@ -34,12 +35,12 @@ import {
|
|
|
34
35
|
void_,
|
|
35
36
|
isSuccess2,
|
|
36
37
|
isFailure2,
|
|
37
|
-
|
|
38
|
+
makeUnsafe,
|
|
38
39
|
_await,
|
|
39
40
|
isDoneUnsafe,
|
|
40
41
|
doneUnsafe,
|
|
41
42
|
Scope,
|
|
42
|
-
|
|
43
|
+
make6,
|
|
43
44
|
provide,
|
|
44
45
|
addFinalizer,
|
|
45
46
|
close,
|
|
@@ -104,9 +105,9 @@ import {
|
|
|
104
105
|
logWarning,
|
|
105
106
|
logError,
|
|
106
107
|
interrupt3,
|
|
108
|
+
makeUnsafe3,
|
|
107
109
|
makeUnsafe4,
|
|
108
|
-
|
|
109
|
-
make13,
|
|
110
|
+
make9,
|
|
110
111
|
map4,
|
|
111
112
|
filter,
|
|
112
113
|
decodeText,
|
|
@@ -115,7 +116,7 @@ import {
|
|
|
115
116
|
FileSystem,
|
|
116
117
|
Path,
|
|
117
118
|
ChildProcessSpawner,
|
|
118
|
-
|
|
119
|
+
make11,
|
|
119
120
|
Crypto,
|
|
120
121
|
value,
|
|
121
122
|
is,
|
|
@@ -146,19 +147,21 @@ import {
|
|
|
146
147
|
encodePrettyJsonString,
|
|
147
148
|
decodeJsonStringSync,
|
|
148
149
|
encodeUnknownJsonStringSync,
|
|
149
|
-
option2,
|
|
150
|
-
String3,
|
|
151
150
|
digestSha256,
|
|
151
|
+
RunSettled,
|
|
152
152
|
CommandFailed2,
|
|
153
153
|
runCommand2,
|
|
154
154
|
shellOutputTailChars2,
|
|
155
|
+
runProcess2,
|
|
155
156
|
runShell2,
|
|
157
|
+
optionalEnv,
|
|
158
|
+
detectHarnesses2,
|
|
156
159
|
herdrExecutionExtension2,
|
|
157
160
|
herdrNativeExtensionIds2,
|
|
158
|
-
|
|
159
|
-
|
|
161
|
+
herdrRunnerCapabilitiesForRepoBinding2,
|
|
162
|
+
herdrRunnerCapabilities2,
|
|
160
163
|
assertHerdrRunnerCapability2
|
|
161
|
-
} from "./chunk-
|
|
164
|
+
} from "./chunk-704ws2q7.js";
|
|
162
165
|
import {
|
|
163
166
|
make4,
|
|
164
167
|
readerString,
|
|
@@ -169,18 +172,17 @@ import {
|
|
|
169
172
|
SocketUpgradeError,
|
|
170
173
|
SocketCloseError,
|
|
171
174
|
SocketError
|
|
172
|
-
} from "./chunk-
|
|
173
|
-
import"./chunk-
|
|
175
|
+
} from "./chunk-dwgta18y.js";
|
|
176
|
+
import"./chunk-ztmwmk8t.js";
|
|
174
177
|
import {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
} from "./chunk-fc0v325q.js";
|
|
178
|
+
programLease,
|
|
179
|
+
programHostsEnv,
|
|
180
|
+
undeclaredHostsEnv
|
|
181
|
+
} from "./chunk-6kdj8psf.js";
|
|
182
|
+
import"./chunk-ae7gx971.js";
|
|
181
183
|
import {
|
|
182
184
|
nextInt
|
|
183
|
-
} from "./chunk-
|
|
185
|
+
} from "./chunk-6f4anyec.js";
|
|
184
186
|
|
|
185
187
|
// packages/core/src/runner-trust.ts
|
|
186
188
|
import { createHash } from "crypto";
|
|
@@ -468,14 +470,6 @@ function sortValue(value) {
|
|
|
468
470
|
}
|
|
469
471
|
return result;
|
|
470
472
|
}
|
|
471
|
-
// packages/agent-runtime/src/env.ts
|
|
472
|
-
var optionalEnv = (name) => gen(function* () {
|
|
473
|
-
const value = getOrUndefined(yield* option2(String3(name)))?.trim();
|
|
474
|
-
return value === undefined || value.length === 0 ? undefined : value;
|
|
475
|
-
}).pipe(orElseSucceed(() => {
|
|
476
|
-
return;
|
|
477
|
-
}));
|
|
478
|
-
|
|
479
473
|
// packages/agent-runtime/src/config.ts
|
|
480
474
|
class AgentRuntimeConfigError extends TaggedError("AgentRuntimeConfigError") {
|
|
481
475
|
}
|
|
@@ -1826,7 +1820,7 @@ var makeNet = (options) => fromDuplex(contextWith((context) => {
|
|
|
1826
1820
|
}), options);
|
|
1827
1821
|
var fromDuplex = (open, options) => withFiber((fiber) => {
|
|
1828
1822
|
let currentSocket;
|
|
1829
|
-
const latch =
|
|
1823
|
+
const latch = makeUnsafe3(false);
|
|
1830
1824
|
const openServices = fiber.context;
|
|
1831
1825
|
const isServer = options?.tlsServer === true;
|
|
1832
1826
|
const secureEvent = isServer ? "secure" : "secureConnect";
|
|
@@ -2354,12 +2348,10 @@ class HerdrServerSupervisor {
|
|
|
2354
2348
|
start = fnUntraced(function* () {
|
|
2355
2349
|
if (this.started && this.client !== undefined)
|
|
2356
2350
|
return yield* this.client.sessionSnapshot().pipe(mapError((error) => fail3(error.message)));
|
|
2357
|
-
if ((this.options.platform ?? process.platform)
|
|
2358
|
-
return yield* fail3("
|
|
2351
|
+
if (!["linux", "darwin"].includes(this.options.platform ?? process.platform))
|
|
2352
|
+
return yield* fail3("herdr_platform_unsupported");
|
|
2359
2353
|
const defaultSession = this.options.session === "default";
|
|
2360
2354
|
const runtime = defaultSession ? undefined : yield* this.prepareRuntime();
|
|
2361
|
-
if (!(yield* (this.options.executableAvailable ?? executableAvailable)(this.options.piCommand ?? "pi")))
|
|
2362
|
-
return yield* fail3("herdr_pi_unavailable");
|
|
2363
2355
|
const socketClientOptions = this.options.socketClientOptions ?? {};
|
|
2364
2356
|
const socketPath = runtime?.socketPath ?? (yield* defaultSessionSocketPath);
|
|
2365
2357
|
const clientOptions = {
|
|
@@ -2499,15 +2491,10 @@ var defaultSessionSocketPath = gen(function* () {
|
|
|
2499
2491
|
});
|
|
2500
2492
|
var homeDirectory = map3(optionalEnv("HOME"), (home) => home ?? "/");
|
|
2501
2493
|
var temporaryDirectory = map3(optionalEnv("TMPDIR"), (tmp) => tmp ?? "/tmp");
|
|
2502
|
-
var executableAvailable = (command) => gen(function* () {
|
|
2503
|
-
const spawner = yield* ChildProcessSpawner;
|
|
2504
|
-
const exitCode = yield* spawner.exitCode(make15("which", [command], { stdin: "ignore", stdout: "ignore", stderr: "ignore" }));
|
|
2505
|
-
return exitCode === 0;
|
|
2506
|
-
}).pipe(orElseSucceed(() => false));
|
|
2507
2494
|
var spawnServer = (input) => gen(function* () {
|
|
2508
2495
|
const spawner = yield* ChildProcessSpawner;
|
|
2509
|
-
const scope = yield*
|
|
2510
|
-
const handle = yield* spawner.spawn(
|
|
2496
|
+
const scope = yield* make6();
|
|
2497
|
+
const handle = yield* spawner.spawn(make11(input.command, [...input.args], {
|
|
2511
2498
|
env: { HERDR_SOCKET_PATH: input.socketPath },
|
|
2512
2499
|
extendEnv: true,
|
|
2513
2500
|
detached: true,
|
|
@@ -2562,7 +2549,7 @@ function digest(value) {
|
|
|
2562
2549
|
class HarnessError extends TaggedError("HarnessError") {
|
|
2563
2550
|
}
|
|
2564
2551
|
|
|
2565
|
-
class Harness extends
|
|
2552
|
+
class Harness extends Service()("Harness") {
|
|
2566
2553
|
}
|
|
2567
2554
|
// packages/agent-runtime/src/herdr-execution-primitives.ts
|
|
2568
2555
|
class HerdrHarnessError extends TaggedError("HerdrHarnessError") {
|
|
@@ -2998,6 +2985,7 @@ var srtSettings = (policy) => policy.network === "open" ? undefined : {
|
|
|
2998
2985
|
network: { allowedDomains: [...policy.network.hosts], deniedDomains: [], strictAllowlist: true },
|
|
2999
2986
|
filesystem: {
|
|
3000
2987
|
denyRead: [...policy.readDeniedPaths],
|
|
2988
|
+
allowRead: policy.readAllowedPaths.map((path) => ({ path, literal: true })),
|
|
3001
2989
|
allowWrite: [...policy.writablePaths],
|
|
3002
2990
|
denyWrite: []
|
|
3003
2991
|
}
|
|
@@ -3008,8 +2996,8 @@ var srtCacheEnvironment = (dir) => ({
|
|
|
3008
2996
|
BUN_INSTALL_CACHE_DIR: `${dir}/bun`
|
|
3009
2997
|
});
|
|
3010
2998
|
var quote = (value) => `'${value.replaceAll("'", `'\\''`)}'`;
|
|
3011
|
-
var
|
|
3012
|
-
const settings = srtSettings(
|
|
2999
|
+
var writeSrtSettings = (policy) => gen(function* () {
|
|
3000
|
+
const settings = srtSettings(policy);
|
|
3013
3001
|
if (settings === undefined)
|
|
3014
3002
|
return yield* die3(new Error("srt cannot run a Step with an open network"));
|
|
3015
3003
|
const fs = yield* FileSystem;
|
|
@@ -3017,11 +3005,24 @@ var prepareSrtPane = (input) => gen(function* () {
|
|
|
3017
3005
|
const dir = yield* fs.makeTempDirectoryScoped({ prefix: "kitman-srt-" });
|
|
3018
3006
|
const settingsFile = path.join(dir, "srt-settings.json");
|
|
3019
3007
|
yield* fs.writeFileString(settingsFile, encodeUnknownJsonStringSync(settings));
|
|
3008
|
+
return { dir, settingsFile };
|
|
3009
|
+
});
|
|
3010
|
+
var srtArgv = (srtCommand, settingsFile, argv) => [
|
|
3011
|
+
...srtCommand,
|
|
3012
|
+
"--settings",
|
|
3013
|
+
settingsFile,
|
|
3014
|
+
"--",
|
|
3015
|
+
...argv
|
|
3016
|
+
];
|
|
3017
|
+
var prepareSrtPane = (input) => gen(function* () {
|
|
3018
|
+
const fs = yield* FileSystem;
|
|
3019
|
+
const path = yield* Path;
|
|
3020
|
+
const { dir, settingsFile } = yield* writeSrtSettings(input.policy);
|
|
3020
3021
|
yield* fs.writeFileString(path.join(dir, input.binary), [
|
|
3021
3022
|
"#!/bin/sh",
|
|
3022
3023
|
`PATH=$(printf %s "$PATH" | tr ':' '\\n' | grep -vxF ${quote(dir)} | paste -sd: -)`,
|
|
3023
3024
|
"export PATH",
|
|
3024
|
-
`exec ${
|
|
3025
|
+
`exec ${srtArgv(input.srtCommand, settingsFile, [input.binary]).map(quote).join(" ")} "$@"`,
|
|
3025
3026
|
""
|
|
3026
3027
|
].join(`
|
|
3027
3028
|
`), { mode: 493 });
|
|
@@ -3062,6 +3063,16 @@ var dockerContainerRunner = map3(ChildProcessSpawner, (spawner) => {
|
|
|
3062
3063
|
input.image,
|
|
3063
3064
|
...input.command
|
|
3064
3065
|
], imagePull)),
|
|
3066
|
+
exec: (input) => runProcess2([
|
|
3067
|
+
"docker",
|
|
3068
|
+
"exec",
|
|
3069
|
+
...input.stdin === undefined ? [] : ["--interactive"],
|
|
3070
|
+
"--workdir",
|
|
3071
|
+
input.workdir,
|
|
3072
|
+
...Object.keys(input.env).flatMap((name) => ["--env", name]),
|
|
3073
|
+
input.container,
|
|
3074
|
+
...input.command
|
|
3075
|
+
], { env: input.env, timeout: input.timeout, ...input.stdin === undefined ? undefined : { stdin: input.stdin } }).pipe(mapError((error) => new ContainerError({ message: error.message })), provideService(ChildProcessSpawner, spawner)),
|
|
3065
3076
|
connect: (input) => asVoid(docker(["network", "connect", "--alias", input.alias, input.network, input.container])),
|
|
3066
3077
|
removeLabelled: ([key, value]) => gen(function* () {
|
|
3067
3078
|
const filter = ["--filter", `label=${key}=${value}`];
|
|
@@ -3076,7 +3087,7 @@ var dockerContainerRunner = map3(ChildProcessSpawner, (spawner) => {
|
|
|
3076
3087
|
});
|
|
3077
3088
|
var quote2 = (value) => `'${value.replaceAll("'", `'\\''`)}'`;
|
|
3078
3089
|
var dockerName = (id) => id.replaceAll(/[^a-zA-Z0-9_.-]/g, "-");
|
|
3079
|
-
var
|
|
3090
|
+
var startDockerSandbox = (input) => gen(function* () {
|
|
3080
3091
|
const { containers } = input.docker;
|
|
3081
3092
|
const fs = yield* FileSystem;
|
|
3082
3093
|
const path = yield* Path;
|
|
@@ -3113,7 +3124,10 @@ var prepareDockerPane = (input) => gen(function* () {
|
|
|
3113
3124
|
labels,
|
|
3114
3125
|
...network === undefined ? undefined : { network },
|
|
3115
3126
|
...input.docker.user === undefined ? undefined : { user: input.docker.user },
|
|
3116
|
-
mounts:
|
|
3127
|
+
mounts: [
|
|
3128
|
+
...input.policy.writablePaths.map((writable) => ({ source: writable, target: writable })),
|
|
3129
|
+
...(input.readOnlyPaths ?? []).map((readable) => ({ source: readable, target: readable, readOnly: true }))
|
|
3130
|
+
],
|
|
3117
3131
|
workdir: input.workspace,
|
|
3118
3132
|
env: {
|
|
3119
3133
|
HOME: path.join(input.configDir, "home"),
|
|
@@ -3130,6 +3144,12 @@ var prepareDockerPane = (input) => gen(function* () {
|
|
|
3130
3144
|
command: ["sleep", "infinity"]
|
|
3131
3145
|
});
|
|
3132
3146
|
yield* fs.makeDirectory(path.join(input.configDir, "home"), { recursive: true });
|
|
3147
|
+
return { container: agent };
|
|
3148
|
+
});
|
|
3149
|
+
var prepareDockerPane = (input) => gen(function* () {
|
|
3150
|
+
const fs = yield* FileSystem;
|
|
3151
|
+
const path = yield* Path;
|
|
3152
|
+
const { container: agent } = yield* startDockerSandbox(input);
|
|
3133
3153
|
const dir = yield* fs.makeTempDirectoryScoped({ prefix: "kitman-docker-" });
|
|
3134
3154
|
const shell = path.join(dir, "shell");
|
|
3135
3155
|
const forwarded = ["TERM", ...Object.keys(input.policy.environment)].flatMap((name) => ["-e", name]);
|
|
@@ -3161,6 +3181,7 @@ var stepSandboxPolicy = (input) => ({
|
|
|
3161
3181
|
...input.policy.readDeniedPaths,
|
|
3162
3182
|
...HarnessAdapters.filter((other) => other.id !== input.adapter.id).flatMap((other) => other.auth)
|
|
3163
3183
|
],
|
|
3184
|
+
readAllowedPaths: [...input.policy.readAllowedPaths, input.workspace, input.configDir],
|
|
3164
3185
|
environment: { ...input.policy.environment, ...input.environment }
|
|
3165
3186
|
});
|
|
3166
3187
|
var executeHerdrStepAttempt = (input) => gen(function* () {
|
|
@@ -3322,7 +3343,7 @@ var classifyFailure = (error) => {
|
|
|
3322
3343
|
class AgentBackendRefusal extends TaggedError("AgentBackendRefusal") {
|
|
3323
3344
|
}
|
|
3324
3345
|
|
|
3325
|
-
class AgentBackend extends
|
|
3346
|
+
class AgentBackend extends Service()("AgentBackend") {
|
|
3326
3347
|
}
|
|
3327
3348
|
var herdrSandboxBackends = ["host"];
|
|
3328
3349
|
var refuseAgentRequest = (request, enforceable) => {
|
|
@@ -3444,183 +3465,340 @@ var probeSandboxHost = (probe, platform = process.platform, options = {}) => gen
|
|
|
3444
3465
|
};
|
|
3445
3466
|
});
|
|
3446
3467
|
var commandHostProbe = map3(ChildProcessSpawner, (spawner) => (command, args) => runCommand2(command, args, { timeout: "10 seconds" }).pipe(as(true), orElseSucceed(() => false), provideService(ChildProcessSpawner, spawner)));
|
|
3447
|
-
// packages/agent-runtime/src/
|
|
3448
|
-
var
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
}
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
kind: "step_attempt",
|
|
3461
|
-
attempt: {
|
|
3462
|
-
id: work.id,
|
|
3463
|
-
workspaceId: "",
|
|
3464
|
-
...work.projectId === undefined ? undefined : { projectId: work.projectId },
|
|
3465
|
-
runId: work.runId,
|
|
3466
|
-
taskId: work.runId,
|
|
3467
|
-
stepKey: work.stepKey,
|
|
3468
|
-
sequence: 0,
|
|
3469
|
-
required: true,
|
|
3470
|
-
attempt: work.attempt,
|
|
3471
|
-
status: "running",
|
|
3472
|
-
inputManifest: { manifestVersion: 1, assembledAt: work.lease.lastHeartbeatAt, entries: [] },
|
|
3473
|
-
execution: { metadata: {} },
|
|
3474
|
-
reviewEvidence: [],
|
|
3475
|
-
lease: {
|
|
3476
|
-
ownerId: work.lease.leaseOwnerId,
|
|
3477
|
-
runnerReplicaId: work.lease.runnerReplicaId,
|
|
3478
|
-
leaseId: work.lease.leaseId,
|
|
3479
|
-
fencingToken: work.lease.fencingToken,
|
|
3480
|
-
capacitySlot: work.lease.capacitySlot,
|
|
3481
|
-
expiresAt: work.lease.leaseExpiresAt,
|
|
3482
|
-
lastHeartbeatAt: work.lease.lastHeartbeatAt
|
|
3483
|
-
},
|
|
3484
|
-
createdAt: work.lease.lastHeartbeatAt,
|
|
3485
|
-
updatedAt: work.lease.lastHeartbeatAt
|
|
3486
|
-
},
|
|
3487
|
-
step: {
|
|
3488
|
-
title: work.stepKey,
|
|
3489
|
-
implementation: { kind: "agent", taskIdRef: work.runId, agentId: work.id, runtimeKind: "herdr" },
|
|
3490
|
-
inputSchemaRef: { kind: "typebox_ref", name: "WorkUnitInput" },
|
|
3491
|
-
outputSchemaRef: { kind: "typebox_ref", name: "WorkUnitOutput" },
|
|
3492
|
-
allowedCapabilities: [],
|
|
3493
|
-
retryPolicy: { maxAttempts: 1, backoff: "none" },
|
|
3494
|
-
timeoutPolicy: { timeoutSeconds: 1800 },
|
|
3495
|
-
metadata: {}
|
|
3496
|
-
}
|
|
3497
|
-
};
|
|
3498
|
-
}
|
|
3499
|
-
// packages/agent-runtime/src/materialization-plan.ts
|
|
3500
|
-
class AgentEnvironmentPlanApplyError extends TaggedError("AgentEnvironmentPlanApplyError") {
|
|
3501
|
-
get message() {
|
|
3502
|
-
return `AgentEnvironment plan apply failed during ${this.phase}: ${this.cause.message}`;
|
|
3468
|
+
// packages/agent-runtime/src/sandbox-command.ts
|
|
3469
|
+
var runSandboxCommand = (input) => scoped(gen(function* () {
|
|
3470
|
+
const { command } = input;
|
|
3471
|
+
const env = { ...input.policy.environment, ...command.env };
|
|
3472
|
+
if (input.backend === "srt") {
|
|
3473
|
+
const { settingsFile } = yield* writeSrtSettings(input.policy);
|
|
3474
|
+
return yield* runProcess2(srtArgv(input.srtCommand ?? pinnedSrtCommand(), settingsFile, command.argv), {
|
|
3475
|
+
cwd: command.cwd,
|
|
3476
|
+
env,
|
|
3477
|
+
timeout: command.timeout,
|
|
3478
|
+
...command.extendEnv === undefined ? undefined : { extendEnv: command.extendEnv },
|
|
3479
|
+
...command.stdin === undefined ? undefined : { stdin: command.stdin }
|
|
3480
|
+
});
|
|
3503
3481
|
}
|
|
3504
|
-
}
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
...input.
|
|
3510
|
-
|
|
3511
|
-
|
|
3482
|
+
const configDir = yield* (yield* FileSystem).makeTempDirectoryScoped({ prefix: "kitman-sandbox-" });
|
|
3483
|
+
const { container } = yield* startDockerSandbox({
|
|
3484
|
+
docker: input.docker,
|
|
3485
|
+
runnerId: input.runnerId,
|
|
3486
|
+
attemptId: input.id,
|
|
3487
|
+
policy: { ...input.policy, writablePaths: [...input.policy.writablePaths, configDir] },
|
|
3488
|
+
workspace: command.cwd,
|
|
3489
|
+
configDir,
|
|
3490
|
+
...input.readOnlyPaths === undefined ? undefined : { readOnlyPaths: input.readOnlyPaths }
|
|
3512
3491
|
});
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
...
|
|
3492
|
+
return yield* input.docker.containers.exec({
|
|
3493
|
+
container,
|
|
3494
|
+
workdir: command.cwd,
|
|
3495
|
+
env,
|
|
3496
|
+
command: command.argv,
|
|
3497
|
+
timeout: command.timeout,
|
|
3498
|
+
...command.stdin === undefined ? undefined : { stdin: command.stdin }
|
|
3520
3499
|
});
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3500
|
+
}));
|
|
3501
|
+
// packages/oversight/src/domain/intent.ts
|
|
3502
|
+
var ConstraintKind = Literals(["rule", "semantic"]);
|
|
3503
|
+
var ConstraintSeverity = Literals(["block", "warn"]);
|
|
3504
|
+
var ConstraintSource = Literals(["launch", "repository", "plan", "parent", "human"]);
|
|
3505
|
+
var ProtectedPathsRule = Struct({
|
|
3506
|
+
kind: Literal("protected_paths"),
|
|
3507
|
+
globs: ArraySchema(String2)
|
|
3529
3508
|
});
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
3537
|
-
yield* applyAgentEnvironmentConfigSync(target.harnessConfig).pipe(mapError((cause) => new AgentEnvironmentPlanApplyError({ phase: "harness_config", cause })));
|
|
3538
|
-
return plan;
|
|
3509
|
+
var Constraint = Struct({
|
|
3510
|
+
id: String2,
|
|
3511
|
+
text: String2,
|
|
3512
|
+
kind: ConstraintKind,
|
|
3513
|
+
severity: ConstraintSeverity,
|
|
3514
|
+
source: ConstraintSource,
|
|
3515
|
+
rule: optionalKey(ProtectedPathsRule)
|
|
3539
3516
|
});
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
},
|
|
3551
|
-
_tag: "TypeMatcher",
|
|
3552
|
-
add(_case) {
|
|
3553
|
-
return makeTypeMatcher(this.select, [...this.cases, _case]);
|
|
3554
|
-
},
|
|
3555
|
-
pipe() {
|
|
3556
|
-
return pipeArguments(this, arguments);
|
|
3557
|
-
}
|
|
3558
|
-
};
|
|
3559
|
-
function makeTypeMatcher(select, cases) {
|
|
3560
|
-
const matcher = Object.create(TypeMatcherProto);
|
|
3561
|
-
matcher.select = select;
|
|
3562
|
-
matcher.cases = cases;
|
|
3563
|
-
return matcher;
|
|
3517
|
+
var Intent = Struct({
|
|
3518
|
+
version: Int,
|
|
3519
|
+
goal: String2,
|
|
3520
|
+
doneWhen: ArraySchema(String2),
|
|
3521
|
+
constraints: ArraySchema(Constraint),
|
|
3522
|
+
corrections: Boolean2,
|
|
3523
|
+
removedConstraintIds: ArraySchema(String2)
|
|
3524
|
+
});
|
|
3525
|
+
|
|
3526
|
+
class ConstraintSpellingInvalid extends TaggedError2()("ConstraintSpellingInvalid", { message: String2 }) {
|
|
3564
3527
|
}
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
_result: identity,
|
|
3570
|
-
_return: identity,
|
|
3571
|
-
_flavor: identity
|
|
3572
|
-
},
|
|
3573
|
-
_tag: "ValueMatcher",
|
|
3574
|
-
add(_case) {
|
|
3575
|
-
if (isSuccess(this.value)) {
|
|
3576
|
-
return this;
|
|
3577
|
-
}
|
|
3578
|
-
if (_case._tag === "When" && _case.guard(this.provided) === true) {
|
|
3579
|
-
return makeValueMatcher(this.provided, succeed(_case.evaluate(this.provided)));
|
|
3580
|
-
} else if (_case._tag === "Not" && _case.guard(this.provided) === false) {
|
|
3581
|
-
return makeValueMatcher(this.provided, succeed(_case.evaluate(this.provided)));
|
|
3582
|
-
}
|
|
3583
|
-
return this;
|
|
3584
|
-
},
|
|
3585
|
-
pipe() {
|
|
3586
|
-
return pipeArguments(this, arguments);
|
|
3587
|
-
}
|
|
3588
|
-
};
|
|
3589
|
-
function makeValueMatcher(provided, value) {
|
|
3590
|
-
const matcher = Object.create(ValueMatcherProto);
|
|
3591
|
-
matcher.provided = provided;
|
|
3592
|
-
matcher.value = value;
|
|
3593
|
-
return matcher;
|
|
3528
|
+
|
|
3529
|
+
class ConstraintNotFound extends TaggedError2()("ConstraintNotFound", {
|
|
3530
|
+
message: String2
|
|
3531
|
+
}) {
|
|
3594
3532
|
}
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3533
|
+
// packages/oversight/src/domain/drift.ts
|
|
3534
|
+
var EvidenceLimits = { files: 20, linesPerFile: 200, changedPaths: 1000, lineLength: 1000 };
|
|
3535
|
+
var outputLines = EvidenceLimits.files * EvidenceLimits.linesPerFile;
|
|
3536
|
+
var EvidenceFile = Struct({
|
|
3537
|
+
path: String2,
|
|
3538
|
+
excerpt: String2,
|
|
3539
|
+
redacted: Boolean2,
|
|
3540
|
+
truncated: Boolean2
|
|
3599
3541
|
});
|
|
3600
|
-
var
|
|
3601
|
-
|
|
3602
|
-
|
|
3542
|
+
var ChangeEvidence = Struct({
|
|
3543
|
+
kind: Literal("change"),
|
|
3544
|
+
changedPaths: ArraySchema(String2),
|
|
3545
|
+
omittedPaths: Int,
|
|
3546
|
+
files: ArraySchema(EvidenceFile),
|
|
3547
|
+
truncated: Boolean2
|
|
3603
3548
|
});
|
|
3604
|
-
var
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3549
|
+
var OutputEvidence = Struct({
|
|
3550
|
+
kind: Literal("output"),
|
|
3551
|
+
text: String2,
|
|
3552
|
+
truncated: Boolean2
|
|
3553
|
+
});
|
|
3554
|
+
var Evidence = Union([ChangeEvidence, OutputEvidence]);
|
|
3555
|
+
var globParts = new Map([
|
|
3556
|
+
["**/", "(?:.*/)?"],
|
|
3557
|
+
["**", ".*"],
|
|
3558
|
+
["*", "[^/]*"],
|
|
3559
|
+
["?", "[^/]"]
|
|
3560
|
+
]);
|
|
3561
|
+
var secretName = /^\.env(\..*)?$|^\.?credentials(\..*)?$|^\.(netrc|npmrc|pgpass)$|\.(pem|key|p12|pfx|jks|keystore)$|^id_(rsa|dsa|ecdsa|ed25519)|secret/i;
|
|
3562
|
+
var looksSecret = (path) => secretName.test(path.split("/").at(-1) ?? path);
|
|
3563
|
+
var capLines = (text, limit) => {
|
|
3564
|
+
const lines = text.split(`
|
|
3565
|
+
`);
|
|
3566
|
+
const capped = lines.slice(0, limit).map((line) => line.length > EvidenceLimits.lineLength ? line.slice(0, EvidenceLimits.lineLength) : line);
|
|
3567
|
+
return {
|
|
3568
|
+
text: capped.join(`
|
|
3569
|
+
`),
|
|
3570
|
+
truncated: lines.length > limit || lines.some((line) => line.length > EvidenceLimits.lineLength)
|
|
3571
|
+
};
|
|
3611
3572
|
};
|
|
3612
|
-
var
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3618
|
-
|
|
3619
|
-
const
|
|
3620
|
-
return
|
|
3621
|
-
|
|
3622
|
-
|
|
3623
|
-
|
|
3573
|
+
var boundChange = (change) => {
|
|
3574
|
+
const changedPaths = change.changedPaths.slice(0, EvidenceLimits.changedPaths);
|
|
3575
|
+
const omittedPaths = (change.omittedPaths ?? 0) + change.changedPaths.length - changedPaths.length;
|
|
3576
|
+
const files = changedPaths.slice(0, EvidenceLimits.files).map((path) => {
|
|
3577
|
+
if (looksSecret(path))
|
|
3578
|
+
return { path, excerpt: "", redacted: true, truncated: false };
|
|
3579
|
+
const given = change.files.find((file) => file.path === path);
|
|
3580
|
+
const capped = capLines(given?.diff ?? "", EvidenceLimits.linesPerFile);
|
|
3581
|
+
return { path, excerpt: capped.text, redacted: false, truncated: capped.truncated || given?.truncated === true };
|
|
3582
|
+
});
|
|
3583
|
+
return {
|
|
3584
|
+
kind: "change",
|
|
3585
|
+
changedPaths,
|
|
3586
|
+
omittedPaths,
|
|
3587
|
+
files,
|
|
3588
|
+
truncated: omittedPaths > 0 || changedPaths.length > files.length || files.some((file) => file.truncated)
|
|
3589
|
+
};
|
|
3590
|
+
};
|
|
3591
|
+
var DriftStatus = Literals(["open", "correction_sent", "escalated", "verified", "dismissed"]);
|
|
3592
|
+
var DriftActor = Struct({ actorType: String2, actorId: String2 });
|
|
3593
|
+
var DriftResolution = Struct({
|
|
3594
|
+
status: DriftStatus,
|
|
3595
|
+
intentVersion: Int,
|
|
3596
|
+
at: Date2,
|
|
3597
|
+
reason: optionalKey(String2),
|
|
3598
|
+
actor: optionalKey(DriftActor)
|
|
3599
|
+
});
|
|
3600
|
+
var DriftReport = Struct({
|
|
3601
|
+
constraintId: String2,
|
|
3602
|
+
constraintText: String2,
|
|
3603
|
+
kind: ConstraintKind,
|
|
3604
|
+
severity: ConstraintSeverity,
|
|
3605
|
+
intentVersion: Int,
|
|
3606
|
+
citedPaths: ArraySchema(String2),
|
|
3607
|
+
truncated: Boolean2,
|
|
3608
|
+
status: DriftStatus,
|
|
3609
|
+
history: ArraySchema(DriftResolution)
|
|
3610
|
+
});
|
|
3611
|
+
|
|
3612
|
+
class DriftReportNotOpen extends TaggedError2()("DriftReportNotOpen", {
|
|
3613
|
+
message: String2
|
|
3614
|
+
}) {
|
|
3615
|
+
}
|
|
3616
|
+
// packages/oversight/src/domain/judgement.ts
|
|
3617
|
+
var ConstraintVerdict = Literals(["holds", "breached", "unverified"]);
|
|
3618
|
+
var OutcomeVerdict = Literals(["met", "not_met", "unverified"]);
|
|
3619
|
+
var Citation = Struct({ path: String2, line: optionalKey(Int) });
|
|
3620
|
+
var JudgeOutput = Struct({
|
|
3621
|
+
constraints: ArraySchema(Struct({ id: String2, verdict: ConstraintVerdict, citations: ArraySchema(Citation) })),
|
|
3622
|
+
goal: optionalKey(OutcomeVerdict),
|
|
3623
|
+
doneWhen: optionalKey(ArraySchema(Struct({ item: Int, verdict: OutcomeVerdict })))
|
|
3624
|
+
});
|
|
3625
|
+
var JudgementReading = Struct({
|
|
3626
|
+
constraints: ArraySchema(Struct({ constraintId: String2, verdict: ConstraintVerdict, citations: ArraySchema(Citation) })),
|
|
3627
|
+
goal: optionalKey(OutcomeVerdict),
|
|
3628
|
+
doneWhen: optionalKey(ArraySchema(OutcomeVerdict))
|
|
3629
|
+
});
|
|
3630
|
+
var verdictEnum = (values) => ({ type: "string", enum: values });
|
|
3631
|
+
var closedObject = (properties, required) => ({
|
|
3632
|
+
type: "object",
|
|
3633
|
+
additionalProperties: false,
|
|
3634
|
+
required,
|
|
3635
|
+
properties
|
|
3636
|
+
});
|
|
3637
|
+
var constraintsSchema = {
|
|
3638
|
+
type: "array",
|
|
3639
|
+
items: closedObject({
|
|
3640
|
+
id: { type: "string" },
|
|
3641
|
+
verdict: verdictEnum(ConstraintVerdict.literals),
|
|
3642
|
+
citations: {
|
|
3643
|
+
type: "array",
|
|
3644
|
+
items: closedObject({ path: { type: "string" }, line: { type: "integer", minimum: 1 } }, ["path"])
|
|
3645
|
+
}
|
|
3646
|
+
}, ["id", "verdict", "citations"])
|
|
3647
|
+
};
|
|
3648
|
+
// packages/oversight/src/domain/alignment.ts
|
|
3649
|
+
var AlignmentVerdict = Literals(["aligned", "not_aligned", "unverified"]);
|
|
3650
|
+
var Alignment = Struct({
|
|
3651
|
+
verdict: AlignmentVerdict,
|
|
3652
|
+
reasons: ArraySchema(String2),
|
|
3653
|
+
intentVersion: Int,
|
|
3654
|
+
judgedAt: Date2
|
|
3655
|
+
});
|
|
3656
|
+
// packages/agent-runtime/src/agent-step-executor.ts
|
|
3657
|
+
import { homedir } from "os";
|
|
3658
|
+
|
|
3659
|
+
// packages/agent-runtime/src/harness-sessions.ts
|
|
3660
|
+
import { gunzipSync, gzipSync } from "zlib";
|
|
3661
|
+
var projectDirectory = (worktree) => worktree.replace(/[^a-zA-Z0-9]/g, "-");
|
|
3662
|
+
var rolloutId = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/;
|
|
3663
|
+
var filesUnder = (directory) => gen(function* () {
|
|
3664
|
+
const fs = yield* FileSystem;
|
|
3665
|
+
if (!(yield* fs.exists(directory)))
|
|
3666
|
+
return [];
|
|
3667
|
+
return (yield* fs.readDirectory(directory, { recursive: true })).map((file) => `${directory}/${file}`);
|
|
3668
|
+
});
|
|
3669
|
+
var rolloutDirectory = (path) => gen(function* () {
|
|
3670
|
+
const fs = yield* FileSystem;
|
|
3671
|
+
const firstLine = (yield* fs.readFileString(path)).split(`
|
|
3672
|
+
`, 1)[0] ?? "";
|
|
3673
|
+
const line = getOrUndefined(decodeJsonStringOption(firstLine));
|
|
3674
|
+
const payload = isJsonObject(line) ? line.payload : undefined;
|
|
3675
|
+
return isJsonObject(payload) && isString2(payload.cwd) ? payload.cwd : undefined;
|
|
3676
|
+
});
|
|
3677
|
+
var findSession = (adapter, place) => gen(function* () {
|
|
3678
|
+
const location = adapter.session?.location;
|
|
3679
|
+
if (location === undefined)
|
|
3680
|
+
return;
|
|
3681
|
+
const root = `${place.home}/${location.root}`;
|
|
3682
|
+
if (location.layout === "per_directory") {
|
|
3683
|
+
if (place.id === undefined)
|
|
3684
|
+
return;
|
|
3685
|
+
const name = `${place.id}.jsonl`;
|
|
3686
|
+
const own = `${root}/${projectDirectory(place.worktree)}/${name}`;
|
|
3687
|
+
const fs = yield* FileSystem;
|
|
3688
|
+
const path = (yield* fs.exists(own)) ? own : (yield* filesUnder(root)).find((file) => file.endsWith(`/${name}`));
|
|
3689
|
+
return path === undefined ? undefined : { id: place.id, name, path };
|
|
3690
|
+
}
|
|
3691
|
+
for (const path of (yield* filesUnder(root)).filter((file) => rolloutId.test(file)).sort().reverse()) {
|
|
3692
|
+
const name = path.slice(path.lastIndexOf("/") + 1);
|
|
3693
|
+
const id = rolloutId.exec(name)?.[1];
|
|
3694
|
+
if (id === undefined)
|
|
3695
|
+
continue;
|
|
3696
|
+
if (place.id === undefined ? (yield* rolloutDirectory(path)) === place.worktree : id === place.id)
|
|
3697
|
+
return { id, name, path };
|
|
3698
|
+
}
|
|
3699
|
+
return;
|
|
3700
|
+
}).pipe(orElseSucceed(() => {
|
|
3701
|
+
return;
|
|
3702
|
+
}));
|
|
3703
|
+
var packSession = (path) => map3(flatMap(FileSystem, (fs) => fs.readFile(path)), (content) => new Uint8Array(gzipSync(content)));
|
|
3704
|
+
var restoreSession = (adapter, place) => gen(function* () {
|
|
3705
|
+
const fs = yield* FileSystem;
|
|
3706
|
+
const location = adapter.session?.location;
|
|
3707
|
+
if (location === undefined)
|
|
3708
|
+
return yield* die3(`${adapter.id} keeps no session to restore`);
|
|
3709
|
+
const root = `${place.home}/${location.root}`;
|
|
3710
|
+
const today = toDate(wallClockMillis()).toISOString().slice(0, 10).replaceAll("-", "/");
|
|
3711
|
+
const directory = location.layout === "per_directory" ? `${root}/${projectDirectory(place.worktree)}` : `${root}/${today}`;
|
|
3712
|
+
const path = `${directory}/${place.session.name}`;
|
|
3713
|
+
yield* fs.makeDirectory(directory, { recursive: true });
|
|
3714
|
+
yield* fs.writeFile(path, new Uint8Array(gunzipSync(place.session.content)));
|
|
3715
|
+
return { id: place.session.id, name: place.session.name, path };
|
|
3716
|
+
});
|
|
3717
|
+
|
|
3718
|
+
// node_modules/.bun/effect@4.0.4/node_modules/effect/dist/internal/matcher.js
|
|
3719
|
+
var TypeId = "~effect/Match/Matcher";
|
|
3720
|
+
var TypeMatcherProto = {
|
|
3721
|
+
[TypeId]: {
|
|
3722
|
+
_input: identity,
|
|
3723
|
+
_filters: identity,
|
|
3724
|
+
_remaining: identity,
|
|
3725
|
+
_result: identity,
|
|
3726
|
+
_return: identity,
|
|
3727
|
+
_args: identity
|
|
3728
|
+
},
|
|
3729
|
+
_tag: "TypeMatcher",
|
|
3730
|
+
add(_case) {
|
|
3731
|
+
return makeTypeMatcher(this.select, [...this.cases, _case]);
|
|
3732
|
+
},
|
|
3733
|
+
pipe() {
|
|
3734
|
+
return pipeArguments(this, arguments);
|
|
3735
|
+
}
|
|
3736
|
+
};
|
|
3737
|
+
function makeTypeMatcher(select, cases) {
|
|
3738
|
+
const matcher = Object.create(TypeMatcherProto);
|
|
3739
|
+
matcher.select = select;
|
|
3740
|
+
matcher.cases = cases;
|
|
3741
|
+
return matcher;
|
|
3742
|
+
}
|
|
3743
|
+
var ValueMatcherProto = {
|
|
3744
|
+
[TypeId]: {
|
|
3745
|
+
_input: identity,
|
|
3746
|
+
_filters: identity,
|
|
3747
|
+
_result: identity,
|
|
3748
|
+
_return: identity,
|
|
3749
|
+
_flavor: identity
|
|
3750
|
+
},
|
|
3751
|
+
_tag: "ValueMatcher",
|
|
3752
|
+
add(_case) {
|
|
3753
|
+
if (isSuccess(this.value)) {
|
|
3754
|
+
return this;
|
|
3755
|
+
}
|
|
3756
|
+
if (_case._tag === "When" && _case.guard(this.provided) === true) {
|
|
3757
|
+
return makeValueMatcher(this.provided, succeed(_case.evaluate(this.provided)));
|
|
3758
|
+
} else if (_case._tag === "Not" && _case.guard(this.provided) === false) {
|
|
3759
|
+
return makeValueMatcher(this.provided, succeed(_case.evaluate(this.provided)));
|
|
3760
|
+
}
|
|
3761
|
+
return this;
|
|
3762
|
+
},
|
|
3763
|
+
pipe() {
|
|
3764
|
+
return pipeArguments(this, arguments);
|
|
3765
|
+
}
|
|
3766
|
+
};
|
|
3767
|
+
function makeValueMatcher(provided, value) {
|
|
3768
|
+
const matcher = Object.create(ValueMatcherProto);
|
|
3769
|
+
matcher.provided = provided;
|
|
3770
|
+
matcher.value = value;
|
|
3771
|
+
return matcher;
|
|
3772
|
+
}
|
|
3773
|
+
var makeWhen = (guard, evaluate) => ({
|
|
3774
|
+
_tag: "When",
|
|
3775
|
+
guard,
|
|
3776
|
+
evaluate
|
|
3777
|
+
});
|
|
3778
|
+
var valueTags = /* @__PURE__ */ dual(2, (input, fields) => {
|
|
3779
|
+
const match = tagsExhaustive(fields)(makeTypeMatcher(identity, []));
|
|
3780
|
+
return match(input);
|
|
3781
|
+
});
|
|
3782
|
+
var discriminators = (field) => (fields) => {
|
|
3783
|
+
const predicate = makeWhen((arg) => arg != null && Object.hasOwn(fields, arg[field]), (data) => fields[data[field]](data));
|
|
3784
|
+
return (self) => self.add(predicate);
|
|
3785
|
+
};
|
|
3786
|
+
var discriminatorsExhaustive = (field) => (fields) => {
|
|
3787
|
+
const addCases = discriminators(field)(fields);
|
|
3788
|
+
return (matcher) => exhaustive(addCases(matcher));
|
|
3789
|
+
};
|
|
3790
|
+
var tagsExhaustive = /* @__PURE__ */ discriminatorsExhaustive("_tag");
|
|
3791
|
+
var result2 = (self) => {
|
|
3792
|
+
if (self._tag === "ValueMatcher") {
|
|
3793
|
+
return self.value;
|
|
3794
|
+
}
|
|
3795
|
+
const len = self.cases.length;
|
|
3796
|
+
if (len === 1) {
|
|
3797
|
+
const _case = self.cases[0];
|
|
3798
|
+
return (...args) => {
|
|
3799
|
+
const input = self.select(...args);
|
|
3800
|
+
if (_case._tag === "When" && _case.guard(input) === true) {
|
|
3801
|
+
return succeed(_case.evaluate(input, ...args));
|
|
3624
3802
|
} else if (_case._tag === "Not" && _case.guard(input) === false) {
|
|
3625
3803
|
return succeed(_case.evaluate(input, ...args));
|
|
3626
3804
|
}
|
|
@@ -3687,7 +3865,7 @@ class RunnerReplicaCancellation extends TaggedError("RunnerReplicaCancellation")
|
|
|
3687
3865
|
}
|
|
3688
3866
|
var makeReplicaSignals = sync(() => {
|
|
3689
3867
|
let generation = 0;
|
|
3690
|
-
let nextWork =
|
|
3868
|
+
let nextWork = makeUnsafe();
|
|
3691
3869
|
const stops = new Map;
|
|
3692
3870
|
const mailboxes = new Map;
|
|
3693
3871
|
const mailboxFor = (workUnitId) => {
|
|
@@ -3697,8 +3875,8 @@ var makeReplicaSignals = sync(() => {
|
|
|
3697
3875
|
const created = {
|
|
3698
3876
|
notes: [],
|
|
3699
3877
|
seen: new Set,
|
|
3700
|
-
arrived:
|
|
3701
|
-
updated:
|
|
3878
|
+
arrived: makeUnsafe(),
|
|
3879
|
+
updated: makeUnsafe()
|
|
3702
3880
|
};
|
|
3703
3881
|
mailboxes.set(workUnitId, created);
|
|
3704
3882
|
return created;
|
|
@@ -3709,14 +3887,14 @@ var makeReplicaSignals = sync(() => {
|
|
|
3709
3887
|
if (note !== undefined)
|
|
3710
3888
|
return succeed5(note);
|
|
3711
3889
|
if (isDoneUnsafe(mailbox.arrived))
|
|
3712
|
-
mailbox.arrived =
|
|
3890
|
+
mailbox.arrived = makeUnsafe();
|
|
3713
3891
|
return andThen(_await(mailbox.arrived), nextSteer(workUnitId));
|
|
3714
3892
|
});
|
|
3715
3893
|
const stopFor = (workUnitId) => {
|
|
3716
3894
|
const existing = stops.get(workUnitId);
|
|
3717
3895
|
if (existing !== undefined)
|
|
3718
3896
|
return existing;
|
|
3719
|
-
const created =
|
|
3897
|
+
const created = makeUnsafe();
|
|
3720
3898
|
stops.set(workUnitId, created);
|
|
3721
3899
|
return created;
|
|
3722
3900
|
};
|
|
@@ -3728,7 +3906,7 @@ var makeReplicaSignals = sync(() => {
|
|
|
3728
3906
|
WorkAvailable: () => {
|
|
3729
3907
|
generation += 1;
|
|
3730
3908
|
const signalled = nextWork;
|
|
3731
|
-
nextWork =
|
|
3909
|
+
nextWork = makeUnsafe();
|
|
3732
3910
|
doneUnsafe(signalled, void_);
|
|
3733
3911
|
},
|
|
3734
3912
|
LeaseRevoked: ({ workUnitId }) => stop(workUnitId, "lost"),
|
|
@@ -3758,7 +3936,7 @@ var makeReplicaSignals = sync(() => {
|
|
|
3758
3936
|
sessionUpdated: (workUnitId) => suspend(() => {
|
|
3759
3937
|
const mailbox = mailboxFor(workUnitId);
|
|
3760
3938
|
return andThen(_await(mailbox.updated), sync(() => {
|
|
3761
|
-
mailbox.updated =
|
|
3939
|
+
mailbox.updated = makeUnsafe();
|
|
3762
3940
|
}));
|
|
3763
3941
|
}),
|
|
3764
3942
|
forget: (workUnitId) => sync(() => {
|
|
@@ -3822,7 +4000,7 @@ function runReplica(control, executor, signals) {
|
|
|
3822
4000
|
var idleBackoff = (idleIterations) => millis(Math.min(1000 * 2 ** idleIterations, 30000));
|
|
3823
4001
|
function superviseReplica(input) {
|
|
3824
4002
|
const { signals } = input;
|
|
3825
|
-
const claimTurn =
|
|
4003
|
+
const claimTurn = makeUnsafe4(1);
|
|
3826
4004
|
let emptyAt = -1;
|
|
3827
4005
|
const wokenControl = (control, signals) => ({
|
|
3828
4006
|
...control,
|
|
@@ -3854,382 +4032,35 @@ function superviseReplica(input) {
|
|
|
3854
4032
|
continue;
|
|
3855
4033
|
}
|
|
3856
4034
|
if (isFailure2(exit2)) {
|
|
3857
|
-
const error = findErrorOption(exit2.cause);
|
|
3858
|
-
if (isSome(error) && error.value instanceof RunnerReplicaError && error.value.kind === "unauthorized")
|
|
3859
|
-
return yield* error.value;
|
|
3860
|
-
yield* logError("runner_slot_recoverable_error", capacitySlot, pretty(exit2.cause));
|
|
3861
|
-
}
|
|
3862
|
-
yield* sleep(idleBackoff(idleIterations++));
|
|
3863
|
-
}
|
|
3864
|
-
});
|
|
3865
|
-
const heartbeat = input.control(input.slots[0] ?? "slot-1").heartbeatReplica;
|
|
3866
|
-
const replicaHeartbeat = gen(function* () {
|
|
3867
|
-
while (true) {
|
|
3868
|
-
const exit2 = yield* exit(retryTransient(heartbeatCall(heartbeat)));
|
|
3869
|
-
if (isFailure2(exit2)) {
|
|
3870
|
-
const error = findErrorOption(exit2.cause);
|
|
3871
|
-
if (isSome(error) && error.value.kind === "unauthorized")
|
|
3872
|
-
return yield* error.value;
|
|
3873
|
-
yield* logError("runner_replica_heartbeat_failed", pretty(exit2.cause));
|
|
3874
|
-
}
|
|
3875
|
-
yield* sleep(ReplicaHeartbeatInterval);
|
|
3876
|
-
}
|
|
3877
|
-
});
|
|
3878
|
-
return all([replicaHeartbeat, forEach(input.slots, runSlot, { concurrency: "unbounded", discard: true })], {
|
|
3879
|
-
concurrency: "unbounded",
|
|
3880
|
-
discard: true
|
|
3881
|
-
}).pipe(andThen(never));
|
|
3882
|
-
}
|
|
3883
|
-
var ReplicaHeartbeatInterval = seconds(10);
|
|
3884
|
-
var ReplicaHeartbeatTimeout = seconds(15);
|
|
3885
|
-
var heartbeatCall = (heartbeat) => suspend(heartbeat).pipe(timeout(ReplicaHeartbeatTimeout), mapError((cause) => new RunnerReplicaError({ operation: "heartbeatReplica", kind: controlFailureKind(cause), cause })));
|
|
3886
|
-
// packages/agent-runtime/src/herdr-executor-surface.ts
|
|
3887
|
-
class HerdrExecutorSurfaceError extends TaggedError("HerdrExecutorSurfaceError") {
|
|
3888
|
-
}
|
|
3889
|
-
function herdrExecutorSurface(input) {
|
|
3890
|
-
const supervisor = input.supervisor ?? new HerdrServerSupervisor({
|
|
3891
|
-
runnerId: input.runnerId,
|
|
3892
|
-
...input.session === undefined ? undefined : { session: input.session }
|
|
3893
|
-
});
|
|
3894
|
-
const createdWorkspaces = new Set;
|
|
3895
|
-
const createdTabs = new Map;
|
|
3896
|
-
const record = (method, response) => sync(() => {
|
|
3897
|
-
const workspaceId = nestedString(response, ["workspace", "workspace_id"]);
|
|
3898
|
-
const tabId = nestedString(response, ["tab", "tab_id"]);
|
|
3899
|
-
const tabWorkspaceId = nestedString(response, ["tab", "workspace_id"]);
|
|
3900
|
-
if (method === "workspace.create" && workspaceId !== undefined)
|
|
3901
|
-
createdWorkspaces.add(workspaceId);
|
|
3902
|
-
if (method === "tab.create" && tabId !== undefined && tabWorkspaceId !== undefined)
|
|
3903
|
-
createdTabs.set(tabId, tabWorkspaceId);
|
|
3904
|
-
});
|
|
3905
|
-
const prune = suspend(() => {
|
|
3906
|
-
const client = supervisor.executionClient;
|
|
3907
|
-
const workspaces = [...createdWorkspaces];
|
|
3908
|
-
const tabs = [...createdTabs].flatMap(([tabId, workspaceId]) => createdWorkspaces.has(workspaceId) ? [] : [tabId]);
|
|
3909
|
-
createdWorkspaces.clear();
|
|
3910
|
-
createdTabs.clear();
|
|
3911
|
-
return all([
|
|
3912
|
-
...workspaces.map((workspaceId) => ignore(client.request("workspace.close", { workspace_id: workspaceId }))),
|
|
3913
|
-
...tabs.map((tabId) => ignore(client.request("tab.close", { tab_id: tabId })))
|
|
3914
|
-
], { discard: true });
|
|
3915
|
-
});
|
|
3916
|
-
return {
|
|
3917
|
-
executionClient: {
|
|
3918
|
-
request: (method, params) => supervisor.executionClient.request(method, params).pipe(tap((response) => record(method, response)))
|
|
3919
|
-
},
|
|
3920
|
-
start: () => supervisor.start().pipe(mapError((error) => new HerdrExecutorSurfaceError({ reason: "start_failed", message: error.message })), flatMap((readiness) => readiness.protocol === HERDR_SOCKET_PROTOCOL ? void_2 : fail4(new HerdrExecutorSurfaceError({ reason: "start_failed", message: "herdr_protocol_mismatch" })))),
|
|
3921
|
-
stop: () => andThen(prune, supervisor.stop())
|
|
3922
|
-
};
|
|
3923
|
-
}
|
|
3924
|
-
// packages/agent-runtime/src/kitman-mcp-preflight.ts
|
|
3925
|
-
class KitmanMcpUnreachable extends TaggedError("KitmanMcpUnreachable") {
|
|
3926
|
-
}
|
|
3927
|
-
var handshake = [
|
|
3928
|
-
{
|
|
3929
|
-
jsonrpc: "2.0",
|
|
3930
|
-
id: 1,
|
|
3931
|
-
method: "initialize",
|
|
3932
|
-
params: { protocolVersion: "2025-06-18", capabilities: {}, clientInfo: { name: "kitman-runner", version: "1" } }
|
|
3933
|
-
},
|
|
3934
|
-
{ jsonrpc: "2.0", method: "notifications/initialized" },
|
|
3935
|
-
{ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: "step_brief", arguments: {} } }
|
|
3936
|
-
].map((message) => `${JSON.stringify(message)}
|
|
3937
|
-
`).join("");
|
|
3938
|
-
var kitmanMcpPreflight = (mcp) => gen(function* () {
|
|
3939
|
-
const spawner = yield* ChildProcessSpawner;
|
|
3940
|
-
const server = yield* spawner.spawn(make15(mcp.command, [...mcp.args], {
|
|
3941
|
-
extendEnv: true,
|
|
3942
|
-
env: mcp.env,
|
|
3943
|
-
stdin: { stream: make13(new TextEncoder().encode(handshake)), endOnDone: false },
|
|
3944
|
-
stderr: "ignore"
|
|
3945
|
-
}));
|
|
3946
|
-
const reply = yield* server.stdout.pipe(decodeText, splitLines, map4((line) => recordValue(getOrUndefined(decodeJsonStringOption(line)))), filter((message) => message?.id === 2), runHead);
|
|
3947
|
-
const result = isSome(reply) ? recordValue(reply.value?.result) : undefined;
|
|
3948
|
-
if (result === undefined || result.isError === true)
|
|
3949
|
-
return yield* new KitmanMcpUnreachable({ message: "Kitman MCP did not return the StepAttempt brief" });
|
|
3950
|
-
}).pipe(scoped, timeoutOrElse({
|
|
3951
|
-
duration: "20 seconds",
|
|
3952
|
-
orElse: () => fail4(new KitmanMcpUnreachable({ message: "Kitman MCP did not answer in time" }))
|
|
3953
|
-
}), mapError((error) => error instanceof KitmanMcpUnreachable ? error : new KitmanMcpUnreachable({ message: error.message })));
|
|
3954
|
-
// packages/agent-runtime/src/loop-bundles.ts
|
|
3955
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
3956
|
-
|
|
3957
|
-
class BundleRefused extends TaggedError("BundleRefused") {
|
|
3958
|
-
get message() {
|
|
3959
|
-
return `Loop bundle ${this.digest} refused: ${this.reason}`;
|
|
3960
|
-
}
|
|
3961
|
-
}
|
|
3962
|
-
var sha2562 = (bytes) => digestSha256(bytes, "hex");
|
|
3963
|
-
var bundleCacheDir = fileURLToPath3(new URL("../.bundles/", import.meta.url));
|
|
3964
|
-
var kitmanBundles = (input) => gen(function* () {
|
|
3965
|
-
const fs = yield* FileSystem;
|
|
3966
|
-
const path = yield* Path;
|
|
3967
|
-
const cacheDir = input.cacheDir ?? bundleCacheDir;
|
|
3968
|
-
const fileOf = (digest) => path.join(cacheDir, `${digest}.js`);
|
|
3969
|
-
const refused = (digest, reason) => new BundleRefused({ digest, reason });
|
|
3970
|
-
const verified = (digest, bytes) => sha2562(bytes) === digest ? void_2 : fail4(refused(digest, "its content does not match its digest"));
|
|
3971
|
-
const write = (digest, bytes) => gen(function* () {
|
|
3972
|
-
const written = `${fileOf(digest)}.${yield* nextInt}.partial`;
|
|
3973
|
-
yield* fs.makeDirectory(cacheDir, { recursive: true });
|
|
3974
|
-
yield* fs.writeFile(written, bytes);
|
|
3975
|
-
yield* fs.rename(written, fileOf(digest));
|
|
3976
|
-
}).pipe(mapError((error) => refused(digest, `not cached: ${error.message}`)));
|
|
3977
|
-
const file = (digest) => gen(function* () {
|
|
3978
|
-
const cached = yield* fs.readFile(fileOf(digest)).pipe(option);
|
|
3979
|
-
if (isSome(cached) && sha2562(cached.value) === digest)
|
|
3980
|
-
return fileOf(digest);
|
|
3981
|
-
const fetched = yield* input.fetch(digest).pipe(mapError((error) => refused(digest, `not fetched: ${error.message}`)));
|
|
3982
|
-
const bytes = new TextEncoder().encode(fetched);
|
|
3983
|
-
yield* verified(digest, bytes);
|
|
3984
|
-
yield* write(digest, bytes);
|
|
3985
|
-
return fileOf(digest);
|
|
3986
|
-
});
|
|
3987
|
-
return {
|
|
3988
|
-
file
|
|
3989
|
-
};
|
|
3990
|
-
});
|
|
3991
|
-
// packages/agent-runtime/src/program-process.ts
|
|
3992
|
-
var inheritedEnv = ["PATH", "HOME", "TMPDIR", "LANG", "LC_ALL", "TZ"];
|
|
3993
|
-
var programProcessExecutor = (input) => (work) => gen(function* () {
|
|
3994
|
-
const file = yield* input.bundles.file(work.loopDigest);
|
|
3995
|
-
const spawner = yield* ChildProcessSpawner;
|
|
3996
|
-
const { program, ...unit } = work;
|
|
3997
|
-
const inherited = yield* forEach(inheritedEnv, (name) => map3(optionalEnv(name), (value) => value === undefined ? [] : [[name, value]]));
|
|
3998
|
-
const handle = yield* spawner.spawn(make15(input.bun ?? process.execPath, [file], {
|
|
3999
|
-
stdin: make13(new TextEncoder().encode(encodeUnknownJsonStringSync(unit))),
|
|
4000
|
-
stdout: "inherit",
|
|
4001
|
-
stderr: "inherit",
|
|
4002
|
-
extendEnv: false,
|
|
4003
|
-
env: {
|
|
4004
|
-
...Object.fromEntries(inherited.flat()),
|
|
4005
|
-
KITMAN_LOOP_ID: program.loopId,
|
|
4006
|
-
KITMAN_API_URL: input.apiUrl,
|
|
4007
|
-
KITMAN_PROGRAM_CREDENTIAL: program.credential
|
|
4008
|
-
},
|
|
4009
|
-
forceKillAfter: "5 seconds"
|
|
4010
|
-
}));
|
|
4011
|
-
const exitCode = yield* handle.exitCode;
|
|
4012
|
-
if (exitCode === 0)
|
|
4013
|
-
return { status: "settled" };
|
|
4014
|
-
yield* logWarning("runner_program_exited_unsettled", { workUnitId: work.id, exitCode });
|
|
4015
|
-
return { status: "deferred" };
|
|
4016
|
-
}).pipe(scoped, catch_((error) => as(logWarning("runner_program_not_started", error.message), { status: "deferred" })));
|
|
4017
|
-
// packages/oversight/src/domain/intent.ts
|
|
4018
|
-
var ConstraintKind = Literals(["rule", "semantic"]);
|
|
4019
|
-
var ConstraintSeverity = Literals(["block", "warn"]);
|
|
4020
|
-
var ConstraintSource = Literals(["launch", "repository", "plan", "parent", "human"]);
|
|
4021
|
-
var ProtectedPathsRule = Struct({
|
|
4022
|
-
kind: Literal("protected_paths"),
|
|
4023
|
-
globs: ArraySchema(String2)
|
|
4024
|
-
});
|
|
4025
|
-
var Constraint = Struct({
|
|
4026
|
-
id: String2,
|
|
4027
|
-
text: String2,
|
|
4028
|
-
kind: ConstraintKind,
|
|
4029
|
-
severity: ConstraintSeverity,
|
|
4030
|
-
source: ConstraintSource,
|
|
4031
|
-
rule: optionalKey(ProtectedPathsRule)
|
|
4032
|
-
});
|
|
4033
|
-
var Intent = Struct({
|
|
4034
|
-
version: Int,
|
|
4035
|
-
goal: String2,
|
|
4036
|
-
doneWhen: ArraySchema(String2),
|
|
4037
|
-
constraints: ArraySchema(Constraint),
|
|
4038
|
-
corrections: Boolean2,
|
|
4039
|
-
removedConstraintIds: ArraySchema(String2)
|
|
4040
|
-
});
|
|
4041
|
-
|
|
4042
|
-
class ConstraintSpellingInvalid extends TaggedError2()("ConstraintSpellingInvalid", { message: String2 }) {
|
|
4043
|
-
}
|
|
4044
|
-
|
|
4045
|
-
class ConstraintNotFound extends TaggedError2()("ConstraintNotFound", {
|
|
4046
|
-
message: String2
|
|
4047
|
-
}) {
|
|
4048
|
-
}
|
|
4049
|
-
// packages/oversight/src/domain/drift.ts
|
|
4050
|
-
var EvidenceLimits = { files: 20, linesPerFile: 200, changedPaths: 1000, lineLength: 1000 };
|
|
4051
|
-
var outputLines = EvidenceLimits.files * EvidenceLimits.linesPerFile;
|
|
4052
|
-
var EvidenceFile = Struct({
|
|
4053
|
-
path: String2,
|
|
4054
|
-
excerpt: String2,
|
|
4055
|
-
redacted: Boolean2,
|
|
4056
|
-
truncated: Boolean2
|
|
4057
|
-
});
|
|
4058
|
-
var ChangeEvidence = Struct({
|
|
4059
|
-
kind: Literal("change"),
|
|
4060
|
-
changedPaths: ArraySchema(String2),
|
|
4061
|
-
omittedPaths: Int,
|
|
4062
|
-
files: ArraySchema(EvidenceFile),
|
|
4063
|
-
truncated: Boolean2
|
|
4064
|
-
});
|
|
4065
|
-
var OutputEvidence = Struct({
|
|
4066
|
-
kind: Literal("output"),
|
|
4067
|
-
text: String2,
|
|
4068
|
-
truncated: Boolean2
|
|
4069
|
-
});
|
|
4070
|
-
var Evidence = Union([ChangeEvidence, OutputEvidence]);
|
|
4071
|
-
var globParts = new Map([
|
|
4072
|
-
["**/", "(?:.*/)?"],
|
|
4073
|
-
["**", ".*"],
|
|
4074
|
-
["*", "[^/]*"],
|
|
4075
|
-
["?", "[^/]"]
|
|
4076
|
-
]);
|
|
4077
|
-
var secretName = /^\.env(\..*)?$|^\.?credentials(\..*)?$|^\.(netrc|npmrc|pgpass)$|\.(pem|key|p12|pfx|jks|keystore)$|^id_(rsa|dsa|ecdsa|ed25519)|secret/i;
|
|
4078
|
-
var looksSecret = (path) => secretName.test(path.split("/").at(-1) ?? path);
|
|
4079
|
-
var capLines = (text, limit) => {
|
|
4080
|
-
const lines = text.split(`
|
|
4081
|
-
`);
|
|
4082
|
-
const capped = lines.slice(0, limit).map((line) => line.length > EvidenceLimits.lineLength ? line.slice(0, EvidenceLimits.lineLength) : line);
|
|
4083
|
-
return {
|
|
4084
|
-
text: capped.join(`
|
|
4085
|
-
`),
|
|
4086
|
-
truncated: lines.length > limit || lines.some((line) => line.length > EvidenceLimits.lineLength)
|
|
4087
|
-
};
|
|
4088
|
-
};
|
|
4089
|
-
var boundChange = (change) => {
|
|
4090
|
-
const changedPaths = change.changedPaths.slice(0, EvidenceLimits.changedPaths);
|
|
4091
|
-
const omittedPaths = (change.omittedPaths ?? 0) + change.changedPaths.length - changedPaths.length;
|
|
4092
|
-
const files = changedPaths.slice(0, EvidenceLimits.files).map((path) => {
|
|
4093
|
-
if (looksSecret(path))
|
|
4094
|
-
return { path, excerpt: "", redacted: true, truncated: false };
|
|
4095
|
-
const given = change.files.find((file) => file.path === path);
|
|
4096
|
-
const capped = capLines(given?.diff ?? "", EvidenceLimits.linesPerFile);
|
|
4097
|
-
return { path, excerpt: capped.text, redacted: false, truncated: capped.truncated || given?.truncated === true };
|
|
4098
|
-
});
|
|
4099
|
-
return {
|
|
4100
|
-
kind: "change",
|
|
4101
|
-
changedPaths,
|
|
4102
|
-
omittedPaths,
|
|
4103
|
-
files,
|
|
4104
|
-
truncated: omittedPaths > 0 || changedPaths.length > files.length || files.some((file) => file.truncated)
|
|
4105
|
-
};
|
|
4106
|
-
};
|
|
4107
|
-
var DriftStatus = Literals(["open", "correction_sent", "escalated", "verified", "dismissed"]);
|
|
4108
|
-
var DriftActor = Struct({ actorType: String2, actorId: String2 });
|
|
4109
|
-
var DriftResolution = Struct({
|
|
4110
|
-
status: DriftStatus,
|
|
4111
|
-
intentVersion: Int,
|
|
4112
|
-
at: Date2,
|
|
4113
|
-
reason: optionalKey(String2),
|
|
4114
|
-
actor: optionalKey(DriftActor)
|
|
4115
|
-
});
|
|
4116
|
-
var DriftReport = Struct({
|
|
4117
|
-
constraintId: String2,
|
|
4118
|
-
constraintText: String2,
|
|
4119
|
-
kind: ConstraintKind,
|
|
4120
|
-
severity: ConstraintSeverity,
|
|
4121
|
-
intentVersion: Int,
|
|
4122
|
-
citedPaths: ArraySchema(String2),
|
|
4123
|
-
truncated: Boolean2,
|
|
4124
|
-
status: DriftStatus,
|
|
4125
|
-
history: ArraySchema(DriftResolution)
|
|
4126
|
-
});
|
|
4127
|
-
|
|
4128
|
-
class DriftReportNotOpen extends TaggedError2()("DriftReportNotOpen", {
|
|
4129
|
-
message: String2
|
|
4130
|
-
}) {
|
|
4131
|
-
}
|
|
4132
|
-
// packages/oversight/src/domain/judgement.ts
|
|
4133
|
-
var ConstraintVerdict = Literals(["holds", "breached", "unverified"]);
|
|
4134
|
-
var OutcomeVerdict = Literals(["met", "not_met", "unverified"]);
|
|
4135
|
-
var Citation = Struct({ path: String2, line: optionalKey(Int) });
|
|
4136
|
-
var JudgeOutput = Struct({
|
|
4137
|
-
constraints: ArraySchema(Struct({ id: String2, verdict: ConstraintVerdict, citations: ArraySchema(Citation) })),
|
|
4138
|
-
goal: optionalKey(OutcomeVerdict),
|
|
4139
|
-
doneWhen: optionalKey(ArraySchema(Struct({ item: Int, verdict: OutcomeVerdict })))
|
|
4140
|
-
});
|
|
4141
|
-
var JudgementReading = Struct({
|
|
4142
|
-
constraints: ArraySchema(Struct({ constraintId: String2, verdict: ConstraintVerdict, citations: ArraySchema(Citation) })),
|
|
4143
|
-
goal: optionalKey(OutcomeVerdict),
|
|
4144
|
-
doneWhen: optionalKey(ArraySchema(OutcomeVerdict))
|
|
4145
|
-
});
|
|
4146
|
-
var verdictEnum = (values) => ({ type: "string", enum: values });
|
|
4147
|
-
var closedObject = (properties, required) => ({
|
|
4148
|
-
type: "object",
|
|
4149
|
-
additionalProperties: false,
|
|
4150
|
-
required,
|
|
4151
|
-
properties
|
|
4152
|
-
});
|
|
4153
|
-
var constraintsSchema = {
|
|
4154
|
-
type: "array",
|
|
4155
|
-
items: closedObject({
|
|
4156
|
-
id: { type: "string" },
|
|
4157
|
-
verdict: verdictEnum(ConstraintVerdict.literals),
|
|
4158
|
-
citations: {
|
|
4159
|
-
type: "array",
|
|
4160
|
-
items: closedObject({ path: { type: "string" }, line: { type: "integer", minimum: 1 } }, ["path"])
|
|
4161
|
-
}
|
|
4162
|
-
}, ["id", "verdict", "citations"])
|
|
4163
|
-
};
|
|
4164
|
-
// packages/oversight/src/domain/alignment.ts
|
|
4165
|
-
var AlignmentVerdict = Literals(["aligned", "not_aligned", "unverified"]);
|
|
4166
|
-
var Alignment = Struct({
|
|
4167
|
-
verdict: AlignmentVerdict,
|
|
4168
|
-
reasons: ArraySchema(String2),
|
|
4169
|
-
intentVersion: Int,
|
|
4170
|
-
judgedAt: Date2
|
|
4171
|
-
});
|
|
4172
|
-
// packages/agent-runtime/src/agent-step-executor.ts
|
|
4173
|
-
import { homedir } from "os";
|
|
4174
|
-
|
|
4175
|
-
// packages/agent-runtime/src/harness-sessions.ts
|
|
4176
|
-
import { gunzipSync, gzipSync } from "zlib";
|
|
4177
|
-
var projectDirectory = (worktree) => worktree.replace(/[^a-zA-Z0-9]/g, "-");
|
|
4178
|
-
var rolloutId = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/;
|
|
4179
|
-
var filesUnder = (directory) => gen(function* () {
|
|
4180
|
-
const fs = yield* FileSystem;
|
|
4181
|
-
if (!(yield* fs.exists(directory)))
|
|
4182
|
-
return [];
|
|
4183
|
-
return (yield* fs.readDirectory(directory, { recursive: true })).map((file) => `${directory}/${file}`);
|
|
4184
|
-
});
|
|
4185
|
-
var rolloutDirectory = (path) => gen(function* () {
|
|
4186
|
-
const fs = yield* FileSystem;
|
|
4187
|
-
const firstLine = (yield* fs.readFileString(path)).split(`
|
|
4188
|
-
`, 1)[0] ?? "";
|
|
4189
|
-
const line = getOrUndefined(decodeJsonStringOption(firstLine));
|
|
4190
|
-
const payload = isJsonObject(line) ? line.payload : undefined;
|
|
4191
|
-
return isJsonObject(payload) && isString2(payload.cwd) ? payload.cwd : undefined;
|
|
4192
|
-
});
|
|
4193
|
-
var findSession = (adapter, place) => gen(function* () {
|
|
4194
|
-
const location = adapter.session?.location;
|
|
4195
|
-
if (location === undefined)
|
|
4196
|
-
return;
|
|
4197
|
-
const root = `${place.home}/${location.root}`;
|
|
4198
|
-
if (location.layout === "per_directory") {
|
|
4199
|
-
if (place.id === undefined)
|
|
4200
|
-
return;
|
|
4201
|
-
const name = `${place.id}.jsonl`;
|
|
4202
|
-
const own = `${root}/${projectDirectory(place.worktree)}/${name}`;
|
|
4203
|
-
const fs = yield* FileSystem;
|
|
4204
|
-
const path = (yield* fs.exists(own)) ? own : (yield* filesUnder(root)).find((file) => file.endsWith(`/${name}`));
|
|
4205
|
-
return path === undefined ? undefined : { id: place.id, name, path };
|
|
4206
|
-
}
|
|
4207
|
-
for (const path of (yield* filesUnder(root)).filter((file) => rolloutId.test(file)).sort().reverse()) {
|
|
4208
|
-
const name = path.slice(path.lastIndexOf("/") + 1);
|
|
4209
|
-
const id = rolloutId.exec(name)?.[1];
|
|
4210
|
-
if (id === undefined)
|
|
4211
|
-
continue;
|
|
4212
|
-
if (place.id === undefined ? (yield* rolloutDirectory(path)) === place.worktree : id === place.id)
|
|
4213
|
-
return { id, name, path };
|
|
4214
|
-
}
|
|
4215
|
-
return;
|
|
4216
|
-
}).pipe(orElseSucceed(() => {
|
|
4217
|
-
return;
|
|
4218
|
-
}));
|
|
4219
|
-
var packSession = (path) => map3(flatMap(FileSystem, (fs) => fs.readFile(path)), (content) => new Uint8Array(gzipSync(content)));
|
|
4220
|
-
var restoreSession = (adapter, place) => gen(function* () {
|
|
4221
|
-
const fs = yield* FileSystem;
|
|
4222
|
-
const location = adapter.session?.location;
|
|
4223
|
-
if (location === undefined)
|
|
4224
|
-
return yield* die3(`${adapter.id} keeps no session to restore`);
|
|
4225
|
-
const root = `${place.home}/${location.root}`;
|
|
4226
|
-
const today = toDate(wallClockMillis()).toISOString().slice(0, 10).replaceAll("-", "/");
|
|
4227
|
-
const directory = location.layout === "per_directory" ? `${root}/${projectDirectory(place.worktree)}` : `${root}/${today}`;
|
|
4228
|
-
const path = `${directory}/${place.session.name}`;
|
|
4229
|
-
yield* fs.makeDirectory(directory, { recursive: true });
|
|
4230
|
-
yield* fs.writeFile(path, new Uint8Array(gunzipSync(place.session.content)));
|
|
4231
|
-
return { id: place.session.id, name: place.session.name, path };
|
|
4232
|
-
});
|
|
4035
|
+
const error = findErrorOption(exit2.cause);
|
|
4036
|
+
if (isSome(error) && error.value instanceof RunnerReplicaError && error.value.kind === "unauthorized")
|
|
4037
|
+
return yield* error.value;
|
|
4038
|
+
yield* logError("runner_slot_recoverable_error", capacitySlot, pretty(exit2.cause));
|
|
4039
|
+
}
|
|
4040
|
+
yield* sleep(idleBackoff(idleIterations++));
|
|
4041
|
+
}
|
|
4042
|
+
});
|
|
4043
|
+
const heartbeat = input.control(input.slots[0] ?? "slot-1").heartbeatReplica;
|
|
4044
|
+
const replicaHeartbeat = gen(function* () {
|
|
4045
|
+
while (true) {
|
|
4046
|
+
const exit2 = yield* exit(retryTransient(heartbeatCall(heartbeat)));
|
|
4047
|
+
if (isFailure2(exit2)) {
|
|
4048
|
+
const error = findErrorOption(exit2.cause);
|
|
4049
|
+
if (isSome(error) && error.value.kind === "unauthorized")
|
|
4050
|
+
return yield* error.value;
|
|
4051
|
+
yield* logError("runner_replica_heartbeat_failed", pretty(exit2.cause));
|
|
4052
|
+
}
|
|
4053
|
+
yield* sleep(ReplicaHeartbeatInterval);
|
|
4054
|
+
}
|
|
4055
|
+
});
|
|
4056
|
+
return all([replicaHeartbeat, forEach(input.slots, runSlot, { concurrency: "unbounded", discard: true })], {
|
|
4057
|
+
concurrency: "unbounded",
|
|
4058
|
+
discard: true
|
|
4059
|
+
}).pipe(andThen(never));
|
|
4060
|
+
}
|
|
4061
|
+
var ReplicaHeartbeatInterval = seconds(10);
|
|
4062
|
+
var ReplicaHeartbeatTimeout = seconds(15);
|
|
4063
|
+
var heartbeatCall = (heartbeat) => suspend(heartbeat).pipe(timeout(ReplicaHeartbeatTimeout), mapError((cause) => new RunnerReplicaError({ operation: "heartbeatReplica", kind: controlFailureKind(cause), cause })));
|
|
4233
4064
|
|
|
4234
4065
|
// packages/agent-runtime/src/agent-step-executor.ts
|
|
4235
4066
|
var transfer = { timeout: "30 minutes" };
|
|
@@ -4237,22 +4068,22 @@ var stallLimit = ["-c", "http.lowSpeedLimit=1000", "-c", "http.lowSpeedTime=60"]
|
|
|
4237
4068
|
var checkpointTransfer = { timeout: "5 minutes" };
|
|
4238
4069
|
var clonePermits = new Map;
|
|
4239
4070
|
var inClone = (directory) => (effect) => {
|
|
4240
|
-
const permit = clonePermits.get(directory) ??
|
|
4071
|
+
const permit = clonePermits.get(directory) ?? makeUnsafe4(1);
|
|
4241
4072
|
clonePermits.set(directory, permit);
|
|
4242
4073
|
return permit.withPermits(1)(effect);
|
|
4243
4074
|
};
|
|
4075
|
+
var repositoryClone = (rootDir, repoBindingId) => `${rootDir}/repos/${repoBindingId}`;
|
|
4244
4076
|
var runCheckouts = (rootDir) => {
|
|
4245
4077
|
const runsDir = `${rootDir}/runs`;
|
|
4246
4078
|
const reposDir = `${rootDir}/repos`;
|
|
4247
4079
|
const cloned = (repoBinding) => gen(function* () {
|
|
4248
4080
|
const fs = yield* FileSystem;
|
|
4249
|
-
const path = yield* Path;
|
|
4250
4081
|
const forbidden = findForbiddenRepoBindingSecretPath(repoBinding);
|
|
4251
4082
|
if (forbidden !== undefined)
|
|
4252
4083
|
return yield* new RepoMaterializationError({
|
|
4253
4084
|
message: `RepoBinding contains forbidden secret-like value at ${forbidden}`
|
|
4254
4085
|
});
|
|
4255
|
-
const directory =
|
|
4086
|
+
const directory = repositoryClone(rootDir, repoBinding.id);
|
|
4256
4087
|
const url = repositoryUrl(repoBinding);
|
|
4257
4088
|
if (yield* fs.exists(directory)) {
|
|
4258
4089
|
const origin = yield* runCommand2("git", ["-C", directory, "remote", "get-url", "origin"]);
|
|
@@ -4265,7 +4096,7 @@ var runCheckouts = (rootDir) => {
|
|
|
4265
4096
|
return directory;
|
|
4266
4097
|
});
|
|
4267
4098
|
const fetch = (directory) => runCommand2("git", ["-C", directory, ...stallLimit, "fetch", "--prune", "origin"], transfer);
|
|
4268
|
-
const inCloneOf = (repoBinding) => inClone(
|
|
4099
|
+
const inCloneOf = (repoBinding) => inClone(repositoryClone(rootDir, repoBinding.id));
|
|
4269
4100
|
const clone = (repoBinding) => inCloneOf(repoBinding)(cloned(repoBinding));
|
|
4270
4101
|
const holds = (directory, revision) => revision === undefined || !/^(?:[0-9a-f]{40}|[0-9a-f]{64})$/.test(revision) ? succeed5(false) : map3(exit(runCommand2("git", ["-C", directory, "cat-file", "-e", `${revision}^{commit}`])), isSuccess2);
|
|
4271
4102
|
const checkout = (work, repoBinding, checkpoint) => gen(function* () {
|
|
@@ -4460,17 +4291,338 @@ var agentStepExecutor = (input) => (work) => gen(function* () {
|
|
|
4460
4291
|
return boundary === undefined ? { status: "completed", revision } : { status: "completed", revision, boundary };
|
|
4461
4292
|
}).pipe(scoped);
|
|
4462
4293
|
var checkpointRef = (work) => `refs/kitman/checkpoints/${work.runId}/${work.id}`;
|
|
4294
|
+
|
|
4295
|
+
// packages/agent-runtime/src/herdr-executor.ts
|
|
4296
|
+
var runnerStateSandboxPolicy = (runner, readAllowed) => ({
|
|
4297
|
+
...runnerAgentSandboxPolicy(),
|
|
4298
|
+
readDeniedPaths: [
|
|
4299
|
+
...new Set([
|
|
4300
|
+
...runnerAgentSandboxPolicy().readDeniedPaths,
|
|
4301
|
+
runner.workRoot,
|
|
4302
|
+
runner.bundleCache,
|
|
4303
|
+
runner.kitmanConfigDir,
|
|
4304
|
+
runner.authStore
|
|
4305
|
+
])
|
|
4306
|
+
],
|
|
4307
|
+
readAllowedPaths: [...readAllowed]
|
|
4308
|
+
});
|
|
4309
|
+
var agentStepSandboxPolicy = (work, apiUrl, runner) => ({
|
|
4310
|
+
...runnerStateSandboxPolicy(runner, work.checkout === "none" || work.repoBinding === undefined ? [] : [repositoryClone(runner.workRoot, work.repoBinding.id)]),
|
|
4311
|
+
network: agentNetworkAllowlist({
|
|
4312
|
+
apiUrl,
|
|
4313
|
+
providerHosts: harnessAdapter(work.brief.harness)?.providerHosts ?? [],
|
|
4314
|
+
...work.repoBinding === undefined ? undefined : { repoBindingHost: work.repoBinding.host },
|
|
4315
|
+
...work.network === undefined ? undefined : { agent: work.network }
|
|
4316
|
+
})
|
|
4317
|
+
});
|
|
4318
|
+
function runnerStepAttemptFromAgentStep(work) {
|
|
4319
|
+
return {
|
|
4320
|
+
kind: "step_attempt",
|
|
4321
|
+
attempt: {
|
|
4322
|
+
id: work.id,
|
|
4323
|
+
workspaceId: "",
|
|
4324
|
+
...work.projectId === undefined ? undefined : { projectId: work.projectId },
|
|
4325
|
+
runId: work.runId,
|
|
4326
|
+
taskId: work.runId,
|
|
4327
|
+
stepKey: work.stepKey,
|
|
4328
|
+
sequence: 0,
|
|
4329
|
+
required: true,
|
|
4330
|
+
attempt: work.attempt,
|
|
4331
|
+
status: "running",
|
|
4332
|
+
inputManifest: { manifestVersion: 1, assembledAt: work.lease.lastHeartbeatAt, entries: [] },
|
|
4333
|
+
execution: { metadata: {} },
|
|
4334
|
+
reviewEvidence: [],
|
|
4335
|
+
lease: {
|
|
4336
|
+
ownerId: work.lease.leaseOwnerId,
|
|
4337
|
+
runnerReplicaId: work.lease.runnerReplicaId,
|
|
4338
|
+
leaseId: work.lease.leaseId,
|
|
4339
|
+
fencingToken: work.lease.fencingToken,
|
|
4340
|
+
capacitySlot: work.lease.capacitySlot,
|
|
4341
|
+
expiresAt: work.lease.leaseExpiresAt,
|
|
4342
|
+
lastHeartbeatAt: work.lease.lastHeartbeatAt
|
|
4343
|
+
},
|
|
4344
|
+
createdAt: work.lease.lastHeartbeatAt,
|
|
4345
|
+
updatedAt: work.lease.lastHeartbeatAt
|
|
4346
|
+
},
|
|
4347
|
+
step: {
|
|
4348
|
+
title: work.stepKey,
|
|
4349
|
+
implementation: { kind: "agent", taskIdRef: work.runId, agentId: work.id, runtimeKind: "herdr" },
|
|
4350
|
+
inputSchemaRef: { kind: "typebox_ref", name: "WorkUnitInput" },
|
|
4351
|
+
outputSchemaRef: { kind: "typebox_ref", name: "WorkUnitOutput" },
|
|
4352
|
+
allowedCapabilities: [],
|
|
4353
|
+
retryPolicy: { maxAttempts: 1, backoff: "none" },
|
|
4354
|
+
timeoutPolicy: { timeoutSeconds: 1800 },
|
|
4355
|
+
metadata: {}
|
|
4356
|
+
}
|
|
4357
|
+
};
|
|
4358
|
+
}
|
|
4359
|
+
// packages/agent-runtime/src/materialization-plan.ts
|
|
4360
|
+
class AgentEnvironmentPlanApplyError extends TaggedError("AgentEnvironmentPlanApplyError") {
|
|
4361
|
+
get message() {
|
|
4362
|
+
return `AgentEnvironment plan apply failed during ${this.phase}: ${this.cause.message}`;
|
|
4363
|
+
}
|
|
4364
|
+
}
|
|
4365
|
+
var previewAgentEnvironmentPlan = fnUntraced(function* (input) {
|
|
4366
|
+
const skills = yield* previewAgentEnvironmentMaterialization({
|
|
4367
|
+
environment: input.environment,
|
|
4368
|
+
...input.rootDir === undefined ? undefined : { rootDir: input.rootDir },
|
|
4369
|
+
...input.scope === undefined ? undefined : { scope: input.scope },
|
|
4370
|
+
...input.cacheRoot === undefined ? undefined : { cacheRoot: input.cacheRoot },
|
|
4371
|
+
...input.noInstall === undefined ? undefined : { noInstall: input.noInstall }
|
|
4372
|
+
});
|
|
4373
|
+
const harnessConfig = yield* previewAgentEnvironmentConfigSync({
|
|
4374
|
+
environment: input.environment,
|
|
4375
|
+
materializedSkills: skills.materializedSkills,
|
|
4376
|
+
...input.syncKit === undefined ? undefined : { syncKit: input.syncKit },
|
|
4377
|
+
...input.rootDir === undefined ? undefined : { rootDir: input.rootDir },
|
|
4378
|
+
...input.scope === undefined ? undefined : { scope: input.scope },
|
|
4379
|
+
...input.mcpCredentialName === undefined ? undefined : { mcpCredentialName: input.mcpCredentialName }
|
|
4380
|
+
});
|
|
4381
|
+
return {
|
|
4382
|
+
harness: input.environment.harness,
|
|
4383
|
+
...input.syncKit === undefined ? undefined : { syncKitHash: input.syncKit.syncKitHash },
|
|
4384
|
+
skills,
|
|
4385
|
+
harnessConfig,
|
|
4386
|
+
operationCount: skills.operations.length + harnessConfig.operations.length,
|
|
4387
|
+
warnings: [...skills.warnings, ...harnessConfig.warnings].map((item) => item.message)
|
|
4388
|
+
};
|
|
4389
|
+
});
|
|
4390
|
+
function composeAgentEnvironmentSyncPlan(targets) {
|
|
4391
|
+
return { version: 1, planId: canonicalSha256(targets), targets };
|
|
4392
|
+
}
|
|
4393
|
+
var applyAgentEnvironmentPlans = fnUntraced(function* (plan) {
|
|
4394
|
+
for (const target of plan.targets)
|
|
4395
|
+
yield* applyAgentEnvironmentMaterialization(target.skills).pipe(mapError((cause) => new AgentEnvironmentPlanApplyError({ phase: "skills", cause })));
|
|
4396
|
+
for (const target of plan.targets)
|
|
4397
|
+
yield* applyAgentEnvironmentConfigSync(target.harnessConfig).pipe(mapError((cause) => new AgentEnvironmentPlanApplyError({ phase: "harness_config", cause })));
|
|
4398
|
+
return plan;
|
|
4399
|
+
});
|
|
4400
|
+
// packages/agent-runtime/src/herdr-executor-surface.ts
|
|
4401
|
+
class HerdrExecutorSurfaceError extends TaggedError("HerdrExecutorSurfaceError") {
|
|
4402
|
+
}
|
|
4403
|
+
function herdrExecutorSurface(input) {
|
|
4404
|
+
const supervisor = input.supervisor ?? new HerdrServerSupervisor({
|
|
4405
|
+
runnerId: input.runnerId,
|
|
4406
|
+
...input.session === undefined ? undefined : { session: input.session }
|
|
4407
|
+
});
|
|
4408
|
+
const createdWorkspaces = new Set;
|
|
4409
|
+
const createdTabs = new Map;
|
|
4410
|
+
const record = (method, response) => sync(() => {
|
|
4411
|
+
const workspaceId = nestedString(response, ["workspace", "workspace_id"]);
|
|
4412
|
+
const tabId = nestedString(response, ["tab", "tab_id"]);
|
|
4413
|
+
const tabWorkspaceId = nestedString(response, ["tab", "workspace_id"]);
|
|
4414
|
+
if (method === "workspace.create" && workspaceId !== undefined)
|
|
4415
|
+
createdWorkspaces.add(workspaceId);
|
|
4416
|
+
if (method === "tab.create" && tabId !== undefined && tabWorkspaceId !== undefined)
|
|
4417
|
+
createdTabs.set(tabId, tabWorkspaceId);
|
|
4418
|
+
});
|
|
4419
|
+
const prune = suspend(() => {
|
|
4420
|
+
const client = supervisor.executionClient;
|
|
4421
|
+
const workspaces = [...createdWorkspaces];
|
|
4422
|
+
const tabs = [...createdTabs].flatMap(([tabId, workspaceId]) => createdWorkspaces.has(workspaceId) ? [] : [tabId]);
|
|
4423
|
+
createdWorkspaces.clear();
|
|
4424
|
+
createdTabs.clear();
|
|
4425
|
+
return all([
|
|
4426
|
+
...workspaces.map((workspaceId) => ignore(client.request("workspace.close", { workspace_id: workspaceId }))),
|
|
4427
|
+
...tabs.map((tabId) => ignore(client.request("tab.close", { tab_id: tabId })))
|
|
4428
|
+
], { discard: true });
|
|
4429
|
+
});
|
|
4430
|
+
return {
|
|
4431
|
+
executionClient: {
|
|
4432
|
+
request: (method, params) => supervisor.executionClient.request(method, params).pipe(tap((response) => record(method, response)))
|
|
4433
|
+
},
|
|
4434
|
+
start: () => supervisor.start().pipe(mapError((error) => new HerdrExecutorSurfaceError({ reason: "start_failed", message: error.message })), flatMap((readiness) => readiness.protocol === HERDR_SOCKET_PROTOCOL ? void_2 : fail4(new HerdrExecutorSurfaceError({ reason: "start_failed", message: "herdr_protocol_mismatch" })))),
|
|
4435
|
+
stop: () => andThen(prune, supervisor.stop())
|
|
4436
|
+
};
|
|
4437
|
+
}
|
|
4438
|
+
// packages/agent-runtime/src/kitman-mcp-preflight.ts
|
|
4439
|
+
class KitmanMcpUnreachable extends TaggedError("KitmanMcpUnreachable") {
|
|
4440
|
+
}
|
|
4441
|
+
var handshake = [
|
|
4442
|
+
{
|
|
4443
|
+
jsonrpc: "2.0",
|
|
4444
|
+
id: 1,
|
|
4445
|
+
method: "initialize",
|
|
4446
|
+
params: { protocolVersion: "2025-06-18", capabilities: {}, clientInfo: { name: "kitman-runner", version: "1" } }
|
|
4447
|
+
},
|
|
4448
|
+
{ jsonrpc: "2.0", method: "notifications/initialized" },
|
|
4449
|
+
{ jsonrpc: "2.0", id: 2, method: "tools/call", params: { name: "step_brief", arguments: {} } }
|
|
4450
|
+
].map((message) => `${JSON.stringify(message)}
|
|
4451
|
+
`).join("");
|
|
4452
|
+
var kitmanMcpPreflight = (mcp) => gen(function* () {
|
|
4453
|
+
const spawner = yield* ChildProcessSpawner;
|
|
4454
|
+
const server = yield* spawner.spawn(make11(mcp.command, [...mcp.args], {
|
|
4455
|
+
extendEnv: true,
|
|
4456
|
+
env: mcp.env,
|
|
4457
|
+
stdin: { stream: make9(new TextEncoder().encode(handshake)), endOnDone: false },
|
|
4458
|
+
stderr: "ignore"
|
|
4459
|
+
}));
|
|
4460
|
+
const reply = yield* server.stdout.pipe(decodeText, splitLines, map4((line) => recordValue(getOrUndefined(decodeJsonStringOption(line)))), filter((message) => message?.id === 2), runHead);
|
|
4461
|
+
const result = isSome(reply) ? recordValue(reply.value?.result) : undefined;
|
|
4462
|
+
if (result === undefined || result.isError === true)
|
|
4463
|
+
return yield* new KitmanMcpUnreachable({ message: "Kitman MCP did not return the StepAttempt brief" });
|
|
4464
|
+
}).pipe(scoped, timeoutOrElse({
|
|
4465
|
+
duration: "20 seconds",
|
|
4466
|
+
orElse: () => fail4(new KitmanMcpUnreachable({ message: "Kitman MCP did not answer in time" }))
|
|
4467
|
+
}), mapError((error) => error instanceof KitmanMcpUnreachable ? error : new KitmanMcpUnreachable({ message: error.message })));
|
|
4468
|
+
// packages/agent-runtime/src/loop-bundles.ts
|
|
4469
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4470
|
+
|
|
4471
|
+
class BundleRefused extends TaggedError("BundleRefused") {
|
|
4472
|
+
get message() {
|
|
4473
|
+
return `Loop bundle ${this.digest} refused: ${this.reason}`;
|
|
4474
|
+
}
|
|
4475
|
+
}
|
|
4476
|
+
var sha2562 = (bytes) => digestSha256(bytes, "hex");
|
|
4477
|
+
var bundleCacheDir = fileURLToPath3(new URL("../.bundles/", import.meta.url));
|
|
4478
|
+
var kitmanBundles = (input) => gen(function* () {
|
|
4479
|
+
const fs = yield* FileSystem;
|
|
4480
|
+
const path = yield* Path;
|
|
4481
|
+
const cacheDir = input.cacheDir ?? bundleCacheDir;
|
|
4482
|
+
const fileOf = (digest) => path.join(cacheDir, `${digest}.js`);
|
|
4483
|
+
const refused = (digest, reason) => new BundleRefused({ digest, reason });
|
|
4484
|
+
const verified = (digest, bytes) => sha2562(bytes) === digest ? void_2 : fail4(refused(digest, "its content does not match its digest"));
|
|
4485
|
+
const write = (digest, bytes) => gen(function* () {
|
|
4486
|
+
const written = `${fileOf(digest)}.${yield* nextInt}.partial`;
|
|
4487
|
+
yield* fs.makeDirectory(cacheDir, { recursive: true });
|
|
4488
|
+
yield* fs.writeFile(written, bytes);
|
|
4489
|
+
yield* fs.rename(written, fileOf(digest));
|
|
4490
|
+
}).pipe(mapError((error) => refused(digest, `not cached: ${error.message}`)));
|
|
4491
|
+
const file = (digest) => gen(function* () {
|
|
4492
|
+
const cached = yield* fs.readFile(fileOf(digest)).pipe(option);
|
|
4493
|
+
if (isSome(cached) && sha2562(cached.value) === digest)
|
|
4494
|
+
return fileOf(digest);
|
|
4495
|
+
const fetched = yield* input.fetch(digest).pipe(mapError((error) => refused(digest, `not fetched: ${error.message}`)));
|
|
4496
|
+
const bytes = new TextEncoder().encode(fetched);
|
|
4497
|
+
yield* verified(digest, bytes);
|
|
4498
|
+
yield* write(digest, bytes);
|
|
4499
|
+
return fileOf(digest);
|
|
4500
|
+
});
|
|
4501
|
+
return {
|
|
4502
|
+
file
|
|
4503
|
+
};
|
|
4504
|
+
});
|
|
4505
|
+
// packages/agent-runtime/src/program-process.ts
|
|
4506
|
+
var inheritedEnv = ["PATH", "HOME", "TMPDIR", "LANG", "LC_ALL", "TZ"];
|
|
4507
|
+
var containerEnv = new Set(["LANG", "LC_ALL", "TZ"]);
|
|
4508
|
+
var failed2 = (failureSummary) => ({ status: "failed", failureSummary });
|
|
4509
|
+
var programProcessExecutor = (input) => (work) => gen(function* () {
|
|
4510
|
+
const { sandbox } = input;
|
|
4511
|
+
if (sandbox !== undefined && sandbox.backend === undefined)
|
|
4512
|
+
return failed2("A shared Runner runs programs only in `srt` or `docker`.");
|
|
4513
|
+
if (sandbox?.backend === "srt" && work.network === "open")
|
|
4514
|
+
return failed2("The Loop opens the network, which `srt` cannot do; it needs `docker`.");
|
|
4515
|
+
const file = yield* input.bundles.file(work.loopDigest);
|
|
4516
|
+
const { program, ...unit } = work;
|
|
4517
|
+
const stdin = encodeUnknownJsonStringSync(unit);
|
|
4518
|
+
const hosts = work.network === "open" ? undefined : [...new Set([new URL(input.apiUrl).hostname, ...work.network?.hosts ?? []])];
|
|
4519
|
+
const inherited = (yield* forEach(inheritedEnv, (name) => map3(optionalEnv(name), (value) => value === undefined ? [] : [[name, value]]))).flat();
|
|
4520
|
+
const programEnv = {
|
|
4521
|
+
KITMAN_LOOP_ID: program.loopId,
|
|
4522
|
+
KITMAN_API_URL: input.apiUrl,
|
|
4523
|
+
KITMAN_PROGRAM_CREDENTIAL: program.credential,
|
|
4524
|
+
...hosts === undefined ? undefined : { [programHostsEnv]: hosts.join(",") },
|
|
4525
|
+
[undeclaredHostsEnv]: sandbox === undefined ? "warn" : "fail"
|
|
4526
|
+
};
|
|
4527
|
+
const exitCode = sandbox === undefined ? yield* gen(function* () {
|
|
4528
|
+
const spawner = yield* ChildProcessSpawner;
|
|
4529
|
+
const handle = yield* spawner.spawn(make11(input.bun ?? process.execPath, [file], {
|
|
4530
|
+
stdin: make9(new TextEncoder().encode(stdin)),
|
|
4531
|
+
stdout: "inherit",
|
|
4532
|
+
stderr: "inherit",
|
|
4533
|
+
extendEnv: false,
|
|
4534
|
+
env: { ...Object.fromEntries(inherited), ...programEnv },
|
|
4535
|
+
forceKillAfter: "5 seconds"
|
|
4536
|
+
}));
|
|
4537
|
+
return yield* handle.exitCode;
|
|
4538
|
+
}) : yield* gen(function* () {
|
|
4539
|
+
const tmp = yield* (yield* FileSystem).makeTempDirectoryScoped({ prefix: "kitman-program-" });
|
|
4540
|
+
const policy = {
|
|
4541
|
+
...runnerStateSandboxPolicy(sandbox.runner, [file]),
|
|
4542
|
+
writablePaths: [tmp],
|
|
4543
|
+
network: hosts === undefined ? "open" : { hosts },
|
|
4544
|
+
environment: {}
|
|
4545
|
+
};
|
|
4546
|
+
const command = (argv, env) => ({
|
|
4547
|
+
argv,
|
|
4548
|
+
cwd: tmp,
|
|
4549
|
+
env: { ...env, ...programEnv },
|
|
4550
|
+
extendEnv: false,
|
|
4551
|
+
stdin,
|
|
4552
|
+
timeout: infinity
|
|
4553
|
+
});
|
|
4554
|
+
const ran = sandbox.backend === "srt" ? yield* runSandboxCommand({
|
|
4555
|
+
backend: "srt",
|
|
4556
|
+
policy,
|
|
4557
|
+
command: command([
|
|
4558
|
+
"env",
|
|
4559
|
+
"-u",
|
|
4560
|
+
"NO_PROXY",
|
|
4561
|
+
"-u",
|
|
4562
|
+
"no_proxy",
|
|
4563
|
+
`TMPDIR=${tmp}`,
|
|
4564
|
+
input.bun ?? process.execPath,
|
|
4565
|
+
file
|
|
4566
|
+
], Object.fromEntries(inherited)),
|
|
4567
|
+
...sandbox.srtCommand === undefined ? undefined : { srtCommand: sandbox.srtCommand }
|
|
4568
|
+
}) : yield* runSandboxCommand({
|
|
4569
|
+
backend: "docker",
|
|
4570
|
+
docker: { ...sandbox.docker, image: sandbox.docker.proxyImage ?? EgressProxyImage },
|
|
4571
|
+
runnerId: sandbox.runnerId,
|
|
4572
|
+
id: work.id,
|
|
4573
|
+
readOnlyPaths: [file],
|
|
4574
|
+
policy,
|
|
4575
|
+
command: command(["bun", file], {
|
|
4576
|
+
...Object.fromEntries(inherited.filter(([name]) => containerEnv.has(name))),
|
|
4577
|
+
TMPDIR: tmp
|
|
4578
|
+
})
|
|
4579
|
+
});
|
|
4580
|
+
if (ran.exitCode !== 0)
|
|
4581
|
+
yield* logWarning("runner_program_output", ran.output);
|
|
4582
|
+
return ran.exitCode;
|
|
4583
|
+
});
|
|
4584
|
+
if (exitCode === 0)
|
|
4585
|
+
return { status: "settled" };
|
|
4586
|
+
yield* logWarning("runner_program_exited_unsettled", { workUnitId: work.id, exitCode });
|
|
4587
|
+
return { status: "deferred" };
|
|
4588
|
+
}).pipe(scoped, catch_((error) => as(logWarning("runner_program_not_started", error.message), { status: "deferred" })));
|
|
4463
4589
|
// packages/agent-runtime/src/verification-executor.ts
|
|
4464
4590
|
var checkTimeout = "30 minutes";
|
|
4465
|
-
var
|
|
4591
|
+
var checkSandboxPolicy = (work, sandbox, checkout, cache) => ({
|
|
4592
|
+
...runnerStateSandboxPolicy(sandbox.runner, [
|
|
4593
|
+
repositoryClone(sandbox.runner.workRoot, work.repoBinding.id),
|
|
4594
|
+
checkout
|
|
4595
|
+
]),
|
|
4596
|
+
writablePaths: [checkout, cache],
|
|
4597
|
+
network: agentNetworkAllowlist({ apiUrl: sandbox.apiUrl, providerHosts: [], repoBindingHost: work.repoBinding.host }),
|
|
4598
|
+
environment: srtCacheEnvironment(cache)
|
|
4599
|
+
});
|
|
4600
|
+
var checkRunner = (work, sandbox, cache) => (checkout) => (command, cwd) => {
|
|
4601
|
+
if (sandbox === undefined || sandbox.backend === undefined)
|
|
4602
|
+
return runShell2(command, { cwd, timeout: checkTimeout });
|
|
4603
|
+
const policy = checkSandboxPolicy(work, sandbox, checkout, cache);
|
|
4604
|
+
const sandboxCommand = { argv: ["sh", "-c", command], cwd, env: {}, timeout: checkTimeout };
|
|
4605
|
+
return sandbox.backend === "srt" ? runSandboxCommand({
|
|
4606
|
+
backend: "srt",
|
|
4607
|
+
policy,
|
|
4608
|
+
command: sandboxCommand,
|
|
4609
|
+
...sandbox.srtCommand === undefined ? undefined : { srtCommand: sandbox.srtCommand }
|
|
4610
|
+
}) : runSandboxCommand({
|
|
4611
|
+
backend: "docker",
|
|
4612
|
+
docker: sandbox.docker,
|
|
4613
|
+
runnerId: sandbox.runnerId,
|
|
4614
|
+
id: work.id,
|
|
4615
|
+
readOnlyPaths: [repositoryClone(sandbox.runner.workRoot, work.repoBinding.id)],
|
|
4616
|
+
policy,
|
|
4617
|
+
command: sandboxCommand
|
|
4618
|
+
});
|
|
4619
|
+
};
|
|
4620
|
+
var runChecks = (worktree, checks, tree, known, run) => gen(function* () {
|
|
4466
4621
|
const path = yield* Path;
|
|
4467
4622
|
const due = checks.filter((check) => !known.some((entry) => entry.tree === tree && entry.name === check.name && entry.command === check.command));
|
|
4468
4623
|
return yield* forEach(due, (check) => gen(function* () {
|
|
4469
4624
|
const startedAt = yield* currentTimeMillis;
|
|
4470
|
-
const ran = yield*
|
|
4471
|
-
cwd: path.join(worktree, check.workingDirectory ?? "."),
|
|
4472
|
-
timeout: checkTimeout
|
|
4473
|
-
});
|
|
4625
|
+
const ran = yield* run(check.command, path.join(worktree, check.workingDirectory ?? "."));
|
|
4474
4626
|
return {
|
|
4475
4627
|
name: check.name,
|
|
4476
4628
|
command: check.command,
|
|
@@ -4483,6 +4635,13 @@ var runChecks = (worktree, checks, tree, known) => gen(function* () {
|
|
|
4483
4635
|
});
|
|
4484
4636
|
var treeOf = (worktree) => map3(runCommand2("git", ["-C", worktree, "rev-parse", "HEAD^{tree}"]), (tree) => tree.trim());
|
|
4485
4637
|
var verificationExecutor = (input) => (work) => gen(function* () {
|
|
4638
|
+
if (input.sandbox !== undefined && input.sandbox.backend === undefined)
|
|
4639
|
+
return {
|
|
4640
|
+
status: "failed",
|
|
4641
|
+
failureSummary: "A shared Runner runs verifications only in `srt` or `docker`."
|
|
4642
|
+
};
|
|
4643
|
+
const cache = yield* (yield* FileSystem).makeTempDirectoryScoped({ prefix: "kitman-verify-cache-" });
|
|
4644
|
+
const runIn = checkRunner(work, input.sandbox, cache);
|
|
4486
4645
|
const checkouts = runCheckouts(input.rootDir);
|
|
4487
4646
|
const head = yield* checkouts.checkout({ runId: work.runId, id: work.id, baseRevision: work.revision }, work.repoBinding);
|
|
4488
4647
|
const baseline = yield* checkouts.checkout({ runId: work.runId, id: `${work.id}-baseline` }, work.repoBinding);
|
|
@@ -4490,7 +4649,7 @@ var verificationExecutor = (input) => (work) => gen(function* () {
|
|
|
4490
4649
|
const baselineTree = yield* treeOf(baseline);
|
|
4491
4650
|
const trees = headTree === baselineTree ? [headTree] : [headTree, baselineTree];
|
|
4492
4651
|
const known = yield* input.known(work, trees);
|
|
4493
|
-
const headChecks = yield* runChecks(head, work.checks, headTree, known);
|
|
4652
|
+
const headChecks = yield* runChecks(head, work.checks, headTree, known, runIn(head));
|
|
4494
4653
|
return {
|
|
4495
4654
|
status: "completed",
|
|
4496
4655
|
evidence: {
|
|
@@ -4499,12 +4658,12 @@ var verificationExecutor = (input) => (work) => gen(function* () {
|
|
|
4499
4658
|
baseline: {
|
|
4500
4659
|
revision: (yield* runCommand2("git", ["-C", baseline, "rev-parse", "HEAD"])).trim(),
|
|
4501
4660
|
tree: baselineTree,
|
|
4502
|
-
checks: yield* runChecks(baseline, work.checks, baselineTree, known)
|
|
4661
|
+
checks: yield* runChecks(baseline, work.checks, baselineTree, known, runIn(baseline))
|
|
4503
4662
|
}
|
|
4504
4663
|
}
|
|
4505
4664
|
}
|
|
4506
4665
|
};
|
|
4507
|
-
});
|
|
4666
|
+
}).pipe(scoped);
|
|
4508
4667
|
var rpcKnownEvidence = (rpc) => (work, trees) => rpc.knownEvidence({ lease: programLease(work), trees: [...trees] });
|
|
4509
4668
|
|
|
4510
4669
|
// packages/agent-runtime/src/index.ts
|
|
@@ -4552,6 +4711,7 @@ export {
|
|
|
4552
4711
|
composeAgentEnvironmentSyncPlan,
|
|
4553
4712
|
controlFailureKind,
|
|
4554
4713
|
defaultAgentRuntimeUserConfigPath,
|
|
4714
|
+
detectHarnesses2 as detectHarnesses,
|
|
4555
4715
|
dockerContainerRunner,
|
|
4556
4716
|
dockerMissing,
|
|
4557
4717
|
executeHerdrStepAttempt,
|
|
@@ -4561,8 +4721,8 @@ export {
|
|
|
4561
4721
|
herdrExecutorSurface,
|
|
4562
4722
|
herdrHarnessLayer,
|
|
4563
4723
|
herdrNativeExtensionIds2 as herdrNativeExtensionIds,
|
|
4564
|
-
|
|
4565
|
-
|
|
4724
|
+
herdrRunnerCapabilities2 as herdrRunnerCapabilities,
|
|
4725
|
+
herdrRunnerCapabilitiesForRepoBinding2 as herdrRunnerCapabilitiesForRepoBinding,
|
|
4566
4726
|
herdrSandboxBackends,
|
|
4567
4727
|
isPathWithin,
|
|
4568
4728
|
isRecord2 as isRecord,
|
|
@@ -4589,6 +4749,7 @@ export {
|
|
|
4589
4749
|
recordValue,
|
|
4590
4750
|
refuseAgentRequest,
|
|
4591
4751
|
removeRunnerContainers,
|
|
4752
|
+
repositoryClone,
|
|
4592
4753
|
repositoryUrl,
|
|
4593
4754
|
requestRecord,
|
|
4594
4755
|
resolveAgentEnvironment,
|
|
@@ -4598,21 +4759,27 @@ export {
|
|
|
4598
4759
|
rpcStepCheckpoints,
|
|
4599
4760
|
runCheckouts,
|
|
4600
4761
|
runCommand2 as runCommand,
|
|
4762
|
+
runProcess2 as runProcess,
|
|
4601
4763
|
runReplica,
|
|
4764
|
+
runSandboxCommand,
|
|
4602
4765
|
runShell2 as runShell,
|
|
4766
|
+
runnerStateSandboxPolicy,
|
|
4603
4767
|
runnerStepAttemptFromAgentStep,
|
|
4604
4768
|
setDefaultAgentRuntimeProfile,
|
|
4605
4769
|
sha2562 as sha256,
|
|
4606
4770
|
shellOutputTailChars2 as shellOutputTailChars,
|
|
4607
4771
|
shortId,
|
|
4608
4772
|
skillIdentity,
|
|
4773
|
+
srtArgv,
|
|
4609
4774
|
srtCacheEnvironment,
|
|
4610
4775
|
srtMissing,
|
|
4611
4776
|
srtSettings,
|
|
4777
|
+
startDockerSandbox,
|
|
4612
4778
|
stepSandboxPolicy,
|
|
4613
4779
|
stopOwnedHarness,
|
|
4614
4780
|
stringValue,
|
|
4615
4781
|
superviseReplica,
|
|
4616
4782
|
verificationExecutor,
|
|
4617
|
-
writeAgentEnvironmentConfigFile
|
|
4783
|
+
writeAgentEnvironmentConfigFile,
|
|
4784
|
+
writeSrtSettings
|
|
4618
4785
|
};
|