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