@kubitnodes/stellaris 0.3.21 → 0.3.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/dist/cli/index.js +854 -588
  2. package/dist/server/index.js +1039 -651
  3. package/package.json +3 -1
  4. package/web/dist/assets/BackLink-CD-iuy-h.js +1 -0
  5. package/web/dist/assets/Button-Yoe21NQ2.js +1 -0
  6. package/web/dist/assets/ChannelForms-55otlg-m.js +1 -0
  7. package/web/dist/assets/ChannelView-DJvLzg0N.js +2 -0
  8. package/web/dist/assets/CitizenView-m1K2aTvK.js +2 -0
  9. package/web/dist/assets/CitizensView-BeTgmrKE.js +1 -0
  10. package/web/dist/assets/{CliIcon-BOSygXeI.js → CliIcon-DbMYJdlU.js} +1 -1
  11. package/web/dist/assets/CronsView-B4kXk5Ld.js +1 -0
  12. package/web/dist/assets/KnowledgeView-aSGxDDKy.js +1 -0
  13. package/web/dist/assets/Markdown-c9bCCLHg.js +30 -0
  14. package/web/dist/assets/{MessageItem-DI05jbrI.js → MessageItem-DKJKMqs-.js} +1 -1
  15. package/web/dist/assets/MetricsView-D2TTry5O.js +1 -0
  16. package/web/dist/assets/NeedsYouView-C3celRei.js +1 -0
  17. package/web/dist/assets/Overview-BveU1yJj.js +1 -0
  18. package/web/dist/assets/{Pane-BendOaje.js → Pane-CLjdfBMM.js} +1 -1
  19. package/web/dist/assets/{Picker-BuVnakvi.js → Picker-CXOe5Xdu.js} +1 -1
  20. package/web/dist/assets/ProjectView-oa4Z46ED.js +1 -0
  21. package/web/dist/assets/ProposalView-B4T-EoX9.js +2 -0
  22. package/web/dist/assets/ProposalsView-BZHivSEm.js +1 -0
  23. package/web/dist/assets/Quota-BC7dpnwd.js +1 -0
  24. package/web/dist/assets/RunnersView-BrJF-aLU.js +1 -0
  25. package/web/dist/assets/SocietyView-C1yosPuf.js +1 -0
  26. package/web/dist/assets/StickyList-7tAlUDCN.js +1 -0
  27. package/web/dist/assets/SubjectThread-CCq6ZAnR.js +1 -0
  28. package/web/dist/assets/TaskFileView-BEXQJQQ6.js +4 -0
  29. package/web/dist/assets/TaskView-Cfhb7NuO.js +3 -0
  30. package/web/dist/assets/TasksView-3XljXcoi.js +1 -0
  31. package/web/dist/assets/ThreadForms-D2y5dXSC.js +1 -0
  32. package/web/dist/assets/ThreadItem-DeIhhmyu.js +1 -0
  33. package/web/dist/assets/ThreadView-CbUnt9WL.js +1 -0
  34. package/web/dist/assets/citizen--bqux6i_.js +1 -0
  35. package/web/dist/assets/compose-DNc3_c5x.js +1 -0
  36. package/web/dist/assets/format-B6fjC0_a.js +55 -0
  37. package/web/dist/assets/governance-RBQ4Lam0.js +1 -0
  38. package/web/dist/assets/index-CyCty7a2.js +23 -0
  39. package/web/dist/assets/index-GRqxKN35.css +2 -0
  40. package/web/dist/assets/mentions-B2Qchd_6.js +3 -0
  41. package/web/dist/assets/{tasks-CyXIxoAy.js → tasks-DCUj5w_d.js} +1 -1
  42. package/web/dist/assets/useMatch-CfbBQirn.js +1 -0
  43. package/web/dist/index.html +9 -10
  44. package/web/dist/assets/BackLink-23Q1JvmZ.js +0 -1
  45. package/web/dist/assets/ChannelForms-0Cwh59E7.js +0 -1
  46. package/web/dist/assets/ChannelView-CqWV1zza.js +0 -2
  47. package/web/dist/assets/CitizenView-s5OdjXmB.js +0 -2
  48. package/web/dist/assets/CitizensView-r6SZLnVl.js +0 -1
  49. package/web/dist/assets/CronsView-Y-bAE0l2.js +0 -1
  50. package/web/dist/assets/KnowledgeView-CI4PJWwm.js +0 -1
  51. package/web/dist/assets/Markdown-DyckB74r.js +0 -32
  52. package/web/dist/assets/MetricsView-DKh-lEW5.js +0 -1
  53. package/web/dist/assets/NeedsYouView-C6FfiTsg.js +0 -1
  54. package/web/dist/assets/Overview-D5RvWBg5.js +0 -1
  55. package/web/dist/assets/ProjectView-blBEh70W.js +0 -1
  56. package/web/dist/assets/ProposalView-CMntpKTc.js +0 -2
  57. package/web/dist/assets/ProposalsView-CVUAV2Mm.js +0 -1
  58. package/web/dist/assets/RunnersView-B-wuWVgB.js +0 -1
  59. package/web/dist/assets/SocietyView-CaVbfJWz.js +0 -1
  60. package/web/dist/assets/SubjectThread-Bd_-sDhJ.js +0 -1
  61. package/web/dist/assets/TaskFileView-CO4Y97OT.js +0 -4
  62. package/web/dist/assets/TaskView-DRZoHALo.js +0 -3
  63. package/web/dist/assets/TasksView-CQVQo3zF.js +0 -1
  64. package/web/dist/assets/ThreadForms-CUSeWu0c.js +0 -1
  65. package/web/dist/assets/ThreadItem-BPYYXh3V.js +0 -1
  66. package/web/dist/assets/ThreadView-BcI2i6FI.js +0 -1
  67. package/web/dist/assets/citizen-Eff1h9rA.js +0 -1
  68. package/web/dist/assets/compose-D73Agshx.js +0 -1
  69. package/web/dist/assets/format-fw0G_Vff.js +0 -55
  70. package/web/dist/assets/governance-sRsfOw52.js +0 -1
  71. package/web/dist/assets/index-BkOq4PSU.css +0 -2
  72. package/web/dist/assets/index-CYiok0pT.js +0 -23
  73. package/web/dist/assets/link-Cl7vKbOz.js +0 -1
  74. package/web/dist/assets/mentions-BCdV0bMK.js +0 -1
  75. package/web/dist/assets/useMatch-D-tEHQEw.js +0 -1
  76. package/web/dist/assets/useStickyScroll-Bn4YyEXL.js +0 -1
package/dist/cli/index.js CHANGED
@@ -9,7 +9,7 @@ import { Command } from "commander";
9
9
  import { chmod as chmod2, cp, mkdir as mkdir4, readdir as readdir3, readFile as readFile4, rename as rename3, rm as rm2, stat as stat3, writeFile as writeFile4 } from "node:fs/promises";
10
10
  import path6 from "node:path";
11
11
  import { decodeTime, monotonicFactory } from "ulid";
12
- import { z as z13 } from "zod";
12
+ import { z as z15 } from "zod";
13
13
 
14
14
  // packages/shared/dist/ids.js
15
15
  import { z } from "zod";
@@ -169,7 +169,7 @@ var SEED_ROLES = [
169
169
  ];
170
170
 
171
171
  // packages/shared/dist/board.js
172
- import { z as z4 } from "zod";
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 = z4.enum(["claude", "codex"]);
304
- var ArchivedChannelSchema = z4.object({
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: z4.string().min(1)
381
+ reason: z5.string().min(1)
309
382
  });
310
- var SocietySchema = z4.object({
311
- name: z4.string().min(1),
312
- version: z4.literal(1),
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: z4.array(NameSchema),
316
- archivedChannels: z4.array(ArchivedChannelSchema).default([]),
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 = z4.enum(["none", "merge", "ghpr"]);
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 = z4.string().trim().regex(PULL_REQUEST_URL, "a pull request's address, https://github.com/<owner>/<repo>/pull/<number>");
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 = z4.string().trim().min(1).max(300).regex(/^[^\n]+$/, "a merge commit's subject is one line");
345
- var PullRequestLinkSchema = z4.object({
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: z4.number().int().positive(),
420
+ number: z5.number().int().positive(),
348
421
  subject: MergeSubjectSchema.optional(),
349
- body: z4.string().max(2e4).optional(),
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: z4.object({ at: IsoDateTimeSchema, ok: z4.boolean(), detail: z4.string() }).optional()
429
+ closed: z5.object({ at: IsoDateTimeSchema, ok: z5.boolean(), detail: z5.string() }).optional()
357
430
  });
358
- var DefaultBranchSchema = z4.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");
359
- var StageIdSchema = z4.string().regex(/^s[1-9][0-9]*$/, "expected a stage id such as s1");
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: z4.string().trim().min(1).max(120),
434
+ name: z5.string().trim().min(1).max(120),
362
435
  role: NameSchema.optional(),
363
436
  agent: NameSchema.optional(),
364
- gate: z4.boolean().default(false)
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 = z4.object(stageFields).refine(oneAssignee, ONE_ASSIGNEE);
371
- var PlanEditStageSchema = z4.object({ id: StageIdSchema.optional(), ...stageFields }).refine(oneAssignee, ONE_ASSIGNEE);
372
- var PlanSchema = z4.array(PlanStageSchema);
373
- var PlanEditSchema = z4.array(PlanEditStageSchema);
374
- var ProjectSchema = z4.object({
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: z4.string().min(1),
377
- repo: z4.string().nullable(),
378
- defaultBranch: z4.string().min(1),
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: z4.array(NameSchema),
381
- archivedChannels: z4.array(ArchivedChannelSchema).default([]),
382
- members: z4.array(NameSchema),
383
- approvers: z4.array(NameSchema),
384
- requiredCapabilities: z4.array(z4.string()),
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: z4.object({ at: IsoDateTimeSchema, by: NameSchema, reason: z4.string().min(1) }).optional()
463
+ archived: z5.object({ at: IsoDateTimeSchema, by: NameSchema, reason: z5.string().min(1) }).optional()
391
464
  });
392
- var TaskStepSchema = z4.object({
393
- action: z4.enum(["advanced", "returned", "abandoned", "landed", "reopened"]),
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 = z4.object({ action: z4.enum(["approved", "rejected"]) });
398
- var MessageStepSchema = z4.union([TaskStepSchema, ProposalStepSchema]);
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 = z4.object({
403
- kind: z4.literal("knowledge"),
404
- action: z4.enum(["written", "updated", "removed"]),
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 = z4.discriminatedUnion("kind", [KnowledgeNoticeSchema]);
409
- var MessageFrontmatterSchema = z4.object({
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: z4.array(NameSchema)
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 = z4.enum(["open", "claimed", "done", "abandoned"]);
433
- var ThreadStateSchema = z4.enum(["open", "closed"]);
434
- var ThreadSubjectSchema = z4.object({
435
- kind: z4.enum(["task", "proposal"]),
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 = z4.object({
511
+ var ThreadFrontmatterSchema = z5.object({
439
512
  id: UlidSchema,
440
513
  channel: ChannelRefSchema,
441
- title: z4.string().min(1).max(200),
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 = z4.object({
522
+ var StageSchema = z5.object({
450
523
  id: StageIdSchema,
451
- name: z4.string().min(1),
524
+ name: z5.string().min(1),
452
525
  role: NameSchema.optional(),
453
526
  agent: NameSchema.optional(),
454
- gate: z4.boolean().default(false),
527
+ gate: z5.boolean().default(false),
455
528
  /** Everyone who has held the stage, oldest first. */
456
- holders: z4.array(NameSchema).default([]),
529
+ holders: z5.array(NameSchema).default([]),
457
530
  completedBy: NameSchema.optional(),
458
531
  completedAt: IsoDateTimeSchema.optional()
459
532
  });
460
- var TaskReturnSchema = z4.object({
533
+ var TaskReturnSchema = z5.object({
461
534
  from: StageIdSchema,
462
535
  by: NameSchema,
463
536
  at: IsoDateTimeSchema
464
537
  });
465
- var TaskFrontmatterSchema = z4.object({
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: z4.string().min(1),
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: z4.array(UlidSchema),
480
- requiredCapabilities: z4.array(z4.string()),
481
- stages: z4.array(StageSchema).min(1),
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: z4.number().int().positive(),
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: z4.boolean().default(false),
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 = z4.string().trim().min(1).max(120).regex(/^[\w.:/[\]-]+$/, "a model name is one word of letters, digits, and . _ : / - [ ]");
516
- var EffortSchema = z4.string().trim().min(1).max(32).regex(/^[a-z][a-z0-9_-]*$/, "an effort is one lowercase word, such as high");
517
- var EffortOptionSchema = z4.object({
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: z4.string().default("")
592
+ description: z5.string().default("")
520
593
  });
521
- var ModelOptionSchema = z4.object({
594
+ var ModelOptionSchema = z5.object({
522
595
  id: ModelNameSchema,
523
- name: z4.string(),
524
- description: z4.string().default(""),
525
- isDefault: z4.boolean().default(false),
526
- efforts: z4.array(EffortOptionSchema).default([]),
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 = z4.object({
602
+ var RunnerModelsSchema = z5.object({
530
603
  runner: NameSchema,
531
604
  cli: CliKindSchema,
532
- models: z4.array(ModelOptionSchema)
605
+ models: z5.array(ModelOptionSchema)
533
606
  });
534
- var AgentStatusSchema = z4.enum(["active", "retired"]);
535
- var AgentSchema = z4.object({
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: z4.string().optional(),
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: z4.string().optional(),
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: z4.array(NameSchema),
545
- subscriptions: z4.array(ChannelRefSchema),
617
+ memberships: z5.array(NameSchema),
618
+ subscriptions: z5.array(ChannelRefSchema),
546
619
  status: AgentStatusSchema,
547
620
  createdAt: IsoDateTimeSchema,
548
- tokenHash: z4.string().min(1),
621
+ tokenHash: z5.string().min(1),
549
622
  retiredAt: IsoDateTimeSchema.optional(),
550
- retiredReason: z4.string().optional()
623
+ retiredReason: z5.string().optional()
551
624
  });
552
- var MemberSchema = z4.object({
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: z4.boolean().default(false),
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: z4.string().optional(),
633
+ model: z5.string().optional(),
561
634
  /** The model the CLI reported on the citizen's last turn. */
562
- lastModel: z4.string().optional(),
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: z4.string().optional(),
637
+ effort: z5.string().optional(),
565
638
  /** The citizen's own skills, by name. */
566
- skills: z4.array(NameSchema).default([]),
567
- memberships: z4.array(NameSchema),
568
- subscriptions: z4.array(ChannelRefSchema),
569
- claimsHeld: z4.number().int().nonnegative().default(0),
570
- tasksDone: z4.number().int().nonnegative().default(0),
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: z4.string().optional(),
645
+ lastTurnOutcome: z5.string().optional(),
573
646
  createdAt: IsoDateTimeSchema,
574
647
  retiredAt: IsoDateTimeSchema.optional()
575
648
  });
576
- var RunnerOsSchema = z4.enum(["linux", "windows", "darwin"]);
577
- var RunnerSchema = z4.object({
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: z4.array(CliKindSchema),
581
- capabilities: z4.array(z4.string()),
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: z4.string().optional(),
584
- status: z4.enum(["connected", "disconnected"]),
585
- lastSeen: IsoDateTimeSchema.optional()
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 = z4.enum([
671
+ var ProposalKindSchema = z5.enum([
588
672
  "role",
589
673
  "member",
590
674
  "channel",
@@ -593,42 +677,42 @@ var ProposalKindSchema = z4.enum([
593
677
  "skill",
594
678
  "archive"
595
679
  ]);
596
- var ProposalStatusSchema = z4.enum([
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 = z4.object({
687
+ var MemberProposalSchema = z5.object({
604
688
  name: NameSchema,
605
689
  role: NameSchema,
606
690
  cli: CliKindSchema,
607
- model: z4.string().optional(),
691
+ model: z5.string().optional(),
608
692
  homeRunner: NameSchema.optional(),
609
- memberships: z4.array(NameSchema).default([]),
610
- subscriptions: z4.array(ChannelRefSchema).default([]),
611
- seedInstructions: z4.string().optional()
693
+ memberships: z5.array(NameSchema).default([]),
694
+ subscriptions: z5.array(ChannelRefSchema).default([]),
695
+ seedInstructions: z5.string().optional()
612
696
  });
613
- var ChannelProposalSchema = z4.object({
697
+ var ChannelProposalSchema = z5.object({
614
698
  project: NameSchema.nullable().default(null),
615
699
  name: NameSchema,
616
- purpose: z4.string().min(1)
700
+ purpose: z5.string().min(1)
617
701
  });
618
- var RoleChangesSchema = z4.strictObject({
619
- maxReplicas: z4.number().int().min(1).optional(),
620
- backlogThreshold: z4.number().positive().optional(),
621
- wakeTriggers: z4.array(CharterTriggerSchema).optional(),
622
- verbs: z4.array(VerbNameSchema).optional()
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()
623
707
  }).refine((changes) => Object.values(changes).some((value) => value !== void 0), {
624
708
  message: "a reallocation changes at least one of maxReplicas, backlogThreshold, wakeTriggers, verbs"
625
709
  });
626
- var ReallocationProposalSchema = z4.object({
710
+ var ReallocationProposalSchema = z5.object({
627
711
  role: NameSchema,
628
712
  changes: RoleChangesSchema,
629
- description: z4.string().min(1)
713
+ description: z5.string().min(1)
630
714
  });
631
- var LegacyReallocationSchema = z4.object({ description: z4.string().min(1) });
715
+ var LegacyReallocationSchema = z5.object({ description: z5.string().min(1) });
632
716
  function applyRoleChanges(role2, changes) {
633
717
  return {
634
718
  ...role2,
@@ -663,18 +747,18 @@ function roleChangeLines(role2, changes) {
663
747
  }
664
748
  return lines;
665
749
  }
666
- var RetirementProposalSchema = z4.object({
750
+ var RetirementProposalSchema = z5.object({
667
751
  agent: NameSchema,
668
- reason: z4.string().min(1)
752
+ reason: z5.string().min(1)
669
753
  });
670
- var ArchiveProposalSchema = z4.object({
754
+ var ArchiveProposalSchema = z5.object({
671
755
  project: NameSchema,
672
- reason: z4.string().min(1)
756
+ reason: z5.string().min(1)
673
757
  });
674
- var SkillProposalSchema = z4.object({
758
+ var SkillProposalSchema = z5.object({
675
759
  name: NameSchema,
676
- summary: z4.string().min(1).max(200),
677
- body: z4.string().min(1).optional()
760
+ summary: z5.string().min(1).max(200),
761
+ body: z5.string().min(1).optional()
678
762
  });
679
763
  var ProposalCharterSchemas = {
680
764
  role: RoleCharterSchema,
@@ -777,23 +861,23 @@ function describeCharter(kind, charter) {
777
861
  }
778
862
  return `${kind} ${JSON.stringify(charter)}`;
779
863
  }
780
- var SkillSchema = z4.object({
864
+ var SkillSchema = z5.object({
781
865
  name: NameSchema,
782
- summary: z4.string().default(""),
783
- scope: z4.enum(["own", "society"]),
784
- path: z4.string().min(1)
866
+ summary: z5.string().default(""),
867
+ scope: z5.enum(["own", "society"]),
868
+ path: z5.string().min(1)
785
869
  });
786
- var RemovedSkillSchema = z4.object({
870
+ var RemovedSkillSchema = z5.object({
787
871
  name: NameSchema,
788
- reason: z4.string().min(1),
872
+ reason: z5.string().min(1),
789
873
  removedBy: NameSchema,
790
874
  removedAt: IsoDateTimeSchema
791
875
  });
792
- var HomeConflictSchema = z4.object({
876
+ var HomeConflictSchema = z5.object({
793
877
  /** The copy, relative to the home. */
794
- path: z4.string().min(1),
878
+ path: z5.string().min(1),
795
879
  /** The file beside it, whose version the board kept. */
796
- file: z4.string().min(1),
880
+ file: z5.string().min(1),
797
881
  /** When the copy reached the board. */
798
882
  since: IsoDateTimeSchema
799
883
  });
@@ -801,79 +885,79 @@ var CONFLICT_COPY = /^(.+)\.conflict-[^/.]+$/;
801
885
  function conflictCopyOf(copy) {
802
886
  return CONFLICT_COPY.exec(copy)?.[1] ?? null;
803
887
  }
804
- var CommitIdSchema = z4.string().regex(/^[0-9a-f]{40}([0-9a-f]{24})?$/);
805
- var HomeFileChangeSchema = z4.object({
806
- path: z4.string().min(1),
807
- status: z4.enum(["added", "modified", "deleted"]),
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"]),
808
892
  /** Lines added and removed, or null for a binary file. */
809
- added: z4.number().int().nonnegative().nullable(),
810
- removed: z4.number().int().nonnegative().nullable()
893
+ added: z5.number().int().nonnegative().nullable(),
894
+ removed: z5.number().int().nonnegative().nullable()
811
895
  });
812
- var HomeChangeSchema = z4.object({
896
+ var HomeChangeSchema = z5.object({
813
897
  commit: CommitIdSchema,
814
898
  at: IsoDateTimeSchema,
815
- kind: z4.enum(["turn", "board", "merge"]),
816
- author: z4.string(),
899
+ kind: z5.enum(["turn", "board", "merge"]),
900
+ author: z5.string(),
817
901
  /** The turn that made it, from the runner's commit message. */
818
902
  turnId: UlidSchema.optional(),
819
- subject: z4.string(),
820
- files: z4.array(HomeFileChangeSchema)
903
+ subject: z5.string(),
904
+ files: z5.array(HomeFileChangeSchema)
821
905
  });
822
- var HomeHistorySchema = z4.object({
823
- changes: z4.array(HomeChangeSchema),
906
+ var HomeHistorySchema = z5.object({
907
+ changes: z5.array(HomeChangeSchema),
824
908
  /** Whether older commits remain past the ones read. */
825
- more: z4.boolean()
909
+ more: z5.boolean()
826
910
  });
827
911
  var HomeFileDiffSchema = HomeFileChangeSchema.pick({ path: true, status: true }).extend({
828
- patch: z4.string().nullable(),
912
+ patch: z5.string().nullable(),
829
913
  /** The patch was cut at its size limit. */
830
- truncated: z4.boolean()
914
+ truncated: z5.boolean()
831
915
  });
832
- var KnowledgeSchema = z4.object({
916
+ var KnowledgeSchema = z5.object({
833
917
  topic: NameSchema,
834
918
  project: NameSchema.nullable(),
835
- revision: z4.number().int().min(0),
919
+ revision: z5.number().int().min(0),
836
920
  updatedBy: NameSchema,
837
921
  updatedAt: IsoDateTimeSchema
838
922
  });
839
- var RemovedKnowledgeSchema = z4.object({
923
+ var RemovedKnowledgeSchema = z5.object({
840
924
  topic: NameSchema,
841
925
  project: NameSchema.nullable(),
842
926
  removedBy: NameSchema,
843
927
  removedAt: IsoDateTimeSchema
844
928
  });
845
- var DashboardSchema = z4.object({
929
+ var DashboardSchema = z5.object({
846
930
  project: NameSchema,
847
- revision: z4.number().int().min(0),
931
+ revision: z5.number().int().min(0),
848
932
  /** Absent until someone updates the dashboard the project began with. */
849
933
  updatedBy: NameSchema.optional(),
850
934
  updatedAt: IsoDateTimeSchema.optional(),
851
- body: z4.string()
935
+ body: z5.string()
852
936
  });
853
- var ProposalOriginSchema = z4.object({
937
+ var ProposalOriginSchema = z5.object({
854
938
  scope: NameSchema,
855
939
  thread: UlidSchema.optional(),
856
940
  channel: NameSchema.optional()
857
941
  });
858
942
  var SKILL_FILES_LIMIT = 100;
859
943
  var SKILL_BYTES_LIMIT = 10 * 1024 * 1024;
860
- var SkillFileSchema = z4.object({
861
- path: z4.string().min(1),
862
- size: z4.number().int().nonnegative(),
863
- executable: z4.boolean()
944
+ var SkillFileSchema = z5.object({
945
+ path: z5.string().min(1),
946
+ size: z5.number().int().nonnegative(),
947
+ executable: z5.boolean()
864
948
  });
865
- var SkillFilesSchema = z4.object({
949
+ var SkillFilesSchema = z5.object({
866
950
  /** The commit of the proposer's home the files came from. */
867
951
  commit: CommitIdSchema,
868
952
  takenAt: IsoDateTimeSchema,
869
- files: z4.array(SkillFileSchema)
953
+ files: z5.array(SkillFileSchema)
870
954
  });
871
955
  var SkillFileContentSchema = SkillFileSchema.extend({
872
- text: z4.string().nullable(),
956
+ text: z5.string().nullable(),
873
957
  /** The text was cut at its size limit. */
874
- truncated: z4.boolean()
958
+ truncated: z5.boolean()
875
959
  });
876
- var ProposalFrontmatterSchema = z4.object({
960
+ var ProposalFrontmatterSchema = z5.object({
877
961
  id: UlidSchema,
878
962
  kind: ProposalKindSchema,
879
963
  proposedBy: NameSchema,
@@ -885,146 +969,146 @@ var ProposalFrontmatterSchema = z4.object({
885
969
  skillFiles: SkillFilesSchema.optional(),
886
970
  decidedBy: NameSchema.optional(),
887
971
  decidedAt: IsoDateTimeSchema.optional(),
888
- reason: z4.string().optional(),
889
- charter: z4.record(z4.string(), z4.unknown()),
972
+ reason: z5.string().optional(),
973
+ charter: z5.record(z5.string(), z5.unknown()),
890
974
  /** What approval created, for kinds the board provisions: the agent, channel, role, or retirement. */
891
975
  provisionedAt: IsoDateTimeSchema.optional(),
892
- provision: z4.record(z4.string(), z4.unknown()).optional()
976
+ provision: z5.record(z5.string(), z5.unknown()).optional()
893
977
  });
894
- var DecisionSchema = z4.object({
978
+ var DecisionSchema = z5.object({
895
979
  id: UlidSchema,
896
980
  proposalId: UlidSchema,
897
981
  decidedBy: NameSchema,
898
- outcome: z4.enum(["approved", "rejected"]),
899
- reason: z4.string().optional(),
982
+ outcome: z5.enum(["approved", "rejected"]),
983
+ reason: z5.string().optional(),
900
984
  ts: IsoDateTimeSchema
901
985
  });
902
986
 
903
987
  // packages/shared/dist/verbs.js
904
- import { z as z5 } from "zod";
905
- var MomentSchema = z5.iso.datetime({ offset: true });
906
- var CronTitleSchema = z5.string().trim().min(1).max(120);
907
- var CronNoteSchema = z5.string().trim().min(1).max(4e3);
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);
908
992
  var VerbInputs = {
909
- post_message: z5.object({
993
+ post_message: z6.object({
910
994
  /** Required outside a thread; in one it may be left out, and must otherwise be the thread's. */
911
995
  channel: ChannelRefSchema.optional(),
912
- body: z5.string().min(1),
996
+ body: z6.string().min(1),
913
997
  thread_id: UlidSchema.optional()
914
998
  }),
915
- read_inbox: z5.object({
999
+ read_inbox: z6.object({
916
1000
  since_cursor: UlidSchema.nullable().optional(),
917
- limit: z5.number().int().positive().max(200).default(50),
918
- advance: z5.boolean().default(true)
1001
+ limit: z6.number().int().positive().max(200).default(50),
1002
+ advance: z6.boolean().default(true)
919
1003
  }),
920
- search: z5.object({
921
- query: z5.string().min(1),
1004
+ search: z6.object({
1005
+ query: z6.string().min(1),
922
1006
  project: NameSchema.optional(),
923
1007
  channel: ChannelRefSchema.optional(),
924
- limit: z5.number().int().positive().max(100).default(20)
1008
+ limit: z6.number().int().positive().max(100).default(20)
925
1009
  }),
926
1010
  /** On a task or a proposal, whose id the thread takes, or on a channel with a title. */
927
- open_thread: z5.object({
1011
+ open_thread: z6.object({
928
1012
  task_id: UlidSchema.optional(),
929
1013
  proposal_id: UlidSchema.optional(),
930
1014
  channel: ChannelRefSchema.optional(),
931
- title: z5.string().min(1).max(200).optional()
1015
+ title: z6.string().min(1).max(200).optional()
932
1016
  }),
933
- close_thread: z5.object({ thread_id: UlidSchema, summary: z5.string().min(1) }),
934
- create_task: z5.object({
1017
+ close_thread: z6.object({ thread_id: UlidSchema, summary: z6.string().min(1) }),
1018
+ create_task: z6.object({
935
1019
  project: NameSchema,
936
- title: z5.string().min(1).max(200),
937
- body: z5.string().default(""),
1020
+ title: z6.string().min(1).max(200),
1021
+ body: z6.string().default(""),
938
1022
  parent_id: UlidSchema.optional(),
939
- required_capabilities: z5.array(z5.string()).default([]),
1023
+ required_capabilities: z6.array(z6.string()).default([]),
940
1024
  /** The plan; without it the task gets one stage, work, that anyone in the project may take. */
941
- stages: z5.array(PlanStageSchema).min(1).optional(),
1025
+ stages: z6.array(PlanStageSchema).min(1).optional(),
942
1026
  /** A channel of the project the task belongs to, such as a release's; its thread opens there. */
943
1027
  channel: NameSchema.default("general")
944
1028
  }),
945
- claim_task: z5.object({ task_id: UlidSchema }),
946
- release_task: z5.object({ task_id: UlidSchema }),
947
- update_task: z5.object({
1029
+ claim_task: z6.object({ task_id: UlidSchema }),
1030
+ release_task: z6.object({ task_id: UlidSchema }),
1031
+ update_task: z6.object({
948
1032
  task_id: UlidSchema,
949
1033
  /** Move the task back to this earlier stage. */
950
1034
  stage: StageIdSchema.optional(),
951
- status: z5.enum(["abandoned"]).optional(),
1035
+ status: z6.enum(["abandoned"]).optional(),
952
1036
  /** Posted to the task's thread as the caller, marked with the step when the task moved. */
953
- note: z5.string().min(1).optional(),
954
- blocked_by: z5.array(UlidSchema).optional(),
1037
+ note: z6.string().min(1).optional(),
1038
+ blocked_by: z6.array(UlidSchema).optional(),
955
1039
  /**
956
1040
  * The pull request a `ghpr` task lands through, on its project's repository, with the merge
957
1041
  * commit's subject and body; null unlinks it.
958
1042
  */
959
- pull_request: z5.object({
1043
+ pull_request: z6.object({
960
1044
  url: PullRequestUrlSchema,
961
1045
  merge_subject: MergeSubjectSchema.optional(),
962
- merge_body: z5.string().max(2e4).optional()
1046
+ merge_body: z6.string().max(2e4).optional()
963
1047
  }).nullable().optional()
964
1048
  }),
965
- get_task: z5.object({ task_id: UlidSchema }),
966
- subscribe: z5.object({ channel: ChannelRefSchema }),
967
- unsubscribe: z5.object({ channel: ChannelRefSchema }),
968
- propose: z5.object({
1049
+ get_task: z6.object({ task_id: UlidSchema }),
1050
+ subscribe: z6.object({ channel: ChannelRefSchema }),
1051
+ unsubscribe: z6.object({ channel: ChannelRefSchema }),
1052
+ propose: z6.object({
969
1053
  kind: ProposalKindSchema,
970
- charter: z5.record(z5.string(), z5.unknown()),
971
- rationale: z5.string().default("")
1054
+ charter: z6.record(z6.string(), z6.unknown()),
1055
+ rationale: z6.string().default("")
972
1056
  }),
973
- approve: z5.object({ proposal_id: UlidSchema, reason: z5.string().optional() }),
974
- reject: z5.object({ proposal_id: UlidSchema, reason: z5.string().min(1) }),
975
- create_project: z5.object({
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({
976
1060
  slug: NameSchema,
977
- name: z5.string().min(1).optional(),
978
- repo: z5.string().min(1).nullable().default(null),
1061
+ name: z6.string().min(1).optional(),
1062
+ repo: z6.string().min(1).nullable().default(null),
979
1063
  default_branch: DefaultBranchSchema.default("main"),
980
1064
  on_done: CompletionEffectSchema.optional()
981
1065
  }),
982
- join_project: z5.object({ project: NameSchema, agent: NameSchema.optional() }),
983
- leave_project: z5.object({ project: NameSchema, agent: NameSchema.optional() }),
984
- write_knowledge: z5.object({
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({
985
1069
  /** A project you belong to, or null for society knowledge, which the steward and the user curate. */
986
1070
  project: NameSchema.nullable().default(null),
987
1071
  topic: NameSchema,
988
- body: z5.string().min(1),
1072
+ body: z6.string().min(1),
989
1073
  /** The `revision` in the frontmatter of the topic you read, 0 when it names none or for a new topic. */
990
- revision: z5.number().int().min(0)
1074
+ revision: z6.number().int().min(0)
991
1075
  }),
992
- remove_knowledge: z5.object({
1076
+ remove_knowledge: z6.object({
993
1077
  /** As for write_knowledge: a project you belong to, or null for society knowledge. */
994
1078
  project: NameSchema.nullable().default(null),
995
1079
  topic: NameSchema
996
1080
  }),
997
- plan_task: z5.object({
1081
+ plan_task: z6.object({
998
1082
  task_id: UlidSchema,
999
- stages: z5.array(PlanEditStageSchema),
1083
+ stages: z6.array(PlanEditStageSchema),
1000
1084
  on_done: CompletionEffectSchema.optional()
1001
1085
  }),
1002
1086
  /** The note is posted to the task's thread as the caller, marked with the step. */
1003
- advance_task: z5.object({ task_id: UlidSchema, note: z5.string().min(1).optional() }),
1004
- configure_project: z5.object({
1087
+ advance_task: z6.object({ task_id: UlidSchema, note: z6.string().min(1).optional() }),
1088
+ configure_project: z6.object({
1005
1089
  project: NameSchema,
1006
1090
  on_done: CompletionEffectSchema.optional(),
1007
1091
  /** A new display name; the slug, which everything refers to the project by, never changes. */
1008
- name: z5.string().trim().min(1).max(120).optional(),
1092
+ name: z6.string().trim().min(1).max(120).optional(),
1009
1093
  /** The branch tasks start from and land on from now; tasks in play keep their branches. */
1010
1094
  default_branch: DefaultBranchSchema.optional()
1011
1095
  }),
1012
- archive_project: z5.object({ project: NameSchema, reason: z5.string().min(1) }),
1013
- create_channel: z5.object({
1096
+ archive_project: z6.object({ project: NameSchema, reason: z6.string().min(1) }),
1097
+ create_channel: z6.object({
1014
1098
  /** A project, or null for a channel of the society. */
1015
1099
  project: NameSchema.nullable().default(null),
1016
1100
  name: NameSchema,
1017
- purpose: z5.string().min(1)
1101
+ purpose: z6.string().min(1)
1018
1102
  }),
1019
- archive_channel: z5.object({ channel: ChannelRefSchema, reason: z5.string().min(1) }),
1020
- update_dashboard: z5.object({
1103
+ archive_channel: z6.object({ channel: ChannelRefSchema, reason: z6.string().min(1) }),
1104
+ update_dashboard: z6.object({
1021
1105
  project: NameSchema,
1022
1106
  /** The whole dashboard as markdown; the board keeps its frontmatter. */
1023
- body: z5.string().min(1),
1107
+ body: z6.string().min(1),
1024
1108
  /** The `revision` in the frontmatter of the dashboard you read, 0 when it names none. */
1025
- revision: z5.number().int().min(0)
1109
+ revision: z6.number().int().min(0)
1026
1110
  }),
1027
- create_cron: z5.object({
1111
+ create_cron: z6.object({
1028
1112
  title: CronTitleSchema,
1029
1113
  /** What to do when it fires; quoted in the prompt of every turn it starts. */
1030
1114
  note: CronNoteSchema,
@@ -1043,10 +1127,10 @@ var VerbInputs = {
1043
1127
  /** An open channel of that place other than general, whose conversation it fires in. */
1044
1128
  channel: NameSchema.optional()
1045
1129
  }),
1046
- update_cron: z5.object({
1130
+ update_cron: z6.object({
1047
1131
  cron_id: UlidSchema,
1048
1132
  /** Pause it, or resume it, which starts its schedule afresh from now. */
1049
- paused: z5.boolean().optional(),
1133
+ paused: z6.boolean().optional(),
1050
1134
  title: CronTitleSchema.optional(),
1051
1135
  note: CronNoteSchema.optional(),
1052
1136
  /** A new expression, or `at` for one time; either starts the schedule afresh. */
@@ -1055,12 +1139,12 @@ var VerbInputs = {
1055
1139
  timezone: TimeZoneSchema.nullable().optional(),
1056
1140
  at: MomentSchema.optional()
1057
1141
  }),
1058
- remove_cron: z5.object({ cron_id: UlidSchema, reason: z5.string().trim().min(1) }),
1059
- remove_skill: z5.object({ name: NameSchema, reason: z5.string().trim().min(1) })
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) })
1060
1144
  };
1061
1145
 
1062
1146
  // packages/shared/dist/events.js
1063
- import { z as z6 } from "zod";
1147
+ import { z as z7 } from "zod";
1064
1148
  var BOARD_EVENT_TYPES = [
1065
1149
  "society.initialized",
1066
1150
  "project.added",
@@ -1105,6 +1189,7 @@ var BOARD_EVENT_TYPES = [
1105
1189
  "user.signed_out",
1106
1190
  "user.token_rotated",
1107
1191
  "runner.changed",
1192
+ "runner.quota",
1108
1193
  "ops.signal",
1109
1194
  "paused.changed",
1110
1195
  "wake.requested",
@@ -1125,28 +1210,36 @@ var BOARD_EVENT_TYPES = [
1125
1210
  "cron.skipped",
1126
1211
  "cron.ended"
1127
1212
  ];
1128
- var BoardEventTypeSchema = z6.enum(BOARD_EVENT_TYPES);
1129
- var BoardEventSchema = z6.object({
1213
+ var BoardEventTypeSchema = z7.enum(BOARD_EVENT_TYPES);
1214
+ var BoardEventSchema = z7.object({
1130
1215
  id: UlidSchema,
1131
1216
  ts: IsoDateTimeSchema,
1132
1217
  type: BoardEventTypeSchema,
1133
1218
  actor: NameSchema,
1134
- payload: z6.record(z6.string(), z6.unknown())
1135
- });
1136
- var UsageSchema = z6.object({
1137
- inputTokens: z6.number().int().nonnegative(),
1138
- outputTokens: z6.number().int().nonnegative(),
1139
- cacheReadTokens: z6.number().int().nonnegative().default(0),
1140
- cacheWriteTokens: z6.number().int().nonnegative().default(0)
1141
- });
1142
- var TurnStatusSchema = z6.object({
1143
- summary: z6.string().min(1),
1144
- claimsHeld: z6.array(UlidSchema).default([]),
1145
- blockedOn: z6.array(z6.string()).default([]),
1146
- needsUserDecision: z6.boolean().default(false),
1147
- memoryUpdated: z6.boolean().default(false)
1148
- });
1149
- var TurnExitReasonSchema = z6.enum([
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([
1150
1243
  "completed",
1151
1244
  "timeout",
1152
1245
  "error",
@@ -1154,50 +1247,50 @@ var TurnExitReasonSchema = z6.enum([
1154
1247
  "blocked",
1155
1248
  "stopped"
1156
1249
  ]);
1157
- var AgentEventSchema = z6.discriminatedUnion("type", [
1158
- z6.object({
1159
- type: z6.literal("turn_started"),
1250
+ var AgentEventSchema = z7.discriminatedUnion("type", [
1251
+ z7.object({
1252
+ type: z7.literal("turn_started"),
1160
1253
  agent: NameSchema,
1161
- session: z6.string(),
1254
+ session: z7.string(),
1162
1255
  runner: NameSchema,
1163
1256
  /** The model the CLI reports running, when it reports one. */
1164
- model: z6.string().optional()
1257
+ model: z7.string().optional()
1165
1258
  }),
1166
1259
  /**
1167
1260
  * The CLI took a steer into the running turn. Adapters name the steer; the server adds the
1168
1261
  * messages it delivered and the text the CLI was given.
1169
1262
  */
1170
- z6.object({
1171
- type: z6.literal("steered"),
1172
- steer: z6.string().min(1),
1173
- messages: z6.array(UlidSchema).optional(),
1174
- text: z6.string().optional()
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()
1175
1268
  }),
1176
- z6.object({ type: z6.literal("text"), delta: z6.string() }),
1177
- z6.object({ type: z6.literal("tool_call"), name: z6.string(), input: z6.unknown() }),
1178
- z6.object({
1179
- type: z6.literal("tool_result"),
1180
- name: z6.string(),
1181
- ok: z6.boolean(),
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(),
1182
1275
  /** What the tool returned, cut to `OUTPUT_LIMIT` characters by `capOutput`. */
1183
- output: z6.string().optional()
1276
+ output: z7.string().optional()
1184
1277
  }),
1185
- z6.object({ type: z6.literal("approval_requested"), kind: z6.string(), detail: z6.unknown() }),
1186
- z6.object({
1187
- type: z6.literal("turn_completed"),
1278
+ z7.object({ type: z7.literal("approval_requested"), kind: z7.string(), detail: z7.unknown() }),
1279
+ z7.object({
1280
+ type: z7.literal("turn_completed"),
1188
1281
  usage: UsageSchema,
1189
- costUsd: z6.number().nonnegative(),
1282
+ costUsd: z7.number().nonnegative(),
1190
1283
  status: TurnStatusSchema.nullable(),
1191
1284
  exitReason: TurnExitReasonSchema
1192
1285
  }),
1193
- z6.object({ type: z6.literal("error"), message: z6.string() })
1286
+ z7.object({ type: z7.literal("error"), message: z7.string() })
1194
1287
  ]);
1195
- var TranscriptEntrySchema = z6.object({
1288
+ var TranscriptEntrySchema = z7.object({
1196
1289
  ts: IsoDateTimeSchema,
1197
1290
  event: AgentEventSchema
1198
1291
  });
1199
- var LiveTurnEventSchema = z6.object({
1200
- seq: z6.number().int().positive(),
1292
+ var LiveTurnEventSchema = z7.object({
1293
+ seq: z7.number().int().positive(),
1201
1294
  ts: IsoDateTimeSchema,
1202
1295
  agent: NameSchema,
1203
1296
  project: NameSchema,
@@ -1209,97 +1302,105 @@ var LiveTurnEventSchema = z6.object({
1209
1302
  });
1210
1303
 
1211
1304
  // packages/shared/dist/turns.js
1212
- import { z as z8 } from "zod";
1305
+ import { z as z9 } from "zod";
1213
1306
 
1214
1307
  // packages/shared/dist/runner.js
1215
- import { z as z7 } from "zod";
1308
+ import { z as z8 } from "zod";
1216
1309
  var HOME_SCRATCH = "scratch";
1217
1310
  var HOME_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
1218
- var RunnerHelloSchema = z7.object({
1219
- protocol: z7.number().int().positive(),
1220
- version: z7.string().min(1),
1311
+ var RunnerHelloSchema = z8.object({
1312
+ protocol: z8.number().int().positive(),
1313
+ version: z8.string().min(1),
1221
1314
  os: RunnerOsSchema,
1222
- clis: z7.array(CliKindSchema),
1315
+ clis: z8.array(CliKindSchema),
1223
1316
  /** The CLIs whose adapter can keep a session warm between turns. */
1224
- residentClis: z7.array(CliKindSchema).default([]),
1317
+ residentClis: z8.array(CliKindSchema).default([]),
1225
1318
  /** The CLIs whose adapter can take input into a running turn; the server steers only these. */
1226
- steerableClis: z7.array(CliKindSchema).default([]),
1319
+ steerableClis: z8.array(CliKindSchema).default([]),
1227
1320
  /** The CLIs whose adapter can stop a running turn; the server stops only these. */
1228
- stoppableClis: z7.array(CliKindSchema).default([]),
1321
+ stoppableClis: z8.array(CliKindSchema).default([]),
1229
1322
  /** Whether the runner answers file reads on its projects' branches; one from before never does. */
1230
- branchReads: z7.boolean().default(false),
1323
+ branchReads: z8.boolean().default(false),
1231
1324
  /** Whether the runner lists what a branch changed; one from before never does. */
1232
- branchChanges: z7.boolean().default(false),
1233
- capabilities: z7.array(z7.string()).default([]),
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(),
1234
1335
  /** Turns the runner runs at once, or null for no limit. */
1235
- slots: z7.number().int().positive().nullable(),
1336
+ slots: z8.number().int().positive().nullable(),
1236
1337
  /** Turns the runner is still running, when it registers again; the server fails the rest of its turns. */
1237
- turns: z7.array(UlidSchema).default([])
1338
+ turns: z8.array(UlidSchema).default([])
1238
1339
  });
1239
- var RunnerWelcomeSchema = z7.object({ name: NameSchema, version: z7.string() });
1240
- var RunnerEnrollRequestSchema = z7.object({
1241
- protocol: z7.number().int().positive(),
1242
- version: z7.string().min(1).max(64),
1243
- hostname: z7.string().min(1).max(253),
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),
1244
1345
  os: RunnerOsSchema,
1245
- clis: z7.array(CliKindSchema).max(8),
1246
- capabilities: z7.array(z7.string().min(1).max(64)).max(32).default([])
1346
+ clis: z8.array(CliKindSchema).max(8),
1347
+ capabilities: z8.array(z8.string().min(1).max(64)).max(32).default([])
1247
1348
  });
1248
- var RunnerEnrollmentSchema = z7.object({
1249
- deviceCode: z7.string().min(1),
1250
- userCode: z7.string().min(1),
1349
+ var RunnerEnrollmentSchema = z8.object({
1350
+ deviceCode: z8.string().min(1),
1351
+ userCode: z8.string().min(1),
1251
1352
  expiresAt: IsoDateTimeSchema,
1252
- intervalMs: z7.number().int().positive()
1353
+ intervalMs: z8.number().int().positive()
1253
1354
  });
1254
- var RunnerEnrollPollSchema = z7.object({ deviceCode: z7.string().min(1) });
1255
- var RunnerEnrollStatusSchema = z7.discriminatedUnion("status", [
1256
- z7.object({ status: z7.literal("pending") }),
1257
- z7.object({ status: z7.literal("approved"), name: NameSchema, token: z7.string().min(1) }),
1258
- z7.object({ status: z7.literal("denied") })
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") })
1259
1360
  ]);
1260
- var PendingEnrollmentSchema = z7.object({
1261
- userCode: z7.string().min(1),
1262
- hostname: z7.string(),
1361
+ var PendingEnrollmentSchema = z8.object({
1362
+ userCode: z8.string().min(1),
1363
+ hostname: z8.string(),
1263
1364
  os: RunnerOsSchema,
1264
- clis: z7.array(CliKindSchema),
1265
- capabilities: z7.array(z7.string()),
1266
- version: z7.string(),
1365
+ clis: z8.array(CliKindSchema),
1366
+ capabilities: z8.array(z8.string()),
1367
+ version: z8.string(),
1267
1368
  requestedAt: IsoDateTimeSchema,
1268
1369
  expiresAt: IsoDateTimeSchema
1269
1370
  });
1270
- var ProjectRepoSchema = z7.object({
1371
+ var ProjectRepoSchema = z8.object({
1271
1372
  slug: NameSchema,
1272
- origin: z7.string().nullable(),
1273
- defaultBranch: z7.string().min(1),
1373
+ origin: z8.string().nullable(),
1374
+ defaultBranch: z8.string().min(1),
1274
1375
  /**
1275
1376
  * The board lands finished tasks on the default branch, itself or through their pull requests,
1276
1377
  * so the runner lets nothing else move it.
1277
1378
  */
1278
- boardLands: z7.boolean()
1379
+ boardLands: z8.boolean()
1279
1380
  });
1280
- var TurnWorkspaceSchema = z7.discriminatedUnion("kind", [
1281
- z7.object({
1282
- kind: z7.literal("home"),
1381
+ var TurnWorkspaceSchema = z8.discriminatedUnion("kind", [
1382
+ z8.object({
1383
+ kind: z8.literal("home"),
1283
1384
  thread: UlidSchema.optional(),
1284
1385
  channel: NameSchema.optional()
1285
1386
  }),
1286
- z7.object({
1287
- kind: z7.literal("project"),
1387
+ z8.object({
1388
+ kind: z8.literal("project"),
1288
1389
  repo: ProjectRepoSchema,
1289
- branches: z7.array(z7.string().min(1)),
1390
+ branches: z8.array(z8.string().min(1)),
1290
1391
  thread: UlidSchema.optional(),
1291
1392
  channel: NameSchema.optional()
1292
1393
  }),
1293
- z7.object({ kind: z7.literal("task"), repo: ProjectRepoSchema, taskId: UlidSchema })
1394
+ z8.object({ kind: z8.literal("task"), repo: ProjectRepoSchema, taskId: UlidSchema })
1294
1395
  ]);
1295
- var TurnJobSchema = z7.object({
1396
+ var TurnJobSchema = z8.object({
1296
1397
  turnId: UlidSchema,
1297
1398
  agent: NameSchema,
1298
1399
  role: NameSchema,
1299
1400
  cli: CliKindSchema,
1300
- model: z7.string().optional(),
1401
+ model: z8.string().optional(),
1301
1402
  /** The reasoning effort set on the agent; absent for the model's own default. */
1302
- effort: z7.string().optional(),
1403
+ effort: z8.string().optional(),
1303
1404
  /** A project slug, or the society scope. */
1304
1405
  scope: NameSchema,
1305
1406
  /** The thread whose conversation the turn is in; absent for the home conversation. */
@@ -1310,125 +1411,130 @@ var TurnJobSchema = z7.object({
1310
1411
  * The session to resume, or null to start one: the CLI's adapter picks a fresh session's id, and
1311
1412
  * the outcome reports it.
1312
1413
  */
1313
- session: z7.string().min(1).nullable(),
1414
+ session: z8.string().min(1).nullable(),
1314
1415
  /** The running total the session reported after its last turn, which a resumed session starts from. */
1315
- costSoFarUsd: z7.number().nonnegative(),
1416
+ costSoFarUsd: z8.number().nonnegative(),
1316
1417
  /** The rendered charter, norms, memory core, and skills index, with `PATH_TOKENS` for places. */
1317
- instructions: z7.string(),
1318
- prompt: z7.string(),
1319
- mcp: z7.object({ url: z7.string().min(1), token: z7.string().min(1) }),
1320
- limits: z7.object({
1321
- timeoutMs: z7.number().int().positive().nullable(),
1322
- maxTurns: z7.number().int().positive().nullable()
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()
1323
1424
  }),
1324
1425
  /** Present when the runner keeps the conversation's session warm between turns, under `key`. */
1325
- resident: z7.object({ key: z7.string().min(1), idleMs: z7.number().int().positive() }).optional(),
1426
+ resident: z8.object({ key: z8.string().min(1), idleMs: z8.number().int().positive() }).optional(),
1326
1427
  workspace: TurnWorkspaceSchema
1327
1428
  });
1328
- var TurnWorkSchema = z7.object({ branch: z7.string().min(1), head: z7.string().min(1) });
1329
- var TurnEventsSchema = z7.object({ entries: z7.array(TranscriptEntrySchema) });
1330
- var TurnOutcomeSchema = z7.object({
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({
1331
1432
  exitReason: TurnExitReasonSchema,
1332
1433
  status: TurnStatusSchema.nullable(),
1333
- error: z7.string().nullable(),
1434
+ error: z8.string().nullable(),
1334
1435
  usage: UsageSchema,
1335
- costUsd: z7.number().nonnegative(),
1436
+ costUsd: z8.number().nonnegative(),
1336
1437
  /** The session's running total after this turn, for CLIs that report one. */
1337
- sessionCostUsd: z7.number().nonnegative().optional(),
1438
+ sessionCostUsd: z8.number().nonnegative().optional(),
1338
1439
  /** The session the CLI used, which differs from the job's for CLIs that assign their own ids. */
1339
- session: z7.string().min(1),
1440
+ session: z8.string().min(1),
1340
1441
  /** The model the CLI reported, when it reported one. */
1341
- model: z7.string().nullable(),
1442
+ model: z8.string().nullable(),
1342
1443
  work: TurnWorkSchema.nullable(),
1343
1444
  /**
1344
1445
  * Whether the turn's own workspace, a thread's, a channel's, or a task's, holds work on no
1345
1446
  * branch after the hand-back: uncommitted changes, or commits no branch contains.
1346
1447
  */
1347
- leftovers: z7.boolean().default(false)
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()
1348
1454
  });
1349
- var TurnAckSchema = z7.object({ dropWorkspace: z7.boolean() });
1350
- var LandRequestSchema = z7.object({
1455
+ var TurnAckSchema = z8.object({ dropWorkspace: z8.boolean() });
1456
+ var LandRequestSchema = z8.object({
1351
1457
  repo: ProjectRepoSchema,
1352
- branch: z7.string().min(1),
1458
+ branch: z8.string().min(1),
1353
1459
  /**
1354
1460
  * For a `ghpr` task, the pull request to merge in place of the branch, which must hold the
1355
1461
  * branch's files, and the merge commit's subject and body, the pull request's title and an
1356
1462
  * empty body when left out.
1357
1463
  */
1358
- pullRequest: z7.object({
1359
- url: z7.string().min(1),
1360
- subject: z7.string().min(1).optional(),
1361
- body: z7.string().optional()
1464
+ pullRequest: z8.object({
1465
+ url: z8.string().min(1),
1466
+ subject: z8.string().min(1).optional(),
1467
+ body: z8.string().optional()
1362
1468
  }).optional()
1363
1469
  });
1364
- var CloseRequestSchema = z7.object({
1470
+ var CloseRequestSchema = z8.object({
1365
1471
  repo: ProjectRepoSchema,
1366
- url: z7.string().min(1),
1367
- comment: z7.string().min(1)
1472
+ url: z8.string().min(1),
1473
+ comment: z8.string().min(1)
1368
1474
  });
1369
- var MergeOutcomeSchema = z7.object({ ok: z7.boolean(), detail: z7.string() });
1370
- var ModelListSchema = z7.array(ModelOptionSchema);
1475
+ var MergeOutcomeSchema = z8.object({ ok: z8.boolean(), detail: z8.string() });
1476
+ var ModelListSchema = z8.array(ModelOptionSchema);
1371
1477
  var BRANCH_FILE_LIMIT_BYTES = 8 * 1024 * 1024;
1372
- var BranchPathSchema = z7.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" });
1373
- var BranchNameSchema = z7.string().regex(/^[A-Za-z0-9][A-Za-z0-9._/-]*$/);
1374
- var BranchReadSchema = z7.object({
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({
1375
1481
  repo: ProjectRepoSchema,
1376
1482
  branch: BranchNameSchema,
1377
1483
  path: BranchPathSchema
1378
1484
  });
1379
- var BranchCommitSchema = z7.object({
1380
- id: z7.string().min(1),
1485
+ var BranchCommitSchema = z8.object({
1486
+ id: z8.string().min(1),
1381
1487
  at: IsoDateTimeSchema,
1382
- author: z7.string()
1488
+ author: z8.string()
1383
1489
  });
1384
- var BranchFileSchema = z7.discriminatedUnion("kind", [
1385
- z7.object({
1386
- kind: z7.literal("file"),
1490
+ var BranchFileSchema = z8.discriminatedUnion("kind", [
1491
+ z8.object({
1492
+ kind: z8.literal("file"),
1387
1493
  path: BranchPathSchema,
1388
1494
  commit: BranchCommitSchema,
1389
- size: z7.number().int().nonnegative(),
1390
- content: z7.string().nullable()
1495
+ size: z8.number().int().nonnegative(),
1496
+ content: z8.string().nullable()
1391
1497
  }),
1392
- z7.object({
1393
- kind: z7.literal("dir"),
1498
+ z8.object({
1499
+ kind: z8.literal("dir"),
1394
1500
  path: BranchPathSchema,
1395
1501
  commit: BranchCommitSchema,
1396
- entries: z7.array(z7.object({
1397
- name: z7.string().min(1),
1398
- kind: z7.enum(["file", "dir"]),
1399
- size: z7.number().int().nonnegative().nullable()
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()
1400
1506
  }))
1401
1507
  })
1402
1508
  ]);
1403
- var BranchChangesReadSchema = z7.object({
1509
+ var BranchChangesReadSchema = z8.object({
1404
1510
  repo: ProjectRepoSchema,
1405
1511
  branch: BranchNameSchema
1406
1512
  });
1407
- var BranchFileChangeSchema = z7.object({
1408
- path: z7.string().min(1),
1409
- status: z7.enum(["added", "modified", "deleted"]),
1513
+ var BranchFileChangeSchema = z8.object({
1514
+ path: z8.string().min(1),
1515
+ status: z8.enum(["added", "modified", "deleted"]),
1410
1516
  /** Lines added and removed, or null for a binary file. */
1411
- added: z7.number().int().nonnegative().nullable(),
1412
- removed: z7.number().int().nonnegative().nullable(),
1517
+ added: z8.number().int().nonnegative().nullable(),
1518
+ removed: z8.number().int().nonnegative().nullable(),
1413
1519
  /** Absent when the file changed only through a merge of another branch. */
1414
- lastChange: z7.object({ author: z7.string(), at: IsoDateTimeSchema }).optional()
1520
+ lastChange: z8.object({ author: z8.string(), at: IsoDateTimeSchema }).optional()
1415
1521
  });
1416
- var BranchChangesSchema = z7.object({
1522
+ var BranchChangesSchema = z8.object({
1417
1523
  head: BranchCommitSchema,
1418
- files: z7.array(BranchFileChangeSchema),
1419
- total: z7.number().int().nonnegative()
1524
+ files: z8.array(BranchFileChangeSchema),
1525
+ total: z8.number().int().nonnegative()
1420
1526
  });
1421
- var BranchDiffReadSchema = z7.object({
1527
+ var BranchDiffReadSchema = z8.object({
1422
1528
  repo: ProjectRepoSchema,
1423
1529
  branch: BranchNameSchema,
1424
1530
  path: BranchPathSchema.min(1)
1425
1531
  });
1426
- var BranchFileDiffSchema = z7.object({
1532
+ var BranchFileDiffSchema = z8.object({
1427
1533
  head: BranchCommitSchema,
1428
1534
  path: BranchPathSchema,
1429
1535
  status: BranchFileChangeSchema.shape.status,
1430
- patch: z7.string().nullable(),
1431
- truncated: z7.boolean()
1536
+ patch: z8.string().nullable(),
1537
+ truncated: z8.boolean()
1432
1538
  });
1433
1539
  function patchHunks(patch, limit) {
1434
1540
  if (/^Binary files .* differ$/m.test(patch)) {
@@ -1442,64 +1548,69 @@ function patchHunks(patch, limit) {
1442
1548
  const cut = hunks.lastIndexOf("\n", limit);
1443
1549
  return { patch: hunks.slice(0, cut === -1 ? limit : cut), truncated: true };
1444
1550
  }
1445
- var WorkspaceConversationSchema = z7.discriminatedUnion("kind", [
1446
- z7.object({ kind: z7.literal("thread"), id: UlidSchema }),
1447
- z7.object({ kind: z7.literal("channel"), scope: NameSchema, name: NameSchema })
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 })
1448
1554
  ]);
1449
- var HeldWorkspaceSchema = z7.object({
1555
+ var HeldWorkspaceSchema = z8.object({
1450
1556
  agent: NameSchema,
1451
1557
  scope: NameSchema,
1452
1558
  conversation: WorkspaceConversationSchema
1453
1559
  });
1454
- var HeldWorkspacesSchema = z7.object({ workspaces: z7.array(HeldWorkspaceSchema) });
1455
- var SweepResultSchema = z7.object({ kept: z7.array(HeldWorkspaceSchema) });
1456
- var TurnSteerSchema = z7.object({ id: z7.uuid(), text: z7.string().min(1) });
1457
- var RunnerMessageSchema = z7.discriminatedUnion("type", [
1458
- z7.object({ type: z7.literal("turn"), job: TurnJobSchema }),
1459
- z7.object({ type: z7.literal("land"), request: z7.string().min(1), land: LandRequestSchema }),
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 }),
1460
1566
  /** Answered with a `MergeOutcome`. */
1461
- z7.object({ type: z7.literal("close"), request: z7.string().min(1), close: CloseRequestSchema }),
1462
- z7.object({ type: z7.literal("models"), request: z7.string().min(1), cli: CliKindSchema }),
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 }),
1463
1574
  /** Answered with a `BranchFile`, or null when the branch or the path does not exist. */
1464
- z7.object({ type: z7.literal("file"), request: z7.string().min(1), read: BranchReadSchema }),
1575
+ z8.object({ type: z8.literal("file"), request: z8.string().min(1), read: BranchReadSchema }),
1465
1576
  /** Answered with `BranchChanges`, or null when the repository or the branch does not exist. */
1466
- z7.object({
1467
- type: z7.literal("changes"),
1468
- request: z7.string().min(1),
1577
+ z8.object({
1578
+ type: z8.literal("changes"),
1579
+ request: z8.string().min(1),
1469
1580
  read: BranchChangesReadSchema
1470
1581
  }),
1471
1582
  /** Answered with a `BranchFileDiff`, or null when the branch does not exist or left the path alone. */
1472
- z7.object({ type: z7.literal("diff"), request: z7.string().min(1), read: BranchDiffReadSchema }),
1583
+ z8.object({ type: z8.literal("diff"), request: z8.string().min(1), read: BranchDiffReadSchema }),
1473
1584
  /** Answered with whether the CLI accepted it; that it took it comes as a `steered` event. */
1474
- z7.object({
1475
- type: z7.literal("steer"),
1476
- request: z7.string().min(1),
1585
+ z8.object({
1586
+ type: z8.literal("steer"),
1587
+ request: z8.string().min(1),
1477
1588
  turnId: UlidSchema,
1478
1589
  steer: TurnSteerSchema
1479
1590
  }),
1480
1591
  /** Answered with whether the turn was there to stop; it ends `stopped`. */
1481
- z7.object({ type: z7.literal("stop"), request: z7.string().min(1), turnId: UlidSchema }),
1592
+ z8.object({ type: z8.literal("stop"), request: z8.string().min(1), turnId: UlidSchema }),
1482
1593
  /**
1483
1594
  * A conversation ended: the runner removes every citizen's workspace for it but those a turn
1484
1595
  * still uses, and answers with a `SweepResult` naming those it kept for holding work on no branch.
1485
1596
  */
1486
- z7.object({
1487
- type: z7.literal("sweep"),
1488
- request: z7.string().min(1),
1597
+ z8.object({
1598
+ type: z8.literal("sweep"),
1599
+ request: z8.string().min(1),
1489
1600
  conversation: WorkspaceConversationSchema
1490
1601
  })
1491
1602
  ]);
1492
- var RunnerAnswerSchema = z7.discriminatedUnion("ok", [
1493
- z7.object({ ok: z7.literal(true), value: z7.unknown() }),
1494
- z7.object({ ok: z7.literal(false), error: z7.string() })
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() })
1495
1606
  ]);
1496
- var WarmSessionsSchema = z7.object({ warm: z7.array(z7.string()) });
1497
- var FileManifestSchema = z7.object({ files: z7.record(z7.string(), z7.string()) });
1607
+ var WarmSessionsSchema = z8.object({ warm: z8.array(z8.string()) });
1608
+ var FileManifestSchema = z8.object({ files: z8.record(z8.string(), z8.string()) });
1498
1609
  function fileVersion(sha, executable) {
1499
1610
  return executable ? `${sha}+x` : sha;
1500
1611
  }
1501
- var FileReadSchema = z7.object({ paths: z7.array(z7.string()) });
1502
- var FileContentsSchema = z7.object({ files: z7.record(z7.string(), z7.string()) });
1612
+ var FileReadSchema = z8.object({ paths: z8.array(z8.string()) });
1613
+ var FileContentsSchema = z8.object({ files: z8.record(z8.string(), z8.string()) });
1503
1614
  function isSafeRelativePath(file) {
1504
1615
  if (file.length === 0 || file.startsWith("/") || file.includes("\\") || file.includes("\0")) {
1505
1616
  return false;
@@ -1508,7 +1619,7 @@ function isSafeRelativePath(file) {
1508
1619
  }
1509
1620
 
1510
1621
  // packages/shared/dist/turns.js
1511
- var TriggerKindSchema = z8.enum([
1622
+ var TriggerKindSchema = z9.enum([
1512
1623
  "mention",
1513
1624
  "stage",
1514
1625
  "task_done",
@@ -1522,11 +1633,11 @@ var TriggerKindSchema = z8.enum([
1522
1633
  "closing",
1523
1634
  "cron"
1524
1635
  ]);
1525
- var TriggerSchema = z8.object({
1636
+ var TriggerSchema = z9.object({
1526
1637
  kind: TriggerKindSchema,
1527
1638
  from: NameSchema.optional(),
1528
- fromUser: z8.boolean().default(false),
1529
- reason: z8.string().default(""),
1639
+ fromUser: z9.boolean().default(false),
1640
+ reason: z9.string().default(""),
1530
1641
  taskId: UlidSchema.optional(),
1531
1642
  messageId: UlidSchema.optional(),
1532
1643
  /** The channel the waking message was posted in. */
@@ -1534,17 +1645,17 @@ var TriggerSchema = z8.object({
1534
1645
  /** The cron that came due, for a `cron` wake. */
1535
1646
  cronId: UlidSchema.optional()
1536
1647
  });
1537
- var TurnThreadSchema = z8.object({ id: UlidSchema, task: z8.boolean() });
1538
- var TurnDispatchSchema = z8.object({
1648
+ var TurnThreadSchema = z9.object({ id: UlidSchema, task: z9.boolean() });
1649
+ var TurnDispatchSchema = z9.object({
1539
1650
  agent: NameSchema,
1540
1651
  project: NameSchema,
1541
1652
  thread: TurnThreadSchema.optional(),
1542
1653
  channel: NameSchema.optional(),
1543
1654
  trigger: TriggerSchema,
1544
- priority: z8.number().int().min(0).max(2),
1545
- onboarding: z8.boolean().default(false),
1655
+ priority: z9.number().int().min(0).max(2),
1656
+ onboarding: z9.boolean().default(false),
1546
1657
  /** Every cron that came due for this turn, whatever wake it merged into; its prompt quotes each. */
1547
- crons: z8.array(UlidSchema).optional()
1658
+ crons: z9.array(UlidSchema).optional()
1548
1659
  });
1549
1660
  function conversationPart(conversation) {
1550
1661
  return conversation.thread ?? (conversation.channel === void 0 ? void 0 : `#${conversation.channel}`);
@@ -1555,7 +1666,7 @@ function channelConversation(scope, channel) {
1555
1666
  const name = at < 0 ? channel : channel.slice(at + 1);
1556
1667
  return place === scope && name !== "general" ? name : void 0;
1557
1668
  }
1558
- var TurnRecordSchema = z8.object({
1669
+ var TurnRecordSchema = z9.object({
1559
1670
  /** Assigned by the board when the turn begins; the turn's transcript is filed under it. */
1560
1671
  id: UlidSchema.optional(),
1561
1672
  agent: NameSchema,
@@ -1566,31 +1677,31 @@ var TurnRecordSchema = z8.object({
1566
1677
  channel: NameSchema.optional(),
1567
1678
  runner: NameSchema,
1568
1679
  cli: CliKindSchema.nullable(),
1569
- session: z8.string().nullable(),
1680
+ session: z9.string().nullable(),
1570
1681
  trigger: TriggerSchema,
1571
1682
  startedAt: IsoDateTimeSchema,
1572
1683
  endedAt: IsoDateTimeSchema.nullable(),
1573
1684
  exitReason: TurnExitReasonSchema.nullable(),
1574
1685
  status: TurnStatusSchema.nullable(),
1575
- error: z8.string().nullable(),
1686
+ error: z9.string().nullable(),
1576
1687
  usage: UsageSchema.nullable(),
1577
- costUsd: z8.number().nonnegative().default(0),
1688
+ costUsd: z9.number().nonnegative().default(0),
1578
1689
  /**
1579
1690
  * The running total the CLI reported for the session after this turn, when it reports one. A
1580
1691
  * resumed session starts from it, so the next turn's own cost is measured from here.
1581
1692
  */
1582
- sessionCostUsd: z8.number().nonnegative().optional(),
1583
- toolCalls: z8.number().int().nonnegative().default(0),
1693
+ sessionCostUsd: z9.number().nonnegative().optional(),
1694
+ toolCalls: z9.number().int().nonnegative().default(0),
1584
1695
  /** The model the CLI reported for this turn, else the model configured for the agent, else null. */
1585
- model: z8.string().nullable().default(null),
1696
+ model: z9.string().nullable().default(null),
1586
1697
  /** The task branch the turn left work on, with its commit, as the runner reported it. */
1587
1698
  work: TurnWorkSchema.optional(),
1588
1699
  /** Who stopped the turn, for one that ended `stopped`. */
1589
1700
  stoppedBy: NameSchema.optional(),
1590
1701
  /** The crons whose fire started the turn, which record how it ended. */
1591
- crons: z8.array(UlidSchema).optional()
1702
+ crons: z9.array(UlidSchema).optional()
1592
1703
  });
1593
- var RunningTurnSchema = z8.object({
1704
+ var RunningTurnSchema = z9.object({
1594
1705
  turnId: UlidSchema,
1595
1706
  agent: NameSchema,
1596
1707
  scope: NameSchema,
@@ -1598,49 +1709,49 @@ var RunningTurnSchema = z8.object({
1598
1709
  channel: NameSchema.optional(),
1599
1710
  cli: CliKindSchema,
1600
1711
  askedIn: ChannelRefSchema.optional(),
1601
- steerable: z8.boolean(),
1602
- stoppable: z8.boolean()
1712
+ steerable: z9.boolean(),
1713
+ stoppable: z9.boolean()
1603
1714
  });
1604
- var SessionsFileSchema = z8.object({
1605
- claude: z8.string().optional(),
1606
- codex: z8.string().optional(),
1715
+ var SessionsFileSchema = z9.object({
1716
+ claude: z9.string().optional(),
1717
+ codex: z9.string().optional(),
1607
1718
  runner: NameSchema.optional()
1608
1719
  });
1609
- var WakeRequestSchema = z8.object({
1720
+ var WakeRequestSchema = z9.object({
1610
1721
  agent: NameSchema,
1611
1722
  project: NameSchema,
1612
- reason: z8.string().default("manual wake"),
1723
+ reason: z9.string().default("manual wake"),
1613
1724
  /** A manual wake, or a reflection turn requested ahead of the cadence. */
1614
- kind: z8.enum(["manual", "reflection"]).default("manual")
1725
+ kind: z9.enum(["manual", "reflection"]).default("manual")
1615
1726
  });
1616
- var TurnHistoryEntrySchema = z8.object({
1727
+ var TurnHistoryEntrySchema = z9.object({
1617
1728
  /** The id of the event that ended the turn. */
1618
1729
  id: UlidSchema,
1619
1730
  /** The turn's own id, when it has a transcript to open; turns before transcripts have none. */
1620
1731
  turnId: UlidSchema.optional(),
1621
1732
  ts: IsoDateTimeSchema,
1622
- outcome: z8.enum(["completed", "failed"]),
1733
+ outcome: z9.enum(["completed", "failed"]),
1623
1734
  /** A project slug, or the society scope. */
1624
1735
  project: NameSchema,
1625
1736
  /** The thread whose conversation the turn was in; absent for the home conversation. */
1626
1737
  thread: UlidSchema.optional(),
1627
1738
  /** The channel, never general, whose conversation the turn was in. */
1628
1739
  channel: NameSchema.optional(),
1629
- trigger: z8.string(),
1630
- exitReason: z8.string().nullable(),
1631
- costUsd: z8.number(),
1740
+ trigger: z9.string(),
1741
+ exitReason: z9.string().nullable(),
1742
+ costUsd: z9.number(),
1632
1743
  /** The tokens the turn used; absent for turns logged before turns recorded them. */
1633
1744
  usage: UsageSchema.optional(),
1634
- model: z8.string().nullable(),
1635
- summary: z8.string().nullable(),
1636
- error: z8.string().nullable(),
1745
+ model: z9.string().nullable(),
1746
+ summary: z9.string().nullable(),
1747
+ error: z9.string().nullable(),
1637
1748
  /** When the log recorded the turn's start; absent when the start is missing from the log. */
1638
1749
  startedAt: IsoDateTimeSchema.optional(),
1639
- toolCalls: z8.number().int().nonnegative().optional()
1750
+ toolCalls: z9.number().int().nonnegative().optional()
1640
1751
  });
1641
1752
 
1642
1753
  // packages/shared/dist/ops.js
1643
- import { z as z9 } from "zod";
1754
+ import { z as z10 } from "zod";
1644
1755
  var OPS_SIGNAL_KINDS = [
1645
1756
  "waiting_stage",
1646
1757
  "backlog",
@@ -1656,16 +1767,16 @@ var OPS_SIGNAL_KINDS = [
1656
1767
  "stuck_workspace",
1657
1768
  "cron_failing"
1658
1769
  ];
1659
- var OpsSignalKindSchema = z9.enum(OPS_SIGNAL_KINDS);
1660
- var OpsSignalSchema = z9.object({
1770
+ var OpsSignalKindSchema = z10.enum(OPS_SIGNAL_KINDS);
1771
+ var OpsSignalSchema = z10.object({
1661
1772
  kind: OpsSignalKindSchema,
1662
1773
  /** Identifies the condition, for example `backlog:demo:engineer`, so a persisting one is not logged again every pass. */
1663
- key: z9.string().min(1),
1774
+ key: z10.string().min(1),
1664
1775
  /** One line a reader can act on. */
1665
- summary: z9.string().min(1),
1776
+ summary: z10.string().min(1),
1666
1777
  /** The counter or timer value behind the signal. */
1667
- value: z9.number(),
1668
- threshold: z9.number().optional(),
1778
+ value: z10.number(),
1779
+ threshold: z10.number().optional(),
1669
1780
  project: NameSchema.optional(),
1670
1781
  agent: NameSchema.optional(),
1671
1782
  role: NameSchema.optional(),
@@ -1673,8 +1784,8 @@ var OpsSignalSchema = z9.object({
1673
1784
  });
1674
1785
 
1675
1786
  // packages/shared/dist/metrics.js
1676
- import { z as z10 } from "zod";
1677
- var MetricsWindowSchema = z10.enum(["24h", "7d", "all"]);
1787
+ import { z as z11 } from "zod";
1788
+ var MetricsWindowSchema = z11.enum(["24h", "7d", "all"]);
1678
1789
  var METRICS_WINDOW_MS = {
1679
1790
  "24h": 24 * 36e5,
1680
1791
  "7d": 7 * 24 * 36e5,
@@ -1685,9 +1796,9 @@ function isBoardAction(tool) {
1685
1796
  const verb = /^mcp__board__(.+)$/.exec(tool)?.[1];
1686
1797
  return verb !== void 0 && !READ_VERBS.some((read2) => read2 === verb);
1687
1798
  }
1688
- var CountSchema = z10.number().int().nonnegative();
1689
- var MsSchema = z10.number().nonnegative();
1690
- var MetricsSchema = z10.object({
1799
+ var CountSchema = z11.number().int().nonnegative();
1800
+ var MsSchema = z11.number().nonnegative();
1801
+ var MetricsSchema = z11.object({
1691
1802
  window: MetricsWindowSchema,
1692
1803
  since: IsoDateTimeSchema.nullable(),
1693
1804
  until: IsoDateTimeSchema,
@@ -1695,12 +1806,12 @@ var MetricsSchema = z10.object({
1695
1806
  * Finished turns that changed nothing on the board. Reflections are left out, since they write
1696
1807
  * memory, not the board; turns without a transcript are counted apart, their actions unknown.
1697
1808
  */
1698
- idle: z10.object({
1809
+ idle: z11.object({
1699
1810
  turns: CountSchema,
1700
1811
  idle: CountSchema,
1701
1812
  unknown: CountSchema,
1702
- byTrigger: z10.array(z10.object({ trigger: z10.string(), turns: CountSchema, idle: CountSchema })),
1703
- byAgent: z10.array(z10.object({
1813
+ byTrigger: z11.array(z11.object({ trigger: z11.string(), turns: CountSchema, idle: CountSchema })),
1814
+ byAgent: z11.array(z11.object({
1704
1815
  agent: NameSchema,
1705
1816
  role: NameSchema.nullable(),
1706
1817
  turns: CountSchema,
@@ -1708,33 +1819,33 @@ var MetricsSchema = z10.object({
1708
1819
  }))
1709
1820
  }),
1710
1821
  /** Work sent back to an earlier stage: over the tasks finished in the window, and by where. */
1711
- sentBack: z10.object({
1822
+ sentBack: z11.object({
1712
1823
  finished: CountSchema,
1713
1824
  sendBacks: CountSchema,
1714
1825
  tasksSentBack: CountSchema,
1715
- byStage: z10.array(z10.object({ project: NameSchema, stage: z10.string(), count: CountSchema })),
1716
- bySender: z10.array(z10.object({ agent: NameSchema, count: CountSchema }))
1826
+ byStage: z11.array(z11.object({ project: NameSchema, stage: z11.string(), count: CountSchema })),
1827
+ bySender: z11.array(z11.object({ agent: NameSchema, count: CountSchema }))
1717
1828
  }),
1718
1829
  /** Posts in the threads of the tasks finished in the window, the board's own notices left out. */
1719
- messages: z10.object({
1830
+ messages: z11.object({
1720
1831
  finished: CountSchema,
1721
1832
  messages: CountSchema,
1722
- byProject: z10.array(z10.object({ project: NameSchema, finished: CountSchema, messages: CountSchema })),
1723
- busiest: z10.array(z10.object({
1833
+ byProject: z11.array(z11.object({ project: NameSchema, finished: CountSchema, messages: CountSchema })),
1834
+ busiest: z11.array(z11.object({
1724
1835
  taskId: UlidSchema,
1725
- title: z10.string(),
1836
+ title: z11.string(),
1726
1837
  project: NameSchema,
1727
1838
  messages: CountSchema
1728
1839
  }))
1729
1840
  }),
1730
1841
  /** Time from a mention to the start of the turn it woke, in the conversation it was made in. */
1731
- latency: z10.object({
1842
+ latency: z11.object({
1732
1843
  mentions: CountSchema,
1733
1844
  /** Mentions no turn has followed yet. */
1734
1845
  unanswered: CountSchema,
1735
1846
  medianMs: MsSchema.nullable(),
1736
1847
  slowestMs: MsSchema.nullable(),
1737
- byAgent: z10.array(z10.object({
1848
+ byAgent: z11.array(z11.object({
1738
1849
  agent: NameSchema,
1739
1850
  mentions: CountSchema,
1740
1851
  medianMs: MsSchema,
@@ -1742,81 +1853,141 @@ var MetricsSchema = z10.object({
1742
1853
  }))
1743
1854
  }),
1744
1855
  /** The user's decisions: proposals decided, questions answered, and stages passed or sent back. */
1745
- decisions: z10.object({
1856
+ decisions: z11.object({
1746
1857
  total: CountSchema,
1747
- byDay: z10.array(z10.object({
1748
- day: z10.string(),
1858
+ byDay: z11.array(z11.object({
1859
+ day: z11.string(),
1749
1860
  proposals: CountSchema,
1750
1861
  answers: CountSchema,
1751
1862
  stages: CountSchema
1752
1863
  }))
1753
1864
  }),
1754
1865
  /** Tasks that needed a capability no connected runner offered, and whether they still do. */
1755
- blocked: z10.array(z10.object({
1866
+ blocked: z11.array(z11.object({
1756
1867
  taskId: UlidSchema,
1757
- title: z10.string().nullable(),
1868
+ title: z11.string().nullable(),
1758
1869
  project: NameSchema.nullable(),
1759
- summary: z10.string(),
1870
+ summary: z11.string(),
1760
1871
  firstAt: IsoDateTimeSchema,
1761
1872
  lastAt: IsoDateTimeSchema,
1762
- holds: z10.boolean()
1873
+ holds: z11.boolean()
1763
1874
  }))
1764
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
+ });
1765
1888
 
1766
1889
  // packages/shared/dist/config.js
1767
- import { z as z11 } from "zod";
1768
- var LogLevelSchema = z11.enum(["trace", "debug", "info", "warn", "error", "fatal"]);
1769
- var GithubSignInSchema = z11.object({
1770
- clientId: z11.string().min(1),
1771
- clientSecret: z11.string().min(1),
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),
1772
1895
  /** Logins, lowercased; GitHub logins are case-insensitive. */
1773
- users: z11.array(z11.string().min(1)).min(1)
1896
+ users: z12.array(z12.string().min(1)).min(1)
1774
1897
  });
1775
- var ServerConfigSchema = z11.object({
1776
- dataDir: z11.string().min(1),
1777
- host: z11.string().min(1),
1778
- port: z11.number().int().positive().max(65535),
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),
1779
1902
  /**
1780
1903
  * An address every runner's agents reach this server at, for example https://board.example, or
1781
1904
  * null for each runner to use the address it reaches the server at itself.
1782
1905
  */
1783
- publicUrl: z11.string().min(1).nullable(),
1906
+ publicUrl: z12.string().min(1).nullable(),
1784
1907
  logLevel: LogLevelSchema,
1785
1908
  /** Turns running at once across every runner, or null for no limit beyond each runner's own. */
1786
- concurrency: z11.number().int().positive().nullable(),
1909
+ concurrency: z12.number().int().positive().nullable(),
1787
1910
  /** How long one turn may run before it is stopped, or null for no limit. */
1788
- turnTimeoutMs: z11.number().int().positive().nullable(),
1911
+ turnTimeoutMs: z12.number().int().positive().nullable(),
1789
1912
  /** Rounds of tool calls one Claude turn may take, or null for no limit. */
1790
- toolRounds: z11.number().int().positive().nullable(),
1913
+ toolRounds: z12.number().int().positive().nullable(),
1791
1914
  /** How long a resident session stays warm after its last turn. */
1792
- residentIdleMs: z11.number().int().positive(),
1915
+ residentIdleMs: z12.number().int().positive(),
1793
1916
  /** Signing in to the board with GitHub, or null when only a token lets anyone in. */
1794
1917
  github: GithubSignInSchema.nullable(),
1795
1918
  /**
1796
1919
  * Reverse proxies in front of the server whose X-Forwarded-For entries name the client, for the
1797
1920
  * rate limits on what anyone may ask without a token: 0 when clients connect directly.
1798
1921
  */
1799
- trustedProxies: z11.number().int().min(0).max(16)
1922
+ trustedProxies: z12.number().int().min(0).max(16)
1800
1923
  });
1801
- var RunnerConfigSchema = z11.object({
1924
+ var RunnerConfigSchema = z12.object({
1802
1925
  /** The board server, for example http://127.0.0.1:4700. */
1803
- serverUrl: z11.string().url(),
1926
+ serverUrl: z12.string().url(),
1804
1927
  /**
1805
1928
  * The runner's token, from `runner add`, or null for the one it saved when it was enrolled, or
1806
1929
  * to enroll it.
1807
1930
  */
1808
- token: z11.string().min(1).nullable(),
1931
+ token: z12.string().min(1).nullable(),
1809
1932
  /** The runner's own data directory: the board mirror, agent homes, repositories, worktrees. */
1810
- dataDir: z11.string().min(1),
1933
+ dataDir: z12.string().min(1),
1811
1934
  logLevel: LogLevelSchema,
1812
1935
  /** Turns this machine runs at once, or null for no limit. */
1813
- slots: z11.number().int().positive().nullable(),
1814
- clis: z11.array(CliKindSchema).min(1),
1815
- capabilities: z11.array(z11.string())
1936
+ slots: z12.number().int().positive().nullable(),
1937
+ clis: z12.array(CliKindSchema).min(1),
1938
+ capabilities: z12.array(z12.string())
1816
1939
  });
1817
1940
 
1818
1941
  // packages/shared/dist/version.js
1819
- var STELLARIS_VERSION = "0.3.21";
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
+ }
1820
1991
 
1821
1992
  // packages/board-core/dist/errors.js
1822
1993
  var BoardError = class extends Error {
@@ -2459,33 +2630,59 @@ function filesOf(lines, status) {
2459
2630
  return [...files.values()];
2460
2631
  }
2461
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
+
2462
2659
  // packages/board-core/dist/metrics.js
2463
- import { z as z12 } from "zod";
2464
- var TurnPayload = z12.object({
2465
- turnId: z12.string().optional(),
2466
- project: z12.string(),
2467
- thread: z12.string().optional(),
2468
- channel: z12.string().optional(),
2469
- trigger: z12.string()
2470
- });
2471
- var TaskPayload = z12.object({
2472
- taskId: z12.string(),
2473
- project: z12.string(),
2474
- from: z12.string().optional()
2475
- });
2476
- var MessagePayload = z12.object({
2477
- id: z12.string().optional(),
2478
- channel: z12.string(),
2479
- thread: z12.string().nullable().optional(),
2480
- mentions: z12.array(z12.string()).default([])
2481
- });
2482
- var SteeredPayload = z12.object({ messages: z12.array(z12.string()) });
2483
- var SignalPayload = z12.object({
2484
- kind: z12.string(),
2485
- key: z12.string(),
2486
- summary: z12.string(),
2487
- taskId: z12.string().optional(),
2488
- project: z12.string().optional()
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()
2489
2686
  });
2490
2687
  function median(values) {
2491
2688
  const sorted = values.toSorted((a, b) => a - b);
@@ -2774,6 +2971,59 @@ function computeMetrics(input) {
2774
2971
  };
2775
2972
  }
2776
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
+
2777
3027
  // packages/board-core/dist/mutex.js
2778
3028
  var Mutex = class {
2779
3029
  tail = Promise.resolve();
@@ -3015,41 +3265,27 @@ function namesList(names) {
3015
3265
  return names.length <= 1 ? names[0] ?? "" : `${names.slice(0, -1).join(", ")} and ${names.at(-1) ?? ""}`;
3016
3266
  }
3017
3267
  var SKIPPED_IN_HOME = /* @__PURE__ */ new Set([".git", "turns", ".claude", ".codex"]);
3018
- var RunnerTokensSchema = z13.object({
3019
- runners: z13.record(z13.string(), z13.object({ tokenHash: z13.string().min(1) }))
3268
+ var RunnerTokensSchema = z15.object({
3269
+ runners: z15.record(z15.string(), z15.object({ tokenHash: z15.string().min(1) }))
3020
3270
  });
3021
- var SignInsSchema = z13.object({
3022
- signIns: z13.array(z13.object({
3023
- tokenHash: z13.string().min(1),
3024
- login: z13.string().min(1),
3271
+ var SignInsSchema = z15.object({
3272
+ signIns: z15.array(z15.object({
3273
+ tokenHash: z15.string().min(1),
3274
+ login: z15.string().min(1),
3025
3275
  /** The account's picture at the identity provider; sign-ins from before it have none. */
3026
- avatarUrl: z13.url().optional(),
3276
+ avatarUrl: z15.url().optional(),
3027
3277
  createdAt: IsoDateTimeSchema,
3028
3278
  expiresAt: IsoDateTimeSchema
3029
3279
  })).default([])
3030
3280
  });
3031
- var TurnHistoryPayloadSchema = z13.object({
3032
- project: NameSchema,
3033
- thread: UlidSchema.optional(),
3034
- channel: NameSchema.optional(),
3035
- trigger: z13.string().default("manual"),
3036
- exitReason: z13.string().nullable().default(null),
3037
- costUsd: z13.number().default(0),
3038
- usage: UsageSchema.optional(),
3039
- model: z13.string().nullable().default(null),
3040
- summary: z13.string().nullable().default(null),
3041
- error: z13.string().nullable().default(null),
3042
- toolCalls: z13.number().int().nonnegative().optional(),
3043
- turnId: UlidSchema.optional()
3044
- });
3045
- var TurnStartPayloadSchema = z13.object({ project: NameSchema, turnId: UlidSchema.optional() });
3046
- var CursorsSchema = z13.object({
3047
- digest: z13.string().nullable(),
3048
- scopes: z13.record(z13.string(), z13.string()).default({}),
3049
- threadsFrom: z13.record(z13.string(), z13.string().nullable()).default({}),
3050
- channelsFrom: z13.record(z13.string(), z13.string().nullable()).default({}),
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({}),
3051
3287
  /** How far a work role has read news, which goes to whichever of its general conversations reads first. */
3052
- news: z13.string().optional()
3288
+ news: z15.string().optional()
3053
3289
  });
3054
3290
  var NO_CURSORS = { digest: null, scopes: {}, threadsFrom: {}, channelsFrom: {} };
3055
3291
  function conversationKey(scope, part) {
@@ -3088,9 +3324,8 @@ function byId(a, b) {
3088
3324
  function turnTime(record) {
3089
3325
  return record.endedAt ?? record.startedAt;
3090
3326
  }
3091
- var PausedSchema = z13.object({ paused: z13.boolean() });
3327
+ var PausedSchema = z15.object({ paused: z15.boolean() });
3092
3328
  var DEFAULT_LEASE_MS = 30 * 60 * 1e3;
3093
- var MENTION_PATTERN = /(^|[^\w@])@([a-z0-9][a-z0-9-]{0,31})(?![\w-])/g;
3094
3329
  function withoutMentions(text) {
3095
3330
  return text.replaceAll(MENTION_PATTERN, "$1$2");
3096
3331
  }
@@ -3114,7 +3349,7 @@ var OPS_WAKE_TRIGGER = "ops_event";
3114
3349
  var FRONT_DESK_TRIGGER = "user_post";
3115
3350
  var OPS_CHANNELS = ["governance"];
3116
3351
  var FRONT_DESK_CHANNELS = [ASK_CHANNEL];
3117
- var AlignmentsSchema = z13.object({ applied: z13.array(z13.string()).default([]) });
3352
+ var AlignmentsSchema = z15.object({ applied: z15.array(z15.string()).default([]) });
3118
3353
  var FOLLOW_DECISIONS = "ops-readers-follow-decisions";
3119
3354
  var THREAD_RECORDS = "threads-as-records";
3120
3355
  var DIGEST_CURSORS = "digest-replaces-inbox";
@@ -3128,10 +3363,10 @@ var CHANNEL_CONVERSATIONS = "channel-conversations";
3128
3363
  var DASHBOARD_UPDATES = "dashboard-updates-granted";
3129
3364
  var CRON_VERBS = "cron-verbs-granted";
3130
3365
  var KNOWLEDGE_NOTICES = "knowledge-notices";
3131
- var KnowledgeEventSchema = z13.object({
3366
+ var KnowledgeEventSchema = z15.object({
3132
3367
  topic: NameSchema,
3133
3368
  project: NameSchema.nullable(),
3134
- replaced: z13.boolean().optional()
3369
+ replaced: z15.boolean().optional()
3135
3370
  });
3136
3371
  var CRON_VERB_NAMES = ["create_cron", "update_cron", "remove_cron"];
3137
3372
  var OLD_DASHBOARD_LINE = "Agents may edit this file. It is rendered by the board UI.";
@@ -3249,16 +3484,6 @@ function unanswered(messages) {
3249
3484
  }
3250
3485
  return waiting;
3251
3486
  }
3252
- function extractMentions(body) {
3253
- const found = /* @__PURE__ */ new Set();
3254
- for (const match of body.matchAll(MENTION_PATTERN)) {
3255
- const name = match[2];
3256
- if (name !== void 0) {
3257
- found.add(name);
3258
- }
3259
- }
3260
- return [...found].toSorted();
3261
- }
3262
3487
  function snippetAround(text, query, radius = 80) {
3263
3488
  const index = text.toLowerCase().indexOf(query.toLowerCase());
3264
3489
  if (index === -1) {
@@ -3586,7 +3811,7 @@ var Board = class _Board {
3586
3811
  }
3587
3812
  }
3588
3813
  for (const file of await listFiles(this.paths.tasks(slug))) {
3589
- const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file), z13.record(z13.string(), z13.unknown()));
3814
+ const raw = await readMarkdown(path6.join(this.paths.tasks(slug), file), z15.record(z15.string(), z15.unknown()));
3590
3815
  const legacy = raw.data["thread"];
3591
3816
  if (legacy === void 0) {
3592
3817
  continue;
@@ -3664,7 +3889,7 @@ var Board = class _Board {
3664
3889
  * turns, so it follows nothing now.
3665
3890
  */
3666
3891
  async renameInboxCursors() {
3667
- const Legacy = z13.object({ inbox: z13.string().nullable() });
3892
+ const Legacy = z15.object({ inbox: z15.string().nullable() });
3668
3893
  for (const agent2 of await this.listAgents()) {
3669
3894
  const file = this.paths.agentCursors(agent2.name);
3670
3895
  if (await exists(file)) {
@@ -3710,7 +3935,7 @@ ${charter.purpose}
3710
3935
  */
3711
3936
  async alignSeedRole(seed) {
3712
3937
  const file = this.paths.role(seed.name);
3713
- const raw = await readMarkdown(file, z13.record(z13.string(), z13.unknown()));
3938
+ const raw = await readMarkdown(file, z15.record(z15.string(), z15.unknown()));
3714
3939
  const current = RoleCharterSchema.parse(raw.data);
3715
3940
  const verbsAdded = seed.verbs.filter((verb) => !current.verbs.includes(verb));
3716
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));
@@ -4027,7 +4252,7 @@ ${charter.purpose}
4027
4252
  /** The society's norms, the one knowledge topic every turn loads. Empty until the steward writes it. */
4028
4253
  async readSocietyNorms() {
4029
4254
  const file = this.paths.societyKnowledgeFile("norms");
4030
- return await exists(file) ? (await readMarkdown(file, z13.record(z13.string(), z13.unknown()))).body : "";
4255
+ return await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
4031
4256
  }
4032
4257
  /** Knowledge topics of a project, or of the society when the project is null. */
4033
4258
  async listKnowledge(project2) {
@@ -4047,7 +4272,7 @@ ${charter.purpose}
4047
4272
  */
4048
4273
  async knowledgeAt(file, project2, topic) {
4049
4274
  const { data, body } = await readLooseMarkdown(file);
4050
- const revision = z13.number().int().min(0).safeParse(data["revision"]);
4275
+ const revision = z15.number().int().min(0).safeParse(data["revision"]);
4051
4276
  const updatedBy = NameSchema.safeParse(data["updatedBy"]);
4052
4277
  const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
4053
4278
  return {
@@ -4380,8 +4605,11 @@ ${DASHBOARD_LINE}
4380
4605
  throw new BoardError("NOT_FOUND", `runner ${name} not found`);
4381
4606
  }
4382
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;
4383
4610
  const next = RunnerSchema.parse({
4384
- ...doc.data,
4611
+ ...rest,
4612
+ ...gitIdentityMissing === void 0 ? {} : { gitIdentityMissing: [...gitIdentityMissing] },
4385
4613
  ...patch.status === void 0 ? {} : { status: patch.status },
4386
4614
  ...patch.os === void 0 ? {} : { os: patch.os },
4387
4615
  ...patch.clis === void 0 ? {} : { clis: [...patch.clis] },
@@ -4409,6 +4637,36 @@ ${DASHBOARD_LINE}
4409
4637
  return next;
4410
4638
  });
4411
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
+ }
4412
4670
  /**
4413
4671
  * Logs an operations signal as an `ops.signal` event. No channel carries it: the scheduler wakes
4414
4672
  * its readers from the event, the runner lists it in their prompts, and the interface's log shows
@@ -6243,7 +6501,7 @@ ${rationale}`}`);
6243
6501
  }
6244
6502
  async readAgentRoleBody(agent2) {
6245
6503
  const file = this.paths.agentRole(agent2);
6246
- return await exists(file) ? (await readMarkdown(file, z13.record(z13.string(), z13.unknown()))).body : "";
6504
+ return await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
6247
6505
  }
6248
6506
  /** The steps of one finished turn, as the runner handed them over when it ended. */
6249
6507
  /**
@@ -6274,6 +6532,14 @@ ${rationale}`}`);
6274
6532
  }
6275
6533
  return computeMetrics({ events, tasks, citizens, actions, activeSignals, window, now });
6276
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
+ }
6277
6543
  /** The board actions a finished turn took, from its transcript; null when it kept none. */
6278
6544
  async turnActions(agent2, turnId) {
6279
6545
  const known = this.actionCounts.get(turnId);
@@ -6643,7 +6909,7 @@ ${rationale}`}`);
6643
6909
  return { project: slug, revision: 0, body: "" };
6644
6910
  }
6645
6911
  const { data, body } = await readLooseMarkdown(file);
6646
- const revision = z13.number().int().min(0).safeParse(data["revision"]);
6912
+ const revision = z15.number().int().min(0).safeParse(data["revision"]);
6647
6913
  const updatedBy = NameSchema.safeParse(data["updatedBy"]);
6648
6914
  const updatedAt = IsoDateTimeSchema.safeParse(data["updatedAt"]);
6649
6915
  return {
@@ -6934,7 +7200,7 @@ ${seed}
6934
7200
  continue;
6935
7201
  }
6936
7202
  const file = this.paths.agentRole(agent2.name);
6937
- const body = await exists(file) ? (await readMarkdown(file, z13.record(z13.string(), z13.unknown()))).body : "";
7203
+ const body = await exists(file) ? (await readMarkdown(file, z15.record(z15.string(), z15.unknown()))).body : "";
6938
7204
  const at = body.indexOf(`
6939
7205
  ${SEED_INSTRUCTIONS_HEADING}
6940
7206
  `);
@@ -7772,7 +8038,7 @@ ${charter.purpose}
7772
8038
  id: this.newId(),
7773
8039
  ...head,
7774
8040
  ts: this.now().toISOString(),
7775
- mentions: extractMentions(body)
8041
+ mentions: postMentions(body)
7776
8042
  });
7777
8043
  const { author } = head;
7778
8044
  await writeMarkdown(this.paths.messageFile(dir, frontmatter.id, author), frontmatter, body);