@kitman-sh/cli 0.6.0 → 0.7.1

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.
@@ -14,7 +14,7 @@ import {
14
14
  isNone,
15
15
  isSome,
16
16
  getOrUndefined,
17
- Service2,
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
- makeUnsafe2,
38
+ makeUnsafe,
38
39
  _await,
39
40
  isDoneUnsafe,
40
41
  doneUnsafe,
41
42
  Scope,
42
- make9,
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
- makeUnsafe5,
109
- make13,
110
+ make10,
110
111
  map4,
111
112
  filter,
112
113
  decodeText,
@@ -115,7 +116,7 @@ import {
115
116
  FileSystem,
116
117
  Path,
117
118
  ChildProcessSpawner,
118
- make15,
119
+ make12,
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
- herdrPiRunnerCapabilitiesForRepoBinding2,
159
- herdrPiRunnerCapabilities2,
161
+ herdrRunnerCapabilitiesForRepoBinding2,
162
+ herdrRunnerCapabilities2,
160
163
  assertHerdrRunnerCapability2
161
- } from "./chunk-txyq8r41.js";
164
+ } from "./chunk-5rp5hvc0.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-hw7qkap1.js";
173
- import"./chunk-hrvcz0m4.js";
175
+ } from "./chunk-9bje6bm0.js";
176
+ import"./chunk-tkk2synn.js";
174
177
  import {
175
- RunSettled
176
- } from "./chunk-xdk488qp.js";
177
- import"./chunk-n32jhswz.js";
178
- import {
179
- programLease
180
- } from "./chunk-fc0v325q.js";
178
+ programLease,
179
+ programHostsEnv,
180
+ undeclaredHostsEnv
181
+ } from "./chunk-2vcae278.js";
182
+ import"./chunk-23ch5vdv.js";
181
183
  import {
182
184
  nextInt
183
- } from "./chunk-brp7cekg.js";
185
+ } from "./chunk-1d2e4je3.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 = makeUnsafe4(false);
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) !== "linux")
2358
- return yield* fail3("herdr_linux_required");
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* make9();
2510
- const handle = yield* spawner.spawn(make15(input.command, [...input.args], {
2496
+ const scope = yield* make6();
2497
+ const handle = yield* spawner.spawn(make12(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 Service2()("Harness") {
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 prepareSrtPane = (input) => gen(function* () {
3012
- const settings = srtSettings(input.policy);
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 ${[...input.srtCommand, "--settings", settingsFile, "--", input.binary].map(quote).join(" ")} "$@"`,
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 prepareDockerPane = (input) => gen(function* () {
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: input.policy.writablePaths.map((writable) => ({ source: writable, target: writable })),
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 Service2()("AgentBackend") {
3346
+ class AgentBackend extends Service()("AgentBackend") {
3326
3347
  }
3327
3348
  var herdrSandboxBackends = ["host"];
3328
3349
  var refuseAgentRequest = (request, enforceable) => {
@@ -3444,185 +3465,342 @@ 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/herdr-executor.ts
3448
- var agentStepSandboxPolicy = (work, apiUrl, authStore) => ({
3449
- ...runnerAgentSandboxPolicy(),
3450
- readDeniedPaths: [...new Set([...runnerAgentSandboxPolicy().readDeniedPaths, authStore])],
3451
- network: agentNetworkAllowlist({
3452
- apiUrl,
3453
- providerHosts: harnessAdapter(work.brief.harness)?.providerHosts ?? [],
3454
- ...work.repoBinding === undefined ? undefined : { repoBindingHost: work.repoBinding.host },
3455
- ...work.network === undefined ? undefined : { agent: work.network }
3456
- })
3457
- });
3458
- function runnerStepAttemptFromAgentStep(work) {
3459
- return {
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
- var previewAgentEnvironmentPlan = fnUntraced(function* (input) {
3506
- const skills = yield* previewAgentEnvironmentMaterialization({
3507
- environment: input.environment,
3508
- ...input.rootDir === undefined ? undefined : { rootDir: input.rootDir },
3509
- ...input.scope === undefined ? undefined : { scope: input.scope },
3510
- ...input.cacheRoot === undefined ? undefined : { cacheRoot: input.cacheRoot },
3511
- ...input.noInstall === undefined ? undefined : { noInstall: input.noInstall }
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
- const harnessConfig = yield* previewAgentEnvironmentConfigSync({
3514
- environment: input.environment,
3515
- materializedSkills: skills.materializedSkills,
3516
- ...input.syncKit === undefined ? undefined : { syncKit: input.syncKit },
3517
- ...input.rootDir === undefined ? undefined : { rootDir: input.rootDir },
3518
- ...input.scope === undefined ? undefined : { scope: input.scope },
3519
- ...input.mcpCredentialName === undefined ? undefined : { mcpCredentialName: input.mcpCredentialName }
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
- return {
3522
- harness: input.environment.harness,
3523
- ...input.syncKit === undefined ? undefined : { syncKitHash: input.syncKit.syncKitHash },
3524
- skills,
3525
- harnessConfig,
3526
- operationCount: skills.operations.length + harnessConfig.operations.length,
3527
- warnings: [...skills.warnings, ...harnessConfig.warnings].map((item) => item.message)
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
- function composeAgentEnvironmentSyncPlan(targets) {
3531
- return { version: 1, planId: canonicalSha256(targets), targets };
3532
- }
3533
- var applyAgentEnvironmentPlans = fnUntraced(function* (plan) {
3534
- for (const target of plan.targets)
3535
- yield* applyAgentEnvironmentMaterialization(target.skills).pipe(mapError((cause) => new AgentEnvironmentPlanApplyError({ phase: "skills", cause })));
3536
- for (const target of plan.targets)
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
- // node_modules/.bun/effect@4.0.4/node_modules/effect/dist/internal/matcher.js
3541
- var TypeId = "~effect/Match/Matcher";
3542
- var TypeMatcherProto = {
3543
- [TypeId]: {
3544
- _input: identity,
3545
- _filters: identity,
3546
- _remaining: identity,
3547
- _result: identity,
3548
- _return: identity,
3549
- _args: identity
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
- var ValueMatcherProto = {
3566
- [TypeId]: {
3567
- _input: identity,
3568
- _filters: identity,
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
- var makeWhen = (guard, evaluate) => ({
3596
- _tag: "When",
3597
- guard,
3598
- evaluate
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 valueTags = /* @__PURE__ */ dual(2, (input, fields) => {
3601
- const match = tagsExhaustive(fields)(makeTypeMatcher(identity, []));
3602
- return match(input);
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 discriminators = (field) => (fields) => {
3605
- const predicate = makeWhen((arg) => arg != null && Object.hasOwn(fields, arg[field]), (data) => fields[data[field]](data));
3606
- return (self) => self.add(predicate);
3607
- };
3608
- var discriminatorsExhaustive = (field) => (fields) => {
3609
- const addCases = discriminators(field)(fields);
3610
- return (matcher) => exhaustive(addCases(matcher));
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 tagsExhaustive = /* @__PURE__ */ discriminatorsExhaustive("_tag");
3613
- var result2 = (self) => {
3614
- if (self._tag === "ValueMatcher") {
3615
- return self.value;
3616
- }
3617
- const len = self.cases.length;
3618
- if (len === 1) {
3619
- const _case = self.cases[0];
3620
- return (...args) => {
3621
- const input = self.select(...args);
3622
- if (_case._tag === "When" && _case.guard(input) === true) {
3623
- return succeed(_case.evaluate(input, ...args));
3624
- } else if (_case._tag === "Not" && _case.guard(input) === false) {
3625
- return succeed(_case.evaluate(input, ...args));
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));
3802
+ } else if (_case._tag === "Not" && _case.guard(input) === false) {
3803
+ return succeed(_case.evaluate(input, ...args));
3626
3804
  }
3627
3805
  return fail(input);
3628
3806
  };
@@ -3687,7 +3865,7 @@ class RunnerReplicaCancellation extends TaggedError("RunnerReplicaCancellation")
3687
3865
  }
3688
3866
  var makeReplicaSignals = sync(() => {
3689
3867
  let generation = 0;
3690
- let nextWork = makeUnsafe2();
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: makeUnsafe2(),
3701
- updated: makeUnsafe2()
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 = makeUnsafe2();
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 = makeUnsafe2();
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 = makeUnsafe2();
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 = makeUnsafe2();
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 = makeUnsafe5(1);
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) ?? makeUnsafe5(1);
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 = path.join(reposDir, repoBinding.id);
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(`${reposDir}/${repoBinding.id}`);
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(make12(mcp.command, [...mcp.args], {
4455
+ extendEnv: true,
4456
+ env: mcp.env,
4457
+ stdin: { stream: make10(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(make12(input.bun ?? process.execPath, [file], {
4530
+ stdin: make10(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 runChecks = (worktree, checks, tree, known) => gen(function* () {
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* runShell2(check.command, {
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
- herdrPiRunnerCapabilities2 as herdrPiRunnerCapabilities,
4565
- herdrPiRunnerCapabilitiesForRepoBinding2 as herdrPiRunnerCapabilitiesForRepoBinding,
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
  };