@kubitnodes/stellaris 0.3.20 → 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 +1029 -637
- package/dist/server/index.js +1313 -729
- package/package.json +3 -1
- package/web/dist/assets/{BackLink-BjfX2KZl.js → BackLink-CD-iuy-h.js} +1 -1
- 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-vSuwLv2K.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-D7MUCA_T.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-_D7n5uKH.js → Pane-CLjdfBMM.js} +1 -1
- package/web/dist/assets/{Picker-DUiiQMFN.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-B6I9DJ8O.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/ChannelForms-BYrcUldk.js +0 -1
- package/web/dist/assets/ChannelView-GJ_DusLQ.js +0 -2
- package/web/dist/assets/CitizenView-Cx7IYSRr.js +0 -2
- package/web/dist/assets/CitizensView-IKH7_yNQ.js +0 -1
- package/web/dist/assets/CronsView-DJbi8Qhx.js +0 -1
- package/web/dist/assets/KnowledgeView-CoYOG9tI.js +0 -1
- package/web/dist/assets/Markdown-YC-fbHiE.js +0 -32
- package/web/dist/assets/MetricsView-CE94VW0I.js +0 -1
- package/web/dist/assets/NeedsYouView-Otnm3lcG.js +0 -1
- package/web/dist/assets/Overview-B8f6rLb2.js +0 -1
- package/web/dist/assets/ProjectView-D_ACOmEd.js +0 -1
- package/web/dist/assets/ProposalView-4d0U3nEb.js +0 -2
- package/web/dist/assets/ProposalsView-BovF6CMD.js +0 -1
- package/web/dist/assets/RunnersView-B2_uCVHC.js +0 -1
- package/web/dist/assets/SocietyView-Bf0iX8AY.js +0 -1
- package/web/dist/assets/SubjectThread-B_Vmgs3d.js +0 -1
- package/web/dist/assets/TaskFileView-BzO0gjE6.js +0 -4
- package/web/dist/assets/TaskView-DB_Nji99.js +0 -3
- package/web/dist/assets/TasksView-Bz36YYWq.js +0 -1
- package/web/dist/assets/ThreadForms-1mbMZsbv.js +0 -1
- package/web/dist/assets/ThreadItem-QJSA92C4.js +0 -1
- package/web/dist/assets/ThreadView-BECLqt5B.js +0 -1
- package/web/dist/assets/citizen-DVFr5T6R.js +0 -1
- package/web/dist/assets/compose-_6feqP1t.js +0 -1
- package/web/dist/assets/format-DxXtbdNM.js +0 -55
- package/web/dist/assets/governance-C9xH4QTm.js +0 -1
- package/web/dist/assets/index-BEVCPm4C.js +0 -23
- package/web/dist/assets/index-BkOq4PSU.css +0 -2
- package/web/dist/assets/link-CTjFMNoY.js +0 -1
- package/web/dist/assets/mentions-BCdV0bMK.js +0 -1
- package/web/dist/assets/useMatch-B3RzAe8y.js +0 -1
- package/web/dist/assets/useStickyScroll-Ca7sWbGH.js +0 -1
package/dist/cli/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { Command } from "commander";
|
|
|
9
9
|
import { chmod as chmod2, cp, mkdir as mkdir4, readdir as readdir3, readFile as readFile4, rename as rename3, rm as rm2, stat as stat3, writeFile as writeFile4 } from "node:fs/promises";
|
|
10
10
|
import path6 from "node:path";
|
|
11
11
|
import { decodeTime, monotonicFactory } from "ulid";
|
|
12
|
-
import { z as
|
|
12
|
+
import { z as z15 } from "zod";
|
|
13
13
|
|
|
14
14
|
// packages/shared/dist/ids.js
|
|
15
15
|
import { z } from "zod";
|
|
@@ -146,7 +146,7 @@ var SEED_ROLES = [
|
|
|
146
146
|
},
|
|
147
147
|
{
|
|
148
148
|
name: "steward",
|
|
149
|
-
purpose: "Watches the operations signals and the task board for capacity, skill, and capability gaps, and turns signals into proposals: a member when a project's plans need a role nobody fills or a backlog persists, a role when a project's work needs one no existing role covers, a retirement when a member has been idle for a long time. Opens a channel with create_channel when a topic or a workstream needs one, and archives it once its work is done. Owns how work is shaped over time: answers stages waiting too long, stages assigned to roles nobody fills, and work sent back again and again by replanning with plan_task, adjusting gates, or proposing the role a plan needs; sets each project's completion effect with configure_project; turns recurring plan shapes into society skills and planning norms into the society's norms. Prefers scaling an existing role over inventing a new one. Never approves its own proposals; hiring, roles, and
|
|
149
|
+
purpose: "Watches the operations signals and the task board for capacity, skill, and capability gaps, and turns signals into proposals: a member when a project's plans need a role nobody fills or a backlog persists, a role when a project's work needs one no existing role covers, a retirement when a member has been idle for a long time. Opens a channel with create_channel when a topic or a workstream needs one, and archives it once its work is done. Owns how work is shaped over time: answers stages waiting too long, stages assigned to roles nobody fills, and work sent back again and again by replanning with plan_task, adjusting gates, or proposing the role a plan needs; sets each project's completion effect with configure_project; turns recurring plan shapes into society skills and planning norms into the society's norms. Prefers scaling an existing role over inventing a new one, by a reallocation of its replicas, backlog threshold, wakes, or verbs. Never approves its own proposals; hiring, roles, retirements, and reallocations that change a role's verbs or replicas are decided by the user, and channels, skills, and other reallocations the steward may decide. Curates society knowledge and skills.",
|
|
150
150
|
verbs: [...MEMBER_VERBS, ...GOVERNANCE_VERBS, ...PLANNING_VERBS, ...CURATING_VERBS],
|
|
151
151
|
wakeTriggers: ["ops_event", "heartbeat"],
|
|
152
152
|
maxReplicas: 1,
|
|
@@ -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";
|
|
@@ -288,6 +288,79 @@ function describeSchedule(schedule, societyZone) {
|
|
|
288
288
|
return schedule.timezone === void 0 ? `\`${schedule.cron}\` in the society's time zone, ${societyZone}` : `\`${schedule.cron}\` in ${schedule.timezone}`;
|
|
289
289
|
}
|
|
290
290
|
|
|
291
|
+
// packages/shared/dist/quota.js
|
|
292
|
+
import { z as z4 } from "zod";
|
|
293
|
+
var QuotaWindowSchema = z4.object({
|
|
294
|
+
/**
|
|
295
|
+
* The CLI's own name for the window: Claude's `five_hour`, `seven_day`, `seven_day_opus`, and
|
|
296
|
+
* `model:<label>` for a model's weekly window; Codex's `primary` and `secondary`.
|
|
297
|
+
*/
|
|
298
|
+
key: z4.string().min(1).max(80),
|
|
299
|
+
/** What a scoped window counts, as the CLI labels it, such as a model's name. */
|
|
300
|
+
label: z4.string().min(1).max(80).optional(),
|
|
301
|
+
/** The window's length in minutes, when known. */
|
|
302
|
+
minutes: z4.number().int().positive().nullable().default(null),
|
|
303
|
+
/** How much of the window is used, in percent, or null when the CLI did not say. */
|
|
304
|
+
usedPercent: z4.number().nonnegative().nullable().default(null),
|
|
305
|
+
/** When the window starts afresh, when known. */
|
|
306
|
+
resetsAt: IsoDateTimeSchema.nullable().default(null),
|
|
307
|
+
/** When the CLI last reported this window. */
|
|
308
|
+
observedAt: IsoDateTimeSchema
|
|
309
|
+
});
|
|
310
|
+
var QuotaStatusSchema = z4.enum(["allowed", "warning", "limited", "none"]);
|
|
311
|
+
var QuotaCreditsSchema = z4.object({
|
|
312
|
+
hasCredits: z4.boolean(),
|
|
313
|
+
unlimited: z4.boolean(),
|
|
314
|
+
balance: z4.string().max(40).nullable()
|
|
315
|
+
});
|
|
316
|
+
var QuotaExtraUsageSchema = z4.object({
|
|
317
|
+
enabled: z4.boolean(),
|
|
318
|
+
monthlyLimit: z4.number().nonnegative().nullable(),
|
|
319
|
+
usedCredits: z4.number().nonnegative().nullable(),
|
|
320
|
+
currency: z4.string().min(1).max(8).nullable()
|
|
321
|
+
});
|
|
322
|
+
var CliQuotaSchema = z4.object({
|
|
323
|
+
/** When the CLI last reported anything here. */
|
|
324
|
+
observedAt: IsoDateTimeSchema,
|
|
325
|
+
/** Whether it came from a turn's stream or from asking the CLI. */
|
|
326
|
+
source: z4.enum(["turn", "read"]),
|
|
327
|
+
status: QuotaStatusSchema,
|
|
328
|
+
/** While `limited`: when work can go on, when known, and the window that stopped it. */
|
|
329
|
+
limitedUntil: IsoDateTimeSchema.nullable().default(null),
|
|
330
|
+
limitedBy: z4.string().min(1).max(80).nullable().default(null),
|
|
331
|
+
/** The plan's name as the CLI gives it, such as `max` or `pro`. */
|
|
332
|
+
plan: z4.string().min(1).max(40).nullable().default(null),
|
|
333
|
+
windows: z4.array(QuotaWindowSchema).max(24).default([]),
|
|
334
|
+
credits: QuotaCreditsSchema.nullable().default(null),
|
|
335
|
+
extraUsage: QuotaExtraUsageSchema.nullable().default(null)
|
|
336
|
+
});
|
|
337
|
+
function mergeQuota(previous, next) {
|
|
338
|
+
if (previous === void 0) {
|
|
339
|
+
return next;
|
|
340
|
+
}
|
|
341
|
+
const windows = new Map(previous.windows.map((window) => [window.key, window]));
|
|
342
|
+
for (const window of next.windows) {
|
|
343
|
+
windows.set(window.key, window);
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
...next,
|
|
347
|
+
plan: next.plan ?? previous.plan,
|
|
348
|
+
credits: next.credits ?? previous.credits,
|
|
349
|
+
extraUsage: next.extraUsage ?? previous.extraUsage,
|
|
350
|
+
windows: [...windows.values()]
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function readings(quota) {
|
|
354
|
+
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();
|
|
355
|
+
return windows.join(",");
|
|
356
|
+
}
|
|
357
|
+
function quotaChanged(previous, next) {
|
|
358
|
+
if (previous === void 0) {
|
|
359
|
+
return true;
|
|
360
|
+
}
|
|
361
|
+
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);
|
|
362
|
+
}
|
|
363
|
+
|
|
291
364
|
// packages/shared/dist/board.js
|
|
292
365
|
var ASK_CHANNEL = "asks";
|
|
293
366
|
var SOCIETY_CHANNELS = ["general", "governance", ASK_CHANNEL];
|
|
@@ -300,24 +373,24 @@ var SOCIETY_SCOPE = "society";
|
|
|
300
373
|
function wakeScope(member, project2) {
|
|
301
374
|
return project2 !== null && member.memberships.includes(project2) ? project2 : SOCIETY_SCOPE;
|
|
302
375
|
}
|
|
303
|
-
var CliKindSchema =
|
|
304
|
-
var ArchivedChannelSchema =
|
|
376
|
+
var CliKindSchema = z5.enum(["claude", "codex"]);
|
|
377
|
+
var ArchivedChannelSchema = z5.object({
|
|
305
378
|
name: NameSchema,
|
|
306
379
|
at: IsoDateTimeSchema,
|
|
307
380
|
by: NameSchema,
|
|
308
|
-
reason:
|
|
381
|
+
reason: z5.string().min(1)
|
|
309
382
|
});
|
|
310
|
-
var SocietySchema =
|
|
311
|
-
name:
|
|
312
|
-
version:
|
|
383
|
+
var SocietySchema = z5.object({
|
|
384
|
+
name: z5.string().min(1),
|
|
385
|
+
version: z5.literal(1),
|
|
313
386
|
createdAt: IsoDateTimeSchema,
|
|
314
387
|
/** The channels that take posts; an archived one moves to `archivedChannels`. */
|
|
315
|
-
channels:
|
|
316
|
-
archivedChannels:
|
|
388
|
+
channels: z5.array(NameSchema),
|
|
389
|
+
archivedChannels: z5.array(ArchivedChannelSchema).default([]),
|
|
317
390
|
/** The time zone crons are read in when they name none, and every prompt tells the time in; the user's to set. */
|
|
318
391
|
timezone: TimeZoneSchema.default(DEFAULT_TIME_ZONE)
|
|
319
392
|
});
|
|
320
|
-
var CompletionEffectSchema =
|
|
393
|
+
var CompletionEffectSchema = z5.enum(["none", "merge", "ghpr"]);
|
|
321
394
|
var GITHUB_REMOTE = [
|
|
322
395
|
/^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?\/?$/,
|
|
323
396
|
/^git@github\.com:([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+?)(?:\.git)?$/,
|
|
@@ -333,7 +406,7 @@ function githubRepository(remote) {
|
|
|
333
406
|
return null;
|
|
334
407
|
}
|
|
335
408
|
var PULL_REQUEST_URL = /^https:\/\/github\.com\/([A-Za-z0-9-]+)\/([A-Za-z0-9._-]+)\/pull\/([1-9]\d*)\/?$/;
|
|
336
|
-
var PullRequestUrlSchema =
|
|
409
|
+
var PullRequestUrlSchema = z5.string().trim().regex(PULL_REQUEST_URL, "a pull request's address, https://github.com/<owner>/<repo>/pull/<number>");
|
|
337
410
|
function parsePullRequestUrl(url) {
|
|
338
411
|
const match = PULL_REQUEST_URL.exec(url.trim());
|
|
339
412
|
return match?.[1] === void 0 || match[2] === void 0 || match[3] === void 0 ? null : { owner: match[1], name: match[2], number: Number(match[3]) };
|
|
@@ -341,72 +414,72 @@ function parsePullRequestUrl(url) {
|
|
|
341
414
|
function sameRepository(a, b) {
|
|
342
415
|
return a.owner.toLowerCase() === b.owner.toLowerCase() && a.name.toLowerCase() === b.name.toLowerCase();
|
|
343
416
|
}
|
|
344
|
-
var MergeSubjectSchema =
|
|
345
|
-
var PullRequestLinkSchema =
|
|
417
|
+
var MergeSubjectSchema = z5.string().trim().min(1).max(300).regex(/^[^\n]+$/, "a merge commit's subject is one line");
|
|
418
|
+
var PullRequestLinkSchema = z5.object({
|
|
346
419
|
url: PullRequestUrlSchema,
|
|
347
|
-
number:
|
|
420
|
+
number: z5.number().int().positive(),
|
|
348
421
|
subject: MergeSubjectSchema.optional(),
|
|
349
|
-
body:
|
|
422
|
+
body: z5.string().max(2e4).optional(),
|
|
350
423
|
linkedBy: NameSchema,
|
|
351
424
|
linkedAt: IsoDateTimeSchema,
|
|
352
425
|
/**
|
|
353
426
|
* Once its `ghpr` task was abandoned, how the board's closing of it on GitHub went: `ok` false
|
|
354
427
|
* leaves it open, for the reason `detail` gives.
|
|
355
428
|
*/
|
|
356
|
-
closed:
|
|
429
|
+
closed: z5.object({ at: IsoDateTimeSchema, ok: z5.boolean(), detail: z5.string() }).optional()
|
|
357
430
|
});
|
|
358
|
-
var DefaultBranchSchema =
|
|
359
|
-
var StageIdSchema =
|
|
431
|
+
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");
|
|
432
|
+
var StageIdSchema = z5.string().regex(/^s[1-9][0-9]*$/, "expected a stage id such as s1");
|
|
360
433
|
var stageFields = {
|
|
361
|
-
name:
|
|
434
|
+
name: z5.string().trim().min(1).max(120),
|
|
362
435
|
role: NameSchema.optional(),
|
|
363
436
|
agent: NameSchema.optional(),
|
|
364
|
-
gate:
|
|
437
|
+
gate: z5.boolean().default(false)
|
|
365
438
|
};
|
|
366
439
|
function oneAssignee(stage) {
|
|
367
440
|
return stage.role === void 0 || stage.agent === void 0;
|
|
368
441
|
}
|
|
369
442
|
var ONE_ASSIGNEE = { message: "a stage names a role or an agent, not both" };
|
|
370
|
-
var PlanStageSchema =
|
|
371
|
-
var PlanEditStageSchema =
|
|
372
|
-
var PlanSchema =
|
|
373
|
-
var PlanEditSchema =
|
|
374
|
-
var ProjectSchema =
|
|
443
|
+
var PlanStageSchema = z5.object(stageFields).refine(oneAssignee, ONE_ASSIGNEE);
|
|
444
|
+
var PlanEditStageSchema = z5.object({ id: StageIdSchema.optional(), ...stageFields }).refine(oneAssignee, ONE_ASSIGNEE);
|
|
445
|
+
var PlanSchema = z5.array(PlanStageSchema);
|
|
446
|
+
var PlanEditSchema = z5.array(PlanEditStageSchema);
|
|
447
|
+
var ProjectSchema = z5.object({
|
|
375
448
|
slug: NameSchema,
|
|
376
|
-
name:
|
|
377
|
-
repo:
|
|
378
|
-
defaultBranch:
|
|
449
|
+
name: z5.string().min(1),
|
|
450
|
+
repo: z5.string().nullable(),
|
|
451
|
+
defaultBranch: z5.string().min(1),
|
|
379
452
|
/** The channels that take posts; an archived one moves to `archivedChannels`. */
|
|
380
|
-
channels:
|
|
381
|
-
archivedChannels:
|
|
382
|
-
members:
|
|
383
|
-
approvers:
|
|
384
|
-
requiredCapabilities:
|
|
453
|
+
channels: z5.array(NameSchema),
|
|
454
|
+
archivedChannels: z5.array(ArchivedChannelSchema).default([]),
|
|
455
|
+
members: z5.array(NameSchema),
|
|
456
|
+
approvers: z5.array(NameSchema),
|
|
457
|
+
requiredCapabilities: z5.array(z5.string()),
|
|
385
458
|
createdAt: IsoDateTimeSchema,
|
|
386
459
|
onDone: CompletionEffectSchema.default("none"),
|
|
387
460
|
/** The runner the project lives on, which holds its repository; set on the project's first turn. */
|
|
388
461
|
runner: NameSchema.optional(),
|
|
389
462
|
/** Set once the project is archived: nobody belongs to it, and nothing more is posted, filed, or joined there. */
|
|
390
|
-
archived:
|
|
463
|
+
archived: z5.object({ at: IsoDateTimeSchema, by: NameSchema, reason: z5.string().min(1) }).optional()
|
|
391
464
|
});
|
|
392
|
-
var TaskStepSchema =
|
|
393
|
-
action:
|
|
465
|
+
var TaskStepSchema = z5.object({
|
|
466
|
+
action: z5.enum(["advanced", "returned", "abandoned", "landed", "reopened"]),
|
|
394
467
|
stage: StageIdSchema,
|
|
395
468
|
to: StageIdSchema.nullable()
|
|
396
469
|
});
|
|
397
|
-
var ProposalStepSchema =
|
|
398
|
-
var MessageStepSchema =
|
|
470
|
+
var ProposalStepSchema = z5.object({ action: z5.enum(["approved", "rejected"]) });
|
|
471
|
+
var MessageStepSchema = z5.union([TaskStepSchema, ProposalStepSchema]);
|
|
399
472
|
function isTaskStep(step) {
|
|
400
473
|
return "stage" in step;
|
|
401
474
|
}
|
|
402
|
-
var KnowledgeNoticeSchema =
|
|
403
|
-
kind:
|
|
404
|
-
action:
|
|
475
|
+
var KnowledgeNoticeSchema = z5.object({
|
|
476
|
+
kind: z5.literal("knowledge"),
|
|
477
|
+
action: z5.enum(["written", "updated", "removed"]),
|
|
405
478
|
topic: NameSchema,
|
|
406
479
|
project: NameSchema.nullable()
|
|
407
480
|
});
|
|
408
|
-
var MessageNoticeSchema =
|
|
409
|
-
var MessageFrontmatterSchema =
|
|
481
|
+
var MessageNoticeSchema = z5.discriminatedUnion("kind", [KnowledgeNoticeSchema]);
|
|
482
|
+
var MessageFrontmatterSchema = z5.object({
|
|
410
483
|
id: UlidSchema,
|
|
411
484
|
author: NameSchema,
|
|
412
485
|
channel: ChannelRefSchema,
|
|
@@ -420,7 +493,7 @@ var MessageFrontmatterSchema = z4.object({
|
|
|
420
493
|
/** On a post a verb made about its work, such as a knowledge topic's note: what it records. */
|
|
421
494
|
notice: MessageNoticeSchema.optional(),
|
|
422
495
|
ts: IsoDateTimeSchema,
|
|
423
|
-
mentions:
|
|
496
|
+
mentions: z5.array(NameSchema)
|
|
424
497
|
});
|
|
425
498
|
var MessageRefSchema = MessageFrontmatterSchema.pick({
|
|
426
499
|
id: true,
|
|
@@ -429,16 +502,16 @@ var MessageRefSchema = MessageFrontmatterSchema.pick({
|
|
|
429
502
|
thread: true,
|
|
430
503
|
ts: true
|
|
431
504
|
});
|
|
432
|
-
var TaskStatusSchema =
|
|
433
|
-
var ThreadStateSchema =
|
|
434
|
-
var ThreadSubjectSchema =
|
|
435
|
-
kind:
|
|
505
|
+
var TaskStatusSchema = z5.enum(["open", "claimed", "done", "abandoned"]);
|
|
506
|
+
var ThreadStateSchema = z5.enum(["open", "closed"]);
|
|
507
|
+
var ThreadSubjectSchema = z5.object({
|
|
508
|
+
kind: z5.enum(["task", "proposal"]),
|
|
436
509
|
id: UlidSchema
|
|
437
510
|
});
|
|
438
|
-
var ThreadFrontmatterSchema =
|
|
511
|
+
var ThreadFrontmatterSchema = z5.object({
|
|
439
512
|
id: UlidSchema,
|
|
440
513
|
channel: ChannelRefSchema,
|
|
441
|
-
title:
|
|
514
|
+
title: z5.string().min(1).max(200),
|
|
442
515
|
subject: ThreadSubjectSchema.optional(),
|
|
443
516
|
state: ThreadStateSchema,
|
|
444
517
|
openedBy: NameSchema,
|
|
@@ -446,28 +519,28 @@ var ThreadFrontmatterSchema = z4.object({
|
|
|
446
519
|
closedBy: NameSchema.optional(),
|
|
447
520
|
closedAt: IsoDateTimeSchema.optional()
|
|
448
521
|
});
|
|
449
|
-
var StageSchema =
|
|
522
|
+
var StageSchema = z5.object({
|
|
450
523
|
id: StageIdSchema,
|
|
451
|
-
name:
|
|
524
|
+
name: z5.string().min(1),
|
|
452
525
|
role: NameSchema.optional(),
|
|
453
526
|
agent: NameSchema.optional(),
|
|
454
|
-
gate:
|
|
527
|
+
gate: z5.boolean().default(false),
|
|
455
528
|
/** Everyone who has held the stage, oldest first. */
|
|
456
|
-
holders:
|
|
529
|
+
holders: z5.array(NameSchema).default([]),
|
|
457
530
|
completedBy: NameSchema.optional(),
|
|
458
531
|
completedAt: IsoDateTimeSchema.optional()
|
|
459
532
|
});
|
|
460
|
-
var TaskReturnSchema =
|
|
533
|
+
var TaskReturnSchema = z5.object({
|
|
461
534
|
from: StageIdSchema,
|
|
462
535
|
by: NameSchema,
|
|
463
536
|
at: IsoDateTimeSchema
|
|
464
537
|
});
|
|
465
|
-
var TaskFrontmatterSchema =
|
|
538
|
+
var TaskFrontmatterSchema = z5.object({
|
|
466
539
|
id: UlidSchema,
|
|
467
540
|
project: NameSchema,
|
|
468
541
|
/** The channel of the project the task is filed in, where its thread hangs. */
|
|
469
542
|
channel: NameSchema.default("general"),
|
|
470
|
-
title:
|
|
543
|
+
title: z5.string().min(1),
|
|
471
544
|
status: TaskStatusSchema,
|
|
472
545
|
createdBy: NameSchema,
|
|
473
546
|
createdAt: IsoDateTimeSchema,
|
|
@@ -476,19 +549,19 @@ var TaskFrontmatterSchema = z4.object({
|
|
|
476
549
|
claimedBy: NameSchema.optional(),
|
|
477
550
|
leaseExpiresAt: IsoDateTimeSchema.optional(),
|
|
478
551
|
parentId: UlidSchema.optional(),
|
|
479
|
-
blockedBy:
|
|
480
|
-
requiredCapabilities:
|
|
481
|
-
stages:
|
|
552
|
+
blockedBy: z5.array(UlidSchema),
|
|
553
|
+
requiredCapabilities: z5.array(z5.string()),
|
|
554
|
+
stages: z5.array(StageSchema).min(1),
|
|
482
555
|
stage: StageIdSchema,
|
|
483
556
|
/** When the current stage last became current or lost its holder: the waiting clock. */
|
|
484
557
|
stageSince: IsoDateTimeSchema,
|
|
485
558
|
/** The highest stage number issued, so a removed stage's id is never reused. */
|
|
486
|
-
stageSeq:
|
|
559
|
+
stageSeq: z5.number().int().positive(),
|
|
487
560
|
onDone: CompletionEffectSchema.default("none"),
|
|
488
561
|
/** The pull request a `ghpr` task lands through. */
|
|
489
562
|
pullRequest: PullRequestLinkSchema.optional(),
|
|
490
563
|
/** The last stage is complete and the completion effect is running. */
|
|
491
|
-
completing:
|
|
564
|
+
completing: z5.boolean().default(false),
|
|
492
565
|
/** The latest send-back while its rework lasts: cleared once the task reaches that stage again. */
|
|
493
566
|
returned: TaskReturnSchema.optional()
|
|
494
567
|
});
|
|
@@ -512,79 +585,90 @@ function mayHoldStage(member, task2) {
|
|
|
512
585
|
}
|
|
513
586
|
return !(stage.gate && task2.stages.slice(0, index).some((s) => s.holders.includes(member.name)));
|
|
514
587
|
}
|
|
515
|
-
var ModelNameSchema =
|
|
516
|
-
var EffortSchema =
|
|
517
|
-
var EffortOptionSchema =
|
|
588
|
+
var ModelNameSchema = z5.string().trim().min(1).max(120).regex(/^[\w.:/[\]-]+$/, "a model name is one word of letters, digits, and . _ : / - [ ]");
|
|
589
|
+
var EffortSchema = z5.string().trim().min(1).max(32).regex(/^[a-z][a-z0-9_-]*$/, "an effort is one lowercase word, such as high");
|
|
590
|
+
var EffortOptionSchema = z5.object({
|
|
518
591
|
id: EffortSchema,
|
|
519
|
-
description:
|
|
592
|
+
description: z5.string().default("")
|
|
520
593
|
});
|
|
521
|
-
var ModelOptionSchema =
|
|
594
|
+
var ModelOptionSchema = z5.object({
|
|
522
595
|
id: ModelNameSchema,
|
|
523
|
-
name:
|
|
524
|
-
description:
|
|
525
|
-
isDefault:
|
|
526
|
-
efforts:
|
|
596
|
+
name: z5.string(),
|
|
597
|
+
description: z5.string().default(""),
|
|
598
|
+
isDefault: z5.boolean().default(false),
|
|
599
|
+
efforts: z5.array(EffortOptionSchema).default([]),
|
|
527
600
|
defaultEffort: EffortSchema.optional()
|
|
528
601
|
});
|
|
529
|
-
var RunnerModelsSchema =
|
|
602
|
+
var RunnerModelsSchema = z5.object({
|
|
530
603
|
runner: NameSchema,
|
|
531
604
|
cli: CliKindSchema,
|
|
532
|
-
models:
|
|
605
|
+
models: z5.array(ModelOptionSchema)
|
|
533
606
|
});
|
|
534
|
-
var AgentStatusSchema =
|
|
535
|
-
var AgentSchema =
|
|
607
|
+
var AgentStatusSchema = z5.enum(["active", "retired"]);
|
|
608
|
+
var AgentSchema = z5.object({
|
|
536
609
|
name: NameSchema,
|
|
537
610
|
role: NameSchema,
|
|
538
611
|
cli: CliKindSchema.nullable(),
|
|
539
|
-
model:
|
|
612
|
+
model: z5.string().optional(),
|
|
540
613
|
/** The reasoning effort set for the agent's turns; the model's own default applies otherwise. */
|
|
541
|
-
effort:
|
|
614
|
+
effort: z5.string().optional(),
|
|
542
615
|
/** The runner preferred for the agent's turns where nothing else decides; any runner with its CLI otherwise. */
|
|
543
616
|
homeRunner: NameSchema.optional(),
|
|
544
|
-
memberships:
|
|
545
|
-
subscriptions:
|
|
617
|
+
memberships: z5.array(NameSchema),
|
|
618
|
+
subscriptions: z5.array(ChannelRefSchema),
|
|
546
619
|
status: AgentStatusSchema,
|
|
547
620
|
createdAt: IsoDateTimeSchema,
|
|
548
|
-
tokenHash:
|
|
621
|
+
tokenHash: z5.string().min(1),
|
|
549
622
|
retiredAt: IsoDateTimeSchema.optional(),
|
|
550
|
-
retiredReason:
|
|
623
|
+
retiredReason: z5.string().optional()
|
|
551
624
|
});
|
|
552
|
-
var MemberSchema =
|
|
625
|
+
var MemberSchema = z5.object({
|
|
553
626
|
name: NameSchema,
|
|
554
627
|
role: NameSchema,
|
|
555
628
|
cli: CliKindSchema.nullable(),
|
|
556
629
|
homeRunner: NameSchema.optional(),
|
|
557
630
|
status: AgentStatusSchema,
|
|
558
|
-
resident:
|
|
631
|
+
resident: z5.boolean().default(false),
|
|
559
632
|
/** The model configured on the record, if any; the CLI's own default applies otherwise. */
|
|
560
|
-
model:
|
|
633
|
+
model: z5.string().optional(),
|
|
561
634
|
/** The model the CLI reported on the citizen's last turn. */
|
|
562
|
-
lastModel:
|
|
635
|
+
lastModel: z5.string().optional(),
|
|
563
636
|
/** The reasoning effort configured on the record, if any; the model's own default applies otherwise. */
|
|
564
|
-
effort:
|
|
637
|
+
effort: z5.string().optional(),
|
|
565
638
|
/** The citizen's own skills, by name. */
|
|
566
|
-
skills:
|
|
567
|
-
memberships:
|
|
568
|
-
subscriptions:
|
|
569
|
-
claimsHeld:
|
|
570
|
-
tasksDone:
|
|
639
|
+
skills: z5.array(NameSchema).default([]),
|
|
640
|
+
memberships: z5.array(NameSchema),
|
|
641
|
+
subscriptions: z5.array(ChannelRefSchema),
|
|
642
|
+
claimsHeld: z5.number().int().nonnegative().default(0),
|
|
643
|
+
tasksDone: z5.number().int().nonnegative().default(0),
|
|
571
644
|
lastTurnAt: IsoDateTimeSchema.optional(),
|
|
572
|
-
lastTurnOutcome:
|
|
645
|
+
lastTurnOutcome: z5.string().optional(),
|
|
573
646
|
createdAt: IsoDateTimeSchema,
|
|
574
647
|
retiredAt: IsoDateTimeSchema.optional()
|
|
575
648
|
});
|
|
576
|
-
var RunnerOsSchema =
|
|
577
|
-
var
|
|
649
|
+
var RunnerOsSchema = z5.enum(["linux", "windows", "darwin"]);
|
|
650
|
+
var GitIdentityPartSchema = z5.enum(["name", "email"]);
|
|
651
|
+
var RunnerSchema = z5.object({
|
|
578
652
|
name: NameSchema,
|
|
579
653
|
os: RunnerOsSchema,
|
|
580
|
-
clis:
|
|
581
|
-
capabilities:
|
|
654
|
+
clis: z5.array(CliKindSchema),
|
|
655
|
+
capabilities: z5.array(z5.string()),
|
|
582
656
|
/** The release the runner reported when it last registered; absent until it has. */
|
|
583
|
-
version:
|
|
584
|
-
|
|
585
|
-
|
|
657
|
+
version: z5.string().optional(),
|
|
658
|
+
/**
|
|
659
|
+
* What the runner's account lacked of a git identity when it last registered, empty when it had
|
|
660
|
+
* both; absent while the runner has not said, as one from before runners checked never does.
|
|
661
|
+
*/
|
|
662
|
+
gitIdentityMissing: z5.array(GitIdentityPartSchema).optional(),
|
|
663
|
+
status: z5.enum(["connected", "disconnected"]),
|
|
664
|
+
lastSeen: IsoDateTimeSchema.optional(),
|
|
665
|
+
/**
|
|
666
|
+
* Each CLI's plan quota as its login on this runner last reported it, from a turn's stream or a
|
|
667
|
+
* read; absent until one has.
|
|
668
|
+
*/
|
|
669
|
+
quotas: z5.partialRecord(CliKindSchema, CliQuotaSchema).optional()
|
|
586
670
|
});
|
|
587
|
-
var ProposalKindSchema =
|
|
671
|
+
var ProposalKindSchema = z5.enum([
|
|
588
672
|
"role",
|
|
589
673
|
"member",
|
|
590
674
|
"channel",
|
|
@@ -593,43 +677,88 @@ var ProposalKindSchema = z4.enum([
|
|
|
593
677
|
"skill",
|
|
594
678
|
"archive"
|
|
595
679
|
]);
|
|
596
|
-
var ProposalStatusSchema =
|
|
680
|
+
var ProposalStatusSchema = z5.enum([
|
|
597
681
|
"proposed",
|
|
598
682
|
"approved",
|
|
599
683
|
"rejected",
|
|
600
684
|
"provisioned",
|
|
601
685
|
"retired"
|
|
602
686
|
]);
|
|
603
|
-
var MemberProposalSchema =
|
|
687
|
+
var MemberProposalSchema = z5.object({
|
|
604
688
|
name: NameSchema,
|
|
605
689
|
role: NameSchema,
|
|
606
690
|
cli: CliKindSchema,
|
|
607
|
-
model:
|
|
691
|
+
model: z5.string().optional(),
|
|
608
692
|
homeRunner: NameSchema.optional(),
|
|
609
|
-
memberships:
|
|
610
|
-
subscriptions:
|
|
611
|
-
seedInstructions:
|
|
693
|
+
memberships: z5.array(NameSchema).default([]),
|
|
694
|
+
subscriptions: z5.array(ChannelRefSchema).default([]),
|
|
695
|
+
seedInstructions: z5.string().optional()
|
|
612
696
|
});
|
|
613
|
-
var ChannelProposalSchema =
|
|
697
|
+
var ChannelProposalSchema = z5.object({
|
|
614
698
|
project: NameSchema.nullable().default(null),
|
|
615
699
|
name: NameSchema,
|
|
616
|
-
purpose:
|
|
700
|
+
purpose: z5.string().min(1)
|
|
617
701
|
});
|
|
618
|
-
var
|
|
619
|
-
|
|
702
|
+
var RoleChangesSchema = z5.strictObject({
|
|
703
|
+
maxReplicas: z5.number().int().min(1).optional(),
|
|
704
|
+
backlogThreshold: z5.number().positive().optional(),
|
|
705
|
+
wakeTriggers: z5.array(CharterTriggerSchema).optional(),
|
|
706
|
+
verbs: z5.array(VerbNameSchema).optional()
|
|
707
|
+
}).refine((changes) => Object.values(changes).some((value) => value !== void 0), {
|
|
708
|
+
message: "a reallocation changes at least one of maxReplicas, backlogThreshold, wakeTriggers, verbs"
|
|
620
709
|
});
|
|
621
|
-
var
|
|
710
|
+
var ReallocationProposalSchema = z5.object({
|
|
711
|
+
role: NameSchema,
|
|
712
|
+
changes: RoleChangesSchema,
|
|
713
|
+
description: z5.string().min(1)
|
|
714
|
+
});
|
|
715
|
+
var LegacyReallocationSchema = z5.object({ description: z5.string().min(1) });
|
|
716
|
+
function applyRoleChanges(role2, changes) {
|
|
717
|
+
return {
|
|
718
|
+
...role2,
|
|
719
|
+
...changes.maxReplicas === void 0 ? {} : { maxReplicas: changes.maxReplicas },
|
|
720
|
+
...changes.backlogThreshold === void 0 ? {} : { backlogThreshold: changes.backlogThreshold },
|
|
721
|
+
...changes.wakeTriggers === void 0 ? {} : { wakeTriggers: [...changes.wakeTriggers] },
|
|
722
|
+
...changes.verbs === void 0 ? {} : { verbs: [...changes.verbs] }
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
function listedOrNone(values) {
|
|
726
|
+
return values.length === 0 ? "none" : values.join(", ");
|
|
727
|
+
}
|
|
728
|
+
function roleChangeLines(role2, changes) {
|
|
729
|
+
const lines = [];
|
|
730
|
+
if (changes.maxReplicas !== void 0 && changes.maxReplicas !== role2.maxReplicas) {
|
|
731
|
+
lines.push(`maxReplicas ${role2.maxReplicas} \u2192 ${changes.maxReplicas}`);
|
|
732
|
+
}
|
|
733
|
+
if (changes.backlogThreshold !== void 0 && changes.backlogThreshold !== role2.backlogThreshold) {
|
|
734
|
+
lines.push(`backlogThreshold ${role2.backlogThreshold} \u2192 ${changes.backlogThreshold}`);
|
|
735
|
+
}
|
|
736
|
+
const wakes = changes.wakeTriggers;
|
|
737
|
+
if (wakes !== void 0 && (wakes.length !== role2.wakeTriggers.length || wakes.some((trigger) => !role2.wakeTriggers.includes(trigger)))) {
|
|
738
|
+
lines.push(`wakeTriggers ${listedOrNone(role2.wakeTriggers)} \u2192 ${listedOrNone(wakes)}`);
|
|
739
|
+
}
|
|
740
|
+
if (changes.verbs !== void 0) {
|
|
741
|
+
const next = changes.verbs;
|
|
742
|
+
const added = next.filter((verb) => !role2.verbs.includes(verb)).map((verb) => `+${verb}`);
|
|
743
|
+
const removed = role2.verbs.filter((verb) => !next.includes(verb)).map((verb) => `\u2212${verb}`);
|
|
744
|
+
if (added.length + removed.length > 0) {
|
|
745
|
+
lines.push(`verbs ${[...added, ...removed].join(" ")}`);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
return lines;
|
|
749
|
+
}
|
|
750
|
+
var RetirementProposalSchema = z5.object({
|
|
622
751
|
agent: NameSchema,
|
|
623
|
-
reason:
|
|
752
|
+
reason: z5.string().min(1)
|
|
624
753
|
});
|
|
625
|
-
var ArchiveProposalSchema =
|
|
754
|
+
var ArchiveProposalSchema = z5.object({
|
|
626
755
|
project: NameSchema,
|
|
627
|
-
reason:
|
|
756
|
+
reason: z5.string().min(1)
|
|
628
757
|
});
|
|
629
|
-
var SkillProposalSchema =
|
|
758
|
+
var SkillProposalSchema = z5.object({
|
|
630
759
|
name: NameSchema,
|
|
631
|
-
summary:
|
|
632
|
-
body:
|
|
760
|
+
summary: z5.string().min(1).max(200),
|
|
761
|
+
body: z5.string().min(1).optional()
|
|
633
762
|
});
|
|
634
763
|
var ProposalCharterSchemas = {
|
|
635
764
|
role: RoleCharterSchema,
|
|
@@ -649,6 +778,32 @@ var ROLE_KIND_APPROVERS = {
|
|
|
649
778
|
reallocation: [USER_ROLE, "steward"],
|
|
650
779
|
skill: [USER_ROLE, "steward"]
|
|
651
780
|
};
|
|
781
|
+
var USER_DECIDED_ROLE_CHANGES = ["verbs", "maxReplicas"];
|
|
782
|
+
function proposalApprovers(kind, charter) {
|
|
783
|
+
if (kind === "reallocation") {
|
|
784
|
+
const parsed = ReallocationProposalSchema.safeParse(charter);
|
|
785
|
+
if (parsed.success && USER_DECIDED_ROLE_CHANGES.some((field) => parsed.data.changes[field] !== void 0)) {
|
|
786
|
+
return [USER_ROLE];
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
return ROLE_KIND_APPROVERS[kind];
|
|
790
|
+
}
|
|
791
|
+
function describeRoleChanges(changes) {
|
|
792
|
+
const parts = [];
|
|
793
|
+
if (changes.maxReplicas !== void 0) {
|
|
794
|
+
parts.push(`up to ${changes.maxReplicas} per project`);
|
|
795
|
+
}
|
|
796
|
+
if (changes.backlogThreshold !== void 0) {
|
|
797
|
+
parts.push(`backlog threshold ${changes.backlogThreshold}`);
|
|
798
|
+
}
|
|
799
|
+
if (changes.wakeTriggers !== void 0) {
|
|
800
|
+
parts.push(changes.wakeTriggers.length === 0 ? "no ambient wakes" : `wakes on ${changes.wakeTriggers.join(", ")}`);
|
|
801
|
+
}
|
|
802
|
+
if (changes.verbs !== void 0) {
|
|
803
|
+
parts.push(`${changes.verbs.length} verbs`);
|
|
804
|
+
}
|
|
805
|
+
return parts.join(", ");
|
|
806
|
+
}
|
|
652
807
|
function describeCharter(kind, charter) {
|
|
653
808
|
switch (kind) {
|
|
654
809
|
case "member": {
|
|
@@ -680,9 +835,14 @@ function describeCharter(kind, charter) {
|
|
|
680
835
|
}
|
|
681
836
|
case "reallocation": {
|
|
682
837
|
const parsed = ReallocationProposalSchema.safeParse(charter);
|
|
683
|
-
if (
|
|
838
|
+
if (parsed.success) {
|
|
839
|
+
const { role: role2, changes, description } = parsed.data;
|
|
840
|
+
return `reallocation of role ${role2} (${describeRoleChanges(changes)}): ${description}`;
|
|
841
|
+
}
|
|
842
|
+
const legacy = LegacyReallocationSchema.safeParse(charter);
|
|
843
|
+
if (!legacy.success)
|
|
684
844
|
break;
|
|
685
|
-
return `reallocation: ${
|
|
845
|
+
return `reallocation: ${legacy.data.description}`;
|
|
686
846
|
}
|
|
687
847
|
case "skill": {
|
|
688
848
|
const parsed = SkillProposalSchema.safeParse(charter);
|
|
@@ -701,23 +861,23 @@ function describeCharter(kind, charter) {
|
|
|
701
861
|
}
|
|
702
862
|
return `${kind} ${JSON.stringify(charter)}`;
|
|
703
863
|
}
|
|
704
|
-
var SkillSchema =
|
|
864
|
+
var SkillSchema = z5.object({
|
|
705
865
|
name: NameSchema,
|
|
706
|
-
summary:
|
|
707
|
-
scope:
|
|
708
|
-
path:
|
|
866
|
+
summary: z5.string().default(""),
|
|
867
|
+
scope: z5.enum(["own", "society"]),
|
|
868
|
+
path: z5.string().min(1)
|
|
709
869
|
});
|
|
710
|
-
var RemovedSkillSchema =
|
|
870
|
+
var RemovedSkillSchema = z5.object({
|
|
711
871
|
name: NameSchema,
|
|
712
|
-
reason:
|
|
872
|
+
reason: z5.string().min(1),
|
|
713
873
|
removedBy: NameSchema,
|
|
714
874
|
removedAt: IsoDateTimeSchema
|
|
715
875
|
});
|
|
716
|
-
var HomeConflictSchema =
|
|
876
|
+
var HomeConflictSchema = z5.object({
|
|
717
877
|
/** The copy, relative to the home. */
|
|
718
|
-
path:
|
|
878
|
+
path: z5.string().min(1),
|
|
719
879
|
/** The file beside it, whose version the board kept. */
|
|
720
|
-
file:
|
|
880
|
+
file: z5.string().min(1),
|
|
721
881
|
/** When the copy reached the board. */
|
|
722
882
|
since: IsoDateTimeSchema
|
|
723
883
|
});
|
|
@@ -725,79 +885,79 @@ var CONFLICT_COPY = /^(.+)\.conflict-[^/.]+$/;
|
|
|
725
885
|
function conflictCopyOf(copy) {
|
|
726
886
|
return CONFLICT_COPY.exec(copy)?.[1] ?? null;
|
|
727
887
|
}
|
|
728
|
-
var CommitIdSchema =
|
|
729
|
-
var HomeFileChangeSchema =
|
|
730
|
-
path:
|
|
731
|
-
status:
|
|
888
|
+
var CommitIdSchema = z5.string().regex(/^[0-9a-f]{40}([0-9a-f]{24})?$/);
|
|
889
|
+
var HomeFileChangeSchema = z5.object({
|
|
890
|
+
path: z5.string().min(1),
|
|
891
|
+
status: z5.enum(["added", "modified", "deleted"]),
|
|
732
892
|
/** Lines added and removed, or null for a binary file. */
|
|
733
|
-
added:
|
|
734
|
-
removed:
|
|
893
|
+
added: z5.number().int().nonnegative().nullable(),
|
|
894
|
+
removed: z5.number().int().nonnegative().nullable()
|
|
735
895
|
});
|
|
736
|
-
var HomeChangeSchema =
|
|
896
|
+
var HomeChangeSchema = z5.object({
|
|
737
897
|
commit: CommitIdSchema,
|
|
738
898
|
at: IsoDateTimeSchema,
|
|
739
|
-
kind:
|
|
740
|
-
author:
|
|
899
|
+
kind: z5.enum(["turn", "board", "merge"]),
|
|
900
|
+
author: z5.string(),
|
|
741
901
|
/** The turn that made it, from the runner's commit message. */
|
|
742
902
|
turnId: UlidSchema.optional(),
|
|
743
|
-
subject:
|
|
744
|
-
files:
|
|
903
|
+
subject: z5.string(),
|
|
904
|
+
files: z5.array(HomeFileChangeSchema)
|
|
745
905
|
});
|
|
746
|
-
var HomeHistorySchema =
|
|
747
|
-
changes:
|
|
906
|
+
var HomeHistorySchema = z5.object({
|
|
907
|
+
changes: z5.array(HomeChangeSchema),
|
|
748
908
|
/** Whether older commits remain past the ones read. */
|
|
749
|
-
more:
|
|
909
|
+
more: z5.boolean()
|
|
750
910
|
});
|
|
751
911
|
var HomeFileDiffSchema = HomeFileChangeSchema.pick({ path: true, status: true }).extend({
|
|
752
|
-
patch:
|
|
912
|
+
patch: z5.string().nullable(),
|
|
753
913
|
/** The patch was cut at its size limit. */
|
|
754
|
-
truncated:
|
|
914
|
+
truncated: z5.boolean()
|
|
755
915
|
});
|
|
756
|
-
var KnowledgeSchema =
|
|
916
|
+
var KnowledgeSchema = z5.object({
|
|
757
917
|
topic: NameSchema,
|
|
758
918
|
project: NameSchema.nullable(),
|
|
759
|
-
revision:
|
|
919
|
+
revision: z5.number().int().min(0),
|
|
760
920
|
updatedBy: NameSchema,
|
|
761
921
|
updatedAt: IsoDateTimeSchema
|
|
762
922
|
});
|
|
763
|
-
var RemovedKnowledgeSchema =
|
|
923
|
+
var RemovedKnowledgeSchema = z5.object({
|
|
764
924
|
topic: NameSchema,
|
|
765
925
|
project: NameSchema.nullable(),
|
|
766
926
|
removedBy: NameSchema,
|
|
767
927
|
removedAt: IsoDateTimeSchema
|
|
768
928
|
});
|
|
769
|
-
var DashboardSchema =
|
|
929
|
+
var DashboardSchema = z5.object({
|
|
770
930
|
project: NameSchema,
|
|
771
|
-
revision:
|
|
931
|
+
revision: z5.number().int().min(0),
|
|
772
932
|
/** Absent until someone updates the dashboard the project began with. */
|
|
773
933
|
updatedBy: NameSchema.optional(),
|
|
774
934
|
updatedAt: IsoDateTimeSchema.optional(),
|
|
775
|
-
body:
|
|
935
|
+
body: z5.string()
|
|
776
936
|
});
|
|
777
|
-
var ProposalOriginSchema =
|
|
937
|
+
var ProposalOriginSchema = z5.object({
|
|
778
938
|
scope: NameSchema,
|
|
779
939
|
thread: UlidSchema.optional(),
|
|
780
940
|
channel: NameSchema.optional()
|
|
781
941
|
});
|
|
782
942
|
var SKILL_FILES_LIMIT = 100;
|
|
783
943
|
var SKILL_BYTES_LIMIT = 10 * 1024 * 1024;
|
|
784
|
-
var SkillFileSchema =
|
|
785
|
-
path:
|
|
786
|
-
size:
|
|
787
|
-
executable:
|
|
944
|
+
var SkillFileSchema = z5.object({
|
|
945
|
+
path: z5.string().min(1),
|
|
946
|
+
size: z5.number().int().nonnegative(),
|
|
947
|
+
executable: z5.boolean()
|
|
788
948
|
});
|
|
789
|
-
var SkillFilesSchema =
|
|
949
|
+
var SkillFilesSchema = z5.object({
|
|
790
950
|
/** The commit of the proposer's home the files came from. */
|
|
791
951
|
commit: CommitIdSchema,
|
|
792
952
|
takenAt: IsoDateTimeSchema,
|
|
793
|
-
files:
|
|
953
|
+
files: z5.array(SkillFileSchema)
|
|
794
954
|
});
|
|
795
955
|
var SkillFileContentSchema = SkillFileSchema.extend({
|
|
796
|
-
text:
|
|
956
|
+
text: z5.string().nullable(),
|
|
797
957
|
/** The text was cut at its size limit. */
|
|
798
|
-
truncated:
|
|
958
|
+
truncated: z5.boolean()
|
|
799
959
|
});
|
|
800
|
-
var ProposalFrontmatterSchema =
|
|
960
|
+
var ProposalFrontmatterSchema = z5.object({
|
|
801
961
|
id: UlidSchema,
|
|
802
962
|
kind: ProposalKindSchema,
|
|
803
963
|
proposedBy: NameSchema,
|
|
@@ -809,146 +969,146 @@ var ProposalFrontmatterSchema = z4.object({
|
|
|
809
969
|
skillFiles: SkillFilesSchema.optional(),
|
|
810
970
|
decidedBy: NameSchema.optional(),
|
|
811
971
|
decidedAt: IsoDateTimeSchema.optional(),
|
|
812
|
-
reason:
|
|
813
|
-
charter:
|
|
972
|
+
reason: z5.string().optional(),
|
|
973
|
+
charter: z5.record(z5.string(), z5.unknown()),
|
|
814
974
|
/** What approval created, for kinds the board provisions: the agent, channel, role, or retirement. */
|
|
815
975
|
provisionedAt: IsoDateTimeSchema.optional(),
|
|
816
|
-
provision:
|
|
976
|
+
provision: z5.record(z5.string(), z5.unknown()).optional()
|
|
817
977
|
});
|
|
818
|
-
var DecisionSchema =
|
|
978
|
+
var DecisionSchema = z5.object({
|
|
819
979
|
id: UlidSchema,
|
|
820
980
|
proposalId: UlidSchema,
|
|
821
981
|
decidedBy: NameSchema,
|
|
822
|
-
outcome:
|
|
823
|
-
reason:
|
|
982
|
+
outcome: z5.enum(["approved", "rejected"]),
|
|
983
|
+
reason: z5.string().optional(),
|
|
824
984
|
ts: IsoDateTimeSchema
|
|
825
985
|
});
|
|
826
986
|
|
|
827
987
|
// packages/shared/dist/verbs.js
|
|
828
|
-
import { z as
|
|
829
|
-
var MomentSchema =
|
|
830
|
-
var CronTitleSchema =
|
|
831
|
-
var CronNoteSchema =
|
|
988
|
+
import { z as z6 } from "zod";
|
|
989
|
+
var MomentSchema = z6.iso.datetime({ offset: true });
|
|
990
|
+
var CronTitleSchema = z6.string().trim().min(1).max(120);
|
|
991
|
+
var CronNoteSchema = z6.string().trim().min(1).max(4e3);
|
|
832
992
|
var VerbInputs = {
|
|
833
|
-
post_message:
|
|
993
|
+
post_message: z6.object({
|
|
834
994
|
/** Required outside a thread; in one it may be left out, and must otherwise be the thread's. */
|
|
835
995
|
channel: ChannelRefSchema.optional(),
|
|
836
|
-
body:
|
|
996
|
+
body: z6.string().min(1),
|
|
837
997
|
thread_id: UlidSchema.optional()
|
|
838
998
|
}),
|
|
839
|
-
read_inbox:
|
|
999
|
+
read_inbox: z6.object({
|
|
840
1000
|
since_cursor: UlidSchema.nullable().optional(),
|
|
841
|
-
limit:
|
|
842
|
-
advance:
|
|
1001
|
+
limit: z6.number().int().positive().max(200).default(50),
|
|
1002
|
+
advance: z6.boolean().default(true)
|
|
843
1003
|
}),
|
|
844
|
-
search:
|
|
845
|
-
query:
|
|
1004
|
+
search: z6.object({
|
|
1005
|
+
query: z6.string().min(1),
|
|
846
1006
|
project: NameSchema.optional(),
|
|
847
1007
|
channel: ChannelRefSchema.optional(),
|
|
848
|
-
limit:
|
|
1008
|
+
limit: z6.number().int().positive().max(100).default(20)
|
|
849
1009
|
}),
|
|
850
1010
|
/** On a task or a proposal, whose id the thread takes, or on a channel with a title. */
|
|
851
|
-
open_thread:
|
|
1011
|
+
open_thread: z6.object({
|
|
852
1012
|
task_id: UlidSchema.optional(),
|
|
853
1013
|
proposal_id: UlidSchema.optional(),
|
|
854
1014
|
channel: ChannelRefSchema.optional(),
|
|
855
|
-
title:
|
|
1015
|
+
title: z6.string().min(1).max(200).optional()
|
|
856
1016
|
}),
|
|
857
|
-
close_thread:
|
|
858
|
-
create_task:
|
|
1017
|
+
close_thread: z6.object({ thread_id: UlidSchema, summary: z6.string().min(1) }),
|
|
1018
|
+
create_task: z6.object({
|
|
859
1019
|
project: NameSchema,
|
|
860
|
-
title:
|
|
861
|
-
body:
|
|
1020
|
+
title: z6.string().min(1).max(200),
|
|
1021
|
+
body: z6.string().default(""),
|
|
862
1022
|
parent_id: UlidSchema.optional(),
|
|
863
|
-
required_capabilities:
|
|
1023
|
+
required_capabilities: z6.array(z6.string()).default([]),
|
|
864
1024
|
/** The plan; without it the task gets one stage, work, that anyone in the project may take. */
|
|
865
|
-
stages:
|
|
1025
|
+
stages: z6.array(PlanStageSchema).min(1).optional(),
|
|
866
1026
|
/** A channel of the project the task belongs to, such as a release's; its thread opens there. */
|
|
867
1027
|
channel: NameSchema.default("general")
|
|
868
1028
|
}),
|
|
869
|
-
claim_task:
|
|
870
|
-
release_task:
|
|
871
|
-
update_task:
|
|
1029
|
+
claim_task: z6.object({ task_id: UlidSchema }),
|
|
1030
|
+
release_task: z6.object({ task_id: UlidSchema }),
|
|
1031
|
+
update_task: z6.object({
|
|
872
1032
|
task_id: UlidSchema,
|
|
873
1033
|
/** Move the task back to this earlier stage. */
|
|
874
1034
|
stage: StageIdSchema.optional(),
|
|
875
|
-
status:
|
|
1035
|
+
status: z6.enum(["abandoned"]).optional(),
|
|
876
1036
|
/** Posted to the task's thread as the caller, marked with the step when the task moved. */
|
|
877
|
-
note:
|
|
878
|
-
blocked_by:
|
|
1037
|
+
note: z6.string().min(1).optional(),
|
|
1038
|
+
blocked_by: z6.array(UlidSchema).optional(),
|
|
879
1039
|
/**
|
|
880
1040
|
* The pull request a `ghpr` task lands through, on its project's repository, with the merge
|
|
881
1041
|
* commit's subject and body; null unlinks it.
|
|
882
1042
|
*/
|
|
883
|
-
pull_request:
|
|
1043
|
+
pull_request: z6.object({
|
|
884
1044
|
url: PullRequestUrlSchema,
|
|
885
1045
|
merge_subject: MergeSubjectSchema.optional(),
|
|
886
|
-
merge_body:
|
|
1046
|
+
merge_body: z6.string().max(2e4).optional()
|
|
887
1047
|
}).nullable().optional()
|
|
888
1048
|
}),
|
|
889
|
-
get_task:
|
|
890
|
-
subscribe:
|
|
891
|
-
unsubscribe:
|
|
892
|
-
propose:
|
|
1049
|
+
get_task: z6.object({ task_id: UlidSchema }),
|
|
1050
|
+
subscribe: z6.object({ channel: ChannelRefSchema }),
|
|
1051
|
+
unsubscribe: z6.object({ channel: ChannelRefSchema }),
|
|
1052
|
+
propose: z6.object({
|
|
893
1053
|
kind: ProposalKindSchema,
|
|
894
|
-
charter:
|
|
895
|
-
rationale:
|
|
1054
|
+
charter: z6.record(z6.string(), z6.unknown()),
|
|
1055
|
+
rationale: z6.string().default("")
|
|
896
1056
|
}),
|
|
897
|
-
approve:
|
|
898
|
-
reject:
|
|
899
|
-
create_project:
|
|
1057
|
+
approve: z6.object({ proposal_id: UlidSchema, reason: z6.string().optional() }),
|
|
1058
|
+
reject: z6.object({ proposal_id: UlidSchema, reason: z6.string().min(1) }),
|
|
1059
|
+
create_project: z6.object({
|
|
900
1060
|
slug: NameSchema,
|
|
901
|
-
name:
|
|
902
|
-
repo:
|
|
1061
|
+
name: z6.string().min(1).optional(),
|
|
1062
|
+
repo: z6.string().min(1).nullable().default(null),
|
|
903
1063
|
default_branch: DefaultBranchSchema.default("main"),
|
|
904
1064
|
on_done: CompletionEffectSchema.optional()
|
|
905
1065
|
}),
|
|
906
|
-
join_project:
|
|
907
|
-
leave_project:
|
|
908
|
-
write_knowledge:
|
|
1066
|
+
join_project: z6.object({ project: NameSchema, agent: NameSchema.optional() }),
|
|
1067
|
+
leave_project: z6.object({ project: NameSchema, agent: NameSchema.optional() }),
|
|
1068
|
+
write_knowledge: z6.object({
|
|
909
1069
|
/** A project you belong to, or null for society knowledge, which the steward and the user curate. */
|
|
910
1070
|
project: NameSchema.nullable().default(null),
|
|
911
1071
|
topic: NameSchema,
|
|
912
|
-
body:
|
|
1072
|
+
body: z6.string().min(1),
|
|
913
1073
|
/** The `revision` in the frontmatter of the topic you read, 0 when it names none or for a new topic. */
|
|
914
|
-
revision:
|
|
1074
|
+
revision: z6.number().int().min(0)
|
|
915
1075
|
}),
|
|
916
|
-
remove_knowledge:
|
|
1076
|
+
remove_knowledge: z6.object({
|
|
917
1077
|
/** As for write_knowledge: a project you belong to, or null for society knowledge. */
|
|
918
1078
|
project: NameSchema.nullable().default(null),
|
|
919
1079
|
topic: NameSchema
|
|
920
1080
|
}),
|
|
921
|
-
plan_task:
|
|
1081
|
+
plan_task: z6.object({
|
|
922
1082
|
task_id: UlidSchema,
|
|
923
|
-
stages:
|
|
1083
|
+
stages: z6.array(PlanEditStageSchema),
|
|
924
1084
|
on_done: CompletionEffectSchema.optional()
|
|
925
1085
|
}),
|
|
926
1086
|
/** The note is posted to the task's thread as the caller, marked with the step. */
|
|
927
|
-
advance_task:
|
|
928
|
-
configure_project:
|
|
1087
|
+
advance_task: z6.object({ task_id: UlidSchema, note: z6.string().min(1).optional() }),
|
|
1088
|
+
configure_project: z6.object({
|
|
929
1089
|
project: NameSchema,
|
|
930
1090
|
on_done: CompletionEffectSchema.optional(),
|
|
931
1091
|
/** A new display name; the slug, which everything refers to the project by, never changes. */
|
|
932
|
-
name:
|
|
1092
|
+
name: z6.string().trim().min(1).max(120).optional(),
|
|
933
1093
|
/** The branch tasks start from and land on from now; tasks in play keep their branches. */
|
|
934
1094
|
default_branch: DefaultBranchSchema.optional()
|
|
935
1095
|
}),
|
|
936
|
-
archive_project:
|
|
937
|
-
create_channel:
|
|
1096
|
+
archive_project: z6.object({ project: NameSchema, reason: z6.string().min(1) }),
|
|
1097
|
+
create_channel: z6.object({
|
|
938
1098
|
/** A project, or null for a channel of the society. */
|
|
939
1099
|
project: NameSchema.nullable().default(null),
|
|
940
1100
|
name: NameSchema,
|
|
941
|
-
purpose:
|
|
1101
|
+
purpose: z6.string().min(1)
|
|
942
1102
|
}),
|
|
943
|
-
archive_channel:
|
|
944
|
-
update_dashboard:
|
|
1103
|
+
archive_channel: z6.object({ channel: ChannelRefSchema, reason: z6.string().min(1) }),
|
|
1104
|
+
update_dashboard: z6.object({
|
|
945
1105
|
project: NameSchema,
|
|
946
1106
|
/** The whole dashboard as markdown; the board keeps its frontmatter. */
|
|
947
|
-
body:
|
|
1107
|
+
body: z6.string().min(1),
|
|
948
1108
|
/** The `revision` in the frontmatter of the dashboard you read, 0 when it names none. */
|
|
949
|
-
revision:
|
|
1109
|
+
revision: z6.number().int().min(0)
|
|
950
1110
|
}),
|
|
951
|
-
create_cron:
|
|
1111
|
+
create_cron: z6.object({
|
|
952
1112
|
title: CronTitleSchema,
|
|
953
1113
|
/** What to do when it fires; quoted in the prompt of every turn it starts. */
|
|
954
1114
|
note: CronNoteSchema,
|
|
@@ -967,10 +1127,10 @@ var VerbInputs = {
|
|
|
967
1127
|
/** An open channel of that place other than general, whose conversation it fires in. */
|
|
968
1128
|
channel: NameSchema.optional()
|
|
969
1129
|
}),
|
|
970
|
-
update_cron:
|
|
1130
|
+
update_cron: z6.object({
|
|
971
1131
|
cron_id: UlidSchema,
|
|
972
1132
|
/** Pause it, or resume it, which starts its schedule afresh from now. */
|
|
973
|
-
paused:
|
|
1133
|
+
paused: z6.boolean().optional(),
|
|
974
1134
|
title: CronTitleSchema.optional(),
|
|
975
1135
|
note: CronNoteSchema.optional(),
|
|
976
1136
|
/** A new expression, or `at` for one time; either starts the schedule afresh. */
|
|
@@ -979,12 +1139,12 @@ var VerbInputs = {
|
|
|
979
1139
|
timezone: TimeZoneSchema.nullable().optional(),
|
|
980
1140
|
at: MomentSchema.optional()
|
|
981
1141
|
}),
|
|
982
|
-
remove_cron:
|
|
983
|
-
remove_skill:
|
|
1142
|
+
remove_cron: z6.object({ cron_id: UlidSchema, reason: z6.string().trim().min(1) }),
|
|
1143
|
+
remove_skill: z6.object({ name: NameSchema, reason: z6.string().trim().min(1) })
|
|
984
1144
|
};
|
|
985
1145
|
|
|
986
1146
|
// packages/shared/dist/events.js
|
|
987
|
-
import { z as
|
|
1147
|
+
import { z as z7 } from "zod";
|
|
988
1148
|
var BOARD_EVENT_TYPES = [
|
|
989
1149
|
"society.initialized",
|
|
990
1150
|
"project.added",
|
|
@@ -1029,6 +1189,7 @@ var BOARD_EVENT_TYPES = [
|
|
|
1029
1189
|
"user.signed_out",
|
|
1030
1190
|
"user.token_rotated",
|
|
1031
1191
|
"runner.changed",
|
|
1192
|
+
"runner.quota",
|
|
1032
1193
|
"ops.signal",
|
|
1033
1194
|
"paused.changed",
|
|
1034
1195
|
"wake.requested",
|
|
@@ -1049,28 +1210,36 @@ var BOARD_EVENT_TYPES = [
|
|
|
1049
1210
|
"cron.skipped",
|
|
1050
1211
|
"cron.ended"
|
|
1051
1212
|
];
|
|
1052
|
-
var BoardEventTypeSchema =
|
|
1053
|
-
var BoardEventSchema =
|
|
1213
|
+
var BoardEventTypeSchema = z7.enum(BOARD_EVENT_TYPES);
|
|
1214
|
+
var BoardEventSchema = z7.object({
|
|
1054
1215
|
id: UlidSchema,
|
|
1055
1216
|
ts: IsoDateTimeSchema,
|
|
1056
1217
|
type: BoardEventTypeSchema,
|
|
1057
1218
|
actor: NameSchema,
|
|
1058
|
-
payload:
|
|
1059
|
-
});
|
|
1060
|
-
var UsageSchema =
|
|
1061
|
-
inputTokens:
|
|
1062
|
-
outputTokens:
|
|
1063
|
-
cacheReadTokens:
|
|
1064
|
-
cacheWriteTokens:
|
|
1065
|
-
});
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1219
|
+
payload: z7.record(z7.string(), z7.unknown())
|
|
1220
|
+
});
|
|
1221
|
+
var UsageSchema = z7.object({
|
|
1222
|
+
inputTokens: z7.number().int().nonnegative(),
|
|
1223
|
+
outputTokens: z7.number().int().nonnegative(),
|
|
1224
|
+
cacheReadTokens: z7.number().int().nonnegative().default(0),
|
|
1225
|
+
cacheWriteTokens: z7.number().int().nonnegative().default(0)
|
|
1226
|
+
});
|
|
1227
|
+
function addUsage(a, b) {
|
|
1228
|
+
return {
|
|
1229
|
+
inputTokens: a.inputTokens + b.inputTokens,
|
|
1230
|
+
outputTokens: a.outputTokens + b.outputTokens,
|
|
1231
|
+
cacheReadTokens: a.cacheReadTokens + b.cacheReadTokens,
|
|
1232
|
+
cacheWriteTokens: a.cacheWriteTokens + b.cacheWriteTokens
|
|
1233
|
+
};
|
|
1234
|
+
}
|
|
1235
|
+
var TurnStatusSchema = z7.object({
|
|
1236
|
+
summary: z7.string().min(1),
|
|
1237
|
+
claimsHeld: z7.array(UlidSchema).default([]),
|
|
1238
|
+
blockedOn: z7.array(z7.string()).default([]),
|
|
1239
|
+
needsUserDecision: z7.boolean().default(false),
|
|
1240
|
+
memoryUpdated: z7.boolean().default(false)
|
|
1241
|
+
});
|
|
1242
|
+
var TurnExitReasonSchema = z7.enum([
|
|
1074
1243
|
"completed",
|
|
1075
1244
|
"timeout",
|
|
1076
1245
|
"error",
|
|
@@ -1078,50 +1247,50 @@ var TurnExitReasonSchema = z6.enum([
|
|
|
1078
1247
|
"blocked",
|
|
1079
1248
|
"stopped"
|
|
1080
1249
|
]);
|
|
1081
|
-
var AgentEventSchema =
|
|
1082
|
-
|
|
1083
|
-
type:
|
|
1250
|
+
var AgentEventSchema = z7.discriminatedUnion("type", [
|
|
1251
|
+
z7.object({
|
|
1252
|
+
type: z7.literal("turn_started"),
|
|
1084
1253
|
agent: NameSchema,
|
|
1085
|
-
session:
|
|
1254
|
+
session: z7.string(),
|
|
1086
1255
|
runner: NameSchema,
|
|
1087
1256
|
/** The model the CLI reports running, when it reports one. */
|
|
1088
|
-
model:
|
|
1257
|
+
model: z7.string().optional()
|
|
1089
1258
|
}),
|
|
1090
1259
|
/**
|
|
1091
1260
|
* The CLI took a steer into the running turn. Adapters name the steer; the server adds the
|
|
1092
1261
|
* messages it delivered and the text the CLI was given.
|
|
1093
1262
|
*/
|
|
1094
|
-
|
|
1095
|
-
type:
|
|
1096
|
-
steer:
|
|
1097
|
-
messages:
|
|
1098
|
-
text:
|
|
1263
|
+
z7.object({
|
|
1264
|
+
type: z7.literal("steered"),
|
|
1265
|
+
steer: z7.string().min(1),
|
|
1266
|
+
messages: z7.array(UlidSchema).optional(),
|
|
1267
|
+
text: z7.string().optional()
|
|
1099
1268
|
}),
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
type:
|
|
1104
|
-
name:
|
|
1105
|
-
ok:
|
|
1269
|
+
z7.object({ type: z7.literal("text"), delta: z7.string() }),
|
|
1270
|
+
z7.object({ type: z7.literal("tool_call"), name: z7.string(), input: z7.unknown() }),
|
|
1271
|
+
z7.object({
|
|
1272
|
+
type: z7.literal("tool_result"),
|
|
1273
|
+
name: z7.string(),
|
|
1274
|
+
ok: z7.boolean(),
|
|
1106
1275
|
/** What the tool returned, cut to `OUTPUT_LIMIT` characters by `capOutput`. */
|
|
1107
|
-
output:
|
|
1276
|
+
output: z7.string().optional()
|
|
1108
1277
|
}),
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
type:
|
|
1278
|
+
z7.object({ type: z7.literal("approval_requested"), kind: z7.string(), detail: z7.unknown() }),
|
|
1279
|
+
z7.object({
|
|
1280
|
+
type: z7.literal("turn_completed"),
|
|
1112
1281
|
usage: UsageSchema,
|
|
1113
|
-
costUsd:
|
|
1282
|
+
costUsd: z7.number().nonnegative(),
|
|
1114
1283
|
status: TurnStatusSchema.nullable(),
|
|
1115
1284
|
exitReason: TurnExitReasonSchema
|
|
1116
1285
|
}),
|
|
1117
|
-
|
|
1286
|
+
z7.object({ type: z7.literal("error"), message: z7.string() })
|
|
1118
1287
|
]);
|
|
1119
|
-
var TranscriptEntrySchema =
|
|
1288
|
+
var TranscriptEntrySchema = z7.object({
|
|
1120
1289
|
ts: IsoDateTimeSchema,
|
|
1121
1290
|
event: AgentEventSchema
|
|
1122
1291
|
});
|
|
1123
|
-
var LiveTurnEventSchema =
|
|
1124
|
-
seq:
|
|
1292
|
+
var LiveTurnEventSchema = z7.object({
|
|
1293
|
+
seq: z7.number().int().positive(),
|
|
1125
1294
|
ts: IsoDateTimeSchema,
|
|
1126
1295
|
agent: NameSchema,
|
|
1127
1296
|
project: NameSchema,
|
|
@@ -1133,97 +1302,105 @@ var LiveTurnEventSchema = z6.object({
|
|
|
1133
1302
|
});
|
|
1134
1303
|
|
|
1135
1304
|
// packages/shared/dist/turns.js
|
|
1136
|
-
import { z as
|
|
1305
|
+
import { z as z9 } from "zod";
|
|
1137
1306
|
|
|
1138
1307
|
// packages/shared/dist/runner.js
|
|
1139
|
-
import { z as
|
|
1308
|
+
import { z as z8 } from "zod";
|
|
1140
1309
|
var HOME_SCRATCH = "scratch";
|
|
1141
1310
|
var HOME_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1142
|
-
var RunnerHelloSchema =
|
|
1143
|
-
protocol:
|
|
1144
|
-
version:
|
|
1311
|
+
var RunnerHelloSchema = z8.object({
|
|
1312
|
+
protocol: z8.number().int().positive(),
|
|
1313
|
+
version: z8.string().min(1),
|
|
1145
1314
|
os: RunnerOsSchema,
|
|
1146
|
-
clis:
|
|
1315
|
+
clis: z8.array(CliKindSchema),
|
|
1147
1316
|
/** The CLIs whose adapter can keep a session warm between turns. */
|
|
1148
|
-
residentClis:
|
|
1317
|
+
residentClis: z8.array(CliKindSchema).default([]),
|
|
1149
1318
|
/** The CLIs whose adapter can take input into a running turn; the server steers only these. */
|
|
1150
|
-
steerableClis:
|
|
1319
|
+
steerableClis: z8.array(CliKindSchema).default([]),
|
|
1151
1320
|
/** The CLIs whose adapter can stop a running turn; the server stops only these. */
|
|
1152
|
-
stoppableClis:
|
|
1321
|
+
stoppableClis: z8.array(CliKindSchema).default([]),
|
|
1153
1322
|
/** Whether the runner answers file reads on its projects' branches; one from before never does. */
|
|
1154
|
-
branchReads:
|
|
1323
|
+
branchReads: z8.boolean().default(false),
|
|
1155
1324
|
/** Whether the runner lists what a branch changed; one from before never does. */
|
|
1156
|
-
branchChanges:
|
|
1157
|
-
|
|
1325
|
+
branchChanges: z8.boolean().default(false),
|
|
1326
|
+
/** Whether the runner answers a read of a CLI's quota; one from before never does. */
|
|
1327
|
+
quotaReads: z8.boolean().default(false),
|
|
1328
|
+
capabilities: z8.array(z8.string()).default([]),
|
|
1329
|
+
/**
|
|
1330
|
+
* What the runner's account lacks of the git identity citizens' own commits carry, checked
|
|
1331
|
+
* before each hello outside any repository; empty when it has both. Absent from a runner from
|
|
1332
|
+
* before the check, which no default fills in, so the board marks only what a runner reported.
|
|
1333
|
+
*/
|
|
1334
|
+
gitIdentityMissing: z8.array(GitIdentityPartSchema).optional(),
|
|
1158
1335
|
/** Turns the runner runs at once, or null for no limit. */
|
|
1159
|
-
slots:
|
|
1336
|
+
slots: z8.number().int().positive().nullable(),
|
|
1160
1337
|
/** Turns the runner is still running, when it registers again; the server fails the rest of its turns. */
|
|
1161
|
-
turns:
|
|
1338
|
+
turns: z8.array(UlidSchema).default([])
|
|
1162
1339
|
});
|
|
1163
|
-
var RunnerWelcomeSchema =
|
|
1164
|
-
var RunnerEnrollRequestSchema =
|
|
1165
|
-
protocol:
|
|
1166
|
-
version:
|
|
1167
|
-
hostname:
|
|
1340
|
+
var RunnerWelcomeSchema = z8.object({ name: NameSchema, version: z8.string() });
|
|
1341
|
+
var RunnerEnrollRequestSchema = z8.object({
|
|
1342
|
+
protocol: z8.number().int().positive(),
|
|
1343
|
+
version: z8.string().min(1).max(64),
|
|
1344
|
+
hostname: z8.string().min(1).max(253),
|
|
1168
1345
|
os: RunnerOsSchema,
|
|
1169
|
-
clis:
|
|
1170
|
-
capabilities:
|
|
1346
|
+
clis: z8.array(CliKindSchema).max(8),
|
|
1347
|
+
capabilities: z8.array(z8.string().min(1).max(64)).max(32).default([])
|
|
1171
1348
|
});
|
|
1172
|
-
var RunnerEnrollmentSchema =
|
|
1173
|
-
deviceCode:
|
|
1174
|
-
userCode:
|
|
1349
|
+
var RunnerEnrollmentSchema = z8.object({
|
|
1350
|
+
deviceCode: z8.string().min(1),
|
|
1351
|
+
userCode: z8.string().min(1),
|
|
1175
1352
|
expiresAt: IsoDateTimeSchema,
|
|
1176
|
-
intervalMs:
|
|
1353
|
+
intervalMs: z8.number().int().positive()
|
|
1177
1354
|
});
|
|
1178
|
-
var RunnerEnrollPollSchema =
|
|
1179
|
-
var RunnerEnrollStatusSchema =
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1355
|
+
var RunnerEnrollPollSchema = z8.object({ deviceCode: z8.string().min(1) });
|
|
1356
|
+
var RunnerEnrollStatusSchema = z8.discriminatedUnion("status", [
|
|
1357
|
+
z8.object({ status: z8.literal("pending") }),
|
|
1358
|
+
z8.object({ status: z8.literal("approved"), name: NameSchema, token: z8.string().min(1) }),
|
|
1359
|
+
z8.object({ status: z8.literal("denied") })
|
|
1183
1360
|
]);
|
|
1184
|
-
var PendingEnrollmentSchema =
|
|
1185
|
-
userCode:
|
|
1186
|
-
hostname:
|
|
1361
|
+
var PendingEnrollmentSchema = z8.object({
|
|
1362
|
+
userCode: z8.string().min(1),
|
|
1363
|
+
hostname: z8.string(),
|
|
1187
1364
|
os: RunnerOsSchema,
|
|
1188
|
-
clis:
|
|
1189
|
-
capabilities:
|
|
1190
|
-
version:
|
|
1365
|
+
clis: z8.array(CliKindSchema),
|
|
1366
|
+
capabilities: z8.array(z8.string()),
|
|
1367
|
+
version: z8.string(),
|
|
1191
1368
|
requestedAt: IsoDateTimeSchema,
|
|
1192
1369
|
expiresAt: IsoDateTimeSchema
|
|
1193
1370
|
});
|
|
1194
|
-
var ProjectRepoSchema =
|
|
1371
|
+
var ProjectRepoSchema = z8.object({
|
|
1195
1372
|
slug: NameSchema,
|
|
1196
|
-
origin:
|
|
1197
|
-
defaultBranch:
|
|
1373
|
+
origin: z8.string().nullable(),
|
|
1374
|
+
defaultBranch: z8.string().min(1),
|
|
1198
1375
|
/**
|
|
1199
1376
|
* The board lands finished tasks on the default branch, itself or through their pull requests,
|
|
1200
1377
|
* so the runner lets nothing else move it.
|
|
1201
1378
|
*/
|
|
1202
|
-
boardLands:
|
|
1379
|
+
boardLands: z8.boolean()
|
|
1203
1380
|
});
|
|
1204
|
-
var TurnWorkspaceSchema =
|
|
1205
|
-
|
|
1206
|
-
kind:
|
|
1381
|
+
var TurnWorkspaceSchema = z8.discriminatedUnion("kind", [
|
|
1382
|
+
z8.object({
|
|
1383
|
+
kind: z8.literal("home"),
|
|
1207
1384
|
thread: UlidSchema.optional(),
|
|
1208
1385
|
channel: NameSchema.optional()
|
|
1209
1386
|
}),
|
|
1210
|
-
|
|
1211
|
-
kind:
|
|
1387
|
+
z8.object({
|
|
1388
|
+
kind: z8.literal("project"),
|
|
1212
1389
|
repo: ProjectRepoSchema,
|
|
1213
|
-
branches:
|
|
1390
|
+
branches: z8.array(z8.string().min(1)),
|
|
1214
1391
|
thread: UlidSchema.optional(),
|
|
1215
1392
|
channel: NameSchema.optional()
|
|
1216
1393
|
}),
|
|
1217
|
-
|
|
1394
|
+
z8.object({ kind: z8.literal("task"), repo: ProjectRepoSchema, taskId: UlidSchema })
|
|
1218
1395
|
]);
|
|
1219
|
-
var TurnJobSchema =
|
|
1396
|
+
var TurnJobSchema = z8.object({
|
|
1220
1397
|
turnId: UlidSchema,
|
|
1221
1398
|
agent: NameSchema,
|
|
1222
1399
|
role: NameSchema,
|
|
1223
1400
|
cli: CliKindSchema,
|
|
1224
|
-
model:
|
|
1401
|
+
model: z8.string().optional(),
|
|
1225
1402
|
/** The reasoning effort set on the agent; absent for the model's own default. */
|
|
1226
|
-
effort:
|
|
1403
|
+
effort: z8.string().optional(),
|
|
1227
1404
|
/** A project slug, or the society scope. */
|
|
1228
1405
|
scope: NameSchema,
|
|
1229
1406
|
/** The thread whose conversation the turn is in; absent for the home conversation. */
|
|
@@ -1234,125 +1411,130 @@ var TurnJobSchema = z7.object({
|
|
|
1234
1411
|
* The session to resume, or null to start one: the CLI's adapter picks a fresh session's id, and
|
|
1235
1412
|
* the outcome reports it.
|
|
1236
1413
|
*/
|
|
1237
|
-
session:
|
|
1414
|
+
session: z8.string().min(1).nullable(),
|
|
1238
1415
|
/** The running total the session reported after its last turn, which a resumed session starts from. */
|
|
1239
|
-
costSoFarUsd:
|
|
1416
|
+
costSoFarUsd: z8.number().nonnegative(),
|
|
1240
1417
|
/** The rendered charter, norms, memory core, and skills index, with `PATH_TOKENS` for places. */
|
|
1241
|
-
instructions:
|
|
1242
|
-
prompt:
|
|
1243
|
-
mcp:
|
|
1244
|
-
limits:
|
|
1245
|
-
timeoutMs:
|
|
1246
|
-
maxTurns:
|
|
1418
|
+
instructions: z8.string(),
|
|
1419
|
+
prompt: z8.string(),
|
|
1420
|
+
mcp: z8.object({ url: z8.string().min(1), token: z8.string().min(1) }),
|
|
1421
|
+
limits: z8.object({
|
|
1422
|
+
timeoutMs: z8.number().int().positive().nullable(),
|
|
1423
|
+
maxTurns: z8.number().int().positive().nullable()
|
|
1247
1424
|
}),
|
|
1248
1425
|
/** Present when the runner keeps the conversation's session warm between turns, under `key`. */
|
|
1249
|
-
resident:
|
|
1426
|
+
resident: z8.object({ key: z8.string().min(1), idleMs: z8.number().int().positive() }).optional(),
|
|
1250
1427
|
workspace: TurnWorkspaceSchema
|
|
1251
1428
|
});
|
|
1252
|
-
var TurnWorkSchema =
|
|
1253
|
-
var TurnEventsSchema =
|
|
1254
|
-
var TurnOutcomeSchema =
|
|
1429
|
+
var TurnWorkSchema = z8.object({ branch: z8.string().min(1), head: z8.string().min(1) });
|
|
1430
|
+
var TurnEventsSchema = z8.object({ entries: z8.array(TranscriptEntrySchema) });
|
|
1431
|
+
var TurnOutcomeSchema = z8.object({
|
|
1255
1432
|
exitReason: TurnExitReasonSchema,
|
|
1256
1433
|
status: TurnStatusSchema.nullable(),
|
|
1257
|
-
error:
|
|
1434
|
+
error: z8.string().nullable(),
|
|
1258
1435
|
usage: UsageSchema,
|
|
1259
|
-
costUsd:
|
|
1436
|
+
costUsd: z8.number().nonnegative(),
|
|
1260
1437
|
/** The session's running total after this turn, for CLIs that report one. */
|
|
1261
|
-
sessionCostUsd:
|
|
1438
|
+
sessionCostUsd: z8.number().nonnegative().optional(),
|
|
1262
1439
|
/** The session the CLI used, which differs from the job's for CLIs that assign their own ids. */
|
|
1263
|
-
session:
|
|
1440
|
+
session: z8.string().min(1),
|
|
1264
1441
|
/** The model the CLI reported, when it reported one. */
|
|
1265
|
-
model:
|
|
1442
|
+
model: z8.string().nullable(),
|
|
1266
1443
|
work: TurnWorkSchema.nullable(),
|
|
1267
1444
|
/**
|
|
1268
1445
|
* Whether the turn's own workspace, a thread's, a channel's, or a task's, holds work on no
|
|
1269
1446
|
* branch after the hand-back: uncommitted changes, or commits no branch contains.
|
|
1270
1447
|
*/
|
|
1271
|
-
leftovers:
|
|
1448
|
+
leftovers: z8.boolean().default(false),
|
|
1449
|
+
/**
|
|
1450
|
+
* The CLI's plan quota as the turn's stream last reported it, when it reported any; a runner from
|
|
1451
|
+
* before never sends it.
|
|
1452
|
+
*/
|
|
1453
|
+
quota: CliQuotaSchema.optional()
|
|
1272
1454
|
});
|
|
1273
|
-
var TurnAckSchema =
|
|
1274
|
-
var LandRequestSchema =
|
|
1455
|
+
var TurnAckSchema = z8.object({ dropWorkspace: z8.boolean() });
|
|
1456
|
+
var LandRequestSchema = z8.object({
|
|
1275
1457
|
repo: ProjectRepoSchema,
|
|
1276
|
-
branch:
|
|
1458
|
+
branch: z8.string().min(1),
|
|
1277
1459
|
/**
|
|
1278
1460
|
* For a `ghpr` task, the pull request to merge in place of the branch, which must hold the
|
|
1279
1461
|
* branch's files, and the merge commit's subject and body, the pull request's title and an
|
|
1280
1462
|
* empty body when left out.
|
|
1281
1463
|
*/
|
|
1282
|
-
pullRequest:
|
|
1283
|
-
url:
|
|
1284
|
-
subject:
|
|
1285
|
-
body:
|
|
1464
|
+
pullRequest: z8.object({
|
|
1465
|
+
url: z8.string().min(1),
|
|
1466
|
+
subject: z8.string().min(1).optional(),
|
|
1467
|
+
body: z8.string().optional()
|
|
1286
1468
|
}).optional()
|
|
1287
1469
|
});
|
|
1288
|
-
var CloseRequestSchema =
|
|
1470
|
+
var CloseRequestSchema = z8.object({
|
|
1289
1471
|
repo: ProjectRepoSchema,
|
|
1290
|
-
url:
|
|
1291
|
-
comment:
|
|
1472
|
+
url: z8.string().min(1),
|
|
1473
|
+
comment: z8.string().min(1)
|
|
1292
1474
|
});
|
|
1293
|
-
var MergeOutcomeSchema =
|
|
1294
|
-
var ModelListSchema =
|
|
1475
|
+
var MergeOutcomeSchema = z8.object({ ok: z8.boolean(), detail: z8.string() });
|
|
1476
|
+
var ModelListSchema = z8.array(ModelOptionSchema);
|
|
1295
1477
|
var BRANCH_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
|
|
1296
|
-
var BranchPathSchema =
|
|
1297
|
-
var BranchNameSchema =
|
|
1298
|
-
var BranchReadSchema =
|
|
1478
|
+
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" });
|
|
1479
|
+
var BranchNameSchema = z8.string().regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/);
|
|
1480
|
+
var BranchReadSchema = z8.object({
|
|
1299
1481
|
repo: ProjectRepoSchema,
|
|
1300
1482
|
branch: BranchNameSchema,
|
|
1301
1483
|
path: BranchPathSchema
|
|
1302
1484
|
});
|
|
1303
|
-
var BranchCommitSchema =
|
|
1304
|
-
id:
|
|
1485
|
+
var BranchCommitSchema = z8.object({
|
|
1486
|
+
id: z8.string().min(1),
|
|
1305
1487
|
at: IsoDateTimeSchema,
|
|
1306
|
-
author:
|
|
1488
|
+
author: z8.string()
|
|
1307
1489
|
});
|
|
1308
|
-
var BranchFileSchema =
|
|
1309
|
-
|
|
1310
|
-
kind:
|
|
1490
|
+
var BranchFileSchema = z8.discriminatedUnion("kind", [
|
|
1491
|
+
z8.object({
|
|
1492
|
+
kind: z8.literal("file"),
|
|
1311
1493
|
path: BranchPathSchema,
|
|
1312
1494
|
commit: BranchCommitSchema,
|
|
1313
|
-
size:
|
|
1314
|
-
content:
|
|
1495
|
+
size: z8.number().int().nonnegative(),
|
|
1496
|
+
content: z8.string().nullable()
|
|
1315
1497
|
}),
|
|
1316
|
-
|
|
1317
|
-
kind:
|
|
1498
|
+
z8.object({
|
|
1499
|
+
kind: z8.literal("dir"),
|
|
1318
1500
|
path: BranchPathSchema,
|
|
1319
1501
|
commit: BranchCommitSchema,
|
|
1320
|
-
entries:
|
|
1321
|
-
name:
|
|
1322
|
-
kind:
|
|
1323
|
-
size:
|
|
1502
|
+
entries: z8.array(z8.object({
|
|
1503
|
+
name: z8.string().min(1),
|
|
1504
|
+
kind: z8.enum(["file", "dir"]),
|
|
1505
|
+
size: z8.number().int().nonnegative().nullable()
|
|
1324
1506
|
}))
|
|
1325
1507
|
})
|
|
1326
1508
|
]);
|
|
1327
|
-
var BranchChangesReadSchema =
|
|
1509
|
+
var BranchChangesReadSchema = z8.object({
|
|
1328
1510
|
repo: ProjectRepoSchema,
|
|
1329
1511
|
branch: BranchNameSchema
|
|
1330
1512
|
});
|
|
1331
|
-
var BranchFileChangeSchema =
|
|
1332
|
-
path:
|
|
1333
|
-
status:
|
|
1513
|
+
var BranchFileChangeSchema = z8.object({
|
|
1514
|
+
path: z8.string().min(1),
|
|
1515
|
+
status: z8.enum(["added", "modified", "deleted"]),
|
|
1334
1516
|
/** Lines added and removed, or null for a binary file. */
|
|
1335
|
-
added:
|
|
1336
|
-
removed:
|
|
1517
|
+
added: z8.number().int().nonnegative().nullable(),
|
|
1518
|
+
removed: z8.number().int().nonnegative().nullable(),
|
|
1337
1519
|
/** Absent when the file changed only through a merge of another branch. */
|
|
1338
|
-
lastChange:
|
|
1520
|
+
lastChange: z8.object({ author: z8.string(), at: IsoDateTimeSchema }).optional()
|
|
1339
1521
|
});
|
|
1340
|
-
var BranchChangesSchema =
|
|
1522
|
+
var BranchChangesSchema = z8.object({
|
|
1341
1523
|
head: BranchCommitSchema,
|
|
1342
|
-
files:
|
|
1343
|
-
total:
|
|
1524
|
+
files: z8.array(BranchFileChangeSchema),
|
|
1525
|
+
total: z8.number().int().nonnegative()
|
|
1344
1526
|
});
|
|
1345
|
-
var BranchDiffReadSchema =
|
|
1527
|
+
var BranchDiffReadSchema = z8.object({
|
|
1346
1528
|
repo: ProjectRepoSchema,
|
|
1347
1529
|
branch: BranchNameSchema,
|
|
1348
1530
|
path: BranchPathSchema.min(1)
|
|
1349
1531
|
});
|
|
1350
|
-
var BranchFileDiffSchema =
|
|
1532
|
+
var BranchFileDiffSchema = z8.object({
|
|
1351
1533
|
head: BranchCommitSchema,
|
|
1352
1534
|
path: BranchPathSchema,
|
|
1353
1535
|
status: BranchFileChangeSchema.shape.status,
|
|
1354
|
-
patch:
|
|
1355
|
-
truncated:
|
|
1536
|
+
patch: z8.string().nullable(),
|
|
1537
|
+
truncated: z8.boolean()
|
|
1356
1538
|
});
|
|
1357
1539
|
function patchHunks(patch, limit) {
|
|
1358
1540
|
if (/^Binary files .* differ$/m.test(patch)) {
|
|
@@ -1366,64 +1548,69 @@ function patchHunks(patch, limit) {
|
|
|
1366
1548
|
const cut = hunks.lastIndexOf("\n", limit);
|
|
1367
1549
|
return { patch: hunks.slice(0, cut === -1 ? limit : cut), truncated: true };
|
|
1368
1550
|
}
|
|
1369
|
-
var WorkspaceConversationSchema =
|
|
1370
|
-
|
|
1371
|
-
|
|
1551
|
+
var WorkspaceConversationSchema = z8.discriminatedUnion("kind", [
|
|
1552
|
+
z8.object({ kind: z8.literal("thread"), id: UlidSchema }),
|
|
1553
|
+
z8.object({ kind: z8.literal("channel"), scope: NameSchema, name: NameSchema })
|
|
1372
1554
|
]);
|
|
1373
|
-
var HeldWorkspaceSchema =
|
|
1555
|
+
var HeldWorkspaceSchema = z8.object({
|
|
1374
1556
|
agent: NameSchema,
|
|
1375
1557
|
scope: NameSchema,
|
|
1376
1558
|
conversation: WorkspaceConversationSchema
|
|
1377
1559
|
});
|
|
1378
|
-
var HeldWorkspacesSchema =
|
|
1379
|
-
var SweepResultSchema =
|
|
1380
|
-
var TurnSteerSchema =
|
|
1381
|
-
var RunnerMessageSchema =
|
|
1382
|
-
|
|
1383
|
-
|
|
1560
|
+
var HeldWorkspacesSchema = z8.object({ workspaces: z8.array(HeldWorkspaceSchema) });
|
|
1561
|
+
var SweepResultSchema = z8.object({ kept: z8.array(HeldWorkspaceSchema) });
|
|
1562
|
+
var TurnSteerSchema = z8.object({ id: z8.uuid(), text: z8.string().min(1) });
|
|
1563
|
+
var RunnerMessageSchema = z8.discriminatedUnion("type", [
|
|
1564
|
+
z8.object({ type: z8.literal("turn"), job: TurnJobSchema }),
|
|
1565
|
+
z8.object({ type: z8.literal("land"), request: z8.string().min(1), land: LandRequestSchema }),
|
|
1384
1566
|
/** Answered with a `MergeOutcome`. */
|
|
1385
|
-
|
|
1386
|
-
|
|
1567
|
+
z8.object({ type: z8.literal("close"), request: z8.string().min(1), close: CloseRequestSchema }),
|
|
1568
|
+
z8.object({ type: z8.literal("models"), request: z8.string().min(1), cli: CliKindSchema }),
|
|
1569
|
+
/**
|
|
1570
|
+
* Answered with a `CliQuota` read from the CLI without a turn, or null when its adapter cannot
|
|
1571
|
+
* read one. Sent only to runners whose hello says `quotaReads`.
|
|
1572
|
+
*/
|
|
1573
|
+
z8.object({ type: z8.literal("quota"), request: z8.string().min(1), cli: CliKindSchema }),
|
|
1387
1574
|
/** Answered with a `BranchFile`, or null when the branch or the path does not exist. */
|
|
1388
|
-
|
|
1575
|
+
z8.object({ type: z8.literal("file"), request: z8.string().min(1), read: BranchReadSchema }),
|
|
1389
1576
|
/** Answered with `BranchChanges`, or null when the repository or the branch does not exist. */
|
|
1390
|
-
|
|
1391
|
-
type:
|
|
1392
|
-
request:
|
|
1577
|
+
z8.object({
|
|
1578
|
+
type: z8.literal("changes"),
|
|
1579
|
+
request: z8.string().min(1),
|
|
1393
1580
|
read: BranchChangesReadSchema
|
|
1394
1581
|
}),
|
|
1395
1582
|
/** Answered with a `BranchFileDiff`, or null when the branch does not exist or left the path alone. */
|
|
1396
|
-
|
|
1583
|
+
z8.object({ type: z8.literal("diff"), request: z8.string().min(1), read: BranchDiffReadSchema }),
|
|
1397
1584
|
/** Answered with whether the CLI accepted it; that it took it comes as a `steered` event. */
|
|
1398
|
-
|
|
1399
|
-
type:
|
|
1400
|
-
request:
|
|
1585
|
+
z8.object({
|
|
1586
|
+
type: z8.literal("steer"),
|
|
1587
|
+
request: z8.string().min(1),
|
|
1401
1588
|
turnId: UlidSchema,
|
|
1402
1589
|
steer: TurnSteerSchema
|
|
1403
1590
|
}),
|
|
1404
1591
|
/** Answered with whether the turn was there to stop; it ends `stopped`. */
|
|
1405
|
-
|
|
1592
|
+
z8.object({ type: z8.literal("stop"), request: z8.string().min(1), turnId: UlidSchema }),
|
|
1406
1593
|
/**
|
|
1407
1594
|
* A conversation ended: the runner removes every citizen's workspace for it but those a turn
|
|
1408
1595
|
* still uses, and answers with a `SweepResult` naming those it kept for holding work on no branch.
|
|
1409
1596
|
*/
|
|
1410
|
-
|
|
1411
|
-
type:
|
|
1412
|
-
request:
|
|
1597
|
+
z8.object({
|
|
1598
|
+
type: z8.literal("sweep"),
|
|
1599
|
+
request: z8.string().min(1),
|
|
1413
1600
|
conversation: WorkspaceConversationSchema
|
|
1414
1601
|
})
|
|
1415
1602
|
]);
|
|
1416
|
-
var RunnerAnswerSchema =
|
|
1417
|
-
|
|
1418
|
-
|
|
1603
|
+
var RunnerAnswerSchema = z8.discriminatedUnion("ok", [
|
|
1604
|
+
z8.object({ ok: z8.literal(true), value: z8.unknown() }),
|
|
1605
|
+
z8.object({ ok: z8.literal(false), error: z8.string() })
|
|
1419
1606
|
]);
|
|
1420
|
-
var WarmSessionsSchema =
|
|
1421
|
-
var FileManifestSchema =
|
|
1607
|
+
var WarmSessionsSchema = z8.object({ warm: z8.array(z8.string()) });
|
|
1608
|
+
var FileManifestSchema = z8.object({ files: z8.record(z8.string(), z8.string()) });
|
|
1422
1609
|
function fileVersion(sha, executable) {
|
|
1423
1610
|
return executable ? `${sha}+x` : sha;
|
|
1424
1611
|
}
|
|
1425
|
-
var FileReadSchema =
|
|
1426
|
-
var FileContentsSchema =
|
|
1612
|
+
var FileReadSchema = z8.object({ paths: z8.array(z8.string()) });
|
|
1613
|
+
var FileContentsSchema = z8.object({ files: z8.record(z8.string(), z8.string()) });
|
|
1427
1614
|
function isSafeRelativePath(file) {
|
|
1428
1615
|
if (file.length === 0 || file.startsWith("/") || file.includes("\\") || file.includes("\0")) {
|
|
1429
1616
|
return false;
|
|
@@ -1432,7 +1619,7 @@ function isSafeRelativePath(file) {
|
|
|
1432
1619
|
}
|
|
1433
1620
|
|
|
1434
1621
|
// packages/shared/dist/turns.js
|
|
1435
|
-
var TriggerKindSchema =
|
|
1622
|
+
var TriggerKindSchema = z9.enum([
|
|
1436
1623
|
"mention",
|
|
1437
1624
|
"stage",
|
|
1438
1625
|
"task_done",
|
|
@@ -1446,11 +1633,11 @@ var TriggerKindSchema = z8.enum([
|
|
|
1446
1633
|
"closing",
|
|
1447
1634
|
"cron"
|
|
1448
1635
|
]);
|
|
1449
|
-
var TriggerSchema =
|
|
1636
|
+
var TriggerSchema = z9.object({
|
|
1450
1637
|
kind: TriggerKindSchema,
|
|
1451
1638
|
from: NameSchema.optional(),
|
|
1452
|
-
fromUser:
|
|
1453
|
-
reason:
|
|
1639
|
+
fromUser: z9.boolean().default(false),
|
|
1640
|
+
reason: z9.string().default(""),
|
|
1454
1641
|
taskId: UlidSchema.optional(),
|
|
1455
1642
|
messageId: UlidSchema.optional(),
|
|
1456
1643
|
/** The channel the waking message was posted in. */
|
|
@@ -1458,17 +1645,17 @@ var TriggerSchema = z8.object({
|
|
|
1458
1645
|
/** The cron that came due, for a `cron` wake. */
|
|
1459
1646
|
cronId: UlidSchema.optional()
|
|
1460
1647
|
});
|
|
1461
|
-
var TurnThreadSchema =
|
|
1462
|
-
var TurnDispatchSchema =
|
|
1648
|
+
var TurnThreadSchema = z9.object({ id: UlidSchema, task: z9.boolean() });
|
|
1649
|
+
var TurnDispatchSchema = z9.object({
|
|
1463
1650
|
agent: NameSchema,
|
|
1464
1651
|
project: NameSchema,
|
|
1465
1652
|
thread: TurnThreadSchema.optional(),
|
|
1466
1653
|
channel: NameSchema.optional(),
|
|
1467
1654
|
trigger: TriggerSchema,
|
|
1468
|
-
priority:
|
|
1469
|
-
onboarding:
|
|
1655
|
+
priority: z9.number().int().min(0).max(2),
|
|
1656
|
+
onboarding: z9.boolean().default(false),
|
|
1470
1657
|
/** Every cron that came due for this turn, whatever wake it merged into; its prompt quotes each. */
|
|
1471
|
-
crons:
|
|
1658
|
+
crons: z9.array(UlidSchema).optional()
|
|
1472
1659
|
});
|
|
1473
1660
|
function conversationPart(conversation) {
|
|
1474
1661
|
return conversation.thread ?? (conversation.channel === void 0 ? void 0 : `#${conversation.channel}`);
|
|
@@ -1479,7 +1666,7 @@ function channelConversation(scope, channel) {
|
|
|
1479
1666
|
const name = at < 0 ? channel : channel.slice(at + 1);
|
|
1480
1667
|
return place === scope && name !== "general" ? name : void 0;
|
|
1481
1668
|
}
|
|
1482
|
-
var TurnRecordSchema =
|
|
1669
|
+
var TurnRecordSchema = z9.object({
|
|
1483
1670
|
/** Assigned by the board when the turn begins; the turn's transcript is filed under it. */
|
|
1484
1671
|
id: UlidSchema.optional(),
|
|
1485
1672
|
agent: NameSchema,
|
|
@@ -1490,31 +1677,31 @@ var TurnRecordSchema = z8.object({
|
|
|
1490
1677
|
channel: NameSchema.optional(),
|
|
1491
1678
|
runner: NameSchema,
|
|
1492
1679
|
cli: CliKindSchema.nullable(),
|
|
1493
|
-
session:
|
|
1680
|
+
session: z9.string().nullable(),
|
|
1494
1681
|
trigger: TriggerSchema,
|
|
1495
1682
|
startedAt: IsoDateTimeSchema,
|
|
1496
1683
|
endedAt: IsoDateTimeSchema.nullable(),
|
|
1497
1684
|
exitReason: TurnExitReasonSchema.nullable(),
|
|
1498
1685
|
status: TurnStatusSchema.nullable(),
|
|
1499
|
-
error:
|
|
1686
|
+
error: z9.string().nullable(),
|
|
1500
1687
|
usage: UsageSchema.nullable(),
|
|
1501
|
-
costUsd:
|
|
1688
|
+
costUsd: z9.number().nonnegative().default(0),
|
|
1502
1689
|
/**
|
|
1503
1690
|
* The running total the CLI reported for the session after this turn, when it reports one. A
|
|
1504
1691
|
* resumed session starts from it, so the next turn's own cost is measured from here.
|
|
1505
1692
|
*/
|
|
1506
|
-
sessionCostUsd:
|
|
1507
|
-
toolCalls:
|
|
1693
|
+
sessionCostUsd: z9.number().nonnegative().optional(),
|
|
1694
|
+
toolCalls: z9.number().int().nonnegative().default(0),
|
|
1508
1695
|
/** The model the CLI reported for this turn, else the model configured for the agent, else null. */
|
|
1509
|
-
model:
|
|
1696
|
+
model: z9.string().nullable().default(null),
|
|
1510
1697
|
/** The task branch the turn left work on, with its commit, as the runner reported it. */
|
|
1511
1698
|
work: TurnWorkSchema.optional(),
|
|
1512
1699
|
/** Who stopped the turn, for one that ended `stopped`. */
|
|
1513
1700
|
stoppedBy: NameSchema.optional(),
|
|
1514
1701
|
/** The crons whose fire started the turn, which record how it ended. */
|
|
1515
|
-
crons:
|
|
1702
|
+
crons: z9.array(UlidSchema).optional()
|
|
1516
1703
|
});
|
|
1517
|
-
var RunningTurnSchema =
|
|
1704
|
+
var RunningTurnSchema = z9.object({
|
|
1518
1705
|
turnId: UlidSchema,
|
|
1519
1706
|
agent: NameSchema,
|
|
1520
1707
|
scope: NameSchema,
|
|
@@ -1522,49 +1709,49 @@ var RunningTurnSchema = z8.object({
|
|
|
1522
1709
|
channel: NameSchema.optional(),
|
|
1523
1710
|
cli: CliKindSchema,
|
|
1524
1711
|
askedIn: ChannelRefSchema.optional(),
|
|
1525
|
-
steerable:
|
|
1526
|
-
stoppable:
|
|
1712
|
+
steerable: z9.boolean(),
|
|
1713
|
+
stoppable: z9.boolean()
|
|
1527
1714
|
});
|
|
1528
|
-
var SessionsFileSchema =
|
|
1529
|
-
claude:
|
|
1530
|
-
codex:
|
|
1715
|
+
var SessionsFileSchema = z9.object({
|
|
1716
|
+
claude: z9.string().optional(),
|
|
1717
|
+
codex: z9.string().optional(),
|
|
1531
1718
|
runner: NameSchema.optional()
|
|
1532
1719
|
});
|
|
1533
|
-
var WakeRequestSchema =
|
|
1720
|
+
var WakeRequestSchema = z9.object({
|
|
1534
1721
|
agent: NameSchema,
|
|
1535
1722
|
project: NameSchema,
|
|
1536
|
-
reason:
|
|
1723
|
+
reason: z9.string().default("manual wake"),
|
|
1537
1724
|
/** A manual wake, or a reflection turn requested ahead of the cadence. */
|
|
1538
|
-
kind:
|
|
1725
|
+
kind: z9.enum(["manual", "reflection"]).default("manual")
|
|
1539
1726
|
});
|
|
1540
|
-
var TurnHistoryEntrySchema =
|
|
1727
|
+
var TurnHistoryEntrySchema = z9.object({
|
|
1541
1728
|
/** The id of the event that ended the turn. */
|
|
1542
1729
|
id: UlidSchema,
|
|
1543
1730
|
/** The turn's own id, when it has a transcript to open; turns before transcripts have none. */
|
|
1544
1731
|
turnId: UlidSchema.optional(),
|
|
1545
1732
|
ts: IsoDateTimeSchema,
|
|
1546
|
-
outcome:
|
|
1733
|
+
outcome: z9.enum(["completed", "failed"]),
|
|
1547
1734
|
/** A project slug, or the society scope. */
|
|
1548
1735
|
project: NameSchema,
|
|
1549
1736
|
/** The thread whose conversation the turn was in; absent for the home conversation. */
|
|
1550
1737
|
thread: UlidSchema.optional(),
|
|
1551
1738
|
/** The channel, never general, whose conversation the turn was in. */
|
|
1552
1739
|
channel: NameSchema.optional(),
|
|
1553
|
-
trigger:
|
|
1554
|
-
exitReason:
|
|
1555
|
-
costUsd:
|
|
1740
|
+
trigger: z9.string(),
|
|
1741
|
+
exitReason: z9.string().nullable(),
|
|
1742
|
+
costUsd: z9.number(),
|
|
1556
1743
|
/** The tokens the turn used; absent for turns logged before turns recorded them. */
|
|
1557
1744
|
usage: UsageSchema.optional(),
|
|
1558
|
-
model:
|
|
1559
|
-
summary:
|
|
1560
|
-
error:
|
|
1745
|
+
model: z9.string().nullable(),
|
|
1746
|
+
summary: z9.string().nullable(),
|
|
1747
|
+
error: z9.string().nullable(),
|
|
1561
1748
|
/** When the log recorded the turn's start; absent when the start is missing from the log. */
|
|
1562
1749
|
startedAt: IsoDateTimeSchema.optional(),
|
|
1563
|
-
toolCalls:
|
|
1750
|
+
toolCalls: z9.number().int().nonnegative().optional()
|
|
1564
1751
|
});
|
|
1565
1752
|
|
|
1566
1753
|
// packages/shared/dist/ops.js
|
|
1567
|
-
import { z as
|
|
1754
|
+
import { z as z10 } from "zod";
|
|
1568
1755
|
var OPS_SIGNAL_KINDS = [
|
|
1569
1756
|
"waiting_stage",
|
|
1570
1757
|
"backlog",
|
|
@@ -1580,16 +1767,16 @@ var OPS_SIGNAL_KINDS = [
|
|
|
1580
1767
|
"stuck_workspace",
|
|
1581
1768
|
"cron_failing"
|
|
1582
1769
|
];
|
|
1583
|
-
var OpsSignalKindSchema =
|
|
1584
|
-
var OpsSignalSchema =
|
|
1770
|
+
var OpsSignalKindSchema = z10.enum(OPS_SIGNAL_KINDS);
|
|
1771
|
+
var OpsSignalSchema = z10.object({
|
|
1585
1772
|
kind: OpsSignalKindSchema,
|
|
1586
1773
|
/** Identifies the condition, for example `backlog:demo:engineer`, so a persisting one is not logged again every pass. */
|
|
1587
|
-
key:
|
|
1774
|
+
key: z10.string().min(1),
|
|
1588
1775
|
/** One line a reader can act on. */
|
|
1589
|
-
summary:
|
|
1776
|
+
summary: z10.string().min(1),
|
|
1590
1777
|
/** The counter or timer value behind the signal. */
|
|
1591
|
-
value:
|
|
1592
|
-
threshold:
|
|
1778
|
+
value: z10.number(),
|
|
1779
|
+
threshold: z10.number().optional(),
|
|
1593
1780
|
project: NameSchema.optional(),
|
|
1594
1781
|
agent: NameSchema.optional(),
|
|
1595
1782
|
role: NameSchema.optional(),
|
|
@@ -1597,8 +1784,8 @@ var OpsSignalSchema = z9.object({
|
|
|
1597
1784
|
});
|
|
1598
1785
|
|
|
1599
1786
|
// packages/shared/dist/metrics.js
|
|
1600
|
-
import { z as
|
|
1601
|
-
var MetricsWindowSchema =
|
|
1787
|
+
import { z as z11 } from "zod";
|
|
1788
|
+
var MetricsWindowSchema = z11.enum(["24h", "7d", "all"]);
|
|
1602
1789
|
var METRICS_WINDOW_MS = {
|
|
1603
1790
|
"24h": 24 * 36e5,
|
|
1604
1791
|
"7d": 7 * 24 * 36e5,
|
|
@@ -1609,9 +1796,9 @@ function isBoardAction(tool) {
|
|
|
1609
1796
|
const verb = /^mcp__board__(.+)$/.exec(tool)?.[1];
|
|
1610
1797
|
return verb !== void 0 && !READ_VERBS.some((read2) => read2 === verb);
|
|
1611
1798
|
}
|
|
1612
|
-
var CountSchema =
|
|
1613
|
-
var MsSchema =
|
|
1614
|
-
var MetricsSchema =
|
|
1799
|
+
var CountSchema = z11.number().int().nonnegative();
|
|
1800
|
+
var MsSchema = z11.number().nonnegative();
|
|
1801
|
+
var MetricsSchema = z11.object({
|
|
1615
1802
|
window: MetricsWindowSchema,
|
|
1616
1803
|
since: IsoDateTimeSchema.nullable(),
|
|
1617
1804
|
until: IsoDateTimeSchema,
|
|
@@ -1619,12 +1806,12 @@ var MetricsSchema = z10.object({
|
|
|
1619
1806
|
* Finished turns that changed nothing on the board. Reflections are left out, since they write
|
|
1620
1807
|
* memory, not the board; turns without a transcript are counted apart, their actions unknown.
|
|
1621
1808
|
*/
|
|
1622
|
-
idle:
|
|
1809
|
+
idle: z11.object({
|
|
1623
1810
|
turns: CountSchema,
|
|
1624
1811
|
idle: CountSchema,
|
|
1625
1812
|
unknown: CountSchema,
|
|
1626
|
-
byTrigger:
|
|
1627
|
-
byAgent:
|
|
1813
|
+
byTrigger: z11.array(z11.object({ trigger: z11.string(), turns: CountSchema, idle: CountSchema })),
|
|
1814
|
+
byAgent: z11.array(z11.object({
|
|
1628
1815
|
agent: NameSchema,
|
|
1629
1816
|
role: NameSchema.nullable(),
|
|
1630
1817
|
turns: CountSchema,
|
|
@@ -1632,33 +1819,33 @@ var MetricsSchema = z10.object({
|
|
|
1632
1819
|
}))
|
|
1633
1820
|
}),
|
|
1634
1821
|
/** Work sent back to an earlier stage: over the tasks finished in the window, and by where. */
|
|
1635
|
-
sentBack:
|
|
1822
|
+
sentBack: z11.object({
|
|
1636
1823
|
finished: CountSchema,
|
|
1637
1824
|
sendBacks: CountSchema,
|
|
1638
1825
|
tasksSentBack: CountSchema,
|
|
1639
|
-
byStage:
|
|
1640
|
-
bySender:
|
|
1826
|
+
byStage: z11.array(z11.object({ project: NameSchema, stage: z11.string(), count: CountSchema })),
|
|
1827
|
+
bySender: z11.array(z11.object({ agent: NameSchema, count: CountSchema }))
|
|
1641
1828
|
}),
|
|
1642
1829
|
/** Posts in the threads of the tasks finished in the window, the board's own notices left out. */
|
|
1643
|
-
messages:
|
|
1830
|
+
messages: z11.object({
|
|
1644
1831
|
finished: CountSchema,
|
|
1645
1832
|
messages: CountSchema,
|
|
1646
|
-
byProject:
|
|
1647
|
-
busiest:
|
|
1833
|
+
byProject: z11.array(z11.object({ project: NameSchema, finished: CountSchema, messages: CountSchema })),
|
|
1834
|
+
busiest: z11.array(z11.object({
|
|
1648
1835
|
taskId: UlidSchema,
|
|
1649
|
-
title:
|
|
1836
|
+
title: z11.string(),
|
|
1650
1837
|
project: NameSchema,
|
|
1651
1838
|
messages: CountSchema
|
|
1652
1839
|
}))
|
|
1653
1840
|
}),
|
|
1654
1841
|
/** Time from a mention to the start of the turn it woke, in the conversation it was made in. */
|
|
1655
|
-
latency:
|
|
1842
|
+
latency: z11.object({
|
|
1656
1843
|
mentions: CountSchema,
|
|
1657
1844
|
/** Mentions no turn has followed yet. */
|
|
1658
1845
|
unanswered: CountSchema,
|
|
1659
1846
|
medianMs: MsSchema.nullable(),
|
|
1660
1847
|
slowestMs: MsSchema.nullable(),
|
|
1661
|
-
byAgent:
|
|
1848
|
+
byAgent: z11.array(z11.object({
|
|
1662
1849
|
agent: NameSchema,
|
|
1663
1850
|
mentions: CountSchema,
|
|
1664
1851
|
medianMs: MsSchema,
|
|
@@ -1666,81 +1853,141 @@ var MetricsSchema = z10.object({
|
|
|
1666
1853
|
}))
|
|
1667
1854
|
}),
|
|
1668
1855
|
/** The user's decisions: proposals decided, questions answered, and stages passed or sent back. */
|
|
1669
|
-
decisions:
|
|
1856
|
+
decisions: z11.object({
|
|
1670
1857
|
total: CountSchema,
|
|
1671
|
-
byDay:
|
|
1672
|
-
day:
|
|
1858
|
+
byDay: z11.array(z11.object({
|
|
1859
|
+
day: z11.string(),
|
|
1673
1860
|
proposals: CountSchema,
|
|
1674
1861
|
answers: CountSchema,
|
|
1675
1862
|
stages: CountSchema
|
|
1676
1863
|
}))
|
|
1677
1864
|
}),
|
|
1678
1865
|
/** Tasks that needed a capability no connected runner offered, and whether they still do. */
|
|
1679
|
-
blocked:
|
|
1866
|
+
blocked: z11.array(z11.object({
|
|
1680
1867
|
taskId: UlidSchema,
|
|
1681
|
-
title:
|
|
1868
|
+
title: z11.string().nullable(),
|
|
1682
1869
|
project: NameSchema.nullable(),
|
|
1683
|
-
summary:
|
|
1870
|
+
summary: z11.string(),
|
|
1684
1871
|
firstAt: IsoDateTimeSchema,
|
|
1685
1872
|
lastAt: IsoDateTimeSchema,
|
|
1686
|
-
holds:
|
|
1873
|
+
holds: z11.boolean()
|
|
1687
1874
|
}))
|
|
1688
1875
|
});
|
|
1876
|
+
var CitizenTokensSchema = z11.object({
|
|
1877
|
+
agent: NameSchema,
|
|
1878
|
+
turns: CountSchema,
|
|
1879
|
+
withUsage: CountSchema,
|
|
1880
|
+
usage: UsageSchema.nullable()
|
|
1881
|
+
});
|
|
1882
|
+
var TokenUseSchema = z11.object({
|
|
1883
|
+
window: MetricsWindowSchema,
|
|
1884
|
+
since: IsoDateTimeSchema.nullable(),
|
|
1885
|
+
until: IsoDateTimeSchema,
|
|
1886
|
+
citizens: z11.array(CitizenTokensSchema)
|
|
1887
|
+
});
|
|
1689
1888
|
|
|
1690
1889
|
// packages/shared/dist/config.js
|
|
1691
|
-
import { z as
|
|
1692
|
-
var LogLevelSchema =
|
|
1693
|
-
var GithubSignInSchema =
|
|
1694
|
-
clientId:
|
|
1695
|
-
clientSecret:
|
|
1890
|
+
import { z as z12 } from "zod";
|
|
1891
|
+
var LogLevelSchema = z12.enum(["trace", "debug", "info", "warn", "error", "fatal"]);
|
|
1892
|
+
var GithubSignInSchema = z12.object({
|
|
1893
|
+
clientId: z12.string().min(1),
|
|
1894
|
+
clientSecret: z12.string().min(1),
|
|
1696
1895
|
/** Logins, lowercased; GitHub logins are case-insensitive. */
|
|
1697
|
-
users:
|
|
1896
|
+
users: z12.array(z12.string().min(1)).min(1)
|
|
1698
1897
|
});
|
|
1699
|
-
var ServerConfigSchema =
|
|
1700
|
-
dataDir:
|
|
1701
|
-
host:
|
|
1702
|
-
port:
|
|
1898
|
+
var ServerConfigSchema = z12.object({
|
|
1899
|
+
dataDir: z12.string().min(1),
|
|
1900
|
+
host: z12.string().min(1),
|
|
1901
|
+
port: z12.number().int().positive().max(65535),
|
|
1703
1902
|
/**
|
|
1704
1903
|
* An address every runner's agents reach this server at, for example https://board.example, or
|
|
1705
1904
|
* null for each runner to use the address it reaches the server at itself.
|
|
1706
1905
|
*/
|
|
1707
|
-
publicUrl:
|
|
1906
|
+
publicUrl: z12.string().min(1).nullable(),
|
|
1708
1907
|
logLevel: LogLevelSchema,
|
|
1709
1908
|
/** Turns running at once across every runner, or null for no limit beyond each runner's own. */
|
|
1710
|
-
concurrency:
|
|
1909
|
+
concurrency: z12.number().int().positive().nullable(),
|
|
1711
1910
|
/** How long one turn may run before it is stopped, or null for no limit. */
|
|
1712
|
-
turnTimeoutMs:
|
|
1911
|
+
turnTimeoutMs: z12.number().int().positive().nullable(),
|
|
1713
1912
|
/** Rounds of tool calls one Claude turn may take, or null for no limit. */
|
|
1714
|
-
toolRounds:
|
|
1913
|
+
toolRounds: z12.number().int().positive().nullable(),
|
|
1715
1914
|
/** How long a resident session stays warm after its last turn. */
|
|
1716
|
-
residentIdleMs:
|
|
1915
|
+
residentIdleMs: z12.number().int().positive(),
|
|
1717
1916
|
/** Signing in to the board with GitHub, or null when only a token lets anyone in. */
|
|
1718
1917
|
github: GithubSignInSchema.nullable(),
|
|
1719
1918
|
/**
|
|
1720
1919
|
* Reverse proxies in front of the server whose X-Forwarded-For entries name the client, for the
|
|
1721
1920
|
* rate limits on what anyone may ask without a token: 0 when clients connect directly.
|
|
1722
1921
|
*/
|
|
1723
|
-
trustedProxies:
|
|
1922
|
+
trustedProxies: z12.number().int().min(0).max(16)
|
|
1724
1923
|
});
|
|
1725
|
-
var RunnerConfigSchema =
|
|
1924
|
+
var RunnerConfigSchema = z12.object({
|
|
1726
1925
|
/** The board server, for example http://127.0.0.1:4700. */
|
|
1727
|
-
serverUrl:
|
|
1926
|
+
serverUrl: z12.string().url(),
|
|
1728
1927
|
/**
|
|
1729
1928
|
* The runner's token, from `runner add`, or null for the one it saved when it was enrolled, or
|
|
1730
1929
|
* to enroll it.
|
|
1731
1930
|
*/
|
|
1732
|
-
token:
|
|
1931
|
+
token: z12.string().min(1).nullable(),
|
|
1733
1932
|
/** The runner's own data directory: the board mirror, agent homes, repositories, worktrees. */
|
|
1734
|
-
dataDir:
|
|
1933
|
+
dataDir: z12.string().min(1),
|
|
1735
1934
|
logLevel: LogLevelSchema,
|
|
1736
1935
|
/** Turns this machine runs at once, or null for no limit. */
|
|
1737
|
-
slots:
|
|
1738
|
-
clis:
|
|
1739
|
-
capabilities:
|
|
1936
|
+
slots: z12.number().int().positive().nullable(),
|
|
1937
|
+
clis: z12.array(CliKindSchema).min(1),
|
|
1938
|
+
capabilities: z12.array(z12.string())
|
|
1740
1939
|
});
|
|
1741
1940
|
|
|
1742
1941
|
// packages/shared/dist/version.js
|
|
1743
|
-
var STELLARIS_VERSION = "0.3.
|
|
1942
|
+
var STELLARIS_VERSION = "0.3.22";
|
|
1943
|
+
|
|
1944
|
+
// packages/shared/dist/mentions.js
|
|
1945
|
+
import { parse, postprocess, preprocess } from "micromark";
|
|
1946
|
+
import { gfm } from "micromark-extension-gfm";
|
|
1947
|
+
var MENTION_PATTERN = /(^|[^\w@])@([a-z0-9][a-z0-9-]{0,31})(?![\w-])/g;
|
|
1948
|
+
var CODE = /* @__PURE__ */ new Set(["codeText", "codeFenced", "codeIndented"]);
|
|
1949
|
+
var SLOW = {
|
|
1950
|
+
disable: {
|
|
1951
|
+
null: [
|
|
1952
|
+
"wwwAutolink",
|
|
1953
|
+
"protocolAutolink",
|
|
1954
|
+
"emailAutolink",
|
|
1955
|
+
"gfmFootnoteCall",
|
|
1956
|
+
"gfmPotentialFootnoteCall"
|
|
1957
|
+
]
|
|
1958
|
+
}
|
|
1959
|
+
};
|
|
1960
|
+
function codeRanges(markdown) {
|
|
1961
|
+
const shift = markdown.startsWith("\uFEFF") ? 1 : 0;
|
|
1962
|
+
const events = postprocess(parse({ extensions: [gfm(), SLOW] }).document().write(preprocess()(markdown, void 0, true)));
|
|
1963
|
+
return events.flatMap(([kind, token]) => kind === "enter" && CODE.has(token.type) ? [[token.start.offset + shift, token.end.offset + shift]] : []);
|
|
1964
|
+
}
|
|
1965
|
+
function addMentions(found, text) {
|
|
1966
|
+
for (const match of text.matchAll(MENTION_PATTERN)) {
|
|
1967
|
+
const name = match[2];
|
|
1968
|
+
if (name !== void 0) {
|
|
1969
|
+
found.add(name);
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
}
|
|
1973
|
+
function mentionsIn(markdown) {
|
|
1974
|
+
if (markdown.search(MENTION_PATTERN) === -1) {
|
|
1975
|
+
return [];
|
|
1976
|
+
}
|
|
1977
|
+
const found = /* @__PURE__ */ new Set();
|
|
1978
|
+
let from = 0;
|
|
1979
|
+
for (const [start, end] of codeRanges(markdown)) {
|
|
1980
|
+
addMentions(found, markdown.slice(from, start));
|
|
1981
|
+
from = end;
|
|
1982
|
+
}
|
|
1983
|
+
addMentions(found, markdown.slice(from));
|
|
1984
|
+
return [...found].toSorted();
|
|
1985
|
+
}
|
|
1986
|
+
function mentionsAnywhere(text) {
|
|
1987
|
+
const found = /* @__PURE__ */ new Set();
|
|
1988
|
+
addMentions(found, text);
|
|
1989
|
+
return [...found].toSorted();
|
|
1990
|
+
}
|
|
1744
1991
|
|
|
1745
1992
|
// packages/board-core/dist/errors.js
|
|
1746
1993
|
var BoardError = class extends Error {
|
|
@@ -2383,33 +2630,59 @@ function filesOf(lines, status) {
|
|
|
2383
2630
|
return [...files.values()];
|
|
2384
2631
|
}
|
|
2385
2632
|
|
|
2633
|
+
// packages/board-core/dist/mentions.js
|
|
2634
|
+
import vm from "node:vm";
|
|
2635
|
+
var MENTION_PARSE_MS = 500;
|
|
2636
|
+
var context = vm.createContext({});
|
|
2637
|
+
var call = new vm.Script("work()");
|
|
2638
|
+
function within(work, ms) {
|
|
2639
|
+
let result;
|
|
2640
|
+
context["work"] = () => {
|
|
2641
|
+
result = work();
|
|
2642
|
+
};
|
|
2643
|
+
try {
|
|
2644
|
+
call.runInContext(context, { timeout: ms });
|
|
2645
|
+
} catch (error) {
|
|
2646
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ERR_SCRIPT_EXECUTION_TIMEOUT") {
|
|
2647
|
+
return void 0;
|
|
2648
|
+
}
|
|
2649
|
+
throw error;
|
|
2650
|
+
} finally {
|
|
2651
|
+
context["work"] = void 0;
|
|
2652
|
+
}
|
|
2653
|
+
return result;
|
|
2654
|
+
}
|
|
2655
|
+
function postMentions(body) {
|
|
2656
|
+
return within(() => mentionsIn(body), MENTION_PARSE_MS) ?? mentionsAnywhere(body);
|
|
2657
|
+
}
|
|
2658
|
+
|
|
2386
2659
|
// packages/board-core/dist/metrics.js
|
|
2387
|
-
import { z as
|
|
2388
|
-
var TurnPayload =
|
|
2389
|
-
turnId:
|
|
2390
|
-
project:
|
|
2391
|
-
thread:
|
|
2392
|
-
channel:
|
|
2393
|
-
trigger:
|
|
2394
|
-
});
|
|
2395
|
-
var TaskPayload =
|
|
2396
|
-
taskId:
|
|
2397
|
-
project:
|
|
2398
|
-
from:
|
|
2399
|
-
});
|
|
2400
|
-
var MessagePayload =
|
|
2401
|
-
id:
|
|
2402
|
-
channel:
|
|
2403
|
-
thread:
|
|
2404
|
-
mentions:
|
|
2405
|
-
});
|
|
2406
|
-
var SteeredPayload =
|
|
2407
|
-
var SignalPayload =
|
|
2408
|
-
kind:
|
|
2409
|
-
key:
|
|
2410
|
-
summary:
|
|
2411
|
-
taskId:
|
|
2412
|
-
project:
|
|
2660
|
+
import { z as z13 } from "zod";
|
|
2661
|
+
var TurnPayload = z13.object({
|
|
2662
|
+
turnId: z13.string().optional(),
|
|
2663
|
+
project: z13.string(),
|
|
2664
|
+
thread: z13.string().optional(),
|
|
2665
|
+
channel: z13.string().optional(),
|
|
2666
|
+
trigger: z13.string()
|
|
2667
|
+
});
|
|
2668
|
+
var TaskPayload = z13.object({
|
|
2669
|
+
taskId: z13.string(),
|
|
2670
|
+
project: z13.string(),
|
|
2671
|
+
from: z13.string().optional()
|
|
2672
|
+
});
|
|
2673
|
+
var MessagePayload = z13.object({
|
|
2674
|
+
id: z13.string().optional(),
|
|
2675
|
+
channel: z13.string(),
|
|
2676
|
+
thread: z13.string().nullable().optional(),
|
|
2677
|
+
mentions: z13.array(z13.string()).default([])
|
|
2678
|
+
});
|
|
2679
|
+
var SteeredPayload = z13.object({ messages: z13.array(z13.string()) });
|
|
2680
|
+
var SignalPayload = z13.object({
|
|
2681
|
+
kind: z13.string(),
|
|
2682
|
+
key: z13.string(),
|
|
2683
|
+
summary: z13.string(),
|
|
2684
|
+
taskId: z13.string().optional(),
|
|
2685
|
+
project: z13.string().optional()
|
|
2413
2686
|
});
|
|
2414
2687
|
function median(values) {
|
|
2415
2688
|
const sorted = values.toSorted((a, b) => a - b);
|
|
@@ -2698,6 +2971,59 @@ function computeMetrics(input) {
|
|
|
2698
2971
|
};
|
|
2699
2972
|
}
|
|
2700
2973
|
|
|
2974
|
+
// packages/board-core/dist/turn-history.js
|
|
2975
|
+
import { z as z14 } from "zod";
|
|
2976
|
+
var TurnHistoryPayloadSchema = z14.object({
|
|
2977
|
+
project: NameSchema,
|
|
2978
|
+
thread: UlidSchema.optional(),
|
|
2979
|
+
channel: NameSchema.optional(),
|
|
2980
|
+
trigger: z14.string().default("manual"),
|
|
2981
|
+
exitReason: z14.string().nullable().default(null),
|
|
2982
|
+
costUsd: z14.number().default(0),
|
|
2983
|
+
usage: UsageSchema.optional(),
|
|
2984
|
+
model: z14.string().nullable().default(null),
|
|
2985
|
+
summary: z14.string().nullable().default(null),
|
|
2986
|
+
error: z14.string().nullable().default(null),
|
|
2987
|
+
toolCalls: z14.number().int().nonnegative().optional(),
|
|
2988
|
+
turnId: UlidSchema.optional()
|
|
2989
|
+
});
|
|
2990
|
+
function tokenUse(events, window, now) {
|
|
2991
|
+
const span = METRICS_WINDOW_MS[window];
|
|
2992
|
+
const since = span === null ? null : now.getTime() - span;
|
|
2993
|
+
const rows = /* @__PURE__ */ new Map();
|
|
2994
|
+
for (const event of events) {
|
|
2995
|
+
if (event.type !== "turn.completed" && event.type !== "turn.failed") {
|
|
2996
|
+
continue;
|
|
2997
|
+
}
|
|
2998
|
+
if (since !== null && Date.parse(event.ts) < since) {
|
|
2999
|
+
continue;
|
|
3000
|
+
}
|
|
3001
|
+
const turn2 = TurnHistoryPayloadSchema.safeParse(event.payload);
|
|
3002
|
+
if (!turn2.success) {
|
|
3003
|
+
continue;
|
|
3004
|
+
}
|
|
3005
|
+
const row = rows.get(event.actor) ?? {
|
|
3006
|
+
agent: event.actor,
|
|
3007
|
+
turns: 0,
|
|
3008
|
+
withUsage: 0,
|
|
3009
|
+
usage: null
|
|
3010
|
+
};
|
|
3011
|
+
const usage = turn2.data.usage;
|
|
3012
|
+
rows.set(event.actor, {
|
|
3013
|
+
agent: event.actor,
|
|
3014
|
+
turns: row.turns + 1,
|
|
3015
|
+
withUsage: row.withUsage + (usage === void 0 ? 0 : 1),
|
|
3016
|
+
usage: usage === void 0 ? row.usage : row.usage === null ? usage : addUsage(row.usage, usage)
|
|
3017
|
+
});
|
|
3018
|
+
}
|
|
3019
|
+
return {
|
|
3020
|
+
window,
|
|
3021
|
+
since: since === null ? null : new Date(since).toISOString(),
|
|
3022
|
+
until: now.toISOString(),
|
|
3023
|
+
citizens: [...rows.values()].toSorted((a, b) => a.agent.localeCompare(b.agent))
|
|
3024
|
+
};
|
|
3025
|
+
}
|
|
3026
|
+
|
|
2701
3027
|
// packages/board-core/dist/mutex.js
|
|
2702
3028
|
var Mutex = class {
|
|
2703
3029
|
tail = Promise.resolve();
|
|
@@ -2939,41 +3265,27 @@ function namesList(names) {
|
|
|
2939
3265
|
return names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names.at(-1) ?? ""}`;
|
|
2940
3266
|
}
|
|
2941
3267
|
var SKIPPED_IN_HOME = /* @__PURE__ */ new Set([".git", "turns", ".claude", ".codex"]);
|
|
2942
|
-
var RunnerTokensSchema =
|
|
2943
|
-
runners:
|
|
3268
|
+
var RunnerTokensSchema = z15.object({
|
|
3269
|
+
runners: z15.record(z15.string(), z15.object({ tokenHash: z15.string().min(1) }))
|
|
2944
3270
|
});
|
|
2945
|
-
var SignInsSchema =
|
|
2946
|
-
signIns:
|
|
2947
|
-
tokenHash:
|
|
2948
|
-
login:
|
|
3271
|
+
var SignInsSchema = z15.object({
|
|
3272
|
+
signIns: z15.array(z15.object({
|
|
3273
|
+
tokenHash: z15.string().min(1),
|
|
3274
|
+
login: z15.string().min(1),
|
|
2949
3275
|
/** The account's picture at the identity provider; sign-ins from before it have none. */
|
|
2950
|
-
avatarUrl:
|
|
3276
|
+
avatarUrl: z15.url().optional(),
|
|
2951
3277
|
createdAt: IsoDateTimeSchema,
|
|
2952
3278
|
expiresAt: IsoDateTimeSchema
|
|
2953
3279
|
})).default([])
|
|
2954
3280
|
});
|
|
2955
|
-
var
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
costUsd: z13.number().default(0),
|
|
2962
|
-
usage: UsageSchema.optional(),
|
|
2963
|
-
model: z13.string().nullable().default(null),
|
|
2964
|
-
summary: z13.string().nullable().default(null),
|
|
2965
|
-
error: z13.string().nullable().default(null),
|
|
2966
|
-
toolCalls: z13.number().int().nonnegative().optional(),
|
|
2967
|
-
turnId: UlidSchema.optional()
|
|
2968
|
-
});
|
|
2969
|
-
var TurnStartPayloadSchema = z13.object({ project: NameSchema, turnId: UlidSchema.optional() });
|
|
2970
|
-
var CursorsSchema = z13.object({
|
|
2971
|
-
digest: z13.string().nullable(),
|
|
2972
|
-
scopes: z13.record(z13.string(), z13.string()).default({}),
|
|
2973
|
-
threadsFrom: z13.record(z13.string(), z13.string().nullable()).default({}),
|
|
2974
|
-
channelsFrom: z13.record(z13.string(), z13.string().nullable()).default({}),
|
|
3281
|
+
var TurnStartPayloadSchema = z15.object({ project: NameSchema, turnId: UlidSchema.optional() });
|
|
3282
|
+
var CursorsSchema = z15.object({
|
|
3283
|
+
digest: z15.string().nullable(),
|
|
3284
|
+
scopes: z15.record(z15.string(), z15.string()).default({}),
|
|
3285
|
+
threadsFrom: z15.record(z15.string(), z15.string().nullable()).default({}),
|
|
3286
|
+
channelsFrom: z15.record(z15.string(), z15.string().nullable()).default({}),
|
|
2975
3287
|
/** How far a work role has read news, which goes to whichever of its general conversations reads first. */
|
|
2976
|
-
news:
|
|
3288
|
+
news: z15.string().optional()
|
|
2977
3289
|
});
|
|
2978
3290
|
var NO_CURSORS = { digest: null, scopes: {}, threadsFrom: {}, channelsFrom: {} };
|
|
2979
3291
|
function conversationKey(scope, part) {
|
|
@@ -3012,9 +3324,8 @@ function byId(a, b) {
|
|
|
3012
3324
|
function turnTime(record) {
|
|
3013
3325
|
return record.endedAt ?? record.startedAt;
|
|
3014
3326
|
}
|
|
3015
|
-
var PausedSchema =
|
|
3327
|
+
var PausedSchema = z15.object({ paused: z15.boolean() });
|
|
3016
3328
|
var DEFAULT_LEASE_MS = 30 * 60 * 1e3;
|
|
3017
|
-
var MENTION_PATTERN = /(^|[^\w@])@([a-z0-9][a-z0-9-]{0,31})(?![\w-])/g;
|
|
3018
3329
|
function withoutMentions(text) {
|
|
3019
3330
|
return text.replaceAll(MENTION_PATTERN, "$1$2");
|
|
3020
3331
|
}
|
|
@@ -3038,7 +3349,7 @@ var OPS_WAKE_TRIGGER = "ops_event";
|
|
|
3038
3349
|
var FRONT_DESK_TRIGGER = "user_post";
|
|
3039
3350
|
var OPS_CHANNELS = ["governance"];
|
|
3040
3351
|
var FRONT_DESK_CHANNELS = [ASK_CHANNEL];
|
|
3041
|
-
var AlignmentsSchema =
|
|
3352
|
+
var AlignmentsSchema = z15.object({ applied: z15.array(z15.string()).default([]) });
|
|
3042
3353
|
var FOLLOW_DECISIONS = "ops-readers-follow-decisions";
|
|
3043
3354
|
var THREAD_RECORDS = "threads-as-records";
|
|
3044
3355
|
var DIGEST_CURSORS = "digest-replaces-inbox";
|
|
@@ -3052,10 +3363,10 @@ var CHANNEL_CONVERSATIONS = "channel-conversations";
|
|
|
3052
3363
|
var DASHBOARD_UPDATES = "dashboard-updates-granted";
|
|
3053
3364
|
var CRON_VERBS = "cron-verbs-granted";
|
|
3054
3365
|
var KNOWLEDGE_NOTICES = "knowledge-notices";
|
|
3055
|
-
var KnowledgeEventSchema =
|
|
3366
|
+
var KnowledgeEventSchema = z15.object({
|
|
3056
3367
|
topic: NameSchema,
|
|
3057
3368
|
project: NameSchema.nullable(),
|
|
3058
|
-
replaced:
|
|
3369
|
+
replaced: z15.boolean().optional()
|
|
3059
3370
|
});
|
|
3060
3371
|
var CRON_VERB_NAMES = ["create_cron", "update_cron", "remove_cron"];
|
|
3061
3372
|
var OLD_DASHBOARD_LINE = "Agents may edit this file. It is rendered by the board UI.";
|
|
@@ -3173,16 +3484,6 @@ function unanswered(messages) {
|
|
|
3173
3484
|
}
|
|
3174
3485
|
return waiting;
|
|
3175
3486
|
}
|
|
3176
|
-
function extractMentions(body) {
|
|
3177
|
-
const found = /* @__PURE__ */ new Set();
|
|
3178
|
-
for (const match of body.matchAll(MENTION_PATTERN)) {
|
|
3179
|
-
const name = match[2];
|
|
3180
|
-
if (name !== void 0) {
|
|
3181
|
-
found.add(name);
|
|
3182
|
-
}
|
|
3183
|
-
}
|
|
3184
|
-
return [...found].toSorted();
|
|
3185
|
-
}
|
|
3186
3487
|
function snippetAround(text, query, radius = 80) {
|
|
3187
3488
|
const index = text.toLowerCase().indexOf(query.toLowerCase());
|
|
3188
3489
|
if (index === -1) {
|
|
@@ -3510,7 +3811,7 @@ var Board = class _Board {
|
|
|
3510
3811
|
}
|
|
3511
3812
|
}
|
|
3512
3813
|
for (const file of await listFiles(this.paths.tasks(slug))) {
|
|
3513
|
-
const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file),
|
|
3814
|
+
const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file), z15.record(z15.string(), z15.unknown()));
|
|
3514
3815
|
const legacy = raw.data["thread"];
|
|
3515
3816
|
if (legacy === void 0) {
|
|
3516
3817
|
continue;
|
|
@@ -3588,7 +3889,7 @@ var Board = class _Board {
|
|
|
3588
3889
|
* turns, so it follows nothing now.
|
|
3589
3890
|
*/
|
|
3590
3891
|
async renameInboxCursors() {
|
|
3591
|
-
const Legacy =
|
|
3892
|
+
const Legacy = z15.object({ inbox: z15.string().nullable() });
|
|
3592
3893
|
for (const agent2 of await this.listAgents()) {
|
|
3593
3894
|
const file = this.paths.agentCursors(agent2.name);
|
|
3594
3895
|
if (await exists(file)) {
|
|
@@ -3634,7 +3935,7 @@ ${charter.purpose}
|
|
|
3634
3935
|
*/
|
|
3635
3936
|
async alignSeedRole(seed) {
|
|
3636
3937
|
const file = this.paths.role(seed.name);
|
|
3637
|
-
const raw = await readMarkdown(file,
|
|
3938
|
+
const raw = await readMarkdown(file, z15.record(z15.string(), z15.unknown()));
|
|
3638
3939
|
const current = RoleCharterSchema.parse(raw.data);
|
|
3639
3940
|
const verbsAdded = seed.verbs.filter((verb) => !current.verbs.includes(verb));
|
|
3640
3941
|
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));
|
|
@@ -3951,7 +4252,7 @@ ${charter.purpose}
|
|
|
3951
4252
|
/** The society's norms, the one knowledge topic every turn loads. Empty until the steward writes it. */
|
|
3952
4253
|
async readSocietyNorms() {
|
|
3953
4254
|
const file = this.paths.societyKnowledgeFile("norms");
|
|
3954
|
-
return await exists(file) ? (await readMarkdown(file,
|
|
4255
|
+
return await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
|
|
3955
4256
|
}
|
|
3956
4257
|
/** Knowledge topics of a project, or of the society when the project is null. */
|
|
3957
4258
|
async listKnowledge(project2) {
|
|
@@ -3971,7 +4272,7 @@ ${charter.purpose}
|
|
|
3971
4272
|
*/
|
|
3972
4273
|
async knowledgeAt(file, project2, topic) {
|
|
3973
4274
|
const { data, body } = await readLooseMarkdown(file);
|
|
3974
|
-
const revision =
|
|
4275
|
+
const revision = z15.number().int().min(0).safeParse(data["revision"]);
|
|
3975
4276
|
const updatedBy = NameSchema.safeParse(data["updatedBy"]);
|
|
3976
4277
|
const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
|
|
3977
4278
|
return {
|
|
@@ -4304,8 +4605,11 @@ ${DASHBOARD_LINE}
|
|
|
4304
4605
|
throw new BoardError("NOT_FOUND", `runner ${name} not found`);
|
|
4305
4606
|
}
|
|
4306
4607
|
const doc = await readMarkdown(file, RunnerSchema);
|
|
4608
|
+
const { gitIdentityMissing: reported, ...rest } = doc.data;
|
|
4609
|
+
const gitIdentityMissing = patch.gitIdentityMissing === void 0 ? reported : patch.gitIdentityMissing ?? void 0;
|
|
4307
4610
|
const next = RunnerSchema.parse({
|
|
4308
|
-
...
|
|
4611
|
+
...rest,
|
|
4612
|
+
...gitIdentityMissing === void 0 ? {} : { gitIdentityMissing: [...gitIdentityMissing] },
|
|
4309
4613
|
...patch.status === void 0 ? {} : { status: patch.status },
|
|
4310
4614
|
...patch.os === void 0 ? {} : { os: patch.os },
|
|
4311
4615
|
...patch.clis === void 0 ? {} : { clis: [...patch.clis] },
|
|
@@ -4333,6 +4637,36 @@ ${DASHBOARD_LINE}
|
|
|
4333
4637
|
return next;
|
|
4334
4638
|
});
|
|
4335
4639
|
}
|
|
4640
|
+
/**
|
|
4641
|
+
* Records a CLI's plan quota as a runner reported it, from a turn's stream or a read, merged over
|
|
4642
|
+
* what the record held. The record is written on every report, so it says when the numbers were
|
|
4643
|
+
* last seen; `runner.quota` is appended only when what a reader would see changes, since every
|
|
4644
|
+
* turn reports.
|
|
4645
|
+
*/
|
|
4646
|
+
async recordQuota(name, cli, quota) {
|
|
4647
|
+
return this.mutex.run(async () => {
|
|
4648
|
+
const file = this.paths.runner(name);
|
|
4649
|
+
if (!await exists(file)) {
|
|
4650
|
+
throw new BoardError("NOT_FOUND", `runner ${name} not found`);
|
|
4651
|
+
}
|
|
4652
|
+
const doc = await readMarkdown(file, RunnerSchema);
|
|
4653
|
+
const previous = doc.data.quotas?.[cli];
|
|
4654
|
+
const merged = mergeQuota(previous, quota);
|
|
4655
|
+
const next = RunnerSchema.parse({
|
|
4656
|
+
...doc.data,
|
|
4657
|
+
quotas: { ...doc.data.quotas, [cli]: merged }
|
|
4658
|
+
});
|
|
4659
|
+
await writeMarkdown(file, next, doc.body);
|
|
4660
|
+
if (quotaChanged(previous, merged)) {
|
|
4661
|
+
await this.events.append("runner.quota", SYSTEM_ACTOR.name, {
|
|
4662
|
+
name,
|
|
4663
|
+
cli,
|
|
4664
|
+
status: merged.status
|
|
4665
|
+
});
|
|
4666
|
+
}
|
|
4667
|
+
return next;
|
|
4668
|
+
});
|
|
4669
|
+
}
|
|
4336
4670
|
/**
|
|
4337
4671
|
* Logs an operations signal as an `ops.signal` event. No channel carries it: the scheduler wakes
|
|
4338
4672
|
* its readers from the event, the runner lists it in their prompts, and the interface's log shows
|
|
@@ -4474,18 +4808,16 @@ ${DASHBOARD_LINE}
|
|
|
4474
4808
|
async readDigest(actor, input = {}) {
|
|
4475
4809
|
const args = VerbInputs.read_inbox.parse(input);
|
|
4476
4810
|
await this.authorize(actor, "read_inbox");
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
return { messages: filed.map((entry) => entry.message), cursor };
|
|
4488
|
-
});
|
|
4811
|
+
const { cursors: stored, upto } = await this.digestSnapshot(actor.name);
|
|
4812
|
+
const from = args.since_cursor === void 0 ? stored : { ...NO_CURSORS, digest: args.since_cursor };
|
|
4813
|
+
const conversation = actor.scope === void 0 ? void 0 : { scope: actor.scope, part: conversationPart(actor) ?? null };
|
|
4814
|
+
const filed = (await this.digestSince(actor, from, upto, conversation)).slice(0, args.limit);
|
|
4815
|
+
if (args.advance) {
|
|
4816
|
+
await this.mutex.run(() => this.advanceCursors(actor.name, filed));
|
|
4817
|
+
}
|
|
4818
|
+
const last = filed.at(-1)?.message.id;
|
|
4819
|
+
const cursor = last ?? (conversation === void 0 ? from.digest : cursorOf(from, conversation.scope, conversation.part));
|
|
4820
|
+
return { messages: filed.map((entry) => entry.message), cursor };
|
|
4489
4821
|
}
|
|
4490
4822
|
/**
|
|
4491
4823
|
* How many unread digest messages a member has in each conversation: a scope's home, for its
|
|
@@ -4497,28 +4829,39 @@ ${DASHBOARD_LINE}
|
|
|
4497
4829
|
* whose signals that call for action wake their readers directly.
|
|
4498
4830
|
*/
|
|
4499
4831
|
async unreadByConversation(actor) {
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
}
|
|
4507
|
-
const posted = parseChannelRef(message.channel).project ?? SOCIETY_SCOPE;
|
|
4508
|
-
if (posted !== scope && scope !== SOCIETY_SCOPE) {
|
|
4509
|
-
continue;
|
|
4510
|
-
}
|
|
4511
|
-
const key = conversationKey(scope, part);
|
|
4512
|
-
const entry = counts.get(key) ?? {
|
|
4513
|
-
scope,
|
|
4514
|
-
thread: threadOfPart(part) ?? null,
|
|
4515
|
-
channel: channelOfPart(part) ?? null,
|
|
4516
|
-
count: 0
|
|
4517
|
-
};
|
|
4518
|
-
counts.set(key, { ...entry, count: entry.count + 1 });
|
|
4832
|
+
const { cursors, upto } = await this.digestSnapshot(actor.name);
|
|
4833
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4834
|
+
const unscoped = { name: actor.name, role: actor.role };
|
|
4835
|
+
for (const { scope, part, message, news } of await this.digestSince(unscoped, cursors, upto)) {
|
|
4836
|
+
if (news === true || message.step !== void 0 || message.author === SYSTEM_ACTOR.name) {
|
|
4837
|
+
continue;
|
|
4519
4838
|
}
|
|
4520
|
-
|
|
4521
|
-
|
|
4839
|
+
const posted = parseChannelRef(message.channel).project ?? SOCIETY_SCOPE;
|
|
4840
|
+
if (posted !== scope && scope !== SOCIETY_SCOPE) {
|
|
4841
|
+
continue;
|
|
4842
|
+
}
|
|
4843
|
+
const key = conversationKey(scope, part);
|
|
4844
|
+
const entry = counts.get(key) ?? {
|
|
4845
|
+
scope,
|
|
4846
|
+
thread: threadOfPart(part) ?? null,
|
|
4847
|
+
channel: channelOfPart(part) ?? null,
|
|
4848
|
+
count: 0
|
|
4849
|
+
};
|
|
4850
|
+
counts.set(key, { ...entry, count: entry.count + 1 });
|
|
4851
|
+
}
|
|
4852
|
+
return [...counts.values()];
|
|
4853
|
+
}
|
|
4854
|
+
/**
|
|
4855
|
+
* A reader's cursors and the id below which every message is already on disk, taken under the
|
|
4856
|
+
* mutex, which a digest scan then leaves: messages carry ids from the same monotonic source and are
|
|
4857
|
+
* written under the mutex, so the scan, which counts nothing newer than the mark, cannot pass over
|
|
4858
|
+
* one written while it reads, and a post never waits for a scan.
|
|
4859
|
+
*/
|
|
4860
|
+
digestSnapshot(agent2) {
|
|
4861
|
+
return this.mutex.run(async () => ({
|
|
4862
|
+
cursors: await this.readCursors(agent2),
|
|
4863
|
+
upto: this.newId()
|
|
4864
|
+
}));
|
|
4522
4865
|
}
|
|
4523
4866
|
async readCursors(agent2) {
|
|
4524
4867
|
const file = this.paths.agentCursors(agent2);
|
|
@@ -4560,9 +4903,10 @@ ${DASHBOARD_LINE}
|
|
|
4560
4903
|
* by the user wherever it is. With a conversation, only what is filed there: for a thread, every
|
|
4561
4904
|
* message of the thread, since the conversation is about it; for a channel's, that channel's
|
|
4562
4905
|
* top-level messages; for a scope's home, general's and those of a project the member is not in,
|
|
4563
|
-
* since each thread and each other channel is a conversation of its own.
|
|
4906
|
+
* since each thread and each other channel is a conversation of its own. Nothing newer than
|
|
4907
|
+
* `upto` counts (see `digestSnapshot`).
|
|
4564
4908
|
*/
|
|
4565
|
-
async digestSince(actor, cursors, conversation) {
|
|
4909
|
+
async digestSince(actor, cursors, upto, conversation) {
|
|
4566
4910
|
const conversationThread = threadOfPart(conversation?.part);
|
|
4567
4911
|
if (conversation !== void 0 && conversationThread !== void 0) {
|
|
4568
4912
|
const { scope, part } = conversation;
|
|
@@ -4570,7 +4914,7 @@ ${DASHBOARD_LINE}
|
|
|
4570
4914
|
if (found === null) {
|
|
4571
4915
|
return [];
|
|
4572
4916
|
}
|
|
4573
|
-
const messages = await this.readMessagesIn(this.paths.threadMessages(found.threads, conversationThread), cursorOf(cursors, scope, part));
|
|
4917
|
+
const messages = await this.readMessagesIn(this.paths.threadMessages(found.threads, conversationThread), cursorOf(cursors, scope, part), upto);
|
|
4574
4918
|
return messages.filter((message) => message.author !== actor.name).map((message) => ({ scope, part, message })).toSorted(byId);
|
|
4575
4919
|
}
|
|
4576
4920
|
const agent2 = await this.readAgent(actor.name);
|
|
@@ -4588,7 +4932,7 @@ ${DASHBOARD_LINE}
|
|
|
4588
4932
|
];
|
|
4589
4933
|
const known = starts.filter((start) => start !== null);
|
|
4590
4934
|
const since = known.length < starts.length ? null : known.toSorted((a, b) => a < b ? -1 : a > b ? 1 : 0)[0] ?? null;
|
|
4591
|
-
for await (const message of this.iterateMessages(since)) {
|
|
4935
|
+
for await (const message of this.iterateMessages(since, void 0, upto)) {
|
|
4592
4936
|
const filedIn = wakeScope(agent2, parseChannelRef(message.channel).project);
|
|
4593
4937
|
const thread2 = message.thread ?? null;
|
|
4594
4938
|
const asked = message.mentions.includes(actor.name) || frontDesk && message.author === USER_NAME;
|
|
@@ -5712,6 +6056,9 @@ ${args.summary}`);
|
|
|
5712
6056
|
}
|
|
5713
6057
|
if (args.blocked_by !== void 0) {
|
|
5714
6058
|
for (const id of args.blocked_by) {
|
|
6059
|
+
if (id === current.id) {
|
|
6060
|
+
throw new BoardError("VALIDATION", `task ${current.id} cannot be blocked by itself`);
|
|
6061
|
+
}
|
|
5715
6062
|
await this.findTask(id);
|
|
5716
6063
|
}
|
|
5717
6064
|
next = { ...next, blockedBy: [...args.blocked_by] };
|
|
@@ -5748,6 +6095,7 @@ ${args.summary}`);
|
|
|
5748
6095
|
from: current.status,
|
|
5749
6096
|
to: task2.status,
|
|
5750
6097
|
note: args.note ?? null,
|
|
6098
|
+
...args.blocked_by === void 0 ? {} : { blockedBy: task2.blockedBy, previousBlockedBy: current.blockedBy },
|
|
5751
6099
|
...args.pull_request === void 0 ? {} : { pullRequest: task2.pullRequest?.url ?? null }
|
|
5752
6100
|
});
|
|
5753
6101
|
}
|
|
@@ -6153,7 +6501,7 @@ ${rationale}`}`);
|
|
|
6153
6501
|
}
|
|
6154
6502
|
async readAgentRoleBody(agent2) {
|
|
6155
6503
|
const file = this.paths.agentRole(agent2);
|
|
6156
|
-
return await exists(file) ? (await readMarkdown(file,
|
|
6504
|
+
return await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
|
|
6157
6505
|
}
|
|
6158
6506
|
/** The steps of one finished turn, as the runner handed them over when it ended. */
|
|
6159
6507
|
/**
|
|
@@ -6184,6 +6532,14 @@ ${rationale}`}`);
|
|
|
6184
6532
|
}
|
|
6185
6533
|
return computeMetrics({ events, tasks, citizens, actions, activeSignals, window, now });
|
|
6186
6534
|
}
|
|
6535
|
+
/**
|
|
6536
|
+
* Each citizen's finished turns over a window and the tokens of those that counted them, from
|
|
6537
|
+
* the event log alone, which holds every turn's end whatever runner it ran on.
|
|
6538
|
+
*/
|
|
6539
|
+
async tokenUse(window) {
|
|
6540
|
+
const events = await this.events.readSince(null, Number.MAX_SAFE_INTEGER);
|
|
6541
|
+
return tokenUse(events, window, this.now());
|
|
6542
|
+
}
|
|
6187
6543
|
/** The board actions a finished turn took, from its transcript; null when it kept none. */
|
|
6188
6544
|
async turnActions(agent2, turnId) {
|
|
6189
6545
|
const known = this.actionCounts.get(turnId);
|
|
@@ -6553,7 +6909,7 @@ ${rationale}`}`);
|
|
|
6553
6909
|
return { project: slug, revision: 0, body: "" };
|
|
6554
6910
|
}
|
|
6555
6911
|
const { data, body } = await readLooseMarkdown(file);
|
|
6556
|
-
const revision =
|
|
6912
|
+
const revision = z15.number().int().min(0).safeParse(data["revision"]);
|
|
6557
6913
|
const updatedBy = NameSchema.safeParse(data["updatedBy"]);
|
|
6558
6914
|
const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
|
|
6559
6915
|
return {
|
|
@@ -6844,7 +7200,7 @@ ${seed}
|
|
|
6844
7200
|
continue;
|
|
6845
7201
|
}
|
|
6846
7202
|
const file = this.paths.agentRole(agent2.name);
|
|
6847
|
-
const body = await exists(file) ? (await readMarkdown(file,
|
|
7203
|
+
const body = await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
|
|
6848
7204
|
const at = body.indexOf(`
|
|
6849
7205
|
${SEED_INSTRUCTIONS_HEADING}
|
|
6850
7206
|
`);
|
|
@@ -7046,12 +7402,37 @@ Short, curated, loaded on every turn. Keep entries that change future behavior a
|
|
|
7046
7402
|
case "archive":
|
|
7047
7403
|
await this.validateArchive(ArchiveProposalSchema.parse(charter).project);
|
|
7048
7404
|
return;
|
|
7049
|
-
case "reallocation":
|
|
7405
|
+
case "reallocation": {
|
|
7406
|
+
const parsed = ReallocationProposalSchema.safeParse(charter);
|
|
7407
|
+
if (parsed.success) {
|
|
7408
|
+
await this.reallocatedRole(parsed.data);
|
|
7409
|
+
} else {
|
|
7410
|
+
LegacyReallocationSchema.parse(charter);
|
|
7411
|
+
}
|
|
7050
7412
|
return;
|
|
7413
|
+
}
|
|
7051
7414
|
default:
|
|
7052
7415
|
return;
|
|
7053
7416
|
}
|
|
7054
7417
|
}
|
|
7418
|
+
/**
|
|
7419
|
+
* The role as a reallocation would leave it, with what changes: refused for the user's charter,
|
|
7420
|
+
* a role that does not exist, a charter the changes would make invalid, and changes the role
|
|
7421
|
+
* has already.
|
|
7422
|
+
*/
|
|
7423
|
+
async reallocatedRole(reallocation) {
|
|
7424
|
+
if (reallocation.role === USER_ROLE) {
|
|
7425
|
+
throw new BoardError("FORBIDDEN", "the user charter is not subject to proposals");
|
|
7426
|
+
}
|
|
7427
|
+
const current = await this.readRole(reallocation.role);
|
|
7428
|
+
const next = RoleCharterSchema.parse(applyRoleChanges(current, reallocation.changes));
|
|
7429
|
+
await this.validateRole(next);
|
|
7430
|
+
const changed = roleChangeLines(current, reallocation.changes);
|
|
7431
|
+
if (changed.length === 0) {
|
|
7432
|
+
throw new BoardError("VALIDATION", `role ${current.name} has these values already; the reallocation changes nothing`);
|
|
7433
|
+
}
|
|
7434
|
+
return { next, changed };
|
|
7435
|
+
}
|
|
7055
7436
|
async executeProvision(by, proposal2) {
|
|
7056
7437
|
const meta = { proposalId: proposal2.id };
|
|
7057
7438
|
switch (proposal2.kind) {
|
|
@@ -7088,8 +7469,15 @@ Short, curated, loaded on every turn. Keep entries that change future behavior a
|
|
|
7088
7469
|
const { members } = await this.archiveUnlocked(by, input.project, input.reason, meta);
|
|
7089
7470
|
return { project: input.project, members };
|
|
7090
7471
|
}
|
|
7091
|
-
case "reallocation":
|
|
7092
|
-
|
|
7472
|
+
case "reallocation": {
|
|
7473
|
+
const parsed = ReallocationProposalSchema.safeParse(proposal2.charter);
|
|
7474
|
+
if (!parsed.success) {
|
|
7475
|
+
return void 0;
|
|
7476
|
+
}
|
|
7477
|
+
const { next, changed } = await this.reallocatedRole(parsed.data);
|
|
7478
|
+
await this.writeRoleUnlocked(by, next, meta);
|
|
7479
|
+
return { role: next.name, changed };
|
|
7480
|
+
}
|
|
7093
7481
|
default:
|
|
7094
7482
|
return void 0;
|
|
7095
7483
|
}
|
|
@@ -7650,7 +8038,7 @@ ${charter.purpose}
|
|
|
7650
8038
|
id: this.newId(),
|
|
7651
8039
|
...head,
|
|
7652
8040
|
ts: this.now().toISOString(),
|
|
7653
|
-
mentions:
|
|
8041
|
+
mentions: postMentions(body)
|
|
7654
8042
|
});
|
|
7655
8043
|
const { author } = head;
|
|
7656
8044
|
await writeMarkdown(this.paths.messageFile(dir, frontmatter.id, author), frontmatter, body);
|
|
@@ -7789,7 +8177,7 @@ ${charter.purpose}
|
|
|
7789
8177
|
if (filed.proposedBy === actor.name) {
|
|
7790
8178
|
throw new BoardError("FORBIDDEN", "a proposer never decides its own proposal");
|
|
7791
8179
|
}
|
|
7792
|
-
const approvers =
|
|
8180
|
+
const approvers = proposalApprovers(filed.kind, filed.charter);
|
|
7793
8181
|
if (!approvers.includes(actor.role)) {
|
|
7794
8182
|
throw new BoardError("FORBIDDEN", `a ${filed.kind} proposal requires one of: ${approvers.join(", ")}`);
|
|
7795
8183
|
}
|
|
@@ -7872,7 +8260,7 @@ ${charter.purpose}
|
|
|
7872
8260
|
}
|
|
7873
8261
|
if (subject?.kind === "proposal") {
|
|
7874
8262
|
const proposal2 = await this.readProposal(subject.id);
|
|
7875
|
-
if (proposal2.proposedBy === actor.name || proposal2.decidedBy === actor.name ||
|
|
8263
|
+
if (proposal2.proposedBy === actor.name || proposal2.decidedBy === actor.name || proposalApprovers(proposal2.kind, proposal2.charter).includes(actor.role)) {
|
|
7876
8264
|
return true;
|
|
7877
8265
|
}
|
|
7878
8266
|
return (await this.readRole(actor.role)).wakeTriggers.includes(OPS_WAKE_TRIGGER);
|
|
@@ -7929,11 +8317,12 @@ ${charter.purpose}
|
|
|
7929
8317
|
});
|
|
7930
8318
|
await this.endCronsUnlocked(by, `its thread closed: its ${found.thread.subject?.kind ?? "subject"} was ${ended}`, (cron2) => cron2.thread === subjectId);
|
|
7931
8319
|
}
|
|
7932
|
-
|
|
8320
|
+
/** The messages in a folder after `since` and, when given, up to `upto`, read by name first. */
|
|
8321
|
+
async readMessagesIn(dir, since, upto) {
|
|
7933
8322
|
const messages = [];
|
|
7934
8323
|
for (const file of await listFiles(dir)) {
|
|
7935
8324
|
const id = file.slice(0, 26);
|
|
7936
|
-
if (since !== null && id <= since) {
|
|
8325
|
+
if (since !== null && id <= since || upto !== void 0 && id > upto) {
|
|
7937
8326
|
continue;
|
|
7938
8327
|
}
|
|
7939
8328
|
const doc = await readMarkdown(path6.join(dir, file), MessageFrontmatterSchema);
|
|
@@ -7941,20 +8330,23 @@ ${charter.purpose}
|
|
|
7941
8330
|
}
|
|
7942
8331
|
return messages;
|
|
7943
8332
|
}
|
|
7944
|
-
/**
|
|
7945
|
-
|
|
8333
|
+
/**
|
|
8334
|
+
* Every message newer than `since`, and no newer than `upto` when given, across society
|
|
8335
|
+
* channels, project channels, and threads.
|
|
8336
|
+
*/
|
|
8337
|
+
async *iterateMessages(since, project2, upto) {
|
|
7946
8338
|
if (project2 === void 0) {
|
|
7947
8339
|
for (const channel of await listDirs(this.paths.societyChannels())) {
|
|
7948
|
-
yield* await this.readMessagesIn(this.paths.societyChannel(channel), since);
|
|
8340
|
+
yield* await this.readMessagesIn(this.paths.societyChannel(channel), since, upto);
|
|
7949
8341
|
}
|
|
7950
|
-
yield* this.threadMessagesIn(this.paths.societyThreads(), since);
|
|
8342
|
+
yield* this.threadMessagesIn(this.paths.societyThreads(), since, upto);
|
|
7951
8343
|
}
|
|
7952
8344
|
const projects = project2 === void 0 ? await listDirs(this.paths.projects()) : [project2];
|
|
7953
8345
|
for (const slug of projects) {
|
|
7954
8346
|
for (const channel of await listDirs(this.paths.projectChannels(slug))) {
|
|
7955
|
-
yield* await this.readMessagesIn(this.paths.projectChannel(slug, channel), since);
|
|
8347
|
+
yield* await this.readMessagesIn(this.paths.projectChannel(slug, channel), since, upto);
|
|
7956
8348
|
}
|
|
7957
|
-
yield* this.threadMessagesIn(this.paths.threads(slug), since);
|
|
8349
|
+
yield* this.threadMessagesIn(this.paths.threads(slug), since, upto);
|
|
7958
8350
|
}
|
|
7959
8351
|
}
|
|
7960
8352
|
/** Every folder that holds messages: each channel's and each thread's, in the society and every project. */
|
|
@@ -7974,9 +8366,9 @@ ${charter.purpose}
|
|
|
7974
8366
|
}
|
|
7975
8367
|
}
|
|
7976
8368
|
}
|
|
7977
|
-
async *threadMessagesIn(threads, since) {
|
|
8369
|
+
async *threadMessagesIn(threads, since, upto) {
|
|
7978
8370
|
for (const id of await listDirs(threads)) {
|
|
7979
|
-
yield* await this.readMessagesIn(this.paths.threadMessages(threads, id), since);
|
|
8371
|
+
yield* await this.readMessagesIn(this.paths.threadMessages(threads, id), since, upto);
|
|
7980
8372
|
}
|
|
7981
8373
|
}
|
|
7982
8374
|
};
|