@kubitnodes/stellaris 0.3.21 → 0.3.23
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/README.md +4 -4
- package/dist/cli/index.js +1007 -598
- package/dist/server/index.js +1252 -671
- package/package.json +3 -1
- package/web/dist/assets/{BackLink-23Q1JvmZ.js → BackLink-DGYs80bb.js} +1 -1
- package/web/dist/assets/Button-f4jgBZY1.js +1 -0
- package/web/dist/assets/ChannelForms-q9zdj4p2.js +1 -0
- package/web/dist/assets/ChannelView-CGs_aWL3.js +2 -0
- package/web/dist/assets/CitizenView-gcIo_sKt.js +2 -0
- package/web/dist/assets/CitizensView-DZ7S8vnJ.js +1 -0
- package/web/dist/assets/{CliIcon-BOSygXeI.js → CliIcon-CLHaA65A.js} +1 -1
- package/web/dist/assets/CronsView-1wns6Uwv.js +1 -0
- package/web/dist/assets/KnowledgeView-Cxfi2-Pt.js +1 -0
- package/web/dist/assets/Markdown-BhtIFcWc.js +30 -0
- package/web/dist/assets/MessageItem-Bk9eBp1U.js +1 -0
- package/web/dist/assets/MetricsView-CTEH6rJn.js +1 -0
- package/web/dist/assets/NeedsYouView-2VNqH2Sb.js +1 -0
- package/web/dist/assets/Overview-CS9HCSmm.js +1 -0
- package/web/dist/assets/{Pane-BendOaje.js → Pane-CJYRVkwh.js} +1 -1
- package/web/dist/assets/{Picker-BuVnakvi.js → Picker-DoxCN6C7.js} +1 -1
- package/web/dist/assets/ProjectView-CJ3r4UdN.js +1 -0
- package/web/dist/assets/ProposalView-DLn9dNPp.js +2 -0
- package/web/dist/assets/ProposalsView-B-cOxTsQ.js +1 -0
- package/web/dist/assets/Quota-Bo7UdWTV.js +1 -0
- package/web/dist/assets/RunnersView-DlQruhwp.js +1 -0
- package/web/dist/assets/SocietyView-Bl4ErnV8.js +1 -0
- package/web/dist/assets/StickyList-MVP34ytV.js +1 -0
- package/web/dist/assets/SubjectThread-BFFnHxIF.js +1 -0
- package/web/dist/assets/TaskFileView-GZ0eQFUb.js +4 -0
- package/web/dist/assets/TaskView-DppFelLW.js +3 -0
- package/web/dist/assets/TasksView-DDNXzeG4.js +1 -0
- package/web/dist/assets/ThreadForms-C846TvtS.js +1 -0
- package/web/dist/assets/ThreadItem-C8cou6wD.js +1 -0
- package/web/dist/assets/ThreadView-DvSGDYoD.js +1 -0
- package/web/dist/assets/citizen-B2Dlbcpe.js +1 -0
- package/web/dist/assets/compose-BmqQmcZH.js +1 -0
- package/web/dist/assets/format-DT52SbbR.js +55 -0
- package/web/dist/assets/governance-Cr5OlQnw.js +1 -0
- package/web/dist/assets/index-BTVy_xFF.js +23 -0
- package/web/dist/assets/index-DzV6CCnG.css +2 -0
- package/web/dist/assets/mentions-D5hNgtg6.js +3 -0
- package/web/dist/assets/{tasks-CyXIxoAy.js → tasks-R3YgpYTe.js} +1 -1
- package/web/dist/assets/useMatch-pEF6RJ6Q.js +1 -0
- package/web/dist/index.html +9 -10
- package/web/dist/assets/ChannelForms-0Cwh59E7.js +0 -1
- package/web/dist/assets/ChannelView-CqWV1zza.js +0 -2
- package/web/dist/assets/CitizenView-s5OdjXmB.js +0 -2
- package/web/dist/assets/CitizensView-r6SZLnVl.js +0 -1
- package/web/dist/assets/CronsView-Y-bAE0l2.js +0 -1
- package/web/dist/assets/KnowledgeView-CI4PJWwm.js +0 -1
- package/web/dist/assets/Markdown-DyckB74r.js +0 -32
- package/web/dist/assets/MessageItem-DI05jbrI.js +0 -1
- package/web/dist/assets/MetricsView-DKh-lEW5.js +0 -1
- package/web/dist/assets/NeedsYouView-C6FfiTsg.js +0 -1
- package/web/dist/assets/Overview-D5RvWBg5.js +0 -1
- package/web/dist/assets/ProjectView-blBEh70W.js +0 -1
- package/web/dist/assets/ProposalView-CMntpKTc.js +0 -2
- package/web/dist/assets/ProposalsView-CVUAV2Mm.js +0 -1
- package/web/dist/assets/RunnersView-B-wuWVgB.js +0 -1
- package/web/dist/assets/SocietyView-CaVbfJWz.js +0 -1
- package/web/dist/assets/SubjectThread-Bd_-sDhJ.js +0 -1
- package/web/dist/assets/TaskFileView-CO4Y97OT.js +0 -4
- package/web/dist/assets/TaskView-DRZoHALo.js +0 -3
- package/web/dist/assets/TasksView-CQVQo3zF.js +0 -1
- package/web/dist/assets/ThreadForms-CUSeWu0c.js +0 -1
- package/web/dist/assets/ThreadItem-BPYYXh3V.js +0 -1
- package/web/dist/assets/ThreadView-BcI2i6FI.js +0 -1
- package/web/dist/assets/citizen-Eff1h9rA.js +0 -1
- package/web/dist/assets/compose-D73Agshx.js +0 -1
- package/web/dist/assets/format-fw0G_Vff.js +0 -55
- package/web/dist/assets/governance-sRsfOw52.js +0 -1
- package/web/dist/assets/index-BkOq4PSU.css +0 -2
- package/web/dist/assets/index-CYiok0pT.js +0 -23
- package/web/dist/assets/link-Cl7vKbOz.js +0 -1
- package/web/dist/assets/mentions-BCdV0bMK.js +0 -1
- package/web/dist/assets/useMatch-D-tEHQEw.js +0 -1
- package/web/dist/assets/useStickyScroll-Bn4YyEXL.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { Command } from "commander";
|
|
|
9
9
|
import { chmod as chmod2, cp, mkdir as mkdir4, readdir as readdir3, readFile as readFile4, rename as rename3, rm as rm2, stat as stat3, writeFile as writeFile4 } from "node:fs/promises";
|
|
10
10
|
import path6 from "node:path";
|
|
11
11
|
import { decodeTime, monotonicFactory } from "ulid";
|
|
12
|
-
import { z as
|
|
12
|
+
import { z as z16 } from "zod";
|
|
13
13
|
|
|
14
14
|
// packages/shared/dist/ids.js
|
|
15
15
|
import { z } from "zod";
|
|
@@ -64,7 +64,8 @@ var VERB_NAMES = [
|
|
|
64
64
|
"create_cron",
|
|
65
65
|
"update_cron",
|
|
66
66
|
"remove_cron",
|
|
67
|
-
"remove_skill"
|
|
67
|
+
"remove_skill",
|
|
68
|
+
"upload_image"
|
|
68
69
|
];
|
|
69
70
|
var VerbNameSchema = z2.enum(VERB_NAMES);
|
|
70
71
|
var CharterTriggerSchema = z2.enum(["user_post", "ops_event", "heartbeat"]);
|
|
@@ -93,6 +94,7 @@ var USER_ROLE = "user";
|
|
|
93
94
|
var USER_NAME = "user";
|
|
94
95
|
var MEMBER_VERBS = [
|
|
95
96
|
"post_message",
|
|
97
|
+
"upload_image",
|
|
96
98
|
"read_inbox",
|
|
97
99
|
"search",
|
|
98
100
|
"open_thread",
|
|
@@ -169,7 +171,7 @@ var SEED_ROLES = [
|
|
|
169
171
|
];
|
|
170
172
|
|
|
171
173
|
// packages/shared/dist/board.js
|
|
172
|
-
import { z as
|
|
174
|
+
import { z as z5 } from "zod";
|
|
173
175
|
|
|
174
176
|
// packages/shared/dist/crons.js
|
|
175
177
|
import { Cron as Pattern } from "croner";
|
|
@@ -288,6 +290,79 @@ function describeSchedule(schedule, societyZone) {
|
|
|
288
290
|
return schedule.timezone === void 0 ? `\`${schedule.cron}\` in the society's time zone, ${societyZone}` : `\`${schedule.cron}\` in ${schedule.timezone}`;
|
|
289
291
|
}
|
|
290
292
|
|
|
293
|
+
// packages/shared/dist/quota.js
|
|
294
|
+
import { z as z4 } from "zod";
|
|
295
|
+
var QuotaWindowSchema = z4.object({
|
|
296
|
+
/**
|
|
297
|
+
* The CLI's own name for the window: Claude's `five_hour`, `seven_day`, `seven_day_opus`, and
|
|
298
|
+
* `model:<label>` for a model's weekly window; Codex's `primary` and `secondary`.
|
|
299
|
+
*/
|
|
300
|
+
key: z4.string().min(1).max(80),
|
|
301
|
+
/** What a scoped window counts, as the CLI labels it, such as a model's name. */
|
|
302
|
+
label: z4.string().min(1).max(80).optional(),
|
|
303
|
+
/** The window's length in minutes, when known. */
|
|
304
|
+
minutes: z4.number().int().positive().nullable().default(null),
|
|
305
|
+
/** How much of the window is used, in percent, or null when the CLI did not say. */
|
|
306
|
+
usedPercent: z4.number().nonnegative().nullable().default(null),
|
|
307
|
+
/** When the window starts afresh, when known. */
|
|
308
|
+
resetsAt: IsoDateTimeSchema.nullable().default(null),
|
|
309
|
+
/** When the CLI last reported this window. */
|
|
310
|
+
observedAt: IsoDateTimeSchema
|
|
311
|
+
});
|
|
312
|
+
var QuotaStatusSchema = z4.enum(["allowed", "warning", "limited", "none"]);
|
|
313
|
+
var QuotaCreditsSchema = z4.object({
|
|
314
|
+
hasCredits: z4.boolean(),
|
|
315
|
+
unlimited: z4.boolean(),
|
|
316
|
+
balance: z4.string().max(40).nullable()
|
|
317
|
+
});
|
|
318
|
+
var QuotaExtraUsageSchema = z4.object({
|
|
319
|
+
enabled: z4.boolean(),
|
|
320
|
+
monthlyLimit: z4.number().nonnegative().nullable(),
|
|
321
|
+
usedCredits: z4.number().nonnegative().nullable(),
|
|
322
|
+
currency: z4.string().min(1).max(8).nullable()
|
|
323
|
+
});
|
|
324
|
+
var CliQuotaSchema = z4.object({
|
|
325
|
+
/** When the CLI last reported anything here. */
|
|
326
|
+
observedAt: IsoDateTimeSchema,
|
|
327
|
+
/** Whether it came from a turn's stream or from asking the CLI. */
|
|
328
|
+
source: z4.enum(["turn", "read"]),
|
|
329
|
+
status: QuotaStatusSchema,
|
|
330
|
+
/** While `limited`: when work can go on, when known, and the window that stopped it. */
|
|
331
|
+
limitedUntil: IsoDateTimeSchema.nullable().default(null),
|
|
332
|
+
limitedBy: z4.string().min(1).max(80).nullable().default(null),
|
|
333
|
+
/** The plan's name as the CLI gives it, such as `max` or `pro`. */
|
|
334
|
+
plan: z4.string().min(1).max(40).nullable().default(null),
|
|
335
|
+
windows: z4.array(QuotaWindowSchema).max(24).default([]),
|
|
336
|
+
credits: QuotaCreditsSchema.nullable().default(null),
|
|
337
|
+
extraUsage: QuotaExtraUsageSchema.nullable().default(null)
|
|
338
|
+
});
|
|
339
|
+
function mergeQuota(previous, next) {
|
|
340
|
+
if (previous === void 0) {
|
|
341
|
+
return next;
|
|
342
|
+
}
|
|
343
|
+
const windows = new Map(previous.windows.map((window) => [window.key, window]));
|
|
344
|
+
for (const window of next.windows) {
|
|
345
|
+
windows.set(window.key, window);
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
...next,
|
|
349
|
+
plan: next.plan ?? previous.plan,
|
|
350
|
+
credits: next.credits ?? previous.credits,
|
|
351
|
+
extraUsage: next.extraUsage ?? previous.extraUsage,
|
|
352
|
+
windows: [...windows.values()]
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
function readings(quota) {
|
|
356
|
+
const windows = quota.windows.map((window) => `${window.key}=${window.usedPercent === null ? "?" : Math.round(window.usedPercent)}@${window.resetsAt === null ? "?" : Math.round(Date.parse(window.resetsAt) / 6e4)}`).toSorted();
|
|
357
|
+
return windows.join(",");
|
|
358
|
+
}
|
|
359
|
+
function quotaChanged(previous, next) {
|
|
360
|
+
if (previous === void 0) {
|
|
361
|
+
return true;
|
|
362
|
+
}
|
|
363
|
+
return previous.status !== next.status || previous.limitedUntil !== next.limitedUntil || previous.plan !== next.plan || previous.credits?.balance !== next.credits?.balance || previous.extraUsage?.usedCredits !== next.extraUsage?.usedCredits || readings(previous) !== readings(next);
|
|
364
|
+
}
|
|
365
|
+
|
|
291
366
|
// packages/shared/dist/board.js
|
|
292
367
|
var ASK_CHANNEL = "asks";
|
|
293
368
|
var SOCIETY_CHANNELS = ["general", "governance", ASK_CHANNEL];
|
|
@@ -300,24 +375,24 @@ var SOCIETY_SCOPE = "society";
|
|
|
300
375
|
function wakeScope(member, project2) {
|
|
301
376
|
return project2 !== null && member.memberships.includes(project2) ? project2 : SOCIETY_SCOPE;
|
|
302
377
|
}
|
|
303
|
-
var CliKindSchema =
|
|
304
|
-
var ArchivedChannelSchema =
|
|
378
|
+
var CliKindSchema = z5.enum(["claude", "codex"]);
|
|
379
|
+
var ArchivedChannelSchema = z5.object({
|
|
305
380
|
name: NameSchema,
|
|
306
381
|
at: IsoDateTimeSchema,
|
|
307
382
|
by: NameSchema,
|
|
308
|
-
reason:
|
|
383
|
+
reason: z5.string().min(1)
|
|
309
384
|
});
|
|
310
|
-
var SocietySchema =
|
|
311
|
-
name:
|
|
312
|
-
version:
|
|
385
|
+
var SocietySchema = z5.object({
|
|
386
|
+
name: z5.string().min(1),
|
|
387
|
+
version: z5.literal(1),
|
|
313
388
|
createdAt: IsoDateTimeSchema,
|
|
314
389
|
/** The channels that take posts; an archived one moves to `archivedChannels`. */
|
|
315
|
-
channels:
|
|
316
|
-
archivedChannels:
|
|
390
|
+
channels: z5.array(NameSchema),
|
|
391
|
+
archivedChannels: z5.array(ArchivedChannelSchema).default([]),
|
|
317
392
|
/** The time zone crons are read in when they name none, and every prompt tells the time in; the user's to set. */
|
|
318
393
|
timezone: TimeZoneSchema.default(DEFAULT_TIME_ZONE)
|
|
319
394
|
});
|
|
320
|
-
var CompletionEffectSchema =
|
|
395
|
+
var CompletionEffectSchema = z5.enum(["none", "merge", "ghpr"]);
|
|
321
396
|
var GITHUB_REMOTE = [
|
|
322
397
|
/^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?\/?$/,
|
|
323
398
|
/^git@github\.com:([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?$/,
|
|
@@ -333,7 +408,7 @@ function githubRepository(remote) {
|
|
|
333
408
|
return null;
|
|
334
409
|
}
|
|
335
410
|
var PULL_REQUEST_URL = /^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)\/pull\/([1-9]\d*)\/?$/;
|
|
336
|
-
var PullRequestUrlSchema =
|
|
411
|
+
var PullRequestUrlSchema = z5.string().trim().regex(PULL_REQUEST_URL, "a pull request's address, https://github.com/<owner>/<repo>/pull/<number>");
|
|
337
412
|
function parsePullRequestUrl(url) {
|
|
338
413
|
const match = PULL_REQUEST_URL.exec(url.trim());
|
|
339
414
|
return match?.[1] === void 0 || match[2] === void 0 || match[3] === void 0 ? null : { owner: match[1], name: match[2], number: Number(match[3]) };
|
|
@@ -341,72 +416,72 @@ function parsePullRequestUrl(url) {
|
|
|
341
416
|
function sameRepository(a, b) {
|
|
342
417
|
return a.owner.toLowerCase() === b.owner.toLowerCase() && a.name.toLowerCase() === b.name.toLowerCase();
|
|
343
418
|
}
|
|
344
|
-
var MergeSubjectSchema =
|
|
345
|
-
var PullRequestLinkSchema =
|
|
419
|
+
var MergeSubjectSchema = z5.string().trim().min(1).max(300).regex(/^[^\n]+$/, "a merge commit's subject is one line");
|
|
420
|
+
var PullRequestLinkSchema = z5.object({
|
|
346
421
|
url: PullRequestUrlSchema,
|
|
347
|
-
number:
|
|
422
|
+
number: z5.number().int().positive(),
|
|
348
423
|
subject: MergeSubjectSchema.optional(),
|
|
349
|
-
body:
|
|
424
|
+
body: z5.string().max(2e4).optional(),
|
|
350
425
|
linkedBy: NameSchema,
|
|
351
426
|
linkedAt: IsoDateTimeSchema,
|
|
352
427
|
/**
|
|
353
428
|
* Once its `ghpr` task was abandoned, how the board's closing of it on GitHub went: `ok` false
|
|
354
429
|
* leaves it open, for the reason `detail` gives.
|
|
355
430
|
*/
|
|
356
|
-
closed:
|
|
431
|
+
closed: z5.object({ at: IsoDateTimeSchema, ok: z5.boolean(), detail: z5.string() }).optional()
|
|
357
432
|
});
|
|
358
|
-
var DefaultBranchSchema =
|
|
359
|
-
var StageIdSchema =
|
|
433
|
+
var DefaultBranchSchema = z5.string().trim().min(1).max(100).regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/, "a branch name is letters, digits, and . _ / -").refine((branch) => !branch.includes("..") && !branch.includes("//") && !branch.endsWith("/") && !branch.endsWith(".") && !branch.endsWith(".lock"), "not a branch name git takes").refine((branch) => !branch.startsWith("task/") && !branch.startsWith("agent/"), "task/ and agent/ hold the board's own branches");
|
|
434
|
+
var StageIdSchema = z5.string().regex(/^s[1-9][0-9]*$/, "expected a stage id such as s1");
|
|
360
435
|
var stageFields = {
|
|
361
|
-
name:
|
|
436
|
+
name: z5.string().trim().min(1).max(120),
|
|
362
437
|
role: NameSchema.optional(),
|
|
363
438
|
agent: NameSchema.optional(),
|
|
364
|
-
gate:
|
|
439
|
+
gate: z5.boolean().default(false)
|
|
365
440
|
};
|
|
366
441
|
function oneAssignee(stage) {
|
|
367
442
|
return stage.role === void 0 || stage.agent === void 0;
|
|
368
443
|
}
|
|
369
444
|
var ONE_ASSIGNEE = { message: "a stage names a role or an agent, not both" };
|
|
370
|
-
var PlanStageSchema =
|
|
371
|
-
var PlanEditStageSchema =
|
|
372
|
-
var PlanSchema =
|
|
373
|
-
var PlanEditSchema =
|
|
374
|
-
var ProjectSchema =
|
|
445
|
+
var PlanStageSchema = z5.object(stageFields).refine(oneAssignee, ONE_ASSIGNEE);
|
|
446
|
+
var PlanEditStageSchema = z5.object({ id: StageIdSchema.optional(), ...stageFields }).refine(oneAssignee, ONE_ASSIGNEE);
|
|
447
|
+
var PlanSchema = z5.array(PlanStageSchema);
|
|
448
|
+
var PlanEditSchema = z5.array(PlanEditStageSchema);
|
|
449
|
+
var ProjectSchema = z5.object({
|
|
375
450
|
slug: NameSchema,
|
|
376
|
-
name:
|
|
377
|
-
repo:
|
|
378
|
-
defaultBranch:
|
|
451
|
+
name: z5.string().min(1),
|
|
452
|
+
repo: z5.string().nullable(),
|
|
453
|
+
defaultBranch: z5.string().min(1),
|
|
379
454
|
/** The channels that take posts; an archived one moves to `archivedChannels`. */
|
|
380
|
-
channels:
|
|
381
|
-
archivedChannels:
|
|
382
|
-
members:
|
|
383
|
-
approvers:
|
|
384
|
-
requiredCapabilities:
|
|
455
|
+
channels: z5.array(NameSchema),
|
|
456
|
+
archivedChannels: z5.array(ArchivedChannelSchema).default([]),
|
|
457
|
+
members: z5.array(NameSchema),
|
|
458
|
+
approvers: z5.array(NameSchema),
|
|
459
|
+
requiredCapabilities: z5.array(z5.string()),
|
|
385
460
|
createdAt: IsoDateTimeSchema,
|
|
386
461
|
onDone: CompletionEffectSchema.default("none"),
|
|
387
462
|
/** The runner the project lives on, which holds its repository; set on the project's first turn. */
|
|
388
463
|
runner: NameSchema.optional(),
|
|
389
464
|
/** Set once the project is archived: nobody belongs to it, and nothing more is posted, filed, or joined there. */
|
|
390
|
-
archived:
|
|
465
|
+
archived: z5.object({ at: IsoDateTimeSchema, by: NameSchema, reason: z5.string().min(1) }).optional()
|
|
391
466
|
});
|
|
392
|
-
var TaskStepSchema =
|
|
393
|
-
action:
|
|
467
|
+
var TaskStepSchema = z5.object({
|
|
468
|
+
action: z5.enum(["advanced", "returned", "abandoned", "landed", "reopened"]),
|
|
394
469
|
stage: StageIdSchema,
|
|
395
470
|
to: StageIdSchema.nullable()
|
|
396
471
|
});
|
|
397
|
-
var ProposalStepSchema =
|
|
398
|
-
var MessageStepSchema =
|
|
472
|
+
var ProposalStepSchema = z5.object({ action: z5.enum(["approved", "rejected"]) });
|
|
473
|
+
var MessageStepSchema = z5.union([TaskStepSchema, ProposalStepSchema]);
|
|
399
474
|
function isTaskStep(step) {
|
|
400
475
|
return "stage" in step;
|
|
401
476
|
}
|
|
402
|
-
var KnowledgeNoticeSchema =
|
|
403
|
-
kind:
|
|
404
|
-
action:
|
|
477
|
+
var KnowledgeNoticeSchema = z5.object({
|
|
478
|
+
kind: z5.literal("knowledge"),
|
|
479
|
+
action: z5.enum(["written", "updated", "removed"]),
|
|
405
480
|
topic: NameSchema,
|
|
406
481
|
project: NameSchema.nullable()
|
|
407
482
|
});
|
|
408
|
-
var MessageNoticeSchema =
|
|
409
|
-
var MessageFrontmatterSchema =
|
|
483
|
+
var MessageNoticeSchema = z5.discriminatedUnion("kind", [KnowledgeNoticeSchema]);
|
|
484
|
+
var MessageFrontmatterSchema = z5.object({
|
|
410
485
|
id: UlidSchema,
|
|
411
486
|
author: NameSchema,
|
|
412
487
|
channel: ChannelRefSchema,
|
|
@@ -420,7 +495,7 @@ var MessageFrontmatterSchema = z4.object({
|
|
|
420
495
|
/** On a post a verb made about its work, such as a knowledge topic's note: what it records. */
|
|
421
496
|
notice: MessageNoticeSchema.optional(),
|
|
422
497
|
ts: IsoDateTimeSchema,
|
|
423
|
-
mentions:
|
|
498
|
+
mentions: z5.array(NameSchema)
|
|
424
499
|
});
|
|
425
500
|
var MessageRefSchema = MessageFrontmatterSchema.pick({
|
|
426
501
|
id: true,
|
|
@@ -429,16 +504,16 @@ var MessageRefSchema = MessageFrontmatterSchema.pick({
|
|
|
429
504
|
thread: true,
|
|
430
505
|
ts: true
|
|
431
506
|
});
|
|
432
|
-
var TaskStatusSchema =
|
|
433
|
-
var ThreadStateSchema =
|
|
434
|
-
var ThreadSubjectSchema =
|
|
435
|
-
kind:
|
|
507
|
+
var TaskStatusSchema = z5.enum(["open", "claimed", "done", "abandoned"]);
|
|
508
|
+
var ThreadStateSchema = z5.enum(["open", "closed"]);
|
|
509
|
+
var ThreadSubjectSchema = z5.object({
|
|
510
|
+
kind: z5.enum(["task", "proposal"]),
|
|
436
511
|
id: UlidSchema
|
|
437
512
|
});
|
|
438
|
-
var ThreadFrontmatterSchema =
|
|
513
|
+
var ThreadFrontmatterSchema = z5.object({
|
|
439
514
|
id: UlidSchema,
|
|
440
515
|
channel: ChannelRefSchema,
|
|
441
|
-
title:
|
|
516
|
+
title: z5.string().min(1).max(200),
|
|
442
517
|
subject: ThreadSubjectSchema.optional(),
|
|
443
518
|
state: ThreadStateSchema,
|
|
444
519
|
openedBy: NameSchema,
|
|
@@ -446,28 +521,28 @@ var ThreadFrontmatterSchema = z4.object({
|
|
|
446
521
|
closedBy: NameSchema.optional(),
|
|
447
522
|
closedAt: IsoDateTimeSchema.optional()
|
|
448
523
|
});
|
|
449
|
-
var StageSchema =
|
|
524
|
+
var StageSchema = z5.object({
|
|
450
525
|
id: StageIdSchema,
|
|
451
|
-
name:
|
|
526
|
+
name: z5.string().min(1),
|
|
452
527
|
role: NameSchema.optional(),
|
|
453
528
|
agent: NameSchema.optional(),
|
|
454
|
-
gate:
|
|
529
|
+
gate: z5.boolean().default(false),
|
|
455
530
|
/** Everyone who has held the stage, oldest first. */
|
|
456
|
-
holders:
|
|
531
|
+
holders: z5.array(NameSchema).default([]),
|
|
457
532
|
completedBy: NameSchema.optional(),
|
|
458
533
|
completedAt: IsoDateTimeSchema.optional()
|
|
459
534
|
});
|
|
460
|
-
var TaskReturnSchema =
|
|
535
|
+
var TaskReturnSchema = z5.object({
|
|
461
536
|
from: StageIdSchema,
|
|
462
537
|
by: NameSchema,
|
|
463
538
|
at: IsoDateTimeSchema
|
|
464
539
|
});
|
|
465
|
-
var TaskFrontmatterSchema =
|
|
540
|
+
var TaskFrontmatterSchema = z5.object({
|
|
466
541
|
id: UlidSchema,
|
|
467
542
|
project: NameSchema,
|
|
468
543
|
/** The channel of the project the task is filed in, where its thread hangs. */
|
|
469
544
|
channel: NameSchema.default("general"),
|
|
470
|
-
title:
|
|
545
|
+
title: z5.string().min(1),
|
|
471
546
|
status: TaskStatusSchema,
|
|
472
547
|
createdBy: NameSchema,
|
|
473
548
|
createdAt: IsoDateTimeSchema,
|
|
@@ -476,19 +551,19 @@ var TaskFrontmatterSchema = z4.object({
|
|
|
476
551
|
claimedBy: NameSchema.optional(),
|
|
477
552
|
leaseExpiresAt: IsoDateTimeSchema.optional(),
|
|
478
553
|
parentId: UlidSchema.optional(),
|
|
479
|
-
blockedBy:
|
|
480
|
-
requiredCapabilities:
|
|
481
|
-
stages:
|
|
554
|
+
blockedBy: z5.array(UlidSchema),
|
|
555
|
+
requiredCapabilities: z5.array(z5.string()),
|
|
556
|
+
stages: z5.array(StageSchema).min(1),
|
|
482
557
|
stage: StageIdSchema,
|
|
483
558
|
/** When the current stage last became current or lost its holder: the waiting clock. */
|
|
484
559
|
stageSince: IsoDateTimeSchema,
|
|
485
560
|
/** The highest stage number issued, so a removed stage's id is never reused. */
|
|
486
|
-
stageSeq:
|
|
561
|
+
stageSeq: z5.number().int().positive(),
|
|
487
562
|
onDone: CompletionEffectSchema.default("none"),
|
|
488
563
|
/** The pull request a `ghpr` task lands through. */
|
|
489
564
|
pullRequest: PullRequestLinkSchema.optional(),
|
|
490
565
|
/** The last stage is complete and the completion effect is running. */
|
|
491
|
-
completing:
|
|
566
|
+
completing: z5.boolean().default(false),
|
|
492
567
|
/** The latest send-back while its rework lasts: cleared once the task reaches that stage again. */
|
|
493
568
|
returned: TaskReturnSchema.optional()
|
|
494
569
|
});
|
|
@@ -512,79 +587,90 @@ function mayHoldStage(member, task2) {
|
|
|
512
587
|
}
|
|
513
588
|
return !(stage.gate && task2.stages.slice(0, index).some((s) => s.holders.includes(member.name)));
|
|
514
589
|
}
|
|
515
|
-
var ModelNameSchema =
|
|
516
|
-
var EffortSchema =
|
|
517
|
-
var EffortOptionSchema =
|
|
590
|
+
var ModelNameSchema = z5.string().trim().min(1).max(120).regex(/^[\w.:/[\]-]+$/, "a model name is one word of letters, digits, and . _ : / - [ ]");
|
|
591
|
+
var EffortSchema = z5.string().trim().min(1).max(32).regex(/^[a-z][a-z0-9_-]*$/, "an effort is one lowercase word, such as high");
|
|
592
|
+
var EffortOptionSchema = z5.object({
|
|
518
593
|
id: EffortSchema,
|
|
519
|
-
description:
|
|
594
|
+
description: z5.string().default("")
|
|
520
595
|
});
|
|
521
|
-
var ModelOptionSchema =
|
|
596
|
+
var ModelOptionSchema = z5.object({
|
|
522
597
|
id: ModelNameSchema,
|
|
523
|
-
name:
|
|
524
|
-
description:
|
|
525
|
-
isDefault:
|
|
526
|
-
efforts:
|
|
598
|
+
name: z5.string(),
|
|
599
|
+
description: z5.string().default(""),
|
|
600
|
+
isDefault: z5.boolean().default(false),
|
|
601
|
+
efforts: z5.array(EffortOptionSchema).default([]),
|
|
527
602
|
defaultEffort: EffortSchema.optional()
|
|
528
603
|
});
|
|
529
|
-
var RunnerModelsSchema =
|
|
604
|
+
var RunnerModelsSchema = z5.object({
|
|
530
605
|
runner: NameSchema,
|
|
531
606
|
cli: CliKindSchema,
|
|
532
|
-
models:
|
|
607
|
+
models: z5.array(ModelOptionSchema)
|
|
533
608
|
});
|
|
534
|
-
var AgentStatusSchema =
|
|
535
|
-
var AgentSchema =
|
|
609
|
+
var AgentStatusSchema = z5.enum(["active", "retired"]);
|
|
610
|
+
var AgentSchema = z5.object({
|
|
536
611
|
name: NameSchema,
|
|
537
612
|
role: NameSchema,
|
|
538
613
|
cli: CliKindSchema.nullable(),
|
|
539
|
-
model:
|
|
614
|
+
model: z5.string().optional(),
|
|
540
615
|
/** The reasoning effort set for the agent's turns; the model's own default applies otherwise. */
|
|
541
|
-
effort:
|
|
616
|
+
effort: z5.string().optional(),
|
|
542
617
|
/** The runner preferred for the agent's turns where nothing else decides; any runner with its CLI otherwise. */
|
|
543
618
|
homeRunner: NameSchema.optional(),
|
|
544
|
-
memberships:
|
|
545
|
-
subscriptions:
|
|
619
|
+
memberships: z5.array(NameSchema),
|
|
620
|
+
subscriptions: z5.array(ChannelRefSchema),
|
|
546
621
|
status: AgentStatusSchema,
|
|
547
622
|
createdAt: IsoDateTimeSchema,
|
|
548
|
-
tokenHash:
|
|
623
|
+
tokenHash: z5.string().min(1),
|
|
549
624
|
retiredAt: IsoDateTimeSchema.optional(),
|
|
550
|
-
retiredReason:
|
|
625
|
+
retiredReason: z5.string().optional()
|
|
551
626
|
});
|
|
552
|
-
var MemberSchema =
|
|
627
|
+
var MemberSchema = z5.object({
|
|
553
628
|
name: NameSchema,
|
|
554
629
|
role: NameSchema,
|
|
555
630
|
cli: CliKindSchema.nullable(),
|
|
556
631
|
homeRunner: NameSchema.optional(),
|
|
557
632
|
status: AgentStatusSchema,
|
|
558
|
-
resident:
|
|
633
|
+
resident: z5.boolean().default(false),
|
|
559
634
|
/** The model configured on the record, if any; the CLI's own default applies otherwise. */
|
|
560
|
-
model:
|
|
635
|
+
model: z5.string().optional(),
|
|
561
636
|
/** The model the CLI reported on the citizen's last turn. */
|
|
562
|
-
lastModel:
|
|
637
|
+
lastModel: z5.string().optional(),
|
|
563
638
|
/** The reasoning effort configured on the record, if any; the model's own default applies otherwise. */
|
|
564
|
-
effort:
|
|
639
|
+
effort: z5.string().optional(),
|
|
565
640
|
/** The citizen's own skills, by name. */
|
|
566
|
-
skills:
|
|
567
|
-
memberships:
|
|
568
|
-
subscriptions:
|
|
569
|
-
claimsHeld:
|
|
570
|
-
tasksDone:
|
|
641
|
+
skills: z5.array(NameSchema).default([]),
|
|
642
|
+
memberships: z5.array(NameSchema),
|
|
643
|
+
subscriptions: z5.array(ChannelRefSchema),
|
|
644
|
+
claimsHeld: z5.number().int().nonnegative().default(0),
|
|
645
|
+
tasksDone: z5.number().int().nonnegative().default(0),
|
|
571
646
|
lastTurnAt: IsoDateTimeSchema.optional(),
|
|
572
|
-
lastTurnOutcome:
|
|
647
|
+
lastTurnOutcome: z5.string().optional(),
|
|
573
648
|
createdAt: IsoDateTimeSchema,
|
|
574
649
|
retiredAt: IsoDateTimeSchema.optional()
|
|
575
650
|
});
|
|
576
|
-
var RunnerOsSchema =
|
|
577
|
-
var
|
|
651
|
+
var RunnerOsSchema = z5.enum(["linux", "windows", "darwin"]);
|
|
652
|
+
var GitIdentityPartSchema = z5.enum(["name", "email"]);
|
|
653
|
+
var RunnerSchema = z5.object({
|
|
578
654
|
name: NameSchema,
|
|
579
655
|
os: RunnerOsSchema,
|
|
580
|
-
clis:
|
|
581
|
-
capabilities:
|
|
656
|
+
clis: z5.array(CliKindSchema),
|
|
657
|
+
capabilities: z5.array(z5.string()),
|
|
582
658
|
/** The release the runner reported when it last registered; absent until it has. */
|
|
583
|
-
version:
|
|
584
|
-
|
|
585
|
-
|
|
659
|
+
version: z5.string().optional(),
|
|
660
|
+
/**
|
|
661
|
+
* What the runner's account lacked of a git identity when it last registered, empty when it had
|
|
662
|
+
* both; absent while the runner has not said, as one from before runners checked never does.
|
|
663
|
+
*/
|
|
664
|
+
gitIdentityMissing: z5.array(GitIdentityPartSchema).optional(),
|
|
665
|
+
status: z5.enum(["connected", "disconnected"]),
|
|
666
|
+
lastSeen: IsoDateTimeSchema.optional(),
|
|
667
|
+
/**
|
|
668
|
+
* Each CLI's plan quota as its login on this runner last reported it, from a turn's stream or a
|
|
669
|
+
* read; absent until one has.
|
|
670
|
+
*/
|
|
671
|
+
quotas: z5.partialRecord(CliKindSchema, CliQuotaSchema).optional()
|
|
586
672
|
});
|
|
587
|
-
var ProposalKindSchema =
|
|
673
|
+
var ProposalKindSchema = z5.enum([
|
|
588
674
|
"role",
|
|
589
675
|
"member",
|
|
590
676
|
"channel",
|
|
@@ -593,42 +679,42 @@ var ProposalKindSchema = z4.enum([
|
|
|
593
679
|
"skill",
|
|
594
680
|
"archive"
|
|
595
681
|
]);
|
|
596
|
-
var ProposalStatusSchema =
|
|
682
|
+
var ProposalStatusSchema = z5.enum([
|
|
597
683
|
"proposed",
|
|
598
684
|
"approved",
|
|
599
685
|
"rejected",
|
|
600
686
|
"provisioned",
|
|
601
687
|
"retired"
|
|
602
688
|
]);
|
|
603
|
-
var MemberProposalSchema =
|
|
689
|
+
var MemberProposalSchema = z5.object({
|
|
604
690
|
name: NameSchema,
|
|
605
691
|
role: NameSchema,
|
|
606
692
|
cli: CliKindSchema,
|
|
607
|
-
model:
|
|
693
|
+
model: z5.string().optional(),
|
|
608
694
|
homeRunner: NameSchema.optional(),
|
|
609
|
-
memberships:
|
|
610
|
-
subscriptions:
|
|
611
|
-
seedInstructions:
|
|
695
|
+
memberships: z5.array(NameSchema).default([]),
|
|
696
|
+
subscriptions: z5.array(ChannelRefSchema).default([]),
|
|
697
|
+
seedInstructions: z5.string().optional()
|
|
612
698
|
});
|
|
613
|
-
var ChannelProposalSchema =
|
|
699
|
+
var ChannelProposalSchema = z5.object({
|
|
614
700
|
project: NameSchema.nullable().default(null),
|
|
615
701
|
name: NameSchema,
|
|
616
|
-
purpose:
|
|
702
|
+
purpose: z5.string().min(1)
|
|
617
703
|
});
|
|
618
|
-
var RoleChangesSchema =
|
|
619
|
-
maxReplicas:
|
|
620
|
-
backlogThreshold:
|
|
621
|
-
wakeTriggers:
|
|
622
|
-
verbs:
|
|
704
|
+
var RoleChangesSchema = z5.strictObject({
|
|
705
|
+
maxReplicas: z5.number().int().min(1).optional(),
|
|
706
|
+
backlogThreshold: z5.number().positive().optional(),
|
|
707
|
+
wakeTriggers: z5.array(CharterTriggerSchema).optional(),
|
|
708
|
+
verbs: z5.array(VerbNameSchema).optional()
|
|
623
709
|
}).refine((changes) => Object.values(changes).some((value) => value !== void 0), {
|
|
624
710
|
message: "a reallocation changes at least one of maxReplicas, backlogThreshold, wakeTriggers, verbs"
|
|
625
711
|
});
|
|
626
|
-
var ReallocationProposalSchema =
|
|
712
|
+
var ReallocationProposalSchema = z5.object({
|
|
627
713
|
role: NameSchema,
|
|
628
714
|
changes: RoleChangesSchema,
|
|
629
|
-
description:
|
|
715
|
+
description: z5.string().min(1)
|
|
630
716
|
});
|
|
631
|
-
var LegacyReallocationSchema =
|
|
717
|
+
var LegacyReallocationSchema = z5.object({ description: z5.string().min(1) });
|
|
632
718
|
function applyRoleChanges(role2, changes) {
|
|
633
719
|
return {
|
|
634
720
|
...role2,
|
|
@@ -663,18 +749,18 @@ function roleChangeLines(role2, changes) {
|
|
|
663
749
|
}
|
|
664
750
|
return lines;
|
|
665
751
|
}
|
|
666
|
-
var RetirementProposalSchema =
|
|
752
|
+
var RetirementProposalSchema = z5.object({
|
|
667
753
|
agent: NameSchema,
|
|
668
|
-
reason:
|
|
754
|
+
reason: z5.string().min(1)
|
|
669
755
|
});
|
|
670
|
-
var ArchiveProposalSchema =
|
|
756
|
+
var ArchiveProposalSchema = z5.object({
|
|
671
757
|
project: NameSchema,
|
|
672
|
-
reason:
|
|
758
|
+
reason: z5.string().min(1)
|
|
673
759
|
});
|
|
674
|
-
var SkillProposalSchema =
|
|
760
|
+
var SkillProposalSchema = z5.object({
|
|
675
761
|
name: NameSchema,
|
|
676
|
-
summary:
|
|
677
|
-
body:
|
|
762
|
+
summary: z5.string().min(1).max(200),
|
|
763
|
+
body: z5.string().min(1).optional()
|
|
678
764
|
});
|
|
679
765
|
var ProposalCharterSchemas = {
|
|
680
766
|
role: RoleCharterSchema,
|
|
@@ -777,23 +863,23 @@ function describeCharter(kind, charter) {
|
|
|
777
863
|
}
|
|
778
864
|
return `${kind} ${JSON.stringify(charter)}`;
|
|
779
865
|
}
|
|
780
|
-
var SkillSchema =
|
|
866
|
+
var SkillSchema = z5.object({
|
|
781
867
|
name: NameSchema,
|
|
782
|
-
summary:
|
|
783
|
-
scope:
|
|
784
|
-
path:
|
|
868
|
+
summary: z5.string().default(""),
|
|
869
|
+
scope: z5.enum(["own", "society"]),
|
|
870
|
+
path: z5.string().min(1)
|
|
785
871
|
});
|
|
786
|
-
var RemovedSkillSchema =
|
|
872
|
+
var RemovedSkillSchema = z5.object({
|
|
787
873
|
name: NameSchema,
|
|
788
|
-
reason:
|
|
874
|
+
reason: z5.string().min(1),
|
|
789
875
|
removedBy: NameSchema,
|
|
790
876
|
removedAt: IsoDateTimeSchema
|
|
791
877
|
});
|
|
792
|
-
var HomeConflictSchema =
|
|
878
|
+
var HomeConflictSchema = z5.object({
|
|
793
879
|
/** The copy, relative to the home. */
|
|
794
|
-
path:
|
|
880
|
+
path: z5.string().min(1),
|
|
795
881
|
/** The file beside it, whose version the board kept. */
|
|
796
|
-
file:
|
|
882
|
+
file: z5.string().min(1),
|
|
797
883
|
/** When the copy reached the board. */
|
|
798
884
|
since: IsoDateTimeSchema
|
|
799
885
|
});
|
|
@@ -801,79 +887,79 @@ var CONFLICT_COPY = /^(.+)\.conflict-[^/.]+$/;
|
|
|
801
887
|
function conflictCopyOf(copy) {
|
|
802
888
|
return CONFLICT_COPY.exec(copy)?.[1] ?? null;
|
|
803
889
|
}
|
|
804
|
-
var CommitIdSchema =
|
|
805
|
-
var HomeFileChangeSchema =
|
|
806
|
-
path:
|
|
807
|
-
status:
|
|
890
|
+
var CommitIdSchema = z5.string().regex(/^[0-9a-f]{40}([0-9a-f]{24})?$/);
|
|
891
|
+
var HomeFileChangeSchema = z5.object({
|
|
892
|
+
path: z5.string().min(1),
|
|
893
|
+
status: z5.enum(["added", "modified", "deleted"]),
|
|
808
894
|
/** Lines added and removed, or null for a binary file. */
|
|
809
|
-
added:
|
|
810
|
-
removed:
|
|
895
|
+
added: z5.number().int().nonnegative().nullable(),
|
|
896
|
+
removed: z5.number().int().nonnegative().nullable()
|
|
811
897
|
});
|
|
812
|
-
var HomeChangeSchema =
|
|
898
|
+
var HomeChangeSchema = z5.object({
|
|
813
899
|
commit: CommitIdSchema,
|
|
814
900
|
at: IsoDateTimeSchema,
|
|
815
|
-
kind:
|
|
816
|
-
author:
|
|
901
|
+
kind: z5.enum(["turn", "board", "merge"]),
|
|
902
|
+
author: z5.string(),
|
|
817
903
|
/** The turn that made it, from the runner's commit message. */
|
|
818
904
|
turnId: UlidSchema.optional(),
|
|
819
|
-
subject:
|
|
820
|
-
files:
|
|
905
|
+
subject: z5.string(),
|
|
906
|
+
files: z5.array(HomeFileChangeSchema)
|
|
821
907
|
});
|
|
822
|
-
var HomeHistorySchema =
|
|
823
|
-
changes:
|
|
908
|
+
var HomeHistorySchema = z5.object({
|
|
909
|
+
changes: z5.array(HomeChangeSchema),
|
|
824
910
|
/** Whether older commits remain past the ones read. */
|
|
825
|
-
more:
|
|
911
|
+
more: z5.boolean()
|
|
826
912
|
});
|
|
827
913
|
var HomeFileDiffSchema = HomeFileChangeSchema.pick({ path: true, status: true }).extend({
|
|
828
|
-
patch:
|
|
914
|
+
patch: z5.string().nullable(),
|
|
829
915
|
/** The patch was cut at its size limit. */
|
|
830
|
-
truncated:
|
|
916
|
+
truncated: z5.boolean()
|
|
831
917
|
});
|
|
832
|
-
var KnowledgeSchema =
|
|
918
|
+
var KnowledgeSchema = z5.object({
|
|
833
919
|
topic: NameSchema,
|
|
834
920
|
project: NameSchema.nullable(),
|
|
835
|
-
revision:
|
|
921
|
+
revision: z5.number().int().min(0),
|
|
836
922
|
updatedBy: NameSchema,
|
|
837
923
|
updatedAt: IsoDateTimeSchema
|
|
838
924
|
});
|
|
839
|
-
var RemovedKnowledgeSchema =
|
|
925
|
+
var RemovedKnowledgeSchema = z5.object({
|
|
840
926
|
topic: NameSchema,
|
|
841
927
|
project: NameSchema.nullable(),
|
|
842
928
|
removedBy: NameSchema,
|
|
843
929
|
removedAt: IsoDateTimeSchema
|
|
844
930
|
});
|
|
845
|
-
var DashboardSchema =
|
|
931
|
+
var DashboardSchema = z5.object({
|
|
846
932
|
project: NameSchema,
|
|
847
|
-
revision:
|
|
933
|
+
revision: z5.number().int().min(0),
|
|
848
934
|
/** Absent until someone updates the dashboard the project began with. */
|
|
849
935
|
updatedBy: NameSchema.optional(),
|
|
850
936
|
updatedAt: IsoDateTimeSchema.optional(),
|
|
851
|
-
body:
|
|
937
|
+
body: z5.string()
|
|
852
938
|
});
|
|
853
|
-
var ProposalOriginSchema =
|
|
939
|
+
var ProposalOriginSchema = z5.object({
|
|
854
940
|
scope: NameSchema,
|
|
855
941
|
thread: UlidSchema.optional(),
|
|
856
942
|
channel: NameSchema.optional()
|
|
857
943
|
});
|
|
858
944
|
var SKILL_FILES_LIMIT = 100;
|
|
859
945
|
var SKILL_BYTES_LIMIT = 10 * 1024 * 1024;
|
|
860
|
-
var SkillFileSchema =
|
|
861
|
-
path:
|
|
862
|
-
size:
|
|
863
|
-
executable:
|
|
946
|
+
var SkillFileSchema = z5.object({
|
|
947
|
+
path: z5.string().min(1),
|
|
948
|
+
size: z5.number().int().nonnegative(),
|
|
949
|
+
executable: z5.boolean()
|
|
864
950
|
});
|
|
865
|
-
var SkillFilesSchema =
|
|
951
|
+
var SkillFilesSchema = z5.object({
|
|
866
952
|
/** The commit of the proposer's home the files came from. */
|
|
867
953
|
commit: CommitIdSchema,
|
|
868
954
|
takenAt: IsoDateTimeSchema,
|
|
869
|
-
files:
|
|
955
|
+
files: z5.array(SkillFileSchema)
|
|
870
956
|
});
|
|
871
957
|
var SkillFileContentSchema = SkillFileSchema.extend({
|
|
872
|
-
text:
|
|
958
|
+
text: z5.string().nullable(),
|
|
873
959
|
/** The text was cut at its size limit. */
|
|
874
|
-
truncated:
|
|
960
|
+
truncated: z5.boolean()
|
|
875
961
|
});
|
|
876
|
-
var ProposalFrontmatterSchema =
|
|
962
|
+
var ProposalFrontmatterSchema = z5.object({
|
|
877
963
|
id: UlidSchema,
|
|
878
964
|
kind: ProposalKindSchema,
|
|
879
965
|
proposedBy: NameSchema,
|
|
@@ -885,146 +971,185 @@ var ProposalFrontmatterSchema = z4.object({
|
|
|
885
971
|
skillFiles: SkillFilesSchema.optional(),
|
|
886
972
|
decidedBy: NameSchema.optional(),
|
|
887
973
|
decidedAt: IsoDateTimeSchema.optional(),
|
|
888
|
-
reason:
|
|
889
|
-
charter:
|
|
974
|
+
reason: z5.string().optional(),
|
|
975
|
+
charter: z5.record(z5.string(), z5.unknown()),
|
|
890
976
|
/** What approval created, for kinds the board provisions: the agent, channel, role, or retirement. */
|
|
891
977
|
provisionedAt: IsoDateTimeSchema.optional(),
|
|
892
|
-
provision:
|
|
978
|
+
provision: z5.record(z5.string(), z5.unknown()).optional()
|
|
893
979
|
});
|
|
894
|
-
var DecisionSchema =
|
|
980
|
+
var DecisionSchema = z5.object({
|
|
895
981
|
id: UlidSchema,
|
|
896
982
|
proposalId: UlidSchema,
|
|
897
983
|
decidedBy: NameSchema,
|
|
898
|
-
outcome:
|
|
899
|
-
reason:
|
|
984
|
+
outcome: z5.enum(["approved", "rejected"]),
|
|
985
|
+
reason: z5.string().optional(),
|
|
900
986
|
ts: IsoDateTimeSchema
|
|
901
987
|
});
|
|
902
988
|
|
|
903
989
|
// packages/shared/dist/verbs.js
|
|
904
|
-
import { z as
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
990
|
+
import { z as z7 } from "zod";
|
|
991
|
+
|
|
992
|
+
// packages/shared/dist/images.js
|
|
993
|
+
import { z as z6 } from "zod";
|
|
994
|
+
var IMAGE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
995
|
+
var ImageTypeSchema = z6.enum(["png", "jpeg", "gif", "webp"]);
|
|
996
|
+
function startsWith(bytes, prefix, at = 0) {
|
|
997
|
+
for (let index = 0; index < prefix.length; index += 1) {
|
|
998
|
+
if (bytes[at + index] !== prefix[index]) {
|
|
999
|
+
return false;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return true;
|
|
1003
|
+
}
|
|
1004
|
+
var ascii = (text) => new TextEncoder().encode(text);
|
|
1005
|
+
function imageTypeOf(bytes) {
|
|
1006
|
+
if (startsWith(bytes, [137, 80, 78, 71, 13, 10, 26, 10])) {
|
|
1007
|
+
return "png";
|
|
1008
|
+
}
|
|
1009
|
+
if (startsWith(bytes, [255, 216, 255])) {
|
|
1010
|
+
return "jpeg";
|
|
1011
|
+
}
|
|
1012
|
+
if (startsWith(bytes, ascii("GIF87a")) || startsWith(bytes, ascii("GIF89a"))) {
|
|
1013
|
+
return "gif";
|
|
1014
|
+
}
|
|
1015
|
+
if (startsWith(bytes, ascii("RIFF")) && startsWith(bytes, ascii("WEBP"), 8)) {
|
|
1016
|
+
return "webp";
|
|
1017
|
+
}
|
|
1018
|
+
return null;
|
|
1019
|
+
}
|
|
1020
|
+
var ImagePathSchema = z6.string().min(1).max(4096).refine((value) => !value.includes("\0"), { message: "a path with no NUL character" });
|
|
1021
|
+
var IMAGE_SCHEME = "image:";
|
|
1022
|
+
var UploadedImageSchema = z6.object({
|
|
1023
|
+
id: UlidSchema,
|
|
1024
|
+
type: ImageTypeSchema,
|
|
1025
|
+
size: z6.number().int().positive(),
|
|
1026
|
+
markdown: z6.string()
|
|
1027
|
+
});
|
|
1028
|
+
|
|
1029
|
+
// packages/shared/dist/verbs.js
|
|
1030
|
+
var MomentSchema = z7.iso.datetime({ offset: true });
|
|
1031
|
+
var CronTitleSchema = z7.string().trim().min(1).max(120);
|
|
1032
|
+
var CronNoteSchema = z7.string().trim().min(1).max(4e3);
|
|
908
1033
|
var VerbInputs = {
|
|
909
|
-
post_message:
|
|
1034
|
+
post_message: z7.object({
|
|
910
1035
|
/** Required outside a thread; in one it may be left out, and must otherwise be the thread's. */
|
|
911
1036
|
channel: ChannelRefSchema.optional(),
|
|
912
|
-
body:
|
|
1037
|
+
body: z7.string().min(1),
|
|
913
1038
|
thread_id: UlidSchema.optional()
|
|
914
1039
|
}),
|
|
915
|
-
read_inbox:
|
|
1040
|
+
read_inbox: z7.object({
|
|
916
1041
|
since_cursor: UlidSchema.nullable().optional(),
|
|
917
|
-
limit:
|
|
918
|
-
advance:
|
|
1042
|
+
limit: z7.number().int().positive().max(200).default(50),
|
|
1043
|
+
advance: z7.boolean().default(true)
|
|
919
1044
|
}),
|
|
920
|
-
search:
|
|
921
|
-
query:
|
|
1045
|
+
search: z7.object({
|
|
1046
|
+
query: z7.string().min(1),
|
|
922
1047
|
project: NameSchema.optional(),
|
|
923
1048
|
channel: ChannelRefSchema.optional(),
|
|
924
|
-
limit:
|
|
1049
|
+
limit: z7.number().int().positive().max(100).default(20)
|
|
925
1050
|
}),
|
|
926
1051
|
/** On a task or a proposal, whose id the thread takes, or on a channel with a title. */
|
|
927
|
-
open_thread:
|
|
1052
|
+
open_thread: z7.object({
|
|
928
1053
|
task_id: UlidSchema.optional(),
|
|
929
1054
|
proposal_id: UlidSchema.optional(),
|
|
930
1055
|
channel: ChannelRefSchema.optional(),
|
|
931
|
-
title:
|
|
1056
|
+
title: z7.string().min(1).max(200).optional()
|
|
932
1057
|
}),
|
|
933
|
-
close_thread:
|
|
934
|
-
create_task:
|
|
1058
|
+
close_thread: z7.object({ thread_id: UlidSchema, summary: z7.string().min(1) }),
|
|
1059
|
+
create_task: z7.object({
|
|
935
1060
|
project: NameSchema,
|
|
936
|
-
title:
|
|
937
|
-
body:
|
|
1061
|
+
title: z7.string().min(1).max(200),
|
|
1062
|
+
body: z7.string().default(""),
|
|
938
1063
|
parent_id: UlidSchema.optional(),
|
|
939
|
-
required_capabilities:
|
|
1064
|
+
required_capabilities: z7.array(z7.string()).default([]),
|
|
940
1065
|
/** The plan; without it the task gets one stage, work, that anyone in the project may take. */
|
|
941
|
-
stages:
|
|
1066
|
+
stages: z7.array(PlanStageSchema).min(1).optional(),
|
|
942
1067
|
/** A channel of the project the task belongs to, such as a release's; its thread opens there. */
|
|
943
1068
|
channel: NameSchema.default("general")
|
|
944
1069
|
}),
|
|
945
|
-
claim_task:
|
|
946
|
-
release_task:
|
|
947
|
-
update_task:
|
|
1070
|
+
claim_task: z7.object({ task_id: UlidSchema }),
|
|
1071
|
+
release_task: z7.object({ task_id: UlidSchema }),
|
|
1072
|
+
update_task: z7.object({
|
|
948
1073
|
task_id: UlidSchema,
|
|
949
1074
|
/** Move the task back to this earlier stage. */
|
|
950
1075
|
stage: StageIdSchema.optional(),
|
|
951
|
-
status:
|
|
1076
|
+
status: z7.enum(["abandoned"]).optional(),
|
|
952
1077
|
/** Posted to the task's thread as the caller, marked with the step when the task moved. */
|
|
953
|
-
note:
|
|
954
|
-
blocked_by:
|
|
1078
|
+
note: z7.string().min(1).optional(),
|
|
1079
|
+
blocked_by: z7.array(UlidSchema).optional(),
|
|
955
1080
|
/**
|
|
956
1081
|
* The pull request a `ghpr` task lands through, on its project's repository, with the merge
|
|
957
1082
|
* commit's subject and body; null unlinks it.
|
|
958
1083
|
*/
|
|
959
|
-
pull_request:
|
|
1084
|
+
pull_request: z7.object({
|
|
960
1085
|
url: PullRequestUrlSchema,
|
|
961
1086
|
merge_subject: MergeSubjectSchema.optional(),
|
|
962
|
-
merge_body:
|
|
1087
|
+
merge_body: z7.string().max(2e4).optional()
|
|
963
1088
|
}).nullable().optional()
|
|
964
1089
|
}),
|
|
965
|
-
get_task:
|
|
966
|
-
subscribe:
|
|
967
|
-
unsubscribe:
|
|
968
|
-
propose:
|
|
1090
|
+
get_task: z7.object({ task_id: UlidSchema }),
|
|
1091
|
+
subscribe: z7.object({ channel: ChannelRefSchema }),
|
|
1092
|
+
unsubscribe: z7.object({ channel: ChannelRefSchema }),
|
|
1093
|
+
propose: z7.object({
|
|
969
1094
|
kind: ProposalKindSchema,
|
|
970
|
-
charter:
|
|
971
|
-
rationale:
|
|
1095
|
+
charter: z7.record(z7.string(), z7.unknown()),
|
|
1096
|
+
rationale: z7.string().default("")
|
|
972
1097
|
}),
|
|
973
|
-
approve:
|
|
974
|
-
reject:
|
|
975
|
-
create_project:
|
|
1098
|
+
approve: z7.object({ proposal_id: UlidSchema, reason: z7.string().optional() }),
|
|
1099
|
+
reject: z7.object({ proposal_id: UlidSchema, reason: z7.string().min(1) }),
|
|
1100
|
+
create_project: z7.object({
|
|
976
1101
|
slug: NameSchema,
|
|
977
|
-
name:
|
|
978
|
-
repo:
|
|
1102
|
+
name: z7.string().min(1).optional(),
|
|
1103
|
+
repo: z7.string().min(1).nullable().default(null),
|
|
979
1104
|
default_branch: DefaultBranchSchema.default("main"),
|
|
980
1105
|
on_done: CompletionEffectSchema.optional()
|
|
981
1106
|
}),
|
|
982
|
-
join_project:
|
|
983
|
-
leave_project:
|
|
984
|
-
write_knowledge:
|
|
1107
|
+
join_project: z7.object({ project: NameSchema, agent: NameSchema.optional() }),
|
|
1108
|
+
leave_project: z7.object({ project: NameSchema, agent: NameSchema.optional() }),
|
|
1109
|
+
write_knowledge: z7.object({
|
|
985
1110
|
/** A project you belong to, or null for society knowledge, which the steward and the user curate. */
|
|
986
1111
|
project: NameSchema.nullable().default(null),
|
|
987
1112
|
topic: NameSchema,
|
|
988
|
-
body:
|
|
1113
|
+
body: z7.string().min(1),
|
|
989
1114
|
/** The `revision` in the frontmatter of the topic you read, 0 when it names none or for a new topic. */
|
|
990
|
-
revision:
|
|
1115
|
+
revision: z7.number().int().min(0)
|
|
991
1116
|
}),
|
|
992
|
-
remove_knowledge:
|
|
1117
|
+
remove_knowledge: z7.object({
|
|
993
1118
|
/** As for write_knowledge: a project you belong to, or null for society knowledge. */
|
|
994
1119
|
project: NameSchema.nullable().default(null),
|
|
995
1120
|
topic: NameSchema
|
|
996
1121
|
}),
|
|
997
|
-
plan_task:
|
|
1122
|
+
plan_task: z7.object({
|
|
998
1123
|
task_id: UlidSchema,
|
|
999
|
-
stages:
|
|
1124
|
+
stages: z7.array(PlanEditStageSchema),
|
|
1000
1125
|
on_done: CompletionEffectSchema.optional()
|
|
1001
1126
|
}),
|
|
1002
1127
|
/** The note is posted to the task's thread as the caller, marked with the step. */
|
|
1003
|
-
advance_task:
|
|
1004
|
-
configure_project:
|
|
1128
|
+
advance_task: z7.object({ task_id: UlidSchema, note: z7.string().min(1).optional() }),
|
|
1129
|
+
configure_project: z7.object({
|
|
1005
1130
|
project: NameSchema,
|
|
1006
1131
|
on_done: CompletionEffectSchema.optional(),
|
|
1007
1132
|
/** A new display name; the slug, which everything refers to the project by, never changes. */
|
|
1008
|
-
name:
|
|
1133
|
+
name: z7.string().trim().min(1).max(120).optional(),
|
|
1009
1134
|
/** The branch tasks start from and land on from now; tasks in play keep their branches. */
|
|
1010
1135
|
default_branch: DefaultBranchSchema.optional()
|
|
1011
1136
|
}),
|
|
1012
|
-
archive_project:
|
|
1013
|
-
create_channel:
|
|
1137
|
+
archive_project: z7.object({ project: NameSchema, reason: z7.string().min(1) }),
|
|
1138
|
+
create_channel: z7.object({
|
|
1014
1139
|
/** A project, or null for a channel of the society. */
|
|
1015
1140
|
project: NameSchema.nullable().default(null),
|
|
1016
1141
|
name: NameSchema,
|
|
1017
|
-
purpose:
|
|
1142
|
+
purpose: z7.string().min(1)
|
|
1018
1143
|
}),
|
|
1019
|
-
archive_channel:
|
|
1020
|
-
update_dashboard:
|
|
1144
|
+
archive_channel: z7.object({ channel: ChannelRefSchema, reason: z7.string().min(1) }),
|
|
1145
|
+
update_dashboard: z7.object({
|
|
1021
1146
|
project: NameSchema,
|
|
1022
1147
|
/** The whole dashboard as markdown; the board keeps its frontmatter. */
|
|
1023
|
-
body:
|
|
1148
|
+
body: z7.string().min(1),
|
|
1024
1149
|
/** The `revision` in the frontmatter of the dashboard you read, 0 when it names none. */
|
|
1025
|
-
revision:
|
|
1150
|
+
revision: z7.number().int().min(0)
|
|
1026
1151
|
}),
|
|
1027
|
-
create_cron:
|
|
1152
|
+
create_cron: z7.object({
|
|
1028
1153
|
title: CronTitleSchema,
|
|
1029
1154
|
/** What to do when it fires; quoted in the prompt of every turn it starts. */
|
|
1030
1155
|
note: CronNoteSchema,
|
|
@@ -1043,10 +1168,10 @@ var VerbInputs = {
|
|
|
1043
1168
|
/** An open channel of that place other than general, whose conversation it fires in. */
|
|
1044
1169
|
channel: NameSchema.optional()
|
|
1045
1170
|
}),
|
|
1046
|
-
update_cron:
|
|
1171
|
+
update_cron: z7.object({
|
|
1047
1172
|
cron_id: UlidSchema,
|
|
1048
1173
|
/** Pause it, or resume it, which starts its schedule afresh from now. */
|
|
1049
|
-
paused:
|
|
1174
|
+
paused: z7.boolean().optional(),
|
|
1050
1175
|
title: CronTitleSchema.optional(),
|
|
1051
1176
|
note: CronNoteSchema.optional(),
|
|
1052
1177
|
/** A new expression, or `at` for one time; either starts the schedule afresh. */
|
|
@@ -1055,12 +1180,16 @@ var VerbInputs = {
|
|
|
1055
1180
|
timezone: TimeZoneSchema.nullable().optional(),
|
|
1056
1181
|
at: MomentSchema.optional()
|
|
1057
1182
|
}),
|
|
1058
|
-
remove_cron:
|
|
1059
|
-
remove_skill:
|
|
1183
|
+
remove_cron: z7.object({ cron_id: UlidSchema, reason: z7.string().trim().min(1) }),
|
|
1184
|
+
remove_skill: z7.object({ name: NameSchema, reason: z7.string().trim().min(1) }),
|
|
1185
|
+
upload_image: z7.object({
|
|
1186
|
+
/** The image file on the machine your turn runs on: absolute, or relative to your working directory. */
|
|
1187
|
+
path: ImagePathSchema
|
|
1188
|
+
})
|
|
1060
1189
|
};
|
|
1061
1190
|
|
|
1062
1191
|
// packages/shared/dist/events.js
|
|
1063
|
-
import { z as
|
|
1192
|
+
import { z as z8 } from "zod";
|
|
1064
1193
|
var BOARD_EVENT_TYPES = [
|
|
1065
1194
|
"society.initialized",
|
|
1066
1195
|
"project.added",
|
|
@@ -1105,6 +1234,7 @@ var BOARD_EVENT_TYPES = [
|
|
|
1105
1234
|
"user.signed_out",
|
|
1106
1235
|
"user.token_rotated",
|
|
1107
1236
|
"runner.changed",
|
|
1237
|
+
"runner.quota",
|
|
1108
1238
|
"ops.signal",
|
|
1109
1239
|
"paused.changed",
|
|
1110
1240
|
"wake.requested",
|
|
@@ -1123,30 +1253,39 @@ var BOARD_EVENT_TYPES = [
|
|
|
1123
1253
|
"cron.updated",
|
|
1124
1254
|
"cron.fired",
|
|
1125
1255
|
"cron.skipped",
|
|
1126
|
-
"cron.ended"
|
|
1256
|
+
"cron.ended",
|
|
1257
|
+
"image.uploaded"
|
|
1127
1258
|
];
|
|
1128
|
-
var BoardEventTypeSchema =
|
|
1129
|
-
var BoardEventSchema =
|
|
1259
|
+
var BoardEventTypeSchema = z8.enum(BOARD_EVENT_TYPES);
|
|
1260
|
+
var BoardEventSchema = z8.object({
|
|
1130
1261
|
id: UlidSchema,
|
|
1131
1262
|
ts: IsoDateTimeSchema,
|
|
1132
1263
|
type: BoardEventTypeSchema,
|
|
1133
1264
|
actor: NameSchema,
|
|
1134
|
-
payload:
|
|
1135
|
-
});
|
|
1136
|
-
var UsageSchema =
|
|
1137
|
-
inputTokens:
|
|
1138
|
-
outputTokens:
|
|
1139
|
-
cacheReadTokens:
|
|
1140
|
-
cacheWriteTokens:
|
|
1141
|
-
});
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
}
|
|
1149
|
-
|
|
1265
|
+
payload: z8.record(z8.string(), z8.unknown())
|
|
1266
|
+
});
|
|
1267
|
+
var UsageSchema = z8.object({
|
|
1268
|
+
inputTokens: z8.number().int().nonnegative(),
|
|
1269
|
+
outputTokens: z8.number().int().nonnegative(),
|
|
1270
|
+
cacheReadTokens: z8.number().int().nonnegative().default(0),
|
|
1271
|
+
cacheWriteTokens: z8.number().int().nonnegative().default(0)
|
|
1272
|
+
});
|
|
1273
|
+
function addUsage(a, b) {
|
|
1274
|
+
return {
|
|
1275
|
+
inputTokens: a.inputTokens + b.inputTokens,
|
|
1276
|
+
outputTokens: a.outputTokens + b.outputTokens,
|
|
1277
|
+
cacheReadTokens: a.cacheReadTokens + b.cacheReadTokens,
|
|
1278
|
+
cacheWriteTokens: a.cacheWriteTokens + b.cacheWriteTokens
|
|
1279
|
+
};
|
|
1280
|
+
}
|
|
1281
|
+
var TurnStatusSchema = z8.object({
|
|
1282
|
+
summary: z8.string().min(1),
|
|
1283
|
+
claimsHeld: z8.array(UlidSchema).default([]),
|
|
1284
|
+
blockedOn: z8.array(z8.string()).default([]),
|
|
1285
|
+
needsUserDecision: z8.boolean().default(false),
|
|
1286
|
+
memoryUpdated: z8.boolean().default(false)
|
|
1287
|
+
});
|
|
1288
|
+
var TurnExitReasonSchema = z8.enum([
|
|
1150
1289
|
"completed",
|
|
1151
1290
|
"timeout",
|
|
1152
1291
|
"error",
|
|
@@ -1154,50 +1293,50 @@ var TurnExitReasonSchema = z6.enum([
|
|
|
1154
1293
|
"blocked",
|
|
1155
1294
|
"stopped"
|
|
1156
1295
|
]);
|
|
1157
|
-
var AgentEventSchema =
|
|
1158
|
-
|
|
1159
|
-
type:
|
|
1296
|
+
var AgentEventSchema = z8.discriminatedUnion("type", [
|
|
1297
|
+
z8.object({
|
|
1298
|
+
type: z8.literal("turn_started"),
|
|
1160
1299
|
agent: NameSchema,
|
|
1161
|
-
session:
|
|
1300
|
+
session: z8.string(),
|
|
1162
1301
|
runner: NameSchema,
|
|
1163
1302
|
/** The model the CLI reports running, when it reports one. */
|
|
1164
|
-
model:
|
|
1303
|
+
model: z8.string().optional()
|
|
1165
1304
|
}),
|
|
1166
1305
|
/**
|
|
1167
1306
|
* The CLI took a steer into the running turn. Adapters name the steer; the server adds the
|
|
1168
1307
|
* messages it delivered and the text the CLI was given.
|
|
1169
1308
|
*/
|
|
1170
|
-
|
|
1171
|
-
type:
|
|
1172
|
-
steer:
|
|
1173
|
-
messages:
|
|
1174
|
-
text:
|
|
1309
|
+
z8.object({
|
|
1310
|
+
type: z8.literal("steered"),
|
|
1311
|
+
steer: z8.string().min(1),
|
|
1312
|
+
messages: z8.array(UlidSchema).optional(),
|
|
1313
|
+
text: z8.string().optional()
|
|
1175
1314
|
}),
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
type:
|
|
1180
|
-
name:
|
|
1181
|
-
ok:
|
|
1315
|
+
z8.object({ type: z8.literal("text"), delta: z8.string() }),
|
|
1316
|
+
z8.object({ type: z8.literal("tool_call"), name: z8.string(), input: z8.unknown() }),
|
|
1317
|
+
z8.object({
|
|
1318
|
+
type: z8.literal("tool_result"),
|
|
1319
|
+
name: z8.string(),
|
|
1320
|
+
ok: z8.boolean(),
|
|
1182
1321
|
/** What the tool returned, cut to `OUTPUT_LIMIT` characters by `capOutput`. */
|
|
1183
|
-
output:
|
|
1322
|
+
output: z8.string().optional()
|
|
1184
1323
|
}),
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
type:
|
|
1324
|
+
z8.object({ type: z8.literal("approval_requested"), kind: z8.string(), detail: z8.unknown() }),
|
|
1325
|
+
z8.object({
|
|
1326
|
+
type: z8.literal("turn_completed"),
|
|
1188
1327
|
usage: UsageSchema,
|
|
1189
|
-
costUsd:
|
|
1328
|
+
costUsd: z8.number().nonnegative(),
|
|
1190
1329
|
status: TurnStatusSchema.nullable(),
|
|
1191
1330
|
exitReason: TurnExitReasonSchema
|
|
1192
1331
|
}),
|
|
1193
|
-
|
|
1332
|
+
z8.object({ type: z8.literal("error"), message: z8.string() })
|
|
1194
1333
|
]);
|
|
1195
|
-
var TranscriptEntrySchema =
|
|
1334
|
+
var TranscriptEntrySchema = z8.object({
|
|
1196
1335
|
ts: IsoDateTimeSchema,
|
|
1197
1336
|
event: AgentEventSchema
|
|
1198
1337
|
});
|
|
1199
|
-
var LiveTurnEventSchema =
|
|
1200
|
-
seq:
|
|
1338
|
+
var LiveTurnEventSchema = z8.object({
|
|
1339
|
+
seq: z8.number().int().positive(),
|
|
1201
1340
|
ts: IsoDateTimeSchema,
|
|
1202
1341
|
agent: NameSchema,
|
|
1203
1342
|
project: NameSchema,
|
|
@@ -1209,97 +1348,107 @@ var LiveTurnEventSchema = z6.object({
|
|
|
1209
1348
|
});
|
|
1210
1349
|
|
|
1211
1350
|
// packages/shared/dist/turns.js
|
|
1212
|
-
import { z as
|
|
1351
|
+
import { z as z10 } from "zod";
|
|
1213
1352
|
|
|
1214
1353
|
// packages/shared/dist/runner.js
|
|
1215
|
-
import { z as
|
|
1354
|
+
import { z as z9 } from "zod";
|
|
1216
1355
|
var HOME_SCRATCH = "scratch";
|
|
1217
1356
|
var HOME_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1218
|
-
var RunnerHelloSchema =
|
|
1219
|
-
protocol:
|
|
1220
|
-
version:
|
|
1357
|
+
var RunnerHelloSchema = z9.object({
|
|
1358
|
+
protocol: z9.number().int().positive(),
|
|
1359
|
+
version: z9.string().min(1),
|
|
1221
1360
|
os: RunnerOsSchema,
|
|
1222
|
-
clis:
|
|
1361
|
+
clis: z9.array(CliKindSchema),
|
|
1223
1362
|
/** The CLIs whose adapter can keep a session warm between turns. */
|
|
1224
|
-
residentClis:
|
|
1363
|
+
residentClis: z9.array(CliKindSchema).default([]),
|
|
1225
1364
|
/** The CLIs whose adapter can take input into a running turn; the server steers only these. */
|
|
1226
|
-
steerableClis:
|
|
1365
|
+
steerableClis: z9.array(CliKindSchema).default([]),
|
|
1227
1366
|
/** The CLIs whose adapter can stop a running turn; the server stops only these. */
|
|
1228
|
-
stoppableClis:
|
|
1367
|
+
stoppableClis: z9.array(CliKindSchema).default([]),
|
|
1229
1368
|
/** Whether the runner answers file reads on its projects' branches; one from before never does. */
|
|
1230
|
-
branchReads:
|
|
1369
|
+
branchReads: z9.boolean().default(false),
|
|
1231
1370
|
/** Whether the runner lists what a branch changed; one from before never does. */
|
|
1232
|
-
branchChanges:
|
|
1233
|
-
|
|
1371
|
+
branchChanges: z9.boolean().default(false),
|
|
1372
|
+
/** Whether the runner answers a read of a CLI's quota; one from before never does. */
|
|
1373
|
+
quotaReads: z9.boolean().default(false),
|
|
1374
|
+
/** Whether the runner reads an image a turn running there uploads; one from before never does. */
|
|
1375
|
+
imageReads: z9.boolean().default(false),
|
|
1376
|
+
capabilities: z9.array(z9.string()).default([]),
|
|
1377
|
+
/**
|
|
1378
|
+
* What the runner's account lacks of the git identity citizens' own commits carry, checked
|
|
1379
|
+
* before each hello outside any repository; empty when it has both. Absent from a runner from
|
|
1380
|
+
* before the check, which no default fills in, so the board marks only what a runner reported.
|
|
1381
|
+
*/
|
|
1382
|
+
gitIdentityMissing: z9.array(GitIdentityPartSchema).optional(),
|
|
1234
1383
|
/** Turns the runner runs at once, or null for no limit. */
|
|
1235
|
-
slots:
|
|
1384
|
+
slots: z9.number().int().positive().nullable(),
|
|
1236
1385
|
/** Turns the runner is still running, when it registers again; the server fails the rest of its turns. */
|
|
1237
|
-
turns:
|
|
1386
|
+
turns: z9.array(UlidSchema).default([])
|
|
1238
1387
|
});
|
|
1239
|
-
var RunnerWelcomeSchema =
|
|
1240
|
-
var RunnerEnrollRequestSchema =
|
|
1241
|
-
protocol:
|
|
1242
|
-
version:
|
|
1243
|
-
hostname:
|
|
1388
|
+
var RunnerWelcomeSchema = z9.object({ name: NameSchema, version: z9.string() });
|
|
1389
|
+
var RunnerEnrollRequestSchema = z9.object({
|
|
1390
|
+
protocol: z9.number().int().positive(),
|
|
1391
|
+
version: z9.string().min(1).max(64),
|
|
1392
|
+
hostname: z9.string().min(1).max(253),
|
|
1244
1393
|
os: RunnerOsSchema,
|
|
1245
|
-
clis:
|
|
1246
|
-
capabilities:
|
|
1394
|
+
clis: z9.array(CliKindSchema).max(8),
|
|
1395
|
+
capabilities: z9.array(z9.string().min(1).max(64)).max(32).default([])
|
|
1247
1396
|
});
|
|
1248
|
-
var RunnerEnrollmentSchema =
|
|
1249
|
-
deviceCode:
|
|
1250
|
-
userCode:
|
|
1397
|
+
var RunnerEnrollmentSchema = z9.object({
|
|
1398
|
+
deviceCode: z9.string().min(1),
|
|
1399
|
+
userCode: z9.string().min(1),
|
|
1251
1400
|
expiresAt: IsoDateTimeSchema,
|
|
1252
|
-
intervalMs:
|
|
1401
|
+
intervalMs: z9.number().int().positive()
|
|
1253
1402
|
});
|
|
1254
|
-
var RunnerEnrollPollSchema =
|
|
1255
|
-
var RunnerEnrollStatusSchema =
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1403
|
+
var RunnerEnrollPollSchema = z9.object({ deviceCode: z9.string().min(1) });
|
|
1404
|
+
var RunnerEnrollStatusSchema = z9.discriminatedUnion("status", [
|
|
1405
|
+
z9.object({ status: z9.literal("pending") }),
|
|
1406
|
+
z9.object({ status: z9.literal("approved"), name: NameSchema, token: z9.string().min(1) }),
|
|
1407
|
+
z9.object({ status: z9.literal("denied") })
|
|
1259
1408
|
]);
|
|
1260
|
-
var PendingEnrollmentSchema =
|
|
1261
|
-
userCode:
|
|
1262
|
-
hostname:
|
|
1409
|
+
var PendingEnrollmentSchema = z9.object({
|
|
1410
|
+
userCode: z9.string().min(1),
|
|
1411
|
+
hostname: z9.string(),
|
|
1263
1412
|
os: RunnerOsSchema,
|
|
1264
|
-
clis:
|
|
1265
|
-
capabilities:
|
|
1266
|
-
version:
|
|
1413
|
+
clis: z9.array(CliKindSchema),
|
|
1414
|
+
capabilities: z9.array(z9.string()),
|
|
1415
|
+
version: z9.string(),
|
|
1267
1416
|
requestedAt: IsoDateTimeSchema,
|
|
1268
1417
|
expiresAt: IsoDateTimeSchema
|
|
1269
1418
|
});
|
|
1270
|
-
var ProjectRepoSchema =
|
|
1419
|
+
var ProjectRepoSchema = z9.object({
|
|
1271
1420
|
slug: NameSchema,
|
|
1272
|
-
origin:
|
|
1273
|
-
defaultBranch:
|
|
1421
|
+
origin: z9.string().nullable(),
|
|
1422
|
+
defaultBranch: z9.string().min(1),
|
|
1274
1423
|
/**
|
|
1275
1424
|
* The board lands finished tasks on the default branch, itself or through their pull requests,
|
|
1276
1425
|
* so the runner lets nothing else move it.
|
|
1277
1426
|
*/
|
|
1278
|
-
boardLands:
|
|
1427
|
+
boardLands: z9.boolean()
|
|
1279
1428
|
});
|
|
1280
|
-
var TurnWorkspaceSchema =
|
|
1281
|
-
|
|
1282
|
-
kind:
|
|
1429
|
+
var TurnWorkspaceSchema = z9.discriminatedUnion("kind", [
|
|
1430
|
+
z9.object({
|
|
1431
|
+
kind: z9.literal("home"),
|
|
1283
1432
|
thread: UlidSchema.optional(),
|
|
1284
1433
|
channel: NameSchema.optional()
|
|
1285
1434
|
}),
|
|
1286
|
-
|
|
1287
|
-
kind:
|
|
1435
|
+
z9.object({
|
|
1436
|
+
kind: z9.literal("project"),
|
|
1288
1437
|
repo: ProjectRepoSchema,
|
|
1289
|
-
branches:
|
|
1438
|
+
branches: z9.array(z9.string().min(1)),
|
|
1290
1439
|
thread: UlidSchema.optional(),
|
|
1291
1440
|
channel: NameSchema.optional()
|
|
1292
1441
|
}),
|
|
1293
|
-
|
|
1442
|
+
z9.object({ kind: z9.literal("task"), repo: ProjectRepoSchema, taskId: UlidSchema })
|
|
1294
1443
|
]);
|
|
1295
|
-
var TurnJobSchema =
|
|
1444
|
+
var TurnJobSchema = z9.object({
|
|
1296
1445
|
turnId: UlidSchema,
|
|
1297
1446
|
agent: NameSchema,
|
|
1298
1447
|
role: NameSchema,
|
|
1299
1448
|
cli: CliKindSchema,
|
|
1300
|
-
model:
|
|
1449
|
+
model: z9.string().optional(),
|
|
1301
1450
|
/** The reasoning effort set on the agent; absent for the model's own default. */
|
|
1302
|
-
effort:
|
|
1451
|
+
effort: z9.string().optional(),
|
|
1303
1452
|
/** A project slug, or the society scope. */
|
|
1304
1453
|
scope: NameSchema,
|
|
1305
1454
|
/** The thread whose conversation the turn is in; absent for the home conversation. */
|
|
@@ -1310,125 +1459,130 @@ var TurnJobSchema = z7.object({
|
|
|
1310
1459
|
* The session to resume, or null to start one: the CLI's adapter picks a fresh session's id, and
|
|
1311
1460
|
* the outcome reports it.
|
|
1312
1461
|
*/
|
|
1313
|
-
session:
|
|
1462
|
+
session: z9.string().min(1).nullable(),
|
|
1314
1463
|
/** The running total the session reported after its last turn, which a resumed session starts from. */
|
|
1315
|
-
costSoFarUsd:
|
|
1464
|
+
costSoFarUsd: z9.number().nonnegative(),
|
|
1316
1465
|
/** The rendered charter, norms, memory core, and skills index, with `PATH_TOKENS` for places. */
|
|
1317
|
-
instructions:
|
|
1318
|
-
prompt:
|
|
1319
|
-
mcp:
|
|
1320
|
-
limits:
|
|
1321
|
-
timeoutMs:
|
|
1322
|
-
maxTurns:
|
|
1466
|
+
instructions: z9.string(),
|
|
1467
|
+
prompt: z9.string(),
|
|
1468
|
+
mcp: z9.object({ url: z9.string().min(1), token: z9.string().min(1) }),
|
|
1469
|
+
limits: z9.object({
|
|
1470
|
+
timeoutMs: z9.number().int().positive().nullable(),
|
|
1471
|
+
maxTurns: z9.number().int().positive().nullable()
|
|
1323
1472
|
}),
|
|
1324
1473
|
/** Present when the runner keeps the conversation's session warm between turns, under `key`. */
|
|
1325
|
-
resident:
|
|
1474
|
+
resident: z9.object({ key: z9.string().min(1), idleMs: z9.number().int().positive() }).optional(),
|
|
1326
1475
|
workspace: TurnWorkspaceSchema
|
|
1327
1476
|
});
|
|
1328
|
-
var TurnWorkSchema =
|
|
1329
|
-
var TurnEventsSchema =
|
|
1330
|
-
var TurnOutcomeSchema =
|
|
1477
|
+
var TurnWorkSchema = z9.object({ branch: z9.string().min(1), head: z9.string().min(1) });
|
|
1478
|
+
var TurnEventsSchema = z9.object({ entries: z9.array(TranscriptEntrySchema) });
|
|
1479
|
+
var TurnOutcomeSchema = z9.object({
|
|
1331
1480
|
exitReason: TurnExitReasonSchema,
|
|
1332
1481
|
status: TurnStatusSchema.nullable(),
|
|
1333
|
-
error:
|
|
1482
|
+
error: z9.string().nullable(),
|
|
1334
1483
|
usage: UsageSchema,
|
|
1335
|
-
costUsd:
|
|
1484
|
+
costUsd: z9.number().nonnegative(),
|
|
1336
1485
|
/** The session's running total after this turn, for CLIs that report one. */
|
|
1337
|
-
sessionCostUsd:
|
|
1486
|
+
sessionCostUsd: z9.number().nonnegative().optional(),
|
|
1338
1487
|
/** The session the CLI used, which differs from the job's for CLIs that assign their own ids. */
|
|
1339
|
-
session:
|
|
1488
|
+
session: z9.string().min(1),
|
|
1340
1489
|
/** The model the CLI reported, when it reported one. */
|
|
1341
|
-
model:
|
|
1490
|
+
model: z9.string().nullable(),
|
|
1342
1491
|
work: TurnWorkSchema.nullable(),
|
|
1343
1492
|
/**
|
|
1344
1493
|
* Whether the turn's own workspace, a thread's, a channel's, or a task's, holds work on no
|
|
1345
1494
|
* branch after the hand-back: uncommitted changes, or commits no branch contains.
|
|
1346
1495
|
*/
|
|
1347
|
-
leftovers:
|
|
1496
|
+
leftovers: z9.boolean().default(false),
|
|
1497
|
+
/**
|
|
1498
|
+
* The CLI's plan quota as the turn's stream last reported it, when it reported any; a runner from
|
|
1499
|
+
* before never sends it.
|
|
1500
|
+
*/
|
|
1501
|
+
quota: CliQuotaSchema.optional()
|
|
1348
1502
|
});
|
|
1349
|
-
var TurnAckSchema =
|
|
1350
|
-
var LandRequestSchema =
|
|
1503
|
+
var TurnAckSchema = z9.object({ dropWorkspace: z9.boolean() });
|
|
1504
|
+
var LandRequestSchema = z9.object({
|
|
1351
1505
|
repo: ProjectRepoSchema,
|
|
1352
|
-
branch:
|
|
1506
|
+
branch: z9.string().min(1),
|
|
1353
1507
|
/**
|
|
1354
1508
|
* For a `ghpr` task, the pull request to merge in place of the branch, which must hold the
|
|
1355
1509
|
* branch's files, and the merge commit's subject and body, the pull request's title and an
|
|
1356
1510
|
* empty body when left out.
|
|
1357
1511
|
*/
|
|
1358
|
-
pullRequest:
|
|
1359
|
-
url:
|
|
1360
|
-
subject:
|
|
1361
|
-
body:
|
|
1512
|
+
pullRequest: z9.object({
|
|
1513
|
+
url: z9.string().min(1),
|
|
1514
|
+
subject: z9.string().min(1).optional(),
|
|
1515
|
+
body: z9.string().optional()
|
|
1362
1516
|
}).optional()
|
|
1363
1517
|
});
|
|
1364
|
-
var CloseRequestSchema =
|
|
1518
|
+
var CloseRequestSchema = z9.object({
|
|
1365
1519
|
repo: ProjectRepoSchema,
|
|
1366
|
-
url:
|
|
1367
|
-
comment:
|
|
1520
|
+
url: z9.string().min(1),
|
|
1521
|
+
comment: z9.string().min(1)
|
|
1368
1522
|
});
|
|
1369
|
-
var MergeOutcomeSchema =
|
|
1370
|
-
var ModelListSchema =
|
|
1523
|
+
var MergeOutcomeSchema = z9.object({ ok: z9.boolean(), detail: z9.string() });
|
|
1524
|
+
var ModelListSchema = z9.array(ModelOptionSchema);
|
|
1371
1525
|
var BRANCH_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1372
|
-
var BranchPathSchema =
|
|
1373
|
-
var BranchNameSchema =
|
|
1374
|
-
var BranchReadSchema =
|
|
1526
|
+
var BranchPathSchema = z9.string().max(4096).refine((value) => value === "" || value.split("/").every((segment) => segment !== "" && segment !== "." && segment !== ".." && !segment.includes("\0")), { message: "a path inside the branch, with no empty, `.`, or `..` segment" });
|
|
1527
|
+
var BranchNameSchema = z9.string().regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/);
|
|
1528
|
+
var BranchReadSchema = z9.object({
|
|
1375
1529
|
repo: ProjectRepoSchema,
|
|
1376
1530
|
branch: BranchNameSchema,
|
|
1377
1531
|
path: BranchPathSchema
|
|
1378
1532
|
});
|
|
1379
|
-
var BranchCommitSchema =
|
|
1380
|
-
id:
|
|
1533
|
+
var BranchCommitSchema = z9.object({
|
|
1534
|
+
id: z9.string().min(1),
|
|
1381
1535
|
at: IsoDateTimeSchema,
|
|
1382
|
-
author:
|
|
1536
|
+
author: z9.string()
|
|
1383
1537
|
});
|
|
1384
|
-
var BranchFileSchema =
|
|
1385
|
-
|
|
1386
|
-
kind:
|
|
1538
|
+
var BranchFileSchema = z9.discriminatedUnion("kind", [
|
|
1539
|
+
z9.object({
|
|
1540
|
+
kind: z9.literal("file"),
|
|
1387
1541
|
path: BranchPathSchema,
|
|
1388
1542
|
commit: BranchCommitSchema,
|
|
1389
|
-
size:
|
|
1390
|
-
content:
|
|
1543
|
+
size: z9.number().int().nonnegative(),
|
|
1544
|
+
content: z9.string().nullable()
|
|
1391
1545
|
}),
|
|
1392
|
-
|
|
1393
|
-
kind:
|
|
1546
|
+
z9.object({
|
|
1547
|
+
kind: z9.literal("dir"),
|
|
1394
1548
|
path: BranchPathSchema,
|
|
1395
1549
|
commit: BranchCommitSchema,
|
|
1396
|
-
entries:
|
|
1397
|
-
name:
|
|
1398
|
-
kind:
|
|
1399
|
-
size:
|
|
1550
|
+
entries: z9.array(z9.object({
|
|
1551
|
+
name: z9.string().min(1),
|
|
1552
|
+
kind: z9.enum(["file", "dir"]),
|
|
1553
|
+
size: z9.number().int().nonnegative().nullable()
|
|
1400
1554
|
}))
|
|
1401
1555
|
})
|
|
1402
1556
|
]);
|
|
1403
|
-
var BranchChangesReadSchema =
|
|
1557
|
+
var BranchChangesReadSchema = z9.object({
|
|
1404
1558
|
repo: ProjectRepoSchema,
|
|
1405
1559
|
branch: BranchNameSchema
|
|
1406
1560
|
});
|
|
1407
|
-
var BranchFileChangeSchema =
|
|
1408
|
-
path:
|
|
1409
|
-
status:
|
|
1561
|
+
var BranchFileChangeSchema = z9.object({
|
|
1562
|
+
path: z9.string().min(1),
|
|
1563
|
+
status: z9.enum(["added", "modified", "deleted"]),
|
|
1410
1564
|
/** Lines added and removed, or null for a binary file. */
|
|
1411
|
-
added:
|
|
1412
|
-
removed:
|
|
1565
|
+
added: z9.number().int().nonnegative().nullable(),
|
|
1566
|
+
removed: z9.number().int().nonnegative().nullable(),
|
|
1413
1567
|
/** Absent when the file changed only through a merge of another branch. */
|
|
1414
|
-
lastChange:
|
|
1568
|
+
lastChange: z9.object({ author: z9.string(), at: IsoDateTimeSchema }).optional()
|
|
1415
1569
|
});
|
|
1416
|
-
var BranchChangesSchema =
|
|
1570
|
+
var BranchChangesSchema = z9.object({
|
|
1417
1571
|
head: BranchCommitSchema,
|
|
1418
|
-
files:
|
|
1419
|
-
total:
|
|
1572
|
+
files: z9.array(BranchFileChangeSchema),
|
|
1573
|
+
total: z9.number().int().nonnegative()
|
|
1420
1574
|
});
|
|
1421
|
-
var BranchDiffReadSchema =
|
|
1575
|
+
var BranchDiffReadSchema = z9.object({
|
|
1422
1576
|
repo: ProjectRepoSchema,
|
|
1423
1577
|
branch: BranchNameSchema,
|
|
1424
1578
|
path: BranchPathSchema.min(1)
|
|
1425
1579
|
});
|
|
1426
|
-
var BranchFileDiffSchema =
|
|
1580
|
+
var BranchFileDiffSchema = z9.object({
|
|
1427
1581
|
head: BranchCommitSchema,
|
|
1428
1582
|
path: BranchPathSchema,
|
|
1429
1583
|
status: BranchFileChangeSchema.shape.status,
|
|
1430
|
-
patch:
|
|
1431
|
-
truncated:
|
|
1584
|
+
patch: z9.string().nullable(),
|
|
1585
|
+
truncated: z9.boolean()
|
|
1432
1586
|
});
|
|
1433
1587
|
function patchHunks(patch, limit) {
|
|
1434
1588
|
if (/^Binary files .* differ$/m.test(patch)) {
|
|
@@ -1442,64 +1596,88 @@ function patchHunks(patch, limit) {
|
|
|
1442
1596
|
const cut = hunks.lastIndexOf("\n", limit);
|
|
1443
1597
|
return { patch: hunks.slice(0, cut === -1 ? limit : cut), truncated: true };
|
|
1444
1598
|
}
|
|
1445
|
-
var
|
|
1446
|
-
|
|
1447
|
-
|
|
1599
|
+
var TurnImageReadSchema = z9.object({
|
|
1600
|
+
turnId: UlidSchema,
|
|
1601
|
+
path: ImagePathSchema
|
|
1602
|
+
});
|
|
1603
|
+
var ImageRefusalSchema = z9.enum(["missing", "outside", "not_image", "too_big"]);
|
|
1604
|
+
var TurnImageSchema = z9.discriminatedUnion("kind", [
|
|
1605
|
+
z9.object({
|
|
1606
|
+
kind: z9.literal("image"),
|
|
1607
|
+
type: ImageTypeSchema,
|
|
1608
|
+
size: z9.number().int().positive(),
|
|
1609
|
+
content: z9.string()
|
|
1610
|
+
}),
|
|
1611
|
+
z9.object({ kind: z9.literal("refused"), why: ImageRefusalSchema, detail: z9.string() })
|
|
1448
1612
|
]);
|
|
1449
|
-
var
|
|
1613
|
+
var WorkspaceConversationSchema = z9.discriminatedUnion("kind", [
|
|
1614
|
+
z9.object({ kind: z9.literal("thread"), id: UlidSchema }),
|
|
1615
|
+
z9.object({ kind: z9.literal("channel"), scope: NameSchema, name: NameSchema })
|
|
1616
|
+
]);
|
|
1617
|
+
var HeldWorkspaceSchema = z9.object({
|
|
1450
1618
|
agent: NameSchema,
|
|
1451
1619
|
scope: NameSchema,
|
|
1452
1620
|
conversation: WorkspaceConversationSchema
|
|
1453
1621
|
});
|
|
1454
|
-
var HeldWorkspacesSchema =
|
|
1455
|
-
var SweepResultSchema =
|
|
1456
|
-
var TurnSteerSchema =
|
|
1457
|
-
var RunnerMessageSchema =
|
|
1458
|
-
|
|
1459
|
-
|
|
1622
|
+
var HeldWorkspacesSchema = z9.object({ workspaces: z9.array(HeldWorkspaceSchema) });
|
|
1623
|
+
var SweepResultSchema = z9.object({ kept: z9.array(HeldWorkspaceSchema) });
|
|
1624
|
+
var TurnSteerSchema = z9.object({ id: z9.uuid(), text: z9.string().min(1) });
|
|
1625
|
+
var RunnerMessageSchema = z9.discriminatedUnion("type", [
|
|
1626
|
+
z9.object({ type: z9.literal("turn"), job: TurnJobSchema }),
|
|
1627
|
+
z9.object({ type: z9.literal("land"), request: z9.string().min(1), land: LandRequestSchema }),
|
|
1460
1628
|
/** Answered with a `MergeOutcome`. */
|
|
1461
|
-
|
|
1462
|
-
|
|
1629
|
+
z9.object({ type: z9.literal("close"), request: z9.string().min(1), close: CloseRequestSchema }),
|
|
1630
|
+
z9.object({ type: z9.literal("models"), request: z9.string().min(1), cli: CliKindSchema }),
|
|
1631
|
+
/**
|
|
1632
|
+
* Answered with a `CliQuota` read from the CLI without a turn, or null when its adapter cannot
|
|
1633
|
+
* read one. Sent only to runners whose hello says `quotaReads`.
|
|
1634
|
+
*/
|
|
1635
|
+
z9.object({ type: z9.literal("quota"), request: z9.string().min(1), cli: CliKindSchema }),
|
|
1463
1636
|
/** Answered with a `BranchFile`, or null when the branch or the path does not exist. */
|
|
1464
|
-
|
|
1637
|
+
z9.object({ type: z9.literal("file"), request: z9.string().min(1), read: BranchReadSchema }),
|
|
1465
1638
|
/** Answered with `BranchChanges`, or null when the repository or the branch does not exist. */
|
|
1466
|
-
|
|
1467
|
-
type:
|
|
1468
|
-
request:
|
|
1639
|
+
z9.object({
|
|
1640
|
+
type: z9.literal("changes"),
|
|
1641
|
+
request: z9.string().min(1),
|
|
1469
1642
|
read: BranchChangesReadSchema
|
|
1470
1643
|
}),
|
|
1471
1644
|
/** Answered with a `BranchFileDiff`, or null when the branch does not exist or left the path alone. */
|
|
1472
|
-
|
|
1645
|
+
z9.object({ type: z9.literal("diff"), request: z9.string().min(1), read: BranchDiffReadSchema }),
|
|
1646
|
+
/**
|
|
1647
|
+
* Answered with a `TurnImage`, or null when the turn is not running there. Sent only to runners
|
|
1648
|
+
* whose hello says `imageReads`.
|
|
1649
|
+
*/
|
|
1650
|
+
z9.object({ type: z9.literal("image"), request: z9.string().min(1), read: TurnImageReadSchema }),
|
|
1473
1651
|
/** Answered with whether the CLI accepted it; that it took it comes as a `steered` event. */
|
|
1474
|
-
|
|
1475
|
-
type:
|
|
1476
|
-
request:
|
|
1652
|
+
z9.object({
|
|
1653
|
+
type: z9.literal("steer"),
|
|
1654
|
+
request: z9.string().min(1),
|
|
1477
1655
|
turnId: UlidSchema,
|
|
1478
1656
|
steer: TurnSteerSchema
|
|
1479
1657
|
}),
|
|
1480
1658
|
/** Answered with whether the turn was there to stop; it ends `stopped`. */
|
|
1481
|
-
|
|
1659
|
+
z9.object({ type: z9.literal("stop"), request: z9.string().min(1), turnId: UlidSchema }),
|
|
1482
1660
|
/**
|
|
1483
1661
|
* A conversation ended: the runner removes every citizen's workspace for it but those a turn
|
|
1484
1662
|
* still uses, and answers with a `SweepResult` naming those it kept for holding work on no branch.
|
|
1485
1663
|
*/
|
|
1486
|
-
|
|
1487
|
-
type:
|
|
1488
|
-
request:
|
|
1664
|
+
z9.object({
|
|
1665
|
+
type: z9.literal("sweep"),
|
|
1666
|
+
request: z9.string().min(1),
|
|
1489
1667
|
conversation: WorkspaceConversationSchema
|
|
1490
1668
|
})
|
|
1491
1669
|
]);
|
|
1492
|
-
var RunnerAnswerSchema =
|
|
1493
|
-
|
|
1494
|
-
|
|
1670
|
+
var RunnerAnswerSchema = z9.discriminatedUnion("ok", [
|
|
1671
|
+
z9.object({ ok: z9.literal(true), value: z9.unknown() }),
|
|
1672
|
+
z9.object({ ok: z9.literal(false), error: z9.string() })
|
|
1495
1673
|
]);
|
|
1496
|
-
var WarmSessionsSchema =
|
|
1497
|
-
var FileManifestSchema =
|
|
1674
|
+
var WarmSessionsSchema = z9.object({ warm: z9.array(z9.string()) });
|
|
1675
|
+
var FileManifestSchema = z9.object({ files: z9.record(z9.string(), z9.string()) });
|
|
1498
1676
|
function fileVersion(sha, executable) {
|
|
1499
1677
|
return executable ? `${sha}+x` : sha;
|
|
1500
1678
|
}
|
|
1501
|
-
var FileReadSchema =
|
|
1502
|
-
var FileContentsSchema =
|
|
1679
|
+
var FileReadSchema = z9.object({ paths: z9.array(z9.string()) });
|
|
1680
|
+
var FileContentsSchema = z9.object({ files: z9.record(z9.string(), z9.string()) });
|
|
1503
1681
|
function isSafeRelativePath(file) {
|
|
1504
1682
|
if (file.length === 0 || file.startsWith("/") || file.includes("\\") || file.includes("\0")) {
|
|
1505
1683
|
return false;
|
|
@@ -1508,7 +1686,7 @@ function isSafeRelativePath(file) {
|
|
|
1508
1686
|
}
|
|
1509
1687
|
|
|
1510
1688
|
// packages/shared/dist/turns.js
|
|
1511
|
-
var TriggerKindSchema =
|
|
1689
|
+
var TriggerKindSchema = z10.enum([
|
|
1512
1690
|
"mention",
|
|
1513
1691
|
"stage",
|
|
1514
1692
|
"task_done",
|
|
@@ -1522,11 +1700,11 @@ var TriggerKindSchema = z8.enum([
|
|
|
1522
1700
|
"closing",
|
|
1523
1701
|
"cron"
|
|
1524
1702
|
]);
|
|
1525
|
-
var TriggerSchema =
|
|
1703
|
+
var TriggerSchema = z10.object({
|
|
1526
1704
|
kind: TriggerKindSchema,
|
|
1527
1705
|
from: NameSchema.optional(),
|
|
1528
|
-
fromUser:
|
|
1529
|
-
reason:
|
|
1706
|
+
fromUser: z10.boolean().default(false),
|
|
1707
|
+
reason: z10.string().default(""),
|
|
1530
1708
|
taskId: UlidSchema.optional(),
|
|
1531
1709
|
messageId: UlidSchema.optional(),
|
|
1532
1710
|
/** The channel the waking message was posted in. */
|
|
@@ -1534,17 +1712,17 @@ var TriggerSchema = z8.object({
|
|
|
1534
1712
|
/** The cron that came due, for a `cron` wake. */
|
|
1535
1713
|
cronId: UlidSchema.optional()
|
|
1536
1714
|
});
|
|
1537
|
-
var TurnThreadSchema =
|
|
1538
|
-
var TurnDispatchSchema =
|
|
1715
|
+
var TurnThreadSchema = z10.object({ id: UlidSchema, task: z10.boolean() });
|
|
1716
|
+
var TurnDispatchSchema = z10.object({
|
|
1539
1717
|
agent: NameSchema,
|
|
1540
1718
|
project: NameSchema,
|
|
1541
1719
|
thread: TurnThreadSchema.optional(),
|
|
1542
1720
|
channel: NameSchema.optional(),
|
|
1543
1721
|
trigger: TriggerSchema,
|
|
1544
|
-
priority:
|
|
1545
|
-
onboarding:
|
|
1722
|
+
priority: z10.number().int().min(0).max(2),
|
|
1723
|
+
onboarding: z10.boolean().default(false),
|
|
1546
1724
|
/** Every cron that came due for this turn, whatever wake it merged into; its prompt quotes each. */
|
|
1547
|
-
crons:
|
|
1725
|
+
crons: z10.array(UlidSchema).optional()
|
|
1548
1726
|
});
|
|
1549
1727
|
function conversationPart(conversation) {
|
|
1550
1728
|
return conversation.thread ?? (conversation.channel === void 0 ? void 0 : `#${conversation.channel}`);
|
|
@@ -1555,7 +1733,7 @@ function channelConversation(scope, channel) {
|
|
|
1555
1733
|
const name = at < 0 ? channel : channel.slice(at + 1);
|
|
1556
1734
|
return place === scope && name !== "general" ? name : void 0;
|
|
1557
1735
|
}
|
|
1558
|
-
var TurnRecordSchema =
|
|
1736
|
+
var TurnRecordSchema = z10.object({
|
|
1559
1737
|
/** Assigned by the board when the turn begins; the turn's transcript is filed under it. */
|
|
1560
1738
|
id: UlidSchema.optional(),
|
|
1561
1739
|
agent: NameSchema,
|
|
@@ -1566,31 +1744,31 @@ var TurnRecordSchema = z8.object({
|
|
|
1566
1744
|
channel: NameSchema.optional(),
|
|
1567
1745
|
runner: NameSchema,
|
|
1568
1746
|
cli: CliKindSchema.nullable(),
|
|
1569
|
-
session:
|
|
1747
|
+
session: z10.string().nullable(),
|
|
1570
1748
|
trigger: TriggerSchema,
|
|
1571
1749
|
startedAt: IsoDateTimeSchema,
|
|
1572
1750
|
endedAt: IsoDateTimeSchema.nullable(),
|
|
1573
1751
|
exitReason: TurnExitReasonSchema.nullable(),
|
|
1574
1752
|
status: TurnStatusSchema.nullable(),
|
|
1575
|
-
error:
|
|
1753
|
+
error: z10.string().nullable(),
|
|
1576
1754
|
usage: UsageSchema.nullable(),
|
|
1577
|
-
costUsd:
|
|
1755
|
+
costUsd: z10.number().nonnegative().default(0),
|
|
1578
1756
|
/**
|
|
1579
1757
|
* The running total the CLI reported for the session after this turn, when it reports one. A
|
|
1580
1758
|
* resumed session starts from it, so the next turn's own cost is measured from here.
|
|
1581
1759
|
*/
|
|
1582
|
-
sessionCostUsd:
|
|
1583
|
-
toolCalls:
|
|
1760
|
+
sessionCostUsd: z10.number().nonnegative().optional(),
|
|
1761
|
+
toolCalls: z10.number().int().nonnegative().default(0),
|
|
1584
1762
|
/** The model the CLI reported for this turn, else the model configured for the agent, else null. */
|
|
1585
|
-
model:
|
|
1763
|
+
model: z10.string().nullable().default(null),
|
|
1586
1764
|
/** The task branch the turn left work on, with its commit, as the runner reported it. */
|
|
1587
1765
|
work: TurnWorkSchema.optional(),
|
|
1588
1766
|
/** Who stopped the turn, for one that ended `stopped`. */
|
|
1589
1767
|
stoppedBy: NameSchema.optional(),
|
|
1590
1768
|
/** The crons whose fire started the turn, which record how it ended. */
|
|
1591
|
-
crons:
|
|
1769
|
+
crons: z10.array(UlidSchema).optional()
|
|
1592
1770
|
});
|
|
1593
|
-
var RunningTurnSchema =
|
|
1771
|
+
var RunningTurnSchema = z10.object({
|
|
1594
1772
|
turnId: UlidSchema,
|
|
1595
1773
|
agent: NameSchema,
|
|
1596
1774
|
scope: NameSchema,
|
|
@@ -1598,49 +1776,49 @@ var RunningTurnSchema = z8.object({
|
|
|
1598
1776
|
channel: NameSchema.optional(),
|
|
1599
1777
|
cli: CliKindSchema,
|
|
1600
1778
|
askedIn: ChannelRefSchema.optional(),
|
|
1601
|
-
steerable:
|
|
1602
|
-
stoppable:
|
|
1779
|
+
steerable: z10.boolean(),
|
|
1780
|
+
stoppable: z10.boolean()
|
|
1603
1781
|
});
|
|
1604
|
-
var SessionsFileSchema =
|
|
1605
|
-
claude:
|
|
1606
|
-
codex:
|
|
1782
|
+
var SessionsFileSchema = z10.object({
|
|
1783
|
+
claude: z10.string().optional(),
|
|
1784
|
+
codex: z10.string().optional(),
|
|
1607
1785
|
runner: NameSchema.optional()
|
|
1608
1786
|
});
|
|
1609
|
-
var WakeRequestSchema =
|
|
1787
|
+
var WakeRequestSchema = z10.object({
|
|
1610
1788
|
agent: NameSchema,
|
|
1611
1789
|
project: NameSchema,
|
|
1612
|
-
reason:
|
|
1790
|
+
reason: z10.string().default("manual wake"),
|
|
1613
1791
|
/** A manual wake, or a reflection turn requested ahead of the cadence. */
|
|
1614
|
-
kind:
|
|
1792
|
+
kind: z10.enum(["manual", "reflection"]).default("manual")
|
|
1615
1793
|
});
|
|
1616
|
-
var TurnHistoryEntrySchema =
|
|
1794
|
+
var TurnHistoryEntrySchema = z10.object({
|
|
1617
1795
|
/** The id of the event that ended the turn. */
|
|
1618
1796
|
id: UlidSchema,
|
|
1619
1797
|
/** The turn's own id, when it has a transcript to open; turns before transcripts have none. */
|
|
1620
1798
|
turnId: UlidSchema.optional(),
|
|
1621
1799
|
ts: IsoDateTimeSchema,
|
|
1622
|
-
outcome:
|
|
1800
|
+
outcome: z10.enum(["completed", "failed"]),
|
|
1623
1801
|
/** A project slug, or the society scope. */
|
|
1624
1802
|
project: NameSchema,
|
|
1625
1803
|
/** The thread whose conversation the turn was in; absent for the home conversation. */
|
|
1626
1804
|
thread: UlidSchema.optional(),
|
|
1627
1805
|
/** The channel, never general, whose conversation the turn was in. */
|
|
1628
1806
|
channel: NameSchema.optional(),
|
|
1629
|
-
trigger:
|
|
1630
|
-
exitReason:
|
|
1631
|
-
costUsd:
|
|
1807
|
+
trigger: z10.string(),
|
|
1808
|
+
exitReason: z10.string().nullable(),
|
|
1809
|
+
costUsd: z10.number(),
|
|
1632
1810
|
/** The tokens the turn used; absent for turns logged before turns recorded them. */
|
|
1633
1811
|
usage: UsageSchema.optional(),
|
|
1634
|
-
model:
|
|
1635
|
-
summary:
|
|
1636
|
-
error:
|
|
1812
|
+
model: z10.string().nullable(),
|
|
1813
|
+
summary: z10.string().nullable(),
|
|
1814
|
+
error: z10.string().nullable(),
|
|
1637
1815
|
/** When the log recorded the turn's start; absent when the start is missing from the log. */
|
|
1638
1816
|
startedAt: IsoDateTimeSchema.optional(),
|
|
1639
|
-
toolCalls:
|
|
1817
|
+
toolCalls: z10.number().int().nonnegative().optional()
|
|
1640
1818
|
});
|
|
1641
1819
|
|
|
1642
1820
|
// packages/shared/dist/ops.js
|
|
1643
|
-
import { z as
|
|
1821
|
+
import { z as z11 } from "zod";
|
|
1644
1822
|
var OPS_SIGNAL_KINDS = [
|
|
1645
1823
|
"waiting_stage",
|
|
1646
1824
|
"backlog",
|
|
@@ -1656,16 +1834,16 @@ var OPS_SIGNAL_KINDS = [
|
|
|
1656
1834
|
"stuck_workspace",
|
|
1657
1835
|
"cron_failing"
|
|
1658
1836
|
];
|
|
1659
|
-
var OpsSignalKindSchema =
|
|
1660
|
-
var OpsSignalSchema =
|
|
1837
|
+
var OpsSignalKindSchema = z11.enum(OPS_SIGNAL_KINDS);
|
|
1838
|
+
var OpsSignalSchema = z11.object({
|
|
1661
1839
|
kind: OpsSignalKindSchema,
|
|
1662
1840
|
/** Identifies the condition, for example `backlog:demo:engineer`, so a persisting one is not logged again every pass. */
|
|
1663
|
-
key:
|
|
1841
|
+
key: z11.string().min(1),
|
|
1664
1842
|
/** One line a reader can act on. */
|
|
1665
|
-
summary:
|
|
1843
|
+
summary: z11.string().min(1),
|
|
1666
1844
|
/** The counter or timer value behind the signal. */
|
|
1667
|
-
value:
|
|
1668
|
-
threshold:
|
|
1845
|
+
value: z11.number(),
|
|
1846
|
+
threshold: z11.number().optional(),
|
|
1669
1847
|
project: NameSchema.optional(),
|
|
1670
1848
|
agent: NameSchema.optional(),
|
|
1671
1849
|
role: NameSchema.optional(),
|
|
@@ -1673,8 +1851,8 @@ var OpsSignalSchema = z9.object({
|
|
|
1673
1851
|
});
|
|
1674
1852
|
|
|
1675
1853
|
// packages/shared/dist/metrics.js
|
|
1676
|
-
import { z as
|
|
1677
|
-
var MetricsWindowSchema =
|
|
1854
|
+
import { z as z12 } from "zod";
|
|
1855
|
+
var MetricsWindowSchema = z12.enum(["24h", "7d", "all"]);
|
|
1678
1856
|
var METRICS_WINDOW_MS = {
|
|
1679
1857
|
"24h": 24 * 36e5,
|
|
1680
1858
|
"7d": 7 * 24 * 36e5,
|
|
@@ -1685,9 +1863,9 @@ function isBoardAction(tool) {
|
|
|
1685
1863
|
const verb = /^mcp__board__(.+)$/.exec(tool)?.[1];
|
|
1686
1864
|
return verb !== void 0 && !READ_VERBS.some((read2) => read2 === verb);
|
|
1687
1865
|
}
|
|
1688
|
-
var CountSchema =
|
|
1689
|
-
var MsSchema =
|
|
1690
|
-
var MetricsSchema =
|
|
1866
|
+
var CountSchema = z12.number().int().nonnegative();
|
|
1867
|
+
var MsSchema = z12.number().nonnegative();
|
|
1868
|
+
var MetricsSchema = z12.object({
|
|
1691
1869
|
window: MetricsWindowSchema,
|
|
1692
1870
|
since: IsoDateTimeSchema.nullable(),
|
|
1693
1871
|
until: IsoDateTimeSchema,
|
|
@@ -1695,12 +1873,12 @@ var MetricsSchema = z10.object({
|
|
|
1695
1873
|
* Finished turns that changed nothing on the board. Reflections are left out, since they write
|
|
1696
1874
|
* memory, not the board; turns without a transcript are counted apart, their actions unknown.
|
|
1697
1875
|
*/
|
|
1698
|
-
idle:
|
|
1876
|
+
idle: z12.object({
|
|
1699
1877
|
turns: CountSchema,
|
|
1700
1878
|
idle: CountSchema,
|
|
1701
1879
|
unknown: CountSchema,
|
|
1702
|
-
byTrigger:
|
|
1703
|
-
byAgent:
|
|
1880
|
+
byTrigger: z12.array(z12.object({ trigger: z12.string(), turns: CountSchema, idle: CountSchema })),
|
|
1881
|
+
byAgent: z12.array(z12.object({
|
|
1704
1882
|
agent: NameSchema,
|
|
1705
1883
|
role: NameSchema.nullable(),
|
|
1706
1884
|
turns: CountSchema,
|
|
@@ -1708,33 +1886,33 @@ var MetricsSchema = z10.object({
|
|
|
1708
1886
|
}))
|
|
1709
1887
|
}),
|
|
1710
1888
|
/** Work sent back to an earlier stage: over the tasks finished in the window, and by where. */
|
|
1711
|
-
sentBack:
|
|
1889
|
+
sentBack: z12.object({
|
|
1712
1890
|
finished: CountSchema,
|
|
1713
1891
|
sendBacks: CountSchema,
|
|
1714
1892
|
tasksSentBack: CountSchema,
|
|
1715
|
-
byStage:
|
|
1716
|
-
bySender:
|
|
1893
|
+
byStage: z12.array(z12.object({ project: NameSchema, stage: z12.string(), count: CountSchema })),
|
|
1894
|
+
bySender: z12.array(z12.object({ agent: NameSchema, count: CountSchema }))
|
|
1717
1895
|
}),
|
|
1718
1896
|
/** Posts in the threads of the tasks finished in the window, the board's own notices left out. */
|
|
1719
|
-
messages:
|
|
1897
|
+
messages: z12.object({
|
|
1720
1898
|
finished: CountSchema,
|
|
1721
1899
|
messages: CountSchema,
|
|
1722
|
-
byProject:
|
|
1723
|
-
busiest:
|
|
1900
|
+
byProject: z12.array(z12.object({ project: NameSchema, finished: CountSchema, messages: CountSchema })),
|
|
1901
|
+
busiest: z12.array(z12.object({
|
|
1724
1902
|
taskId: UlidSchema,
|
|
1725
|
-
title:
|
|
1903
|
+
title: z12.string(),
|
|
1726
1904
|
project: NameSchema,
|
|
1727
1905
|
messages: CountSchema
|
|
1728
1906
|
}))
|
|
1729
1907
|
}),
|
|
1730
1908
|
/** Time from a mention to the start of the turn it woke, in the conversation it was made in. */
|
|
1731
|
-
latency:
|
|
1909
|
+
latency: z12.object({
|
|
1732
1910
|
mentions: CountSchema,
|
|
1733
1911
|
/** Mentions no turn has followed yet. */
|
|
1734
1912
|
unanswered: CountSchema,
|
|
1735
1913
|
medianMs: MsSchema.nullable(),
|
|
1736
1914
|
slowestMs: MsSchema.nullable(),
|
|
1737
|
-
byAgent:
|
|
1915
|
+
byAgent: z12.array(z12.object({
|
|
1738
1916
|
agent: NameSchema,
|
|
1739
1917
|
mentions: CountSchema,
|
|
1740
1918
|
medianMs: MsSchema,
|
|
@@ -1742,81 +1920,141 @@ var MetricsSchema = z10.object({
|
|
|
1742
1920
|
}))
|
|
1743
1921
|
}),
|
|
1744
1922
|
/** The user's decisions: proposals decided, questions answered, and stages passed or sent back. */
|
|
1745
|
-
decisions:
|
|
1923
|
+
decisions: z12.object({
|
|
1746
1924
|
total: CountSchema,
|
|
1747
|
-
byDay:
|
|
1748
|
-
day:
|
|
1925
|
+
byDay: z12.array(z12.object({
|
|
1926
|
+
day: z12.string(),
|
|
1749
1927
|
proposals: CountSchema,
|
|
1750
1928
|
answers: CountSchema,
|
|
1751
1929
|
stages: CountSchema
|
|
1752
1930
|
}))
|
|
1753
1931
|
}),
|
|
1754
1932
|
/** Tasks that needed a capability no connected runner offered, and whether they still do. */
|
|
1755
|
-
blocked:
|
|
1933
|
+
blocked: z12.array(z12.object({
|
|
1756
1934
|
taskId: UlidSchema,
|
|
1757
|
-
title:
|
|
1935
|
+
title: z12.string().nullable(),
|
|
1758
1936
|
project: NameSchema.nullable(),
|
|
1759
|
-
summary:
|
|
1937
|
+
summary: z12.string(),
|
|
1760
1938
|
firstAt: IsoDateTimeSchema,
|
|
1761
1939
|
lastAt: IsoDateTimeSchema,
|
|
1762
|
-
holds:
|
|
1940
|
+
holds: z12.boolean()
|
|
1763
1941
|
}))
|
|
1764
1942
|
});
|
|
1943
|
+
var CitizenTokensSchema = z12.object({
|
|
1944
|
+
agent: NameSchema,
|
|
1945
|
+
turns: CountSchema,
|
|
1946
|
+
withUsage: CountSchema,
|
|
1947
|
+
usage: UsageSchema.nullable()
|
|
1948
|
+
});
|
|
1949
|
+
var TokenUseSchema = z12.object({
|
|
1950
|
+
window: MetricsWindowSchema,
|
|
1951
|
+
since: IsoDateTimeSchema.nullable(),
|
|
1952
|
+
until: IsoDateTimeSchema,
|
|
1953
|
+
citizens: z12.array(CitizenTokensSchema)
|
|
1954
|
+
});
|
|
1765
1955
|
|
|
1766
1956
|
// packages/shared/dist/config.js
|
|
1767
|
-
import { z as
|
|
1768
|
-
var LogLevelSchema =
|
|
1769
|
-
var GithubSignInSchema =
|
|
1770
|
-
clientId:
|
|
1771
|
-
clientSecret:
|
|
1957
|
+
import { z as z13 } from "zod";
|
|
1958
|
+
var LogLevelSchema = z13.enum(["trace", "debug", "info", "warn", "error", "fatal"]);
|
|
1959
|
+
var GithubSignInSchema = z13.object({
|
|
1960
|
+
clientId: z13.string().min(1),
|
|
1961
|
+
clientSecret: z13.string().min(1),
|
|
1772
1962
|
/** Logins, lowercased; GitHub logins are case-insensitive. */
|
|
1773
|
-
users:
|
|
1963
|
+
users: z13.array(z13.string().min(1)).min(1)
|
|
1774
1964
|
});
|
|
1775
|
-
var ServerConfigSchema =
|
|
1776
|
-
dataDir:
|
|
1777
|
-
host:
|
|
1778
|
-
port:
|
|
1965
|
+
var ServerConfigSchema = z13.object({
|
|
1966
|
+
dataDir: z13.string().min(1),
|
|
1967
|
+
host: z13.string().min(1),
|
|
1968
|
+
port: z13.number().int().positive().max(65535),
|
|
1779
1969
|
/**
|
|
1780
1970
|
* An address every runner's agents reach this server at, for example https://board.example, or
|
|
1781
1971
|
* null for each runner to use the address it reaches the server at itself.
|
|
1782
1972
|
*/
|
|
1783
|
-
publicUrl:
|
|
1973
|
+
publicUrl: z13.string().min(1).nullable(),
|
|
1784
1974
|
logLevel: LogLevelSchema,
|
|
1785
1975
|
/** Turns running at once across every runner, or null for no limit beyond each runner's own. */
|
|
1786
|
-
concurrency:
|
|
1976
|
+
concurrency: z13.number().int().positive().nullable(),
|
|
1787
1977
|
/** How long one turn may run before it is stopped, or null for no limit. */
|
|
1788
|
-
turnTimeoutMs:
|
|
1978
|
+
turnTimeoutMs: z13.number().int().positive().nullable(),
|
|
1789
1979
|
/** Rounds of tool calls one Claude turn may take, or null for no limit. */
|
|
1790
|
-
toolRounds:
|
|
1980
|
+
toolRounds: z13.number().int().positive().nullable(),
|
|
1791
1981
|
/** How long a resident session stays warm after its last turn. */
|
|
1792
|
-
residentIdleMs:
|
|
1982
|
+
residentIdleMs: z13.number().int().positive(),
|
|
1793
1983
|
/** Signing in to the board with GitHub, or null when only a token lets anyone in. */
|
|
1794
1984
|
github: GithubSignInSchema.nullable(),
|
|
1795
1985
|
/**
|
|
1796
1986
|
* Reverse proxies in front of the server whose X-Forwarded-For entries name the client, for the
|
|
1797
1987
|
* rate limits on what anyone may ask without a token: 0 when clients connect directly.
|
|
1798
1988
|
*/
|
|
1799
|
-
trustedProxies:
|
|
1989
|
+
trustedProxies: z13.number().int().min(0).max(16)
|
|
1800
1990
|
});
|
|
1801
|
-
var RunnerConfigSchema =
|
|
1991
|
+
var RunnerConfigSchema = z13.object({
|
|
1802
1992
|
/** The board server, for example http://127.0.0.1:4700. */
|
|
1803
|
-
serverUrl:
|
|
1993
|
+
serverUrl: z13.string().url(),
|
|
1804
1994
|
/**
|
|
1805
1995
|
* The runner's token, from `runner add`, or null for the one it saved when it was enrolled, or
|
|
1806
1996
|
* to enroll it.
|
|
1807
1997
|
*/
|
|
1808
|
-
token:
|
|
1998
|
+
token: z13.string().min(1).nullable(),
|
|
1809
1999
|
/** The runner's own data directory: the board mirror, agent homes, repositories, worktrees. */
|
|
1810
|
-
dataDir:
|
|
2000
|
+
dataDir: z13.string().min(1),
|
|
1811
2001
|
logLevel: LogLevelSchema,
|
|
1812
2002
|
/** Turns this machine runs at once, or null for no limit. */
|
|
1813
|
-
slots:
|
|
1814
|
-
clis:
|
|
1815
|
-
capabilities:
|
|
2003
|
+
slots: z13.number().int().positive().nullable(),
|
|
2004
|
+
clis: z13.array(CliKindSchema).min(1),
|
|
2005
|
+
capabilities: z13.array(z13.string())
|
|
1816
2006
|
});
|
|
1817
2007
|
|
|
1818
2008
|
// packages/shared/dist/version.js
|
|
1819
|
-
var STELLARIS_VERSION = "0.3.
|
|
2009
|
+
var STELLARIS_VERSION = "0.3.23";
|
|
2010
|
+
|
|
2011
|
+
// packages/shared/dist/mentions.js
|
|
2012
|
+
import { parse, postprocess, preprocess } from "micromark";
|
|
2013
|
+
import { gfm } from "micromark-extension-gfm";
|
|
2014
|
+
var MENTION_PATTERN = /(^|[^\w@])@([a-z0-9][a-z0-9-]{0,31})(?![\w-])/g;
|
|
2015
|
+
var CODE = /* @__PURE__ */ new Set(["codeText", "codeFenced", "codeIndented"]);
|
|
2016
|
+
var SLOW = {
|
|
2017
|
+
disable: {
|
|
2018
|
+
null: [
|
|
2019
|
+
"wwwAutolink",
|
|
2020
|
+
"protocolAutolink",
|
|
2021
|
+
"emailAutolink",
|
|
2022
|
+
"gfmFootnoteCall",
|
|
2023
|
+
"gfmPotentialFootnoteCall"
|
|
2024
|
+
]
|
|
2025
|
+
}
|
|
2026
|
+
};
|
|
2027
|
+
function codeRanges(markdown) {
|
|
2028
|
+
const shift = markdown.startsWith("\uFEFF") ? 1 : 0;
|
|
2029
|
+
const events = postprocess(parse({ extensions: [gfm(), SLOW] }).document().write(preprocess()(markdown, void 0, true)));
|
|
2030
|
+
return events.flatMap(([kind, token]) => kind === "enter" && CODE.has(token.type) ? [[token.start.offset + shift, token.end.offset + shift]] : []);
|
|
2031
|
+
}
|
|
2032
|
+
function addMentions(found, text) {
|
|
2033
|
+
for (const match of text.matchAll(MENTION_PATTERN)) {
|
|
2034
|
+
const name = match[2];
|
|
2035
|
+
if (name !== void 0) {
|
|
2036
|
+
found.add(name);
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
function mentionsIn(markdown) {
|
|
2041
|
+
if (markdown.search(MENTION_PATTERN) === -1) {
|
|
2042
|
+
return [];
|
|
2043
|
+
}
|
|
2044
|
+
const found = /* @__PURE__ */ new Set();
|
|
2045
|
+
let from = 0;
|
|
2046
|
+
for (const [start, end] of codeRanges(markdown)) {
|
|
2047
|
+
addMentions(found, markdown.slice(from, start));
|
|
2048
|
+
from = end;
|
|
2049
|
+
}
|
|
2050
|
+
addMentions(found, markdown.slice(from));
|
|
2051
|
+
return [...found].toSorted();
|
|
2052
|
+
}
|
|
2053
|
+
function mentionsAnywhere(text) {
|
|
2054
|
+
const found = /* @__PURE__ */ new Set();
|
|
2055
|
+
addMentions(found, text);
|
|
2056
|
+
return [...found].toSorted();
|
|
2057
|
+
}
|
|
1820
2058
|
|
|
1821
2059
|
// packages/board-core/dist/errors.js
|
|
1822
2060
|
var BoardError = class extends Error {
|
|
@@ -2459,33 +2697,59 @@ function filesOf(lines, status) {
|
|
|
2459
2697
|
return [...files.values()];
|
|
2460
2698
|
}
|
|
2461
2699
|
|
|
2700
|
+
// packages/board-core/dist/mentions.js
|
|
2701
|
+
import vm from "node:vm";
|
|
2702
|
+
var MENTION_PARSE_MS = 500;
|
|
2703
|
+
var context = vm.createContext({});
|
|
2704
|
+
var call = new vm.Script("work()");
|
|
2705
|
+
function within(work, ms) {
|
|
2706
|
+
let result;
|
|
2707
|
+
context["work"] = () => {
|
|
2708
|
+
result = work();
|
|
2709
|
+
};
|
|
2710
|
+
try {
|
|
2711
|
+
call.runInContext(context, { timeout: ms });
|
|
2712
|
+
} catch (error) {
|
|
2713
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
|
|
2714
|
+
return void 0;
|
|
2715
|
+
}
|
|
2716
|
+
throw error;
|
|
2717
|
+
} finally {
|
|
2718
|
+
context["work"] = void 0;
|
|
2719
|
+
}
|
|
2720
|
+
return result;
|
|
2721
|
+
}
|
|
2722
|
+
function postMentions(body) {
|
|
2723
|
+
return within(() => mentionsIn(body), MENTION_PARSE_MS) ?? mentionsAnywhere(body);
|
|
2724
|
+
}
|
|
2725
|
+
|
|
2462
2726
|
// packages/board-core/dist/metrics.js
|
|
2463
|
-
import { z as
|
|
2464
|
-
var TurnPayload =
|
|
2465
|
-
turnId:
|
|
2466
|
-
project:
|
|
2467
|
-
thread:
|
|
2468
|
-
channel:
|
|
2469
|
-
trigger:
|
|
2470
|
-
});
|
|
2471
|
-
var TaskPayload =
|
|
2472
|
-
taskId:
|
|
2473
|
-
project:
|
|
2474
|
-
from:
|
|
2475
|
-
});
|
|
2476
|
-
var MessagePayload =
|
|
2477
|
-
id:
|
|
2478
|
-
channel:
|
|
2479
|
-
thread:
|
|
2480
|
-
mentions:
|
|
2481
|
-
});
|
|
2482
|
-
var SteeredPayload =
|
|
2483
|
-
var SignalPayload =
|
|
2484
|
-
kind:
|
|
2485
|
-
key:
|
|
2486
|
-
summary:
|
|
2487
|
-
taskId:
|
|
2488
|
-
project:
|
|
2727
|
+
import { z as z14 } from "zod";
|
|
2728
|
+
var TurnPayload = z14.object({
|
|
2729
|
+
turnId: z14.string().optional(),
|
|
2730
|
+
project: z14.string(),
|
|
2731
|
+
thread: z14.string().optional(),
|
|
2732
|
+
channel: z14.string().optional(),
|
|
2733
|
+
trigger: z14.string()
|
|
2734
|
+
});
|
|
2735
|
+
var TaskPayload = z14.object({
|
|
2736
|
+
taskId: z14.string(),
|
|
2737
|
+
project: z14.string(),
|
|
2738
|
+
from: z14.string().optional()
|
|
2739
|
+
});
|
|
2740
|
+
var MessagePayload = z14.object({
|
|
2741
|
+
id: z14.string().optional(),
|
|
2742
|
+
channel: z14.string(),
|
|
2743
|
+
thread: z14.string().nullable().optional(),
|
|
2744
|
+
mentions: z14.array(z14.string()).default([])
|
|
2745
|
+
});
|
|
2746
|
+
var SteeredPayload = z14.object({ messages: z14.array(z14.string()) });
|
|
2747
|
+
var SignalPayload = z14.object({
|
|
2748
|
+
kind: z14.string(),
|
|
2749
|
+
key: z14.string(),
|
|
2750
|
+
summary: z14.string(),
|
|
2751
|
+
taskId: z14.string().optional(),
|
|
2752
|
+
project: z14.string().optional()
|
|
2489
2753
|
});
|
|
2490
2754
|
function median(values) {
|
|
2491
2755
|
const sorted = values.toSorted((a, b) => a - b);
|
|
@@ -2774,6 +3038,59 @@ function computeMetrics(input) {
|
|
|
2774
3038
|
};
|
|
2775
3039
|
}
|
|
2776
3040
|
|
|
3041
|
+
// packages/board-core/dist/turn-history.js
|
|
3042
|
+
import { z as z15 } from "zod";
|
|
3043
|
+
var TurnHistoryPayloadSchema = z15.object({
|
|
3044
|
+
project: NameSchema,
|
|
3045
|
+
thread: UlidSchema.optional(),
|
|
3046
|
+
channel: NameSchema.optional(),
|
|
3047
|
+
trigger: z15.string().default("manual"),
|
|
3048
|
+
exitReason: z15.string().nullable().default(null),
|
|
3049
|
+
costUsd: z15.number().default(0),
|
|
3050
|
+
usage: UsageSchema.optional(),
|
|
3051
|
+
model: z15.string().nullable().default(null),
|
|
3052
|
+
summary: z15.string().nullable().default(null),
|
|
3053
|
+
error: z15.string().nullable().default(null),
|
|
3054
|
+
toolCalls: z15.number().int().nonnegative().optional(),
|
|
3055
|
+
turnId: UlidSchema.optional()
|
|
3056
|
+
});
|
|
3057
|
+
function tokenUse(events, window, now) {
|
|
3058
|
+
const span = METRICS_WINDOW_MS[window];
|
|
3059
|
+
const since = span === null ? null : now.getTime() - span;
|
|
3060
|
+
const rows = /* @__PURE__ */ new Map();
|
|
3061
|
+
for (const event of events) {
|
|
3062
|
+
if (event.type !== "turn.completed" && event.type !== "turn.failed") {
|
|
3063
|
+
continue;
|
|
3064
|
+
}
|
|
3065
|
+
if (since !== null && Date.parse(event.ts) < since) {
|
|
3066
|
+
continue;
|
|
3067
|
+
}
|
|
3068
|
+
const turn2 = TurnHistoryPayloadSchema.safeParse(event.payload);
|
|
3069
|
+
if (!turn2.success) {
|
|
3070
|
+
continue;
|
|
3071
|
+
}
|
|
3072
|
+
const row = rows.get(event.actor) ?? {
|
|
3073
|
+
agent: event.actor,
|
|
3074
|
+
turns: 0,
|
|
3075
|
+
withUsage: 0,
|
|
3076
|
+
usage: null
|
|
3077
|
+
};
|
|
3078
|
+
const usage = turn2.data.usage;
|
|
3079
|
+
rows.set(event.actor, {
|
|
3080
|
+
agent: event.actor,
|
|
3081
|
+
turns: row.turns + 1,
|
|
3082
|
+
withUsage: row.withUsage + (usage === void 0 ? 0 : 1),
|
|
3083
|
+
usage: usage === void 0 ? row.usage : row.usage === null ? usage : addUsage(row.usage, usage)
|
|
3084
|
+
});
|
|
3085
|
+
}
|
|
3086
|
+
return {
|
|
3087
|
+
window,
|
|
3088
|
+
since: since === null ? null : new Date(since).toISOString(),
|
|
3089
|
+
until: now.toISOString(),
|
|
3090
|
+
citizens: [...rows.values()].toSorted((a, b) => a.agent.localeCompare(b.agent))
|
|
3091
|
+
};
|
|
3092
|
+
}
|
|
3093
|
+
|
|
2777
3094
|
// packages/board-core/dist/mutex.js
|
|
2778
3095
|
var Mutex = class {
|
|
2779
3096
|
tail = Promise.resolve();
|
|
@@ -2980,6 +3297,13 @@ var BoardPaths = class {
|
|
|
2980
3297
|
eventLog() {
|
|
2981
3298
|
return path5.join(this.events(), "log.jsonl");
|
|
2982
3299
|
}
|
|
3300
|
+
/** Images citizens uploaded, by id: outside the projection, which every runner mirrors. */
|
|
3301
|
+
images() {
|
|
3302
|
+
return path5.join(this.dataDir, "images");
|
|
3303
|
+
}
|
|
3304
|
+
image(id) {
|
|
3305
|
+
return path5.join(this.images(), id);
|
|
3306
|
+
}
|
|
2983
3307
|
state() {
|
|
2984
3308
|
return path5.join(this.dataDir, "state");
|
|
2985
3309
|
}
|
|
@@ -3015,41 +3339,27 @@ function namesList(names) {
|
|
|
3015
3339
|
return names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names.at(-1) ?? ""}`;
|
|
3016
3340
|
}
|
|
3017
3341
|
var SKIPPED_IN_HOME = /* @__PURE__ */ new Set([".git", "turns", ".claude", ".codex"]);
|
|
3018
|
-
var RunnerTokensSchema =
|
|
3019
|
-
runners:
|
|
3342
|
+
var RunnerTokensSchema = z16.object({
|
|
3343
|
+
runners: z16.record(z16.string(), z16.object({ tokenHash: z16.string().min(1) }))
|
|
3020
3344
|
});
|
|
3021
|
-
var SignInsSchema =
|
|
3022
|
-
signIns:
|
|
3023
|
-
tokenHash:
|
|
3024
|
-
login:
|
|
3345
|
+
var SignInsSchema = z16.object({
|
|
3346
|
+
signIns: z16.array(z16.object({
|
|
3347
|
+
tokenHash: z16.string().min(1),
|
|
3348
|
+
login: z16.string().min(1),
|
|
3025
3349
|
/** The account's picture at the identity provider; sign-ins from before it have none. */
|
|
3026
|
-
avatarUrl:
|
|
3350
|
+
avatarUrl: z16.url().optional(),
|
|
3027
3351
|
createdAt: IsoDateTimeSchema,
|
|
3028
3352
|
expiresAt: IsoDateTimeSchema
|
|
3029
3353
|
})).default([])
|
|
3030
3354
|
});
|
|
3031
|
-
var
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
costUsd: z13.number().default(0),
|
|
3038
|
-
usage: UsageSchema.optional(),
|
|
3039
|
-
model: z13.string().nullable().default(null),
|
|
3040
|
-
summary: z13.string().nullable().default(null),
|
|
3041
|
-
error: z13.string().nullable().default(null),
|
|
3042
|
-
toolCalls: z13.number().int().nonnegative().optional(),
|
|
3043
|
-
turnId: UlidSchema.optional()
|
|
3044
|
-
});
|
|
3045
|
-
var TurnStartPayloadSchema = z13.object({ project: NameSchema, turnId: UlidSchema.optional() });
|
|
3046
|
-
var CursorsSchema = z13.object({
|
|
3047
|
-
digest: z13.string().nullable(),
|
|
3048
|
-
scopes: z13.record(z13.string(), z13.string()).default({}),
|
|
3049
|
-
threadsFrom: z13.record(z13.string(), z13.string().nullable()).default({}),
|
|
3050
|
-
channelsFrom: z13.record(z13.string(), z13.string().nullable()).default({}),
|
|
3355
|
+
var TurnStartPayloadSchema = z16.object({ project: NameSchema, turnId: UlidSchema.optional() });
|
|
3356
|
+
var CursorsSchema = z16.object({
|
|
3357
|
+
digest: z16.string().nullable(),
|
|
3358
|
+
scopes: z16.record(z16.string(), z16.string()).default({}),
|
|
3359
|
+
threadsFrom: z16.record(z16.string(), z16.string().nullable()).default({}),
|
|
3360
|
+
channelsFrom: z16.record(z16.string(), z16.string().nullable()).default({}),
|
|
3051
3361
|
/** How far a work role has read news, which goes to whichever of its general conversations reads first. */
|
|
3052
|
-
news:
|
|
3362
|
+
news: z16.string().optional()
|
|
3053
3363
|
});
|
|
3054
3364
|
var NO_CURSORS = { digest: null, scopes: {}, threadsFrom: {}, channelsFrom: {} };
|
|
3055
3365
|
function conversationKey(scope, part) {
|
|
@@ -3088,9 +3398,8 @@ function byId(a, b) {
|
|
|
3088
3398
|
function turnTime(record) {
|
|
3089
3399
|
return record.endedAt ?? record.startedAt;
|
|
3090
3400
|
}
|
|
3091
|
-
var PausedSchema =
|
|
3401
|
+
var PausedSchema = z16.object({ paused: z16.boolean() });
|
|
3092
3402
|
var DEFAULT_LEASE_MS = 30 * 60 * 1e3;
|
|
3093
|
-
var MENTION_PATTERN = /(^|[^\w@])@([a-z0-9][a-z0-9-]{0,31})(?![\w-])/g;
|
|
3094
3403
|
function withoutMentions(text) {
|
|
3095
3404
|
return text.replaceAll(MENTION_PATTERN, "$1$2");
|
|
3096
3405
|
}
|
|
@@ -3114,7 +3423,7 @@ var OPS_WAKE_TRIGGER = "ops_event";
|
|
|
3114
3423
|
var FRONT_DESK_TRIGGER = "user_post";
|
|
3115
3424
|
var OPS_CHANNELS = ["governance"];
|
|
3116
3425
|
var FRONT_DESK_CHANNELS = [ASK_CHANNEL];
|
|
3117
|
-
var AlignmentsSchema =
|
|
3426
|
+
var AlignmentsSchema = z16.object({ applied: z16.array(z16.string()).default([]) });
|
|
3118
3427
|
var FOLLOW_DECISIONS = "ops-readers-follow-decisions";
|
|
3119
3428
|
var THREAD_RECORDS = "threads-as-records";
|
|
3120
3429
|
var DIGEST_CURSORS = "digest-replaces-inbox";
|
|
@@ -3128,10 +3437,11 @@ var CHANNEL_CONVERSATIONS = "channel-conversations";
|
|
|
3128
3437
|
var DASHBOARD_UPDATES = "dashboard-updates-granted";
|
|
3129
3438
|
var CRON_VERBS = "cron-verbs-granted";
|
|
3130
3439
|
var KNOWLEDGE_NOTICES = "knowledge-notices";
|
|
3131
|
-
var
|
|
3440
|
+
var IMAGE_UPLOADS = "image-uploads-granted";
|
|
3441
|
+
var KnowledgeEventSchema = z16.object({
|
|
3132
3442
|
topic: NameSchema,
|
|
3133
3443
|
project: NameSchema.nullable(),
|
|
3134
|
-
replaced:
|
|
3444
|
+
replaced: z16.boolean().optional()
|
|
3135
3445
|
});
|
|
3136
3446
|
var CRON_VERB_NAMES = ["create_cron", "update_cron", "remove_cron"];
|
|
3137
3447
|
var OLD_DASHBOARD_LINE = "Agents may edit this file. It is rendered by the board UI.";
|
|
@@ -3249,16 +3559,6 @@ function unanswered(messages) {
|
|
|
3249
3559
|
}
|
|
3250
3560
|
return waiting;
|
|
3251
3561
|
}
|
|
3252
|
-
function extractMentions(body) {
|
|
3253
|
-
const found = /* @__PURE__ */ new Set();
|
|
3254
|
-
for (const match of body.matchAll(MENTION_PATTERN)) {
|
|
3255
|
-
const name = match[2];
|
|
3256
|
-
if (name !== void 0) {
|
|
3257
|
-
found.add(name);
|
|
3258
|
-
}
|
|
3259
|
-
}
|
|
3260
|
-
return [...found].toSorted();
|
|
3261
|
-
}
|
|
3262
3562
|
function snippetAround(text, query, radius = 80) {
|
|
3263
3563
|
const index = text.toLowerCase().indexOf(query.toLowerCase());
|
|
3264
3564
|
if (index === -1) {
|
|
@@ -3273,6 +3573,7 @@ var Board = class _Board {
|
|
|
3273
3573
|
mutex = new Mutex();
|
|
3274
3574
|
/** The turns in flight, which the server hosting them supplies; none until it does. */
|
|
3275
3575
|
turnsInFlight = () => [];
|
|
3576
|
+
imageSource = null;
|
|
3276
3577
|
newId = monotonicFactory();
|
|
3277
3578
|
events;
|
|
3278
3579
|
actionCounts = /* @__PURE__ */ new Map();
|
|
@@ -3337,7 +3638,8 @@ var Board = class _Board {
|
|
|
3337
3638
|
CHANNEL_CONVERSATIONS,
|
|
3338
3639
|
DASHBOARD_UPDATES,
|
|
3339
3640
|
CRON_VERBS,
|
|
3340
|
-
KNOWLEDGE_NOTICES
|
|
3641
|
+
KNOWLEDGE_NOTICES,
|
|
3642
|
+
IMAGE_UPLOADS
|
|
3341
3643
|
].filter((name) => !applied.includes(name));
|
|
3342
3644
|
if (pending.length === 0) {
|
|
3343
3645
|
return;
|
|
@@ -3367,13 +3669,13 @@ var Board = class _Board {
|
|
|
3367
3669
|
await this.openAsksChannel();
|
|
3368
3670
|
}
|
|
3369
3671
|
if (pending.includes(KNOWLEDGE_REMOVAL)) {
|
|
3370
|
-
await this.
|
|
3672
|
+
await this.grantBeside("write_knowledge", "remove_knowledge");
|
|
3371
3673
|
}
|
|
3372
3674
|
if (pending.includes(CHANNEL_CONVERSATIONS)) {
|
|
3373
3675
|
await this.startChannelCursors();
|
|
3374
3676
|
}
|
|
3375
3677
|
if (pending.includes(DASHBOARD_UPDATES)) {
|
|
3376
|
-
await this.
|
|
3678
|
+
await this.grantBeside("write_knowledge", "update_dashboard");
|
|
3377
3679
|
await this.rewordDashboards();
|
|
3378
3680
|
}
|
|
3379
3681
|
if (pending.includes(CRON_VERBS)) {
|
|
@@ -3382,6 +3684,9 @@ var Board = class _Board {
|
|
|
3382
3684
|
if (pending.includes(KNOWLEDGE_NOTICES)) {
|
|
3383
3685
|
await this.noticeKnowledgeNotes();
|
|
3384
3686
|
}
|
|
3687
|
+
if (pending.includes(IMAGE_UPLOADS)) {
|
|
3688
|
+
await this.grantBeside("post_message", "upload_image");
|
|
3689
|
+
}
|
|
3385
3690
|
await writeJson(file, { applied: [...applied, ...pending] });
|
|
3386
3691
|
}
|
|
3387
3692
|
/**
|
|
@@ -3423,12 +3728,12 @@ var Board = class _Board {
|
|
|
3423
3728
|
}
|
|
3424
3729
|
}
|
|
3425
3730
|
/**
|
|
3426
|
-
* Grants `verb` once to every charter granting `
|
|
3427
|
-
*
|
|
3731
|
+
* Grants `verb` once to every charter granting `beside`, the work roles' charters in practice;
|
|
3732
|
+
* seed roles have it from their seed.
|
|
3428
3733
|
*/
|
|
3429
|
-
async
|
|
3734
|
+
async grantBeside(beside, verb) {
|
|
3430
3735
|
for (const charter of await this.listRoles()) {
|
|
3431
|
-
if (charter.verbs.includes(
|
|
3736
|
+
if (charter.verbs.includes(beside) && !charter.verbs.includes(verb)) {
|
|
3432
3737
|
await this.writeRoleUnlocked(USER_NAME, { ...charter, verbs: [...charter.verbs, verb] }, { verbsAdded: [verb] });
|
|
3433
3738
|
}
|
|
3434
3739
|
}
|
|
@@ -3586,7 +3891,7 @@ var Board = class _Board {
|
|
|
3586
3891
|
}
|
|
3587
3892
|
}
|
|
3588
3893
|
for (const file of await listFiles(this.paths.tasks(slug))) {
|
|
3589
|
-
const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file),
|
|
3894
|
+
const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file), z16.record(z16.string(), z16.unknown()));
|
|
3590
3895
|
const legacy = raw.data["thread"];
|
|
3591
3896
|
if (legacy === void 0) {
|
|
3592
3897
|
continue;
|
|
@@ -3664,7 +3969,7 @@ var Board = class _Board {
|
|
|
3664
3969
|
* turns, so it follows nothing now.
|
|
3665
3970
|
*/
|
|
3666
3971
|
async renameInboxCursors() {
|
|
3667
|
-
const Legacy =
|
|
3972
|
+
const Legacy = z16.object({ inbox: z16.string().nullable() });
|
|
3668
3973
|
for (const agent2 of await this.listAgents()) {
|
|
3669
3974
|
const file = this.paths.agentCursors(agent2.name);
|
|
3670
3975
|
if (await exists(file)) {
|
|
@@ -3710,7 +4015,7 @@ ${charter.purpose}
|
|
|
3710
4015
|
*/
|
|
3711
4016
|
async alignSeedRole(seed) {
|
|
3712
4017
|
const file = this.paths.role(seed.name);
|
|
3713
|
-
const raw = await readMarkdown(file,
|
|
4018
|
+
const raw = await readMarkdown(file, z16.record(z16.string(), z16.unknown()));
|
|
3714
4019
|
const current = RoleCharterSchema.parse(raw.data);
|
|
3715
4020
|
const verbsAdded = seed.verbs.filter((verb) => !current.verbs.includes(verb));
|
|
3716
4021
|
const fieldsAligned = RoleCharterSchema.keyof().options.filter((key) => key === "verbs" || seed[key] === void 0 ? false : seed.name === USER_ROLE ? JSON.stringify(seed[key]) !== JSON.stringify(current[key]) : !(key in raw.data));
|
|
@@ -4027,7 +4332,7 @@ ${charter.purpose}
|
|
|
4027
4332
|
/** The society's norms, the one knowledge topic every turn loads. Empty until the steward writes it. */
|
|
4028
4333
|
async readSocietyNorms() {
|
|
4029
4334
|
const file = this.paths.societyKnowledgeFile("norms");
|
|
4030
|
-
return await exists(file) ? (await readMarkdown(file,
|
|
4335
|
+
return await exists(file) ? (await readMarkdown(file, z16.record(z16.string(), z16.unknown()))).body : "";
|
|
4031
4336
|
}
|
|
4032
4337
|
/** Knowledge topics of a project, or of the society when the project is null. */
|
|
4033
4338
|
async listKnowledge(project2) {
|
|
@@ -4047,7 +4352,7 @@ ${charter.purpose}
|
|
|
4047
4352
|
*/
|
|
4048
4353
|
async knowledgeAt(file, project2, topic) {
|
|
4049
4354
|
const { data, body } = await readLooseMarkdown(file);
|
|
4050
|
-
const revision =
|
|
4355
|
+
const revision = z16.number().int().min(0).safeParse(data["revision"]);
|
|
4051
4356
|
const updatedBy = NameSchema.safeParse(data["updatedBy"]);
|
|
4052
4357
|
const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
|
|
4053
4358
|
return {
|
|
@@ -4380,8 +4685,11 @@ ${DASHBOARD_LINE}
|
|
|
4380
4685
|
throw new BoardError("NOT_FOUND", `runner ${name} not found`);
|
|
4381
4686
|
}
|
|
4382
4687
|
const doc = await readMarkdown(file, RunnerSchema);
|
|
4688
|
+
const { gitIdentityMissing: reported, ...rest } = doc.data;
|
|
4689
|
+
const gitIdentityMissing = patch.gitIdentityMissing === void 0 ? reported : patch.gitIdentityMissing ?? void 0;
|
|
4383
4690
|
const next = RunnerSchema.parse({
|
|
4384
|
-
...
|
|
4691
|
+
...rest,
|
|
4692
|
+
...gitIdentityMissing === void 0 ? {} : { gitIdentityMissing: [...gitIdentityMissing] },
|
|
4385
4693
|
...patch.status === void 0 ? {} : { status: patch.status },
|
|
4386
4694
|
...patch.os === void 0 ? {} : { os: patch.os },
|
|
4387
4695
|
...patch.clis === void 0 ? {} : { clis: [...patch.clis] },
|
|
@@ -4409,6 +4717,36 @@ ${DASHBOARD_LINE}
|
|
|
4409
4717
|
return next;
|
|
4410
4718
|
});
|
|
4411
4719
|
}
|
|
4720
|
+
/**
|
|
4721
|
+
* Records a CLI's plan quota as a runner reported it, from a turn's stream or a read, merged over
|
|
4722
|
+
* what the record held. The record is written on every report, so it says when the numbers were
|
|
4723
|
+
* last seen; `runner.quota` is appended only when what a reader would see changes, since every
|
|
4724
|
+
* turn reports.
|
|
4725
|
+
*/
|
|
4726
|
+
async recordQuota(name, cli, quota) {
|
|
4727
|
+
return this.mutex.run(async () => {
|
|
4728
|
+
const file = this.paths.runner(name);
|
|
4729
|
+
if (!await exists(file)) {
|
|
4730
|
+
throw new BoardError("NOT_FOUND", `runner ${name} not found`);
|
|
4731
|
+
}
|
|
4732
|
+
const doc = await readMarkdown(file, RunnerSchema);
|
|
4733
|
+
const previous = doc.data.quotas?.[cli];
|
|
4734
|
+
const merged = mergeQuota(previous, quota);
|
|
4735
|
+
const next = RunnerSchema.parse({
|
|
4736
|
+
...doc.data,
|
|
4737
|
+
quotas: { ...doc.data.quotas, [cli]: merged }
|
|
4738
|
+
});
|
|
4739
|
+
await writeMarkdown(file, next, doc.body);
|
|
4740
|
+
if (quotaChanged(previous, merged)) {
|
|
4741
|
+
await this.events.append("runner.quota", SYSTEM_ACTOR.name, {
|
|
4742
|
+
name,
|
|
4743
|
+
cli,
|
|
4744
|
+
status: merged.status
|
|
4745
|
+
});
|
|
4746
|
+
}
|
|
4747
|
+
return next;
|
|
4748
|
+
});
|
|
4749
|
+
}
|
|
4412
4750
|
/**
|
|
4413
4751
|
* Logs an operations signal as an `ops.signal` event. No channel carries it: the scheduler wakes
|
|
4414
4752
|
* its readers from the event, the runner lists it in their prompts, and the interface's log shows
|
|
@@ -4977,6 +5315,60 @@ ${current.body}`);
|
|
|
4977
5315
|
return updated;
|
|
4978
5316
|
});
|
|
4979
5317
|
}
|
|
5318
|
+
/**
|
|
5319
|
+
* Keeps an image a citizen's turn names by its path, read on the runner the turn runs on, which
|
|
5320
|
+
* refuses a file outside the turn's worktree, the citizen's home, and the system temp folder.
|
|
5321
|
+
* Only the bytes of a PNG, JPEG, GIF, or WebP of at most `IMAGE_LIMIT_BYTES` are kept, checked
|
|
5322
|
+
* here again whatever the runner said, under a new id outside the projection, so no runner
|
|
5323
|
+
* mirrors them and no prompt carries them: a post shows the image by its `image:` address.
|
|
5324
|
+
*/
|
|
5325
|
+
async uploadImage(actor, input) {
|
|
5326
|
+
const args = VerbInputs.upload_image.parse(input);
|
|
5327
|
+
await this.authorize(actor, "upload_image");
|
|
5328
|
+
if (actor.scope === void 0) {
|
|
5329
|
+
throw new BoardError("INVALID_STATE", "upload_image reads the file on the machine a turn runs on, so only a turn can call it");
|
|
5330
|
+
}
|
|
5331
|
+
if (this.imageSource === null) {
|
|
5332
|
+
throw new BoardError("NOT_FOUND", "this board has no runners to read an image from");
|
|
5333
|
+
}
|
|
5334
|
+
const bytes = await this.imageSource(actor, args.path);
|
|
5335
|
+
const type = imageTypeOf(bytes);
|
|
5336
|
+
if (type === null) {
|
|
5337
|
+
throw new BoardError("VALIDATION", `${args.path} is not a PNG, JPEG, GIF, or WebP image by its first bytes`);
|
|
5338
|
+
}
|
|
5339
|
+
if (bytes.byteLength > IMAGE_LIMIT_BYTES) {
|
|
5340
|
+
throw new BoardError("VALIDATION", `${args.path} is ${bytes.byteLength} bytes, over the ${IMAGE_LIMIT_BYTES} an image may be`);
|
|
5341
|
+
}
|
|
5342
|
+
return this.mutex.run(async () => {
|
|
5343
|
+
const id = this.newId();
|
|
5344
|
+
await writeFileAtomic(this.paths.image(id), bytes);
|
|
5345
|
+
await this.events.append("image.uploaded", actor.name, {
|
|
5346
|
+
id,
|
|
5347
|
+
type,
|
|
5348
|
+
size: bytes.byteLength
|
|
5349
|
+
});
|
|
5350
|
+
const name = path6.basename(args.path).replaceAll(/[[\]\\\r\n]/g, "");
|
|
5351
|
+
return {
|
|
5352
|
+
id,
|
|
5353
|
+
type,
|
|
5354
|
+
size: bytes.byteLength,
|
|
5355
|
+
markdown: ``
|
|
5356
|
+
};
|
|
5357
|
+
});
|
|
5358
|
+
}
|
|
5359
|
+
/** An uploaded image's bytes and kind, which its first bytes tell. */
|
|
5360
|
+
async readImage(id) {
|
|
5361
|
+
const file = this.paths.image(UlidSchema.parse(id));
|
|
5362
|
+
if (!await exists(file)) {
|
|
5363
|
+
throw new BoardError("NOT_FOUND", `image ${id} not found`);
|
|
5364
|
+
}
|
|
5365
|
+
const bytes = await readFile4(file);
|
|
5366
|
+
const type = imageTypeOf(bytes);
|
|
5367
|
+
if (type === null) {
|
|
5368
|
+
throw new BoardError("NOT_FOUND", `image ${id} is not an image the board shows`);
|
|
5369
|
+
}
|
|
5370
|
+
return { type, bytes };
|
|
5371
|
+
}
|
|
4980
5372
|
/** Every cron, ended ones included, oldest first. */
|
|
4981
5373
|
async listCrons() {
|
|
4982
5374
|
const crons = [];
|
|
@@ -5368,6 +5760,13 @@ ${current.body}`);
|
|
|
5368
5760
|
watchTurns(source) {
|
|
5369
5761
|
this.turnsInFlight = source;
|
|
5370
5762
|
}
|
|
5763
|
+
/**
|
|
5764
|
+
* Where `upload_image` reads a file from: the runner the calling turn runs on, through the server
|
|
5765
|
+
* that hosts the runners. Without one, as in the admin CLI, nothing can be uploaded.
|
|
5766
|
+
*/
|
|
5767
|
+
readImagesWith(source) {
|
|
5768
|
+
this.imageSource = source;
|
|
5769
|
+
}
|
|
5371
5770
|
/**
|
|
5372
5771
|
* Refuses to end conversations while another citizen's turn is in one of them: `cut` picks the
|
|
5373
5772
|
* turns that would lose theirs. The caller's own turn is exempt, since ending a conversation
|
|
@@ -6197,6 +6596,8 @@ ${rationale}`}`);
|
|
|
6197
6596
|
return this.updateCron(actor, VerbInputs.update_cron.parse(input));
|
|
6198
6597
|
case "remove_cron":
|
|
6199
6598
|
return this.removeCron(actor, VerbInputs.remove_cron.parse(input));
|
|
6599
|
+
case "upload_image":
|
|
6600
|
+
return this.uploadImage(actor, VerbInputs.upload_image.parse(input));
|
|
6200
6601
|
default:
|
|
6201
6602
|
throw new BoardError("VALIDATION", `unknown verb ${String(verb)}`);
|
|
6202
6603
|
}
|
|
@@ -6243,7 +6644,7 @@ ${rationale}`}`);
|
|
|
6243
6644
|
}
|
|
6244
6645
|
async readAgentRoleBody(agent2) {
|
|
6245
6646
|
const file = this.paths.agentRole(agent2);
|
|
6246
|
-
return await exists(file) ? (await readMarkdown(file,
|
|
6647
|
+
return await exists(file) ? (await readMarkdown(file, z16.record(z16.string(), z16.unknown()))).body : "";
|
|
6247
6648
|
}
|
|
6248
6649
|
/** The steps of one finished turn, as the runner handed them over when it ended. */
|
|
6249
6650
|
/**
|
|
@@ -6274,6 +6675,14 @@ ${rationale}`}`);
|
|
|
6274
6675
|
}
|
|
6275
6676
|
return computeMetrics({ events, tasks, citizens, actions, activeSignals, window, now });
|
|
6276
6677
|
}
|
|
6678
|
+
/**
|
|
6679
|
+
* Each citizen's finished turns over a window and the tokens of those that counted them, from
|
|
6680
|
+
* the event log alone, which holds every turn's end whatever runner it ran on.
|
|
6681
|
+
*/
|
|
6682
|
+
async tokenUse(window) {
|
|
6683
|
+
const events = await this.events.readSince(null, Number.MAX_SAFE_INTEGER);
|
|
6684
|
+
return tokenUse(events, window, this.now());
|
|
6685
|
+
}
|
|
6277
6686
|
/** The board actions a finished turn took, from its transcript; null when it kept none. */
|
|
6278
6687
|
async turnActions(agent2, turnId) {
|
|
6279
6688
|
const known = this.actionCounts.get(turnId);
|
|
@@ -6643,7 +7052,7 @@ ${rationale}`}`);
|
|
|
6643
7052
|
return { project: slug, revision: 0, body: "" };
|
|
6644
7053
|
}
|
|
6645
7054
|
const { data, body } = await readLooseMarkdown(file);
|
|
6646
|
-
const revision =
|
|
7055
|
+
const revision = z16.number().int().min(0).safeParse(data["revision"]);
|
|
6647
7056
|
const updatedBy = NameSchema.safeParse(data["updatedBy"]);
|
|
6648
7057
|
const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
|
|
6649
7058
|
return {
|
|
@@ -6917,7 +7326,7 @@ ${charter.purpose}
|
|
|
6917
7326
|
|
|
6918
7327
|
${charter.purpose}
|
|
6919
7328
|
|
|
6920
|
-
Route every lesson with one question: about me, my craft, or the user, it goes in memory/core.md; about this codebase, it goes in the project's knowledge
|
|
7329
|
+
Route every lesson with one question: about me, my craft, or the user, it goes in memory/core.md; about how this codebase behaves, it goes in the repo's AGENTS.md or README; about this project as a place (runners, access, flow, where results live), it goes in the project's knowledge; something everyone should know, post it.
|
|
6921
7330
|
` + (seed.length === 0 ? "" : `
|
|
6922
7331
|
${SEED_INSTRUCTIONS_HEADING}
|
|
6923
7332
|
|
|
@@ -6934,7 +7343,7 @@ ${seed}
|
|
|
6934
7343
|
continue;
|
|
6935
7344
|
}
|
|
6936
7345
|
const file = this.paths.agentRole(agent2.name);
|
|
6937
|
-
const body = await exists(file) ? (await readMarkdown(file,
|
|
7346
|
+
const body = await exists(file) ? (await readMarkdown(file, z16.record(z16.string(), z16.unknown()))).body : "";
|
|
6938
7347
|
const at = body.indexOf(`
|
|
6939
7348
|
${SEED_INSTRUCTIONS_HEADING}
|
|
6940
7349
|
`);
|
|
@@ -7772,7 +8181,7 @@ ${charter.purpose}
|
|
|
7772
8181
|
id: this.newId(),
|
|
7773
8182
|
...head,
|
|
7774
8183
|
ts: this.now().toISOString(),
|
|
7775
|
-
mentions:
|
|
8184
|
+
mentions: postMentions(body)
|
|
7776
8185
|
});
|
|
7777
8186
|
const { author } = head;
|
|
7778
8187
|
await writeMarkdown(this.paths.messageFile(dir, frontmatter.id, author), frontmatter, body);
|