@aspectlylabs/mikka 0.0.64 → 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 +692 -573
- package/client.js +448 -403
- package/http-link.js +856 -699
- package/login.js +502 -457
- package/main.js +1061 -1000
- package/mikka-release-manifest.json +19 -19
- package/mikka.js +692 -573
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
- package/paths.js +2 -2
- package/sbom.cdx.json +7 -7
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((
|
|
268
|
-
if (/^[0-9]+$/.test(
|
|
269
|
-
const num = +
|
|
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
|
|
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 = (
|
|
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
|
|
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${
|
|
1157
|
+
ret = `>=${M}.0.0${z32} <${+M + 1}.0.0-0`;
|
|
1158
1158
|
} else if (isX(p)) {
|
|
1159
|
-
ret = `>=${M}.${m}.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
|
|
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${
|
|
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${
|
|
1186
|
+
ret = `>=${M}.${m}.0${z32} <${M}.${+m + 1}.0-0`;
|
|
1187
1187
|
} else {
|
|
1188
|
-
ret = `>=${M}.${m}.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
|
|
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
|
|
3270
|
+
import { z as z13 } from "zod";
|
|
3217
3271
|
|
|
3218
3272
|
// ../protocol/src/skill-artifact.ts
|
|
3219
|
-
import { z as
|
|
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 =
|
|
3223
|
-
schemaVersion:
|
|
3224
|
-
registryId:
|
|
3225
|
-
skillId:
|
|
3226
|
-
versionId:
|
|
3227
|
-
format:
|
|
3228
|
-
sha256:
|
|
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 =
|
|
3231
|
-
id:
|
|
3232
|
-
runId:
|
|
3233
|
-
issueId:
|
|
3234
|
-
agentId:
|
|
3235
|
-
repoId:
|
|
3236
|
-
deviceId:
|
|
3237
|
-
leaseExpiresAt:
|
|
3238
|
-
assignedAt:
|
|
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 =
|
|
3295
|
+
var skillReceiptRevalidationSchema = z12.object({
|
|
3242
3296
|
skillReceipt: skillAssignmentReceiptSchema,
|
|
3243
|
-
leaseExpiresAt:
|
|
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 =
|
|
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 =
|
|
3313
|
+
var skillFileSchema = z13.object({
|
|
3260
3314
|
path: skillFilePathSchema,
|
|
3261
|
-
content:
|
|
3315
|
+
content: z13.string().max(MAX_SKILL_FILE_CONTENT_LENGTH)
|
|
3262
3316
|
});
|
|
3263
|
-
var skillFilesSchema =
|
|
3264
|
-
var skillNameSchema =
|
|
3265
|
-
var skillDescriptionSchema =
|
|
3266
|
-
var skillInstructionsSchema =
|
|
3267
|
-
var runSkillSchema =
|
|
3268
|
-
id:
|
|
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:
|
|
3324
|
+
description: z13.string().nullable(),
|
|
3271
3325
|
instructions: skillInstructionsSchema,
|
|
3272
3326
|
files: skillFilesSchema
|
|
3273
3327
|
});
|
|
3274
|
-
var runSkillRefSchema =
|
|
3275
|
-
id:
|
|
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
|
|
3315
|
-
var isoTime =
|
|
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 =
|
|
3343
|
-
var deviceRegistration =
|
|
3344
|
-
deviceType:
|
|
3345
|
-
name:
|
|
3346
|
-
hostname:
|
|
3347
|
-
platform:
|
|
3348
|
-
arch:
|
|
3349
|
-
daemonVersion:
|
|
3350
|
-
protocolVersion:
|
|
3351
|
-
harnesses:
|
|
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:
|
|
3413
|
+
deviceId: id2.optional(),
|
|
3360
3414
|
/** Needed only when the user belongs to more than one workspace. */
|
|
3361
|
-
workspaceId:
|
|
3415
|
+
workspaceId: z14.uuid().optional()
|
|
3362
3416
|
});
|
|
3363
|
-
var deviceRegistered =
|
|
3364
|
-
deviceId:
|
|
3365
|
-
workspaceId:
|
|
3417
|
+
var deviceRegistered = z14.object({
|
|
3418
|
+
deviceId: id2,
|
|
3419
|
+
workspaceId: z14.uuid()
|
|
3366
3420
|
});
|
|
3367
|
-
var heartbeatRunSchema =
|
|
3368
|
-
runId:
|
|
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 =
|
|
3373
|
-
var deviceHeartbeatSchema =
|
|
3374
|
-
completedDeviceCommands:
|
|
3375
|
-
failedDeviceCommands:
|
|
3376
|
-
harnesses:
|
|
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:
|
|
3379
|
-
runs:
|
|
3380
|
-
worktreeDiskBytes:
|
|
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:
|
|
3439
|
+
quotas: z14.array(quotaSnapshotSchema).max(6).optional()
|
|
3386
3440
|
});
|
|
3387
|
-
var heartbeatResultSchema =
|
|
3388
|
-
deviceCommands:
|
|
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:
|
|
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:
|
|
3450
|
+
revoked: z14.array(id2).max(500).optional(),
|
|
3397
3451
|
/** Short-lived cloud device token, returned only over its authenticated link. */
|
|
3398
|
-
cloudCredential:
|
|
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 =
|
|
3457
|
+
var runCheckpointSchema = z14.object({
|
|
3404
3458
|
/** The commit the run's worktree started from. */
|
|
3405
|
-
baseCommit:
|
|
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:
|
|
3465
|
+
patch: z14.string().max(Math.ceil(RUN_CHECKPOINT_MAX_BYTES * 4 / 3) + 4),
|
|
3412
3466
|
/** Files the patch touches. */
|
|
3413
|
-
files:
|
|
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:
|
|
3470
|
+
unavailableReason: z14.literal("too_large").optional()
|
|
3417
3471
|
});
|
|
3418
|
-
var setupRecipeSchema =
|
|
3472
|
+
var setupRecipeSchema = z14.object({
|
|
3419
3473
|
/** Paths relative to the main checkout copied into each new worktree. */
|
|
3420
|
-
copyFiles:
|
|
3474
|
+
copyFiles: z14.array(z14.string().max(1e3)).max(200),
|
|
3421
3475
|
/** Shell command run in the worktree, e.g. `bun install`. */
|
|
3422
|
-
command:
|
|
3476
|
+
command: z14.string().max(2e3).optional(),
|
|
3423
3477
|
/** Approved once per repo by the user; unapproved recipes never run. */
|
|
3424
|
-
approved:
|
|
3478
|
+
approved: z14.boolean()
|
|
3425
3479
|
});
|
|
3426
3480
|
var REPO_ORIGIN_HEADER = "x-mikka-repo-origin-check";
|
|
3427
|
-
var deviceRepoSchema =
|
|
3428
|
-
repoId:
|
|
3429
|
-
name:
|
|
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:
|
|
3432
|
-
remoteUrl:
|
|
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:
|
|
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:
|
|
3438
|
-
approved:
|
|
3439
|
-
remote:
|
|
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 =
|
|
3443
|
-
repos:
|
|
3496
|
+
var deviceReposResponse = z14.object({
|
|
3497
|
+
repos: z14.array(deviceRepoSchema)
|
|
3444
3498
|
});
|
|
3445
|
-
var pendingRunsResponse =
|
|
3499
|
+
var pendingRunsResponse = z14.object({ runIds: z14.array(id2) });
|
|
3446
3500
|
var RUN_KINDS = ["implement", "acceptance", "fix", "plan"];
|
|
3447
|
-
var runAssignmentSchema =
|
|
3448
|
-
runId:
|
|
3449
|
-
issueId:
|
|
3450
|
-
deviceId:
|
|
3451
|
-
repoId:
|
|
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:
|
|
3507
|
+
remoteUrl: z14.string().min(1).max(4e3).optional(),
|
|
3454
3508
|
/** Absent means origin/HEAD after fetch. */
|
|
3455
|
-
baseBranch:
|
|
3456
|
-
expectedRepoRemote:
|
|
3509
|
+
baseBranch: z14.string().min(1).max(500).optional(),
|
|
3510
|
+
expectedRepoRemote: z14.string().max(2e3).optional(),
|
|
3457
3511
|
harness: harnessSchema,
|
|
3458
|
-
prompt:
|
|
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:
|
|
3468
|
-
bindingId:
|
|
3469
|
-
ownerId:
|
|
3470
|
-
workspaceId:
|
|
3471
|
-
consumerId:
|
|
3472
|
-
route:
|
|
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:
|
|
3476
|
-
botId:
|
|
3477
|
-
ownerId:
|
|
3478
|
-
workspaceId:
|
|
3479
|
-
policyVersion:
|
|
3480
|
-
permission:
|
|
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:
|
|
3484
|
-
botId:
|
|
3485
|
-
ownerId:
|
|
3486
|
-
display:
|
|
3487
|
-
policyVersion:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
3564
|
+
pushBranch: z14.string().min(1).max(250).optional(),
|
|
3511
3565
|
/** Run by the daemon in the worktree after the agent submits. */
|
|
3512
|
-
verifyCommand:
|
|
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:
|
|
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:
|
|
3524
|
-
endpoint:
|
|
3525
|
-
repository:
|
|
3526
|
-
branch:
|
|
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:
|
|
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:
|
|
3593
|
+
continuesRunId: id2.optional(),
|
|
3540
3594
|
/** A same-device retry with no usable snapshot must reuse its real worktree. */
|
|
3541
|
-
requireWorktreeContinuation:
|
|
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:
|
|
3555
|
-
requireSessionResume:
|
|
3556
|
-
preserveQuestionWorktree:
|
|
3557
|
-
questionId:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
3584
|
-
state:
|
|
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:
|
|
3596
|
-
worktree:
|
|
3597
|
-
error:
|
|
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 =
|
|
3602
|
-
fromSeq:
|
|
3603
|
-
chunks:
|
|
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 =
|
|
3662
|
+
var runEventsAccepted = z14.object({
|
|
3606
3663
|
/** Producer seq of the last chunk the server holds for this run. */
|
|
3607
|
-
offset:
|
|
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 =
|
|
3613
|
-
|
|
3614
|
-
kind:
|
|
3615
|
-
runId:
|
|
3616
|
-
messageId:
|
|
3617
|
-
text:
|
|
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
|
-
|
|
3676
|
+
z14.object({ kind: z14.literal("stop"), runId: id2 })
|
|
3620
3677
|
]);
|
|
3621
|
-
var runCommandsResponse =
|
|
3622
|
-
commands:
|
|
3678
|
+
var runCommandsResponse = z14.object({
|
|
3679
|
+
commands: z14.array(runCommandSchema).max(500)
|
|
3623
3680
|
});
|
|
3624
|
-
var runCommandsAck =
|
|
3625
|
-
delivered:
|
|
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 =
|
|
3686
|
+
var fsBrowseRequest = z14.object({
|
|
3630
3687
|
/** Absolute path on the device; omitted: the device's home folder. */
|
|
3631
|
-
path:
|
|
3632
|
-
showHidden:
|
|
3688
|
+
path: z14.string().trim().min(1).max(4e3).optional(),
|
|
3689
|
+
showHidden: z14.boolean().optional()
|
|
3633
3690
|
});
|
|
3634
|
-
var fsPendingRequest = fsBrowseRequest.extend({ id:
|
|
3635
|
-
var fsRequestsResponse =
|
|
3636
|
-
requests:
|
|
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 =
|
|
3639
|
-
name:
|
|
3640
|
-
path:
|
|
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:
|
|
3699
|
+
isRepo: z14.boolean()
|
|
3643
3700
|
});
|
|
3644
|
-
var fsListing =
|
|
3645
|
-
ok:
|
|
3646
|
-
path:
|
|
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:
|
|
3649
|
-
home:
|
|
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:
|
|
3652
|
-
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:
|
|
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:
|
|
3660
|
-
path:
|
|
3661
|
-
remoteUrl:
|
|
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 =
|
|
3671
|
-
ok:
|
|
3672
|
-
code:
|
|
3673
|
-
message:
|
|
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 =
|
|
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
|
|
3740
|
+
import { z as z15 } from "zod";
|
|
3684
3741
|
var minutes = (n) => n * 6e4;
|
|
3685
|
-
var orchestratorSettingsSchema =
|
|
3742
|
+
var orchestratorSettingsSchema = z15.object({
|
|
3686
3743
|
/** "Continue" prompts after a turn ended without a submit. */
|
|
3687
|
-
maxContinuations:
|
|
3744
|
+
maxContinuations: z15.number().int().min(0).max(20).default(3),
|
|
3688
3745
|
/** Resumes after the CLI crashed, before one fresh session. */
|
|
3689
|
-
maxCrashRetries:
|
|
3746
|
+
maxCrashRetries: z15.number().int().min(0).max(20).default(3),
|
|
3690
3747
|
/** Fix rounds after the daemon's verify failed. */
|
|
3691
|
-
maxFixAttempts:
|
|
3748
|
+
maxFixAttempts: z15.number().int().min(0).max(20).default(3),
|
|
3692
3749
|
/** "You seem stuck" prompts after a run stalled. */
|
|
3693
|
-
maxStallRecoveries:
|
|
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:
|
|
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:
|
|
3754
|
+
deviceOfflineEscalateMs: z15.number().int().min(0).default(minutes(30)),
|
|
3698
3755
|
/** An unanswered question frees its concurrency slot after this. */
|
|
3699
|
-
questionSlotReleaseMs:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
3767
|
+
ciNoChecksMs: z15.number().int().min(0).default(minutes(5)),
|
|
3711
3768
|
/** CI still running after this long goes to a person. */
|
|
3712
|
-
ciTimeoutMs:
|
|
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:
|
|
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 =
|
|
3759
|
-
code:
|
|
3760
|
-
params:
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
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
|
-
|
|
3824
|
+
z15.array(z15.record(z15.string(), z15.string()))
|
|
3768
3825
|
])
|
|
3769
3826
|
).optional()
|
|
3770
3827
|
});
|
|
3771
|
-
var prChecksSchema =
|
|
3772
|
-
state:
|
|
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:
|
|
3775
|
-
|
|
3776
|
-
name:
|
|
3777
|
-
summary:
|
|
3778
|
-
url:
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
3859
|
+
var reviewRuleSchema = z15.object({
|
|
3803
3860
|
/** In Review needs an open pull request for the issue's branch (ADR 0024). */
|
|
3804
|
-
requirePullRequest:
|
|
3861
|
+
requirePullRequest: z15.boolean().default(true),
|
|
3805
3862
|
/** ... and green CI on it. Ignored when no pull request is required. */
|
|
3806
|
-
requireCi:
|
|
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:
|
|
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
|
|
3894
|
+
import { z as z16 } from "zod";
|
|
3838
3895
|
var PREVIEW_MAX_LENGTH = 5 * 1024 * 1024;
|
|
3839
|
-
var previewHtml =
|
|
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
|
|
3857
|
-
var usernameSchema =
|
|
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 =
|
|
3862
|
-
var avatarUrlSchema =
|
|
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 =
|
|
3871
|
-
contentType:
|
|
3927
|
+
var avatarPresignRequest = z17.object({
|
|
3928
|
+
contentType: z17.enum(AVATAR_CONTENT_TYPES),
|
|
3872
3929
|
/** Bytes, checked against AVATAR_MAX_BYTES. */
|
|
3873
|
-
size:
|
|
3930
|
+
size: z17.number().int().positive()
|
|
3874
3931
|
});
|
|
3875
|
-
var avatarPresignResponse =
|
|
3876
|
-
uploadUrl:
|
|
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:
|
|
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
|
|
3945
|
+
import { z as z18 } from "zod";
|
|
3889
3946
|
var RELAY_PROTOCOL_VERSION = 1;
|
|
3890
3947
|
var MAX_INPUT_LENGTH = 2e4;
|
|
3891
|
-
var uuid =
|
|
3892
|
-
var runEvent =
|
|
3948
|
+
var uuid = z18.uuid();
|
|
3949
|
+
var runEvent = z18.discriminatedUnion("kind", [
|
|
3893
3950
|
/** One streaming chunk of the unfinished message `messageId`. */
|
|
3894
|
-
|
|
3895
|
-
kind:
|
|
3951
|
+
z18.object({
|
|
3952
|
+
kind: z18.literal("chunk"),
|
|
3896
3953
|
messageId: uuid,
|
|
3897
|
-
chunk:
|
|
3954
|
+
chunk: z18.looseObject({ type: z18.string() })
|
|
3898
3955
|
}),
|
|
3899
3956
|
/** A finished message; persisted as a `message` row, then fanned out. */
|
|
3900
|
-
|
|
3901
|
-
kind:
|
|
3957
|
+
z18.object({
|
|
3958
|
+
kind: z18.literal("message.final"),
|
|
3902
3959
|
/** Order of the message within the run. */
|
|
3903
|
-
seq:
|
|
3904
|
-
message:
|
|
3960
|
+
seq: z18.number().int().min(0),
|
|
3961
|
+
message: z18.looseObject({
|
|
3905
3962
|
id: uuid,
|
|
3906
|
-
role:
|
|
3907
|
-
parts:
|
|
3963
|
+
role: z18.enum(["system", "user", "assistant"]),
|
|
3964
|
+
parts: z18.array(z18.looseObject({ type: z18.string() }))
|
|
3908
3965
|
})
|
|
3909
3966
|
}),
|
|
3910
|
-
|
|
3911
|
-
kind:
|
|
3912
|
-
status:
|
|
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 =
|
|
3926
|
-
var presenceView =
|
|
3927
|
-
|
|
3928
|
-
|
|
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 =
|
|
3931
|
-
|
|
3987
|
+
var relayClientMessage = z18.discriminatedUnion("type", [
|
|
3988
|
+
z18.object({
|
|
3932
3989
|
v,
|
|
3933
|
-
type:
|
|
3990
|
+
type: z18.literal("subscribe"),
|
|
3934
3991
|
runId: uuid,
|
|
3935
3992
|
/** Resume after this seq; omitted = everything still buffered. */
|
|
3936
|
-
after:
|
|
3993
|
+
after: z18.number().int().min(0).optional()
|
|
3937
3994
|
}),
|
|
3938
|
-
|
|
3939
|
-
|
|
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
|
-
|
|
4002
|
+
z18.object({
|
|
3946
4003
|
v,
|
|
3947
|
-
type:
|
|
4004
|
+
type: z18.literal("send"),
|
|
3948
4005
|
runId: uuid,
|
|
3949
4006
|
messageId: uuid,
|
|
3950
|
-
text:
|
|
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
|
-
|
|
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
|
-
|
|
4016
|
+
z18.object({
|
|
3960
4017
|
v,
|
|
3961
|
-
type:
|
|
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
|
-
|
|
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 =
|
|
3981
|
-
var relayServerMessage =
|
|
3982
|
-
|
|
4037
|
+
var relayErrorCode = z18.enum(RELAY_ERROR_CODES);
|
|
4038
|
+
var relayServerMessage = z18.discriminatedUnion("type", [
|
|
4039
|
+
z18.object({
|
|
3983
4040
|
v,
|
|
3984
|
-
type:
|
|
4041
|
+
type: z18.literal("subscribed"),
|
|
3985
4042
|
runId: uuid,
|
|
3986
|
-
latestSeq:
|
|
4043
|
+
latestSeq: z18.number().int().min(0)
|
|
3987
4044
|
}),
|
|
3988
|
-
|
|
4045
|
+
z18.object({
|
|
3989
4046
|
v,
|
|
3990
|
-
type:
|
|
4047
|
+
type: z18.literal("event"),
|
|
3991
4048
|
runId: uuid,
|
|
3992
|
-
seq:
|
|
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
|
-
|
|
4056
|
+
z18.object({
|
|
4000
4057
|
v,
|
|
4001
|
-
type:
|
|
4058
|
+
type: z18.literal("accepted"),
|
|
4002
4059
|
runId: uuid,
|
|
4003
|
-
request:
|
|
4060
|
+
request: z18.enum(["send", "stop"]),
|
|
4004
4061
|
messageId: uuid.optional()
|
|
4005
4062
|
}),
|
|
4006
4063
|
/** Publisher acknowledgment with the seq the hub assigned. */
|
|
4007
|
-
|
|
4064
|
+
z18.object({
|
|
4008
4065
|
v,
|
|
4009
|
-
type:
|
|
4066
|
+
type: z18.literal("ack"),
|
|
4010
4067
|
runId: uuid,
|
|
4011
|
-
seq:
|
|
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
|
-
|
|
4075
|
+
z18.object({
|
|
4019
4076
|
v,
|
|
4020
|
-
type:
|
|
4077
|
+
type: z18.literal("presence"),
|
|
4021
4078
|
workspaceId: uuid,
|
|
4022
|
-
members:
|
|
4023
|
-
|
|
4079
|
+
members: z18.array(
|
|
4080
|
+
z18.object({
|
|
4024
4081
|
userId: uuid,
|
|
4025
4082
|
view: presenceView.nullable(),
|
|
4026
|
-
lastSeenAt:
|
|
4083
|
+
lastSeenAt: z18.number().int()
|
|
4027
4084
|
})
|
|
4028
4085
|
)
|
|
4029
4086
|
}),
|
|
4030
|
-
|
|
4087
|
+
z18.object({
|
|
4031
4088
|
v,
|
|
4032
|
-
type:
|
|
4089
|
+
type: z18.literal("error"),
|
|
4033
4090
|
code: relayErrorCode,
|
|
4034
|
-
message:
|
|
4091
|
+
message: z18.string(),
|
|
4035
4092
|
runId: uuid.optional(),
|
|
4036
|
-
minVersion:
|
|
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
|
|
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 =
|
|
4046
|
-
var updateRequiredError =
|
|
4047
|
-
error:
|
|
4048
|
-
minVersion:
|
|
4049
|
-
message:
|
|
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
|
|
4054
|
-
var coordinatorRuntimeSchema =
|
|
4055
|
-
|
|
4056
|
-
|
|
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 =
|
|
4059
|
-
name:
|
|
4060
|
-
description:
|
|
4061
|
-
inputSchema:
|
|
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 =
|
|
4064
|
-
id:
|
|
4065
|
-
harness:
|
|
4066
|
-
model:
|
|
4067
|
-
instructions:
|
|
4068
|
-
context:
|
|
4069
|
-
tools:
|
|
4070
|
-
expiresAt:
|
|
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 =
|
|
4073
|
-
var nativeCoordinatorCommandSchema =
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
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 =
|
|
4079
|
-
|
|
4080
|
-
|
|
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
|
|
4085
|
-
var machineStateSchema =
|
|
4086
|
-
var controlStateSchema =
|
|
4087
|
-
var computerToolSchema =
|
|
4088
|
-
var screenRectSchema =
|
|
4089
|
-
var computerActionSchema =
|
|
4090
|
-
var lastActionSchema = computerActionSchema.omit({ text: true }).extend({ at:
|
|
4091
|
-
var approvalViewSchema =
|
|
4092
|
-
id:
|
|
4093
|
-
digest:
|
|
4094
|
-
runId:
|
|
4095
|
-
botId:
|
|
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:
|
|
4098
|
-
expiresAt:
|
|
4154
|
+
summary: z21.string(),
|
|
4155
|
+
expiresAt: z21.iso.datetime()
|
|
4099
4156
|
});
|
|
4100
|
-
var computerStateSchema =
|
|
4157
|
+
var computerStateSchema = z21.object({
|
|
4101
4158
|
machine: machineStateSchema,
|
|
4102
4159
|
control: controlStateSchema,
|
|
4103
|
-
controlledBy:
|
|
4160
|
+
controlledBy: z21.object({ userId: z21.string() }).optional(),
|
|
4104
4161
|
lastAction: lastActionSchema.optional(),
|
|
4105
4162
|
pendingApproval: approvalViewSchema.optional()
|
|
4106
4163
|
});
|
|
4107
|
-
var viewerModeSchema =
|
|
4108
|
-
var viewerRequestSchema =
|
|
4109
|
-
var viewerGrantSchema =
|
|
4110
|
-
var createBotSchema =
|
|
4111
|
-
var botViewSchema =
|
|
4112
|
-
var approvalDecisionSchema =
|
|
4113
|
-
var computerTaskStateSchema =
|
|
4114
|
-
var computerTaskSchema =
|
|
4115
|
-
var computerEventSchema =
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
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 =
|
|
4122
|
-
var localComputerCall =
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
key:
|
|
4128
|
-
modifiers:
|
|
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
|
-
|
|
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 =
|
|
4133
|
-
id:
|
|
4134
|
-
runId:
|
|
4189
|
+
var localComputerRequest = z21.object({
|
|
4190
|
+
id: z21.uuid(),
|
|
4191
|
+
runId: z21.uuid(),
|
|
4135
4192
|
target: reviewDigestSchema,
|
|
4136
|
-
display:
|
|
4193
|
+
display: z21.string().regex(/^:[1-9][0-9]{0,2}$/).optional(),
|
|
4137
4194
|
call: localComputerCall,
|
|
4138
|
-
expiresAt:
|
|
4195
|
+
expiresAt: z21.number().int().positive(),
|
|
4139
4196
|
digest: reviewDigestSchema
|
|
4140
4197
|
}).strict();
|
|
4141
|
-
var localComputerDecision =
|
|
4142
|
-
var computerSyncBody =
|
|
4143
|
-
var computerSyncResponse =
|
|
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
|
|
4204
|
+
import { z as z22 } from "zod";
|
|
4148
4205
|
var HOSTED_NATIVE_IMAGE = "node@sha256:6449e19d8184d84062525b6a7524def03146c2cb04a7f08b076680d0e8e4240a";
|
|
4149
|
-
var
|
|
4150
|
-
var subscriptionRouteSchema =
|
|
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 =
|
|
4158
|
-
id:
|
|
4159
|
-
ownerId:
|
|
4160
|
-
workspaceId:
|
|
4161
|
-
provider:
|
|
4162
|
-
state:
|
|
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:
|
|
4226
|
+
revision: z22.number().int().positive(),
|
|
4170
4227
|
quota: quotaSnapshotSchema
|
|
4171
4228
|
}).strict();
|
|
4172
|
-
var subscriptionBindingSchema =
|
|
4173
|
-
id:
|
|
4174
|
-
ownerId:
|
|
4175
|
-
workspaceId:
|
|
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:
|
|
4178
|
-
connectionId:
|
|
4179
|
-
connectionRevision:
|
|
4234
|
+
consumerId: id3,
|
|
4235
|
+
connectionId: id3,
|
|
4236
|
+
connectionRevision: z22.number().int().positive(),
|
|
4180
4237
|
route: subscriptionRouteSchema
|
|
4181
4238
|
}).strict();
|
|
4182
|
-
var nativeBrokerContextSchema =
|
|
4183
|
-
route:
|
|
4184
|
-
modelId:
|
|
4185
|
-
revision:
|
|
4186
|
-
accountId:
|
|
4187
|
-
plan:
|
|
4188
|
-
expiresAt:
|
|
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
|
|
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.
|
|
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: "
|
|
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
|
|
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
|
|
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 =
|
|
4766
|
-
var title =
|
|
4767
|
-
var captureUploadRequest =
|
|
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:
|
|
4840
|
+
captureId: z23.uuid().optional(),
|
|
4770
4841
|
title,
|
|
4771
|
-
contentType:
|
|
4772
|
-
size:
|
|
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 =
|
|
4776
|
-
|
|
4777
|
-
|
|
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 =
|
|
4780
|
-
captureId:
|
|
4850
|
+
var captureUploadResponse = z23.object({
|
|
4851
|
+
captureId: z23.uuid(),
|
|
4781
4852
|
upload: captureUploadTarget
|
|
4782
4853
|
});
|
|
4783
|
-
var captureView =
|
|
4784
|
-
id:
|
|
4785
|
-
kind:
|
|
4786
|
-
contentType:
|
|
4787
|
-
title:
|
|
4788
|
-
size:
|
|
4789
|
-
durationMs:
|
|
4790
|
-
source:
|
|
4791
|
-
createdAt:
|
|
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 =
|
|
4794
|
-
var screenCaptureRequest =
|
|
4795
|
-
|
|
4796
|
-
|
|
4797
|
-
|
|
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 =
|
|
4800
|
-
|
|
4801
|
-
|
|
4802
|
-
|
|
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
|
|
4883
|
+
import { z as z25 } from "zod";
|
|
4813
4884
|
|
|
4814
4885
|
// ../protocol/src/mailbox.ts
|
|
4815
|
-
import { z as
|
|
4816
|
-
var mailboxSend =
|
|
4817
|
-
var mailboxAck =
|
|
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:
|
|
4890
|
+
mailbox_recipients: z24.object({}).strict(),
|
|
4820
4891
|
mailbox_send: mailboxSend,
|
|
4821
|
-
mailbox_inbox:
|
|
4892
|
+
mailbox_inbox: z24.object({}).strict(),
|
|
4822
4893
|
mailbox_ack: mailboxAck,
|
|
4823
|
-
mailbox_sent:
|
|
4894
|
+
mailbox_sent: z24.object({}).strict()
|
|
4824
4895
|
};
|
|
4825
4896
|
|
|
4826
4897
|
// src/run-mailbox.ts
|
|
4827
|
-
var requestSchema =
|
|
4828
|
-
|
|
4829
|
-
|
|
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
|
|
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:
|
|
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 !==
|
|
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:
|
|
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 =
|
|
4966
|
-
function checkId(
|
|
4967
|
-
if (
|
|
4968
|
-
throw new InvalidIdError(`Refusing id ${JSON.stringify(
|
|
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
|
|
5041
|
+
return id4;
|
|
4971
5042
|
}
|
|
4972
|
-
function seg2(
|
|
4973
|
-
return encodeURIComponent(checkId(
|
|
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 =
|
|
5006
|
-
const response =
|
|
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
|
-
|
|
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 =
|
|
5353
|
-
device_code:
|
|
5354
|
-
user_code:
|
|
5355
|
-
verification_uri:
|
|
5356
|
-
verification_uri_complete:
|
|
5357
|
-
expires_in:
|
|
5358
|
-
interval:
|
|
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 =
|
|
5361
|
-
var errorResponse =
|
|
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
|
|
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 ||
|
|
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 ||
|
|
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
|
|
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,
|
|
6596
|
-
for (const name of [`${
|
|
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
|
|
6604
|
-
if (!ID.test(
|
|
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, `${
|
|
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:
|
|
6617
|
-
drop(dir,
|
|
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 =
|
|
6622
|
-
const pendingPath = pendingDir ? join9(pendingDir, `${
|
|
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,
|
|
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:
|
|
6760
|
+
writeJsonAtomic(pendingPath, { captureId: id4, sha256: sha2562 });
|
|
6654
6761
|
}
|
|
6655
|
-
target = await link.beginCapture(runId, { ...pendingPath ? { captureId:
|
|
6656
|
-
if (pendingPath && target.captureId !==
|
|
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,
|
|
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:
|
|
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:
|
|
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:
|
|
6678
|
-
drop(dir,
|
|
6679
|
-
if (pendingDir) rmSync7(join9(pendingDir, `${
|
|
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
|
|
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",
|
|
6877
|
+
runDir: join10(stateDir, "runs", id4),
|
|
6771
6878
|
/** Daemon only. */
|
|
6772
|
-
pidFile: join10(stateDir, "pids", `${
|
|
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
|
|
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 =
|
|
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
|
|
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:
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
7338
|
-
if (!(schema instanceof
|
|
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
|
|
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:
|
|
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(
|
|
7694
|
+
if (!pending.delete(id4)) return;
|
|
7587
7695
|
controller.abort();
|
|
7588
|
-
send({ type: "decision", id:
|
|
7696
|
+
send({ type: "decision", id: id4, allow: false });
|
|
7589
7697
|
}, NETWORK_DECISION_MS);
|
|
7590
|
-
pending.set(
|
|
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(
|
|
7703
|
+
if (!pending.delete(id4)) return;
|
|
7596
7704
|
clearTimeout(timer);
|
|
7597
|
-
send({ type: "decision", id:
|
|
7705
|
+
send({ type: "decision", id: id4, allow: allow === true && !stopped && !lifetime.signal.aborted && !controller.signal.aborted });
|
|
7598
7706
|
}, () => {
|
|
7599
|
-
if (pending.delete(
|
|
7707
|
+
if (pending.delete(id4)) {
|
|
7600
7708
|
clearTimeout(timer);
|
|
7601
|
-
send({ type: "decision", id:
|
|
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
|
|
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:
|
|
7850
|
-
{ type: "text-delta", id:
|
|
7851
|
-
{ type: "text-end", id:
|
|
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:
|
|
7856
|
-
{ type: "reasoning-delta", id:
|
|
7857
|
-
{ type: "reasoning-end", id:
|
|
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 [
|
|
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:
|
|
9087
|
+
const { kind, id: id4 } = this.open;
|
|
8978
9088
|
this.open = null;
|
|
8979
|
-
return [{ type: kind === "text" ? "text-end" : "reasoning-end", id:
|
|
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
|
|
8986
|
-
this.open = { kind, id:
|
|
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:
|
|
9099
|
+
id: id5
|
|
8990
9100
|
});
|
|
8991
9101
|
}
|
|
8992
|
-
const
|
|
9102
|
+
const id4 = this.open?.id;
|
|
8993
9103
|
chunks.push(
|
|
8994
|
-
kind === "text" ? { type: "text-delta", id:
|
|
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
|
|
9447
|
-
yield { type: "chunk", chunk: { type: "text-start", id:
|
|
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:
|
|
9561
|
+
chunk: { type: "text-delta", id: id4, delta: `Noted: ${text3}` }
|
|
9451
9562
|
};
|
|
9452
|
-
yield { type: "chunk", chunk: { type: "text-end", id:
|
|
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((
|
|
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(([
|
|
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),
|
|
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:
|
|
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
|
|
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
|
-
([
|
|
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(([
|
|
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
|
|
11763
|
-
const input = this.inputs.get(
|
|
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 ?
|
|
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 =
|
|
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 (
|
|
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
|
|
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",
|
|
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
|
|
13134
|
-
var webUrlSchema =
|
|
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 [
|
|
13384
|
-
if (labels?.["com.mikka.native.resource"] !== record.nonce || record.id && record.id !==
|
|
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",
|
|
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
|
|
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
|
|
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:
|
|
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 =
|
|
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
|
|
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 = ++
|
|
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
|
|
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 [
|
|
14438
|
+
for (const [id4, row] of this.pending) {
|
|
14325
14439
|
if (row.token !== token) continue;
|
|
14326
|
-
this.pending.delete(
|
|
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(
|
|
14333
|
-
const row = this.pending.get(
|
|
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(
|
|
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(
|
|
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:
|
|
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
|
|
14493
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
14380
14494
|
function credentialAwareExecutor(deps) {
|
|
14381
14495
|
return async (driver, call, display, runId, context) => {
|
|
14382
|
-
const
|
|
14383
|
-
const resolved = await deps.consumeMatchingIntent(runId, context.actionId,
|
|
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 !==
|
|
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
|
-
(
|
|
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
|
|
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:
|
|
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,
|
|
15014
|
+
await link.answerFsRequest(deviceId, id4, result);
|
|
14896
15015
|
})
|
|
14897
15016
|
);
|
|
14898
15017
|
} catch (error) {
|