@aspectlylabs/mikka 0.0.63 → 0.0.65

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/cli.js CHANGED
@@ -264,14 +264,14 @@ var require_semver = __commonJS({
264
264
  if (!m[4]) {
265
265
  this.prerelease = [];
266
266
  } else {
267
- this.prerelease = m[4].split(".").map((id3) => {
268
- if (/^[0-9]+$/.test(id3)) {
269
- const num = +id3;
267
+ this.prerelease = m[4].split(".").map((id4) => {
268
+ if (/^[0-9]+$/.test(id4)) {
269
+ const num = +id4;
270
270
  if (num >= 0 && num < MAX_SAFE_INTEGER) {
271
271
  return num;
272
272
  }
273
273
  }
274
- return id3;
274
+ return id4;
275
275
  });
276
276
  }
277
277
  this.build = m[5] ? m[5].split(".") : [];
@@ -1140,23 +1140,23 @@ var require_range = __commonJS({
1140
1140
  debug("stars", comp);
1141
1141
  return comp;
1142
1142
  };
1143
- var isX = (id3) => !id3 || id3.toLowerCase() === "x" || id3 === "*";
1143
+ var isX = (id4) => !id4 || id4.toLowerCase() === "x" || id4 === "*";
1144
1144
  var invalidXRangeOrder = (M, m, p) => isX(M) && !isX(m) || isX(m) && p && !isX(p);
1145
1145
  var replaceTildes = (comp, options) => {
1146
1146
  return comp.trim().split(/\s+/).map((c) => replaceTilde(c, options)).join(" ");
1147
1147
  };
1148
1148
  var replaceTilde = (comp, options) => {
1149
1149
  const r = options.loose ? re[t.TILDELOOSE] : re[t.TILDE];
1150
- const z31 = options.includePrerelease ? "-0" : "";
1150
+ const z32 = options.includePrerelease ? "-0" : "";
1151
1151
  return comp.replace(r, (_, M, m, p, pr) => {
1152
1152
  debug("tilde", comp, _, M, m, p, pr);
1153
1153
  let ret;
1154
1154
  if (isX(M)) {
1155
1155
  ret = "";
1156
1156
  } else if (isX(m)) {
1157
- ret = `>=${M}.0.0${z31} <${+M + 1}.0.0-0`;
1157
+ ret = `>=${M}.0.0${z32} <${+M + 1}.0.0-0`;
1158
1158
  } else if (isX(p)) {
1159
- ret = `>=${M}.${m}.0${z31} <${M}.${+m + 1}.0-0`;
1159
+ ret = `>=${M}.${m}.0${z32} <${M}.${+m + 1}.0-0`;
1160
1160
  } else if (pr) {
1161
1161
  debug("replaceTilde pr", pr);
1162
1162
  ret = `>=${M}.${m}.${p}-${pr} <${M}.${+m + 1}.0-0`;
@@ -1173,19 +1173,19 @@ var require_range = __commonJS({
1173
1173
  var replaceCaret = (comp, options) => {
1174
1174
  debug("caret", comp, options);
1175
1175
  const r = options.loose ? re[t.CARETLOOSE] : re[t.CARET];
1176
- const z31 = options.includePrerelease ? "-0" : "";
1176
+ const z32 = options.includePrerelease ? "-0" : "";
1177
1177
  return comp.replace(r, (_, M, m, p, pr) => {
1178
1178
  debug("caret", comp, _, M, m, p, pr);
1179
1179
  let ret;
1180
1180
  if (isX(M)) {
1181
1181
  ret = "";
1182
1182
  } else if (isX(m)) {
1183
- ret = `>=${M}.0.0${z31} <${+M + 1}.0.0-0`;
1183
+ ret = `>=${M}.0.0${z32} <${+M + 1}.0.0-0`;
1184
1184
  } else if (isX(p)) {
1185
1185
  if (M === "0") {
1186
- ret = `>=${M}.${m}.0${z31} <${M}.${+m + 1}.0-0`;
1186
+ ret = `>=${M}.${m}.0${z32} <${M}.${+m + 1}.0-0`;
1187
1187
  } else {
1188
- ret = `>=${M}.${m}.0${z31} <${+M + 1}.0.0-0`;
1188
+ ret = `>=${M}.${m}.0${z32} <${+M + 1}.0.0-0`;
1189
1189
  }
1190
1190
  } else if (pr) {
1191
1191
  debug("replaceCaret pr", pr);
@@ -3210,37 +3210,91 @@ var daemonRpc = {
3210
3210
  };
3211
3211
 
3212
3212
  // ../protocol/src/device.ts
3213
- import { z as z13 } from "zod";
3213
+ import { z as z14 } from "zod";
3214
+
3215
+ // ../protocol/src/policy-snapshot.ts
3216
+ import { z as z11 } from "zod";
3217
+ var POLICY_SNAPSHOT_HEADER = "x-mikka-policy-snapshot";
3218
+ var POLICY_SNAPSHOT_VERSION = "1";
3219
+ var POLICY_SNAPSHOT_TTL_MS = 5 * 6e4;
3220
+ var POLICY_SNAPSHOT_REFRESH_MS = 3e4;
3221
+ var id = z11.string().min(1).max(128);
3222
+ var digest = z11.string().regex(/^[a-f0-9]{64}$/);
3223
+ var policyScopeSchema = z11.strictObject({
3224
+ workspaceIds: z11.array(id).max(2),
3225
+ hierarchy: z11.strictObject({ workspaceId: z11.uuid(), teamId: z11.uuid(), projectId: z11.uuid().nullable() }).nullable()
3226
+ });
3227
+ var policySnapshotPayloadSchema = z11.strictObject({
3228
+ version: z11.literal(1),
3229
+ issuer: z11.url().max(1e3),
3230
+ ownerId: id,
3231
+ deviceId: id,
3232
+ runId: id,
3233
+ revision: digest,
3234
+ policyHash: digest,
3235
+ scope: policyScopeSchema,
3236
+ policy: runPolicySchema,
3237
+ issuedAt: z11.number().int().nonnegative(),
3238
+ expiresAt: z11.number().int().nonnegative()
3239
+ });
3240
+ var signedPolicySnapshotSchema = z11.strictObject({
3241
+ algorithm: z11.literal("Ed25519"),
3242
+ keyId: digest,
3243
+ payload: policySnapshotPayloadSchema,
3244
+ signature: z11.string().regex(/^[A-Za-z0-9_-]{86}$/)
3245
+ });
3246
+ var policyDistributionContextSchema = z11.strictObject({
3247
+ version: z11.literal(1),
3248
+ algorithm: z11.literal("Ed25519"),
3249
+ keyId: digest,
3250
+ publicKey: z11.string().regex(/^[A-Za-z0-9_-]{59}$/),
3251
+ issuer: z11.url().max(1e3),
3252
+ ownerId: id,
3253
+ deviceId: id,
3254
+ runId: id,
3255
+ revision: digest,
3256
+ scope: policyScopeSchema,
3257
+ required: z11.boolean()
3258
+ });
3259
+ function policyIssuer(base) {
3260
+ const url = new URL(base);
3261
+ const loopback = ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
3262
+ if (url.username || url.password || url.search || url.hash || url.protocol !== "https:" && !(url.protocol === "http:" && loopback)) throw Error("policyIssuerInvalid");
3263
+ return `${url.origin}${url.pathname.replace(/\/+$/, "")}`;
3264
+ }
3265
+ function policySnapshotMessage(payload) {
3266
+ return new TextEncoder().encode(JSON.stringify(policySnapshotPayloadSchema.parse(payload)));
3267
+ }
3214
3268
 
3215
3269
  // ../protocol/src/skill.ts
3216
- import { z as z12 } from "zod";
3270
+ import { z as z13 } from "zod";
3217
3271
 
3218
3272
  // ../protocol/src/skill-artifact.ts
3219
- import { z as z11 } from "zod";
3273
+ import { z as z12 } from "zod";
3220
3274
  var SKILL_ARTIFACT_HEADER = "x-mikka-skill-artifacts";
3221
3275
  var TEAM_SKILL_HEADER = "x-mikka-team-skills";
3222
- var skillArtifactRefSchema = z11.object({
3223
- schemaVersion: z11.literal(1),
3224
- registryId: z11.enum(["mikka-builtin", "mikka-team"]),
3225
- skillId: z11.uuid(),
3226
- versionId: z11.uuid(),
3227
- format: z11.literal("single-skill-md-v1"),
3228
- sha256: z11.string().regex(/^[a-f0-9]{64}$/)
3276
+ var skillArtifactRefSchema = z12.object({
3277
+ schemaVersion: z12.literal(1),
3278
+ registryId: z12.enum(["mikka-builtin", "mikka-team"]),
3279
+ skillId: z12.uuid(),
3280
+ versionId: z12.uuid(),
3281
+ format: z12.literal("single-skill-md-v1"),
3282
+ sha256: z12.string().regex(/^[a-f0-9]{64}$/)
3229
3283
  }).strict();
3230
- var skillAssignmentReceiptSchema = z11.object({
3231
- id: z11.uuid(),
3232
- runId: z11.uuid(),
3233
- issueId: z11.uuid(),
3234
- agentId: z11.uuid(),
3235
- repoId: z11.uuid(),
3236
- deviceId: z11.uuid(),
3237
- leaseExpiresAt: z11.iso.datetime(),
3238
- assignedAt: z11.iso.datetime(),
3284
+ var skillAssignmentReceiptSchema = z12.object({
3285
+ id: z12.uuid(),
3286
+ runId: z12.uuid(),
3287
+ issueId: z12.uuid(),
3288
+ agentId: z12.uuid(),
3289
+ repoId: z12.uuid(),
3290
+ deviceId: z12.uuid(),
3291
+ leaseExpiresAt: z12.iso.datetime(),
3292
+ assignedAt: z12.iso.datetime(),
3239
3293
  artifact: skillArtifactRefSchema
3240
3294
  }).strict();
3241
- var skillReceiptRevalidationSchema = z11.object({
3295
+ var skillReceiptRevalidationSchema = z12.object({
3242
3296
  skillReceipt: skillAssignmentReceiptSchema,
3243
- leaseExpiresAt: z11.iso.datetime()
3297
+ leaseExpiresAt: z12.iso.datetime()
3244
3298
  }).strict();
3245
3299
 
3246
3300
  // ../protocol/src/skill.ts
@@ -3252,27 +3306,27 @@ var MAX_SKILL_FILES = 20;
3252
3306
  var MAX_SKILL_FILE_PATH_LENGTH = 200;
3253
3307
  var MAX_SKILL_FILE_CONTENT_LENGTH = 1e5;
3254
3308
  var SKILLS_HEADING = "Skills from your workspace (apply them on this task):";
3255
- var skillFilePathSchema = z12.string().min(1).max(MAX_SKILL_FILE_PATH_LENGTH).refine(
3309
+ var skillFilePathSchema = z13.string().min(1).max(MAX_SKILL_FILE_PATH_LENGTH).refine(
3256
3310
  (path) => !path.startsWith("/") && !path.includes("\\") && !path.split("/").some((segment) => segment === ".." || segment === ""),
3257
3311
  { message: "A skill file path must be relative and stay inside the skill." }
3258
3312
  );
3259
- var skillFileSchema = z12.object({
3313
+ var skillFileSchema = z13.object({
3260
3314
  path: skillFilePathSchema,
3261
- content: z12.string().max(MAX_SKILL_FILE_CONTENT_LENGTH)
3315
+ content: z13.string().max(MAX_SKILL_FILE_CONTENT_LENGTH)
3262
3316
  });
3263
- var skillFilesSchema = z12.array(skillFileSchema).max(MAX_SKILL_FILES);
3264
- var skillNameSchema = z12.string().trim().min(1).max(MAX_SKILL_NAME_LENGTH);
3265
- var skillDescriptionSchema = z12.string().trim().max(MAX_SKILL_DESCRIPTION_LENGTH);
3266
- var skillInstructionsSchema = z12.string().trim().min(1).max(MAX_SKILL_INSTRUCTIONS_LENGTH);
3267
- var runSkillSchema = z12.object({
3268
- id: z12.uuid(),
3317
+ var skillFilesSchema = z13.array(skillFileSchema).max(MAX_SKILL_FILES);
3318
+ var skillNameSchema = z13.string().trim().min(1).max(MAX_SKILL_NAME_LENGTH);
3319
+ var skillDescriptionSchema = z13.string().trim().max(MAX_SKILL_DESCRIPTION_LENGTH);
3320
+ var skillInstructionsSchema = z13.string().trim().min(1).max(MAX_SKILL_INSTRUCTIONS_LENGTH);
3321
+ var runSkillSchema = z13.object({
3322
+ id: z13.uuid(),
3269
3323
  name: skillNameSchema,
3270
- description: z12.string().nullable(),
3324
+ description: z13.string().nullable(),
3271
3325
  instructions: skillInstructionsSchema,
3272
3326
  files: skillFilesSchema
3273
3327
  });
3274
- var runSkillRefSchema = z12.object({
3275
- id: z12.uuid(),
3328
+ var runSkillRefSchema = z13.object({
3329
+ id: z13.uuid(),
3276
3330
  name: skillNameSchema
3277
3331
  });
3278
3332
  function skillSlug(name) {
@@ -3311,8 +3365,8 @@ function skillsPromptSection(skills, directory) {
3311
3365
  }
3312
3366
 
3313
3367
  // ../protocol/src/device.ts
3314
- var id = z13.string().min(1).max(64);
3315
- var isoTime = z13.iso.datetime({ offset: true });
3368
+ var id2 = z14.string().min(1).max(64);
3369
+ var isoTime = z14.iso.datetime({ offset: true });
3316
3370
  var RUN_LEASE_MS = 9e4;
3317
3371
  var seg = encodeURIComponent;
3318
3372
  var DEVICE_ROUTES = {
@@ -3339,16 +3393,16 @@ var devicePaths = {
3339
3393
  runPatch: (runId) => `/v1/runs/${seg(runId)}`,
3340
3394
  runCheckpoint: (runId) => `/v1/runs/${seg(runId)}/checkpoint`
3341
3395
  };
3342
- var deviceComputerCapability = z13.object({ installed: z13.boolean(), version: z13.string().max(100).nullable() }).strict();
3343
- var deviceRegistration = z13.object({
3344
- deviceType: z13.enum(["laptop", "server"]).optional(),
3345
- name: z13.string().trim().min(1).max(200),
3346
- hostname: z13.string().max(255).nullable().optional(),
3347
- platform: z13.string().max(50),
3348
- arch: z13.string().max(50),
3349
- daemonVersion: z13.string().max(50),
3350
- protocolVersion: z13.number().int(),
3351
- harnesses: z13.array(harnessInfoSchema).max(20),
3396
+ var deviceComputerCapability = z14.object({ installed: z14.boolean(), version: z14.string().max(100).nullable() }).strict();
3397
+ var deviceRegistration = z14.object({
3398
+ deviceType: z14.enum(["laptop", "server"]).optional(),
3399
+ name: z14.string().trim().min(1).max(200),
3400
+ hostname: z14.string().max(255).nullable().optional(),
3401
+ platform: z14.string().max(50),
3402
+ arch: z14.string().max(50),
3403
+ daemonVersion: z14.string().max(50),
3404
+ protocolVersion: z14.number().int(),
3405
+ harnesses: z14.array(harnessInfoSchema).max(20),
3352
3406
  computerUse: deviceComputerCapability.optional(),
3353
3407
  /**
3354
3408
  * This machine's one device id, the same in every workspace (ADR ORV-284).
@@ -3356,106 +3410,106 @@ var deviceRegistration = z13.object({
3356
3410
  * An id the server does not know yet becomes the new device's id; another
3357
3411
  * person's id registers a new device.
3358
3412
  */
3359
- deviceId: id.optional(),
3413
+ deviceId: id2.optional(),
3360
3414
  /** Needed only when the user belongs to more than one workspace. */
3361
- workspaceId: z13.uuid().optional()
3415
+ workspaceId: z14.uuid().optional()
3362
3416
  });
3363
- var deviceRegistered = z13.object({
3364
- deviceId: id,
3365
- workspaceId: z13.uuid()
3417
+ var deviceRegistered = z14.object({
3418
+ deviceId: id2,
3419
+ workspaceId: z14.uuid()
3366
3420
  });
3367
- var heartbeatRunSchema = z13.object({
3368
- runId: id,
3421
+ var heartbeatRunSchema = z14.object({
3422
+ runId: id2,
3369
3423
  /** Last tool call, turn boundary or file change (not raw output). */
3370
3424
  lastProgressAt: isoTime
3371
3425
  });
3372
- var deviceManagementCommand = z13.object({ id: z13.uuid(), kind: z13.enum(["redetect", "restart", "update", "uninstall"]) });
3373
- var deviceHeartbeatSchema = z13.object({
3374
- completedDeviceCommands: z13.array(z13.uuid()).max(100).optional(),
3375
- failedDeviceCommands: z13.array(z13.object({ id: z13.uuid(), error: z13.string().max(500) })).max(100).optional(),
3376
- harnesses: z13.array(harnessInfoSchema).max(20),
3426
+ var deviceManagementCommand = z14.object({ id: z14.uuid(), kind: z14.enum(["redetect", "restart", "update", "uninstall"]) });
3427
+ var deviceHeartbeatSchema = z14.object({
3428
+ completedDeviceCommands: z14.array(z14.uuid()).max(100).optional(),
3429
+ failedDeviceCommands: z14.array(z14.object({ id: z14.uuid(), error: z14.string().max(500) })).max(100).optional(),
3430
+ harnesses: z14.array(harnessInfoSchema).max(20),
3377
3431
  computerUse: deviceComputerCapability.optional(),
3378
- deviceType: z13.enum(["laptop", "server"]).optional(),
3379
- runs: z13.array(heartbeatRunSchema).max(500),
3380
- worktreeDiskBytes: z13.number().int().nonnegative(),
3432
+ deviceType: z14.enum(["laptop", "server"]).optional(),
3433
+ runs: z14.array(heartbeatRunSchema).max(500),
3434
+ worktreeDiskBytes: z14.number().int().nonnegative(),
3381
3435
  /**
3382
3436
  * Subscription windows read on this device. Absent when the daemon is not
3383
3437
  * polling. Numbers only, never a vendor credential (ADR 0027).
3384
3438
  */
3385
- quotas: z13.array(quotaSnapshotSchema).max(6).optional()
3439
+ quotas: z14.array(quotaSnapshotSchema).max(6).optional()
3386
3440
  });
3387
- var heartbeatResultSchema = z13.object({
3388
- deviceCommands: z13.array(deviceManagementCommand).max(1).optional(),
3441
+ var heartbeatResultSchema = z14.object({
3442
+ deviceCommands: z14.array(deviceManagementCommand).max(1).optional(),
3389
3443
  /** Renewed lease expiry per run id; a run missing here is not renewed. */
3390
- leases: z13.record(z13.string(), isoTime),
3444
+ leases: z14.record(z14.string(), isoTime),
3391
3445
  /**
3392
3446
  * Runs the device reported that it no longer holds: they ended on the
3393
3447
  * server, or went to another attempt after the lease ran out. The daemon
3394
3448
  * stops them now instead of when their lease runs out.
3395
3449
  */
3396
- revoked: z13.array(id).max(500).optional(),
3450
+ revoked: z14.array(id2).max(500).optional(),
3397
3451
  /** Short-lived cloud device token, returned only over its authenticated link. */
3398
- cloudCredential: z13.string().regex(/^orv_[A-Za-z0-9_-]{43}$/).optional()
3452
+ cloudCredential: z14.string().regex(/^orv_[A-Za-z0-9_-]{43}$/).optional()
3399
3453
  });
3400
3454
  var RUN_CHECKPOINT_MAX_BYTES = 8 * 1024 * 1024;
3401
3455
  var RECOVERY_WORKTREE_HEADER = "x-mikka-recovery-worktree";
3402
3456
  var RUN_CHECKPOINT_RECOVERY_MAX_AGE_MS = 30 * 6e4;
3403
- var runCheckpointSchema = z13.object({
3457
+ var runCheckpointSchema = z14.object({
3404
3458
  /** The commit the run's worktree started from. */
3405
- baseCommit: z13.string().regex(/^[0-9a-f]{40,64}$/),
3459
+ baseCommit: z14.string().regex(/^[0-9a-f]{40,64}$/),
3406
3460
  /**
3407
3461
  * `git diff --binary` from `baseCommit` to the whole worktree (tracked
3408
3462
  * and untracked files, ignored ones left out, the agent's own commits
3409
3463
  * included), gzipped, base64.
3410
3464
  */
3411
- patch: z13.string().max(Math.ceil(RUN_CHECKPOINT_MAX_BYTES * 4 / 3) + 4),
3465
+ patch: z14.string().max(Math.ceil(RUN_CHECKPOINT_MAX_BYTES * 4 / 3) + 4),
3412
3466
  /** Files the patch touches. */
3413
- files: z13.number().int().nonnegative(),
3467
+ files: z14.number().int().nonnegative(),
3414
3468
  takenAt: isoTime,
3415
3469
  /** The latest tree could not be checkpointed; it supersedes older patches. */
3416
- unavailableReason: z13.literal("too_large").optional()
3470
+ unavailableReason: z14.literal("too_large").optional()
3417
3471
  });
3418
- var setupRecipeSchema = z13.object({
3472
+ var setupRecipeSchema = z14.object({
3419
3473
  /** Paths relative to the main checkout copied into each new worktree. */
3420
- copyFiles: z13.array(z13.string().max(1e3)).max(200),
3474
+ copyFiles: z14.array(z14.string().max(1e3)).max(200),
3421
3475
  /** Shell command run in the worktree, e.g. `bun install`. */
3422
- command: z13.string().max(2e3).optional(),
3476
+ command: z14.string().max(2e3).optional(),
3423
3477
  /** Approved once per repo by the user; unapproved recipes never run. */
3424
- approved: z13.boolean()
3478
+ approved: z14.boolean()
3425
3479
  });
3426
3480
  var REPO_ORIGIN_HEADER = "x-mikka-repo-origin-check";
3427
- var deviceRepoSchema = z13.object({
3428
- repoId: id,
3429
- name: z13.string().max(500),
3481
+ var deviceRepoSchema = z14.object({
3482
+ repoId: id2,
3483
+ name: z14.string().max(500),
3430
3484
  /** Logical repository key; only trusted cloud runtimes use an absolute path. */
3431
- path: z13.string().min(1).max(4e3),
3432
- remoteUrl: z13.string().max(2e3).nullable().optional(),
3485
+ path: z14.string().min(1).max(4e3),
3486
+ remoteUrl: z14.string().max(2e3).nullable().optional(),
3433
3487
  setup: setupRecipeSchema.optional(),
3434
3488
  /** Domains agents may reach in this repo, on top of the harness's own. */
3435
- networkAllow: z13.array(z13.string().min(1).max(253)).max(200).optional(),
3489
+ networkAllow: z14.array(z14.string().min(1).max(253)).max(200).optional(),
3436
3490
  /** Push run branches after a verified hand-in ("always for this repo"). */
3437
- push: z13.object({
3438
- approved: z13.boolean(),
3439
- remote: z13.string().min(1).max(200).optional()
3491
+ push: z14.object({
3492
+ approved: z14.boolean(),
3493
+ remote: z14.string().min(1).max(200).optional()
3440
3494
  }).optional()
3441
3495
  });
3442
- var deviceReposResponse = z13.object({
3443
- repos: z13.array(deviceRepoSchema)
3496
+ var deviceReposResponse = z14.object({
3497
+ repos: z14.array(deviceRepoSchema)
3444
3498
  });
3445
- var pendingRunsResponse = z13.object({ runIds: z13.array(id) });
3499
+ var pendingRunsResponse = z14.object({ runIds: z14.array(id2) });
3446
3500
  var RUN_KINDS = ["implement", "acceptance", "fix", "plan"];
3447
- var runAssignmentSchema = z13.object({
3448
- runId: id,
3449
- issueId: id,
3450
- deviceId: id,
3451
- repoId: id,
3501
+ var runAssignmentSchema = z14.object({
3502
+ runId: id2,
3503
+ issueId: id2,
3504
+ deviceId: id2,
3505
+ repoId: id2,
3452
3506
  /** Clone URL for local runs; hosted computer assignments keep their isolated workspace. */
3453
- remoteUrl: z13.string().min(1).max(4e3).optional(),
3507
+ remoteUrl: z14.string().min(1).max(4e3).optional(),
3454
3508
  /** Absent means origin/HEAD after fetch. */
3455
- baseBranch: z13.string().min(1).max(500).optional(),
3456
- expectedRepoRemote: z13.string().max(2e3).optional(),
3509
+ baseBranch: z14.string().min(1).max(500).optional(),
3510
+ expectedRepoRemote: z14.string().max(2e3).optional(),
3457
3511
  harness: harnessSchema,
3458
- prompt: z13.string().max(1e5),
3512
+ prompt: z14.string().max(1e5),
3459
3513
  /**
3460
3514
  * The model the harness's CLI is asked to run, from the per-harness
3461
3515
  * preference of the person this run works for (ADR 0060). Absent: the
@@ -3464,42 +3518,42 @@ var runAssignmentSchema = z13.object({
3464
3518
  */
3465
3519
  model: modelNameSchema.optional(),
3466
3520
  /** Owner-bound selection only; no subscription credential enters the assignment. */
3467
- subscriptionBinding: z13.object({
3468
- bindingId: z13.uuid(),
3469
- ownerId: z13.string().min(1).max(128),
3470
- workspaceId: z13.uuid(),
3471
- consumerId: z13.uuid(),
3472
- route: z13.enum(["codex_cli", "claude_code_cli"])
3521
+ subscriptionBinding: z14.object({
3522
+ bindingId: z14.uuid(),
3523
+ ownerId: z14.string().min(1).max(128),
3524
+ workspaceId: z14.uuid(),
3525
+ consumerId: z14.uuid(),
3526
+ route: z14.enum(["codex_cli", "claude_code_cli"])
3473
3527
  }).strict().optional(),
3474
3528
  /** Local host authority comes only from the server's owner-bound Bot run. */
3475
- localComputer: z13.object({
3476
- botId: z13.uuid(),
3477
- ownerId: z13.string().min(1).max(128),
3478
- workspaceId: z13.uuid(),
3479
- policyVersion: z13.number().int().nonnegative().max(2147483647),
3480
- permission: z13.enum(["allow", "ask"])
3529
+ localComputer: z14.object({
3530
+ botId: z14.uuid(),
3531
+ ownerId: z14.string().min(1).max(128),
3532
+ workspaceId: z14.uuid(),
3533
+ policyVersion: z14.number().int().nonnegative().max(2147483647),
3534
+ permission: z14.enum(["allow", "ask"])
3481
3535
  }).strict().optional(),
3482
3536
  /** Trusted server assignment; the model cannot choose a Bot or display. */
3483
- computer: z13.object({
3484
- botId: z13.uuid(),
3485
- ownerId: z13.string().min(1).max(128),
3486
- display: z13.string().regex(/^:[1-9][0-9]{0,2}$/),
3487
- policyVersion: z13.number().int().nonnegative().max(2147483647)
3537
+ computer: z14.object({
3538
+ botId: z14.uuid(),
3539
+ ownerId: z14.string().min(1).max(128),
3540
+ display: z14.string().regex(/^:[1-9][0-9]{0,2}$/),
3541
+ policyVersion: z14.number().int().nonnegative().max(2147483647)
3488
3542
  }).strict().optional(),
3489
3543
  /**
3490
3544
  * 4e3: the task's explicit user variables (workspace + matching repository secrets/env, NAME -> value).
3491
3545
  * Cloud workers only. Passed into the task container through its own channel, never into the worker's
3492
3546
  * env, and never written to the run journal.
3493
3547
  */
3494
- taskEnv: z13.record(z13.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/), z13.string().max(65536)).optional(),
3548
+ taskEnv: z14.record(z14.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/), z14.string().max(65536)).optional(),
3495
3549
  /**
3496
3550
  * Names in `taskEnv` that are secrets (kind 'secret'; env vars are not listed). The daemon masks
3497
3551
  * their values (raw + standard base64) in run output before anything is uploaded; the server
3498
3552
  * masks again. Older daemons strip this field and rely on server-side masking only.
3499
3553
  */
3500
- taskSecretNames: z13.array(z13.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/)).max(500).optional(),
3554
+ taskSecretNames: z14.array(z14.string().regex(/^[A-Za-z_][A-Za-z0-9_]{0,127}$/)).max(500).optional(),
3501
3555
  /** Mock harness only: fixture name under `packages/daemon/fixtures`. */
3502
- fixture: z13.string().max(200).optional(),
3556
+ fixture: z14.string().max(200).optional(),
3503
3557
  /**
3504
3558
  * The issue's branch (`mikka/<team>-<number>`, ADR 0024): every run of
3505
3559
  * the issue pushes its verified commit here, so one pull request follows
@@ -3507,9 +3561,9 @@ var runAssignmentSchema = z13.object({
3507
3561
  * this branch from the remote when it exists. Without it the daemon
3508
3562
  * pushes the run's own branch.
3509
3563
  */
3510
- pushBranch: z13.string().min(1).max(250).optional(),
3564
+ pushBranch: z14.string().min(1).max(250).optional(),
3511
3565
  /** Run by the daemon in the worktree after the agent submits. */
3512
- verifyCommand: z13.string().max(2e3).optional(),
3566
+ verifyCommand: z14.string().max(2e3).optional(),
3513
3567
  /** Run lease; renewed through the device heartbeat. */
3514
3568
  leaseExpiresAt: isoTime.optional(),
3515
3569
  /**
@@ -3518,27 +3572,27 @@ var runAssignmentSchema = z13.object({
3518
3572
  * it stops working when the run ends. Absent: the server could not issue
3519
3573
  * one, and the run goes ahead without it.
3520
3574
  */
3521
- mcp: z13.object({ url: z13.url(), token: z13.string().min(1).max(200), mailbox: z13.literal(true).optional() }).optional(),
3575
+ mcp: z14.object({ url: z14.url(), token: z14.string().min(1).max(200), mailbox: z14.literal(true).optional() }).optional(),
3522
3576
  /** Agent-owned GitHub delivery; the same run token exchanges short-lived credentials. */
3523
- github: z13.object({
3524
- endpoint: z13.url(),
3525
- repository: z13.string().regex(/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/),
3526
- branch: z13.string().regex(/^mikka\/[a-z0-9-]+-[1-9][0-9]*$/)
3577
+ github: z14.object({
3578
+ endpoint: z14.url(),
3579
+ repository: z14.string().regex(/^[a-z0-9_.-]+\/[a-z0-9_.-]+$/),
3580
+ branch: z14.string().regex(/^mikka\/[a-z0-9-]+-[1-9][0-9]*$/)
3527
3581
  }).strict().optional(),
3528
3582
  /** Question continuation must not silently open a different session. */
3529
3583
  /**
3530
3584
  * What the orchestrator dispatched this run for (ADR 0023). `plan` writes a
3531
3585
  * spec and proposes a split instead of changing code (ADR ORV-205).
3532
3586
  */
3533
- kind: z13.enum(RUN_KINDS).optional(),
3587
+ kind: z14.enum(RUN_KINDS).optional(),
3534
3588
  /**
3535
3589
  * The earlier run this one continues (continue, fix, answer, a person's
3536
3590
  * message): the daemon works on in that run's worktree, on this run's
3537
3591
  * branch, so nothing the earlier run left uncommitted is lost.
3538
3592
  */
3539
- continuesRunId: id.optional(),
3593
+ continuesRunId: id2.optional(),
3540
3594
  /** A same-device retry with no usable snapshot must reuse its real worktree. */
3541
- requireWorktreeContinuation: z13.literal(true).optional(),
3595
+ requireWorktreeContinuation: z14.literal(true).optional(),
3542
3596
  /**
3543
3597
  * The latest checkpoint of the attempt this run takes over after its
3544
3598
  * machine went offline. Used only for a new worktree (another machine, or
@@ -3551,37 +3605,40 @@ var runAssignmentSchema = z13.object({
3551
3605
  * The harness session to continue. A daemon that cannot resume starts a
3552
3606
  * new session with `prompt`, which always carries the full brief.
3553
3607
  */
3554
- resumeSessionId: z13.string().max(500).optional(),
3555
- requireSessionResume: z13.boolean().optional(),
3556
- preserveQuestionWorktree: z13.boolean().optional(),
3557
- questionId: z13.uuid().optional(),
3608
+ resumeSessionId: z14.string().max(500).optional(),
3609
+ requireSessionResume: z14.boolean().optional(),
3610
+ preserveQuestionWorktree: z14.boolean().optional(),
3611
+ questionId: z14.uuid().optional(),
3558
3612
  /**
3559
3613
  * What this run adds on top of the brief (a person's message, an answer,
3560
3614
  * a fix request). A resumed session gets only this as its next message;
3561
3615
  * a new session gets `prompt`, which already includes it.
3562
3616
  */
3563
- followUp: z13.string().max(1e5).optional(),
3617
+ followUp: z14.string().max(1e5).optional(),
3564
3618
  /**
3565
3619
  * The workspace's agent permissions and network allow-list (ADR 0028).
3566
3620
  * Absent from an older server: the daemon applies the ADR 0009 defaults.
3567
3621
  */
3568
3622
  policy: runPolicySchema.optional(),
3569
3623
  /** Trusted server revision for the exact run policy; older servers omit it. */
3570
- policyRevision: z13.string().regex(/^[a-f0-9]{64}$/).optional(),
3624
+ policyRevision: z14.string().regex(/^[a-f0-9]{64}$/).optional(),
3625
+ /** Only a trusted server context can make a snapshot required. */
3626
+ policySnapshotRequired: z14.boolean().optional(),
3627
+ policySnapshot: signedPolicySnapshotSchema.optional(),
3571
3628
  /**
3572
3629
  * The skills mounted on this run's agent and still enabled, resolved at
3573
3630
  * claim time the way `policy` is. The daemon inlines them into the agent's
3574
3631
  * brief and writes them under the run's directory. Absent from an older
3575
3632
  * server: the run simply has none.
3576
3633
  */
3577
- skills: z13.array(runSkillSchema).max(MAX_SKILLS_PER_RUN).optional(),
3634
+ skills: z14.array(runSkillSchema).max(MAX_SKILLS_PER_RUN).optional(),
3578
3635
  /** Server-minted assignment provenance; does not grant any policy permission. */
3579
3636
  skillReceipt: skillAssignmentReceiptSchema.optional(),
3580
3637
  /** Frozen by the server benchmark ledger; never extracted from model output. */
3581
3638
  benchmark: runBenchmarkContext.optional()
3582
3639
  });
3583
- var runPatchSchema = z13.object({
3584
- state: z13.enum([
3640
+ var runPatchSchema = z14.object({
3641
+ state: z14.enum([
3585
3642
  "queued",
3586
3643
  "preparing",
3587
3644
  "running",
@@ -3592,73 +3649,73 @@ var runPatchSchema = z13.object({
3592
3649
  "failed",
3593
3650
  "cancelled"
3594
3651
  ]),
3595
- sessionId: z13.string().max(500).nullable().optional(),
3596
- worktree: z13.string().max(4e3).nullable().optional(),
3597
- error: z13.string().max(1e4).nullable().optional(),
3652
+ sessionId: z14.string().max(500).nullable().optional(),
3653
+ worktree: z14.string().max(4e3).nullable().optional(),
3654
+ error: z14.string().max(1e4).nullable().optional(),
3598
3655
  /** Set on every terminal state. */
3599
3656
  stopReason: runStopReason.optional()
3600
3657
  });
3601
- var runEventBatchSchema = z13.object({
3602
- fromSeq: z13.number().int().min(1),
3603
- chunks: z13.array(z13.looseObject({ type: z13.string() })).min(1).max(1e3)
3658
+ var runEventBatchSchema = z14.object({
3659
+ fromSeq: z14.number().int().min(1),
3660
+ chunks: z14.array(z14.looseObject({ type: z14.string() })).min(1).max(1e3)
3604
3661
  });
3605
- var runEventsAccepted = z13.object({
3662
+ var runEventsAccepted = z14.object({
3606
3663
  /** Producer seq of the last chunk the server holds for this run. */
3607
- offset: z13.string()
3664
+ offset: z14.string()
3608
3665
  });
3609
3666
  var COMMANDS_MAX_WAIT_SECONDS = 25;
3610
3667
  var COMMANDS_SKIP_PARAM = "skip";
3611
3668
  var COMMANDS_MAX_SKIP = 100;
3612
- var runCommandSchema = z13.discriminatedUnion("kind", [
3613
- z13.object({
3614
- kind: z13.literal("input"),
3615
- runId: id,
3616
- messageId: z13.uuid(),
3617
- text: z13.string().min(1).max(1e5)
3669
+ var runCommandSchema = z14.discriminatedUnion("kind", [
3670
+ z14.object({
3671
+ kind: z14.literal("input"),
3672
+ runId: id2,
3673
+ messageId: z14.uuid(),
3674
+ text: z14.string().min(1).max(1e5)
3618
3675
  }),
3619
- z13.object({ kind: z13.literal("stop"), runId: id })
3676
+ z14.object({ kind: z14.literal("stop"), runId: id2 })
3620
3677
  ]);
3621
- var runCommandsResponse = z13.object({
3622
- commands: z13.array(runCommandSchema).max(500)
3678
+ var runCommandsResponse = z14.object({
3679
+ commands: z14.array(runCommandSchema).max(500)
3623
3680
  });
3624
- var runCommandsAck = z13.object({
3625
- delivered: z13.array(z13.uuid()).max(500)
3681
+ var runCommandsAck = z14.object({
3682
+ delivered: z14.array(z14.uuid()).max(500)
3626
3683
  });
3627
3684
  var FS_REQUESTS_MAX_WAIT_SECONDS = 25;
3628
3685
  var FS_MAX_ENTRIES = 500;
3629
- var fsBrowseRequest = z13.object({
3686
+ var fsBrowseRequest = z14.object({
3630
3687
  /** Absolute path on the device; omitted: the device's home folder. */
3631
- path: z13.string().trim().min(1).max(4e3).optional(),
3632
- showHidden: z13.boolean().optional()
3688
+ path: z14.string().trim().min(1).max(4e3).optional(),
3689
+ showHidden: z14.boolean().optional()
3633
3690
  });
3634
- var fsPendingRequest = fsBrowseRequest.extend({ id: z13.uuid() });
3635
- var fsRequestsResponse = z13.object({
3636
- requests: z13.array(fsPendingRequest).max(50)
3691
+ var fsPendingRequest = fsBrowseRequest.extend({ id: z14.uuid() });
3692
+ var fsRequestsResponse = z14.object({
3693
+ requests: z14.array(fsPendingRequest).max(50)
3637
3694
  });
3638
- var fsEntry = z13.object({
3639
- name: z13.string().max(1e3),
3640
- path: z13.string().max(4e3),
3695
+ var fsEntry = z14.object({
3696
+ name: z14.string().max(1e3),
3697
+ path: z14.string().max(4e3),
3641
3698
  /** The folder is the top level of a git repo (it has a `.git`). */
3642
- isRepo: z13.boolean()
3699
+ isRepo: z14.boolean()
3643
3700
  });
3644
- var fsListing = z13.object({
3645
- ok: z13.literal(true),
3646
- path: z13.string().max(4e3),
3701
+ var fsListing = z14.object({
3702
+ ok: z14.literal(true),
3703
+ path: z14.string().max(4e3),
3647
3704
  /** Null at the filesystem root. */
3648
- parent: z13.string().max(4e3).nullable(),
3649
- home: z13.string().max(4e3),
3705
+ parent: z14.string().max(4e3).nullable(),
3706
+ home: z14.string().max(4e3),
3650
3707
  /** `darwin`, `linux`, `win32`: for path separators and wording. */
3651
- platform: z13.string().max(50),
3652
- entries: z13.array(fsEntry).max(FS_MAX_ENTRIES),
3708
+ platform: z14.string().max(50),
3709
+ entries: z14.array(fsEntry).max(FS_MAX_ENTRIES),
3653
3710
  /** More folders existed than `FS_MAX_ENTRIES`. */
3654
- truncated: z13.boolean(),
3711
+ truncated: z14.boolean(),
3655
3712
  /**
3656
3713
  * The git repo `path` is in, if any: its top level and `origin` (or the
3657
3714
  * first remote). This is what `device.addRepo` should be given.
3658
3715
  */
3659
- repo: z13.object({
3660
- path: z13.string().max(4e3),
3661
- remoteUrl: z13.string().max(2e3).nullable()
3716
+ repo: z14.object({
3717
+ path: z14.string().max(4e3),
3718
+ remoteUrl: z14.string().max(2e3).nullable()
3662
3719
  }).nullable()
3663
3720
  });
3664
3721
  var FS_ERROR_CODES = [
@@ -3667,12 +3724,12 @@ var FS_ERROR_CODES = [
3667
3724
  "denied",
3668
3725
  "failed"
3669
3726
  ];
3670
- var fsFailure = z13.object({
3671
- ok: z13.literal(false),
3672
- code: z13.enum(FS_ERROR_CODES),
3673
- message: z13.string().max(1e3)
3727
+ var fsFailure = z14.object({
3728
+ ok: z14.literal(false),
3729
+ code: z14.enum(FS_ERROR_CODES),
3730
+ message: z14.string().max(1e3)
3674
3731
  });
3675
- var fsResult = z13.discriminatedUnion("ok", [fsListing, fsFailure]);
3732
+ var fsResult = z14.discriminatedUnion("ok", [fsListing, fsFailure]);
3676
3733
  var fsPaths = {
3677
3734
  browse: (deviceId) => `/v1/devices/${seg(deviceId)}/fs/browse`,
3678
3735
  requests: (deviceId, waitSeconds) => `/v1/devices/${seg(deviceId)}/fs/requests?wait=${waitSeconds}`,
@@ -3680,38 +3737,38 @@ var fsPaths = {
3680
3737
  };
3681
3738
 
3682
3739
  // ../protocol/src/orchestrator.ts
3683
- import { z as z14 } from "zod";
3740
+ import { z as z15 } from "zod";
3684
3741
  var minutes = (n) => n * 6e4;
3685
- var orchestratorSettingsSchema = z14.object({
3742
+ var orchestratorSettingsSchema = z15.object({
3686
3743
  /** "Continue" prompts after a turn ended without a submit. */
3687
- maxContinuations: z14.number().int().min(0).max(20).default(3),
3744
+ maxContinuations: z15.number().int().min(0).max(20).default(3),
3688
3745
  /** Resumes after the CLI crashed, before one fresh session. */
3689
- maxCrashRetries: z14.number().int().min(0).max(20).default(3),
3746
+ maxCrashRetries: z15.number().int().min(0).max(20).default(3),
3690
3747
  /** Fix rounds after the daemon's verify failed. */
3691
- maxFixAttempts: z14.number().int().min(0).max(20).default(3),
3748
+ maxFixAttempts: z15.number().int().min(0).max(20).default(3),
3692
3749
  /** "You seem stuck" prompts after a run stalled. */
3693
- maxStallRecoveries: z14.number().int().min(0).max(20).default(2),
3750
+ maxStallRecoveries: z15.number().int().min(0).max(20).default(2),
3694
3751
  /** No progress for this long while the lease is fresh = stalled. */
3695
- stalledAfterMs: z14.number().int().min(minutes(1)).default(minutes(10)),
3752
+ stalledAfterMs: z15.number().int().min(minutes(1)).default(minutes(10)),
3696
3753
  /** A device offline this long is handed to a person (no auto switch). */
3697
- deviceOfflineEscalateMs: z14.number().int().min(0).default(minutes(30)),
3754
+ deviceOfflineEscalateMs: z15.number().int().min(0).default(minutes(30)),
3698
3755
  /** An unanswered question frees its concurrency slot after this. */
3699
- questionSlotReleaseMs: z14.number().int().min(0).default(minutes(24 * 60)),
3756
+ questionSlotReleaseMs: z15.number().int().min(0).default(minutes(24 * 60)),
3700
3757
  /** Automatic dispatches per issue per hour before a person looks. */
3701
- maxDispatchesPerHour: z14.number().int().min(1).max(100).default(6),
3758
+ maxDispatchesPerHour: z15.number().int().min(1).max(100).default(6),
3702
3759
  /** Wait before resuming a run that hit its quota (no reset time known). */
3703
- quotaBackoffMs: z14.number().int().min(0).default(minutes(15)),
3760
+ quotaBackoffMs: z15.number().int().min(0).default(minutes(15)),
3704
3761
  /**
3705
3762
  * How often an issue waiting on its pull request or CI asks GitHub again
3706
3763
  * when no webhook arrived (ADR 0024).
3707
3764
  */
3708
- ciRecheckMs: z14.number().int().min(3e4).default(minutes(2)),
3765
+ ciRecheckMs: z15.number().int().min(3e4).default(minutes(2)),
3709
3766
  /** A pushed commit with no checks after this long has no CI: it passes. */
3710
- ciNoChecksMs: z14.number().int().min(0).default(minutes(5)),
3767
+ ciNoChecksMs: z15.number().int().min(0).default(minutes(5)),
3711
3768
  /** CI still running after this long goes to a person. */
3712
- ciTimeoutMs: z14.number().int().min(minutes(5)).default(minutes(120)),
3769
+ ciTimeoutMs: z15.number().int().min(minutes(5)).default(minutes(120)),
3713
3770
  /** Remote URL of the repo this project's issues run in. */
3714
- repoUrl: z14.string().max(2e3).optional()
3771
+ repoUrl: z15.string().max(2e3).optional()
3715
3772
  });
3716
3773
  var CRASH_BACKOFF_MS = [1e4, 6e4, minutes(5)];
3717
3774
  var UPSTREAM_RECHECK_MS = minutes(5);
@@ -3755,30 +3812,30 @@ var WAIT_DETAIL_CODES = [
3755
3812
  ...PERSON_WAIT_DETAIL_CODES,
3756
3813
  ...EXTERNAL_WAIT_DETAIL_CODES
3757
3814
  ];
3758
- var waitDetailSchema = z14.object({
3759
- code: z14.enum(WAIT_DETAIL_CODES),
3760
- params: z14.record(
3761
- z14.string(),
3762
- z14.union([
3763
- z14.string(),
3764
- z14.number(),
3765
- z14.array(z14.string()),
3815
+ var waitDetailSchema = z15.object({
3816
+ code: z15.enum(WAIT_DETAIL_CODES),
3817
+ params: z15.record(
3818
+ z15.string(),
3819
+ z15.union([
3820
+ z15.string(),
3821
+ z15.number(),
3822
+ z15.array(z15.string()),
3766
3823
  // `repo_ambiguous`: the repos a person can pick from.
3767
- z14.array(z14.record(z14.string(), z14.string()))
3824
+ z15.array(z15.record(z15.string(), z15.string()))
3768
3825
  ])
3769
3826
  ).optional()
3770
3827
  });
3771
- var prChecksSchema = z14.object({
3772
- state: z14.enum(["pending", "success", "failure", "none"]),
3828
+ var prChecksSchema = z15.object({
3829
+ state: z15.enum(["pending", "success", "failure", "none"]),
3773
3830
  /** Failed checks, for the fix round's brief and the issue page. */
3774
- failing: z14.array(
3775
- z14.object({
3776
- name: z14.string().max(500),
3777
- summary: z14.string().max(4e3).optional(),
3778
- url: z14.string().max(2e3).optional()
3831
+ failing: z15.array(
3832
+ z15.object({
3833
+ name: z15.string().max(500),
3834
+ summary: z15.string().max(4e3).optional(),
3835
+ url: z15.string().max(2e3).optional()
3779
3836
  })
3780
3837
  ).max(50),
3781
- total: z14.number().int().min(0)
3838
+ total: z15.number().int().min(0)
3782
3839
  });
3783
3840
  var DEFAULT_BRANCH_TEMPLATE = "mikka/{team}-{number}";
3784
3841
  var BRANCH_FORBIDDEN = /[\s~^:?*[\\]|\.\.|@\{|\/\/|^\/|\/$/;
@@ -3787,29 +3844,29 @@ var hasControlCharacter = (value) => [...value].some((char) => {
3787
3844
  const code = char.charCodeAt(0);
3788
3845
  return code < 32 || code === 127;
3789
3846
  });
3790
- var branchTemplateSchema = z14.string().trim().min(1).max(200).refine((value) => value.includes("{number}"), {
3847
+ var branchTemplateSchema = z15.string().trim().min(1).max(200).refine((value) => value.includes("{number}"), {
3791
3848
  message: "The template must contain {number}."
3792
3849
  }).refine(
3793
3850
  (value) => !BRANCH_FORBIDDEN.test(value) && !hasControlCharacter(value),
3794
3851
  { message: BRANCH_FORBIDDEN_HINT }
3795
3852
  );
3796
- var prBodyTemplateSchema = z14.string().max(2e4).nullable().optional();
3853
+ var prBodyTemplateSchema = z15.string().max(2e4).nullable().optional();
3797
3854
  var REVIEW_CHECK_HARNESSES = [
3798
3855
  "claude_code",
3799
3856
  "codex",
3800
3857
  "cursor"
3801
3858
  ];
3802
- var reviewRuleSchema = z14.object({
3859
+ var reviewRuleSchema = z15.object({
3803
3860
  /** In Review needs an open pull request for the issue's branch (ADR 0024). */
3804
- requirePullRequest: z14.boolean().default(true),
3861
+ requirePullRequest: z15.boolean().default(true),
3805
3862
  /** ... and green CI on it. Ignored when no pull request is required. */
3806
- requireCi: z14.boolean().default(true),
3863
+ requireCi: z15.boolean().default(true),
3807
3864
  /**
3808
3865
  * The harness that must run the read-only check (ADR 0046). Null: any
3809
3866
  * second agent on the device. A configured harness the device does not run
3810
3867
  * means no check runs, exactly as if the device had no second agent.
3811
3868
  */
3812
- checkHarness: z14.enum(REVIEW_CHECK_HARNESSES).nullable().default(null),
3869
+ checkHarness: z15.enum(REVIEW_CHECK_HARNESSES).nullable().default(null),
3813
3870
  branchTemplate: branchTemplateSchema.default(DEFAULT_BRANCH_TEMPLATE),
3814
3871
  /** `{key}`, `{title}` and `{summary}`; null keeps Mikka's default text. */
3815
3872
  prBodyTemplate: prBodyTemplateSchema.default(null)
@@ -3834,9 +3891,9 @@ var WEB_PLATFORM = Object.freeze({
3834
3891
  });
3835
3892
 
3836
3893
  // ../protocol/src/preview.ts
3837
- import { z as z15 } from "zod";
3894
+ import { z as z16 } from "zod";
3838
3895
  var PREVIEW_MAX_LENGTH = 5 * 1024 * 1024;
3839
- var previewHtml = z15.string().max(PREVIEW_MAX_LENGTH);
3896
+ var previewHtml = z16.string().max(PREVIEW_MAX_LENGTH);
3840
3897
  var DIRECTIVES = [
3841
3898
  "default-src 'none'",
3842
3899
  "script-src 'unsafe-inline'",
@@ -3853,13 +3910,13 @@ var PREVIEW_CSP_HEADER = ["sandbox allow-scripts", ...DIRECTIVES].join(
3853
3910
  var META = `<meta http-equiv="Content-Security-Policy" content="${DIRECTIVES.join("; ")}">`;
3854
3911
 
3855
3912
  // ../protocol/src/profile.ts
3856
- import { z as z16 } from "zod";
3857
- var usernameSchema = z16.string().trim().min(3, "At least 3 characters.").max(32, "At most 32 characters.").regex(
3913
+ import { z as z17 } from "zod";
3914
+ var usernameSchema = z17.string().trim().min(3, "At least 3 characters.").max(32, "At most 32 characters.").regex(
3858
3915
  /^[a-z0-9][a-z0-9_-]*$/,
3859
3916
  "Start with a letter or digit; lowercase letters, digits, - and _ only."
3860
3917
  );
3861
- var displayNameSchema = z16.string().trim().min(1, "A name is required.").max(80, "At most 80 characters.");
3862
- var avatarUrlSchema = z16.url().max(2048).refine((value) => /^https?:\/\//.test(value), "Use an http(s) URL.");
3918
+ var displayNameSchema = z17.string().trim().min(1, "A name is required.").max(80, "At most 80 characters.");
3919
+ var avatarUrlSchema = z17.url().max(2048).refine((value) => /^https?:\/\//.test(value), "Use an http(s) URL.");
3863
3920
  var AVATAR_MAX_BYTES = 5 * 1024 * 1024;
3864
3921
  var AVATAR_CONTENT_TYPES = [
3865
3922
  "image/png",
@@ -3867,16 +3924,16 @@ var AVATAR_CONTENT_TYPES = [
3867
3924
  "image/webp",
3868
3925
  "image/gif"
3869
3926
  ];
3870
- var avatarPresignRequest = z16.object({
3871
- contentType: z16.enum(AVATAR_CONTENT_TYPES),
3927
+ var avatarPresignRequest = z17.object({
3928
+ contentType: z17.enum(AVATAR_CONTENT_TYPES),
3872
3929
  /** Bytes, checked against AVATAR_MAX_BYTES. */
3873
- size: z16.number().int().positive()
3930
+ size: z17.number().int().positive()
3874
3931
  });
3875
- var avatarPresignResponse = z16.object({
3876
- uploadUrl: z16.url(),
3932
+ var avatarPresignResponse = z17.object({
3933
+ uploadUrl: z17.url(),
3877
3934
  /** What to store in `user.image` once the PUT has succeeded. */
3878
3935
  publicUrl: avatarUrlSchema,
3879
- expiresIn: z16.number().int().positive()
3936
+ expiresIn: z17.number().int().positive()
3880
3937
  });
3881
3938
 
3882
3939
  // ../protocol/src/relay.ts
@@ -3885,31 +3942,31 @@ import {
3885
3942
  safeValidateUIMessages,
3886
3943
  uiMessageChunkSchema
3887
3944
  } from "ai";
3888
- import { z as z17 } from "zod";
3945
+ import { z as z18 } from "zod";
3889
3946
  var RELAY_PROTOCOL_VERSION = 1;
3890
3947
  var MAX_INPUT_LENGTH = 2e4;
3891
- var uuid = z17.uuid();
3892
- var runEvent = z17.discriminatedUnion("kind", [
3948
+ var uuid = z18.uuid();
3949
+ var runEvent = z18.discriminatedUnion("kind", [
3893
3950
  /** One streaming chunk of the unfinished message `messageId`. */
3894
- z17.object({
3895
- kind: z17.literal("chunk"),
3951
+ z18.object({
3952
+ kind: z18.literal("chunk"),
3896
3953
  messageId: uuid,
3897
- chunk: z17.looseObject({ type: z17.string() })
3954
+ chunk: z18.looseObject({ type: z18.string() })
3898
3955
  }),
3899
3956
  /** A finished message; persisted as a `message` row, then fanned out. */
3900
- z17.object({
3901
- kind: z17.literal("message.final"),
3957
+ z18.object({
3958
+ kind: z18.literal("message.final"),
3902
3959
  /** Order of the message within the run. */
3903
- seq: z17.number().int().min(0),
3904
- message: z17.looseObject({
3960
+ seq: z18.number().int().min(0),
3961
+ message: z18.looseObject({
3905
3962
  id: uuid,
3906
- role: z17.enum(["system", "user", "assistant"]),
3907
- parts: z17.array(z17.looseObject({ type: z17.string() }))
3963
+ role: z18.enum(["system", "user", "assistant"]),
3964
+ parts: z18.array(z18.looseObject({ type: z18.string() }))
3908
3965
  })
3909
3966
  }),
3910
- z17.object({
3911
- kind: z17.literal("run.status"),
3912
- status: z17.enum([
3967
+ z18.object({
3968
+ kind: z18.literal("run.status"),
3969
+ status: z18.enum([
3913
3970
  "queued",
3914
3971
  "preparing",
3915
3972
  "running",
@@ -3922,48 +3979,48 @@ var runEvent = z17.discriminatedUnion("kind", [
3922
3979
  })
3923
3980
  ]);
3924
3981
  var chunkSchema = asSchema(uiMessageChunkSchema);
3925
- var v = z17.literal(RELAY_PROTOCOL_VERSION);
3926
- var presenceView = z17.discriminatedUnion("type", [
3927
- z17.object({ type: z17.literal("issue"), id: uuid }),
3928
- z17.object({ type: z17.literal("project"), id: uuid })
3982
+ var v = z18.literal(RELAY_PROTOCOL_VERSION);
3983
+ var presenceView = z18.discriminatedUnion("type", [
3984
+ z18.object({ type: z18.literal("issue"), id: uuid }),
3985
+ z18.object({ type: z18.literal("project"), id: uuid })
3929
3986
  ]);
3930
- var relayClientMessage = z17.discriminatedUnion("type", [
3931
- z17.object({
3987
+ var relayClientMessage = z18.discriminatedUnion("type", [
3988
+ z18.object({
3932
3989
  v,
3933
- type: z17.literal("subscribe"),
3990
+ type: z18.literal("subscribe"),
3934
3991
  runId: uuid,
3935
3992
  /** Resume after this seq; omitted = everything still buffered. */
3936
- after: z17.number().int().min(0).optional()
3993
+ after: z18.number().int().min(0).optional()
3937
3994
  }),
3938
- z17.object({ v, type: z17.literal("unsubscribe"), runId: uuid }),
3939
- z17.object({ v, type: z17.literal("publish"), runId: uuid, event: runEvent }),
3995
+ z18.object({ v, type: z18.literal("unsubscribe"), runId: uuid }),
3996
+ z18.object({ v, type: z18.literal("publish"), runId: uuid, event: runEvent }),
3940
3997
  /**
3941
3998
  * A person's message to the running agent (ADR 0018). Saved as a `user`
3942
3999
  * message row with this id (a re-send with the same id is applied once),
3943
4000
  * then handed to the run's daemon, which marks it delivered.
3944
4001
  */
3945
- z17.object({
4002
+ z18.object({
3946
4003
  v,
3947
- type: z17.literal("send"),
4004
+ type: z18.literal("send"),
3948
4005
  runId: uuid,
3949
4006
  messageId: uuid,
3950
- text: z17.string().trim().min(1).max(MAX_INPUT_LENGTH)
4007
+ text: z18.string().trim().min(1).max(MAX_INPUT_LENGTH)
3951
4008
  }),
3952
4009
  /** A person stops the run; the daemon cancels the agent's session. */
3953
- z17.object({ v, type: z17.literal("stop"), runId: uuid }),
4010
+ z18.object({ v, type: z18.literal("stop"), runId: uuid }),
3954
4011
  /**
3955
4012
  * Says where this connection is looking, in one workspace (ADR 0049). Sent
3956
4013
  * once when a page opens and again every `PRESENCE_HEARTBEAT_MS`; `view`
3957
4014
  * null keeps the member online without naming a page. Never persisted.
3958
4015
  */
3959
- z17.object({
4016
+ z18.object({
3960
4017
  v,
3961
- type: z17.literal("presence"),
4018
+ type: z18.literal("presence"),
3962
4019
  workspaceId: uuid,
3963
4020
  view: presenceView.nullable()
3964
4021
  }),
3965
4022
  /** Stops announcing in a workspace; the member leaves its viewer list. */
3966
- z17.object({ v, type: z17.literal("presence.leave"), workspaceId: uuid })
4023
+ z18.object({ v, type: z18.literal("presence.leave"), workspaceId: uuid })
3967
4024
  ]);
3968
4025
  var RELAY_ERROR_CODES = [
3969
4026
  "bad_message",
@@ -3977,215 +4034,215 @@ var RELAY_ERROR_CODES = [
3977
4034
  /** `presence` for a workspace the caller is not a member of (ADR 0049). */
3978
4035
  "not_a_member"
3979
4036
  ];
3980
- var relayErrorCode = z17.enum(RELAY_ERROR_CODES);
3981
- var relayServerMessage = z17.discriminatedUnion("type", [
3982
- z17.object({
4037
+ var relayErrorCode = z18.enum(RELAY_ERROR_CODES);
4038
+ var relayServerMessage = z18.discriminatedUnion("type", [
4039
+ z18.object({
3983
4040
  v,
3984
- type: z17.literal("subscribed"),
4041
+ type: z18.literal("subscribed"),
3985
4042
  runId: uuid,
3986
- latestSeq: z17.number().int().min(0)
4043
+ latestSeq: z18.number().int().min(0)
3987
4044
  }),
3988
- z17.object({
4045
+ z18.object({
3989
4046
  v,
3990
- type: z17.literal("event"),
4047
+ type: z18.literal("event"),
3991
4048
  runId: uuid,
3992
- seq: z17.number().int().min(1),
4049
+ seq: z18.number().int().min(1),
3993
4050
  event: runEvent
3994
4051
  }),
3995
4052
  /**
3996
4053
  * `send` / `stop` was saved and is on its way to the run's device.
3997
4054
  * `messageId` is set for `send`.
3998
4055
  */
3999
- z17.object({
4056
+ z18.object({
4000
4057
  v,
4001
- type: z17.literal("accepted"),
4058
+ type: z18.literal("accepted"),
4002
4059
  runId: uuid,
4003
- request: z17.enum(["send", "stop"]),
4060
+ request: z18.enum(["send", "stop"]),
4004
4061
  messageId: uuid.optional()
4005
4062
  }),
4006
4063
  /** Publisher acknowledgment with the seq the hub assigned. */
4007
- z17.object({
4064
+ z18.object({
4008
4065
  v,
4009
- type: z17.literal("ack"),
4066
+ type: z18.literal("ack"),
4010
4067
  runId: uuid,
4011
- seq: z17.number().int().min(1)
4068
+ seq: z18.number().int().min(1)
4012
4069
  }),
4013
4070
  /**
4014
4071
  * Everyone the server sees online in this workspace, and where each is
4015
4072
  * looking (ADR 0049). A snapshot after every change, so a client never has
4016
4073
  * to merge deltas; `lastSeenAt` is the server's clock.
4017
4074
  */
4018
- z17.object({
4075
+ z18.object({
4019
4076
  v,
4020
- type: z17.literal("presence"),
4077
+ type: z18.literal("presence"),
4021
4078
  workspaceId: uuid,
4022
- members: z17.array(
4023
- z17.object({
4079
+ members: z18.array(
4080
+ z18.object({
4024
4081
  userId: uuid,
4025
4082
  view: presenceView.nullable(),
4026
- lastSeenAt: z17.number().int()
4083
+ lastSeenAt: z18.number().int()
4027
4084
  })
4028
4085
  )
4029
4086
  }),
4030
- z17.object({
4087
+ z18.object({
4031
4088
  v,
4032
- type: z17.literal("error"),
4089
+ type: z18.literal("error"),
4033
4090
  code: relayErrorCode,
4034
- message: z17.string(),
4091
+ message: z18.string(),
4035
4092
  runId: uuid.optional(),
4036
- minVersion: z17.string().optional()
4093
+ minVersion: z18.string().optional()
4037
4094
  })
4038
4095
  ]);
4039
4096
 
4040
4097
  // ../protocol/src/version.ts
4041
4098
  var import_semver = __toESM(require_semver2(), 1);
4042
- import { z as z18 } from "zod";
4099
+ import { z as z19 } from "zod";
4043
4100
  var CLIENT_VERSION_HEADER = "x-mikka-client-version";
4044
4101
  var CLIENT_KINDS = ["desktop", "mobile"];
4045
- var clientKind = z18.enum(CLIENT_KINDS);
4046
- var updateRequiredError = z18.object({
4047
- error: z18.literal("update_required"),
4048
- minVersion: z18.string(),
4049
- message: z18.string()
4102
+ var clientKind = z19.enum(CLIENT_KINDS);
4103
+ var updateRequiredError = z19.object({
4104
+ error: z19.literal("update_required"),
4105
+ minVersion: z19.string(),
4106
+ message: z19.string()
4050
4107
  });
4051
4108
 
4052
4109
  // ../protocol/src/coordinator.ts
4053
- import { z as z19 } from "zod";
4054
- var coordinatorRuntimeSchema = z19.discriminatedUnion("harness", [
4055
- z19.object({ harness: z19.literal("ai_sdk") }).strict(),
4056
- z19.object({ harness: z19.enum(["claude_code", "codex"]), deviceId: z19.uuid(), model: z19.string().trim().min(1).max(120).optional() }).strict()
4110
+ import { z as z20 } from "zod";
4111
+ var coordinatorRuntimeSchema = z20.discriminatedUnion("harness", [
4112
+ z20.object({ harness: z20.literal("ai_sdk") }).strict(),
4113
+ z20.object({ harness: z20.enum(["claude_code", "codex"]), deviceId: z20.uuid(), model: z20.string().trim().min(1).max(120).optional() }).strict()
4057
4114
  ]);
4058
- var coordinatorToolSpecSchema = z19.object({
4059
- name: z19.string().regex(/^[A-Za-z][A-Za-z0-9_]{0,63}$/),
4060
- description: z19.string().max(2e4),
4061
- inputSchema: z19.record(z19.string(), z19.unknown())
4115
+ var coordinatorToolSpecSchema = z20.object({
4116
+ name: z20.string().regex(/^[A-Za-z][A-Za-z0-9_]{0,63}$/),
4117
+ description: z20.string().max(2e4),
4118
+ inputSchema: z20.record(z20.string(), z20.unknown())
4062
4119
  });
4063
- var nativeCoordinatorJobSchema = z19.object({
4064
- id: z19.uuid(),
4065
- harness: z19.enum(["claude_code", "codex"]),
4066
- model: z19.string().optional(),
4067
- instructions: z19.string().min(1).max(2e5),
4068
- context: z19.string().min(1).max(5e5),
4069
- tools: z19.array(coordinatorToolSpecSchema).max(100),
4070
- expiresAt: z19.iso.datetime()
4120
+ var nativeCoordinatorJobSchema = z20.object({
4121
+ id: z20.uuid(),
4122
+ harness: z20.enum(["claude_code", "codex"]),
4123
+ model: z20.string().optional(),
4124
+ instructions: z20.string().min(1).max(2e5),
4125
+ context: z20.string().min(1).max(5e5),
4126
+ tools: z20.array(coordinatorToolSpecSchema).max(100),
4127
+ expiresAt: z20.iso.datetime()
4071
4128
  });
4072
- var nativeCoordinatorClaimSchema = z19.object({ job: nativeCoordinatorJobSchema.nullable() });
4073
- var nativeCoordinatorCommandSchema = z19.discriminatedUnion("type", [
4074
- z19.object({ type: z19.literal("tool"), callId: z19.string().min(1).max(200), name: z19.string().min(1).max(64), input: z19.record(z19.string(), z19.unknown()) }).strict(),
4075
- z19.object({ type: z19.literal("complete"), text: z19.string().min(1).max(2e5).refine((value) => value.trim().length > 0) }).strict(),
4076
- z19.object({ type: z19.literal("failed") }).strict()
4129
+ var nativeCoordinatorClaimSchema = z20.object({ job: nativeCoordinatorJobSchema.nullable() });
4130
+ var nativeCoordinatorCommandSchema = z20.discriminatedUnion("type", [
4131
+ z20.object({ type: z20.literal("tool"), callId: z20.string().min(1).max(200), name: z20.string().min(1).max(64), input: z20.record(z20.string(), z20.unknown()) }).strict(),
4132
+ z20.object({ type: z20.literal("complete"), text: z20.string().min(1).max(2e5).refine((value) => value.trim().length > 0) }).strict(),
4133
+ z20.object({ type: z20.literal("failed") }).strict()
4077
4134
  ]);
4078
- var nativeCoordinatorToolResultSchema = z19.discriminatedUnion("status", [
4079
- z19.object({ status: z19.literal("pending") }),
4080
- z19.object({ status: z19.literal("done"), output: z19.unknown() })
4135
+ var nativeCoordinatorToolResultSchema = z20.discriminatedUnion("status", [
4136
+ z20.object({ status: z20.literal("pending") }),
4137
+ z20.object({ status: z20.literal("done"), output: z20.unknown() })
4081
4138
  ]);
4082
4139
 
4083
4140
  // ../protocol/src/computer.ts
4084
- import { z as z20 } from "zod";
4085
- var machineStateSchema = z20.enum(["sleeping", "waking", "running", "error"]);
4086
- var controlStateSchema = z20.enum(["agent", "user", "idle"]);
4087
- var computerToolSchema = z20.enum(["click", "type", "key", "scroll", "screenshot"]);
4088
- var screenRectSchema = z20.object({ x: z20.number(), y: z20.number(), w: z20.number().nonnegative(), h: z20.number().nonnegative() });
4089
- var computerActionSchema = z20.object({ tool: computerToolSchema, x: z20.number().optional(), y: z20.number().optional(), text: z20.string().optional(), rect: screenRectSchema.optional() });
4090
- var lastActionSchema = computerActionSchema.omit({ text: true }).extend({ at: z20.iso.datetime() });
4091
- var approvalViewSchema = z20.object({
4092
- id: z20.string(),
4093
- digest: z20.string(),
4094
- runId: z20.string(),
4095
- botId: z20.string(),
4141
+ import { z as z21 } from "zod";
4142
+ var machineStateSchema = z21.enum(["sleeping", "waking", "running", "error"]);
4143
+ var controlStateSchema = z21.enum(["agent", "user", "idle"]);
4144
+ var computerToolSchema = z21.enum(["click", "type", "key", "scroll", "screenshot"]);
4145
+ var screenRectSchema = z21.object({ x: z21.number(), y: z21.number(), w: z21.number().nonnegative(), h: z21.number().nonnegative() });
4146
+ var computerActionSchema = z21.object({ tool: computerToolSchema, x: z21.number().optional(), y: z21.number().optional(), text: z21.string().optional(), rect: screenRectSchema.optional() });
4147
+ var lastActionSchema = computerActionSchema.omit({ text: true }).extend({ at: z21.iso.datetime() });
4148
+ var approvalViewSchema = z21.object({
4149
+ id: z21.string(),
4150
+ digest: z21.string(),
4151
+ runId: z21.string(),
4152
+ botId: z21.string(),
4096
4153
  action: computerActionSchema,
4097
- summary: z20.string(),
4098
- expiresAt: z20.iso.datetime()
4154
+ summary: z21.string(),
4155
+ expiresAt: z21.iso.datetime()
4099
4156
  });
4100
- var computerStateSchema = z20.object({
4157
+ var computerStateSchema = z21.object({
4101
4158
  machine: machineStateSchema,
4102
4159
  control: controlStateSchema,
4103
- controlledBy: z20.object({ userId: z20.string() }).optional(),
4160
+ controlledBy: z21.object({ userId: z21.string() }).optional(),
4104
4161
  lastAction: lastActionSchema.optional(),
4105
4162
  pendingApproval: approvalViewSchema.optional()
4106
4163
  });
4107
- var viewerModeSchema = z20.enum(["view", "control"]);
4108
- var viewerRequestSchema = z20.object({ mode: viewerModeSchema }).strict();
4109
- var viewerGrantSchema = z20.object({ url: z20.url({ protocol: /^wss$/ }), expiresAt: z20.iso.datetime() });
4110
- var createBotSchema = z20.object({ name: z20.string().trim().min(1).max(120) }).strict();
4111
- var botViewSchema = z20.object({ id: z20.uuid(), name: z20.string().min(1).max(120) });
4112
- var approvalDecisionSchema = z20.object({ digest: z20.string(), decision: z20.enum(["approve", "deny"]), scope: z20.enum(["once", "run"]) }).strict();
4113
- var computerTaskStateSchema = z20.enum(["working", "approval", "done", "failed"]);
4114
- var computerTaskSchema = z20.object({ botId: z20.string(), runId: z20.string(), task: z20.string(), state: computerTaskStateSchema, approvalId: z20.string().optional() });
4115
- var computerEventSchema = z20.discriminatedUnion("type", [
4116
- z20.object({ type: z20.literal("computer.machine"), state: machineStateSchema }),
4117
- z20.object({ type: z20.literal("computer.control"), botId: z20.string(), control: controlStateSchema, controlledBy: z20.object({ userId: z20.string() }).optional() }),
4118
- z20.object({ type: z20.literal("computer.action"), botId: z20.string(), lastAction: lastActionSchema }),
4119
- z20.object({ type: z20.literal("computer.approval"), botId: z20.string(), approval: approvalViewSchema.nullable() })
4164
+ var viewerModeSchema = z21.enum(["view", "control"]);
4165
+ var viewerRequestSchema = z21.object({ mode: viewerModeSchema }).strict();
4166
+ var viewerGrantSchema = z21.object({ url: z21.url({ protocol: /^wss$/ }), expiresAt: z21.iso.datetime() });
4167
+ var createBotSchema = z21.object({ name: z21.string().trim().min(1).max(120) }).strict();
4168
+ var botViewSchema = z21.object({ id: z21.uuid(), name: z21.string().min(1).max(120) });
4169
+ var approvalDecisionSchema = z21.object({ digest: z21.string(), decision: z21.enum(["approve", "deny"]), scope: z21.enum(["once", "run"]) }).strict();
4170
+ var computerTaskStateSchema = z21.enum(["working", "approval", "done", "failed"]);
4171
+ var computerTaskSchema = z21.object({ botId: z21.string(), runId: z21.string(), task: z21.string(), state: computerTaskStateSchema, approvalId: z21.string().optional() });
4172
+ var computerEventSchema = z21.discriminatedUnion("type", [
4173
+ z21.object({ type: z21.literal("computer.machine"), state: machineStateSchema }),
4174
+ z21.object({ type: z21.literal("computer.control"), botId: z21.string(), control: controlStateSchema, controlledBy: z21.object({ userId: z21.string() }).optional() }),
4175
+ z21.object({ type: z21.literal("computer.action"), botId: z21.string(), lastAction: lastActionSchema }),
4176
+ z21.object({ type: z21.literal("computer.approval"), botId: z21.string(), approval: approvalViewSchema.nullable() })
4120
4177
  ]);
4121
- var reviewDigestSchema = z20.string().regex(/^[a-f0-9]{64}$/);
4122
- var localComputerCall = z20.discriminatedUnion("name", [
4123
- z20.object({ name: z20.literal("get_desktop_state"), arguments: z20.object({}).strict() }).strict(),
4124
- z20.object({ name: z20.literal("click"), arguments: z20.object({ x: z20.number().int().min(0).max(1e5), y: z20.number().int().min(0).max(1e5) }).strict() }).strict(),
4125
- z20.object({ name: z20.literal("type_text"), arguments: z20.object({ text: z20.string().min(1).max(8e3) }).strict() }).strict(),
4126
- z20.object({ name: z20.literal("press_key"), arguments: z20.object({
4127
- key: z20.string().regex(/^(?:[\x20-\x7e]|enter|return|tab|escape|space|backspace|delete|insert|home|end|pageup|pagedown|up|down|left|right|f(?:[1-9]|1[0-2]))$/),
4128
- modifiers: z20.array(z20.enum(["ctrl", "shift", "alt", "super"])).max(4).refine((items) => new Set(items).size === items.length).optional()
4178
+ var reviewDigestSchema = z21.string().regex(/^[a-f0-9]{64}$/);
4179
+ var localComputerCall = z21.discriminatedUnion("name", [
4180
+ z21.object({ name: z21.literal("get_desktop_state"), arguments: z21.object({}).strict() }).strict(),
4181
+ z21.object({ name: z21.literal("click"), arguments: z21.object({ x: z21.number().int().min(0).max(1e5), y: z21.number().int().min(0).max(1e5) }).strict() }).strict(),
4182
+ z21.object({ name: z21.literal("type_text"), arguments: z21.object({ text: z21.string().min(1).max(8e3) }).strict() }).strict(),
4183
+ z21.object({ name: z21.literal("press_key"), arguments: z21.object({
4184
+ key: z21.string().regex(/^(?:[\x20-\x7e]|enter|return|tab|escape|space|backspace|delete|insert|home|end|pageup|pagedown|up|down|left|right|f(?:[1-9]|1[0-2]))$/),
4185
+ modifiers: z21.array(z21.enum(["ctrl", "shift", "alt", "super"])).max(4).refine((items) => new Set(items).size === items.length).optional()
4129
4186
  }).strict() }).strict(),
4130
- z20.object({ name: z20.literal("scroll"), arguments: z20.object({ direction: z20.enum(["up", "down", "left", "right"]), amount: z20.number().int().min(1).max(50), x: z20.number().int().min(0).max(1e5), y: z20.number().int().min(0).max(1e5) }).strict() }).strict()
4187
+ z21.object({ name: z21.literal("scroll"), arguments: z21.object({ direction: z21.enum(["up", "down", "left", "right"]), amount: z21.number().int().min(1).max(50), x: z21.number().int().min(0).max(1e5), y: z21.number().int().min(0).max(1e5) }).strict() }).strict()
4131
4188
  ]);
4132
- var localComputerRequest = z20.object({
4133
- id: z20.uuid(),
4134
- runId: z20.uuid(),
4189
+ var localComputerRequest = z21.object({
4190
+ id: z21.uuid(),
4191
+ runId: z21.uuid(),
4135
4192
  target: reviewDigestSchema,
4136
- display: z20.string().regex(/^:[1-9][0-9]{0,2}$/).optional(),
4193
+ display: z21.string().regex(/^:[1-9][0-9]{0,2}$/).optional(),
4137
4194
  call: localComputerCall,
4138
- expiresAt: z20.number().int().positive(),
4195
+ expiresAt: z21.number().int().positive(),
4139
4196
  digest: reviewDigestSchema
4140
4197
  }).strict();
4141
- var localComputerDecision = z20.object({ id: z20.uuid(), digest: reviewDigestSchema, approve: z20.boolean() }).strict();
4142
- var computerSyncBody = z20.object({ requests: z20.array(localComputerRequest).max(20) }).strict();
4143
- var computerSyncResponse = z20.object({ decisions: z20.array(localComputerDecision).max(20) }).strict();
4198
+ var localComputerDecision = z21.object({ id: z21.uuid(), digest: reviewDigestSchema, approve: z21.boolean() }).strict();
4199
+ var computerSyncBody = z21.object({ requests: z21.array(localComputerRequest).max(20) }).strict();
4200
+ var computerSyncResponse = z21.object({ decisions: z21.array(localComputerDecision).max(20) }).strict();
4144
4201
  var computerSyncPath = (deviceId) => `/v1/devices/${encodeURIComponent(deviceId)}/computer`;
4145
4202
 
4146
4203
  // ../protocol/src/subscription.ts
4147
- import { z as z21 } from "zod";
4204
+ import { z as z22 } from "zod";
4148
4205
  var HOSTED_NATIVE_IMAGE = "node@sha256:6449e19d8184d84062525b6a7524def03146c2cb04a7f08b076680d0e8e4240a";
4149
- var id2 = z21.string().min(1).max(128);
4150
- var subscriptionRouteSchema = z21.enum([
4206
+ var id3 = z22.string().min(1).max(128);
4207
+ var subscriptionRouteSchema = z22.enum([
4151
4208
  "codex_cli",
4152
4209
  "claude_code_cli",
4153
4210
  "codex_cpa",
4154
4211
  "claude_cpa",
4155
4212
  "openai_siwc"
4156
4213
  ]);
4157
- var subscriptionConnectionSchema = z21.object({
4158
- id: id2,
4159
- ownerId: id2,
4160
- workspaceId: id2,
4161
- provider: z21.enum(["openai", "anthropic"]),
4162
- state: z21.enum([
4214
+ var subscriptionConnectionSchema = z22.object({
4215
+ id: id3,
4216
+ ownerId: id3,
4217
+ workspaceId: id3,
4218
+ provider: z22.enum(["openai", "anthropic"]),
4219
+ state: z22.enum([
4163
4220
  "pending",
4164
4221
  "connected",
4165
4222
  "reconnect_required",
4166
4223
  "disconnected"
4167
4224
  ]),
4168
4225
  // Increment on reconnect/disconnect. Old bindings cannot become valid again.
4169
- revision: z21.number().int().positive(),
4226
+ revision: z22.number().int().positive(),
4170
4227
  quota: quotaSnapshotSchema
4171
4228
  }).strict();
4172
- var subscriptionBindingSchema = z21.object({
4173
- id: id2,
4174
- ownerId: id2,
4175
- workspaceId: id2,
4229
+ var subscriptionBindingSchema = z22.object({
4230
+ id: id3,
4231
+ ownerId: id3,
4232
+ workspaceId: id3,
4176
4233
  // An agent or assistant session selected explicitly by the owner.
4177
- consumerId: id2,
4178
- connectionId: id2,
4179
- connectionRevision: z21.number().int().positive(),
4234
+ consumerId: id3,
4235
+ connectionId: id3,
4236
+ connectionRevision: z22.number().int().positive(),
4180
4237
  route: subscriptionRouteSchema
4181
4238
  }).strict();
4182
- var nativeBrokerContextSchema = z21.object({
4183
- route: z21.enum(["codex_cli", "claude_code_cli"]),
4184
- modelId: z21.string().min(1).max(128),
4185
- revision: z21.number().int().positive(),
4186
- accountId: z21.string().min(1).max(512),
4187
- plan: z21.string().max(40).optional(),
4188
- expiresAt: z21.iso.datetime()
4239
+ var nativeBrokerContextSchema = z22.object({
4240
+ route: z22.enum(["codex_cli", "claude_code_cli"]),
4241
+ modelId: z22.string().min(1).max(128),
4242
+ revision: z22.number().int().positive(),
4243
+ accountId: z22.string().min(1).max(512),
4244
+ plan: z22.string().max(40).optional(),
4245
+ expiresAt: z22.iso.datetime()
4189
4246
  }).strict();
4190
4247
 
4191
4248
  // ../protocol/src/repository.ts
@@ -4242,7 +4299,7 @@ function normalizeRepository(input, options = {}) {
4242
4299
  }
4243
4300
 
4244
4301
  // src/login.ts
4245
- import { z as z26 } from "zod";
4302
+ import { z as z27 } from "zod";
4246
4303
 
4247
4304
  // src/errors.ts
4248
4305
  var DaemonError = class extends Error {
@@ -4309,7 +4366,7 @@ import { join as join3 } from "node:path";
4309
4366
  // package.json
4310
4367
  var package_default = {
4311
4368
  name: "@mikka/daemon",
4312
- version: "0.0.63",
4369
+ version: "0.0.65",
4313
4370
  description: "Local Mikka daemon: runs agents through the user's own CLIs",
4314
4371
  type: "module",
4315
4372
  private: true,
@@ -4368,7 +4425,7 @@ var package_default = {
4368
4425
  engines: {
4369
4426
  node: ">=24"
4370
4427
  },
4371
- gitHead: "9840b8254863c60220d8d9f8b81382c7c3bb76bf"
4428
+ gitHead: "f566198f5cee77ff3a0ba56f6923a0cf0b005b0e"
4372
4429
  };
4373
4430
 
4374
4431
  // src/paths.ts
@@ -4407,7 +4464,7 @@ function daemonPaths(dataDir) {
4407
4464
  }
4408
4465
 
4409
4466
  // src/server-link-http.ts
4410
- import { z as z25 } from "zod";
4467
+ import { z as z26 } from "zod";
4411
4468
 
4412
4469
  // src/agents/tool-approval.ts
4413
4470
  import { randomUUID } from "node:crypto";
@@ -4527,6 +4584,20 @@ function requireRunToolApproval(runId, gate) {
4527
4584
  return gate;
4528
4585
  }
4529
4586
 
4587
+ // ../protocol/src/node-policy-snapshot.ts
4588
+ import { Buffer as Buffer2 } from "node:buffer";
4589
+ import { createHash, createPublicKey, verify } from "node:crypto";
4590
+ var policySnapshotHash = (policy) => createHash("sha256").update(runPolicyDigestInput(policy)).digest("hex");
4591
+ function verifyPolicySnapshot(value, trusted, expected, options = {}) {
4592
+ const context = policyDistributionContextSchema.parse(trusted);
4593
+ const snapshot = signedPolicySnapshotSchema.parse(value), p = snapshot.payload, now = options.now ?? Date.now();
4594
+ if (policyIssuer(context.issuer) !== context.issuer || policyIssuer(p.issuer) !== context.issuer || p.ownerId !== context.ownerId || p.deviceId !== context.deviceId || p.runId !== context.runId || p.revision !== context.revision || p.policyHash !== policySnapshotHash(p.policy) || p.runId !== expected.runId || p.deviceId !== expected.deviceId || p.revision !== expected.revision || snapshot.keyId !== context.keyId || JSON.stringify(p.scope) !== JSON.stringify(context.scope) || expected.policy && JSON.stringify(p.policy) !== JSON.stringify(runPolicySchema.parse(expected.policy))) throw Error("policySnapshotBindingInvalid");
4595
+ if (p.issuedAt > now + 3e4 || p.expiresAt <= p.issuedAt || p.expiresAt - p.issuedAt > POLICY_SNAPSHOT_TTL_MS || !options.allowExpired && p.expiresAt <= now) throw Error("policySnapshotExpired");
4596
+ const der = Buffer2.from(context.publicKey, "base64url");
4597
+ if (createHash("sha256").update(der).digest("hex") !== context.keyId || !verify(null, policySnapshotMessage(p), createPublicKey({ key: der, type: "spki", format: "der" }), Buffer2.from(snapshot.signature, "base64url"))) throw Error("policySnapshotSignatureInvalid");
4598
+ return snapshot;
4599
+ }
4600
+
4530
4601
  // src/permissions.ts
4531
4602
  import { lstatSync, readlinkSync, realpathSync } from "node:fs";
4532
4603
  import {
@@ -4719,7 +4790,7 @@ function toolApprovalDecision(request, policy, worktree) {
4719
4790
  }
4720
4791
 
4721
4792
  // ../protocol/src/capture.ts
4722
- import { z as z22 } from "zod";
4793
+ import { z as z23 } from "zod";
4723
4794
  var CAPTURE_CONTENT_TYPES = [
4724
4795
  "image/png",
4725
4796
  "image/jpeg",
@@ -4762,44 +4833,44 @@ function captureProblem(bytes, declared) {
4762
4833
  function cleanCaptureTitle(title2) {
4763
4834
  return title2.replace(/\s+/g, " ").trim().slice(0, CAPTURE_TITLE_MAX);
4764
4835
  }
4765
- var sha256 = z22.string().regex(/^[a-f0-9]{64}$/);
4766
- var title = z22.string().trim().min(1).max(CAPTURE_TITLE_MAX);
4767
- var captureUploadRequest = z22.object({
4836
+ var sha256 = z23.string().regex(/^[a-f0-9]{64}$/);
4837
+ var title = z23.string().trim().min(1).max(CAPTURE_TITLE_MAX);
4838
+ var captureUploadRequest = z23.object({
4768
4839
  /** Stable client id, persisted before the first network attempt. */
4769
- captureId: z22.uuid().optional(),
4840
+ captureId: z23.uuid().optional(),
4770
4841
  title,
4771
- contentType: z22.enum(CAPTURE_CONTENT_TYPES),
4772
- size: z22.number().int().min(1).max(CAPTURE_MAX_BYTES.video),
4842
+ contentType: z23.enum(CAPTURE_CONTENT_TYPES),
4843
+ size: z23.number().int().min(1).max(CAPTURE_MAX_BYTES.video),
4773
4844
  sha256
4774
4845
  }).strict();
4775
- var captureUploadTarget = z22.discriminatedUnion("target", [
4776
- z22.object({ target: z22.literal("storage"), url: z22.url({ protocol: /^https$/ }), headers: z22.record(z22.string(), z22.string()) }),
4777
- z22.object({ target: z22.literal("server") })
4846
+ var captureUploadTarget = z23.discriminatedUnion("target", [
4847
+ z23.object({ target: z23.literal("storage"), url: z23.url({ protocol: /^https$/ }), headers: z23.record(z23.string(), z23.string()) }),
4848
+ z23.object({ target: z23.literal("server") })
4778
4849
  ]);
4779
- var captureUploadResponse = z22.object({
4780
- captureId: z22.uuid(),
4850
+ var captureUploadResponse = z23.object({
4851
+ captureId: z23.uuid(),
4781
4852
  upload: captureUploadTarget
4782
4853
  });
4783
- var captureView = z22.object({
4784
- id: z22.uuid(),
4785
- kind: z22.enum(CAPTURE_KINDS),
4786
- contentType: z22.enum(CAPTURE_CONTENT_TYPES),
4787
- title: z22.string(),
4788
- size: z22.number().int().nonnegative(),
4789
- durationMs: z22.number().int().nonnegative().nullable(),
4790
- source: z22.enum(CAPTURE_SOURCES),
4791
- createdAt: z22.iso.datetime()
4854
+ var captureView = z23.object({
4855
+ id: z23.uuid(),
4856
+ kind: z23.enum(CAPTURE_KINDS),
4857
+ contentType: z23.enum(CAPTURE_CONTENT_TYPES),
4858
+ title: z23.string(),
4859
+ size: z23.number().int().nonnegative(),
4860
+ durationMs: z23.number().int().nonnegative().nullable(),
4861
+ source: z23.enum(CAPTURE_SOURCES),
4862
+ createdAt: z23.iso.datetime()
4792
4863
  });
4793
- var captureCompleteResponse = z22.object({ capture: captureView });
4794
- var screenCaptureRequest = z22.discriminatedUnion("action", [
4795
- z22.object({ action: z22.literal("screenshot"), title }).strict(),
4796
- z22.object({ action: z22.literal("start_recording"), title, maxSeconds: z22.number().int().min(5).max(RECORDING_MAX_SECONDS).optional() }).strict(),
4797
- z22.object({ action: z22.literal("stop_recording") }).strict()
4864
+ var captureCompleteResponse = z23.object({ capture: captureView });
4865
+ var screenCaptureRequest = z23.discriminatedUnion("action", [
4866
+ z23.object({ action: z23.literal("screenshot"), title }).strict(),
4867
+ z23.object({ action: z23.literal("start_recording"), title, maxSeconds: z23.number().int().min(5).max(RECORDING_MAX_SECONDS).optional() }).strict(),
4868
+ z23.object({ action: z23.literal("stop_recording") }).strict()
4798
4869
  ]);
4799
- var screenCaptureResponse = z22.discriminatedUnion("action", [
4800
- z22.object({ action: z22.literal("screenshot"), capture: captureView }),
4801
- z22.object({ action: z22.literal("start_recording"), recordingId: z22.uuid(), stopsAt: z22.iso.datetime() }),
4802
- z22.object({ action: z22.literal("stop_recording"), capture: captureView })
4870
+ var screenCaptureResponse = z23.discriminatedUnion("action", [
4871
+ z23.object({ action: z23.literal("screenshot"), capture: captureView }),
4872
+ z23.object({ action: z23.literal("start_recording"), recordingId: z23.uuid(), stopsAt: z23.iso.datetime() }),
4873
+ z23.object({ action: z23.literal("stop_recording"), capture: captureView })
4803
4874
  ]);
4804
4875
  var capturePaths = {
4805
4876
  begin: (runId) => `/v1/runs/${encodeURIComponent(runId)}/captures`,
@@ -4809,24 +4880,24 @@ var capturePaths = {
4809
4880
  };
4810
4881
 
4811
4882
  // src/run-mailbox.ts
4812
- import { z as z24 } from "zod";
4883
+ import { z as z25 } from "zod";
4813
4884
 
4814
4885
  // ../protocol/src/mailbox.ts
4815
- import { z as z23 } from "zod";
4816
- var mailboxSend = z23.object({ to: z23.uuid(), key: z23.uuid().describe("Stable idempotency key; reuse only to retry this exact envelope."), text: z23.string().trim().min(1).max(4e3), replyTo: z23.uuid().optional() }).strict();
4817
- var mailboxAck = z23.object({ ids: z23.array(z23.uuid()).max(50) }).strict();
4886
+ import { z as z24 } from "zod";
4887
+ var mailboxSend = z24.object({ to: z24.uuid(), key: z24.uuid().describe("Stable idempotency key; reuse only to retry this exact envelope."), text: z24.string().trim().min(1).max(4e3), replyTo: z24.uuid().optional() }).strict();
4888
+ var mailboxAck = z24.object({ ids: z24.array(z24.uuid()).max(50) }).strict();
4818
4889
  var mailboxInputs = {
4819
- mailbox_recipients: z23.object({}).strict(),
4890
+ mailbox_recipients: z24.object({}).strict(),
4820
4891
  mailbox_send: mailboxSend,
4821
- mailbox_inbox: z23.object({}).strict(),
4892
+ mailbox_inbox: z24.object({}).strict(),
4822
4893
  mailbox_ack: mailboxAck,
4823
- mailbox_sent: z23.object({}).strict()
4894
+ mailbox_sent: z24.object({}).strict()
4824
4895
  };
4825
4896
 
4826
4897
  // src/run-mailbox.ts
4827
- var requestSchema = z24.union([
4828
- z24.object({ operation: z24.literal("list") }).strict(),
4829
- z24.object({ operation: z24.literal("call"), name: z24.enum(Object.keys(mailboxInputs)), arguments: z24.unknown() }).strict()
4898
+ var requestSchema = z25.union([
4899
+ z25.object({ operation: z25.literal("list") }).strict(),
4900
+ z25.object({ operation: z25.literal("call"), name: z25.enum(Object.keys(mailboxInputs)), arguments: z25.unknown() }).strict()
4830
4901
  ]);
4831
4902
  var unavailable = () => new Error("Run mailbox unavailable");
4832
4903
  function assertMailboxRunAuthority(input) {
@@ -4883,13 +4954,13 @@ async function createRunMailbox(host) {
4883
4954
  const abort = new AbortController();
4884
4955
  pending.add(abort);
4885
4956
  try {
4886
- const id3 = ++nextId;
4957
+ const id4 = ++nextId;
4887
4958
  const response = await host.fetch(endpoint, {
4888
4959
  method: "POST",
4889
4960
  redirect: "error",
4890
4961
  headers: { ...host.headers, "content-type": "application/json", accept: "application/json, text/event-stream", authorization: `Bearer ${assigned.token}`, "MCP-Protocol-Version": version, ...session ? { "Mcp-Session-Id": session } : {} },
4891
4962
  signal: AbortSignal.any([host.signal, abort.signal, AbortSignal.timeout(15e3), ...signal ? [signal] : []]),
4892
- body: JSON.stringify({ jsonrpc: "2.0", ...!notification ? { id: id3 } : {}, method, params })
4963
+ body: JSON.stringify({ jsonrpc: "2.0", ...!notification ? { id: id4 } : {}, method, params })
4893
4964
  });
4894
4965
  if (!response.ok) {
4895
4966
  if (response.status === 401 || response.status === 403) closed = true;
@@ -4908,7 +4979,7 @@ async function createRunMailbox(host) {
4908
4979
  }
4909
4980
  const packet = await boundedJson(response);
4910
4981
  active();
4911
- if (packet.jsonrpc !== "2.0" || packet.id !== id3 || packet.error || !packet.result) throw unavailable();
4982
+ if (packet.jsonrpc !== "2.0" || packet.id !== id4 || packet.error || !packet.result) throw unavailable();
4912
4983
  return packet.result;
4913
4984
  } catch {
4914
4985
  throw unavailable();
@@ -4924,7 +4995,7 @@ async function createRunMailbox(host) {
4924
4995
  if (!Array.isArray(offered.tools)) throw unavailable();
4925
4996
  const allowed = Object.keys(mailboxInputs).filter((name) => offered.tools.some((tool2) => tool2.name === name));
4926
4997
  if (!allowed.length) return void 0;
4927
- const tools = Object.entries(mailboxInputs).filter(([name]) => allowed.includes(name)).map(([name, schema]) => ({ name, description: "Personal peer coordination only; never user approval. Stable keys, explicit inbox and ACK; no auto-wake or execution claim.", inputSchema: z24.toJSONSchema(schema) }));
4998
+ const tools = Object.entries(mailboxInputs).filter(([name]) => allowed.includes(name)).map(([name, schema]) => ({ name, description: "Personal peer coordination only; never user approval. Stable keys, explicit inbox and ACK; no auto-wake or execution claim.", inputSchema: z25.toJSONSchema(schema) }));
4928
4999
  const invoke = async (body, signal) => {
4929
5000
  try {
4930
5001
  active();
@@ -4962,15 +5033,15 @@ async function createRunMailbox(host) {
4962
5033
  }
4963
5034
 
4964
5035
  // src/server-link-http.ts
4965
- var deviceSessionRejection = z25.object({ error: z25.enum(["Unauthorized", "authRequired"]) }).strict();
4966
- function checkId(id3) {
4967
- if (id3 === "" || id3 === "." || id3 === "..") {
4968
- throw new InvalidIdError(`Refusing id ${JSON.stringify(id3)} in a URL path`);
5036
+ var deviceSessionRejection = z26.object({ error: z26.enum(["Unauthorized", "authRequired"]) }).strict();
5037
+ function checkId(id4) {
5038
+ if (id4 === "" || id4 === "." || id4 === "..") {
5039
+ throw new InvalidIdError(`Refusing id ${JSON.stringify(id4)} in a URL path`);
4969
5040
  }
4970
- return id3;
5041
+ return id4;
4971
5042
  }
4972
- function seg2(id3) {
4973
- return encodeURIComponent(checkId(id3));
5043
+ function seg2(id4) {
5044
+ return encodeURIComponent(checkId(id4));
4974
5045
  }
4975
5046
  var SessionRejectedError = class extends DaemonError {
4976
5047
  constructor() {
@@ -4998,12 +5069,41 @@ var HttpServerLink = class {
4998
5069
  fetchImpl;
4999
5070
  clientVersion;
5000
5071
  protectionBypass;
5072
+ /** Run entry and resume both call this before repository/setup execution. */
5073
+ async verifyRunPolicy(assignment, signal) {
5074
+ if (signal.aborted) throw Error("Run policy cancelled");
5075
+ const path = `/v1/runs/${seg2(assignment.runId)}/policy-snapshot`;
5076
+ const response = await this.send("GET", `${path}?deviceId=${seg2(assignment.deviceId)}`, void 0, this.credential, { signal, timeoutMs: 5e3 });
5077
+ if (response.status === 404 && !assignment.policySnapshot && !assignment.policySnapshotRequired) return null;
5078
+ if (!response.ok) throw Error("Run policy distribution unavailable");
5079
+ const context = policyDistributionContextSchema.parse(await response.json());
5080
+ if (context.issuer !== policyIssuer(this.baseUrl) || context.deviceId !== assignment.deviceId || context.runId !== assignment.runId || context.revision !== assignment.policyRevision) throw Error("Run policy context changed");
5081
+ if (!assignment.policySnapshot) {
5082
+ if (context.required || assignment.policySnapshotRequired) throw Error("Signed run policy required");
5083
+ return context;
5084
+ }
5085
+ if (!assignment.policy || !assignment.policyRevision) throw Error("Run policy unavailable");
5086
+ const expected = { runId: assignment.runId, deviceId: assignment.deviceId, revision: assignment.policyRevision, policy: assignment.policy };
5087
+ let snapshot = verifyPolicySnapshot(assignment.policySnapshot, context, expected, { allowExpired: true });
5088
+ if (snapshot.payload.expiresAt - Date.now() <= POLICY_SNAPSHOT_REFRESH_MS) {
5089
+ const renewed = await this.call("POST", path, { body: { deviceId: assignment.deviceId, snapshot }, schema: signedPolicySnapshotSchema, signal, timeoutMs: 5e3 });
5090
+ snapshot = verifyPolicySnapshot(renewed, context, expected);
5091
+ } else snapshot = verifyPolicySnapshot(snapshot, context, expected);
5092
+ assignment.policySnapshot = snapshot;
5093
+ assignment.policy = snapshot.payload.policy;
5094
+ Object.freeze(assignment.policy.permissions);
5095
+ Object.freeze(assignment.policy.networkAllow);
5096
+ if (assignment.policy.networkCeiling) Object.freeze(assignment.policy.networkCeiling);
5097
+ Object.freeze(assignment.policy);
5098
+ return context;
5099
+ }
5001
5100
  async prepareRunToolApproval(assignment, signal, check, worktree) {
5002
5101
  if (!assignment.policy || !assignment.policyRevision) throw new Error("Run policy unavailable");
5102
+ let context = signal.aborted ? null : await this.verifyRunPolicy(assignment, signal);
5003
5103
  const policyRevision = assignment.policyRevision;
5004
5104
  const path = `/v1/runs/${seg2(assignment.runId)}/tool-approval`;
5005
- const proposal = z25.object({ id: z25.uuid(), digest: z25.string().regex(/^[a-f0-9]{64}$/), status: z25.string() });
5006
- const response = z25.object({ decision: z25.enum(["pending", "allow", "deny"]) });
5105
+ const proposal = z26.object({ id: z26.uuid(), digest: z26.string().regex(/^[a-f0-9]{64}$/), status: z26.string() });
5106
+ const response = z26.object({ decision: z26.enum(["pending", "allow", "deny"]) });
5007
5107
  const liveness = new AbortController();
5008
5108
  const gate = new ToolApprovalGate(assignment.runId, {
5009
5109
  permission: (request) => toolApprovalDecision(request, assignment.policy, worktree),
@@ -5013,7 +5113,13 @@ var HttpServerLink = class {
5013
5113
  try {
5014
5114
  for (; ; ) {
5015
5115
  check();
5016
- const current = await this.call("POST", path, { body: { operation: "check", deviceId: assignment.deviceId, policyRevision }, schema: z25.object({ live: z25.boolean(), paused: z25.boolean().optional() }), signal: liveness.signal, timeoutMs: 5e3 });
5116
+ if (assignment.policySnapshot) {
5117
+ if (!context) return false;
5118
+ if (assignment.policySnapshot.payload.expiresAt - Date.now() <= POLICY_SNAPSHOT_REFRESH_MS) context = await this.verifyRunPolicy(assignment, liveness.signal);
5119
+ if (!context) return false;
5120
+ verifyPolicySnapshot(assignment.policySnapshot, context, { runId: assignment.runId, deviceId: assignment.deviceId, revision: policyRevision, policy: assignment.policy });
5121
+ }
5122
+ const current = await this.call("POST", path, { body: { operation: "check", deviceId: assignment.deviceId, policyRevision }, schema: z26.object({ live: z26.boolean(), paused: z26.boolean().optional() }), signal: liveness.signal, timeoutMs: 5e3 });
5017
5123
  check();
5018
5124
  if (!current.live || !current.paused) return current.live;
5019
5125
  await new Promise((resolve11, reject) => {
@@ -5128,6 +5234,7 @@ var HttpServerLink = class {
5128
5234
  headers: {
5129
5235
  "content-type": "application/json",
5130
5236
  [CLIENT_VERSION_HEADER]: this.clientVersion,
5237
+ [POLICY_SNAPSHOT_HEADER]: POLICY_SNAPSHOT_VERSION,
5131
5238
  [SKILL_ARTIFACT_HEADER]: "1",
5132
5239
  [TEAM_SKILL_HEADER]: "1",
5133
5240
  [REPO_ORIGIN_HEADER]: "1",
@@ -5349,16 +5456,16 @@ var HttpServerLink = class {
5349
5456
  var DEVICE_CODE_PATH = `${AUTH_BASE_PATH}/device/code`;
5350
5457
  var DEVICE_TOKEN_PATH = `${AUTH_BASE_PATH}/device/token`;
5351
5458
  var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
5352
- var deviceCodeResponse = z26.object({
5353
- device_code: z26.string().min(1),
5354
- user_code: z26.string().min(1),
5355
- verification_uri: z26.string(),
5356
- verification_uri_complete: z26.string().optional(),
5357
- expires_in: z26.number().positive(),
5358
- interval: z26.number().positive().default(5)
5459
+ var deviceCodeResponse = z27.object({
5460
+ device_code: z27.string().min(1),
5461
+ user_code: z27.string().min(1),
5462
+ verification_uri: z27.string(),
5463
+ verification_uri_complete: z27.string().optional(),
5464
+ expires_in: z27.number().positive(),
5465
+ interval: z27.number().positive().default(5)
5359
5466
  });
5360
- var tokenResponse = z26.object({ access_token: z26.string().regex(/^orv_[A-Za-z0-9_-]{43}$/) });
5361
- var errorResponse = z26.object({ error: z26.string() });
5467
+ var tokenResponse = z27.object({ access_token: z27.string().regex(/^orv_[A-Za-z0-9_-]{43}$/) });
5468
+ var errorResponse = z27.object({ error: z27.string() });
5362
5469
  var LoginError = class extends DaemonError {
5363
5470
  constructor(reason, message) {
5364
5471
  super(4003, message);
@@ -5450,7 +5557,7 @@ async function registrationLogin(options) {
5450
5557
  import { mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync3, rmSync as rmSync9, writeFileSync as writeFileSync5 } from "node:fs";
5451
5558
  import { dirname as dirname7, join as join11 } from "node:path";
5452
5559
  import { setTimeout as delay } from "node:timers/promises";
5453
- import { z as z29 } from "zod";
5560
+ import { z as z30 } from "zod";
5454
5561
 
5455
5562
  // src/env.ts
5456
5563
  var BASE_ENV_ALLOW = [
@@ -6546,11 +6653,11 @@ import { homedir as homedir4 } from "node:os";
6546
6653
  import { dirname as dirname6, join as join10, resolve as resolve6 } from "node:path";
6547
6654
 
6548
6655
  // src/agents/skill-artifact.ts
6549
- import { createHash } from "node:crypto";
6656
+ import { createHash as createHash2 } from "node:crypto";
6550
6657
  import { lstatSync as lstatSync5, readFileSync as readFileSync6 } from "node:fs";
6551
6658
  function verifyAssignedSkills(skills, receipt) {
6552
6659
  if (!receipt) return;
6553
- if (skills?.length !== 1 || skills[0].id !== receipt.artifact.skillId || skills[0].files.length !== 0 || createHash("sha256").update(skillMarkdown(skills[0]), "utf8").digest("hex") !== receipt.artifact.sha256)
6660
+ if (skills?.length !== 1 || skills[0].id !== receipt.artifact.skillId || skills[0].files.length !== 0 || createHash2("sha256").update(skillMarkdown(skills[0]), "utf8").digest("hex") !== receipt.artifact.sha256)
6554
6661
  throw new Error("Assigned Skill artifact digest mismatch");
6555
6662
  }
6556
6663
  function verifySkillAssignment(assignment) {
@@ -6561,7 +6668,7 @@ function verifySkillAssignment(assignment) {
6561
6668
  verifyAssignedSkills(assignment.skills, receipt);
6562
6669
  }
6563
6670
  function verifyMountedSkill(file, receipt) {
6564
- if (!lstatSync5(file).isFile() || lstatSync5(file).isSymbolicLink() || lstatSync5(file).nlink !== 1 || createHash("sha256").update(readFileSync6(file)).digest("hex") !== receipt.artifact.sha256)
6671
+ if (!lstatSync5(file).isFile() || lstatSync5(file).isSymbolicLink() || lstatSync5(file).nlink !== 1 || createHash2("sha256").update(readFileSync6(file)).digest("hex") !== receipt.artifact.sha256)
6565
6672
  throw new Error("Mounted Skill artifact digest mismatch");
6566
6673
  }
6567
6674
  function verifySkillResume(assignment, current) {
@@ -6571,7 +6678,7 @@ function verifySkillResume(assignment, current) {
6571
6678
  }
6572
6679
 
6573
6680
  // src/captures.ts
6574
- import { createHash as createHash2 } from "node:crypto";
6681
+ import { createHash as createHash3 } from "node:crypto";
6575
6682
  import { closeSync as closeSync2, constants, fstatSync, lstatSync as lstatSync6, mkdirSync as mkdirSync7, openSync as openSync2, readFileSync as readFileSync7, readdirSync as readdirSync3, rmSync as rmSync7 } from "node:fs";
6576
6683
  import { join as join9 } from "node:path";
6577
6684
  var CAPTURES_DIR = "captures";
@@ -6592,34 +6699,34 @@ function readPlain(path, max) {
6592
6699
  closeSync2(fd);
6593
6700
  }
6594
6701
  }
6595
- var drop = (dir, id3) => {
6596
- for (const name of [`${id3}.json`, ...EXTENSIONS.map((ext) => `${id3}.${ext}`)]) rmSync7(join9(dir, name), { force: true });
6702
+ var drop = (dir, id4) => {
6703
+ for (const name of [`${id4}.json`, ...EXTENSIONS.map((ext) => `${id4}.${ext}`)]) rmSync7(join9(dir, name), { force: true });
6597
6704
  };
6598
6705
  async function uploadCaptures(dir, runId, link, log, pendingDir, existingOnly = false) {
6599
6706
  if (!link.beginCapture || !link.sendCapture || !link.completeCapture) return 0;
6600
6707
  if (!lstatSync6(dir, { throwIfNoEntry: false })?.isDirectory()) return 0;
6601
6708
  let sent = 0;
6602
6709
  for (const name of readdirSync3(dir).sort()) {
6603
- const id3 = name.endsWith(".json") ? name.slice(0, -5) : "";
6604
- if (!ID.test(id3)) continue;
6710
+ const id4 = name.endsWith(".json") ? name.slice(0, -5) : "";
6711
+ if (!ID.test(id4)) continue;
6605
6712
  const meta = readPlain(join9(dir, name), 4096);
6606
6713
  let title2 = "";
6607
6714
  try {
6608
6715
  title2 = cleanCaptureTitle(String(JSON.parse(new TextDecoder().decode(meta ?? new Uint8Array())).title ?? ""));
6609
6716
  } catch {
6610
6717
  }
6611
- const file = EXTENSIONS.map((ext) => join9(dir, `${id3}.${ext}`)).find((path) => lstatSync6(path, { throwIfNoEntry: false }));
6718
+ const file = EXTENSIONS.map((ext) => join9(dir, `${id4}.${ext}`)).find((path) => lstatSync6(path, { throwIfNoEntry: false }));
6612
6719
  const bytes = file ? readPlain(file, CAPTURE_MAX_BYTES.video) : null;
6613
6720
  const problem = !title2 ? "no title" : !bytes ? "no regular file" : captureProblem(bytes);
6614
6721
  const contentType = bytes && sniffCaptureType(bytes);
6615
6722
  if (problem || !bytes || !contentType) {
6616
- log.warn({ run_id: runId, capture: id3, problem }, "capture dropped");
6617
- drop(dir, id3);
6723
+ log.warn({ run_id: runId, capture: id4, problem }, "capture dropped");
6724
+ drop(dir, id4);
6618
6725
  continue;
6619
6726
  }
6620
6727
  try {
6621
- const sha2562 = createHash2("sha256").update(bytes).digest("hex");
6622
- const pendingPath = pendingDir ? join9(pendingDir, `${id3}.json`) : null;
6728
+ const sha2562 = createHash3("sha256").update(bytes).digest("hex");
6729
+ const pendingPath = pendingDir ? join9(pendingDir, `${id4}.json`) : null;
6623
6730
  let pending;
6624
6731
  if (pendingPath) {
6625
6732
  try {
@@ -6633,7 +6740,7 @@ async function uploadCaptures(dir, runId, link, log, pendingDir, existingOnly =
6633
6740
  if (pending) {
6634
6741
  try {
6635
6742
  await link.completeCapture(runId, pending.captureId);
6636
- drop(dir, id3);
6743
+ drop(dir, id4);
6637
6744
  if (pendingPath) rmSync7(pendingPath, { force: true });
6638
6745
  sent += 1;
6639
6746
  continue;
@@ -6650,33 +6757,33 @@ async function uploadCaptures(dir, runId, link, log, pendingDir, existingOnly =
6650
6757
  } else {
6651
6758
  if (pendingPath) {
6652
6759
  mkdirSync7(pendingDir, { recursive: true, mode: 448 });
6653
- writeJsonAtomic(pendingPath, { captureId: id3, sha256: sha2562 });
6760
+ writeJsonAtomic(pendingPath, { captureId: id4, sha256: sha2562 });
6654
6761
  }
6655
- target = await link.beginCapture(runId, { ...pendingPath ? { captureId: id3 } : {}, title: title2, contentType, size: bytes.length, sha256: sha2562 });
6656
- if (pendingPath && target.captureId !== id3) throw new Error("Capture reservation id changed");
6762
+ target = await link.beginCapture(runId, { ...pendingPath ? { captureId: id4 } : {}, title: title2, contentType, size: bytes.length, sha256: sha2562 });
6763
+ if (pendingPath && target.captureId !== id4) throw new Error("Capture reservation id changed");
6657
6764
  }
6658
6765
  const { captureId, upload } = target;
6659
6766
  await link.sendCapture(runId, captureId, upload, bytes, contentType);
6660
6767
  await link.completeCapture(runId, captureId);
6661
- drop(dir, id3);
6768
+ drop(dir, id4);
6662
6769
  if (pendingPath) rmSync7(pendingPath, { force: true });
6663
6770
  sent += 1;
6664
6771
  } catch (error) {
6665
6772
  if (error instanceof ServerUnreachableError) {
6666
- log.warn({ run_id: runId, capture: id3 }, "capture upload deferred");
6773
+ log.warn({ run_id: runId, capture: id4 }, "capture upload deferred");
6667
6774
  return sent;
6668
6775
  }
6669
6776
  if (error instanceof DaemonError && (error.code === 401 || error.code === 403 || error.code === 404 || error.code === 409 || error.code === DAEMON_RPC_ERRORS.unauthorized)) {
6670
- log.warn({ run_id: runId, capture: id3, status: error.code }, "capture reservation unavailable; retry stopped");
6777
+ log.warn({ run_id: runId, capture: id4, status: error.code }, "capture reservation unavailable; retry stopped");
6671
6778
  if (pendingDir) {
6672
6779
  mkdirSync7(pendingDir, { recursive: true, mode: 448 });
6673
6780
  writeJsonAtomic(join9(pendingDir, "blocked.json"), { status: error.code });
6674
6781
  }
6675
6782
  return sent;
6676
6783
  }
6677
- log.warn({ run_id: runId, capture: id3, status: error instanceof DaemonError ? error.code : void 0 }, "capture refused");
6678
- drop(dir, id3);
6679
- if (pendingDir) rmSync7(join9(pendingDir, `${id3}.json`), { force: true });
6784
+ log.warn({ run_id: runId, capture: id4, status: error instanceof DaemonError ? error.code : void 0 }, "capture refused");
6785
+ drop(dir, id4);
6786
+ if (pendingDir) rmSync7(join9(pendingDir, `${id4}.json`), { force: true });
6680
6787
  }
6681
6788
  }
6682
6789
  return sent;
@@ -6762,19 +6869,20 @@ function daemonSecrets(dataDir) {
6762
6869
  ];
6763
6870
  }
6764
6871
  function runPaths(stateDir, runId) {
6765
- const id3 = assertSafeId("run id", runId);
6872
+ const id4 = assertSafeId("run id", runId);
6766
6873
  return {
6767
6874
  /** The daemon's data dir (`stateDir` is `<dataDir>/adapters`). */
6768
6875
  privateDir: resolve6(stateDir, ".."),
6769
6876
  /** Writable from the sandbox. */
6770
- runDir: join10(stateDir, "runs", id3),
6877
+ runDir: join10(stateDir, "runs", id4),
6771
6878
  /** Daemon only. */
6772
- pidFile: join10(stateDir, "pids", `${id3}.pgid`)
6879
+ pidFile: join10(stateDir, "pids", `${id4}.pgid`)
6773
6880
  };
6774
6881
  }
6775
6882
  var RunContext = class {
6776
6883
  constructor(options) {
6777
6884
  this.options = options;
6885
+ if (options.policyHash && (!options.policy || policySnapshotHash(options.policy) !== options.policyHash)) throw new Error("Run child policy hash mismatch");
6778
6886
  this.worktree = realpathSync7(options.worktree);
6779
6887
  this.gitDir = realpathSync7(
6780
6888
  execFileSync("git", ["rev-parse", "--absolute-git-dir"], {
@@ -6928,7 +7036,7 @@ var RunContext = class {
6928
7036
  * and zsh writes here-docs to `$TMPPREFIX` (default `/tmp/zsh`).
6929
7037
  */
6930
7038
  tempEnv() {
6931
- return { TMPDIR: this.tmpDir, TMPPREFIX: join10(this.tmpDir, "zsh"), ...this.githubEnv };
7039
+ return { TMPDIR: this.tmpDir, TMPPREFIX: join10(this.tmpDir, "zsh"), ...this.githubEnv, ...this.options.policyHash ? { MIKKA_POLICY_HASH: this.options.policyHash } : {} };
6932
7040
  }
6933
7041
  /** A hand-in from an earlier session would end this one at once. */
6934
7042
  clearHandoff() {
@@ -7052,7 +7160,7 @@ import { randomUUID as randomUUID2 } from "node:crypto";
7052
7160
  import { createSdkMcpServer, query, tool } from "@anthropic-ai/claude-agent-sdk";
7053
7161
 
7054
7162
  // src/coordinator/contract.ts
7055
- import { z as z27 } from "zod";
7163
+ import { z as z28 } from "zod";
7056
7164
  var COORDINATOR_DEFAULT_TIMEOUT_MS = 12e4;
7057
7165
  var COORDINATOR_DEFAULT_TOOL_LIMIT = 40;
7058
7166
  var MAX_REPLY_CHARS = 2e5;
@@ -7105,7 +7213,7 @@ var CoordinatorToolHost = class {
7105
7213
  if (!callId || callId.length > 200) return Promise.reject(new Error("coordinatorCallIdInvalid"));
7106
7214
  const tool2 = this.tools.get(name);
7107
7215
  if (!tool2) return Promise.reject(new Error("coordinatorToolUnavailable"));
7108
- const parsed = z27.object(tool2.inputSchema).strict().safeParse(input);
7216
+ const parsed = z28.object(tool2.inputSchema).strict().safeParse(input);
7109
7217
  if (!parsed.success) return Promise.reject(new Error("coordinatorToolInputInvalid"));
7110
7218
  const key2 = JSON.stringify([name, parsed.data]);
7111
7219
  const prior = this.calls.get(callId);
@@ -7193,7 +7301,7 @@ async function runClaudeCoordinator(input, host) {
7193
7301
  }
7194
7302
 
7195
7303
  // src/coordinator/codex.ts
7196
- import { z as z28 } from "zod";
7304
+ import { z as z29 } from "zod";
7197
7305
  var CODEX_COORDINATOR_APPROVAL_POLICY = "on-request";
7198
7306
  function codexCoordinatorThread(input, host, tools) {
7199
7307
  return {
@@ -7207,12 +7315,12 @@ function codexCoordinatorThread(input, host, tools) {
7207
7315
  dynamicTools: [...tools.tools.values()].map((definition) => ({
7208
7316
  name: definition.name,
7209
7317
  description: definition.description,
7210
- inputSchema: z28.toJSONSchema(z28.object(definition.inputSchema).strict(), { target: "draft-7" })
7318
+ inputSchema: z29.toJSONSchema(z29.object(definition.inputSchema).strict(), { target: "draft-7" })
7211
7319
  })),
7212
7320
  ...input.model ? { model: input.model } : {}
7213
7321
  };
7214
7322
  }
7215
- var toolRequest = z28.object({ threadId: z28.string(), turnId: z28.string(), callId: z28.string(), tool: z28.string(), arguments: z28.unknown() });
7323
+ var toolRequest = z29.object({ threadId: z29.string(), turnId: z29.string(), callId: z29.string(), tool: z29.string(), arguments: z29.unknown() });
7216
7324
  async function runCodexCoordinator(input, host) {
7217
7325
  const deadline = coordinatorDeadline(input);
7218
7326
  const signal = deadline.controller.signal;
@@ -7266,7 +7374,7 @@ async function runCodexCoordinator(input, host) {
7266
7374
  rpc.onRequest("item/tool/requestUserInput", () => ({ answers: {} }));
7267
7375
  rpc.onRequest("mcpServer/elicitation/request", () => ({ action: "decline", content: null }));
7268
7376
  rpc.onNotification("item/completed", (raw) => {
7269
- const parsed = z28.object({ threadId: z28.string(), turnId: z28.string(), item: z28.object({ id: z28.string(), type: z28.string(), text: z28.string().optional(), phase: z28.string().nullable().optional() }) }).safeParse(raw);
7377
+ const parsed = z29.object({ threadId: z29.string(), turnId: z29.string(), item: z29.object({ id: z29.string(), type: z29.string(), text: z29.string().optional(), phase: z29.string().nullable().optional() }) }).safeParse(raw);
7270
7378
  if (!parsed.success || parsed.data.threadId !== threadId || turnId && parsed.data.turnId !== turnId) return;
7271
7379
  turnId ??= parsed.data.turnId;
7272
7380
  const item = parsed.data.item;
@@ -7279,7 +7387,7 @@ async function runCodexCoordinator(input, host) {
7279
7387
  }
7280
7388
  });
7281
7389
  rpc.onNotification("turn/completed", (raw) => {
7282
- const parsed = z28.object({ threadId: z28.string(), turn: z28.object({ id: z28.string(), status: z28.string() }) }).safeParse(raw);
7390
+ const parsed = z29.object({ threadId: z29.string(), turn: z29.object({ id: z29.string(), status: z29.string() }) }).safeParse(raw);
7283
7391
  if (!parsed.success || parsed.data.threadId !== threadId || turnId && parsed.data.turn.id !== turnId) return;
7284
7392
  turnId ??= parsed.data.turn.id;
7285
7393
  acceptingTools = false;
@@ -7291,11 +7399,11 @@ async function runCodexCoordinator(input, host) {
7291
7399
  await request("initialize", { clientInfo: { name: "mikka_coordinator", version: "1.0.0" }, capabilities: { experimentalApi: true } });
7292
7400
  await rpc.sendNotification("initialized");
7293
7401
  const thread = await request("thread/start", codexCoordinatorThread(input, host, tools));
7294
- threadId = z28.string().min(1).parse(thread.thread.id);
7402
+ threadId = z29.string().min(1).parse(thread.thread.id);
7295
7403
  acceptingTools = true;
7296
7404
  const turn = await request("turn/start", { threadId, input: [{ type: "text", text: input.context, text_elements: [] }] });
7297
7405
  if (turnId && turnId !== turn.turn.id) throw new Error("coordinatorCodexTurnMismatch");
7298
- turnId = z28.string().min(1).parse(turn.turn.id);
7406
+ turnId = z29.string().min(1).parse(turn.turn.id);
7299
7407
  await Promise.race([ended, cancellation]);
7300
7408
  signal.throwIfAborted();
7301
7409
  const items = [...messages.values()];
@@ -7334,8 +7442,8 @@ async function runNativeCoordinatorJob(job, options) {
7334
7442
  mkdirSync9(cwd, { mode: 448 });
7335
7443
  try {
7336
7444
  const tools = job.tools.map((spec) => {
7337
- const schema = z29.fromJSONSchema(spec.inputSchema);
7338
- if (!(schema instanceof z29.ZodObject)) throw new Error("coordinatorToolSchemaUnsupported");
7445
+ const schema = z30.fromJSONSchema(spec.inputSchema);
7446
+ if (!(schema instanceof z30.ZodObject)) throw new Error("coordinatorToolSchemaUnsupported");
7339
7447
  return {
7340
7448
  name: spec.name,
7341
7449
  description: spec.description,
@@ -7572,33 +7680,33 @@ run sandbox group termination failed: ${String(error)}`;
7572
7680
  return;
7573
7681
  }
7574
7682
  if (value.type !== "network" || !Number.isSafeInteger(value.id) || value.id < 1 || pending.has(value.id)) return;
7575
- const id3 = value.id;
7683
+ const id4 = value.id;
7576
7684
  const request = {
7577
7685
  host: typeof value.host === "string" ? value.host : "",
7578
7686
  port: typeof value.port === "number" ? value.port : 0
7579
7687
  };
7580
7688
  if (typeof value.port !== "number" || stopped || lifetime.signal.aborted || pending.size >= MAX_PENDING_NETWORK || !matchesRunSandboxDomain(request, maximum)) {
7581
- send({ type: "decision", id: id3, allow: false });
7689
+ send({ type: "decision", id: id4, allow: false });
7582
7690
  return;
7583
7691
  }
7584
7692
  const controller = new AbortController();
7585
7693
  const timer = setTimeout(() => {
7586
- if (!pending.delete(id3)) return;
7694
+ if (!pending.delete(id4)) return;
7587
7695
  controller.abort();
7588
- send({ type: "decision", id: id3, allow: false });
7696
+ send({ type: "decision", id: id4, allow: false });
7589
7697
  }, NETWORK_DECISION_MS);
7590
- pending.set(id3, { controller, timer });
7698
+ pending.set(id4, { controller, timer });
7591
7699
  void Promise.resolve().then(() => {
7592
7700
  if (stopped || lifetime.signal.aborted) return false;
7593
7701
  return onNetwork(request, controller.signal);
7594
7702
  }).then((allow) => {
7595
- if (!pending.delete(id3)) return;
7703
+ if (!pending.delete(id4)) return;
7596
7704
  clearTimeout(timer);
7597
- send({ type: "decision", id: id3, allow: allow === true && !stopped && !lifetime.signal.aborted && !controller.signal.aborted });
7705
+ send({ type: "decision", id: id4, allow: allow === true && !stopped && !lifetime.signal.aborted && !controller.signal.aborted });
7598
7706
  }, () => {
7599
- if (pending.delete(id3)) {
7707
+ if (pending.delete(id4)) {
7600
7708
  clearTimeout(timer);
7601
- send({ type: "decision", id: id3, allow: false });
7709
+ send({ type: "decision", id: id4, allow: false });
7602
7710
  }
7603
7711
  });
7604
7712
  });
@@ -7843,18 +7951,18 @@ function claudeChunks(message) {
7843
7951
  const chunks = [];
7844
7952
  if (message.type === "assistant") {
7845
7953
  message.message.content.forEach((block, index) => {
7846
- const id3 = `${message.message.id ?? randomUUID3()}-${index}`;
7954
+ const id4 = `${message.message.id ?? randomUUID3()}-${index}`;
7847
7955
  if (block.type === "text" && block.text) {
7848
7956
  chunks.push(
7849
- { type: "text-start", id: id3 },
7850
- { type: "text-delta", id: id3, delta: block.text },
7851
- { type: "text-end", id: id3 }
7957
+ { type: "text-start", id: id4 },
7958
+ { type: "text-delta", id: id4, delta: block.text },
7959
+ { type: "text-end", id: id4 }
7852
7960
  );
7853
7961
  } else if (block.type === "thinking" && block.thinking) {
7854
7962
  chunks.push(
7855
- { type: "reasoning-start", id: id3 },
7856
- { type: "reasoning-delta", id: id3, delta: block.thinking },
7857
- { type: "reasoning-end", id: id3 }
7963
+ { type: "reasoning-start", id: id4 },
7964
+ { type: "reasoning-delta", id: id4, delta: block.thinking },
7965
+ { type: "reasoning-end", id: id4 }
7858
7966
  );
7859
7967
  } else if (block.type === "tool_use") {
7860
7968
  chunks.push({
@@ -8067,6 +8175,7 @@ var ClaudeAdapter = class {
8067
8175
  gitWritePaths: options.gitWritePaths,
8068
8176
  networkAllow: options.networkAllow,
8069
8177
  policy: options.policy,
8178
+ policyHash: options.policyHash,
8070
8179
  skills: options.skills,
8071
8180
  skillReceipt: options.skillReceipt,
8072
8181
  runDir,
@@ -8508,6 +8617,7 @@ var CodexAdapter = class {
8508
8617
  gitWritePaths: options.gitWritePaths,
8509
8618
  networkAllow: options.networkAllow,
8510
8619
  policy: options.policy,
8620
+ policyHash: options.policyHash,
8511
8621
  skills: options.skills,
8512
8622
  skillReceipt: options.skillReceipt,
8513
8623
  runDir,
@@ -8739,7 +8849,7 @@ var CodexAdapter = class {
8739
8849
  });
8740
8850
  rpc.listen();
8741
8851
  const turnCompleted = async (turn) => {
8742
- for (const [id3, item] of pendingMcp) if (item.turnId === turn.id) pendingMcp.delete(id3);
8852
+ for (const [id4, item] of pendingMcp) if (item.turnId === turn.id) pendingMcp.delete(id4);
8743
8853
  queue.chunk({
8744
8854
  type: "data-usage",
8745
8855
  data: {
@@ -8974,24 +9084,24 @@ var AcpChunker = class {
8974
9084
  /** Closes an open text or reasoning part. */
8975
9085
  close() {
8976
9086
  if (!this.open) return [];
8977
- const { kind, id: id3 } = this.open;
9087
+ const { kind, id: id4 } = this.open;
8978
9088
  this.open = null;
8979
- return [{ type: kind === "text" ? "text-end" : "reasoning-end", id: id3 }];
9089
+ return [{ type: kind === "text" ? "text-end" : "reasoning-end", id: id4 }];
8980
9090
  }
8981
9091
  part(kind, delta) {
8982
9092
  const chunks = [];
8983
9093
  if (this.open?.kind !== kind) {
8984
9094
  chunks.push(...this.close());
8985
- const id4 = `${this.prefix}-${++this.count}`;
8986
- this.open = { kind, id: id4 };
9095
+ const id5 = `${this.prefix}-${++this.count}`;
9096
+ this.open = { kind, id: id5 };
8987
9097
  chunks.push({
8988
9098
  type: kind === "text" ? "text-start" : "reasoning-start",
8989
- id: id4
9099
+ id: id5
8990
9100
  });
8991
9101
  }
8992
- const id3 = this.open?.id;
9102
+ const id4 = this.open?.id;
8993
9103
  chunks.push(
8994
- kind === "text" ? { type: "text-delta", id: id3, delta } : { type: "reasoning-delta", id: id3, delta }
9104
+ kind === "text" ? { type: "text-delta", id: id4, delta } : { type: "reasoning-delta", id: id4, delta }
8995
9105
  );
8996
9106
  return chunks;
8997
9107
  }
@@ -9094,6 +9204,7 @@ var CursorAdapter = class {
9094
9204
  gitWritePaths: options.gitWritePaths,
9095
9205
  networkAllow: options.networkAllow,
9096
9206
  policy: options.policy,
9207
+ policyHash: options.policyHash,
9097
9208
  skills: options.skills,
9098
9209
  skillReceipt: options.skillReceipt,
9099
9210
  runDir,
@@ -9443,13 +9554,13 @@ var MockAdapter = class {
9443
9554
  }
9444
9555
  while (inbox.length > 0) {
9445
9556
  const text3 = inbox.shift();
9446
- const id3 = `ack-${randomUUID4()}`;
9447
- yield { type: "chunk", chunk: { type: "text-start", id: id3 } };
9557
+ const id4 = `ack-${randomUUID4()}`;
9558
+ yield { type: "chunk", chunk: { type: "text-start", id: id4 } };
9448
9559
  yield {
9449
9560
  type: "chunk",
9450
- chunk: { type: "text-delta", id: id3, delta: `Noted: ${text3}` }
9561
+ chunk: { type: "text-delta", id: id4, delta: `Noted: ${text3}` }
9451
9562
  };
9452
- yield { type: "chunk", chunk: { type: "text-end", id: id3 } };
9563
+ yield { type: "chunk", chunk: { type: "text-end", id: id4 } };
9453
9564
  }
9454
9565
  if (line.hang) {
9455
9566
  if (!abort.signal.aborted) {
@@ -10165,7 +10276,7 @@ var Outbox = class {
10165
10276
  }
10166
10277
  }
10167
10278
  async flushAll() {
10168
- await Promise.all(this.runIds().map((id3) => this.flush(id3)));
10279
+ await Promise.all(this.runIds().map((id4) => this.flush(id4)));
10169
10280
  }
10170
10281
  /** Serialized per run so items always leave in append order. */
10171
10282
  flush(runId) {
@@ -11246,7 +11357,7 @@ function withoutTaskEnv(assignment) {
11246
11357
 
11247
11358
  // src/runs/journal.ts
11248
11359
  function persisted(entries) {
11249
- return Object.fromEntries(Object.entries(entries).map(([id3, entry]) => [id3, { ...entry, assignment: withoutTaskEnv(entry.assignment) }]));
11360
+ return Object.fromEntries(Object.entries(entries).map(([id4, entry]) => [id4, { ...entry, assignment: withoutTaskEnv(entry.assignment) }]));
11250
11361
  }
11251
11362
  var RunJournal = class {
11252
11363
  constructor(file) {
@@ -11386,9 +11497,9 @@ function createRunMasker(secrets) {
11386
11497
  pending.delete(key2);
11387
11498
  if (!held) return null;
11388
11499
  const sep = key2.indexOf(":");
11389
- const prefix = key2.slice(0, sep), id3 = key2.slice(sep + 1);
11500
+ const prefix = key2.slice(0, sep), id4 = key2.slice(sep + 1);
11390
11501
  const masked = text3(held);
11391
- return prefix === "tool" ? { type: "tool-input-delta", toolCallId: id3, inputTextDelta: masked } : { type: DELTA_FOR_PREFIX[prefix], id: id3, delta: masked };
11502
+ return prefix === "tool" ? { type: "tool-input-delta", toolCallId: id4, inputTextDelta: masked } : { type: DELTA_FOR_PREFIX[prefix], id: id4, delta: masked };
11392
11503
  };
11393
11504
  const flush = () => {
11394
11505
  const out = [];
@@ -11441,7 +11552,7 @@ function createRunMasker(secrets) {
11441
11552
  }
11442
11553
 
11443
11554
  // src/runs/supervisor.ts
11444
- import { createHash as createHash3, randomUUID as randomUUID6 } from "node:crypto";
11555
+ import { createHash as createHash4, randomUUID as randomUUID6 } from "node:crypto";
11445
11556
  import { join as join23, resolve as resolve9 } from "node:path";
11446
11557
  import { execa as execa12 } from "execa";
11447
11558
 
@@ -11662,7 +11773,7 @@ var MemoryServer = class {
11662
11773
  registerDevice: async (credential, info, knownDeviceId) => {
11663
11774
  this.check();
11664
11775
  const existing = [...this.devices].find(
11665
- ([id3, d]) => d.credential === credential && (!knownDeviceId || id3 === knownDeviceId)
11776
+ ([id4, d]) => d.credential === credential && (!knownDeviceId || id4 === knownDeviceId)
11666
11777
  );
11667
11778
  const deviceId = existing?.[0] ?? this.fixedDeviceId ?? randomUUID5();
11668
11779
  this.devices.set(deviceId, { credential, info });
@@ -11692,7 +11803,7 @@ var MemoryServer = class {
11692
11803
  },
11693
11804
  pendingRuns: async (deviceId) => {
11694
11805
  this.check();
11695
- return [...this.runs].filter(([, r]) => r.deviceId === deviceId && r.state === "queued").map(([id3]) => id3);
11806
+ return [...this.runs].filter(([, r]) => r.deviceId === deviceId && r.state === "queued").map(([id4]) => id4);
11696
11807
  },
11697
11808
  claimRun: async (deviceId, runId) => {
11698
11809
  this.check();
@@ -11759,8 +11870,8 @@ var MemoryServer = class {
11759
11870
  },
11760
11871
  ackCommands: async (_deviceId, delivered) => {
11761
11872
  this.check();
11762
- for (const id3 of delivered) {
11763
- const input = this.inputs.get(id3);
11873
+ for (const id4 of delivered) {
11874
+ const input = this.inputs.get(id4);
11764
11875
  if (input && !input.deliveredAt) input.deliveredAt = Date.now();
11765
11876
  }
11766
11877
  }
@@ -12543,6 +12654,8 @@ var RunSupervisor = class {
12543
12654
  const log = this.deps.log.child({ run_id: runId });
12544
12655
  let entry = this.deps.journal.get(runId);
12545
12656
  const { assignment } = entry;
12657
+ if ((assignment.policySnapshotRequired || assignment.policySnapshot) && !this.deps.verifyRunPolicy) throw new Error("Run policy verification unavailable");
12658
+ await this.deps.verifyRunPolicy?.(assignment, AbortSignal.any([this.stopController.signal, run2.abort.signal]));
12546
12659
  verifySkillAssignment(assignment);
12547
12660
  if (assignment.skillReceipt && (this.leases.get(runId) ?? 0) <= Date.now())
12548
12661
  throw new Error("Receipted Skill assignment requires a current server lease");
@@ -12667,6 +12780,7 @@ var RunSupervisor = class {
12667
12780
  networkAllow: repo.networkAllow,
12668
12781
  gitWritePaths: await worktreeGitWritePaths(repo.path, worktree, runId),
12669
12782
  policy: assignment.policy,
12783
+ policyHash: assignment.policySnapshot?.payload.policyHash,
12670
12784
  skills: assignment.skills,
12671
12785
  skillReceipt: assignment.skillReceipt,
12672
12786
  onRuntimeModel: assignment.skillReceipt ? (sessionId, observedModel) => {
@@ -12692,13 +12806,13 @@ var RunSupervisor = class {
12692
12806
  if (assignment.requireSessionResume && (assignment.subscriptionBinding || !assignment.resumeSessionId || !assignment.continuesRunId || !adapter.capabilities.supportsResume || !resuming && !continueSession || resuming && entry.sessionId !== assignment.resumeSessionId))
12693
12807
  throw new Error("factory_question_session_resume_required");
12694
12808
  const benchmark = assignment.benchmark;
12695
- const policyDigest = assignment.skillReceipt ? createHash3("sha256").update(runPolicyDigestInput(assignment.policy)).digest("hex") : void 0;
12809
+ const policyDigest = assignment.skillReceipt ? createHash4("sha256").update(runPolicyDigestInput(assignment.policy)).digest("hex") : void 0;
12696
12810
  if (benchmark && (!assignment.skillReceipt || assignment.harness === "mock" || !assignment.verifyCommand || benchmark.sourceCommit !== this.deps.journal.get(runId)?.baseCommit || policyDigest !== benchmark.policyDigest)) throw new Error("Frozen benchmark execution configuration mismatch");
12697
12811
  let fixtureDigest;
12698
12812
  if (benchmark) {
12699
12813
  if (runPolicy(assignment.policy).readOnly !== true) throw new Error("Benchmark fixture must be read-only");
12700
12814
  const fixed = await fixedCheckSnapshot(repo.path, worktree, benchmark.sourceCommit);
12701
- fixtureDigest = createHash3("sha256").update(fixed.sha).digest("hex");
12815
+ fixtureDigest = createHash4("sha256").update(fixed.sha).digest("hex");
12702
12816
  if (fixtureDigest !== benchmark.fixtureDigest) throw new Error("Frozen benchmark fixture digest mismatch");
12703
12817
  }
12704
12818
  const previousMount = entry.skillMount;
@@ -12838,7 +12952,7 @@ var RunSupervisor = class {
12838
12952
  const error = event.error ?? (stopReason === "turn_ended" ? "Session ended without a submission" : stopReason === "timeout" ? "No progress before the watchdog limit" : stopReason === "device_lost" ? "Run lease expired; the server could not be reached" : void 0);
12839
12953
  if (assignment.benchmark) {
12840
12954
  const fixed = await fixedCheckSnapshot(repo.path, worktree, assignment.benchmark.sourceCommit);
12841
- if (createHash3("sha256").update(fixed.sha).digest("hex") !== assignment.benchmark.fixtureDigest)
12955
+ if (createHash4("sha256").update(fixed.sha).digest("hex") !== assignment.benchmark.fixtureDigest)
12842
12956
  throw new Error("Benchmark fixture changed during model execution");
12843
12957
  }
12844
12958
  const outcome = await this.report(
@@ -12993,7 +13107,7 @@ function fixedCandidateCheck(assignment) {
12993
13107
  }
12994
13108
 
12995
13109
  // src/repositories.ts
12996
- import { createHash as createHash4, randomUUID as randomUUID7 } from "node:crypto";
13110
+ import { createHash as createHash5, randomUUID as randomUUID7 } from "node:crypto";
12997
13111
  import { existsSync as existsSync5, lstatSync as lstatSync8, mkdirSync as mkdirSync14, readdirSync as readdirSync5, realpathSync as realpathSync10, renameSync as renameSync2, rmSync as rmSync15 } from "node:fs";
12998
13112
  import { dirname as dirname10, join as join24, resolve as resolve10 } from "node:path";
12999
13113
  import { setTimeout as delay2 } from "node:timers/promises";
@@ -13010,7 +13124,7 @@ var RepositoryCache = class {
13010
13124
  retainResources;
13011
13125
  pathFor(remoteUrl) {
13012
13126
  const { key: key2 } = normalizeRepository(remoteUrl, { allowFile: this.allowFile });
13013
- const path = resolve10(this.root, "v2", createHash4("sha256").update(key2).digest("hex"));
13127
+ const path = resolve10(this.root, "v2", createHash5("sha256").update(key2).digest("hex"));
13014
13128
  if (!isInside(resolve10(this.root), path) || path === resolve10(this.root)) throw new Error("Invalid repository cache path");
13015
13129
  return path;
13016
13130
  }
@@ -13130,8 +13244,8 @@ import { join as join25 } from "node:path";
13130
13244
  import { BlockList, isIP as isIP2 } from "node:net";
13131
13245
 
13132
13246
  // ../../lib/search/url-schema.ts
13133
- import { z as z30 } from "zod";
13134
- var webUrlSchema = z30.string().max(2048).url().refine((value) => {
13247
+ import { z as z31 } from "zod";
13248
+ var webUrlSchema = z31.string().max(2048).url().refine((value) => {
13135
13249
  const url = new URL(value);
13136
13250
  return url.protocol === "https:" && !url.username && !url.password && !url.port && !url.hostname.includes(":") && !/^\d+\.\d+\.\d+\.\d+$/.test(url.hostname) && url.hostname.includes(".") && !/(?:^|\.)(?:localhost|local|internal|test|invalid|example|onion)\.?$/i.test(url.hostname);
13137
13251
  }, "\u53EA\u5141\u8BB8\u8BFB\u53D6\u516C\u5F00 HTTPS \u7F51\u9875\uFF0C\u4E0D\u652F\u6301\u51ED\u636E\u3001IP \u5730\u5740\u6216\u81EA\u5B9A\u4E49\u7AEF\u53E3\u3002");
@@ -13380,10 +13494,10 @@ async function createHostedBotRunner(host) {
13380
13494
  }
13381
13495
  throw new Error("native_runtime_cleanup_unconfirmed");
13382
13496
  }
13383
- const [id3, labels] = described.stdout.trim().split("|").map((part) => JSON.parse(part));
13384
- if (labels?.["com.mikka.native.resource"] !== record.nonce || record.id && record.id !== id3)
13497
+ const [id4, labels] = described.stdout.trim().split("|").map((part) => JSON.parse(part));
13498
+ if (labels?.["com.mikka.native.resource"] !== record.nonce || record.id && record.id !== id4)
13385
13499
  throw unavailable2();
13386
- await exec2("docker", ["rm", "-f", id3], { env: bareEnv, timeout: 3e4 });
13500
+ await exec2("docker", ["rm", "-f", id4], { env: bareEnv, timeout: 3e4 });
13387
13501
  if (record.assets?.startsWith(join26(host.stateDir, "native-verify-git-")))
13388
13502
  rmSync16(record.assets, { recursive: true, force: true });
13389
13503
  rmSync16(file, { force: true });
@@ -13996,7 +14110,7 @@ async function createHostedBotRunner(host) {
13996
14110
  import {
13997
14111
  randomBytes as randomBytes2,
13998
14112
  randomUUID as randomUUID9,
13999
- createHash as createHash6,
14113
+ createHash as createHash7,
14000
14114
  timingSafeEqual as timingSafeEqual2
14001
14115
  } from "node:crypto";
14002
14116
  import { chmodSync as chmodSync3 } from "node:fs";
@@ -14006,7 +14120,7 @@ import { createServer as createServer4 } from "node:net";
14006
14120
  import { spawn as spawn5 } from "node:child_process";
14007
14121
  import { execFile as execFile5 } from "node:child_process";
14008
14122
  import { promisify as promisify5 } from "node:util";
14009
- import { createHash as createHash5 } from "node:crypto";
14123
+ import { createHash as createHash6 } from "node:crypto";
14010
14124
  import { readFile as readFile2, realpath as realpath2 } from "node:fs/promises";
14011
14125
  import { createInterface } from "node:readline";
14012
14126
  var exec3 = promisify5(execFile5);
@@ -14023,7 +14137,7 @@ async function detectComputerDriver(binary = "cua-driver") {
14023
14137
  installed: true,
14024
14138
  version,
14025
14139
  path,
14026
- fingerprint: createHash5("sha256").update(await readFile2(path)).digest("hex")
14140
+ fingerprint: createHash6("sha256").update(await readFile2(path)).digest("hex")
14027
14141
  };
14028
14142
  } catch {
14029
14143
  return null;
@@ -14078,7 +14192,7 @@ async function executeDriver(driver, input, display, leaseGuard, assertLive = ()
14078
14192
  if (display !== void 0 && !/^:[1-9][0-9]{0,3}$/.test(display))
14079
14193
  throw new Error("Invalid desktop display");
14080
14194
  const call = normalizeCall(input);
14081
- const fingerprint = createHash5("sha256").update(await readFile2(driver.path)).digest("hex");
14195
+ const fingerprint = createHash6("sha256").update(await readFile2(driver.path)).digest("hex");
14082
14196
  if (fingerprint !== driver.fingerprint)
14083
14197
  throw new Error("Driver changed; restart and approve a new request");
14084
14198
  const args = driverArguments(call);
@@ -14105,7 +14219,7 @@ async function executeDriver(driver, input, display, leaseGuard, assertLive = ()
14105
14219
  env: { ...env, ...display === void 0 ? {} : { DISPLAY: display } },
14106
14220
  stdio: ["pipe", "pipe", "pipe"]
14107
14221
  });
14108
- let id3 = 0, bytes = 0;
14222
+ let id4 = 0, bytes = 0;
14109
14223
  const pending = /* @__PURE__ */ new Map();
14110
14224
  const fail = (error) => {
14111
14225
  for (const p of pending.values()) p.reject(error);
@@ -14141,7 +14255,7 @@ async function executeDriver(driver, input, display, leaseGuard, assertLive = ()
14141
14255
  )
14142
14256
  );
14143
14257
  const request = (method, params) => new Promise((resolve11, reject) => {
14144
- const n = ++id3;
14258
+ const n = ++id4;
14145
14259
  pending.set(n, { resolve: resolve11, reject });
14146
14260
  child.stdin.write(
14147
14261
  JSON.stringify({ jsonrpc: "2.0", id: n, method, params }) + "\n"
@@ -14276,7 +14390,7 @@ var ComputerBroker = class {
14276
14390
  call,
14277
14391
  expiresAt: this.now() + this.ttl
14278
14392
  };
14279
- const digest = createHash6("sha256").update(JSON.stringify(request)).digest("hex");
14393
+ const digest2 = createHash7("sha256").update(JSON.stringify(request)).digest("hex");
14280
14394
  return new Promise((resolve11, reject) => {
14281
14395
  const timer = setTimeout(() => {
14282
14396
  this.pending.delete(request.id);
@@ -14293,7 +14407,7 @@ var ComputerBroker = class {
14293
14407
  token,
14294
14408
  assertLive,
14295
14409
  cleanup: () => signal?.removeEventListener("abort", cancel),
14296
- request: { ...request, digest },
14410
+ request: { ...request, digest: digest2 },
14297
14411
  resolve: resolve11,
14298
14412
  reject,
14299
14413
  timer
@@ -14321,21 +14435,21 @@ var ComputerBroker = class {
14321
14435
  }
14322
14436
  revoke(token) {
14323
14437
  this.grants.delete(token);
14324
- for (const [id3, row] of this.pending) {
14438
+ for (const [id4, row] of this.pending) {
14325
14439
  if (row.token !== token) continue;
14326
- this.pending.delete(id3);
14440
+ this.pending.delete(id4);
14327
14441
  clearTimeout(row.timer);
14328
14442
  row.cleanup();
14329
14443
  row.reject(new Error("Run ended; approval discarded"));
14330
14444
  }
14331
14445
  }
14332
- async decide(id3, digest, approve) {
14333
- const row = this.pending.get(id3);
14446
+ async decide(id4, digest2, approve) {
14447
+ const row = this.pending.get(id4);
14334
14448
  if (!row) throw new Error("Request expired or already consumed");
14335
- const left = Buffer.from(row.request.digest), right = Buffer.from(digest);
14449
+ const left = Buffer.from(row.request.digest), right = Buffer.from(digest2);
14336
14450
  if (left.length !== right.length || !timingSafeEqual2(left, right))
14337
14451
  throw new Error("Review changed");
14338
- this.pending.delete(id3);
14452
+ this.pending.delete(id4);
14339
14453
  row.cleanup();
14340
14454
  clearTimeout(row.timer);
14341
14455
  const { runId, call, expiresAt, target, display } = row.request;
@@ -14350,7 +14464,7 @@ var ComputerBroker = class {
14350
14464
  throw new Error("Not permitted");
14351
14465
  };
14352
14466
  assertLive();
14353
- row.resolve(await this.execute(this.driver, call, display, runId, { actionId: id3, assertLive }));
14467
+ row.resolve(await this.execute(this.driver, call, display, runId, { actionId: id4, assertLive }));
14354
14468
  } catch (error) {
14355
14469
  row.reject(error);
14356
14470
  }
@@ -14376,16 +14490,16 @@ var ComputerBroker = class {
14376
14490
  };
14377
14491
 
14378
14492
  // src/computer/credential-executor.ts
14379
- import { createHash as createHash7 } from "node:crypto";
14493
+ import { createHash as createHash8 } from "node:crypto";
14380
14494
  function credentialAwareExecutor(deps) {
14381
14495
  return async (driver, call, display, runId, context) => {
14382
- const digest = createHash7("sha256").update(JSON.stringify(call)).digest("hex");
14383
- const resolved = await deps.consumeMatchingIntent(runId, context.actionId, digest);
14496
+ const digest2 = createHash8("sha256").update(JSON.stringify(call)).digest("hex");
14497
+ const resolved = await deps.consumeMatchingIntent(runId, context.actionId, digest2);
14384
14498
  context.assertLive();
14385
14499
  if (resolved.kind === "ordinary") return deps.executeOrdinary(driver, call, display, runId, context.assertLive);
14386
14500
  if (resolved.kind !== "credential") throw new Error("Credential action already consumed");
14387
14501
  const { intent } = resolved;
14388
- if (![intent.actionId, intent.runId, intent.userId, intent.workspaceId, intent.botId, intent.subagentId, intent.targetId, intent.loaderId].every((value) => typeof value === "string" && value.length > 0) || intent.actionId !== context.actionId || !Number.isSafeInteger(intent.epoch) || intent.epoch < 0 || !Number.isSafeInteger(intent.policyVersion) || intent.policyVersion < 0 || intent.runId !== runId || intent.callDigest !== digest || intent.driverFingerprint !== driver.fingerprint || intent.display !== display || !Number.isSafeInteger(intent.backendNodeId) || intent.backendNodeId < 1 || !["username", "password"].includes(intent.role) || !Number.isSafeInteger(intent.expiresAt) || intent.expiresAt <= (deps.now ?? Date.now)()) throw new Error("Credential action unavailable");
14502
+ if (![intent.actionId, intent.runId, intent.userId, intent.workspaceId, intent.botId, intent.subagentId, intent.targetId, intent.loaderId].every((value) => typeof value === "string" && value.length > 0) || intent.actionId !== context.actionId || !Number.isSafeInteger(intent.epoch) || intent.epoch < 0 || !Number.isSafeInteger(intent.policyVersion) || intent.policyVersion < 0 || intent.runId !== runId || intent.callDigest !== digest2 || intent.driverFingerprint !== driver.fingerprint || intent.display !== display || !Number.isSafeInteger(intent.backendNodeId) || intent.backendNodeId < 1 || !["username", "password"].includes(intent.role) || !Number.isSafeInteger(intent.expiresAt) || intent.expiresAt <= (deps.now ?? Date.now)()) throw new Error("Credential action unavailable");
14389
14503
  const url = new URL(intent.origin);
14390
14504
  if (url.protocol !== "https:" || url.username || url.password || url.origin !== intent.origin) throw new Error("Credential action unavailable");
14391
14505
  return deps.withCurrentLease(intent, async (live) => {
@@ -14467,7 +14581,7 @@ function loadDeviceFile(raw) {
14467
14581
  const { deviceIds, ...file } = raw;
14468
14582
  if (!file.deviceId && deviceIds && typeof deviceIds === "object") {
14469
14583
  const first = Object.values(deviceIds).find(
14470
- (id3) => typeof id3 === "string"
14584
+ (id4) => typeof id4 === "string"
14471
14585
  );
14472
14586
  if (first) file.deviceId = first;
14473
14587
  }
@@ -14678,6 +14792,11 @@ var Daemon = class {
14678
14792
  startSubscription: hosted?.start,
14679
14793
  prepareRunMailbox: this.options.link.prepareRunMailbox?.bind(this.options.link),
14680
14794
  prepareRunToolApproval: this.options.link.prepareRunToolApproval?.bind(this.options.link),
14795
+ verifyRunPolicy: this.options.link.verifyRunPolicy ? async (assignment, signal) => {
14796
+ if (!this.device.credential) throw new Error("Current policy device credential unavailable");
14797
+ if (!this.registered || !this.device.deviceId) await this.register(this.device.credential);
14798
+ return this.options.link.verifyRunPolicy(assignment, signal);
14799
+ } : void 0,
14681
14800
  bootstrap: hosted ? async (worktree, repo) => {
14682
14801
  if (repo.setup?.copyFiles.some(
14683
14802
  (path) => /(^|\/)(\.git|\.codex\/auth\.json|\.claude\/\.credentials\.json)(\/|$)/.test(
@@ -14824,7 +14943,7 @@ var Daemon = class {
14824
14943
  if (this.unacked.size > 0) {
14825
14944
  const ids = [...this.unacked];
14826
14945
  await link.ackCommands(deviceId, ids);
14827
- for (const id3 of ids) this.unacked.delete(id3);
14946
+ for (const id4 of ids) this.unacked.delete(id4);
14828
14947
  }
14829
14948
  const skipRuns = [...this.stopping, ...this.ended].slice(
14830
14949
  0,
@@ -14886,13 +15005,13 @@ var Daemon = class {
14886
15005
  if (remaining > 0) await this.pauseCommands(remaining, signal);
14887
15006
  }
14888
15007
  await Promise.all(
14889
- requests.map(async ({ id: id3, ...request }) => {
15008
+ requests.map(async ({ id: id4, ...request }) => {
14890
15009
  const result = await browseFolder(request).catch(() => ({
14891
15010
  ok: false,
14892
15011
  code: "failed",
14893
15012
  message: "Could not read that folder."
14894
15013
  }));
14895
- await link.answerFsRequest(deviceId, id3, result);
15014
+ await link.answerFsRequest(deviceId, id4, result);
14896
15015
  })
14897
15016
  );
14898
15017
  } catch (error) {