@kubitnodes/stellaris 0.3.21 → 0.3.22
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/dist/cli/index.js +854 -588
- package/dist/server/index.js +1039 -651
- package/package.json +3 -1
- package/web/dist/assets/BackLink-CD-iuy-h.js +1 -0
- package/web/dist/assets/Button-Yoe21NQ2.js +1 -0
- package/web/dist/assets/ChannelForms-55otlg-m.js +1 -0
- package/web/dist/assets/ChannelView-DJvLzg0N.js +2 -0
- package/web/dist/assets/CitizenView-m1K2aTvK.js +2 -0
- package/web/dist/assets/CitizensView-BeTgmrKE.js +1 -0
- package/web/dist/assets/{CliIcon-BOSygXeI.js → CliIcon-DbMYJdlU.js} +1 -1
- package/web/dist/assets/CronsView-B4kXk5Ld.js +1 -0
- package/web/dist/assets/KnowledgeView-aSGxDDKy.js +1 -0
- package/web/dist/assets/Markdown-c9bCCLHg.js +30 -0
- package/web/dist/assets/{MessageItem-DI05jbrI.js → MessageItem-DKJKMqs-.js} +1 -1
- package/web/dist/assets/MetricsView-D2TTry5O.js +1 -0
- package/web/dist/assets/NeedsYouView-C3celRei.js +1 -0
- package/web/dist/assets/Overview-BveU1yJj.js +1 -0
- package/web/dist/assets/{Pane-BendOaje.js → Pane-CLjdfBMM.js} +1 -1
- package/web/dist/assets/{Picker-BuVnakvi.js → Picker-CXOe5Xdu.js} +1 -1
- package/web/dist/assets/ProjectView-oa4Z46ED.js +1 -0
- package/web/dist/assets/ProposalView-B4T-EoX9.js +2 -0
- package/web/dist/assets/ProposalsView-BZHivSEm.js +1 -0
- package/web/dist/assets/Quota-BC7dpnwd.js +1 -0
- package/web/dist/assets/RunnersView-BrJF-aLU.js +1 -0
- package/web/dist/assets/SocietyView-C1yosPuf.js +1 -0
- package/web/dist/assets/StickyList-7tAlUDCN.js +1 -0
- package/web/dist/assets/SubjectThread-CCq6ZAnR.js +1 -0
- package/web/dist/assets/TaskFileView-BEXQJQQ6.js +4 -0
- package/web/dist/assets/TaskView-Cfhb7NuO.js +3 -0
- package/web/dist/assets/TasksView-3XljXcoi.js +1 -0
- package/web/dist/assets/ThreadForms-D2y5dXSC.js +1 -0
- package/web/dist/assets/ThreadItem-DeIhhmyu.js +1 -0
- package/web/dist/assets/ThreadView-CbUnt9WL.js +1 -0
- package/web/dist/assets/citizen--bqux6i_.js +1 -0
- package/web/dist/assets/compose-DNc3_c5x.js +1 -0
- package/web/dist/assets/format-B6fjC0_a.js +55 -0
- package/web/dist/assets/governance-RBQ4Lam0.js +1 -0
- package/web/dist/assets/index-CyCty7a2.js +23 -0
- package/web/dist/assets/index-GRqxKN35.css +2 -0
- package/web/dist/assets/mentions-B2Qchd_6.js +3 -0
- package/web/dist/assets/{tasks-CyXIxoAy.js → tasks-DCUj5w_d.js} +1 -1
- package/web/dist/assets/useMatch-CfbBQirn.js +1 -0
- package/web/dist/index.html +9 -10
- package/web/dist/assets/BackLink-23Q1JvmZ.js +0 -1
- 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/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/server/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { serve } from "@hono/node-server";
|
|
|
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 z15 } from "zod";
|
|
13
13
|
|
|
14
14
|
// packages/shared/dist/ids.js
|
|
15
15
|
import { z } from "zod";
|
|
@@ -169,7 +169,7 @@ var SEED_ROLES = [
|
|
|
169
169
|
];
|
|
170
170
|
|
|
171
171
|
// packages/shared/dist/board.js
|
|
172
|
-
import { z as
|
|
172
|
+
import { z as z5 } from "zod";
|
|
173
173
|
|
|
174
174
|
// packages/shared/dist/crons.js
|
|
175
175
|
import { Cron as Pattern } from "croner";
|
|
@@ -303,6 +303,115 @@ function localTime(date, timeZone) {
|
|
|
303
303
|
return `${part("weekday")} ${part("year")}-${part("month")}-${part("day")} ${part("hour")}:${part("minute")}`;
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
// packages/shared/dist/quota.js
|
|
307
|
+
import { z as z4 } from "zod";
|
|
308
|
+
var QUOTA_WARNING_PERCENT = 80;
|
|
309
|
+
var QuotaWindowSchema = z4.object({
|
|
310
|
+
/**
|
|
311
|
+
* The CLI's own name for the window: Claude's `five_hour`, `seven_day`, `seven_day_opus`, and
|
|
312
|
+
* `model:<label>` for a model's weekly window; Codex's `primary` and `secondary`.
|
|
313
|
+
*/
|
|
314
|
+
key: z4.string().min(1).max(80),
|
|
315
|
+
/** What a scoped window counts, as the CLI labels it, such as a model's name. */
|
|
316
|
+
label: z4.string().min(1).max(80).optional(),
|
|
317
|
+
/** The window's length in minutes, when known. */
|
|
318
|
+
minutes: z4.number().int().positive().nullable().default(null),
|
|
319
|
+
/** How much of the window is used, in percent, or null when the CLI did not say. */
|
|
320
|
+
usedPercent: z4.number().nonnegative().nullable().default(null),
|
|
321
|
+
/** When the window starts afresh, when known. */
|
|
322
|
+
resetsAt: IsoDateTimeSchema.nullable().default(null),
|
|
323
|
+
/** When the CLI last reported this window. */
|
|
324
|
+
observedAt: IsoDateTimeSchema
|
|
325
|
+
});
|
|
326
|
+
var QuotaStatusSchema = z4.enum(["allowed", "warning", "limited", "none"]);
|
|
327
|
+
var QuotaCreditsSchema = z4.object({
|
|
328
|
+
hasCredits: z4.boolean(),
|
|
329
|
+
unlimited: z4.boolean(),
|
|
330
|
+
balance: z4.string().max(40).nullable()
|
|
331
|
+
});
|
|
332
|
+
var QuotaExtraUsageSchema = z4.object({
|
|
333
|
+
enabled: z4.boolean(),
|
|
334
|
+
monthlyLimit: z4.number().nonnegative().nullable(),
|
|
335
|
+
usedCredits: z4.number().nonnegative().nullable(),
|
|
336
|
+
currency: z4.string().min(1).max(8).nullable()
|
|
337
|
+
});
|
|
338
|
+
var CliQuotaSchema = z4.object({
|
|
339
|
+
/** When the CLI last reported anything here. */
|
|
340
|
+
observedAt: IsoDateTimeSchema,
|
|
341
|
+
/** Whether it came from a turn's stream or from asking the CLI. */
|
|
342
|
+
source: z4.enum(["turn", "read"]),
|
|
343
|
+
status: QuotaStatusSchema,
|
|
344
|
+
/** While `limited`: when work can go on, when known, and the window that stopped it. */
|
|
345
|
+
limitedUntil: IsoDateTimeSchema.nullable().default(null),
|
|
346
|
+
limitedBy: z4.string().min(1).max(80).nullable().default(null),
|
|
347
|
+
/** The plan's name as the CLI gives it, such as `max` or `pro`. */
|
|
348
|
+
plan: z4.string().min(1).max(40).nullable().default(null),
|
|
349
|
+
windows: z4.array(QuotaWindowSchema).max(24).default([]),
|
|
350
|
+
credits: QuotaCreditsSchema.nullable().default(null),
|
|
351
|
+
extraUsage: QuotaExtraUsageSchema.nullable().default(null)
|
|
352
|
+
});
|
|
353
|
+
function mergeQuota(previous, next) {
|
|
354
|
+
if (previous === void 0) {
|
|
355
|
+
return next;
|
|
356
|
+
}
|
|
357
|
+
const windows = new Map(previous.windows.map((window) => [window.key, window]));
|
|
358
|
+
for (const window of next.windows) {
|
|
359
|
+
windows.set(window.key, window);
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
...next,
|
|
363
|
+
plan: next.plan ?? previous.plan,
|
|
364
|
+
credits: next.credits ?? previous.credits,
|
|
365
|
+
extraUsage: next.extraUsage ?? previous.extraUsage,
|
|
366
|
+
windows: [...windows.values()]
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
function windowCurrent(window, now) {
|
|
370
|
+
return window.resetsAt === null || Date.parse(window.resetsAt) > now.getTime();
|
|
371
|
+
}
|
|
372
|
+
function quotaLevel(quota, now) {
|
|
373
|
+
if (quota.status === "none") {
|
|
374
|
+
return "none";
|
|
375
|
+
}
|
|
376
|
+
if (quota.status === "limited" && (quota.limitedUntil === null || Date.parse(quota.limitedUntil) > now.getTime())) {
|
|
377
|
+
return "limited";
|
|
378
|
+
}
|
|
379
|
+
const high = quota.windows.some((window) => windowCurrent(window, now) && window.usedPercent !== null && window.usedPercent >= QUOTA_WARNING_PERCENT);
|
|
380
|
+
return quota.status === "warning" || high ? "warning" : "ok";
|
|
381
|
+
}
|
|
382
|
+
var WINDOW_NAMES = {
|
|
383
|
+
five_hour: "5h",
|
|
384
|
+
seven_day: "7d",
|
|
385
|
+
seven_day_opus: "7d Opus",
|
|
386
|
+
seven_day_sonnet: "7d Sonnet",
|
|
387
|
+
seven_day_oauth_apps: "7d apps",
|
|
388
|
+
seven_day_overage_included: "7d extra",
|
|
389
|
+
overage: "extra usage"
|
|
390
|
+
};
|
|
391
|
+
function windowName(window) {
|
|
392
|
+
if (window.label !== void 0) {
|
|
393
|
+
return window.minutes === 10080 ? `7d ${window.label}` : window.label;
|
|
394
|
+
}
|
|
395
|
+
const named = WINDOW_NAMES[window.key];
|
|
396
|
+
if (named !== void 0) {
|
|
397
|
+
return named;
|
|
398
|
+
}
|
|
399
|
+
if (window.minutes !== null) {
|
|
400
|
+
return window.minutes % 1440 === 0 ? `${window.minutes / 1440}d` : window.minutes % 60 === 0 ? `${window.minutes / 60}h` : `${window.minutes}m`;
|
|
401
|
+
}
|
|
402
|
+
return window.key;
|
|
403
|
+
}
|
|
404
|
+
function readings(quota) {
|
|
405
|
+
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();
|
|
406
|
+
return windows.join(",");
|
|
407
|
+
}
|
|
408
|
+
function quotaChanged(previous, next) {
|
|
409
|
+
if (previous === void 0) {
|
|
410
|
+
return true;
|
|
411
|
+
}
|
|
412
|
+
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);
|
|
413
|
+
}
|
|
414
|
+
|
|
306
415
|
// packages/shared/dist/board.js
|
|
307
416
|
var ASK_CHANNEL = "asks";
|
|
308
417
|
var SOCIETY_CHANNELS = ["general", "governance", ASK_CHANNEL];
|
|
@@ -315,24 +424,24 @@ var SOCIETY_SCOPE = "society";
|
|
|
315
424
|
function wakeScope(member, project) {
|
|
316
425
|
return project !== null && member.memberships.includes(project) ? project : SOCIETY_SCOPE;
|
|
317
426
|
}
|
|
318
|
-
var CliKindSchema =
|
|
319
|
-
var ArchivedChannelSchema =
|
|
427
|
+
var CliKindSchema = z5.enum(["claude", "codex"]);
|
|
428
|
+
var ArchivedChannelSchema = z5.object({
|
|
320
429
|
name: NameSchema,
|
|
321
430
|
at: IsoDateTimeSchema,
|
|
322
431
|
by: NameSchema,
|
|
323
|
-
reason:
|
|
432
|
+
reason: z5.string().min(1)
|
|
324
433
|
});
|
|
325
|
-
var SocietySchema =
|
|
326
|
-
name:
|
|
327
|
-
version:
|
|
434
|
+
var SocietySchema = z5.object({
|
|
435
|
+
name: z5.string().min(1),
|
|
436
|
+
version: z5.literal(1),
|
|
328
437
|
createdAt: IsoDateTimeSchema,
|
|
329
438
|
/** The channels that take posts; an archived one moves to `archivedChannels`. */
|
|
330
|
-
channels:
|
|
331
|
-
archivedChannels:
|
|
439
|
+
channels: z5.array(NameSchema),
|
|
440
|
+
archivedChannels: z5.array(ArchivedChannelSchema).default([]),
|
|
332
441
|
/** The time zone crons are read in when they name none, and every prompt tells the time in; the user's to set. */
|
|
333
442
|
timezone: TimeZoneSchema.default(DEFAULT_TIME_ZONE)
|
|
334
443
|
});
|
|
335
|
-
var CompletionEffectSchema =
|
|
444
|
+
var CompletionEffectSchema = z5.enum(["none", "merge", "ghpr"]);
|
|
336
445
|
var GITHUB_REMOTE = [
|
|
337
446
|
/^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?\/?$/,
|
|
338
447
|
/^git@github\.com:([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?$/,
|
|
@@ -348,7 +457,7 @@ function githubRepository(remote) {
|
|
|
348
457
|
return null;
|
|
349
458
|
}
|
|
350
459
|
var PULL_REQUEST_URL = /^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)\/pull\/([1-9]\d*)\/?$/;
|
|
351
|
-
var PullRequestUrlSchema =
|
|
460
|
+
var PullRequestUrlSchema = z5.string().trim().regex(PULL_REQUEST_URL, "a pull request's address, https://github.com/<owner>/<repo>/pull/<number>");
|
|
352
461
|
function parsePullRequestUrl(url) {
|
|
353
462
|
const match = PULL_REQUEST_URL.exec(url.trim());
|
|
354
463
|
return match?.[1] === void 0 || match[2] === void 0 || match[3] === void 0 ? null : { owner: match[1], name: match[2], number: Number(match[3]) };
|
|
@@ -356,72 +465,72 @@ function parsePullRequestUrl(url) {
|
|
|
356
465
|
function sameRepository(a, b) {
|
|
357
466
|
return a.owner.toLowerCase() === b.owner.toLowerCase() && a.name.toLowerCase() === b.name.toLowerCase();
|
|
358
467
|
}
|
|
359
|
-
var MergeSubjectSchema =
|
|
360
|
-
var PullRequestLinkSchema =
|
|
468
|
+
var MergeSubjectSchema = z5.string().trim().min(1).max(300).regex(/^[^\n]+$/, "a merge commit's subject is one line");
|
|
469
|
+
var PullRequestLinkSchema = z5.object({
|
|
361
470
|
url: PullRequestUrlSchema,
|
|
362
|
-
number:
|
|
471
|
+
number: z5.number().int().positive(),
|
|
363
472
|
subject: MergeSubjectSchema.optional(),
|
|
364
|
-
body:
|
|
473
|
+
body: z5.string().max(2e4).optional(),
|
|
365
474
|
linkedBy: NameSchema,
|
|
366
475
|
linkedAt: IsoDateTimeSchema,
|
|
367
476
|
/**
|
|
368
477
|
* Once its `ghpr` task was abandoned, how the board's closing of it on GitHub went: `ok` false
|
|
369
478
|
* leaves it open, for the reason `detail` gives.
|
|
370
479
|
*/
|
|
371
|
-
closed:
|
|
480
|
+
closed: z5.object({ at: IsoDateTimeSchema, ok: z5.boolean(), detail: z5.string() }).optional()
|
|
372
481
|
});
|
|
373
|
-
var DefaultBranchSchema =
|
|
374
|
-
var StageIdSchema =
|
|
482
|
+
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");
|
|
483
|
+
var StageIdSchema = z5.string().regex(/^s[1-9][0-9]*$/, "expected a stage id such as s1");
|
|
375
484
|
var stageFields = {
|
|
376
|
-
name:
|
|
485
|
+
name: z5.string().trim().min(1).max(120),
|
|
377
486
|
role: NameSchema.optional(),
|
|
378
487
|
agent: NameSchema.optional(),
|
|
379
|
-
gate:
|
|
488
|
+
gate: z5.boolean().default(false)
|
|
380
489
|
};
|
|
381
490
|
function oneAssignee(stage) {
|
|
382
491
|
return stage.role === void 0 || stage.agent === void 0;
|
|
383
492
|
}
|
|
384
493
|
var ONE_ASSIGNEE = { message: "a stage names a role or an agent, not both" };
|
|
385
|
-
var PlanStageSchema =
|
|
386
|
-
var PlanEditStageSchema =
|
|
387
|
-
var PlanSchema =
|
|
388
|
-
var PlanEditSchema =
|
|
389
|
-
var ProjectSchema =
|
|
494
|
+
var PlanStageSchema = z5.object(stageFields).refine(oneAssignee, ONE_ASSIGNEE);
|
|
495
|
+
var PlanEditStageSchema = z5.object({ id: StageIdSchema.optional(), ...stageFields }).refine(oneAssignee, ONE_ASSIGNEE);
|
|
496
|
+
var PlanSchema = z5.array(PlanStageSchema);
|
|
497
|
+
var PlanEditSchema = z5.array(PlanEditStageSchema);
|
|
498
|
+
var ProjectSchema = z5.object({
|
|
390
499
|
slug: NameSchema,
|
|
391
|
-
name:
|
|
392
|
-
repo:
|
|
393
|
-
defaultBranch:
|
|
500
|
+
name: z5.string().min(1),
|
|
501
|
+
repo: z5.string().nullable(),
|
|
502
|
+
defaultBranch: z5.string().min(1),
|
|
394
503
|
/** The channels that take posts; an archived one moves to `archivedChannels`. */
|
|
395
|
-
channels:
|
|
396
|
-
archivedChannels:
|
|
397
|
-
members:
|
|
398
|
-
approvers:
|
|
399
|
-
requiredCapabilities:
|
|
504
|
+
channels: z5.array(NameSchema),
|
|
505
|
+
archivedChannels: z5.array(ArchivedChannelSchema).default([]),
|
|
506
|
+
members: z5.array(NameSchema),
|
|
507
|
+
approvers: z5.array(NameSchema),
|
|
508
|
+
requiredCapabilities: z5.array(z5.string()),
|
|
400
509
|
createdAt: IsoDateTimeSchema,
|
|
401
510
|
onDone: CompletionEffectSchema.default("none"),
|
|
402
511
|
/** The runner the project lives on, which holds its repository; set on the project's first turn. */
|
|
403
512
|
runner: NameSchema.optional(),
|
|
404
513
|
/** Set once the project is archived: nobody belongs to it, and nothing more is posted, filed, or joined there. */
|
|
405
|
-
archived:
|
|
514
|
+
archived: z5.object({ at: IsoDateTimeSchema, by: NameSchema, reason: z5.string().min(1) }).optional()
|
|
406
515
|
});
|
|
407
|
-
var TaskStepSchema =
|
|
408
|
-
action:
|
|
516
|
+
var TaskStepSchema = z5.object({
|
|
517
|
+
action: z5.enum(["advanced", "returned", "abandoned", "landed", "reopened"]),
|
|
409
518
|
stage: StageIdSchema,
|
|
410
519
|
to: StageIdSchema.nullable()
|
|
411
520
|
});
|
|
412
|
-
var ProposalStepSchema =
|
|
413
|
-
var MessageStepSchema =
|
|
521
|
+
var ProposalStepSchema = z5.object({ action: z5.enum(["approved", "rejected"]) });
|
|
522
|
+
var MessageStepSchema = z5.union([TaskStepSchema, ProposalStepSchema]);
|
|
414
523
|
function isTaskStep(step) {
|
|
415
524
|
return "stage" in step;
|
|
416
525
|
}
|
|
417
|
-
var KnowledgeNoticeSchema =
|
|
418
|
-
kind:
|
|
419
|
-
action:
|
|
526
|
+
var KnowledgeNoticeSchema = z5.object({
|
|
527
|
+
kind: z5.literal("knowledge"),
|
|
528
|
+
action: z5.enum(["written", "updated", "removed"]),
|
|
420
529
|
topic: NameSchema,
|
|
421
530
|
project: NameSchema.nullable()
|
|
422
531
|
});
|
|
423
|
-
var MessageNoticeSchema =
|
|
424
|
-
var MessageFrontmatterSchema =
|
|
532
|
+
var MessageNoticeSchema = z5.discriminatedUnion("kind", [KnowledgeNoticeSchema]);
|
|
533
|
+
var MessageFrontmatterSchema = z5.object({
|
|
425
534
|
id: UlidSchema,
|
|
426
535
|
author: NameSchema,
|
|
427
536
|
channel: ChannelRefSchema,
|
|
@@ -435,7 +544,7 @@ var MessageFrontmatterSchema = z4.object({
|
|
|
435
544
|
/** On a post a verb made about its work, such as a knowledge topic's note: what it records. */
|
|
436
545
|
notice: MessageNoticeSchema.optional(),
|
|
437
546
|
ts: IsoDateTimeSchema,
|
|
438
|
-
mentions:
|
|
547
|
+
mentions: z5.array(NameSchema)
|
|
439
548
|
});
|
|
440
549
|
var MessageRefSchema = MessageFrontmatterSchema.pick({
|
|
441
550
|
id: true,
|
|
@@ -445,16 +554,16 @@ var MessageRefSchema = MessageFrontmatterSchema.pick({
|
|
|
445
554
|
ts: true
|
|
446
555
|
});
|
|
447
556
|
var MESSAGE_LOOKUP_LIMIT = 50;
|
|
448
|
-
var TaskStatusSchema =
|
|
449
|
-
var ThreadStateSchema =
|
|
450
|
-
var ThreadSubjectSchema =
|
|
451
|
-
kind:
|
|
557
|
+
var TaskStatusSchema = z5.enum(["open", "claimed", "done", "abandoned"]);
|
|
558
|
+
var ThreadStateSchema = z5.enum(["open", "closed"]);
|
|
559
|
+
var ThreadSubjectSchema = z5.object({
|
|
560
|
+
kind: z5.enum(["task", "proposal"]),
|
|
452
561
|
id: UlidSchema
|
|
453
562
|
});
|
|
454
|
-
var ThreadFrontmatterSchema =
|
|
563
|
+
var ThreadFrontmatterSchema = z5.object({
|
|
455
564
|
id: UlidSchema,
|
|
456
565
|
channel: ChannelRefSchema,
|
|
457
|
-
title:
|
|
566
|
+
title: z5.string().min(1).max(200),
|
|
458
567
|
subject: ThreadSubjectSchema.optional(),
|
|
459
568
|
state: ThreadStateSchema,
|
|
460
569
|
openedBy: NameSchema,
|
|
@@ -462,28 +571,28 @@ var ThreadFrontmatterSchema = z4.object({
|
|
|
462
571
|
closedBy: NameSchema.optional(),
|
|
463
572
|
closedAt: IsoDateTimeSchema.optional()
|
|
464
573
|
});
|
|
465
|
-
var StageSchema =
|
|
574
|
+
var StageSchema = z5.object({
|
|
466
575
|
id: StageIdSchema,
|
|
467
|
-
name:
|
|
576
|
+
name: z5.string().min(1),
|
|
468
577
|
role: NameSchema.optional(),
|
|
469
578
|
agent: NameSchema.optional(),
|
|
470
|
-
gate:
|
|
579
|
+
gate: z5.boolean().default(false),
|
|
471
580
|
/** Everyone who has held the stage, oldest first. */
|
|
472
|
-
holders:
|
|
581
|
+
holders: z5.array(NameSchema).default([]),
|
|
473
582
|
completedBy: NameSchema.optional(),
|
|
474
583
|
completedAt: IsoDateTimeSchema.optional()
|
|
475
584
|
});
|
|
476
|
-
var TaskReturnSchema =
|
|
585
|
+
var TaskReturnSchema = z5.object({
|
|
477
586
|
from: StageIdSchema,
|
|
478
587
|
by: NameSchema,
|
|
479
588
|
at: IsoDateTimeSchema
|
|
480
589
|
});
|
|
481
|
-
var TaskFrontmatterSchema =
|
|
590
|
+
var TaskFrontmatterSchema = z5.object({
|
|
482
591
|
id: UlidSchema,
|
|
483
592
|
project: NameSchema,
|
|
484
593
|
/** The channel of the project the task is filed in, where its thread hangs. */
|
|
485
594
|
channel: NameSchema.default("general"),
|
|
486
|
-
title:
|
|
595
|
+
title: z5.string().min(1),
|
|
487
596
|
status: TaskStatusSchema,
|
|
488
597
|
createdBy: NameSchema,
|
|
489
598
|
createdAt: IsoDateTimeSchema,
|
|
@@ -492,19 +601,19 @@ var TaskFrontmatterSchema = z4.object({
|
|
|
492
601
|
claimedBy: NameSchema.optional(),
|
|
493
602
|
leaseExpiresAt: IsoDateTimeSchema.optional(),
|
|
494
603
|
parentId: UlidSchema.optional(),
|
|
495
|
-
blockedBy:
|
|
496
|
-
requiredCapabilities:
|
|
497
|
-
stages:
|
|
604
|
+
blockedBy: z5.array(UlidSchema),
|
|
605
|
+
requiredCapabilities: z5.array(z5.string()),
|
|
606
|
+
stages: z5.array(StageSchema).min(1),
|
|
498
607
|
stage: StageIdSchema,
|
|
499
608
|
/** When the current stage last became current or lost its holder: the waiting clock. */
|
|
500
609
|
stageSince: IsoDateTimeSchema,
|
|
501
610
|
/** The highest stage number issued, so a removed stage's id is never reused. */
|
|
502
|
-
stageSeq:
|
|
611
|
+
stageSeq: z5.number().int().positive(),
|
|
503
612
|
onDone: CompletionEffectSchema.default("none"),
|
|
504
613
|
/** The pull request a `ghpr` task lands through. */
|
|
505
614
|
pullRequest: PullRequestLinkSchema.optional(),
|
|
506
615
|
/** The last stage is complete and the completion effect is running. */
|
|
507
|
-
completing:
|
|
616
|
+
completing: z5.boolean().default(false),
|
|
508
617
|
/** The latest send-back while its rework lasts: cleared once the task reaches that stage again. */
|
|
509
618
|
returned: TaskReturnSchema.optional()
|
|
510
619
|
});
|
|
@@ -528,79 +637,90 @@ function mayHoldStage(member, task) {
|
|
|
528
637
|
}
|
|
529
638
|
return !(stage.gate && task.stages.slice(0, index).some((s) => s.holders.includes(member.name)));
|
|
530
639
|
}
|
|
531
|
-
var ModelNameSchema =
|
|
532
|
-
var EffortSchema =
|
|
533
|
-
var EffortOptionSchema =
|
|
640
|
+
var ModelNameSchema = z5.string().trim().min(1).max(120).regex(/^[\w.:/[\]-]+$/, "a model name is one word of letters, digits, and . _ : / - [ ]");
|
|
641
|
+
var EffortSchema = z5.string().trim().min(1).max(32).regex(/^[a-z][a-z0-9_-]*$/, "an effort is one lowercase word, such as high");
|
|
642
|
+
var EffortOptionSchema = z5.object({
|
|
534
643
|
id: EffortSchema,
|
|
535
|
-
description:
|
|
644
|
+
description: z5.string().default("")
|
|
536
645
|
});
|
|
537
|
-
var ModelOptionSchema =
|
|
646
|
+
var ModelOptionSchema = z5.object({
|
|
538
647
|
id: ModelNameSchema,
|
|
539
|
-
name:
|
|
540
|
-
description:
|
|
541
|
-
isDefault:
|
|
542
|
-
efforts:
|
|
648
|
+
name: z5.string(),
|
|
649
|
+
description: z5.string().default(""),
|
|
650
|
+
isDefault: z5.boolean().default(false),
|
|
651
|
+
efforts: z5.array(EffortOptionSchema).default([]),
|
|
543
652
|
defaultEffort: EffortSchema.optional()
|
|
544
653
|
});
|
|
545
|
-
var RunnerModelsSchema =
|
|
654
|
+
var RunnerModelsSchema = z5.object({
|
|
546
655
|
runner: NameSchema,
|
|
547
656
|
cli: CliKindSchema,
|
|
548
|
-
models:
|
|
657
|
+
models: z5.array(ModelOptionSchema)
|
|
549
658
|
});
|
|
550
|
-
var AgentStatusSchema =
|
|
551
|
-
var AgentSchema =
|
|
659
|
+
var AgentStatusSchema = z5.enum(["active", "retired"]);
|
|
660
|
+
var AgentSchema = z5.object({
|
|
552
661
|
name: NameSchema,
|
|
553
662
|
role: NameSchema,
|
|
554
663
|
cli: CliKindSchema.nullable(),
|
|
555
|
-
model:
|
|
664
|
+
model: z5.string().optional(),
|
|
556
665
|
/** The reasoning effort set for the agent's turns; the model's own default applies otherwise. */
|
|
557
|
-
effort:
|
|
666
|
+
effort: z5.string().optional(),
|
|
558
667
|
/** The runner preferred for the agent's turns where nothing else decides; any runner with its CLI otherwise. */
|
|
559
668
|
homeRunner: NameSchema.optional(),
|
|
560
|
-
memberships:
|
|
561
|
-
subscriptions:
|
|
669
|
+
memberships: z5.array(NameSchema),
|
|
670
|
+
subscriptions: z5.array(ChannelRefSchema),
|
|
562
671
|
status: AgentStatusSchema,
|
|
563
672
|
createdAt: IsoDateTimeSchema,
|
|
564
|
-
tokenHash:
|
|
673
|
+
tokenHash: z5.string().min(1),
|
|
565
674
|
retiredAt: IsoDateTimeSchema.optional(),
|
|
566
|
-
retiredReason:
|
|
675
|
+
retiredReason: z5.string().optional()
|
|
567
676
|
});
|
|
568
|
-
var MemberSchema =
|
|
677
|
+
var MemberSchema = z5.object({
|
|
569
678
|
name: NameSchema,
|
|
570
679
|
role: NameSchema,
|
|
571
680
|
cli: CliKindSchema.nullable(),
|
|
572
681
|
homeRunner: NameSchema.optional(),
|
|
573
682
|
status: AgentStatusSchema,
|
|
574
|
-
resident:
|
|
683
|
+
resident: z5.boolean().default(false),
|
|
575
684
|
/** The model configured on the record, if any; the CLI's own default applies otherwise. */
|
|
576
|
-
model:
|
|
685
|
+
model: z5.string().optional(),
|
|
577
686
|
/** The model the CLI reported on the citizen's last turn. */
|
|
578
|
-
lastModel:
|
|
687
|
+
lastModel: z5.string().optional(),
|
|
579
688
|
/** The reasoning effort configured on the record, if any; the model's own default applies otherwise. */
|
|
580
|
-
effort:
|
|
689
|
+
effort: z5.string().optional(),
|
|
581
690
|
/** The citizen's own skills, by name. */
|
|
582
|
-
skills:
|
|
583
|
-
memberships:
|
|
584
|
-
subscriptions:
|
|
585
|
-
claimsHeld:
|
|
586
|
-
tasksDone:
|
|
691
|
+
skills: z5.array(NameSchema).default([]),
|
|
692
|
+
memberships: z5.array(NameSchema),
|
|
693
|
+
subscriptions: z5.array(ChannelRefSchema),
|
|
694
|
+
claimsHeld: z5.number().int().nonnegative().default(0),
|
|
695
|
+
tasksDone: z5.number().int().nonnegative().default(0),
|
|
587
696
|
lastTurnAt: IsoDateTimeSchema.optional(),
|
|
588
|
-
lastTurnOutcome:
|
|
697
|
+
lastTurnOutcome: z5.string().optional(),
|
|
589
698
|
createdAt: IsoDateTimeSchema,
|
|
590
699
|
retiredAt: IsoDateTimeSchema.optional()
|
|
591
700
|
});
|
|
592
|
-
var RunnerOsSchema =
|
|
593
|
-
var
|
|
701
|
+
var RunnerOsSchema = z5.enum(["linux", "windows", "darwin"]);
|
|
702
|
+
var GitIdentityPartSchema = z5.enum(["name", "email"]);
|
|
703
|
+
var RunnerSchema = z5.object({
|
|
594
704
|
name: NameSchema,
|
|
595
705
|
os: RunnerOsSchema,
|
|
596
|
-
clis:
|
|
597
|
-
capabilities:
|
|
706
|
+
clis: z5.array(CliKindSchema),
|
|
707
|
+
capabilities: z5.array(z5.string()),
|
|
598
708
|
/** The release the runner reported when it last registered; absent until it has. */
|
|
599
|
-
version:
|
|
600
|
-
|
|
601
|
-
|
|
709
|
+
version: z5.string().optional(),
|
|
710
|
+
/**
|
|
711
|
+
* What the runner's account lacked of a git identity when it last registered, empty when it had
|
|
712
|
+
* both; absent while the runner has not said, as one from before runners checked never does.
|
|
713
|
+
*/
|
|
714
|
+
gitIdentityMissing: z5.array(GitIdentityPartSchema).optional(),
|
|
715
|
+
status: z5.enum(["connected", "disconnected"]),
|
|
716
|
+
lastSeen: IsoDateTimeSchema.optional(),
|
|
717
|
+
/**
|
|
718
|
+
* Each CLI's plan quota as its login on this runner last reported it, from a turn's stream or a
|
|
719
|
+
* read; absent until one has.
|
|
720
|
+
*/
|
|
721
|
+
quotas: z5.partialRecord(CliKindSchema, CliQuotaSchema).optional()
|
|
602
722
|
});
|
|
603
|
-
var ProposalKindSchema =
|
|
723
|
+
var ProposalKindSchema = z5.enum([
|
|
604
724
|
"role",
|
|
605
725
|
"member",
|
|
606
726
|
"channel",
|
|
@@ -609,42 +729,42 @@ var ProposalKindSchema = z4.enum([
|
|
|
609
729
|
"skill",
|
|
610
730
|
"archive"
|
|
611
731
|
]);
|
|
612
|
-
var ProposalStatusSchema =
|
|
732
|
+
var ProposalStatusSchema = z5.enum([
|
|
613
733
|
"proposed",
|
|
614
734
|
"approved",
|
|
615
735
|
"rejected",
|
|
616
736
|
"provisioned",
|
|
617
737
|
"retired"
|
|
618
738
|
]);
|
|
619
|
-
var MemberProposalSchema =
|
|
739
|
+
var MemberProposalSchema = z5.object({
|
|
620
740
|
name: NameSchema,
|
|
621
741
|
role: NameSchema,
|
|
622
742
|
cli: CliKindSchema,
|
|
623
|
-
model:
|
|
743
|
+
model: z5.string().optional(),
|
|
624
744
|
homeRunner: NameSchema.optional(),
|
|
625
|
-
memberships:
|
|
626
|
-
subscriptions:
|
|
627
|
-
seedInstructions:
|
|
745
|
+
memberships: z5.array(NameSchema).default([]),
|
|
746
|
+
subscriptions: z5.array(ChannelRefSchema).default([]),
|
|
747
|
+
seedInstructions: z5.string().optional()
|
|
628
748
|
});
|
|
629
|
-
var ChannelProposalSchema =
|
|
749
|
+
var ChannelProposalSchema = z5.object({
|
|
630
750
|
project: NameSchema.nullable().default(null),
|
|
631
751
|
name: NameSchema,
|
|
632
|
-
purpose:
|
|
752
|
+
purpose: z5.string().min(1)
|
|
633
753
|
});
|
|
634
|
-
var RoleChangesSchema =
|
|
635
|
-
maxReplicas:
|
|
636
|
-
backlogThreshold:
|
|
637
|
-
wakeTriggers:
|
|
638
|
-
verbs:
|
|
754
|
+
var RoleChangesSchema = z5.strictObject({
|
|
755
|
+
maxReplicas: z5.number().int().min(1).optional(),
|
|
756
|
+
backlogThreshold: z5.number().positive().optional(),
|
|
757
|
+
wakeTriggers: z5.array(CharterTriggerSchema).optional(),
|
|
758
|
+
verbs: z5.array(VerbNameSchema).optional()
|
|
639
759
|
}).refine((changes) => Object.values(changes).some((value) => value !== void 0), {
|
|
640
760
|
message: "a reallocation changes at least one of maxReplicas, backlogThreshold, wakeTriggers, verbs"
|
|
641
761
|
});
|
|
642
|
-
var ReallocationProposalSchema =
|
|
762
|
+
var ReallocationProposalSchema = z5.object({
|
|
643
763
|
role: NameSchema,
|
|
644
764
|
changes: RoleChangesSchema,
|
|
645
|
-
description:
|
|
765
|
+
description: z5.string().min(1)
|
|
646
766
|
});
|
|
647
|
-
var LegacyReallocationSchema =
|
|
767
|
+
var LegacyReallocationSchema = z5.object({ description: z5.string().min(1) });
|
|
648
768
|
function applyRoleChanges(role, changes) {
|
|
649
769
|
return {
|
|
650
770
|
...role,
|
|
@@ -679,18 +799,18 @@ function roleChangeLines(role, changes) {
|
|
|
679
799
|
}
|
|
680
800
|
return lines;
|
|
681
801
|
}
|
|
682
|
-
var RetirementProposalSchema =
|
|
802
|
+
var RetirementProposalSchema = z5.object({
|
|
683
803
|
agent: NameSchema,
|
|
684
|
-
reason:
|
|
804
|
+
reason: z5.string().min(1)
|
|
685
805
|
});
|
|
686
|
-
var ArchiveProposalSchema =
|
|
806
|
+
var ArchiveProposalSchema = z5.object({
|
|
687
807
|
project: NameSchema,
|
|
688
|
-
reason:
|
|
808
|
+
reason: z5.string().min(1)
|
|
689
809
|
});
|
|
690
|
-
var SkillProposalSchema =
|
|
810
|
+
var SkillProposalSchema = z5.object({
|
|
691
811
|
name: NameSchema,
|
|
692
|
-
summary:
|
|
693
|
-
body:
|
|
812
|
+
summary: z5.string().min(1).max(200),
|
|
813
|
+
body: z5.string().min(1).optional()
|
|
694
814
|
});
|
|
695
815
|
var ProposalCharterSchemas = {
|
|
696
816
|
role: RoleCharterSchema,
|
|
@@ -793,23 +913,23 @@ function describeCharter(kind, charter) {
|
|
|
793
913
|
}
|
|
794
914
|
return `${kind} ${JSON.stringify(charter)}`;
|
|
795
915
|
}
|
|
796
|
-
var SkillSchema =
|
|
916
|
+
var SkillSchema = z5.object({
|
|
797
917
|
name: NameSchema,
|
|
798
|
-
summary:
|
|
799
|
-
scope:
|
|
800
|
-
path:
|
|
918
|
+
summary: z5.string().default(""),
|
|
919
|
+
scope: z5.enum(["own", "society"]),
|
|
920
|
+
path: z5.string().min(1)
|
|
801
921
|
});
|
|
802
|
-
var RemovedSkillSchema =
|
|
922
|
+
var RemovedSkillSchema = z5.object({
|
|
803
923
|
name: NameSchema,
|
|
804
|
-
reason:
|
|
924
|
+
reason: z5.string().min(1),
|
|
805
925
|
removedBy: NameSchema,
|
|
806
926
|
removedAt: IsoDateTimeSchema
|
|
807
927
|
});
|
|
808
|
-
var HomeConflictSchema =
|
|
928
|
+
var HomeConflictSchema = z5.object({
|
|
809
929
|
/** The copy, relative to the home. */
|
|
810
|
-
path:
|
|
930
|
+
path: z5.string().min(1),
|
|
811
931
|
/** The file beside it, whose version the board kept. */
|
|
812
|
-
file:
|
|
932
|
+
file: z5.string().min(1),
|
|
813
933
|
/** When the copy reached the board. */
|
|
814
934
|
since: IsoDateTimeSchema
|
|
815
935
|
});
|
|
@@ -817,79 +937,79 @@ var CONFLICT_COPY = /^(.+)\.conflict-[^/.]+$/;
|
|
|
817
937
|
function conflictCopyOf(copy) {
|
|
818
938
|
return CONFLICT_COPY.exec(copy)?.[1] ?? null;
|
|
819
939
|
}
|
|
820
|
-
var CommitIdSchema =
|
|
821
|
-
var HomeFileChangeSchema =
|
|
822
|
-
path:
|
|
823
|
-
status:
|
|
940
|
+
var CommitIdSchema = z5.string().regex(/^[0-9a-f]{40}([0-9a-f]{24})?$/);
|
|
941
|
+
var HomeFileChangeSchema = z5.object({
|
|
942
|
+
path: z5.string().min(1),
|
|
943
|
+
status: z5.enum(["added", "modified", "deleted"]),
|
|
824
944
|
/** Lines added and removed, or null for a binary file. */
|
|
825
|
-
added:
|
|
826
|
-
removed:
|
|
945
|
+
added: z5.number().int().nonnegative().nullable(),
|
|
946
|
+
removed: z5.number().int().nonnegative().nullable()
|
|
827
947
|
});
|
|
828
|
-
var HomeChangeSchema =
|
|
948
|
+
var HomeChangeSchema = z5.object({
|
|
829
949
|
commit: CommitIdSchema,
|
|
830
950
|
at: IsoDateTimeSchema,
|
|
831
|
-
kind:
|
|
832
|
-
author:
|
|
951
|
+
kind: z5.enum(["turn", "board", "merge"]),
|
|
952
|
+
author: z5.string(),
|
|
833
953
|
/** The turn that made it, from the runner's commit message. */
|
|
834
954
|
turnId: UlidSchema.optional(),
|
|
835
|
-
subject:
|
|
836
|
-
files:
|
|
955
|
+
subject: z5.string(),
|
|
956
|
+
files: z5.array(HomeFileChangeSchema)
|
|
837
957
|
});
|
|
838
|
-
var HomeHistorySchema =
|
|
839
|
-
changes:
|
|
958
|
+
var HomeHistorySchema = z5.object({
|
|
959
|
+
changes: z5.array(HomeChangeSchema),
|
|
840
960
|
/** Whether older commits remain past the ones read. */
|
|
841
|
-
more:
|
|
961
|
+
more: z5.boolean()
|
|
842
962
|
});
|
|
843
963
|
var HomeFileDiffSchema = HomeFileChangeSchema.pick({ path: true, status: true }).extend({
|
|
844
|
-
patch:
|
|
964
|
+
patch: z5.string().nullable(),
|
|
845
965
|
/** The patch was cut at its size limit. */
|
|
846
|
-
truncated:
|
|
966
|
+
truncated: z5.boolean()
|
|
847
967
|
});
|
|
848
|
-
var KnowledgeSchema =
|
|
968
|
+
var KnowledgeSchema = z5.object({
|
|
849
969
|
topic: NameSchema,
|
|
850
970
|
project: NameSchema.nullable(),
|
|
851
|
-
revision:
|
|
971
|
+
revision: z5.number().int().min(0),
|
|
852
972
|
updatedBy: NameSchema,
|
|
853
973
|
updatedAt: IsoDateTimeSchema
|
|
854
974
|
});
|
|
855
|
-
var RemovedKnowledgeSchema =
|
|
975
|
+
var RemovedKnowledgeSchema = z5.object({
|
|
856
976
|
topic: NameSchema,
|
|
857
977
|
project: NameSchema.nullable(),
|
|
858
978
|
removedBy: NameSchema,
|
|
859
979
|
removedAt: IsoDateTimeSchema
|
|
860
980
|
});
|
|
861
|
-
var DashboardSchema =
|
|
981
|
+
var DashboardSchema = z5.object({
|
|
862
982
|
project: NameSchema,
|
|
863
|
-
revision:
|
|
983
|
+
revision: z5.number().int().min(0),
|
|
864
984
|
/** Absent until someone updates the dashboard the project began with. */
|
|
865
985
|
updatedBy: NameSchema.optional(),
|
|
866
986
|
updatedAt: IsoDateTimeSchema.optional(),
|
|
867
|
-
body:
|
|
987
|
+
body: z5.string()
|
|
868
988
|
});
|
|
869
|
-
var ProposalOriginSchema =
|
|
989
|
+
var ProposalOriginSchema = z5.object({
|
|
870
990
|
scope: NameSchema,
|
|
871
991
|
thread: UlidSchema.optional(),
|
|
872
992
|
channel: NameSchema.optional()
|
|
873
993
|
});
|
|
874
994
|
var SKILL_FILES_LIMIT = 100;
|
|
875
995
|
var SKILL_BYTES_LIMIT = 10 * 1024 * 1024;
|
|
876
|
-
var SkillFileSchema =
|
|
877
|
-
path:
|
|
878
|
-
size:
|
|
879
|
-
executable:
|
|
996
|
+
var SkillFileSchema = z5.object({
|
|
997
|
+
path: z5.string().min(1),
|
|
998
|
+
size: z5.number().int().nonnegative(),
|
|
999
|
+
executable: z5.boolean()
|
|
880
1000
|
});
|
|
881
|
-
var SkillFilesSchema =
|
|
1001
|
+
var SkillFilesSchema = z5.object({
|
|
882
1002
|
/** The commit of the proposer's home the files came from. */
|
|
883
1003
|
commit: CommitIdSchema,
|
|
884
1004
|
takenAt: IsoDateTimeSchema,
|
|
885
|
-
files:
|
|
1005
|
+
files: z5.array(SkillFileSchema)
|
|
886
1006
|
});
|
|
887
1007
|
var SkillFileContentSchema = SkillFileSchema.extend({
|
|
888
|
-
text:
|
|
1008
|
+
text: z5.string().nullable(),
|
|
889
1009
|
/** The text was cut at its size limit. */
|
|
890
|
-
truncated:
|
|
1010
|
+
truncated: z5.boolean()
|
|
891
1011
|
});
|
|
892
|
-
var ProposalFrontmatterSchema =
|
|
1012
|
+
var ProposalFrontmatterSchema = z5.object({
|
|
893
1013
|
id: UlidSchema,
|
|
894
1014
|
kind: ProposalKindSchema,
|
|
895
1015
|
proposedBy: NameSchema,
|
|
@@ -901,146 +1021,146 @@ var ProposalFrontmatterSchema = z4.object({
|
|
|
901
1021
|
skillFiles: SkillFilesSchema.optional(),
|
|
902
1022
|
decidedBy: NameSchema.optional(),
|
|
903
1023
|
decidedAt: IsoDateTimeSchema.optional(),
|
|
904
|
-
reason:
|
|
905
|
-
charter:
|
|
1024
|
+
reason: z5.string().optional(),
|
|
1025
|
+
charter: z5.record(z5.string(), z5.unknown()),
|
|
906
1026
|
/** What approval created, for kinds the board provisions: the agent, channel, role, or retirement. */
|
|
907
1027
|
provisionedAt: IsoDateTimeSchema.optional(),
|
|
908
|
-
provision:
|
|
1028
|
+
provision: z5.record(z5.string(), z5.unknown()).optional()
|
|
909
1029
|
});
|
|
910
|
-
var DecisionSchema =
|
|
1030
|
+
var DecisionSchema = z5.object({
|
|
911
1031
|
id: UlidSchema,
|
|
912
1032
|
proposalId: UlidSchema,
|
|
913
1033
|
decidedBy: NameSchema,
|
|
914
|
-
outcome:
|
|
915
|
-
reason:
|
|
1034
|
+
outcome: z5.enum(["approved", "rejected"]),
|
|
1035
|
+
reason: z5.string().optional(),
|
|
916
1036
|
ts: IsoDateTimeSchema
|
|
917
1037
|
});
|
|
918
1038
|
|
|
919
1039
|
// packages/shared/dist/verbs.js
|
|
920
|
-
import { z as
|
|
921
|
-
var MomentSchema =
|
|
922
|
-
var CronTitleSchema =
|
|
923
|
-
var CronNoteSchema =
|
|
1040
|
+
import { z as z6 } from "zod";
|
|
1041
|
+
var MomentSchema = z6.iso.datetime({ offset: true });
|
|
1042
|
+
var CronTitleSchema = z6.string().trim().min(1).max(120);
|
|
1043
|
+
var CronNoteSchema = z6.string().trim().min(1).max(4e3);
|
|
924
1044
|
var VerbInputs = {
|
|
925
|
-
post_message:
|
|
1045
|
+
post_message: z6.object({
|
|
926
1046
|
/** Required outside a thread; in one it may be left out, and must otherwise be the thread's. */
|
|
927
1047
|
channel: ChannelRefSchema.optional(),
|
|
928
|
-
body:
|
|
1048
|
+
body: z6.string().min(1),
|
|
929
1049
|
thread_id: UlidSchema.optional()
|
|
930
1050
|
}),
|
|
931
|
-
read_inbox:
|
|
1051
|
+
read_inbox: z6.object({
|
|
932
1052
|
since_cursor: UlidSchema.nullable().optional(),
|
|
933
|
-
limit:
|
|
934
|
-
advance:
|
|
1053
|
+
limit: z6.number().int().positive().max(200).default(50),
|
|
1054
|
+
advance: z6.boolean().default(true)
|
|
935
1055
|
}),
|
|
936
|
-
search:
|
|
937
|
-
query:
|
|
1056
|
+
search: z6.object({
|
|
1057
|
+
query: z6.string().min(1),
|
|
938
1058
|
project: NameSchema.optional(),
|
|
939
1059
|
channel: ChannelRefSchema.optional(),
|
|
940
|
-
limit:
|
|
1060
|
+
limit: z6.number().int().positive().max(100).default(20)
|
|
941
1061
|
}),
|
|
942
1062
|
/** On a task or a proposal, whose id the thread takes, or on a channel with a title. */
|
|
943
|
-
open_thread:
|
|
1063
|
+
open_thread: z6.object({
|
|
944
1064
|
task_id: UlidSchema.optional(),
|
|
945
1065
|
proposal_id: UlidSchema.optional(),
|
|
946
1066
|
channel: ChannelRefSchema.optional(),
|
|
947
|
-
title:
|
|
1067
|
+
title: z6.string().min(1).max(200).optional()
|
|
948
1068
|
}),
|
|
949
|
-
close_thread:
|
|
950
|
-
create_task:
|
|
1069
|
+
close_thread: z6.object({ thread_id: UlidSchema, summary: z6.string().min(1) }),
|
|
1070
|
+
create_task: z6.object({
|
|
951
1071
|
project: NameSchema,
|
|
952
|
-
title:
|
|
953
|
-
body:
|
|
1072
|
+
title: z6.string().min(1).max(200),
|
|
1073
|
+
body: z6.string().default(""),
|
|
954
1074
|
parent_id: UlidSchema.optional(),
|
|
955
|
-
required_capabilities:
|
|
1075
|
+
required_capabilities: z6.array(z6.string()).default([]),
|
|
956
1076
|
/** The plan; without it the task gets one stage, work, that anyone in the project may take. */
|
|
957
|
-
stages:
|
|
1077
|
+
stages: z6.array(PlanStageSchema).min(1).optional(),
|
|
958
1078
|
/** A channel of the project the task belongs to, such as a release's; its thread opens there. */
|
|
959
1079
|
channel: NameSchema.default("general")
|
|
960
1080
|
}),
|
|
961
|
-
claim_task:
|
|
962
|
-
release_task:
|
|
963
|
-
update_task:
|
|
1081
|
+
claim_task: z6.object({ task_id: UlidSchema }),
|
|
1082
|
+
release_task: z6.object({ task_id: UlidSchema }),
|
|
1083
|
+
update_task: z6.object({
|
|
964
1084
|
task_id: UlidSchema,
|
|
965
1085
|
/** Move the task back to this earlier stage. */
|
|
966
1086
|
stage: StageIdSchema.optional(),
|
|
967
|
-
status:
|
|
1087
|
+
status: z6.enum(["abandoned"]).optional(),
|
|
968
1088
|
/** Posted to the task's thread as the caller, marked with the step when the task moved. */
|
|
969
|
-
note:
|
|
970
|
-
blocked_by:
|
|
1089
|
+
note: z6.string().min(1).optional(),
|
|
1090
|
+
blocked_by: z6.array(UlidSchema).optional(),
|
|
971
1091
|
/**
|
|
972
1092
|
* The pull request a `ghpr` task lands through, on its project's repository, with the merge
|
|
973
1093
|
* commit's subject and body; null unlinks it.
|
|
974
1094
|
*/
|
|
975
|
-
pull_request:
|
|
1095
|
+
pull_request: z6.object({
|
|
976
1096
|
url: PullRequestUrlSchema,
|
|
977
1097
|
merge_subject: MergeSubjectSchema.optional(),
|
|
978
|
-
merge_body:
|
|
1098
|
+
merge_body: z6.string().max(2e4).optional()
|
|
979
1099
|
}).nullable().optional()
|
|
980
1100
|
}),
|
|
981
|
-
get_task:
|
|
982
|
-
subscribe:
|
|
983
|
-
unsubscribe:
|
|
984
|
-
propose:
|
|
1101
|
+
get_task: z6.object({ task_id: UlidSchema }),
|
|
1102
|
+
subscribe: z6.object({ channel: ChannelRefSchema }),
|
|
1103
|
+
unsubscribe: z6.object({ channel: ChannelRefSchema }),
|
|
1104
|
+
propose: z6.object({
|
|
985
1105
|
kind: ProposalKindSchema,
|
|
986
|
-
charter:
|
|
987
|
-
rationale:
|
|
1106
|
+
charter: z6.record(z6.string(), z6.unknown()),
|
|
1107
|
+
rationale: z6.string().default("")
|
|
988
1108
|
}),
|
|
989
|
-
approve:
|
|
990
|
-
reject:
|
|
991
|
-
create_project:
|
|
1109
|
+
approve: z6.object({ proposal_id: UlidSchema, reason: z6.string().optional() }),
|
|
1110
|
+
reject: z6.object({ proposal_id: UlidSchema, reason: z6.string().min(1) }),
|
|
1111
|
+
create_project: z6.object({
|
|
992
1112
|
slug: NameSchema,
|
|
993
|
-
name:
|
|
994
|
-
repo:
|
|
1113
|
+
name: z6.string().min(1).optional(),
|
|
1114
|
+
repo: z6.string().min(1).nullable().default(null),
|
|
995
1115
|
default_branch: DefaultBranchSchema.default("main"),
|
|
996
1116
|
on_done: CompletionEffectSchema.optional()
|
|
997
1117
|
}),
|
|
998
|
-
join_project:
|
|
999
|
-
leave_project:
|
|
1000
|
-
write_knowledge:
|
|
1118
|
+
join_project: z6.object({ project: NameSchema, agent: NameSchema.optional() }),
|
|
1119
|
+
leave_project: z6.object({ project: NameSchema, agent: NameSchema.optional() }),
|
|
1120
|
+
write_knowledge: z6.object({
|
|
1001
1121
|
/** A project you belong to, or null for society knowledge, which the steward and the user curate. */
|
|
1002
1122
|
project: NameSchema.nullable().default(null),
|
|
1003
1123
|
topic: NameSchema,
|
|
1004
|
-
body:
|
|
1124
|
+
body: z6.string().min(1),
|
|
1005
1125
|
/** The `revision` in the frontmatter of the topic you read, 0 when it names none or for a new topic. */
|
|
1006
|
-
revision:
|
|
1126
|
+
revision: z6.number().int().min(0)
|
|
1007
1127
|
}),
|
|
1008
|
-
remove_knowledge:
|
|
1128
|
+
remove_knowledge: z6.object({
|
|
1009
1129
|
/** As for write_knowledge: a project you belong to, or null for society knowledge. */
|
|
1010
1130
|
project: NameSchema.nullable().default(null),
|
|
1011
1131
|
topic: NameSchema
|
|
1012
1132
|
}),
|
|
1013
|
-
plan_task:
|
|
1133
|
+
plan_task: z6.object({
|
|
1014
1134
|
task_id: UlidSchema,
|
|
1015
|
-
stages:
|
|
1135
|
+
stages: z6.array(PlanEditStageSchema),
|
|
1016
1136
|
on_done: CompletionEffectSchema.optional()
|
|
1017
1137
|
}),
|
|
1018
1138
|
/** The note is posted to the task's thread as the caller, marked with the step. */
|
|
1019
|
-
advance_task:
|
|
1020
|
-
configure_project:
|
|
1139
|
+
advance_task: z6.object({ task_id: UlidSchema, note: z6.string().min(1).optional() }),
|
|
1140
|
+
configure_project: z6.object({
|
|
1021
1141
|
project: NameSchema,
|
|
1022
1142
|
on_done: CompletionEffectSchema.optional(),
|
|
1023
1143
|
/** A new display name; the slug, which everything refers to the project by, never changes. */
|
|
1024
|
-
name:
|
|
1144
|
+
name: z6.string().trim().min(1).max(120).optional(),
|
|
1025
1145
|
/** The branch tasks start from and land on from now; tasks in play keep their branches. */
|
|
1026
1146
|
default_branch: DefaultBranchSchema.optional()
|
|
1027
1147
|
}),
|
|
1028
|
-
archive_project:
|
|
1029
|
-
create_channel:
|
|
1148
|
+
archive_project: z6.object({ project: NameSchema, reason: z6.string().min(1) }),
|
|
1149
|
+
create_channel: z6.object({
|
|
1030
1150
|
/** A project, or null for a channel of the society. */
|
|
1031
1151
|
project: NameSchema.nullable().default(null),
|
|
1032
1152
|
name: NameSchema,
|
|
1033
|
-
purpose:
|
|
1153
|
+
purpose: z6.string().min(1)
|
|
1034
1154
|
}),
|
|
1035
|
-
archive_channel:
|
|
1036
|
-
update_dashboard:
|
|
1155
|
+
archive_channel: z6.object({ channel: ChannelRefSchema, reason: z6.string().min(1) }),
|
|
1156
|
+
update_dashboard: z6.object({
|
|
1037
1157
|
project: NameSchema,
|
|
1038
1158
|
/** The whole dashboard as markdown; the board keeps its frontmatter. */
|
|
1039
|
-
body:
|
|
1159
|
+
body: z6.string().min(1),
|
|
1040
1160
|
/** The `revision` in the frontmatter of the dashboard you read, 0 when it names none. */
|
|
1041
|
-
revision:
|
|
1161
|
+
revision: z6.number().int().min(0)
|
|
1042
1162
|
}),
|
|
1043
|
-
create_cron:
|
|
1163
|
+
create_cron: z6.object({
|
|
1044
1164
|
title: CronTitleSchema,
|
|
1045
1165
|
/** What to do when it fires; quoted in the prompt of every turn it starts. */
|
|
1046
1166
|
note: CronNoteSchema,
|
|
@@ -1059,10 +1179,10 @@ var VerbInputs = {
|
|
|
1059
1179
|
/** An open channel of that place other than general, whose conversation it fires in. */
|
|
1060
1180
|
channel: NameSchema.optional()
|
|
1061
1181
|
}),
|
|
1062
|
-
update_cron:
|
|
1182
|
+
update_cron: z6.object({
|
|
1063
1183
|
cron_id: UlidSchema,
|
|
1064
1184
|
/** Pause it, or resume it, which starts its schedule afresh from now. */
|
|
1065
|
-
paused:
|
|
1185
|
+
paused: z6.boolean().optional(),
|
|
1066
1186
|
title: CronTitleSchema.optional(),
|
|
1067
1187
|
note: CronNoteSchema.optional(),
|
|
1068
1188
|
/** A new expression, or `at` for one time; either starts the schedule afresh. */
|
|
@@ -1071,8 +1191,8 @@ var VerbInputs = {
|
|
|
1071
1191
|
timezone: TimeZoneSchema.nullable().optional(),
|
|
1072
1192
|
at: MomentSchema.optional()
|
|
1073
1193
|
}),
|
|
1074
|
-
remove_cron:
|
|
1075
|
-
remove_skill:
|
|
1194
|
+
remove_cron: z6.object({ cron_id: UlidSchema, reason: z6.string().trim().min(1) }),
|
|
1195
|
+
remove_skill: z6.object({ name: NameSchema, reason: z6.string().trim().min(1) })
|
|
1076
1196
|
};
|
|
1077
1197
|
var VERB_DESCRIPTIONS = {
|
|
1078
1198
|
post_message: "Post a markdown message to a channel, or into a thread when thread_id is given; a thread's message goes to the thread's channel.",
|
|
@@ -1109,7 +1229,7 @@ var VERB_DESCRIPTIONS = {
|
|
|
1109
1229
|
};
|
|
1110
1230
|
|
|
1111
1231
|
// packages/shared/dist/events.js
|
|
1112
|
-
import { z as
|
|
1232
|
+
import { z as z7 } from "zod";
|
|
1113
1233
|
var BOARD_EVENT_TYPES = [
|
|
1114
1234
|
"society.initialized",
|
|
1115
1235
|
"project.added",
|
|
@@ -1154,6 +1274,7 @@ var BOARD_EVENT_TYPES = [
|
|
|
1154
1274
|
"user.signed_out",
|
|
1155
1275
|
"user.token_rotated",
|
|
1156
1276
|
"runner.changed",
|
|
1277
|
+
"runner.quota",
|
|
1157
1278
|
"ops.signal",
|
|
1158
1279
|
"paused.changed",
|
|
1159
1280
|
"wake.requested",
|
|
@@ -1174,28 +1295,36 @@ var BOARD_EVENT_TYPES = [
|
|
|
1174
1295
|
"cron.skipped",
|
|
1175
1296
|
"cron.ended"
|
|
1176
1297
|
];
|
|
1177
|
-
var BoardEventTypeSchema =
|
|
1178
|
-
var BoardEventSchema =
|
|
1298
|
+
var BoardEventTypeSchema = z7.enum(BOARD_EVENT_TYPES);
|
|
1299
|
+
var BoardEventSchema = z7.object({
|
|
1179
1300
|
id: UlidSchema,
|
|
1180
1301
|
ts: IsoDateTimeSchema,
|
|
1181
1302
|
type: BoardEventTypeSchema,
|
|
1182
1303
|
actor: NameSchema,
|
|
1183
|
-
payload:
|
|
1304
|
+
payload: z7.record(z7.string(), z7.unknown())
|
|
1184
1305
|
});
|
|
1185
|
-
var UsageSchema =
|
|
1186
|
-
inputTokens:
|
|
1187
|
-
outputTokens:
|
|
1188
|
-
cacheReadTokens:
|
|
1189
|
-
cacheWriteTokens:
|
|
1306
|
+
var UsageSchema = z7.object({
|
|
1307
|
+
inputTokens: z7.number().int().nonnegative(),
|
|
1308
|
+
outputTokens: z7.number().int().nonnegative(),
|
|
1309
|
+
cacheReadTokens: z7.number().int().nonnegative().default(0),
|
|
1310
|
+
cacheWriteTokens: z7.number().int().nonnegative().default(0)
|
|
1190
1311
|
});
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1312
|
+
function addUsage(a, b) {
|
|
1313
|
+
return {
|
|
1314
|
+
inputTokens: a.inputTokens + b.inputTokens,
|
|
1315
|
+
outputTokens: a.outputTokens + b.outputTokens,
|
|
1316
|
+
cacheReadTokens: a.cacheReadTokens + b.cacheReadTokens,
|
|
1317
|
+
cacheWriteTokens: a.cacheWriteTokens + b.cacheWriteTokens
|
|
1318
|
+
};
|
|
1319
|
+
}
|
|
1320
|
+
var TurnStatusSchema = z7.object({
|
|
1321
|
+
summary: z7.string().min(1),
|
|
1322
|
+
claimsHeld: z7.array(UlidSchema).default([]),
|
|
1323
|
+
blockedOn: z7.array(z7.string()).default([]),
|
|
1324
|
+
needsUserDecision: z7.boolean().default(false),
|
|
1325
|
+
memoryUpdated: z7.boolean().default(false)
|
|
1197
1326
|
});
|
|
1198
|
-
var TurnExitReasonSchema =
|
|
1327
|
+
var TurnExitReasonSchema = z7.enum([
|
|
1199
1328
|
"completed",
|
|
1200
1329
|
"timeout",
|
|
1201
1330
|
"error",
|
|
@@ -1203,50 +1332,50 @@ var TurnExitReasonSchema = z6.enum([
|
|
|
1203
1332
|
"blocked",
|
|
1204
1333
|
"stopped"
|
|
1205
1334
|
]);
|
|
1206
|
-
var AgentEventSchema =
|
|
1207
|
-
|
|
1208
|
-
type:
|
|
1335
|
+
var AgentEventSchema = z7.discriminatedUnion("type", [
|
|
1336
|
+
z7.object({
|
|
1337
|
+
type: z7.literal("turn_started"),
|
|
1209
1338
|
agent: NameSchema,
|
|
1210
|
-
session:
|
|
1339
|
+
session: z7.string(),
|
|
1211
1340
|
runner: NameSchema,
|
|
1212
1341
|
/** The model the CLI reports running, when it reports one. */
|
|
1213
|
-
model:
|
|
1342
|
+
model: z7.string().optional()
|
|
1214
1343
|
}),
|
|
1215
1344
|
/**
|
|
1216
1345
|
* The CLI took a steer into the running turn. Adapters name the steer; the server adds the
|
|
1217
1346
|
* messages it delivered and the text the CLI was given.
|
|
1218
1347
|
*/
|
|
1219
|
-
|
|
1220
|
-
type:
|
|
1221
|
-
steer:
|
|
1222
|
-
messages:
|
|
1223
|
-
text:
|
|
1348
|
+
z7.object({
|
|
1349
|
+
type: z7.literal("steered"),
|
|
1350
|
+
steer: z7.string().min(1),
|
|
1351
|
+
messages: z7.array(UlidSchema).optional(),
|
|
1352
|
+
text: z7.string().optional()
|
|
1224
1353
|
}),
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
type:
|
|
1229
|
-
name:
|
|
1230
|
-
ok:
|
|
1354
|
+
z7.object({ type: z7.literal("text"), delta: z7.string() }),
|
|
1355
|
+
z7.object({ type: z7.literal("tool_call"), name: z7.string(), input: z7.unknown() }),
|
|
1356
|
+
z7.object({
|
|
1357
|
+
type: z7.literal("tool_result"),
|
|
1358
|
+
name: z7.string(),
|
|
1359
|
+
ok: z7.boolean(),
|
|
1231
1360
|
/** What the tool returned, cut to `OUTPUT_LIMIT` characters by `capOutput`. */
|
|
1232
|
-
output:
|
|
1361
|
+
output: z7.string().optional()
|
|
1233
1362
|
}),
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
type:
|
|
1363
|
+
z7.object({ type: z7.literal("approval_requested"), kind: z7.string(), detail: z7.unknown() }),
|
|
1364
|
+
z7.object({
|
|
1365
|
+
type: z7.literal("turn_completed"),
|
|
1237
1366
|
usage: UsageSchema,
|
|
1238
|
-
costUsd:
|
|
1367
|
+
costUsd: z7.number().nonnegative(),
|
|
1239
1368
|
status: TurnStatusSchema.nullable(),
|
|
1240
1369
|
exitReason: TurnExitReasonSchema
|
|
1241
1370
|
}),
|
|
1242
|
-
|
|
1371
|
+
z7.object({ type: z7.literal("error"), message: z7.string() })
|
|
1243
1372
|
]);
|
|
1244
|
-
var TranscriptEntrySchema =
|
|
1373
|
+
var TranscriptEntrySchema = z7.object({
|
|
1245
1374
|
ts: IsoDateTimeSchema,
|
|
1246
1375
|
event: AgentEventSchema
|
|
1247
1376
|
});
|
|
1248
|
-
var LiveTurnEventSchema =
|
|
1249
|
-
seq:
|
|
1377
|
+
var LiveTurnEventSchema = z7.object({
|
|
1378
|
+
seq: z7.number().int().positive(),
|
|
1250
1379
|
ts: IsoDateTimeSchema,
|
|
1251
1380
|
agent: NameSchema,
|
|
1252
1381
|
project: NameSchema,
|
|
@@ -1258,10 +1387,10 @@ var LiveTurnEventSchema = z6.object({
|
|
|
1258
1387
|
});
|
|
1259
1388
|
|
|
1260
1389
|
// packages/shared/dist/turns.js
|
|
1261
|
-
import { z as
|
|
1390
|
+
import { z as z9 } from "zod";
|
|
1262
1391
|
|
|
1263
1392
|
// packages/shared/dist/runner.js
|
|
1264
|
-
import { z as
|
|
1393
|
+
import { z as z8 } from "zod";
|
|
1265
1394
|
var RUNNER_PROTOCOL = 1;
|
|
1266
1395
|
var PATH_TOKENS = {
|
|
1267
1396
|
home: "{{stellaris:home}}",
|
|
@@ -1272,67 +1401,75 @@ var SERVER_TOKEN = "{{stellaris:server}}";
|
|
|
1272
1401
|
var WORKSPACE_TOKEN = "{{stellaris:workspace}}";
|
|
1273
1402
|
var HOME_SCRATCH = "scratch";
|
|
1274
1403
|
var HOME_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1275
|
-
var RunnerHelloSchema =
|
|
1276
|
-
protocol:
|
|
1277
|
-
version:
|
|
1404
|
+
var RunnerHelloSchema = z8.object({
|
|
1405
|
+
protocol: z8.number().int().positive(),
|
|
1406
|
+
version: z8.string().min(1),
|
|
1278
1407
|
os: RunnerOsSchema,
|
|
1279
|
-
clis:
|
|
1408
|
+
clis: z8.array(CliKindSchema),
|
|
1280
1409
|
/** The CLIs whose adapter can keep a session warm between turns. */
|
|
1281
|
-
residentClis:
|
|
1410
|
+
residentClis: z8.array(CliKindSchema).default([]),
|
|
1282
1411
|
/** The CLIs whose adapter can take input into a running turn; the server steers only these. */
|
|
1283
|
-
steerableClis:
|
|
1412
|
+
steerableClis: z8.array(CliKindSchema).default([]),
|
|
1284
1413
|
/** The CLIs whose adapter can stop a running turn; the server stops only these. */
|
|
1285
|
-
stoppableClis:
|
|
1414
|
+
stoppableClis: z8.array(CliKindSchema).default([]),
|
|
1286
1415
|
/** Whether the runner answers file reads on its projects' branches; one from before never does. */
|
|
1287
|
-
branchReads:
|
|
1416
|
+
branchReads: z8.boolean().default(false),
|
|
1288
1417
|
/** Whether the runner lists what a branch changed; one from before never does. */
|
|
1289
|
-
branchChanges:
|
|
1290
|
-
|
|
1418
|
+
branchChanges: z8.boolean().default(false),
|
|
1419
|
+
/** Whether the runner answers a read of a CLI's quota; one from before never does. */
|
|
1420
|
+
quotaReads: z8.boolean().default(false),
|
|
1421
|
+
capabilities: z8.array(z8.string()).default([]),
|
|
1422
|
+
/**
|
|
1423
|
+
* What the runner's account lacks of the git identity citizens' own commits carry, checked
|
|
1424
|
+
* before each hello outside any repository; empty when it has both. Absent from a runner from
|
|
1425
|
+
* before the check, which no default fills in, so the board marks only what a runner reported.
|
|
1426
|
+
*/
|
|
1427
|
+
gitIdentityMissing: z8.array(GitIdentityPartSchema).optional(),
|
|
1291
1428
|
/** Turns the runner runs at once, or null for no limit. */
|
|
1292
|
-
slots:
|
|
1429
|
+
slots: z8.number().int().positive().nullable(),
|
|
1293
1430
|
/** Turns the runner is still running, when it registers again; the server fails the rest of its turns. */
|
|
1294
|
-
turns:
|
|
1431
|
+
turns: z8.array(UlidSchema).default([])
|
|
1295
1432
|
});
|
|
1296
|
-
var RunnerWelcomeSchema =
|
|
1297
|
-
var RunnerEnrollRequestSchema =
|
|
1298
|
-
protocol:
|
|
1299
|
-
version:
|
|
1300
|
-
hostname:
|
|
1433
|
+
var RunnerWelcomeSchema = z8.object({ name: NameSchema, version: z8.string() });
|
|
1434
|
+
var RunnerEnrollRequestSchema = z8.object({
|
|
1435
|
+
protocol: z8.number().int().positive(),
|
|
1436
|
+
version: z8.string().min(1).max(64),
|
|
1437
|
+
hostname: z8.string().min(1).max(253),
|
|
1301
1438
|
os: RunnerOsSchema,
|
|
1302
|
-
clis:
|
|
1303
|
-
capabilities:
|
|
1439
|
+
clis: z8.array(CliKindSchema).max(8),
|
|
1440
|
+
capabilities: z8.array(z8.string().min(1).max(64)).max(32).default([])
|
|
1304
1441
|
});
|
|
1305
|
-
var RunnerEnrollmentSchema =
|
|
1306
|
-
deviceCode:
|
|
1307
|
-
userCode:
|
|
1442
|
+
var RunnerEnrollmentSchema = z8.object({
|
|
1443
|
+
deviceCode: z8.string().min(1),
|
|
1444
|
+
userCode: z8.string().min(1),
|
|
1308
1445
|
expiresAt: IsoDateTimeSchema,
|
|
1309
|
-
intervalMs:
|
|
1446
|
+
intervalMs: z8.number().int().positive()
|
|
1310
1447
|
});
|
|
1311
|
-
var RunnerEnrollPollSchema =
|
|
1312
|
-
var RunnerEnrollStatusSchema =
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1448
|
+
var RunnerEnrollPollSchema = z8.object({ deviceCode: z8.string().min(1) });
|
|
1449
|
+
var RunnerEnrollStatusSchema = z8.discriminatedUnion("status", [
|
|
1450
|
+
z8.object({ status: z8.literal("pending") }),
|
|
1451
|
+
z8.object({ status: z8.literal("approved"), name: NameSchema, token: z8.string().min(1) }),
|
|
1452
|
+
z8.object({ status: z8.literal("denied") })
|
|
1316
1453
|
]);
|
|
1317
|
-
var PendingEnrollmentSchema =
|
|
1318
|
-
userCode:
|
|
1319
|
-
hostname:
|
|
1454
|
+
var PendingEnrollmentSchema = z8.object({
|
|
1455
|
+
userCode: z8.string().min(1),
|
|
1456
|
+
hostname: z8.string(),
|
|
1320
1457
|
os: RunnerOsSchema,
|
|
1321
|
-
clis:
|
|
1322
|
-
capabilities:
|
|
1323
|
-
version:
|
|
1458
|
+
clis: z8.array(CliKindSchema),
|
|
1459
|
+
capabilities: z8.array(z8.string()),
|
|
1460
|
+
version: z8.string(),
|
|
1324
1461
|
requestedAt: IsoDateTimeSchema,
|
|
1325
1462
|
expiresAt: IsoDateTimeSchema
|
|
1326
1463
|
});
|
|
1327
|
-
var ProjectRepoSchema =
|
|
1464
|
+
var ProjectRepoSchema = z8.object({
|
|
1328
1465
|
slug: NameSchema,
|
|
1329
|
-
origin:
|
|
1330
|
-
defaultBranch:
|
|
1466
|
+
origin: z8.string().nullable(),
|
|
1467
|
+
defaultBranch: z8.string().min(1),
|
|
1331
1468
|
/**
|
|
1332
1469
|
* The board lands finished tasks on the default branch, itself or through their pull requests,
|
|
1333
1470
|
* so the runner lets nothing else move it.
|
|
1334
1471
|
*/
|
|
1335
|
-
boardLands:
|
|
1472
|
+
boardLands: z8.boolean()
|
|
1336
1473
|
});
|
|
1337
1474
|
function projectRepo(project) {
|
|
1338
1475
|
return {
|
|
@@ -1342,29 +1479,29 @@ function projectRepo(project) {
|
|
|
1342
1479
|
boardLands: project.onDone !== "none"
|
|
1343
1480
|
};
|
|
1344
1481
|
}
|
|
1345
|
-
var TurnWorkspaceSchema =
|
|
1346
|
-
|
|
1347
|
-
kind:
|
|
1482
|
+
var TurnWorkspaceSchema = z8.discriminatedUnion("kind", [
|
|
1483
|
+
z8.object({
|
|
1484
|
+
kind: z8.literal("home"),
|
|
1348
1485
|
thread: UlidSchema.optional(),
|
|
1349
1486
|
channel: NameSchema.optional()
|
|
1350
1487
|
}),
|
|
1351
|
-
|
|
1352
|
-
kind:
|
|
1488
|
+
z8.object({
|
|
1489
|
+
kind: z8.literal("project"),
|
|
1353
1490
|
repo: ProjectRepoSchema,
|
|
1354
|
-
branches:
|
|
1491
|
+
branches: z8.array(z8.string().min(1)),
|
|
1355
1492
|
thread: UlidSchema.optional(),
|
|
1356
1493
|
channel: NameSchema.optional()
|
|
1357
1494
|
}),
|
|
1358
|
-
|
|
1495
|
+
z8.object({ kind: z8.literal("task"), repo: ProjectRepoSchema, taskId: UlidSchema })
|
|
1359
1496
|
]);
|
|
1360
|
-
var TurnJobSchema =
|
|
1497
|
+
var TurnJobSchema = z8.object({
|
|
1361
1498
|
turnId: UlidSchema,
|
|
1362
1499
|
agent: NameSchema,
|
|
1363
1500
|
role: NameSchema,
|
|
1364
1501
|
cli: CliKindSchema,
|
|
1365
|
-
model:
|
|
1502
|
+
model: z8.string().optional(),
|
|
1366
1503
|
/** The reasoning effort set on the agent; absent for the model's own default. */
|
|
1367
|
-
effort:
|
|
1504
|
+
effort: z8.string().optional(),
|
|
1368
1505
|
/** A project slug, or the society scope. */
|
|
1369
1506
|
scope: NameSchema,
|
|
1370
1507
|
/** The thread whose conversation the turn is in; absent for the home conversation. */
|
|
@@ -1375,125 +1512,130 @@ var TurnJobSchema = z7.object({
|
|
|
1375
1512
|
* The session to resume, or null to start one: the CLI's adapter picks a fresh session's id, and
|
|
1376
1513
|
* the outcome reports it.
|
|
1377
1514
|
*/
|
|
1378
|
-
session:
|
|
1515
|
+
session: z8.string().min(1).nullable(),
|
|
1379
1516
|
/** The running total the session reported after its last turn, which a resumed session starts from. */
|
|
1380
|
-
costSoFarUsd:
|
|
1517
|
+
costSoFarUsd: z8.number().nonnegative(),
|
|
1381
1518
|
/** The rendered charter, norms, memory core, and skills index, with `PATH_TOKENS` for places. */
|
|
1382
|
-
instructions:
|
|
1383
|
-
prompt:
|
|
1384
|
-
mcp:
|
|
1385
|
-
limits:
|
|
1386
|
-
timeoutMs:
|
|
1387
|
-
maxTurns:
|
|
1519
|
+
instructions: z8.string(),
|
|
1520
|
+
prompt: z8.string(),
|
|
1521
|
+
mcp: z8.object({ url: z8.string().min(1), token: z8.string().min(1) }),
|
|
1522
|
+
limits: z8.object({
|
|
1523
|
+
timeoutMs: z8.number().int().positive().nullable(),
|
|
1524
|
+
maxTurns: z8.number().int().positive().nullable()
|
|
1388
1525
|
}),
|
|
1389
1526
|
/** Present when the runner keeps the conversation's session warm between turns, under `key`. */
|
|
1390
|
-
resident:
|
|
1527
|
+
resident: z8.object({ key: z8.string().min(1), idleMs: z8.number().int().positive() }).optional(),
|
|
1391
1528
|
workspace: TurnWorkspaceSchema
|
|
1392
1529
|
});
|
|
1393
|
-
var TurnWorkSchema =
|
|
1394
|
-
var TurnEventsSchema =
|
|
1395
|
-
var TurnOutcomeSchema =
|
|
1530
|
+
var TurnWorkSchema = z8.object({ branch: z8.string().min(1), head: z8.string().min(1) });
|
|
1531
|
+
var TurnEventsSchema = z8.object({ entries: z8.array(TranscriptEntrySchema) });
|
|
1532
|
+
var TurnOutcomeSchema = z8.object({
|
|
1396
1533
|
exitReason: TurnExitReasonSchema,
|
|
1397
1534
|
status: TurnStatusSchema.nullable(),
|
|
1398
|
-
error:
|
|
1535
|
+
error: z8.string().nullable(),
|
|
1399
1536
|
usage: UsageSchema,
|
|
1400
|
-
costUsd:
|
|
1537
|
+
costUsd: z8.number().nonnegative(),
|
|
1401
1538
|
/** The session's running total after this turn, for CLIs that report one. */
|
|
1402
|
-
sessionCostUsd:
|
|
1539
|
+
sessionCostUsd: z8.number().nonnegative().optional(),
|
|
1403
1540
|
/** The session the CLI used, which differs from the job's for CLIs that assign their own ids. */
|
|
1404
|
-
session:
|
|
1541
|
+
session: z8.string().min(1),
|
|
1405
1542
|
/** The model the CLI reported, when it reported one. */
|
|
1406
|
-
model:
|
|
1543
|
+
model: z8.string().nullable(),
|
|
1407
1544
|
work: TurnWorkSchema.nullable(),
|
|
1408
1545
|
/**
|
|
1409
1546
|
* Whether the turn's own workspace, a thread's, a channel's, or a task's, holds work on no
|
|
1410
1547
|
* branch after the hand-back: uncommitted changes, or commits no branch contains.
|
|
1411
1548
|
*/
|
|
1412
|
-
leftovers:
|
|
1549
|
+
leftovers: z8.boolean().default(false),
|
|
1550
|
+
/**
|
|
1551
|
+
* The CLI's plan quota as the turn's stream last reported it, when it reported any; a runner from
|
|
1552
|
+
* before never sends it.
|
|
1553
|
+
*/
|
|
1554
|
+
quota: CliQuotaSchema.optional()
|
|
1413
1555
|
});
|
|
1414
|
-
var TurnAckSchema =
|
|
1415
|
-
var LandRequestSchema =
|
|
1556
|
+
var TurnAckSchema = z8.object({ dropWorkspace: z8.boolean() });
|
|
1557
|
+
var LandRequestSchema = z8.object({
|
|
1416
1558
|
repo: ProjectRepoSchema,
|
|
1417
|
-
branch:
|
|
1559
|
+
branch: z8.string().min(1),
|
|
1418
1560
|
/**
|
|
1419
1561
|
* For a `ghpr` task, the pull request to merge in place of the branch, which must hold the
|
|
1420
1562
|
* branch's files, and the merge commit's subject and body, the pull request's title and an
|
|
1421
1563
|
* empty body when left out.
|
|
1422
1564
|
*/
|
|
1423
|
-
pullRequest:
|
|
1424
|
-
url:
|
|
1425
|
-
subject:
|
|
1426
|
-
body:
|
|
1565
|
+
pullRequest: z8.object({
|
|
1566
|
+
url: z8.string().min(1),
|
|
1567
|
+
subject: z8.string().min(1).optional(),
|
|
1568
|
+
body: z8.string().optional()
|
|
1427
1569
|
}).optional()
|
|
1428
1570
|
});
|
|
1429
|
-
var CloseRequestSchema =
|
|
1571
|
+
var CloseRequestSchema = z8.object({
|
|
1430
1572
|
repo: ProjectRepoSchema,
|
|
1431
|
-
url:
|
|
1432
|
-
comment:
|
|
1573
|
+
url: z8.string().min(1),
|
|
1574
|
+
comment: z8.string().min(1)
|
|
1433
1575
|
});
|
|
1434
|
-
var MergeOutcomeSchema =
|
|
1435
|
-
var ModelListSchema =
|
|
1576
|
+
var MergeOutcomeSchema = z8.object({ ok: z8.boolean(), detail: z8.string() });
|
|
1577
|
+
var ModelListSchema = z8.array(ModelOptionSchema);
|
|
1436
1578
|
var BRANCH_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1437
|
-
var BranchPathSchema =
|
|
1438
|
-
var BranchNameSchema =
|
|
1439
|
-
var BranchReadSchema =
|
|
1579
|
+
var BranchPathSchema = z8.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" });
|
|
1580
|
+
var BranchNameSchema = z8.string().regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/);
|
|
1581
|
+
var BranchReadSchema = z8.object({
|
|
1440
1582
|
repo: ProjectRepoSchema,
|
|
1441
1583
|
branch: BranchNameSchema,
|
|
1442
1584
|
path: BranchPathSchema
|
|
1443
1585
|
});
|
|
1444
|
-
var BranchCommitSchema =
|
|
1445
|
-
id:
|
|
1586
|
+
var BranchCommitSchema = z8.object({
|
|
1587
|
+
id: z8.string().min(1),
|
|
1446
1588
|
at: IsoDateTimeSchema,
|
|
1447
|
-
author:
|
|
1589
|
+
author: z8.string()
|
|
1448
1590
|
});
|
|
1449
|
-
var BranchFileSchema =
|
|
1450
|
-
|
|
1451
|
-
kind:
|
|
1591
|
+
var BranchFileSchema = z8.discriminatedUnion("kind", [
|
|
1592
|
+
z8.object({
|
|
1593
|
+
kind: z8.literal("file"),
|
|
1452
1594
|
path: BranchPathSchema,
|
|
1453
1595
|
commit: BranchCommitSchema,
|
|
1454
|
-
size:
|
|
1455
|
-
content:
|
|
1596
|
+
size: z8.number().int().nonnegative(),
|
|
1597
|
+
content: z8.string().nullable()
|
|
1456
1598
|
}),
|
|
1457
|
-
|
|
1458
|
-
kind:
|
|
1599
|
+
z8.object({
|
|
1600
|
+
kind: z8.literal("dir"),
|
|
1459
1601
|
path: BranchPathSchema,
|
|
1460
1602
|
commit: BranchCommitSchema,
|
|
1461
|
-
entries:
|
|
1462
|
-
name:
|
|
1463
|
-
kind:
|
|
1464
|
-
size:
|
|
1603
|
+
entries: z8.array(z8.object({
|
|
1604
|
+
name: z8.string().min(1),
|
|
1605
|
+
kind: z8.enum(["file", "dir"]),
|
|
1606
|
+
size: z8.number().int().nonnegative().nullable()
|
|
1465
1607
|
}))
|
|
1466
1608
|
})
|
|
1467
1609
|
]);
|
|
1468
|
-
var BranchChangesReadSchema =
|
|
1610
|
+
var BranchChangesReadSchema = z8.object({
|
|
1469
1611
|
repo: ProjectRepoSchema,
|
|
1470
1612
|
branch: BranchNameSchema
|
|
1471
1613
|
});
|
|
1472
|
-
var BranchFileChangeSchema =
|
|
1473
|
-
path:
|
|
1474
|
-
status:
|
|
1614
|
+
var BranchFileChangeSchema = z8.object({
|
|
1615
|
+
path: z8.string().min(1),
|
|
1616
|
+
status: z8.enum(["added", "modified", "deleted"]),
|
|
1475
1617
|
/** Lines added and removed, or null for a binary file. */
|
|
1476
|
-
added:
|
|
1477
|
-
removed:
|
|
1618
|
+
added: z8.number().int().nonnegative().nullable(),
|
|
1619
|
+
removed: z8.number().int().nonnegative().nullable(),
|
|
1478
1620
|
/** Absent when the file changed only through a merge of another branch. */
|
|
1479
|
-
lastChange:
|
|
1621
|
+
lastChange: z8.object({ author: z8.string(), at: IsoDateTimeSchema }).optional()
|
|
1480
1622
|
});
|
|
1481
|
-
var BranchChangesSchema =
|
|
1623
|
+
var BranchChangesSchema = z8.object({
|
|
1482
1624
|
head: BranchCommitSchema,
|
|
1483
|
-
files:
|
|
1484
|
-
total:
|
|
1625
|
+
files: z8.array(BranchFileChangeSchema),
|
|
1626
|
+
total: z8.number().int().nonnegative()
|
|
1485
1627
|
});
|
|
1486
|
-
var BranchDiffReadSchema =
|
|
1628
|
+
var BranchDiffReadSchema = z8.object({
|
|
1487
1629
|
repo: ProjectRepoSchema,
|
|
1488
1630
|
branch: BranchNameSchema,
|
|
1489
1631
|
path: BranchPathSchema.min(1)
|
|
1490
1632
|
});
|
|
1491
|
-
var BranchFileDiffSchema =
|
|
1633
|
+
var BranchFileDiffSchema = z8.object({
|
|
1492
1634
|
head: BranchCommitSchema,
|
|
1493
1635
|
path: BranchPathSchema,
|
|
1494
1636
|
status: BranchFileChangeSchema.shape.status,
|
|
1495
|
-
patch:
|
|
1496
|
-
truncated:
|
|
1637
|
+
patch: z8.string().nullable(),
|
|
1638
|
+
truncated: z8.boolean()
|
|
1497
1639
|
});
|
|
1498
1640
|
function patchHunks(patch, limit2) {
|
|
1499
1641
|
if (/^Binary files .* differ$/m.test(patch)) {
|
|
@@ -1507,9 +1649,9 @@ function patchHunks(patch, limit2) {
|
|
|
1507
1649
|
const cut = hunks.lastIndexOf("\n", limit2);
|
|
1508
1650
|
return { patch: hunks.slice(0, cut === -1 ? limit2 : cut), truncated: true };
|
|
1509
1651
|
}
|
|
1510
|
-
var WorkspaceConversationSchema =
|
|
1511
|
-
|
|
1512
|
-
|
|
1652
|
+
var WorkspaceConversationSchema = z8.discriminatedUnion("kind", [
|
|
1653
|
+
z8.object({ kind: z8.literal("thread"), id: UlidSchema }),
|
|
1654
|
+
z8.object({ kind: z8.literal("channel"), scope: NameSchema, name: NameSchema })
|
|
1513
1655
|
]);
|
|
1514
1656
|
function workspaceConversationOf(turn) {
|
|
1515
1657
|
if (turn.thread !== void 0) {
|
|
@@ -1517,60 +1659,65 @@ function workspaceConversationOf(turn) {
|
|
|
1517
1659
|
}
|
|
1518
1660
|
return turn.channel === void 0 ? null : { kind: "channel", scope: turn.scope, name: turn.channel };
|
|
1519
1661
|
}
|
|
1520
|
-
var HeldWorkspaceSchema =
|
|
1662
|
+
var HeldWorkspaceSchema = z8.object({
|
|
1521
1663
|
agent: NameSchema,
|
|
1522
1664
|
scope: NameSchema,
|
|
1523
1665
|
conversation: WorkspaceConversationSchema
|
|
1524
1666
|
});
|
|
1525
|
-
var HeldWorkspacesSchema =
|
|
1526
|
-
var SweepResultSchema =
|
|
1527
|
-
var TurnSteerSchema =
|
|
1528
|
-
var RunnerMessageSchema =
|
|
1529
|
-
|
|
1530
|
-
|
|
1667
|
+
var HeldWorkspacesSchema = z8.object({ workspaces: z8.array(HeldWorkspaceSchema) });
|
|
1668
|
+
var SweepResultSchema = z8.object({ kept: z8.array(HeldWorkspaceSchema) });
|
|
1669
|
+
var TurnSteerSchema = z8.object({ id: z8.uuid(), text: z8.string().min(1) });
|
|
1670
|
+
var RunnerMessageSchema = z8.discriminatedUnion("type", [
|
|
1671
|
+
z8.object({ type: z8.literal("turn"), job: TurnJobSchema }),
|
|
1672
|
+
z8.object({ type: z8.literal("land"), request: z8.string().min(1), land: LandRequestSchema }),
|
|
1531
1673
|
/** Answered with a `MergeOutcome`. */
|
|
1532
|
-
|
|
1533
|
-
|
|
1674
|
+
z8.object({ type: z8.literal("close"), request: z8.string().min(1), close: CloseRequestSchema }),
|
|
1675
|
+
z8.object({ type: z8.literal("models"), request: z8.string().min(1), cli: CliKindSchema }),
|
|
1676
|
+
/**
|
|
1677
|
+
* Answered with a `CliQuota` read from the CLI without a turn, or null when its adapter cannot
|
|
1678
|
+
* read one. Sent only to runners whose hello says `quotaReads`.
|
|
1679
|
+
*/
|
|
1680
|
+
z8.object({ type: z8.literal("quota"), request: z8.string().min(1), cli: CliKindSchema }),
|
|
1534
1681
|
/** Answered with a `BranchFile`, or null when the branch or the path does not exist. */
|
|
1535
|
-
|
|
1682
|
+
z8.object({ type: z8.literal("file"), request: z8.string().min(1), read: BranchReadSchema }),
|
|
1536
1683
|
/** Answered with `BranchChanges`, or null when the repository or the branch does not exist. */
|
|
1537
|
-
|
|
1538
|
-
type:
|
|
1539
|
-
request:
|
|
1684
|
+
z8.object({
|
|
1685
|
+
type: z8.literal("changes"),
|
|
1686
|
+
request: z8.string().min(1),
|
|
1540
1687
|
read: BranchChangesReadSchema
|
|
1541
1688
|
}),
|
|
1542
1689
|
/** Answered with a `BranchFileDiff`, or null when the branch does not exist or left the path alone. */
|
|
1543
|
-
|
|
1690
|
+
z8.object({ type: z8.literal("diff"), request: z8.string().min(1), read: BranchDiffReadSchema }),
|
|
1544
1691
|
/** Answered with whether the CLI accepted it; that it took it comes as a `steered` event. */
|
|
1545
|
-
|
|
1546
|
-
type:
|
|
1547
|
-
request:
|
|
1692
|
+
z8.object({
|
|
1693
|
+
type: z8.literal("steer"),
|
|
1694
|
+
request: z8.string().min(1),
|
|
1548
1695
|
turnId: UlidSchema,
|
|
1549
1696
|
steer: TurnSteerSchema
|
|
1550
1697
|
}),
|
|
1551
1698
|
/** Answered with whether the turn was there to stop; it ends `stopped`. */
|
|
1552
|
-
|
|
1699
|
+
z8.object({ type: z8.literal("stop"), request: z8.string().min(1), turnId: UlidSchema }),
|
|
1553
1700
|
/**
|
|
1554
1701
|
* A conversation ended: the runner removes every citizen's workspace for it but those a turn
|
|
1555
1702
|
* still uses, and answers with a `SweepResult` naming those it kept for holding work on no branch.
|
|
1556
1703
|
*/
|
|
1557
|
-
|
|
1558
|
-
type:
|
|
1559
|
-
request:
|
|
1704
|
+
z8.object({
|
|
1705
|
+
type: z8.literal("sweep"),
|
|
1706
|
+
request: z8.string().min(1),
|
|
1560
1707
|
conversation: WorkspaceConversationSchema
|
|
1561
1708
|
})
|
|
1562
1709
|
]);
|
|
1563
|
-
var RunnerAnswerSchema =
|
|
1564
|
-
|
|
1565
|
-
|
|
1710
|
+
var RunnerAnswerSchema = z8.discriminatedUnion("ok", [
|
|
1711
|
+
z8.object({ ok: z8.literal(true), value: z8.unknown() }),
|
|
1712
|
+
z8.object({ ok: z8.literal(false), error: z8.string() })
|
|
1566
1713
|
]);
|
|
1567
|
-
var WarmSessionsSchema =
|
|
1568
|
-
var FileManifestSchema =
|
|
1714
|
+
var WarmSessionsSchema = z8.object({ warm: z8.array(z8.string()) });
|
|
1715
|
+
var FileManifestSchema = z8.object({ files: z8.record(z8.string(), z8.string()) });
|
|
1569
1716
|
function fileVersion(sha, executable) {
|
|
1570
1717
|
return executable ? `${sha}+x` : sha;
|
|
1571
1718
|
}
|
|
1572
|
-
var FileReadSchema =
|
|
1573
|
-
var FileContentsSchema =
|
|
1719
|
+
var FileReadSchema = z8.object({ paths: z8.array(z8.string()) });
|
|
1720
|
+
var FileContentsSchema = z8.object({ files: z8.record(z8.string(), z8.string()) });
|
|
1574
1721
|
function isSafeRelativePath(file) {
|
|
1575
1722
|
if (file.length === 0 || file.startsWith("/") || file.includes("\\") || file.includes("\0")) {
|
|
1576
1723
|
return false;
|
|
@@ -1579,7 +1726,7 @@ function isSafeRelativePath(file) {
|
|
|
1579
1726
|
}
|
|
1580
1727
|
|
|
1581
1728
|
// packages/shared/dist/turns.js
|
|
1582
|
-
var TriggerKindSchema =
|
|
1729
|
+
var TriggerKindSchema = z9.enum([
|
|
1583
1730
|
"mention",
|
|
1584
1731
|
"stage",
|
|
1585
1732
|
"task_done",
|
|
@@ -1593,11 +1740,11 @@ var TriggerKindSchema = z8.enum([
|
|
|
1593
1740
|
"closing",
|
|
1594
1741
|
"cron"
|
|
1595
1742
|
]);
|
|
1596
|
-
var TriggerSchema =
|
|
1743
|
+
var TriggerSchema = z9.object({
|
|
1597
1744
|
kind: TriggerKindSchema,
|
|
1598
1745
|
from: NameSchema.optional(),
|
|
1599
|
-
fromUser:
|
|
1600
|
-
reason:
|
|
1746
|
+
fromUser: z9.boolean().default(false),
|
|
1747
|
+
reason: z9.string().default(""),
|
|
1601
1748
|
taskId: UlidSchema.optional(),
|
|
1602
1749
|
messageId: UlidSchema.optional(),
|
|
1603
1750
|
/** The channel the waking message was posted in. */
|
|
@@ -1605,17 +1752,17 @@ var TriggerSchema = z8.object({
|
|
|
1605
1752
|
/** The cron that came due, for a `cron` wake. */
|
|
1606
1753
|
cronId: UlidSchema.optional()
|
|
1607
1754
|
});
|
|
1608
|
-
var TurnThreadSchema =
|
|
1609
|
-
var TurnDispatchSchema =
|
|
1755
|
+
var TurnThreadSchema = z9.object({ id: UlidSchema, task: z9.boolean() });
|
|
1756
|
+
var TurnDispatchSchema = z9.object({
|
|
1610
1757
|
agent: NameSchema,
|
|
1611
1758
|
project: NameSchema,
|
|
1612
1759
|
thread: TurnThreadSchema.optional(),
|
|
1613
1760
|
channel: NameSchema.optional(),
|
|
1614
1761
|
trigger: TriggerSchema,
|
|
1615
|
-
priority:
|
|
1616
|
-
onboarding:
|
|
1762
|
+
priority: z9.number().int().min(0).max(2),
|
|
1763
|
+
onboarding: z9.boolean().default(false),
|
|
1617
1764
|
/** Every cron that came due for this turn, whatever wake it merged into; its prompt quotes each. */
|
|
1618
|
-
crons:
|
|
1765
|
+
crons: z9.array(UlidSchema).optional()
|
|
1619
1766
|
});
|
|
1620
1767
|
function conversationPart(conversation) {
|
|
1621
1768
|
return conversation.thread ?? (conversation.channel === void 0 ? void 0 : `#${conversation.channel}`);
|
|
@@ -1639,7 +1786,7 @@ function channelConversation(scope, channel) {
|
|
|
1639
1786
|
const name = at < 0 ? channel : channel.slice(at + 1);
|
|
1640
1787
|
return place === scope && name !== "general" ? name : void 0;
|
|
1641
1788
|
}
|
|
1642
|
-
var TurnRecordSchema =
|
|
1789
|
+
var TurnRecordSchema = z9.object({
|
|
1643
1790
|
/** Assigned by the board when the turn begins; the turn's transcript is filed under it. */
|
|
1644
1791
|
id: UlidSchema.optional(),
|
|
1645
1792
|
agent: NameSchema,
|
|
@@ -1650,31 +1797,31 @@ var TurnRecordSchema = z8.object({
|
|
|
1650
1797
|
channel: NameSchema.optional(),
|
|
1651
1798
|
runner: NameSchema,
|
|
1652
1799
|
cli: CliKindSchema.nullable(),
|
|
1653
|
-
session:
|
|
1800
|
+
session: z9.string().nullable(),
|
|
1654
1801
|
trigger: TriggerSchema,
|
|
1655
1802
|
startedAt: IsoDateTimeSchema,
|
|
1656
1803
|
endedAt: IsoDateTimeSchema.nullable(),
|
|
1657
1804
|
exitReason: TurnExitReasonSchema.nullable(),
|
|
1658
1805
|
status: TurnStatusSchema.nullable(),
|
|
1659
|
-
error:
|
|
1806
|
+
error: z9.string().nullable(),
|
|
1660
1807
|
usage: UsageSchema.nullable(),
|
|
1661
|
-
costUsd:
|
|
1808
|
+
costUsd: z9.number().nonnegative().default(0),
|
|
1662
1809
|
/**
|
|
1663
1810
|
* The running total the CLI reported for the session after this turn, when it reports one. A
|
|
1664
1811
|
* resumed session starts from it, so the next turn's own cost is measured from here.
|
|
1665
1812
|
*/
|
|
1666
|
-
sessionCostUsd:
|
|
1667
|
-
toolCalls:
|
|
1813
|
+
sessionCostUsd: z9.number().nonnegative().optional(),
|
|
1814
|
+
toolCalls: z9.number().int().nonnegative().default(0),
|
|
1668
1815
|
/** The model the CLI reported for this turn, else the model configured for the agent, else null. */
|
|
1669
|
-
model:
|
|
1816
|
+
model: z9.string().nullable().default(null),
|
|
1670
1817
|
/** The task branch the turn left work on, with its commit, as the runner reported it. */
|
|
1671
1818
|
work: TurnWorkSchema.optional(),
|
|
1672
1819
|
/** Who stopped the turn, for one that ended `stopped`. */
|
|
1673
1820
|
stoppedBy: NameSchema.optional(),
|
|
1674
1821
|
/** The crons whose fire started the turn, which record how it ended. */
|
|
1675
|
-
crons:
|
|
1822
|
+
crons: z9.array(UlidSchema).optional()
|
|
1676
1823
|
});
|
|
1677
|
-
var RunningTurnSchema =
|
|
1824
|
+
var RunningTurnSchema = z9.object({
|
|
1678
1825
|
turnId: UlidSchema,
|
|
1679
1826
|
agent: NameSchema,
|
|
1680
1827
|
scope: NameSchema,
|
|
@@ -1682,49 +1829,49 @@ var RunningTurnSchema = z8.object({
|
|
|
1682
1829
|
channel: NameSchema.optional(),
|
|
1683
1830
|
cli: CliKindSchema,
|
|
1684
1831
|
askedIn: ChannelRefSchema.optional(),
|
|
1685
|
-
steerable:
|
|
1686
|
-
stoppable:
|
|
1832
|
+
steerable: z9.boolean(),
|
|
1833
|
+
stoppable: z9.boolean()
|
|
1687
1834
|
});
|
|
1688
|
-
var SessionsFileSchema =
|
|
1689
|
-
claude:
|
|
1690
|
-
codex:
|
|
1835
|
+
var SessionsFileSchema = z9.object({
|
|
1836
|
+
claude: z9.string().optional(),
|
|
1837
|
+
codex: z9.string().optional(),
|
|
1691
1838
|
runner: NameSchema.optional()
|
|
1692
1839
|
});
|
|
1693
|
-
var WakeRequestSchema =
|
|
1840
|
+
var WakeRequestSchema = z9.object({
|
|
1694
1841
|
agent: NameSchema,
|
|
1695
1842
|
project: NameSchema,
|
|
1696
|
-
reason:
|
|
1843
|
+
reason: z9.string().default("manual wake"),
|
|
1697
1844
|
/** A manual wake, or a reflection turn requested ahead of the cadence. */
|
|
1698
|
-
kind:
|
|
1845
|
+
kind: z9.enum(["manual", "reflection"]).default("manual")
|
|
1699
1846
|
});
|
|
1700
|
-
var TurnHistoryEntrySchema =
|
|
1847
|
+
var TurnHistoryEntrySchema = z9.object({
|
|
1701
1848
|
/** The id of the event that ended the turn. */
|
|
1702
1849
|
id: UlidSchema,
|
|
1703
1850
|
/** The turn's own id, when it has a transcript to open; turns before transcripts have none. */
|
|
1704
1851
|
turnId: UlidSchema.optional(),
|
|
1705
1852
|
ts: IsoDateTimeSchema,
|
|
1706
|
-
outcome:
|
|
1853
|
+
outcome: z9.enum(["completed", "failed"]),
|
|
1707
1854
|
/** A project slug, or the society scope. */
|
|
1708
1855
|
project: NameSchema,
|
|
1709
1856
|
/** The thread whose conversation the turn was in; absent for the home conversation. */
|
|
1710
1857
|
thread: UlidSchema.optional(),
|
|
1711
1858
|
/** The channel, never general, whose conversation the turn was in. */
|
|
1712
1859
|
channel: NameSchema.optional(),
|
|
1713
|
-
trigger:
|
|
1714
|
-
exitReason:
|
|
1715
|
-
costUsd:
|
|
1860
|
+
trigger: z9.string(),
|
|
1861
|
+
exitReason: z9.string().nullable(),
|
|
1862
|
+
costUsd: z9.number(),
|
|
1716
1863
|
/** The tokens the turn used; absent for turns logged before turns recorded them. */
|
|
1717
1864
|
usage: UsageSchema.optional(),
|
|
1718
|
-
model:
|
|
1719
|
-
summary:
|
|
1720
|
-
error:
|
|
1865
|
+
model: z9.string().nullable(),
|
|
1866
|
+
summary: z9.string().nullable(),
|
|
1867
|
+
error: z9.string().nullable(),
|
|
1721
1868
|
/** When the log recorded the turn's start; absent when the start is missing from the log. */
|
|
1722
1869
|
startedAt: IsoDateTimeSchema.optional(),
|
|
1723
|
-
toolCalls:
|
|
1870
|
+
toolCalls: z9.number().int().nonnegative().optional()
|
|
1724
1871
|
});
|
|
1725
1872
|
|
|
1726
1873
|
// packages/shared/dist/ops.js
|
|
1727
|
-
import { z as
|
|
1874
|
+
import { z as z10 } from "zod";
|
|
1728
1875
|
var OPS_SIGNAL_KINDS = [
|
|
1729
1876
|
"waiting_stage",
|
|
1730
1877
|
"backlog",
|
|
@@ -1740,7 +1887,7 @@ var OPS_SIGNAL_KINDS = [
|
|
|
1740
1887
|
"stuck_workspace",
|
|
1741
1888
|
"cron_failing"
|
|
1742
1889
|
];
|
|
1743
|
-
var OpsSignalKindSchema =
|
|
1890
|
+
var OpsSignalKindSchema = z10.enum(OPS_SIGNAL_KINDS);
|
|
1744
1891
|
var WAKING_SIGNAL_KINDS = [
|
|
1745
1892
|
"backlog",
|
|
1746
1893
|
"role_gap",
|
|
@@ -1750,15 +1897,15 @@ var WAKING_SIGNAL_KINDS = [
|
|
|
1750
1897
|
"blocked_capability",
|
|
1751
1898
|
"scaled"
|
|
1752
1899
|
];
|
|
1753
|
-
var OpsSignalSchema =
|
|
1900
|
+
var OpsSignalSchema = z10.object({
|
|
1754
1901
|
kind: OpsSignalKindSchema,
|
|
1755
1902
|
/** Identifies the condition, for example `backlog:demo:engineer`, so a persisting one is not logged again every pass. */
|
|
1756
|
-
key:
|
|
1903
|
+
key: z10.string().min(1),
|
|
1757
1904
|
/** One line a reader can act on. */
|
|
1758
|
-
summary:
|
|
1905
|
+
summary: z10.string().min(1),
|
|
1759
1906
|
/** The counter or timer value behind the signal. */
|
|
1760
|
-
value:
|
|
1761
|
-
threshold:
|
|
1907
|
+
value: z10.number(),
|
|
1908
|
+
threshold: z10.number().optional(),
|
|
1762
1909
|
project: NameSchema.optional(),
|
|
1763
1910
|
agent: NameSchema.optional(),
|
|
1764
1911
|
role: NameSchema.optional(),
|
|
@@ -1766,8 +1913,8 @@ var OpsSignalSchema = z9.object({
|
|
|
1766
1913
|
});
|
|
1767
1914
|
|
|
1768
1915
|
// packages/shared/dist/metrics.js
|
|
1769
|
-
import { z as
|
|
1770
|
-
var MetricsWindowSchema =
|
|
1916
|
+
import { z as z11 } from "zod";
|
|
1917
|
+
var MetricsWindowSchema = z11.enum(["24h", "7d", "all"]);
|
|
1771
1918
|
var METRICS_WINDOW_MS = {
|
|
1772
1919
|
"24h": 24 * 36e5,
|
|
1773
1920
|
"7d": 7 * 24 * 36e5,
|
|
@@ -1778,9 +1925,9 @@ function isBoardAction(tool) {
|
|
|
1778
1925
|
const verb = /^mcp__board__(.+)$/.exec(tool)?.[1];
|
|
1779
1926
|
return verb !== void 0 && !READ_VERBS.some((read2) => read2 === verb);
|
|
1780
1927
|
}
|
|
1781
|
-
var CountSchema =
|
|
1782
|
-
var MsSchema =
|
|
1783
|
-
var MetricsSchema =
|
|
1928
|
+
var CountSchema = z11.number().int().nonnegative();
|
|
1929
|
+
var MsSchema = z11.number().nonnegative();
|
|
1930
|
+
var MetricsSchema = z11.object({
|
|
1784
1931
|
window: MetricsWindowSchema,
|
|
1785
1932
|
since: IsoDateTimeSchema.nullable(),
|
|
1786
1933
|
until: IsoDateTimeSchema,
|
|
@@ -1788,12 +1935,12 @@ var MetricsSchema = z10.object({
|
|
|
1788
1935
|
* Finished turns that changed nothing on the board. Reflections are left out, since they write
|
|
1789
1936
|
* memory, not the board; turns without a transcript are counted apart, their actions unknown.
|
|
1790
1937
|
*/
|
|
1791
|
-
idle:
|
|
1938
|
+
idle: z11.object({
|
|
1792
1939
|
turns: CountSchema,
|
|
1793
1940
|
idle: CountSchema,
|
|
1794
1941
|
unknown: CountSchema,
|
|
1795
|
-
byTrigger:
|
|
1796
|
-
byAgent:
|
|
1942
|
+
byTrigger: z11.array(z11.object({ trigger: z11.string(), turns: CountSchema, idle: CountSchema })),
|
|
1943
|
+
byAgent: z11.array(z11.object({
|
|
1797
1944
|
agent: NameSchema,
|
|
1798
1945
|
role: NameSchema.nullable(),
|
|
1799
1946
|
turns: CountSchema,
|
|
@@ -1801,33 +1948,33 @@ var MetricsSchema = z10.object({
|
|
|
1801
1948
|
}))
|
|
1802
1949
|
}),
|
|
1803
1950
|
/** Work sent back to an earlier stage: over the tasks finished in the window, and by where. */
|
|
1804
|
-
sentBack:
|
|
1951
|
+
sentBack: z11.object({
|
|
1805
1952
|
finished: CountSchema,
|
|
1806
1953
|
sendBacks: CountSchema,
|
|
1807
1954
|
tasksSentBack: CountSchema,
|
|
1808
|
-
byStage:
|
|
1809
|
-
bySender:
|
|
1955
|
+
byStage: z11.array(z11.object({ project: NameSchema, stage: z11.string(), count: CountSchema })),
|
|
1956
|
+
bySender: z11.array(z11.object({ agent: NameSchema, count: CountSchema }))
|
|
1810
1957
|
}),
|
|
1811
1958
|
/** Posts in the threads of the tasks finished in the window, the board's own notices left out. */
|
|
1812
|
-
messages:
|
|
1959
|
+
messages: z11.object({
|
|
1813
1960
|
finished: CountSchema,
|
|
1814
1961
|
messages: CountSchema,
|
|
1815
|
-
byProject:
|
|
1816
|
-
busiest:
|
|
1962
|
+
byProject: z11.array(z11.object({ project: NameSchema, finished: CountSchema, messages: CountSchema })),
|
|
1963
|
+
busiest: z11.array(z11.object({
|
|
1817
1964
|
taskId: UlidSchema,
|
|
1818
|
-
title:
|
|
1965
|
+
title: z11.string(),
|
|
1819
1966
|
project: NameSchema,
|
|
1820
1967
|
messages: CountSchema
|
|
1821
1968
|
}))
|
|
1822
1969
|
}),
|
|
1823
1970
|
/** Time from a mention to the start of the turn it woke, in the conversation it was made in. */
|
|
1824
|
-
latency:
|
|
1971
|
+
latency: z11.object({
|
|
1825
1972
|
mentions: CountSchema,
|
|
1826
1973
|
/** Mentions no turn has followed yet. */
|
|
1827
1974
|
unanswered: CountSchema,
|
|
1828
1975
|
medianMs: MsSchema.nullable(),
|
|
1829
1976
|
slowestMs: MsSchema.nullable(),
|
|
1830
|
-
byAgent:
|
|
1977
|
+
byAgent: z11.array(z11.object({
|
|
1831
1978
|
agent: NameSchema,
|
|
1832
1979
|
mentions: CountSchema,
|
|
1833
1980
|
medianMs: MsSchema,
|
|
@@ -1835,61 +1982,73 @@ var MetricsSchema = z10.object({
|
|
|
1835
1982
|
}))
|
|
1836
1983
|
}),
|
|
1837
1984
|
/** The user's decisions: proposals decided, questions answered, and stages passed or sent back. */
|
|
1838
|
-
decisions:
|
|
1985
|
+
decisions: z11.object({
|
|
1839
1986
|
total: CountSchema,
|
|
1840
|
-
byDay:
|
|
1841
|
-
day:
|
|
1987
|
+
byDay: z11.array(z11.object({
|
|
1988
|
+
day: z11.string(),
|
|
1842
1989
|
proposals: CountSchema,
|
|
1843
1990
|
answers: CountSchema,
|
|
1844
1991
|
stages: CountSchema
|
|
1845
1992
|
}))
|
|
1846
1993
|
}),
|
|
1847
1994
|
/** Tasks that needed a capability no connected runner offered, and whether they still do. */
|
|
1848
|
-
blocked:
|
|
1995
|
+
blocked: z11.array(z11.object({
|
|
1849
1996
|
taskId: UlidSchema,
|
|
1850
|
-
title:
|
|
1997
|
+
title: z11.string().nullable(),
|
|
1851
1998
|
project: NameSchema.nullable(),
|
|
1852
|
-
summary:
|
|
1999
|
+
summary: z11.string(),
|
|
1853
2000
|
firstAt: IsoDateTimeSchema,
|
|
1854
2001
|
lastAt: IsoDateTimeSchema,
|
|
1855
|
-
holds:
|
|
2002
|
+
holds: z11.boolean()
|
|
1856
2003
|
}))
|
|
1857
2004
|
});
|
|
2005
|
+
var CitizenTokensSchema = z11.object({
|
|
2006
|
+
agent: NameSchema,
|
|
2007
|
+
turns: CountSchema,
|
|
2008
|
+
withUsage: CountSchema,
|
|
2009
|
+
usage: UsageSchema.nullable()
|
|
2010
|
+
});
|
|
2011
|
+
var TokenUseSchema = z11.object({
|
|
2012
|
+
window: MetricsWindowSchema,
|
|
2013
|
+
since: IsoDateTimeSchema.nullable(),
|
|
2014
|
+
until: IsoDateTimeSchema,
|
|
2015
|
+
citizens: z11.array(CitizenTokensSchema)
|
|
2016
|
+
});
|
|
1858
2017
|
|
|
1859
2018
|
// packages/shared/dist/config.js
|
|
1860
|
-
import { z as
|
|
1861
|
-
var LogLevelSchema =
|
|
1862
|
-
var GithubSignInSchema =
|
|
1863
|
-
clientId:
|
|
1864
|
-
clientSecret:
|
|
2019
|
+
import { z as z12 } from "zod";
|
|
2020
|
+
var LogLevelSchema = z12.enum(["trace", "debug", "info", "warn", "error", "fatal"]);
|
|
2021
|
+
var GithubSignInSchema = z12.object({
|
|
2022
|
+
clientId: z12.string().min(1),
|
|
2023
|
+
clientSecret: z12.string().min(1),
|
|
1865
2024
|
/** Logins, lowercased; GitHub logins are case-insensitive. */
|
|
1866
|
-
users:
|
|
2025
|
+
users: z12.array(z12.string().min(1)).min(1)
|
|
1867
2026
|
});
|
|
1868
|
-
var ServerConfigSchema =
|
|
1869
|
-
dataDir:
|
|
1870
|
-
host:
|
|
1871
|
-
port:
|
|
2027
|
+
var ServerConfigSchema = z12.object({
|
|
2028
|
+
dataDir: z12.string().min(1),
|
|
2029
|
+
host: z12.string().min(1),
|
|
2030
|
+
port: z12.number().int().positive().max(65535),
|
|
1872
2031
|
/**
|
|
1873
2032
|
* An address every runner's agents reach this server at, for example https://board.example, or
|
|
1874
2033
|
* null for each runner to use the address it reaches the server at itself.
|
|
1875
2034
|
*/
|
|
1876
|
-
publicUrl:
|
|
2035
|
+
publicUrl: z12.string().min(1).nullable(),
|
|
1877
2036
|
logLevel: LogLevelSchema,
|
|
1878
2037
|
/** Turns running at once across every runner, or null for no limit beyond each runner's own. */
|
|
1879
|
-
concurrency:
|
|
2038
|
+
concurrency: z12.number().int().positive().nullable(),
|
|
1880
2039
|
/** How long one turn may run before it is stopped, or null for no limit. */
|
|
1881
|
-
turnTimeoutMs:
|
|
2040
|
+
turnTimeoutMs: z12.number().int().positive().nullable(),
|
|
1882
2041
|
/** Rounds of tool calls one Claude turn may take, or null for no limit. */
|
|
1883
|
-
toolRounds:
|
|
2042
|
+
toolRounds: z12.number().int().positive().nullable(),
|
|
1884
2043
|
/** How long a resident session stays warm after its last turn. */
|
|
1885
|
-
residentIdleMs:
|
|
2044
|
+
residentIdleMs: z12.number().int().positive(),
|
|
1886
2045
|
/** Signing in to the board with GitHub, or null when only a token lets anyone in. */
|
|
1887
2046
|
github: GithubSignInSchema.nullable(),
|
|
1888
2047
|
/**
|
|
1889
2048
|
* Reverse proxies in front of the server whose X-Forwarded-For entries name the client, for the
|
|
1890
2049
|
* rate limits on what anyone may ask without a token: 0 when clients connect directly.
|
|
1891
2050
|
*/
|
|
1892
|
-
trustedProxies:
|
|
2051
|
+
trustedProxies: z12.number().int().min(0).max(16)
|
|
1893
2052
|
});
|
|
1894
2053
|
function limit(value, fallback) {
|
|
1895
2054
|
if (value === void 0 || value.trim() === "") {
|
|
@@ -1927,25 +2086,73 @@ function loadServerConfig(env) {
|
|
|
1927
2086
|
trustedProxies: Number(env["STELLARIS_TRUSTED_PROXIES"] ?? "0")
|
|
1928
2087
|
});
|
|
1929
2088
|
}
|
|
1930
|
-
var RunnerConfigSchema =
|
|
2089
|
+
var RunnerConfigSchema = z12.object({
|
|
1931
2090
|
/** The board server, for example http://127.0.0.1:4700. */
|
|
1932
|
-
serverUrl:
|
|
2091
|
+
serverUrl: z12.string().url(),
|
|
1933
2092
|
/**
|
|
1934
2093
|
* The runner's token, from `runner add`, or null for the one it saved when it was enrolled, or
|
|
1935
2094
|
* to enroll it.
|
|
1936
2095
|
*/
|
|
1937
|
-
token:
|
|
2096
|
+
token: z12.string().min(1).nullable(),
|
|
1938
2097
|
/** The runner's own data directory: the board mirror, agent homes, repositories, worktrees. */
|
|
1939
|
-
dataDir:
|
|
2098
|
+
dataDir: z12.string().min(1),
|
|
1940
2099
|
logLevel: LogLevelSchema,
|
|
1941
2100
|
/** Turns this machine runs at once, or null for no limit. */
|
|
1942
|
-
slots:
|
|
1943
|
-
clis:
|
|
1944
|
-
capabilities:
|
|
2101
|
+
slots: z12.number().int().positive().nullable(),
|
|
2102
|
+
clis: z12.array(CliKindSchema).min(1),
|
|
2103
|
+
capabilities: z12.array(z12.string())
|
|
1945
2104
|
});
|
|
1946
2105
|
|
|
1947
2106
|
// packages/shared/dist/version.js
|
|
1948
|
-
var STELLARIS_VERSION = "0.3.
|
|
2107
|
+
var STELLARIS_VERSION = "0.3.22";
|
|
2108
|
+
|
|
2109
|
+
// packages/shared/dist/mentions.js
|
|
2110
|
+
import { parse, postprocess, preprocess } from "micromark";
|
|
2111
|
+
import { gfm } from "micromark-extension-gfm";
|
|
2112
|
+
var MENTION_PATTERN = /(^|[^\w@])@([a-z0-9][a-z0-9-]{0,31})(?![\w-])/g;
|
|
2113
|
+
var CODE = /* @__PURE__ */ new Set(["codeText", "codeFenced", "codeIndented"]);
|
|
2114
|
+
var SLOW = {
|
|
2115
|
+
disable: {
|
|
2116
|
+
null: [
|
|
2117
|
+
"wwwAutolink",
|
|
2118
|
+
"protocolAutolink",
|
|
2119
|
+
"emailAutolink",
|
|
2120
|
+
"gfmFootnoteCall",
|
|
2121
|
+
"gfmPotentialFootnoteCall"
|
|
2122
|
+
]
|
|
2123
|
+
}
|
|
2124
|
+
};
|
|
2125
|
+
function codeRanges(markdown) {
|
|
2126
|
+
const shift = markdown.startsWith("\uFEFF") ? 1 : 0;
|
|
2127
|
+
const events = postprocess(parse({ extensions: [gfm(), SLOW] }).document().write(preprocess()(markdown, void 0, true)));
|
|
2128
|
+
return events.flatMap(([kind, token]) => kind === "enter" && CODE.has(token.type) ? [[token.start.offset + shift, token.end.offset + shift]] : []);
|
|
2129
|
+
}
|
|
2130
|
+
function addMentions(found, text) {
|
|
2131
|
+
for (const match of text.matchAll(MENTION_PATTERN)) {
|
|
2132
|
+
const name = match[2];
|
|
2133
|
+
if (name !== void 0) {
|
|
2134
|
+
found.add(name);
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
}
|
|
2138
|
+
function mentionsIn(markdown) {
|
|
2139
|
+
if (markdown.search(MENTION_PATTERN) === -1) {
|
|
2140
|
+
return [];
|
|
2141
|
+
}
|
|
2142
|
+
const found = /* @__PURE__ */ new Set();
|
|
2143
|
+
let from = 0;
|
|
2144
|
+
for (const [start, end] of codeRanges(markdown)) {
|
|
2145
|
+
addMentions(found, markdown.slice(from, start));
|
|
2146
|
+
from = end;
|
|
2147
|
+
}
|
|
2148
|
+
addMentions(found, markdown.slice(from));
|
|
2149
|
+
return [...found].toSorted();
|
|
2150
|
+
}
|
|
2151
|
+
function mentionsAnywhere(text) {
|
|
2152
|
+
const found = /* @__PURE__ */ new Set();
|
|
2153
|
+
addMentions(found, text);
|
|
2154
|
+
return [...found].toSorted();
|
|
2155
|
+
}
|
|
1949
2156
|
|
|
1950
2157
|
// packages/board-core/dist/errors.js
|
|
1951
2158
|
var BoardError = class extends Error {
|
|
@@ -2591,33 +2798,59 @@ function filesOf(lines, status) {
|
|
|
2591
2798
|
return [...files.values()];
|
|
2592
2799
|
}
|
|
2593
2800
|
|
|
2801
|
+
// packages/board-core/dist/mentions.js
|
|
2802
|
+
import vm from "node:vm";
|
|
2803
|
+
var MENTION_PARSE_MS = 500;
|
|
2804
|
+
var context = vm.createContext({});
|
|
2805
|
+
var call = new vm.Script("work()");
|
|
2806
|
+
function within(work, ms) {
|
|
2807
|
+
let result;
|
|
2808
|
+
context["work"] = () => {
|
|
2809
|
+
result = work();
|
|
2810
|
+
};
|
|
2811
|
+
try {
|
|
2812
|
+
call.runInContext(context, { timeout: ms });
|
|
2813
|
+
} catch (error) {
|
|
2814
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
|
|
2815
|
+
return void 0;
|
|
2816
|
+
}
|
|
2817
|
+
throw error;
|
|
2818
|
+
} finally {
|
|
2819
|
+
context["work"] = void 0;
|
|
2820
|
+
}
|
|
2821
|
+
return result;
|
|
2822
|
+
}
|
|
2823
|
+
function postMentions(body) {
|
|
2824
|
+
return within(() => mentionsIn(body), MENTION_PARSE_MS) ?? mentionsAnywhere(body);
|
|
2825
|
+
}
|
|
2826
|
+
|
|
2594
2827
|
// packages/board-core/dist/metrics.js
|
|
2595
|
-
import { z as
|
|
2596
|
-
var TurnPayload =
|
|
2597
|
-
turnId:
|
|
2598
|
-
project:
|
|
2599
|
-
thread:
|
|
2600
|
-
channel:
|
|
2601
|
-
trigger:
|
|
2828
|
+
import { z as z13 } from "zod";
|
|
2829
|
+
var TurnPayload = z13.object({
|
|
2830
|
+
turnId: z13.string().optional(),
|
|
2831
|
+
project: z13.string(),
|
|
2832
|
+
thread: z13.string().optional(),
|
|
2833
|
+
channel: z13.string().optional(),
|
|
2834
|
+
trigger: z13.string()
|
|
2602
2835
|
});
|
|
2603
|
-
var TaskPayload =
|
|
2604
|
-
taskId:
|
|
2605
|
-
project:
|
|
2606
|
-
from:
|
|
2836
|
+
var TaskPayload = z13.object({
|
|
2837
|
+
taskId: z13.string(),
|
|
2838
|
+
project: z13.string(),
|
|
2839
|
+
from: z13.string().optional()
|
|
2607
2840
|
});
|
|
2608
|
-
var MessagePayload =
|
|
2609
|
-
id:
|
|
2610
|
-
channel:
|
|
2611
|
-
thread:
|
|
2612
|
-
mentions:
|
|
2841
|
+
var MessagePayload = z13.object({
|
|
2842
|
+
id: z13.string().optional(),
|
|
2843
|
+
channel: z13.string(),
|
|
2844
|
+
thread: z13.string().nullable().optional(),
|
|
2845
|
+
mentions: z13.array(z13.string()).default([])
|
|
2613
2846
|
});
|
|
2614
|
-
var SteeredPayload =
|
|
2615
|
-
var SignalPayload =
|
|
2616
|
-
kind:
|
|
2617
|
-
key:
|
|
2618
|
-
summary:
|
|
2619
|
-
taskId:
|
|
2620
|
-
project:
|
|
2847
|
+
var SteeredPayload = z13.object({ messages: z13.array(z13.string()) });
|
|
2848
|
+
var SignalPayload = z13.object({
|
|
2849
|
+
kind: z13.string(),
|
|
2850
|
+
key: z13.string(),
|
|
2851
|
+
summary: z13.string(),
|
|
2852
|
+
taskId: z13.string().optional(),
|
|
2853
|
+
project: z13.string().optional()
|
|
2621
2854
|
});
|
|
2622
2855
|
function median(values) {
|
|
2623
2856
|
const sorted = values.toSorted((a, b) => a - b);
|
|
@@ -2906,6 +3139,59 @@ function computeMetrics(input) {
|
|
|
2906
3139
|
};
|
|
2907
3140
|
}
|
|
2908
3141
|
|
|
3142
|
+
// packages/board-core/dist/turn-history.js
|
|
3143
|
+
import { z as z14 } from "zod";
|
|
3144
|
+
var TurnHistoryPayloadSchema = z14.object({
|
|
3145
|
+
project: NameSchema,
|
|
3146
|
+
thread: UlidSchema.optional(),
|
|
3147
|
+
channel: NameSchema.optional(),
|
|
3148
|
+
trigger: z14.string().default("manual"),
|
|
3149
|
+
exitReason: z14.string().nullable().default(null),
|
|
3150
|
+
costUsd: z14.number().default(0),
|
|
3151
|
+
usage: UsageSchema.optional(),
|
|
3152
|
+
model: z14.string().nullable().default(null),
|
|
3153
|
+
summary: z14.string().nullable().default(null),
|
|
3154
|
+
error: z14.string().nullable().default(null),
|
|
3155
|
+
toolCalls: z14.number().int().nonnegative().optional(),
|
|
3156
|
+
turnId: UlidSchema.optional()
|
|
3157
|
+
});
|
|
3158
|
+
function tokenUse(events, window, now) {
|
|
3159
|
+
const span = METRICS_WINDOW_MS[window];
|
|
3160
|
+
const since = span === null ? null : now.getTime() - span;
|
|
3161
|
+
const rows = /* @__PURE__ */ new Map();
|
|
3162
|
+
for (const event of events) {
|
|
3163
|
+
if (event.type !== "turn.completed" && event.type !== "turn.failed") {
|
|
3164
|
+
continue;
|
|
3165
|
+
}
|
|
3166
|
+
if (since !== null && Date.parse(event.ts) < since) {
|
|
3167
|
+
continue;
|
|
3168
|
+
}
|
|
3169
|
+
const turn = TurnHistoryPayloadSchema.safeParse(event.payload);
|
|
3170
|
+
if (!turn.success) {
|
|
3171
|
+
continue;
|
|
3172
|
+
}
|
|
3173
|
+
const row = rows.get(event.actor) ?? {
|
|
3174
|
+
agent: event.actor,
|
|
3175
|
+
turns: 0,
|
|
3176
|
+
withUsage: 0,
|
|
3177
|
+
usage: null
|
|
3178
|
+
};
|
|
3179
|
+
const usage = turn.data.usage;
|
|
3180
|
+
rows.set(event.actor, {
|
|
3181
|
+
agent: event.actor,
|
|
3182
|
+
turns: row.turns + 1,
|
|
3183
|
+
withUsage: row.withUsage + (usage === void 0 ? 0 : 1),
|
|
3184
|
+
usage: usage === void 0 ? row.usage : row.usage === null ? usage : addUsage(row.usage, usage)
|
|
3185
|
+
});
|
|
3186
|
+
}
|
|
3187
|
+
return {
|
|
3188
|
+
window,
|
|
3189
|
+
since: since === null ? null : new Date(since).toISOString(),
|
|
3190
|
+
until: now.toISOString(),
|
|
3191
|
+
citizens: [...rows.values()].toSorted((a, b) => a.agent.localeCompare(b.agent))
|
|
3192
|
+
};
|
|
3193
|
+
}
|
|
3194
|
+
|
|
2909
3195
|
// packages/board-core/dist/mutex.js
|
|
2910
3196
|
var Mutex = class {
|
|
2911
3197
|
tail = Promise.resolve();
|
|
@@ -3147,41 +3433,27 @@ function namesList(names) {
|
|
|
3147
3433
|
return names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names.at(-1) ?? ""}`;
|
|
3148
3434
|
}
|
|
3149
3435
|
var SKIPPED_IN_HOME = /* @__PURE__ */ new Set([".git", "turns", ".claude", ".codex"]);
|
|
3150
|
-
var RunnerTokensSchema =
|
|
3151
|
-
runners:
|
|
3436
|
+
var RunnerTokensSchema = z15.object({
|
|
3437
|
+
runners: z15.record(z15.string(), z15.object({ tokenHash: z15.string().min(1) }))
|
|
3152
3438
|
});
|
|
3153
|
-
var SignInsSchema =
|
|
3154
|
-
signIns:
|
|
3155
|
-
tokenHash:
|
|
3156
|
-
login:
|
|
3439
|
+
var SignInsSchema = z15.object({
|
|
3440
|
+
signIns: z15.array(z15.object({
|
|
3441
|
+
tokenHash: z15.string().min(1),
|
|
3442
|
+
login: z15.string().min(1),
|
|
3157
3443
|
/** The account's picture at the identity provider; sign-ins from before it have none. */
|
|
3158
|
-
avatarUrl:
|
|
3444
|
+
avatarUrl: z15.url().optional(),
|
|
3159
3445
|
createdAt: IsoDateTimeSchema,
|
|
3160
3446
|
expiresAt: IsoDateTimeSchema
|
|
3161
3447
|
})).default([])
|
|
3162
3448
|
});
|
|
3163
|
-
var
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
costUsd: z13.number().default(0),
|
|
3170
|
-
usage: UsageSchema.optional(),
|
|
3171
|
-
model: z13.string().nullable().default(null),
|
|
3172
|
-
summary: z13.string().nullable().default(null),
|
|
3173
|
-
error: z13.string().nullable().default(null),
|
|
3174
|
-
toolCalls: z13.number().int().nonnegative().optional(),
|
|
3175
|
-
turnId: UlidSchema.optional()
|
|
3176
|
-
});
|
|
3177
|
-
var TurnStartPayloadSchema = z13.object({ project: NameSchema, turnId: UlidSchema.optional() });
|
|
3178
|
-
var CursorsSchema = z13.object({
|
|
3179
|
-
digest: z13.string().nullable(),
|
|
3180
|
-
scopes: z13.record(z13.string(), z13.string()).default({}),
|
|
3181
|
-
threadsFrom: z13.record(z13.string(), z13.string().nullable()).default({}),
|
|
3182
|
-
channelsFrom: z13.record(z13.string(), z13.string().nullable()).default({}),
|
|
3449
|
+
var TurnStartPayloadSchema = z15.object({ project: NameSchema, turnId: UlidSchema.optional() });
|
|
3450
|
+
var CursorsSchema = z15.object({
|
|
3451
|
+
digest: z15.string().nullable(),
|
|
3452
|
+
scopes: z15.record(z15.string(), z15.string()).default({}),
|
|
3453
|
+
threadsFrom: z15.record(z15.string(), z15.string().nullable()).default({}),
|
|
3454
|
+
channelsFrom: z15.record(z15.string(), z15.string().nullable()).default({}),
|
|
3183
3455
|
/** How far a work role has read news, which goes to whichever of its general conversations reads first. */
|
|
3184
|
-
news:
|
|
3456
|
+
news: z15.string().optional()
|
|
3185
3457
|
});
|
|
3186
3458
|
var NO_CURSORS = { digest: null, scopes: {}, threadsFrom: {}, channelsFrom: {} };
|
|
3187
3459
|
function conversationKey(scope, part) {
|
|
@@ -3220,9 +3492,8 @@ function byId(a, b) {
|
|
|
3220
3492
|
function turnTime(record) {
|
|
3221
3493
|
return record.endedAt ?? record.startedAt;
|
|
3222
3494
|
}
|
|
3223
|
-
var PausedSchema =
|
|
3495
|
+
var PausedSchema = z15.object({ paused: z15.boolean() });
|
|
3224
3496
|
var DEFAULT_LEASE_MS = 30 * 60 * 1e3;
|
|
3225
|
-
var MENTION_PATTERN = /(^|[^\w@])@([a-z0-9][a-z0-9-]{0,31})(?![\w-])/g;
|
|
3226
3497
|
function withoutMentions(text) {
|
|
3227
3498
|
return text.replaceAll(MENTION_PATTERN, "$1$2");
|
|
3228
3499
|
}
|
|
@@ -3246,7 +3517,7 @@ var OPS_WAKE_TRIGGER = "ops_event";
|
|
|
3246
3517
|
var FRONT_DESK_TRIGGER = "user_post";
|
|
3247
3518
|
var OPS_CHANNELS = ["governance"];
|
|
3248
3519
|
var FRONT_DESK_CHANNELS = [ASK_CHANNEL];
|
|
3249
|
-
var AlignmentsSchema =
|
|
3520
|
+
var AlignmentsSchema = z15.object({ applied: z15.array(z15.string()).default([]) });
|
|
3250
3521
|
var FOLLOW_DECISIONS = "ops-readers-follow-decisions";
|
|
3251
3522
|
var THREAD_RECORDS = "threads-as-records";
|
|
3252
3523
|
var DIGEST_CURSORS = "digest-replaces-inbox";
|
|
@@ -3260,10 +3531,10 @@ var CHANNEL_CONVERSATIONS = "channel-conversations";
|
|
|
3260
3531
|
var DASHBOARD_UPDATES = "dashboard-updates-granted";
|
|
3261
3532
|
var CRON_VERBS = "cron-verbs-granted";
|
|
3262
3533
|
var KNOWLEDGE_NOTICES = "knowledge-notices";
|
|
3263
|
-
var KnowledgeEventSchema =
|
|
3534
|
+
var KnowledgeEventSchema = z15.object({
|
|
3264
3535
|
topic: NameSchema,
|
|
3265
3536
|
project: NameSchema.nullable(),
|
|
3266
|
-
replaced:
|
|
3537
|
+
replaced: z15.boolean().optional()
|
|
3267
3538
|
});
|
|
3268
3539
|
var CRON_VERB_NAMES = ["create_cron", "update_cron", "remove_cron"];
|
|
3269
3540
|
var OLD_DASHBOARD_LINE = "Agents may edit this file. It is rendered by the board UI.";
|
|
@@ -3381,16 +3652,6 @@ function unanswered(messages) {
|
|
|
3381
3652
|
}
|
|
3382
3653
|
return waiting;
|
|
3383
3654
|
}
|
|
3384
|
-
function extractMentions(body) {
|
|
3385
|
-
const found = /* @__PURE__ */ new Set();
|
|
3386
|
-
for (const match of body.matchAll(MENTION_PATTERN)) {
|
|
3387
|
-
const name = match[2];
|
|
3388
|
-
if (name !== void 0) {
|
|
3389
|
-
found.add(name);
|
|
3390
|
-
}
|
|
3391
|
-
}
|
|
3392
|
-
return [...found].toSorted();
|
|
3393
|
-
}
|
|
3394
3655
|
function snippetAround(text, query, radius = 80) {
|
|
3395
3656
|
const index = text.toLowerCase().indexOf(query.toLowerCase());
|
|
3396
3657
|
if (index === -1) {
|
|
@@ -3718,7 +3979,7 @@ var Board = class _Board {
|
|
|
3718
3979
|
}
|
|
3719
3980
|
}
|
|
3720
3981
|
for (const file of await listFiles(this.paths.tasks(slug))) {
|
|
3721
|
-
const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file),
|
|
3982
|
+
const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file), z15.record(z15.string(), z15.unknown()));
|
|
3722
3983
|
const legacy = raw.data["thread"];
|
|
3723
3984
|
if (legacy === void 0) {
|
|
3724
3985
|
continue;
|
|
@@ -3796,7 +4057,7 @@ var Board = class _Board {
|
|
|
3796
4057
|
* turns, so it follows nothing now.
|
|
3797
4058
|
*/
|
|
3798
4059
|
async renameInboxCursors() {
|
|
3799
|
-
const Legacy =
|
|
4060
|
+
const Legacy = z15.object({ inbox: z15.string().nullable() });
|
|
3800
4061
|
for (const agent of await this.listAgents()) {
|
|
3801
4062
|
const file = this.paths.agentCursors(agent.name);
|
|
3802
4063
|
if (await exists(file)) {
|
|
@@ -3842,7 +4103,7 @@ ${charter.purpose}
|
|
|
3842
4103
|
*/
|
|
3843
4104
|
async alignSeedRole(seed) {
|
|
3844
4105
|
const file = this.paths.role(seed.name);
|
|
3845
|
-
const raw = await readMarkdown(file,
|
|
4106
|
+
const raw = await readMarkdown(file, z15.record(z15.string(), z15.unknown()));
|
|
3846
4107
|
const current = RoleCharterSchema.parse(raw.data);
|
|
3847
4108
|
const verbsAdded = seed.verbs.filter((verb) => !current.verbs.includes(verb));
|
|
3848
4109
|
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));
|
|
@@ -4159,7 +4420,7 @@ ${charter.purpose}
|
|
|
4159
4420
|
/** The society's norms, the one knowledge topic every turn loads. Empty until the steward writes it. */
|
|
4160
4421
|
async readSocietyNorms() {
|
|
4161
4422
|
const file = this.paths.societyKnowledgeFile("norms");
|
|
4162
|
-
return await exists(file) ? (await readMarkdown(file,
|
|
4423
|
+
return await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
|
|
4163
4424
|
}
|
|
4164
4425
|
/** Knowledge topics of a project, or of the society when the project is null. */
|
|
4165
4426
|
async listKnowledge(project) {
|
|
@@ -4179,7 +4440,7 @@ ${charter.purpose}
|
|
|
4179
4440
|
*/
|
|
4180
4441
|
async knowledgeAt(file, project, topic) {
|
|
4181
4442
|
const { data, body } = await readLooseMarkdown(file);
|
|
4182
|
-
const revision =
|
|
4443
|
+
const revision = z15.number().int().min(0).safeParse(data["revision"]);
|
|
4183
4444
|
const updatedBy = NameSchema.safeParse(data["updatedBy"]);
|
|
4184
4445
|
const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
|
|
4185
4446
|
return {
|
|
@@ -4512,8 +4773,11 @@ ${DASHBOARD_LINE}
|
|
|
4512
4773
|
throw new BoardError("NOT_FOUND", `runner ${name} not found`);
|
|
4513
4774
|
}
|
|
4514
4775
|
const doc = await readMarkdown(file, RunnerSchema);
|
|
4776
|
+
const { gitIdentityMissing: reported, ...rest } = doc.data;
|
|
4777
|
+
const gitIdentityMissing = patch.gitIdentityMissing === void 0 ? reported : patch.gitIdentityMissing ?? void 0;
|
|
4515
4778
|
const next = RunnerSchema.parse({
|
|
4516
|
-
...
|
|
4779
|
+
...rest,
|
|
4780
|
+
...gitIdentityMissing === void 0 ? {} : { gitIdentityMissing: [...gitIdentityMissing] },
|
|
4517
4781
|
...patch.status === void 0 ? {} : { status: patch.status },
|
|
4518
4782
|
...patch.os === void 0 ? {} : { os: patch.os },
|
|
4519
4783
|
...patch.clis === void 0 ? {} : { clis: [...patch.clis] },
|
|
@@ -4541,6 +4805,36 @@ ${DASHBOARD_LINE}
|
|
|
4541
4805
|
return next;
|
|
4542
4806
|
});
|
|
4543
4807
|
}
|
|
4808
|
+
/**
|
|
4809
|
+
* Records a CLI's plan quota as a runner reported it, from a turn's stream or a read, merged over
|
|
4810
|
+
* what the record held. The record is written on every report, so it says when the numbers were
|
|
4811
|
+
* last seen; `runner.quota` is appended only when what a reader would see changes, since every
|
|
4812
|
+
* turn reports.
|
|
4813
|
+
*/
|
|
4814
|
+
async recordQuota(name, cli, quota) {
|
|
4815
|
+
return this.mutex.run(async () => {
|
|
4816
|
+
const file = this.paths.runner(name);
|
|
4817
|
+
if (!await exists(file)) {
|
|
4818
|
+
throw new BoardError("NOT_FOUND", `runner ${name} not found`);
|
|
4819
|
+
}
|
|
4820
|
+
const doc = await readMarkdown(file, RunnerSchema);
|
|
4821
|
+
const previous = doc.data.quotas?.[cli];
|
|
4822
|
+
const merged = mergeQuota(previous, quota);
|
|
4823
|
+
const next = RunnerSchema.parse({
|
|
4824
|
+
...doc.data,
|
|
4825
|
+
quotas: { ...doc.data.quotas, [cli]: merged }
|
|
4826
|
+
});
|
|
4827
|
+
await writeMarkdown(file, next, doc.body);
|
|
4828
|
+
if (quotaChanged(previous, merged)) {
|
|
4829
|
+
await this.events.append("runner.quota", SYSTEM_ACTOR.name, {
|
|
4830
|
+
name,
|
|
4831
|
+
cli,
|
|
4832
|
+
status: merged.status
|
|
4833
|
+
});
|
|
4834
|
+
}
|
|
4835
|
+
return next;
|
|
4836
|
+
});
|
|
4837
|
+
}
|
|
4544
4838
|
/**
|
|
4545
4839
|
* Logs an operations signal as an `ops.signal` event. No channel carries it: the scheduler wakes
|
|
4546
4840
|
* its readers from the event, the runner lists it in their prompts, and the interface's log shows
|
|
@@ -6375,7 +6669,7 @@ ${rationale}`}`);
|
|
|
6375
6669
|
}
|
|
6376
6670
|
async readAgentRoleBody(agent) {
|
|
6377
6671
|
const file = this.paths.agentRole(agent);
|
|
6378
|
-
return await exists(file) ? (await readMarkdown(file,
|
|
6672
|
+
return await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
|
|
6379
6673
|
}
|
|
6380
6674
|
/** The steps of one finished turn, as the runner handed them over when it ended. */
|
|
6381
6675
|
/**
|
|
@@ -6406,6 +6700,14 @@ ${rationale}`}`);
|
|
|
6406
6700
|
}
|
|
6407
6701
|
return computeMetrics({ events, tasks, citizens, actions, activeSignals, window, now });
|
|
6408
6702
|
}
|
|
6703
|
+
/**
|
|
6704
|
+
* Each citizen's finished turns over a window and the tokens of those that counted them, from
|
|
6705
|
+
* the event log alone, which holds every turn's end whatever runner it ran on.
|
|
6706
|
+
*/
|
|
6707
|
+
async tokenUse(window) {
|
|
6708
|
+
const events = await this.events.readSince(null, Number.MAX_SAFE_INTEGER);
|
|
6709
|
+
return tokenUse(events, window, this.now());
|
|
6710
|
+
}
|
|
6409
6711
|
/** The board actions a finished turn took, from its transcript; null when it kept none. */
|
|
6410
6712
|
async turnActions(agent, turnId) {
|
|
6411
6713
|
const known = this.actionCounts.get(turnId);
|
|
@@ -6775,7 +7077,7 @@ ${rationale}`}`);
|
|
|
6775
7077
|
return { project: slug, revision: 0, body: "" };
|
|
6776
7078
|
}
|
|
6777
7079
|
const { data, body } = await readLooseMarkdown(file);
|
|
6778
|
-
const revision =
|
|
7080
|
+
const revision = z15.number().int().min(0).safeParse(data["revision"]);
|
|
6779
7081
|
const updatedBy = NameSchema.safeParse(data["updatedBy"]);
|
|
6780
7082
|
const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
|
|
6781
7083
|
return {
|
|
@@ -7066,7 +7368,7 @@ ${seed}
|
|
|
7066
7368
|
continue;
|
|
7067
7369
|
}
|
|
7068
7370
|
const file = this.paths.agentRole(agent.name);
|
|
7069
|
-
const body = await exists(file) ? (await readMarkdown(file,
|
|
7371
|
+
const body = await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
|
|
7070
7372
|
const at = body.indexOf(`
|
|
7071
7373
|
${SEED_INSTRUCTIONS_HEADING}
|
|
7072
7374
|
`);
|
|
@@ -7904,7 +8206,7 @@ ${charter.purpose}
|
|
|
7904
8206
|
id: this.newId(),
|
|
7905
8207
|
...head,
|
|
7906
8208
|
ts: this.now().toISOString(),
|
|
7907
|
-
mentions:
|
|
8209
|
+
mentions: postMentions(body)
|
|
7908
8210
|
});
|
|
7909
8211
|
const { author } = head;
|
|
7910
8212
|
await writeMarkdown(this.paths.messageFile(dir, frontmatter.id, author), frontmatter, body);
|
|
@@ -8282,7 +8584,7 @@ function decideWake(input) {
|
|
|
8282
8584
|
}
|
|
8283
8585
|
|
|
8284
8586
|
// packages/scheduler/dist/scheduler.js
|
|
8285
|
-
import { z as
|
|
8587
|
+
import { z as z16 } from "zod";
|
|
8286
8588
|
function besideFields(beside) {
|
|
8287
8589
|
if (beside === void 0) {
|
|
8288
8590
|
return {};
|
|
@@ -8309,21 +8611,21 @@ var DEFAULT_TIMINGS = Object.freeze({
|
|
|
8309
8611
|
scaleCooldownMs: 36e5,
|
|
8310
8612
|
reflectionMs: 24 * 36e5
|
|
8311
8613
|
});
|
|
8312
|
-
var SchedulerTimingsSchema =
|
|
8313
|
-
pollMs:
|
|
8314
|
-
debounceMs:
|
|
8315
|
-
userDebounceMs:
|
|
8316
|
-
heartbeatMs:
|
|
8317
|
-
waitingStageMs:
|
|
8318
|
-
leaseSweepMs:
|
|
8319
|
-
opsIntervalMs:
|
|
8320
|
-
signalRepeatMs:
|
|
8321
|
-
costReportMs:
|
|
8322
|
-
staleThreadMs:
|
|
8323
|
-
idleMemberMs:
|
|
8324
|
-
homeConflictMs:
|
|
8325
|
-
scaleCooldownMs:
|
|
8326
|
-
reflectionMs:
|
|
8614
|
+
var SchedulerTimingsSchema = z16.object({
|
|
8615
|
+
pollMs: z16.number().positive(),
|
|
8616
|
+
debounceMs: z16.number().nonnegative(),
|
|
8617
|
+
userDebounceMs: z16.number().nonnegative(),
|
|
8618
|
+
heartbeatMs: z16.number().positive(),
|
|
8619
|
+
waitingStageMs: z16.number().positive(),
|
|
8620
|
+
leaseSweepMs: z16.number().positive(),
|
|
8621
|
+
opsIntervalMs: z16.number().positive(),
|
|
8622
|
+
signalRepeatMs: z16.number().positive(),
|
|
8623
|
+
costReportMs: z16.number().positive(),
|
|
8624
|
+
staleThreadMs: z16.number().positive(),
|
|
8625
|
+
idleMemberMs: z16.number().positive(),
|
|
8626
|
+
homeConflictMs: z16.number().positive(),
|
|
8627
|
+
scaleCooldownMs: z16.number().positive(),
|
|
8628
|
+
reflectionMs: z16.number().positive()
|
|
8327
8629
|
}).partial();
|
|
8328
8630
|
function parseTimings(input) {
|
|
8329
8631
|
const parsed = SchedulerTimingsSchema.parse(input);
|
|
@@ -8335,32 +8637,32 @@ function parseTimings(input) {
|
|
|
8335
8637
|
}
|
|
8336
8638
|
return overrides;
|
|
8337
8639
|
}
|
|
8338
|
-
var PendingSchema =
|
|
8640
|
+
var PendingSchema = z16.object({
|
|
8339
8641
|
dispatch: TurnDispatchSchema,
|
|
8340
|
-
readyAt:
|
|
8341
|
-
stageWakes:
|
|
8342
|
-
holder:
|
|
8642
|
+
readyAt: z16.number(),
|
|
8643
|
+
stageWakes: z16.array(TriggerSchema).optional(),
|
|
8644
|
+
holder: z16.boolean().optional(),
|
|
8343
8645
|
newestMessage: UlidSchema.optional(),
|
|
8344
|
-
onlyMessages:
|
|
8646
|
+
onlyMessages: z16.boolean().optional(),
|
|
8345
8647
|
steeredThrough: UlidSchema.optional(),
|
|
8346
|
-
onlyCrons:
|
|
8648
|
+
onlyCrons: z16.boolean().optional()
|
|
8347
8649
|
});
|
|
8348
|
-
var StateSchema =
|
|
8349
|
-
cursor:
|
|
8350
|
-
lastHeartbeat:
|
|
8650
|
+
var StateSchema = z16.object({
|
|
8651
|
+
cursor: z16.string().nullable(),
|
|
8652
|
+
lastHeartbeat: z16.record(z16.string(), z16.string()),
|
|
8351
8653
|
/** Waiting stages already signalled, as `task:stage`, so each is logged once while it waits. */
|
|
8352
|
-
waitingSeen:
|
|
8654
|
+
waitingSeen: z16.record(z16.string(), z16.string()).default({}),
|
|
8353
8655
|
/** Queued dispatches survive a restart; the cursor has already moved past the events that made them. */
|
|
8354
|
-
pending:
|
|
8355
|
-
opsReported:
|
|
8356
|
-
releaseCounts:
|
|
8357
|
-
lastOps:
|
|
8358
|
-
lastScaled:
|
|
8359
|
-
lastCostReport:
|
|
8360
|
-
costSinceReport:
|
|
8361
|
-
turnsSinceReport:
|
|
8656
|
+
pending: z16.record(z16.string(), PendingSchema).default({}),
|
|
8657
|
+
opsReported: z16.record(z16.string(), z16.string()).default({}),
|
|
8658
|
+
releaseCounts: z16.record(z16.string(), z16.number().int().nonnegative()).default({}),
|
|
8659
|
+
lastOps: z16.string().nullable().default(null),
|
|
8660
|
+
lastScaled: z16.record(z16.string(), z16.string()).default({}),
|
|
8661
|
+
lastCostReport: z16.string().nullable().default(null),
|
|
8662
|
+
costSinceReport: z16.number().nonnegative().default(0),
|
|
8663
|
+
turnsSinceReport: z16.number().int().nonnegative().default(0),
|
|
8362
8664
|
/** When each member last reflected, or was first seen; the cadence counts from here. */
|
|
8363
|
-
lastReflection:
|
|
8665
|
+
lastReflection: z16.record(z16.string(), z16.string()).default({})
|
|
8364
8666
|
});
|
|
8365
8667
|
function messageOf(trigger) {
|
|
8366
8668
|
return trigger.kind === "mention" || trigger.kind === "user_post" ? trigger.messageId : void 0;
|
|
@@ -9933,7 +10235,7 @@ var TURN_CONTRACT = [
|
|
|
9933
10235
|
"- Posts that would wake this conversation may arrive while you work, delivered into the turn under a heading that says so and formatted like the digest. They are part of this turn: act on them now, after the step in hand, or not at all, as with the digest. The user may also stop a turn; the next turn is told.",
|
|
9934
10236
|
"- Silence is allowed. If the digest needs no reply, post nothing.",
|
|
9935
10237
|
"- To come back to something later, set a cron with create_cron: a note on what to do then, and a five-field cron expression or one time with at. It wakes you in this conversation unless you name another, at most every fifteen minutes, and every fire is a paid turn, so end a cron with remove_cron once it has done its job. Never wait by holding a stage, sleeping, or leaving a process running: a turn's board token ends with the turn, so nothing it leaves behind can act on the board. The society's crons are under society/crons/ in the board projection.",
|
|
9936
|
-
"- An @mention wakes the citizen named, and every wake costs a turn. Address someone with @ only when you need them to act; when you merely refer to citizens, write their names plainly. @user wakes nobody, since the user takes no turns; it is what puts a question before the user, so use it only when you need the user to answer or decide.",
|
|
10238
|
+
"- An @mention wakes the citizen named, and every wake costs a turn. Address someone with @ only when you need them to act; when you merely refer to citizens, write their names plainly. A name in a code span or a code block is no mention, so code keeps its @ as written. @user wakes nobody, since the user takes no turns; it is what puts a question before the user, so use it only when you need the user to answer or decide.",
|
|
9937
10239
|
"- A thread is a conversation off a channel that reaches only its participants and whoever is mentioned in it. Every task has one, opened with it under the task's id on the channel of its project it was filed in, general unless it was filed in another: talk about a task there, with post_message and its thread_id, and the notes you give advance_task and update_task are posted there as you. Its participants are the task's creator, its stage holders and assignees, whoever may take the stage that waits, and anyone who posted; it closes when the task ends. Every proposal has one too, in governance, opened with its pitch and closed by its decision. Open other threads with open_thread on a channel with a title, for any other topic; close_thread posts your summary to its channel.",
|
|
9938
10240
|
"- To show an image in a post, such as a screenshot or a chart, commit the file to a task's branch and link it by its path in the task's worktree, as ``: the board shows a file on a task's branch in place once it is committed, at the latest when your turn ends. An image at an https address shows too. Never put an image or any other file into a message as base64 or a data: URL: the board does not show it, and every reader of the conversation gets it in full in their prompt.",
|
|
9939
10241
|
"- Route every lesson: about you, your craft, or the user, write it to memory/core.md in your home directory, and keep that file short by moving detail to memory/<topic>.md, your archive; a durable fact about a project's codebase or process goes through `write_knowledge` on that project; something the whole project should know now, post it to the project channel, and anything about one task, in the task's thread.",
|
|
@@ -9967,15 +10269,15 @@ var GOVERNANCE = [
|
|
|
9967
10269
|
"- Prefer scaling an existing role over inventing one, with a reallocation of its replicas, backlog threshold, wakes, or verbs; a new role is justified by work a project needs that no existing role covers. A role that needs a tool the board lacks is an engineering task, not a hiring request.",
|
|
9968
10270
|
"- Operations signals are counters and timers the board logs, listed in the prompt of a role that reads them: stages waiting for a holder, backlog per role, stages waiting on a role nobody fills, churn, stale threads, idle members, missing capabilities, replicas added, spend. They are not posts in any channel; interpreting them is your judgment."
|
|
9969
10271
|
].join("\n");
|
|
9970
|
-
function renderOnboardingPreamble(
|
|
10272
|
+
function renderOnboardingPreamble(context2) {
|
|
9971
10273
|
return [
|
|
9972
|
-
`This is your first turn as ${
|
|
10274
|
+
`This is your first turn as ${context2.agentName}.`,
|
|
9973
10275
|
"",
|
|
9974
|
-
`Your role in one paragraph: ${
|
|
10276
|
+
`Your role in one paragraph: ${context2.roleSummary}`,
|
|
9975
10277
|
"",
|
|
9976
|
-
`You are working on project "${
|
|
9977
|
-
...(
|
|
9978
|
-
`You follow its general channel. It also has ${(
|
|
10278
|
+
`You are working on project "${context2.project}" in the worktree at ${context2.worktree}.`,
|
|
10279
|
+
...(context2.otherChannels ?? []).length === 0 ? [] : [
|
|
10280
|
+
`You follow its general channel. It also has ${(context2.otherChannels ?? []).map((ref) => `#${ref}`).join(", ")}, each a workstream such as a release: subscribe to one when your work there needs its posts. Its tasks and mentions reach you either way.`
|
|
9979
10281
|
],
|
|
9980
10282
|
"Your memory is empty. Write durable lessons about yourself, your craft, or the user to memory/core.md in your home directory.",
|
|
9981
10283
|
"Write profile.md in your home directory: one paragraph on what you do well and what to send your way. The roster the front desk routes with is built from it.",
|
|
@@ -10061,10 +10363,25 @@ function signalLine(ts, signal) {
|
|
|
10061
10363
|
].filter((fact) => fact.length > 0);
|
|
10062
10364
|
return `- [${ts}] ${signal.kind}: ${signal.summary} (${facts.join("; ")})`;
|
|
10063
10365
|
}
|
|
10064
|
-
function
|
|
10366
|
+
function quotaPhrase(cli, quota, now) {
|
|
10367
|
+
const level = quotaLevel(quota, now);
|
|
10368
|
+
if (level === "none") {
|
|
10369
|
+
return `${cli} reports no plan limits`;
|
|
10370
|
+
}
|
|
10371
|
+
if (level === "limited") {
|
|
10372
|
+
return `${cli} limited until ${quota.limitedUntil ?? "an unknown time"}`;
|
|
10373
|
+
}
|
|
10374
|
+
const windows = quota.windows.map((window) => !windowCurrent(window, now) ? `${windowName(window)} reset since` : `${windowName(window)} ${window.usedPercent === null ? "?" : Math.floor(window.usedPercent)}%`);
|
|
10375
|
+
return `${cli} ${windows.length === 0 ? "allowed" : windows.join(", ")}${level === "warning" ? " (near a limit)" : ""} as of ${quota.observedAt}`;
|
|
10376
|
+
}
|
|
10377
|
+
function runnerLine(runner, projects, now) {
|
|
10065
10378
|
const living = projects.filter((project) => project.runner === runner.name).map((project) => project.slug);
|
|
10066
10379
|
const state = runner.status === "connected" ? "connected" : `away${runner.lastSeen === void 0 ? "" : ` since ${runner.lastSeen}`}`;
|
|
10067
|
-
|
|
10380
|
+
const quotas = runner.clis.flatMap((cli) => {
|
|
10381
|
+
const quota = runner.quotas?.[cli];
|
|
10382
|
+
return quota === void 0 ? [] : [quotaPhrase(cli, quota, now)];
|
|
10383
|
+
});
|
|
10384
|
+
return `- ${runner.name}: ${state}; ${runner.os}; CLIs ${runner.clis.length === 0 ? "none" : runner.clis.join(", ")}; offers ${runner.capabilities.length === 0 ? "nothing beyond its CLIs" : runner.capabilities.join(", ")}; ${living.length === 0 ? "no projects" : `projects ${living.join(", ")}`}${quotas.length === 0 ? "" : `; quota ${quotas.join("; ")}`}`;
|
|
10068
10385
|
}
|
|
10069
10386
|
function profileLine(profile) {
|
|
10070
10387
|
const line = profile.split("\n").map((entry) => entry.trim()).find((entry) => entry.length > 0 && !entry.startsWith("#"));
|
|
@@ -10214,12 +10531,12 @@ function buildTurnPrompt(input) {
|
|
|
10214
10531
|
}
|
|
10215
10532
|
const machines = input.runners;
|
|
10216
10533
|
if (machines !== void 0 && machines !== null) {
|
|
10217
|
-
lines.push("", "## Runners", "", "The machines turns run on. A project lives on the runner that takes its first turn, one that offers every capability the project and that turn's task require, and never moves. A task's required_capabilities must name capabilities exactly as a runner below offers them; a task needing one its project's runner lacks waits.", "");
|
|
10534
|
+
lines.push("", "## Runners", "", "The machines turns run on. A project lives on the runner that takes its first turn, one that offers every capability the project and that turn's task require, and never moves. A task's required_capabilities must name capabilities exactly as a runner below offers them; a task needing one its project's runner lacks waits. A runner's quota is what each CLI's login there last reported of its plan, in percent of each window; a CLI limited until a time fails its turns there until then.", "");
|
|
10218
10535
|
if (machines.runners.length === 0) {
|
|
10219
10536
|
lines.push("None registered yet.");
|
|
10220
10537
|
}
|
|
10221
10538
|
for (const runner of machines.runners) {
|
|
10222
|
-
lines.push(runnerLine(runner, machines.projects));
|
|
10539
|
+
lines.push(runnerLine(runner, machines.projects, input.clock?.now ?? /* @__PURE__ */ new Date()));
|
|
10223
10540
|
}
|
|
10224
10541
|
}
|
|
10225
10542
|
const knowledge = input.knowledge;
|
|
@@ -10752,6 +11069,11 @@ var TurnHost = class {
|
|
|
10752
11069
|
}
|
|
10753
11070
|
}
|
|
10754
11071
|
});
|
|
11072
|
+
if (outcome.quota !== void 0) {
|
|
11073
|
+
await this.board.recordQuota(turn.runner, job.cli, outcome.quota).catch((error) => {
|
|
11074
|
+
this.log.warn({ runner: turn.runner, cli: job.cli, error: String(error) }, "could not record a quota");
|
|
11075
|
+
});
|
|
11076
|
+
}
|
|
10755
11077
|
if (recorded) {
|
|
10756
11078
|
this.log.info({
|
|
10757
11079
|
agent: job.agent,
|
|
@@ -11081,7 +11403,8 @@ var RunnerHub = class {
|
|
|
11081
11403
|
os: hello.os,
|
|
11082
11404
|
clis: hello.clis,
|
|
11083
11405
|
capabilities: hello.capabilities,
|
|
11084
|
-
version: hello.version
|
|
11406
|
+
version: hello.version,
|
|
11407
|
+
gitIdentityMissing: hello.gitIdentityMissing ?? null
|
|
11085
11408
|
});
|
|
11086
11409
|
this.runnerChanged(name);
|
|
11087
11410
|
this.log.info({ runner: name, version: hello.version, clis: hello.clis, slots: hello.slots }, "runner registered");
|
|
@@ -11523,6 +11846,26 @@ var RunnerHub = class {
|
|
|
11523
11846
|
}
|
|
11524
11847
|
return ModelListSchema.parse(await this.request(seat, (request) => ({ type: "models", request, cli })));
|
|
11525
11848
|
}
|
|
11849
|
+
/**
|
|
11850
|
+
* A CLI's plan quota, read on a runner without a turn and recorded on the runner's record.
|
|
11851
|
+
* Refused for a runner not connected with the CLI, and for one from before quota reads, which
|
|
11852
|
+
* would skip the request and leave the reader waiting.
|
|
11853
|
+
*/
|
|
11854
|
+
async quota(runner, cli) {
|
|
11855
|
+
const seat = this.seats.get(runner);
|
|
11856
|
+
if (seat === void 0 || seat.send === null || !seat.hello.clis.includes(cli)) {
|
|
11857
|
+
throw new RunnerAwayError(`runner ${runner} is not connected with ${cli}`);
|
|
11858
|
+
}
|
|
11859
|
+
if (!seat.hello.quotaReads) {
|
|
11860
|
+
throw new BoardError("INVALID_STATE", `runner ${runner} cannot read quotas yet; upgrade it`);
|
|
11861
|
+
}
|
|
11862
|
+
const quota = CliQuotaSchema.nullable().parse(await this.request(seat, (request) => ({ type: "quota", request, cli }), FILE_TIMEOUT_MS));
|
|
11863
|
+
if (quota === null) {
|
|
11864
|
+
throw new BoardError("NOT_FOUND", `${cli} on runner ${runner} cannot read its quota`);
|
|
11865
|
+
}
|
|
11866
|
+
await this.board.recordQuota(runner, cli, quota);
|
|
11867
|
+
return quota;
|
|
11868
|
+
}
|
|
11526
11869
|
/** Calls `listener` whenever a runner registers, connects, or goes away. */
|
|
11527
11870
|
onRunnerChange(listener) {
|
|
11528
11871
|
this.runnerListeners.add(listener);
|
|
@@ -11755,20 +12098,20 @@ async function handleMcpRequest(board2, actor, request, version) {
|
|
|
11755
12098
|
import { Hono as Hono3 } from "hono";
|
|
11756
12099
|
import { compress } from "hono/compress";
|
|
11757
12100
|
import { streamSSE as streamSSE2 } from "hono/streaming";
|
|
11758
|
-
import { z as
|
|
12101
|
+
import { z as z18, ZodError } from "zod";
|
|
11759
12102
|
|
|
11760
12103
|
// apps/server/dist/github-auth.js
|
|
11761
12104
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
11762
12105
|
import { Hono } from "hono";
|
|
11763
|
-
import { z as
|
|
12106
|
+
import { z as z17 } from "zod";
|
|
11764
12107
|
var SIGN_IN_TTL_MS = 30 * 24 * 36e5;
|
|
11765
12108
|
var STATE_TTL_MS = 10 * 6e4;
|
|
11766
12109
|
var MAX_STATES = 1e3;
|
|
11767
|
-
var TokenAnswerSchema =
|
|
11768
|
-
var GithubUserSchema =
|
|
11769
|
-
login:
|
|
11770
|
-
id:
|
|
11771
|
-
avatar_url:
|
|
12110
|
+
var TokenAnswerSchema = z17.object({ access_token: z17.string().min(1) });
|
|
12111
|
+
var GithubUserSchema = z17.object({
|
|
12112
|
+
login: z17.string().min(1),
|
|
12113
|
+
id: z17.number().int(),
|
|
12114
|
+
avatar_url: z17.string().optional()
|
|
11772
12115
|
});
|
|
11773
12116
|
function githubAvatar(url) {
|
|
11774
12117
|
try {
|
|
@@ -12191,7 +12534,7 @@ async function isFile(file) {
|
|
|
12191
12534
|
return false;
|
|
12192
12535
|
}
|
|
12193
12536
|
}
|
|
12194
|
-
function
|
|
12537
|
+
function within2(root, pathname) {
|
|
12195
12538
|
let decoded;
|
|
12196
12539
|
try {
|
|
12197
12540
|
decoded = decodeURIComponent(pathname);
|
|
@@ -12208,7 +12551,7 @@ function spaHandler(staticDir) {
|
|
|
12208
12551
|
if (pathname.startsWith("/api/")) {
|
|
12209
12552
|
return c.json({ error: "NOT_FOUND", message: `no route ${pathname}` }, 404);
|
|
12210
12553
|
}
|
|
12211
|
-
const file =
|
|
12554
|
+
const file = within2(root, pathname);
|
|
12212
12555
|
const headers = { "x-content-type-options": "nosniff" };
|
|
12213
12556
|
if (file !== null && await isFile(file)) {
|
|
12214
12557
|
return c.body(await readFile5(file), 200, {
|
|
@@ -12243,19 +12586,19 @@ var ERROR_STATUS = {
|
|
|
12243
12586
|
INVALID_STATE: 409
|
|
12244
12587
|
};
|
|
12245
12588
|
var EVENT_PAGE = 100;
|
|
12246
|
-
var RetireBodySchema =
|
|
12247
|
-
var RunnerBodySchema =
|
|
12248
|
-
var EnrollmentApprovalSchema =
|
|
12249
|
-
var HomeRunnerBodySchema =
|
|
12250
|
-
var ModelBodySchema =
|
|
12251
|
-
var EffortBodySchema =
|
|
12252
|
-
var HistoryLimitSchema =
|
|
12253
|
-
var MessageIdsSchema =
|
|
12254
|
-
var TimezoneBodySchema =
|
|
12255
|
-
var ChannelBodySchema =
|
|
12589
|
+
var RetireBodySchema = z18.object({ reason: z18.string().min(1) });
|
|
12590
|
+
var RunnerBodySchema = z18.object({ name: NameSchema });
|
|
12591
|
+
var EnrollmentApprovalSchema = z18.object({ name: NameSchema });
|
|
12592
|
+
var HomeRunnerBodySchema = z18.object({ runner: NameSchema.nullable() });
|
|
12593
|
+
var ModelBodySchema = z18.object({ model: ModelNameSchema.nullable() });
|
|
12594
|
+
var EffortBodySchema = z18.object({ effort: EffortSchema.nullable() });
|
|
12595
|
+
var HistoryLimitSchema = z18.coerce.number().int().min(1).max(500);
|
|
12596
|
+
var MessageIdsSchema = z18.string().transform((ids) => ids.split(",").filter((id) => id !== "")).pipe(z18.array(UlidSchema).min(1).max(MESSAGE_LOOKUP_LIMIT));
|
|
12597
|
+
var TimezoneBodySchema = z18.object({ timezone: TimeZoneSchema });
|
|
12598
|
+
var ChannelBodySchema = z18.object({
|
|
12256
12599
|
project: NameSchema.nullable().default(null),
|
|
12257
12600
|
name: NameSchema,
|
|
12258
|
-
purpose:
|
|
12601
|
+
purpose: z18.string().min(1)
|
|
12259
12602
|
});
|
|
12260
12603
|
function bearer2(c) {
|
|
12261
12604
|
const header = c.req.header("authorization") ?? "";
|
|
@@ -12263,7 +12606,7 @@ function bearer2(c) {
|
|
|
12263
12606
|
return match?.[1]?.trim() ?? null;
|
|
12264
12607
|
}
|
|
12265
12608
|
function createApp(deps) {
|
|
12266
|
-
const { board: board2, version, turns: turns2, scheduler: scheduler2, models } = deps;
|
|
12609
|
+
const { board: board2, version, turns: turns2, scheduler: scheduler2, models, quotas } = deps;
|
|
12267
12610
|
const eventStreamPingMs = deps.eventStreamPingMs ?? 15e3;
|
|
12268
12611
|
const app2 = new Hono3();
|
|
12269
12612
|
app2.get("/health", (c) => c.json({ ok: true, version }));
|
|
@@ -12333,6 +12676,17 @@ function createApp(deps) {
|
|
|
12333
12676
|
api.get("/agents/:name/history/:commit", async (c) => c.json(await board2.homeChange(c.req.param("name"), c.req.param("commit"))));
|
|
12334
12677
|
api.get("/roles", async (c) => c.json(await board2.listRoles()));
|
|
12335
12678
|
api.get("/runners", async (c) => c.json(await board2.listRunners()));
|
|
12679
|
+
api.post("/runners/:name/quota/:cli", async (c) => {
|
|
12680
|
+
if (c.get("actor").role !== USER_ROLE) {
|
|
12681
|
+
throw new BoardError("FORBIDDEN", "only the user reads a runner's quota");
|
|
12682
|
+
}
|
|
12683
|
+
const runner = NameSchema.parse(c.req.param("name"));
|
|
12684
|
+
const cli = CliKindSchema.parse(c.req.param("cli"));
|
|
12685
|
+
if (quotas === void 0) {
|
|
12686
|
+
throw new RunnerAwayError("this server asks no runner for quotas");
|
|
12687
|
+
}
|
|
12688
|
+
return c.json(await quotas.read(runner, cli));
|
|
12689
|
+
});
|
|
12336
12690
|
api.post("/runners", async (c) => {
|
|
12337
12691
|
const body = RunnerBodySchema.parse(await c.req.json());
|
|
12338
12692
|
return c.json(await board2.addRunner(c.get("actor"), body.name));
|
|
@@ -12369,6 +12723,10 @@ function createApp(deps) {
|
|
|
12369
12723
|
const window = MetricsWindowSchema.parse(c.req.query("window") ?? "7d");
|
|
12370
12724
|
return c.json(await board2.metrics(window, new Set(scheduler2?.activeSignals ?? [])));
|
|
12371
12725
|
});
|
|
12726
|
+
api.get("/tokens", async (c) => {
|
|
12727
|
+
const window = MetricsWindowSchema.parse(c.req.query("window") ?? "24h");
|
|
12728
|
+
return c.json(await board2.tokenUse(window));
|
|
12729
|
+
});
|
|
12372
12730
|
api.get("/society/knowledge", async (c) => c.json(await board2.listKnowledge(null)));
|
|
12373
12731
|
api.get("/skills", async (c) => c.json(await board2.listSocietySkills()));
|
|
12374
12732
|
api.post("/agents/:name/retire", async (c) => {
|
|
@@ -12412,7 +12770,7 @@ function createApp(deps) {
|
|
|
12412
12770
|
});
|
|
12413
12771
|
api.put("/roles/:name", async (c) => {
|
|
12414
12772
|
const charter = RoleCharterSchema.parse({
|
|
12415
|
-
...
|
|
12773
|
+
...z18.record(z18.string(), z18.unknown()).parse(await c.req.json()),
|
|
12416
12774
|
name: c.req.param("name")
|
|
12417
12775
|
});
|
|
12418
12776
|
return c.json(await board2.setRoleCharter(c.get("actor"), charter));
|
|
@@ -12762,6 +13120,35 @@ var ModelCatalog = class {
|
|
|
12762
13120
|
}
|
|
12763
13121
|
};
|
|
12764
13122
|
|
|
13123
|
+
// apps/server/dist/quotas.js
|
|
13124
|
+
var MINUTE = 6e4;
|
|
13125
|
+
var QuotaReads = class {
|
|
13126
|
+
runners;
|
|
13127
|
+
floorMs;
|
|
13128
|
+
now;
|
|
13129
|
+
kept = /* @__PURE__ */ new Map();
|
|
13130
|
+
constructor(runners2, floorMs = MINUTE, now = Date.now) {
|
|
13131
|
+
this.runners = runners2;
|
|
13132
|
+
this.floorMs = floorMs;
|
|
13133
|
+
this.now = now;
|
|
13134
|
+
}
|
|
13135
|
+
read(runner, cli) {
|
|
13136
|
+
const key = `${runner}/${cli}`;
|
|
13137
|
+
const kept = this.kept.get(key);
|
|
13138
|
+
if (kept !== void 0 && this.now() - kept.at < this.floorMs) {
|
|
13139
|
+
return kept.quota;
|
|
13140
|
+
}
|
|
13141
|
+
const quota = this.runners.quota(runner, cli);
|
|
13142
|
+
this.kept.set(key, { at: this.now(), quota });
|
|
13143
|
+
quota.catch(() => {
|
|
13144
|
+
if (this.kept.get(key)?.quota === quota) {
|
|
13145
|
+
this.kept.delete(key);
|
|
13146
|
+
}
|
|
13147
|
+
});
|
|
13148
|
+
return quota;
|
|
13149
|
+
}
|
|
13150
|
+
};
|
|
13151
|
+
|
|
12765
13152
|
// apps/server/dist/turn-hub.js
|
|
12766
13153
|
var TurnHub = class {
|
|
12767
13154
|
capacity;
|
|
@@ -12869,6 +13256,7 @@ var app = createApp({
|
|
|
12869
13256
|
turns,
|
|
12870
13257
|
scheduler: view,
|
|
12871
13258
|
models: new ModelCatalog(runners),
|
|
13259
|
+
quotas: new QuotaReads(runners),
|
|
12872
13260
|
runners,
|
|
12873
13261
|
webDir,
|
|
12874
13262
|
signIn: { github: config.github, log },
|