@herdingchats/friday 0.1.660 → 0.1.666

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 (2) hide show
  1. package/herd.mjs +739 -652
  2. package/package.json +2 -2
package/herd.mjs CHANGED
@@ -18,7 +18,7 @@ var __export = (target, all) => {
18
18
  var define_HERD_PACKAGE_default;
19
19
  var init_define_HERD_PACKAGE = __esm({
20
20
  "<define:HERD_PACKAGE>"() {
21
- define_HERD_PACKAGE_default = { version: "0.1.660", gitHead: "21101252ff98a4dc317139a36c286b347f5f5933" };
21
+ define_HERD_PACKAGE_default = { version: "0.1.666", gitHead: "696b23f94dba08b3cf37c586ef28c4ce29fab715" };
22
22
  }
23
23
  });
24
24
 
@@ -472,8 +472,69 @@ var init_github = __esm({
472
472
  }
473
473
  });
474
474
 
475
- // ../common-chat/src/usage.ts
475
+ // ../common-chat/src/terminals.ts
476
476
  import { z as z6 } from "zod";
477
+ var terminalAccessSchema, machineTerminalsSchema, terminalModeSchema, terminalTargetSchema, terminalClosedReasonSchema, size, terminalFrameSchema, TERMINAL_DIAL_MS, TERMINAL_IDLE_MS, TERMINAL_MAX_MS, TERMINAL_PROOF_MS;
478
+ var init_terminals = __esm({
479
+ "../common-chat/src/terminals.ts"() {
480
+ "use strict";
481
+ init_define_HERD_PACKAGE();
482
+ terminalAccessSchema = z6.enum(["drive", "watch", "off"]);
483
+ machineTerminalsSchema = z6.object({ remote: terminalAccessSchema });
484
+ terminalModeSchema = z6.enum(["watch", "drive"]);
485
+ terminalTargetSchema = z6.discriminatedUnion("kind", [
486
+ z6.object({ kind: z6.literal("conversation"), conversationId: z6.string().min(1) }),
487
+ z6.object({ kind: z6.literal("activation"), agent: z6.string().min(1) })
488
+ ]);
489
+ terminalClosedReasonSchema = z6.enum([
490
+ // The page closed it, or the person let it go.
491
+ "closed",
492
+ // The machine never dialed, or its socket dropped.
493
+ "expired",
494
+ "machine_gone",
495
+ // Its limits: no input for a while, too long in all, or the browser's sign-in is due a check.
496
+ "idle",
497
+ "too_long",
498
+ "reauthorize",
499
+ // A newer session took its place on the machine.
500
+ "superseded",
501
+ // The machine wouldn't open it, saying why in `detail`.
502
+ "refused",
503
+ // The terminal itself exited.
504
+ "exited"
505
+ ]);
506
+ size = {
507
+ cols: z6.number().int().min(10).max(1e3),
508
+ rows: z6.number().int().min(5).max(1e3)
509
+ };
510
+ terminalFrameSchema = z6.discriminatedUnion("type", [
511
+ z6.object({ type: z6.literal("snapshot"), data: z6.string() }),
512
+ z6.object({ type: z6.literal("data"), data: z6.string() }),
513
+ z6.object({ type: z6.literal("exit"), exitCode: z6.number().int().nullable() }),
514
+ z6.object({ type: z6.literal("mode"), mode: terminalModeSchema }),
515
+ z6.object({ type: z6.literal("input"), data: z6.string().max(64 * 1024) }),
516
+ z6.object({ type: z6.literal("resize"), ...size }),
517
+ z6.object({ type: z6.literal("drive") }),
518
+ z6.object({ type: z6.literal("watch") }),
519
+ z6.object({
520
+ type: z6.literal("closed"),
521
+ reason: terminalClosedReasonSchema,
522
+ detail: z6.string().max(500).optional()
523
+ }),
524
+ z6.object({
525
+ type: z6.literal("refused"),
526
+ code: z6.enum(["confirmation_needed", "watch_only", "not_driving"])
527
+ })
528
+ ]);
529
+ TERMINAL_DIAL_MS = 60 * 1e3;
530
+ TERMINAL_IDLE_MS = 15 * 60 * 1e3;
531
+ TERMINAL_MAX_MS = 2 * 60 * 60 * 1e3;
532
+ TERMINAL_PROOF_MS = 60 * 60 * 1e3;
533
+ }
534
+ });
535
+
536
+ // ../common-chat/src/usage.ts
537
+ import { z as z7 } from "zod";
477
538
  function currentUsage(usage, now) {
478
539
  if (!usage) return void 0;
479
540
  const fresh = (window) => window && window.resetsAt > now ? window : void 0;
@@ -491,38 +552,38 @@ var init_usage = __esm({
491
552
  "../common-chat/src/usage.ts"() {
492
553
  "use strict";
493
554
  init_define_HERD_PACKAGE();
494
- usageWindowSchema = z6.object({
495
- usedPercentage: z6.number().min(0).max(100),
496
- resetsAt: z6.number().int().nonnegative()
555
+ usageWindowSchema = z7.object({
556
+ usedPercentage: z7.number().min(0).max(100),
557
+ resetsAt: z7.number().int().nonnegative()
497
558
  });
498
559
  USAGE_AGENTS = {
499
560
  "claude-code": "Claude",
500
561
  codex: "Codex",
501
562
  agy: "Antigravity"
502
563
  };
503
- usageSchema = z6.object({
564
+ usageSchema = z7.object({
504
565
  fiveHour: usageWindowSchema.optional(),
505
566
  sevenDay: usageWindowSchema.optional(),
506
- agent: z6.enum(["claude-code", "codex", "agy"]).optional()
567
+ agent: z7.enum(["claude-code", "codex", "agy"]).optional()
507
568
  }).refine((usage) => usage.fiveHour || usage.sevenDay, "Usage needs at least one window");
508
569
  MAX_ACTIVITY_LENGTH = 150;
509
- activityTextSchema = z6.string().trim().min(1).max(MAX_ACTIVITY_LENGTH).regex(/^[^\r\n]+$/);
570
+ activityTextSchema = z7.string().trim().min(1).max(MAX_ACTIVITY_LENGTH).regex(/^[^\r\n]+$/);
510
571
  MAX_TITLE_LENGTH = 40;
511
- titleSchema = z6.string().trim().min(1).max(MAX_TITLE_LENGTH).regex(/^[^\r\n]+$/);
512
- listedWindowSchema = z6.union([
572
+ titleSchema = z7.string().trim().min(1).max(MAX_TITLE_LENGTH).regex(/^[^\r\n]+$/);
573
+ listedWindowSchema = z7.union([
513
574
  usageWindowSchema,
514
- z6.object({ reset: z6.literal(true), resetsAt: z6.number().int().nonnegative() })
575
+ z7.object({ reset: z7.literal(true), resetsAt: z7.number().int().nonnegative() })
515
576
  ]);
516
- listedUsageSchema = z6.object({
577
+ listedUsageSchema = z7.object({
517
578
  fiveHour: listedWindowSchema.optional(),
518
579
  sevenDay: listedWindowSchema.optional(),
519
- agent: z6.enum(["claude-code", "codex", "agy"]).optional()
580
+ agent: z7.enum(["claude-code", "codex", "agy"]).optional()
520
581
  });
521
582
  }
522
583
  });
523
584
 
524
585
  // ../common-chat/src/workers.ts
525
- import { z as z7 } from "zod";
586
+ import { z as z8 } from "zod";
526
587
  function agentShortName(cli) {
527
588
  return AGENTS[cli]?.short ?? cli;
528
589
  }
@@ -558,11 +619,11 @@ var init_workers = __esm({
558
619
  "xcode",
559
620
  "image_generation"
560
621
  ];
561
- capabilitySchema = z7.enum(CAPABILITIES);
622
+ capabilitySchema = z8.enum(CAPABILITIES);
562
623
  PLATFORMS = ["macos", "linux", "windows"];
563
- platformSchema = z7.enum(PLATFORMS);
624
+ platformSchema = z8.enum(PLATFORMS);
564
625
  TOOLS = ["xcode", "gpu"];
565
- toolSchema = z7.enum(TOOLS);
626
+ toolSchema = z8.enum(TOOLS);
566
627
  CAPABILITY_WORDING = {
567
628
  macos: "a Mac running macOS",
568
629
  linux: "a Linux computer",
@@ -580,51 +641,51 @@ var init_workers = __esm({
580
641
  PHRASE_MAX = 100;
581
642
  PHRASES_MAX = 10;
582
643
  ABOUT_MAX = 500;
583
- phrase = z7.string().trim().min(1).max(PHRASE_MAX, `at most ${PHRASE_MAX} characters`);
584
- phrases = z7.array(phrase).max(PHRASES_MAX, `at most ${PHRASES_MAX} phrases`);
644
+ phrase = z8.string().trim().min(1).max(PHRASE_MAX, `at most ${PHRASE_MAX} characters`);
645
+ phrases = z8.array(phrase).max(PHRASES_MAX, `at most ${PHRASES_MAX} phrases`);
585
646
  SHARES = ["off", "little", "some", "lot"];
586
- shareSchema = z7.enum(SHARES);
647
+ shareSchema = z8.enum(SHARES);
587
648
  SHARE_LABELS = {
588
649
  off: "off",
589
650
  little: "a little",
590
651
  some: "some",
591
652
  lot: "a lot"
592
653
  };
593
- harnessConfigSchema = z7.object({
654
+ harnessConfigSchema = z8.object({
594
655
  share: shareSchema.optional(),
595
656
  /** Read as `share: "off"` when false, from files written before shares. */
596
- enabled: z7.boolean().optional(),
657
+ enabled: z8.boolean().optional(),
597
658
  only: phrases.optional(),
598
659
  great: phrases.optional(),
599
660
  good: phrases.optional(),
600
661
  okay: phrases.optional(),
601
662
  cant: phrases.optional(),
602
663
  /** false starts the harness's profile empty, rather than from herd's defaults. */
603
- defaults: z7.boolean().optional(),
664
+ defaults: z8.boolean().optional(),
604
665
  /** Read as `great`, from files written before profiles. */
605
666
  prefer: phrases.optional(),
606
667
  /** Read as `cant`, from files written before profiles. */
607
668
  avoid: phrases.optional(),
608
- priority: z7.number().int().min(-100).max(100).optional()
669
+ priority: z8.number().int().min(-100).max(100).optional()
609
670
  }).strict();
610
671
  BUILDS_MAX = 4;
611
- buildsSettingSchema = z7.union([
612
- z7.literal(true),
613
- z7.object({ max: z7.number().int().min(1).max(BUILDS_MAX) }).strict()
672
+ buildsSettingSchema = z8.union([
673
+ z8.literal(true),
674
+ z8.object({ max: z8.number().int().min(1).max(BUILDS_MAX) }).strict()
614
675
  ]);
615
676
  CONFIG_REPOS_MAX = 50;
616
- configRepoSchema = z7.object({
617
- remote: z7.string().trim().min(1).max(300),
618
- about: z7.string().trim().max(PHRASE_MAX, `at most ${PHRASE_MAX} characters`).optional()
677
+ configRepoSchema = z8.object({
678
+ remote: z8.string().trim().min(1).max(300),
679
+ about: z8.string().trim().max(PHRASE_MAX, `at most ${PHRASE_MAX} characters`).optional()
619
680
  }).strict();
620
- herdConfigSchema = z7.object({
621
- about: z7.string().trim().max(ABOUT_MAX, `at most ${ABOUT_MAX} characters`).optional(),
681
+ herdConfigSchema = z8.object({
682
+ about: z8.string().trim().max(ABOUT_MAX, `at most ${ABOUT_MAX} characters`).optional(),
622
683
  cant: phrases.optional(),
623
684
  /** Read as `cant`, from files written before profiles. */
624
685
  avoid: phrases.optional(),
625
- harnesses: z7.record(z7.string().regex(/^[a-z][a-z0-9-]*$/), harnessConfigSchema).optional(),
686
+ harnesses: z8.record(z8.string().regex(/^[a-z][a-z0-9-]*$/), harnessConfigSchema).optional(),
626
687
  builds: buildsSettingSchema.optional(),
627
- repos: z7.array(configRepoSchema).max(CONFIG_REPOS_MAX, `at most ${CONFIG_REPOS_MAX} repos`).optional()
688
+ repos: z8.array(configRepoSchema).max(CONFIG_REPOS_MAX, `at most ${CONFIG_REPOS_MAX} repos`).optional()
628
689
  }).strict();
629
690
  HERD_CONFIG_TYPE = `type HerdConfig = {
630
691
  /** What this machine is for, in plain words. At most ${ABOUT_MAX} characters. */
@@ -675,54 +736,55 @@ export default {
675
736
  harnesses: { claude: { great: ["code review"] }, codex: { cant: ["the billing service"] } },
676
737
  } satisfies HerdConfig;`;
677
738
  PROFILE_LEVELS = ["great", "good", "okay", "cant"];
678
- profileEntrySchema = z7.object({
679
- statement: z7.string().min(1),
680
- level: z7.enum(PROFILE_LEVELS),
681
- source: z7.enum(["default", "owner"])
682
- });
683
- workerSchema = z7.object({
684
- key: z7.string().min(1),
685
- name: z7.string().min(1),
686
- machineId: z7.string().min(1),
687
- machineName: z7.string().min(1),
688
- agent: z7.string().min(1),
689
- capabilities: z7.array(capabilitySchema),
690
- about: z7.string().optional(),
691
- only: z7.array(z7.string()),
739
+ profileEntrySchema = z8.object({
740
+ statement: z8.string().min(1),
741
+ level: z8.enum(PROFILE_LEVELS),
742
+ source: z8.enum(["default", "owner"])
743
+ });
744
+ workerSchema = z8.object({
745
+ key: z8.string().min(1),
746
+ name: z8.string().min(1),
747
+ machineId: z8.string().min(1),
748
+ machineName: z8.string().min(1),
749
+ agent: z8.string().min(1),
750
+ capabilities: z8.array(capabilitySchema),
751
+ about: z8.string().optional(),
752
+ only: z8.array(z8.string()),
692
753
  /** What it's great, good and okay at, and can't do: its agent's defaults with its owner's word. */
693
- profile: z7.array(profileEntrySchema),
694
- priority: z7.number().int(),
754
+ profile: z8.array(profileEntrySchema),
755
+ priority: z8.number().int(),
695
756
  /** How much of its agent its owner has. Servers from before shares send none, which is "some". */
696
757
  share: shareSchema.default("some"),
697
- enabled: z7.boolean(),
758
+ enabled: z8.boolean(),
698
759
  /** Whether its agent checked in from herd's terminal on this version, so it's offered work. */
699
- activated: z7.boolean(),
760
+ activated: z8.boolean(),
700
761
  activation: agentActivationSchema.optional(),
701
- online: z7.boolean(),
762
+ online: z8.boolean(),
702
763
  /** A folder its machine works in that isn't there, so it's offered no work until it is. */
703
- folderUnavailable: z7.object({ path: z7.string().min(1), target: z7.string().min(1).optional() }).optional(),
764
+ folderUnavailable: z8.object({ path: z8.string().min(1), target: z8.string().min(1).optional() }).optional(),
704
765
  // Its machine's repos, each marked whether herd has cloned it there. Older daemons send no `cloned`.
705
- repos: z7.array(
706
- z7.object({ name: z7.string(), remote: z7.string(), cloned: z7.boolean().optional() })
766
+ repos: z8.array(
767
+ z8.object({ name: z8.string(), remote: z8.string(), cloned: z8.boolean().optional() })
707
768
  ),
708
- machineCreatedAt: z7.number().int().nonnegative()
769
+ machineCreatedAt: z8.number().int().nonnegative()
709
770
  });
710
771
  }
711
772
  });
712
773
 
713
774
  // ../common-chat/src/machines.ts
714
- import { z as z8 } from "zod";
775
+ import { z as z9 } from "zod";
715
776
  var nonEmpty4, time2, terminalStateSchema, agentStatusSchema, machineRepoSchema, isCloned, machineCliSchema, folderUnavailableSchema, machineRegistrationSchema, machineSchema, machinePresenceSchema, worktreeSchema, MAX_REPO_HINTS, repoHintSchema, terminalSchema, offerSchema, offerAnswerSchema, dispatchFrameSchema, machineMessageSchema;
716
777
  var init_machines = __esm({
717
778
  "../common-chat/src/machines.ts"() {
718
779
  "use strict";
719
780
  init_define_HERD_PACKAGE();
720
781
  init_activation();
782
+ init_terminals();
721
783
  init_usage();
722
784
  init_workers();
723
- nonEmpty4 = z8.string().min(1);
724
- time2 = z8.number().int().nonnegative();
725
- terminalStateSchema = z8.enum([
785
+ nonEmpty4 = z9.string().min(1);
786
+ time2 = z9.number().int().nonnegative();
787
+ terminalStateSchema = z9.enum([
726
788
  "working",
727
789
  "idle",
728
790
  "waiting_on_someone",
@@ -730,64 +792,66 @@ var init_machines = __esm({
730
792
  "signed_out",
731
793
  "unknown"
732
794
  ]);
733
- agentStatusSchema = z8.enum(["working", "idle", "waiting_on_someone", "exited"]);
734
- machineRepoSchema = z8.object({
795
+ agentStatusSchema = z9.enum(["working", "idle", "waiting_on_someone", "exited"]);
796
+ machineRepoSchema = z9.object({
735
797
  name: nonEmpty4,
736
798
  remote: nonEmpty4,
737
- cloned: z8.boolean().optional()
799
+ cloned: z9.boolean().optional()
738
800
  });
739
801
  isCloned = (repo) => repo.cloned !== false;
740
- machineCliSchema = z8.object({
802
+ machineCliSchema = z9.object({
741
803
  name: nonEmpty4,
742
804
  version: nonEmpty4,
743
- runnable: z8.boolean().optional(),
744
- capabilities: z8.array(capabilitySchema).optional(),
805
+ runnable: z9.boolean().optional(),
806
+ capabilities: z9.array(capabilitySchema).optional(),
745
807
  activation: agentActivationSchema.optional()
746
808
  });
747
- folderUnavailableSchema = z8.object({
748
- path: z8.string().min(1).max(1e3),
749
- target: z8.string().min(1).max(1e3).optional()
809
+ folderUnavailableSchema = z9.object({
810
+ path: z9.string().min(1).max(1e3),
811
+ target: z9.string().min(1).max(1e3).optional()
750
812
  });
751
- machineRegistrationSchema = z8.object({
813
+ machineRegistrationSchema = z9.object({
752
814
  id: nonEmpty4,
753
815
  name: nonEmpty4,
754
- repos: z8.array(machineRepoSchema),
755
- clis: z8.array(machineCliSchema),
816
+ repos: z9.array(machineRepoSchema),
817
+ clis: z9.array(machineCliSchema),
756
818
  // The platform the agent actually runs on, and tools from herd's fixed list.
757
819
  platform: platformSchema.optional(),
758
- tools: z8.array(toolSchema).optional(),
820
+ tools: z9.array(toolSchema).optional(),
759
821
  // The machine's validated `herd.config.ts`, and why the file on disk didn't load if it didn't.
760
822
  config: herdConfigSchema.optional(),
761
- configError: z8.string().max(1e3).optional(),
823
+ configError: z9.string().max(1e3).optional(),
762
824
  // Whether its GitHub CLI is signed in, and as whom.
763
825
  gh: gitHubCliSchema.optional(),
764
826
  // A folder it works in that isn't there, while it takes no work.
765
827
  folderUnavailable: folderUnavailableSchema.optional(),
766
828
  // The daemon's own package version, or `dev` from a checkout. Daemons from before send none,
767
829
  // which reads as older than any that does.
768
- herdVersion: z8.string().min(1).max(50).optional()
830
+ herdVersion: z9.string().min(1).max(50).optional(),
831
+ // What the web may do with its terminals. A daemon from before terminal sessions doesn't say.
832
+ terminals: machineTerminalsSchema.optional()
769
833
  });
770
834
  machineSchema = machineRegistrationSchema.extend({
771
835
  ownerId: nonEmpty4,
772
- online: z8.boolean(),
836
+ online: z9.boolean(),
773
837
  lastSeenAt: time2,
774
838
  createdAt: time2
775
839
  });
776
- machinePresenceSchema = z8.object({ name: nonEmpty4, online: z8.boolean() });
777
- worktreeSchema = z8.object({ repo: nonEmpty4, branch: nonEmpty4 });
840
+ machinePresenceSchema = z9.object({ name: nonEmpty4, online: z9.boolean() });
841
+ worktreeSchema = z9.object({ repo: nonEmpty4, branch: nonEmpty4 });
778
842
  MAX_REPO_HINTS = 10;
779
- repoHintSchema = z8.object({
843
+ repoHintSchema = z9.object({
780
844
  remote: nonEmpty4,
781
845
  branch: nonEmpty4.optional(),
782
846
  folder: nonEmpty4.optional()
783
847
  });
784
- terminalSchema = z8.object({
848
+ terminalSchema = z9.object({
785
849
  id: nonEmpty4,
786
850
  name: nonEmpty4,
787
851
  machineId: nonEmpty4,
788
852
  conversationId: nonEmpty4,
789
853
  // The lead terminal receives the conversation's notices. Others are started with `herd run`.
790
- lead: z8.boolean(),
854
+ lead: z9.boolean(),
791
855
  // Only for a conversation from before folders, which works in one repo's worktree.
792
856
  worktree: worktreeSchema.optional(),
793
857
  // The program the screen reader recognized, such as `claude-code` or `shell`, when it knows.
@@ -795,7 +859,7 @@ var init_machines = __esm({
795
859
  state: terminalStateSchema,
796
860
  updatedAt: time2
797
861
  });
798
- offerSchema = z8.object({
862
+ offerSchema = z9.object({
799
863
  id: nonEmpty4,
800
864
  conversationId: nonEmpty4,
801
865
  machineId: nonEmpty4,
@@ -803,33 +867,41 @@ var init_machines = __esm({
803
867
  expiresAt: time2,
804
868
  // The repos the work hints, which the machine adds to the conversation's folder before the agent
805
869
  // starts. Hints never decide which machines are offered the work.
806
- repos: z8.array(repoHintSchema).max(MAX_REPO_HINTS).optional(),
870
+ repos: z9.array(repoHintSchema).max(MAX_REPO_HINTS).optional(),
807
871
  // The first hint's remote, for daemons from before `repos`, which work in that one repo.
808
872
  repo: nonEmpty4.optional(),
809
873
  // The agent CLI of the worker it's offered to. Without one, it's Claude Code.
810
874
  agent: nonEmpty4.optional(),
811
875
  // A handed-off conversation restores each of its repos from its branch, if the remote has it.
812
- handoff: z8.boolean().optional()
876
+ handoff: z9.boolean().optional()
813
877
  });
814
- offerAnswerSchema = z8.discriminatedUnion("answer", [
815
- z8.object({ answer: z8.literal("accept") }),
816
- z8.object({ answer: z8.literal("refuse"), reason: nonEmpty4 })
878
+ offerAnswerSchema = z9.discriminatedUnion("answer", [
879
+ z9.object({ answer: z9.literal("accept") }),
880
+ z9.object({ answer: z9.literal("refuse"), reason: nonEmpty4 })
817
881
  ]);
818
- dispatchFrameSchema = z8.discriminatedUnion("type", [
819
- z8.object({ type: z8.literal("offer"), offer: offerSchema }),
820
- z8.object({
821
- type: z8.literal("message"),
882
+ dispatchFrameSchema = z9.discriminatedUnion("type", [
883
+ z9.object({ type: z9.literal("offer"), offer: offerSchema }),
884
+ z9.object({
885
+ type: z9.literal("message"),
822
886
  conversationId: nonEmpty4,
823
- delivery: z8.enum(["interrupt", "defer"])
887
+ delivery: z9.enum(["interrupt", "defer"])
824
888
  }),
825
- z8.object({ type: z8.literal("reconnect") }),
889
+ z9.object({ type: z9.literal("reconnect") }),
826
890
  // Its owner asked for a sign-in on this machine, which the daemon runs and reports on.
827
- z8.object({ type: z8.literal("sign_in"), signInId: nonEmpty4, tool: signInToolSchema })
891
+ z9.object({ type: z9.literal("sign_in"), signInId: nonEmpty4, tool: signInToolSchema }),
892
+ // Its owner opened a terminal session from the web, which the daemon dials. An older daemon
893
+ // ignores it, and the session expires.
894
+ z9.object({
895
+ type: z9.literal("terminal_open"),
896
+ sessionId: nonEmpty4,
897
+ target: terminalTargetSchema,
898
+ mode: terminalModeSchema
899
+ })
828
900
  ]);
829
- machineMessageSchema = z8.discriminatedUnion("type", [
830
- z8.object({ type: z8.literal("ack"), conversationId: nonEmpty4 }),
831
- z8.object({
832
- type: z8.literal("usage"),
901
+ machineMessageSchema = z9.discriminatedUnion("type", [
902
+ z9.object({ type: z9.literal("ack"), conversationId: nonEmpty4 }),
903
+ z9.object({
904
+ type: z9.literal("usage"),
833
905
  /** The worker's agent on this machine, such as `claude-code`. */
834
906
  agent: nonEmpty4,
835
907
  usage: usageSchema,
@@ -840,39 +912,39 @@ var init_machines = __esm({
840
912
  });
841
913
 
842
914
  // ../common-chat/src/prompts.ts
843
- import { z as z9 } from "zod";
915
+ import { z as z10 } from "zod";
844
916
  var nonEmpty5, id, promptKindSchema, promptOptionSchema, promptQuestionSchema, promptRequestSchema, promptOutcomeSchema;
845
917
  var init_prompts = __esm({
846
918
  "../common-chat/src/prompts.ts"() {
847
919
  "use strict";
848
920
  init_define_HERD_PACKAGE();
849
- nonEmpty5 = z9.string().min(1);
850
- id = z9.string().regex(/^[A-Za-z0-9_-]{1,40}$/).describe("Short, so it fits in a button's value and action ID");
851
- promptKindSchema = z9.enum(["permission", "question", "plan", "automation"]);
852
- promptOptionSchema = z9.object({
921
+ nonEmpty5 = z10.string().min(1);
922
+ id = z10.string().regex(/^[A-Za-z0-9_-]{1,40}$/).describe("Short, so it fits in a button's value and action ID");
923
+ promptKindSchema = z10.enum(["permission", "question", "plan", "automation"]);
924
+ promptOptionSchema = z10.object({
853
925
  id,
854
- label: z9.string().trim().min(1).max(75),
855
- description: z9.string().max(200).optional(),
926
+ label: z10.string().trim().min(1).max(75),
927
+ description: z10.string().max(200).optional(),
856
928
  // How a button for it is drawn: `primary` to go ahead, `danger` to refuse.
857
- style: z9.enum(["primary", "danger"]).optional()
929
+ style: z10.enum(["primary", "danger"]).optional()
858
930
  });
859
- promptQuestionSchema = z9.object({
931
+ promptQuestionSchema = z10.object({
860
932
  id,
861
- text: z9.string().trim().min(1).max(300),
862
- options: z9.array(promptOptionSchema).min(1).max(10)
933
+ text: z10.string().trim().min(1).max(300),
934
+ options: z10.array(promptOptionSchema).min(1).max(10)
863
935
  });
864
- promptRequestSchema = z9.object({
936
+ promptRequestSchema = z10.object({
865
937
  kind: promptKindSchema,
866
- title: z9.string().trim().min(1).max(150),
867
- detail: z9.string().max(2800).optional(),
868
- questions: z9.array(promptQuestionSchema).min(1).max(4)
938
+ title: z10.string().trim().min(1).max(150),
939
+ detail: z10.string().max(2800).optional(),
940
+ questions: z10.array(promptQuestionSchema).min(1).max(4)
869
941
  });
870
- promptOutcomeSchema = z9.enum(["answered", "cancelled"]);
942
+ promptOutcomeSchema = z10.enum(["answered", "cancelled"]);
871
943
  }
872
944
  });
873
945
 
874
946
  // ../common-chat/src/pull-requests.ts
875
- import { z as z10 } from "zod";
947
+ import { z as z11 } from "zod";
876
948
  function statusOfPhase(phase) {
877
949
  return phase === "merged" ? "done" : phase === "closed" ? "closed" : "open";
878
950
  }
@@ -911,8 +983,8 @@ var init_pull_requests = __esm({
911
983
  "../common-chat/src/pull-requests.ts"() {
912
984
  "use strict";
913
985
  init_define_HERD_PACKAGE();
914
- time3 = z10.number().int().nonnegative();
915
- pullRequestPhaseSchema = z10.enum([
986
+ time3 = z11.number().int().nonnegative();
987
+ pullRequestPhaseSchema = z11.enum([
916
988
  "draft",
917
989
  "checks_running",
918
990
  "checks_failed",
@@ -923,7 +995,7 @@ var init_pull_requests = __esm({
923
995
  "merged",
924
996
  "closed"
925
997
  ]);
926
- pullRequestMoveSchema = z10.enum(["you", "agent", "others", "nobody"]);
998
+ pullRequestMoveSchema = z11.enum(["you", "agent", "others", "nobody"]);
927
999
  PHASE_LABELS = {
928
1000
  draft: "draft",
929
1001
  checks_running: "checks running",
@@ -935,22 +1007,22 @@ var init_pull_requests = __esm({
935
1007
  merged: "merged",
936
1008
  closed: "closed"
937
1009
  };
938
- leadChangeSchema = z10.object({
1010
+ leadChangeSchema = z11.object({
939
1011
  /** Its repo and number, such as `api#104`, or "a pull request" when hidden. */
940
- label: z10.string().min(1),
1012
+ label: z11.string().min(1),
941
1013
  phase: pullRequestPhaseSchema,
942
1014
  move: pullRequestMoveSchema,
943
1015
  changedAt: time3,
944
1016
  /** How many of the conversation's other open pull requests are also the person's move. */
945
- moreForYou: z10.number().int().nonnegative(),
1017
+ moreForYou: z11.number().int().nonnegative(),
946
1018
  /** Absent when hidden. */
947
- url: z10.string().optional()
1019
+ url: z11.string().optional()
948
1020
  });
949
1021
  }
950
1022
  });
951
1023
 
952
1024
  // ../common-chat/src/work-objects.ts
953
- import { z as z11 } from "zod";
1025
+ import { z as z12 } from "zod";
954
1026
  function workLine(work) {
955
1027
  const parts = [
956
1028
  work.phase ? `${work.kind} ${PHASE_LABELS[work.phase]}` : `${work.kind} ${work.status}`
@@ -965,21 +1037,21 @@ var init_work_objects = __esm({
965
1037
  "use strict";
966
1038
  init_define_HERD_PACKAGE();
967
1039
  init_pull_requests();
968
- time4 = z11.number().int().nonnegative();
969
- workKindSchema = z11.enum(["change", "ticket", "deploy", "document", "other"]);
970
- workStatusSchema = z11.enum(["open", "done", "closed"]);
971
- workSourceSchema = z11.enum(["agent", "provider"]);
1040
+ time4 = z12.number().int().nonnegative();
1041
+ workKindSchema = z12.enum(["change", "ticket", "deploy", "document", "other"]);
1042
+ workStatusSchema = z12.enum(["open", "done", "closed"]);
1043
+ workSourceSchema = z12.enum(["agent", "provider"]);
972
1044
  MAX_WORK_TITLE = 200;
973
1045
  MAX_WORK_DETAIL = 100;
974
1046
  MAX_WORK_URL = 2048;
975
- workObjectSchema = z11.object({
976
- url: z11.string().min(1).max(MAX_WORK_URL),
1047
+ workObjectSchema = z12.object({
1048
+ url: z12.string().min(1).max(MAX_WORK_URL),
977
1049
  kind: workKindSchema,
978
- title: z11.string().min(1).max(MAX_WORK_TITLE),
1050
+ title: z12.string().min(1).max(MAX_WORK_TITLE),
979
1051
  status: workStatusSchema,
980
- detail: z11.string().max(MAX_WORK_DETAIL).nullable(),
1052
+ detail: z12.string().max(MAX_WORK_DETAIL).nullable(),
981
1053
  /** Whether the conversation made it, rather than only being about it. */
982
- made: z11.boolean(),
1054
+ made: z12.boolean(),
983
1055
  changedAt: time4,
984
1056
  changedBy: workSourceSchema,
985
1057
  createdAt: time4,
@@ -987,21 +1059,21 @@ var init_work_objects = __esm({
987
1059
  phase: pullRequestPhaseSchema.nullable().optional(),
988
1060
  move: pullRequestMoveSchema.nullable().optional(),
989
1061
  /** The delegate holding it, when it's read from an ancestor. */
990
- conversationId: z11.string().min(1).optional()
1062
+ conversationId: z12.string().min(1).optional()
991
1063
  });
992
- workChangeSchema = z11.object({
993
- url: z11.string().trim().min(1).max(MAX_WORK_URL),
1064
+ workChangeSchema = z12.object({
1065
+ url: z12.string().trim().min(1).max(MAX_WORK_URL),
994
1066
  kind: workKindSchema.optional(),
995
- title: z11.string().trim().min(1).max(2e3).optional(),
1067
+ title: z12.string().trim().min(1).max(2e3).optional(),
996
1068
  status: workStatusSchema.optional(),
997
- detail: z11.string().trim().max(2e3).nullable().optional(),
998
- made: z11.boolean().optional(),
1069
+ detail: z12.string().trim().max(2e3).nullable().optional(),
1070
+ made: z12.boolean().optional(),
999
1071
  /** Only for a `change`. Its status then follows it. */
1000
1072
  phase: pullRequestPhaseSchema.optional(),
1001
1073
  /** Set by a provider, which knows who was asked to review. Otherwise it follows the phase. */
1002
1074
  move: pullRequestMoveSchema.optional()
1003
1075
  });
1004
- workFieldSchema = z11.enum([
1076
+ workFieldSchema = z12.enum([
1005
1077
  "kind",
1006
1078
  "title",
1007
1079
  "status",
@@ -1010,27 +1082,27 @@ var init_work_objects = __esm({
1010
1082
  "phase",
1011
1083
  "move"
1012
1084
  ]);
1013
- workObjectSummarySchema = z11.object({
1085
+ workObjectSummarySchema = z12.object({
1014
1086
  kind: workKindSchema,
1015
1087
  status: workStatusSchema,
1016
- made: z11.boolean(),
1088
+ made: z12.boolean(),
1017
1089
  changedAt: time4,
1018
1090
  /** A pull request's phase and move, which say nothing of its content, so they're never hidden. */
1019
1091
  phase: pullRequestPhaseSchema.nullable().optional(),
1020
1092
  move: pullRequestMoveSchema.nullable().optional(),
1021
- url: z11.string().optional(),
1022
- title: z11.string().optional(),
1023
- detail: z11.string().nullable().optional(),
1093
+ url: z12.string().optional(),
1094
+ title: z12.string().optional(),
1095
+ detail: z12.string().nullable().optional(),
1024
1096
  /** The delegate holding it, when it isn't the item's own conversation. */
1025
- conversationId: z11.string().min(1).optional()
1097
+ conversationId: z12.string().min(1).optional()
1026
1098
  });
1027
1099
  }
1028
1100
  });
1029
1101
 
1030
1102
  // ../common-chat/src/events.ts
1031
- import { z as z12 } from "zod";
1103
+ import { z as z13 } from "zod";
1032
1104
  function event(type, payload) {
1033
- return z12.object({ ...eventBase, type: z12.literal(type), payload: z12.object(payload) });
1105
+ return z13.object({ ...eventBase, type: z13.literal(type), payload: z13.object(payload) });
1034
1106
  }
1035
1107
  var routeSchema, deliveryModeSchema, eventSourceSchema, nonEmpty6, actorSchema, eventBase, entryIds, routingRecordSchema, threadChangeSchema, conversationEventSchema, conversationVisibilitySchema, conversationStatusSchema, conversationSummarySchema, placementSchema, treeSummarySchema, conversationSnapshotSchema, liveFrameSchema, adapterCapabilitiesSchema;
1036
1108
  var init_events = __esm({
@@ -1045,141 +1117,141 @@ var init_events = __esm({
1045
1117
  init_usage();
1046
1118
  init_work_objects();
1047
1119
  init_workers();
1048
- routeSchema = z12.enum(["direct", "mention", "joined"]);
1049
- deliveryModeSchema = z12.enum(["interrupt", "defer"]);
1050
- eventSourceSchema = z12.enum(["slack", "discord", "web", "api", "cli", "mcp", "system"]);
1051
- nonEmpty6 = z12.string().min(1);
1052
- actorSchema = z12.discriminatedUnion("kind", [
1120
+ routeSchema = z13.enum(["direct", "mention", "joined"]);
1121
+ deliveryModeSchema = z13.enum(["interrupt", "defer"]);
1122
+ eventSourceSchema = z13.enum(["slack", "discord", "web", "api", "cli", "mcp", "system"]);
1123
+ nonEmpty6 = z13.string().min(1);
1124
+ actorSchema = z13.discriminatedUnion("kind", [
1053
1125
  // Someone signed in to this system. `id` is the stable person identifier.
1054
- z12.object({ kind: z12.literal("person"), id: nonEmpty6, name: nonEmpty6 }),
1126
+ z13.object({ kind: z13.literal("person"), id: nonEmpty6, name: nonEmpty6 }),
1055
1127
  // An account on a platform, which may or may not be linked to a person.
1056
- z12.object({
1057
- kind: z12.literal("account"),
1128
+ z13.object({
1129
+ kind: z13.literal("account"),
1058
1130
  provider: nonEmpty6,
1059
1131
  tenant: nonEmpty6,
1060
1132
  subject: nonEmpty6,
1061
- name: z12.string().optional(),
1062
- isBot: z12.boolean()
1133
+ name: z13.string().optional(),
1134
+ isBot: z13.boolean()
1063
1135
  }),
1064
- z12.object({ kind: z12.literal("system") })
1136
+ z13.object({ kind: z13.literal("system") })
1065
1137
  ]);
1066
1138
  eventBase = {
1067
- seq: z12.number().int().positive(),
1139
+ seq: z13.number().int().positive(),
1068
1140
  source: eventSourceSchema,
1069
1141
  actor: actorSchema,
1070
- createdAt: z12.number().int().nonnegative()
1142
+ createdAt: z13.number().int().nonnegative()
1071
1143
  };
1072
- entryIds = z12.array(nonEmpty6);
1073
- routingRecordSchema = z12.object({
1074
- eligible: z12.array(z12.object({ key: nonEmpty6, name: nonEmpty6 })),
1075
- questions: z12.array(
1076
- z12.object({
1144
+ entryIds = z13.array(nonEmpty6);
1145
+ routingRecordSchema = z13.object({
1146
+ eligible: z13.array(z13.object({ key: nonEmpty6, name: nonEmpty6 })),
1147
+ questions: z13.array(
1148
+ z13.object({
1077
1149
  id: nonEmpty6,
1078
1150
  question: nonEmpty6,
1079
- probability: z12.number().min(0).max(1).nullable()
1151
+ probability: z13.number().min(0).max(1).nullable()
1080
1152
  })
1081
1153
  ),
1082
1154
  model: nonEmpty6.optional(),
1083
1155
  // Why the model's answers weren't used, when they weren't.
1084
- fallback: z12.string().optional(),
1085
- removed: z12.array(z12.object({ key: nonEmpty6, name: nonEmpty6, rule: nonEmpty6 })),
1086
- order: z12.array(nonEmpty6),
1156
+ fallback: z13.string().optional(),
1157
+ removed: z13.array(z13.object({ key: nonEmpty6, name: nonEmpty6, rule: nonEmpty6 })),
1158
+ order: z13.array(nonEmpty6),
1087
1159
  // Each ordered worker's fit, and the profile statement and level that gave it, when the model
1088
1160
  // answered.
1089
- fits: z12.array(
1090
- z12.object({
1161
+ fits: z13.array(
1162
+ z13.object({
1091
1163
  key: nonEmpty6,
1092
- fit: z12.number().min(0).max(1),
1093
- statement: z12.string().optional(),
1094
- level: z12.enum(["great", "good", "okay"]).optional()
1164
+ fit: z13.number().min(0).max(1),
1165
+ statement: z13.string().optional(),
1166
+ level: z13.enum(["great", "good", "okay"]).optional()
1095
1167
  })
1096
1168
  ).optional(),
1097
1169
  // Profile statements left out to keep within the most questions one call asks.
1098
- dropped: z12.array(z12.string()).optional(),
1170
+ dropped: z13.array(z13.string()).optional(),
1099
1171
  // The repos the work hinted, and the workers whose machine had cloned every one, which go first
1100
1172
  // among workers that tie on fit and priority.
1101
- hints: z12.array(nonEmpty6).optional(),
1102
- warm: z12.array(nonEmpty6).optional(),
1173
+ hints: z13.array(nonEmpty6).optional(),
1174
+ warm: z13.array(nonEmpty6).optional(),
1103
1175
  // Each ordered worker's share, how its weekly usage is pacing, and the weight that gives it. The
1104
1176
  // first worker was drawn by weight from those in `drawn`, which suited the work equally.
1105
- shares: z12.array(
1106
- z12.object({
1177
+ shares: z13.array(
1178
+ z13.object({
1107
1179
  key: nonEmpty6,
1108
1180
  share: shareSchema,
1109
- pacing: z12.enum(["ahead", "even", "under", "unknown"]),
1110
- weight: z12.number().nonnegative()
1181
+ pacing: z13.enum(["ahead", "even", "under", "unknown"]),
1182
+ weight: z13.number().nonnegative()
1111
1183
  })
1112
1184
  ).optional(),
1113
- drawn: z12.array(nonEmpty6).optional()
1185
+ drawn: z13.array(nonEmpty6).optional()
1114
1186
  });
1115
- threadChangeSchema = z12.discriminatedUnion("kind", [
1116
- z12.object({ kind: z12.literal("edited"), messageId: nonEmpty6, previous: z12.string() }),
1117
- z12.object({
1118
- kind: z12.literal("reacted"),
1187
+ threadChangeSchema = z13.discriminatedUnion("kind", [
1188
+ z13.object({ kind: z13.literal("edited"), messageId: nonEmpty6, previous: z13.string() }),
1189
+ z13.object({
1190
+ kind: z13.literal("reacted"),
1119
1191
  messageId: nonEmpty6,
1120
1192
  reaction: nonEmpty6,
1121
1193
  /** The words of the message reacted to, cut short. */
1122
- target: z12.string(),
1194
+ target: z13.string(),
1123
1195
  /** Whether Friday wrote that message. */
1124
- onBot: z12.boolean()
1196
+ onBot: z13.boolean()
1125
1197
  })
1126
1198
  ]);
1127
- conversationEventSchema = z12.discriminatedUnion("type", [
1199
+ conversationEventSchema = z13.discriminatedUnion("type", [
1128
1200
  event("message.created", {
1129
1201
  messageId: nonEmpty6,
1130
- text: z12.string(),
1131
- direction: z12.enum(["inbound", "outbound"]),
1202
+ text: z13.string(),
1203
+ direction: z13.enum(["inbound", "outbound"]),
1132
1204
  route: routeSchema.optional(),
1133
1205
  // Why the message did or didn't wake the conversation.
1134
- reason: z12.string().optional(),
1206
+ reason: z13.string().optional(),
1135
1207
  // Loaded from before the conversation joined the thread, so it never waits for a response.
1136
- isContext: z12.boolean().optional(),
1208
+ isContext: z13.boolean().optional(),
1137
1209
  // Set when the message was deleted on its platform. `text` is then empty.
1138
- deleted: z12.boolean().optional(),
1210
+ deleted: z13.boolean().optional(),
1139
1211
  // Sent through the API but kept out of the platform, so only clients see it.
1140
- quiet: z12.boolean().optional(),
1212
+ quiet: z13.boolean().optional(),
1141
1213
  // The client an agent sent it through, such as "Claude Code". Such a message is the agent's.
1142
- client: z12.string().optional(),
1214
+ client: z13.string().optional(),
1143
1215
  // How to read `text`. Absent means plain text, as every message before this field was.
1144
- format: z12.enum(["markdown"]).optional(),
1216
+ format: z13.enum(["markdown"]).optional(),
1145
1217
  // Files attached to it, kept with the conversation.
1146
- files: z12.array(messageFileSchema).optional(),
1218
+ files: z13.array(messageFileSchema).optional(),
1147
1219
  // A platform's own layout, shown there in place of `text`. Every other surface shows `text`.
1148
- layout: z12.object({ platform: layoutPlatformSchema, blocks: z12.array(z12.unknown()) }).optional(),
1220
+ layout: z13.object({ platform: layoutPlatformSchema, blocks: z13.array(z13.unknown()) }).optional(),
1149
1221
  // Set when this was posted in another channel, starting the conversation named here.
1150
1222
  post: postTargetSchema.optional(),
1151
1223
  // Set on a channel post's own conversation: the conversation that posted it. Its ID is left
1152
1224
  // out for anyone who can't read that conversation.
1153
- origin: z12.object({ conversationId: nonEmpty6.optional() }).optional(),
1225
+ origin: z13.object({ conversationId: nonEmpty6.optional() }).optional(),
1154
1226
  // Set on Friday's one notice that a firing with no thread can't run yet, saying why.
1155
1227
  threadNotice: nonEmpty6.optional(),
1156
1228
  // Set when this reply answered an open prompt, so it never waits as a message of its own.
1157
1229
  answersPrompt: nonEmpty6.optional(),
1158
1230
  // Set on a child conversation's first message: the brief its parent's agent wrote, from the
1159
1231
  // principal's own account. `by` is the parent's worker.
1160
- delegation: z12.object({ parent: nonEmpty6, by: nonEmpty6 }).optional(),
1232
+ delegation: z13.object({ parent: nonEmpty6, by: nonEmpty6 }).optional(),
1161
1233
  // Set on a message from another of the principal's conversations' agents, which is that agent's
1162
1234
  // words, not a person's. `posted` means a delegate already posted it in the thread, and
1163
1235
  // `outsideTree` that the sender isn't in this conversation's tree.
1164
- agentMessage: z12.object({
1236
+ agentMessage: z13.object({
1165
1237
  from: nonEmpty6,
1166
1238
  worker: nonEmpty6,
1167
- posted: z12.boolean().optional(),
1168
- overdue: z12.boolean().optional(),
1239
+ posted: z13.boolean().optional(),
1240
+ overdue: z13.boolean().optional(),
1169
1241
  // herd's own note about the delegate, such as that it's waiting for its worker.
1170
- notice: z12.boolean().optional(),
1171
- outsideTree: z12.boolean().optional()
1242
+ notice: z13.boolean().optional(),
1243
+ outsideTree: z13.boolean().optional()
1172
1244
  }).optional(),
1173
1245
  // Set on a message a root posted for one of its children, which is labelled as the child's.
1174
- forChild: z12.object({ id: nonEmpty6, worker: nonEmpty6, for: nonEmpty6 }).optional(),
1246
+ forChild: z13.object({ id: nonEmpty6, worker: nonEmpty6, for: nonEmpty6 }).optional(),
1175
1247
  // Set on an automation's firing, whose `text` is the owner's instructions, and on the opening
1176
1248
  // post that starts a conversation for one. `payload` is what the trigger brought: untrusted.
1177
- automation: z12.object({
1249
+ automation: z13.object({
1178
1250
  id: nonEmpty6,
1179
1251
  name: nonEmpty6,
1180
1252
  reason: nonEmpty6,
1181
1253
  key: nonEmpty6,
1182
- payload: z12.string().optional(),
1254
+ payload: z13.string().optional(),
1183
1255
  // The opening post a firing's reactions are shown on, in a conversation it started.
1184
1256
  opener: nonEmpty6.optional()
1185
1257
  }).optional(),
@@ -1190,27 +1262,27 @@ var init_events = __esm({
1190
1262
  // quiet waking work. For an edit `text` is the new words, and for a reaction its emoji.
1191
1263
  threadChange: threadChangeSchema.optional()
1192
1264
  }),
1193
- event("message.updated", { messageId: nonEmpty6, text: z12.string() }),
1265
+ event("message.updated", { messageId: nonEmpty6, text: z13.string() }),
1194
1266
  // A decision model judged whether a reply in a joined thread was meant for the bot. `for_bot`
1195
1267
  // woke the conversation. `failed` means it couldn't be decided in time, so nothing woke.
1196
1268
  event("message.decided", {
1197
1269
  messageId: nonEmpty6,
1198
- messageSeq: z12.number().int().positive(),
1199
- outcome: z12.enum(["for_bot", "not_for_bot", "failed"]),
1200
- probability: z12.number().min(0).max(1).optional(),
1270
+ messageSeq: z13.number().int().positive(),
1271
+ outcome: z13.enum(["for_bot", "not_for_bot", "failed"]),
1272
+ probability: z13.number().min(0).max(1).optional(),
1201
1273
  model: nonEmpty6,
1202
- error: z12.string().optional()
1274
+ error: z13.string().optional()
1203
1275
  }),
1204
1276
  // A decision model judged whether the bot's last message of a turn asks a person to answer,
1205
1277
  // decide, provide or confirm something before it can carry on. `asks` keeps the conversation
1206
1278
  // waiting on them. `failed` means it couldn't be judged in time, so nothing changed.
1207
1279
  event("message.asked", {
1208
1280
  messageId: nonEmpty6,
1209
- messageSeq: z12.number().int().positive(),
1210
- outcome: z12.enum(["asks", "doesnt_ask", "failed"]),
1211
- probability: z12.number().min(0).max(1).optional(),
1281
+ messageSeq: z13.number().int().positive(),
1282
+ outcome: z13.enum(["asks", "doesnt_ask", "failed"]),
1283
+ probability: z13.number().min(0).max(1).optional(),
1212
1284
  model: nonEmpty6,
1213
- error: z12.string().optional()
1285
+ error: z13.string().optional()
1214
1286
  }),
1215
1287
  // One of an incoming message's files arrived, or couldn't. `file` replaces the one with its ID.
1216
1288
  event("message.file_changed", { messageId: nonEmpty6, file: messageFileSchema }),
@@ -1222,21 +1294,21 @@ var init_events = __esm({
1222
1294
  event("context.unavailable", { reason: nonEmpty6 }),
1223
1295
  event("mailbox.queued", {
1224
1296
  entryId: nonEmpty6,
1225
- messageSeq: z12.number().int().positive(),
1297
+ messageSeq: z13.number().int().positive(),
1226
1298
  delivery: deliveryModeSchema
1227
1299
  }),
1228
1300
  event("mailbox.claimed", {
1229
1301
  claimId: nonEmpty6,
1230
1302
  entryIds,
1231
1303
  holder: nonEmpty6,
1232
- expiresAt: z12.number().int()
1304
+ expiresAt: z13.number().int()
1233
1305
  }),
1234
- event("mailbox.renewed", { claimId: nonEmpty6, expiresAt: z12.number().int() }),
1306
+ event("mailbox.renewed", { claimId: nonEmpty6, expiresAt: z13.number().int() }),
1235
1307
  event("mailbox.released", {
1236
1308
  claimId: nonEmpty6,
1237
1309
  entryIds,
1238
1310
  // `delegates` means messages held for delegates are waiting again now that they've settled.
1239
- reason: z12.enum(["released", "expired", "delegates"])
1311
+ reason: z13.enum(["released", "expired", "delegates"])
1240
1312
  }),
1241
1313
  // A turn ended with delegates still open, so the messages it worked on wait for them, still ⏳.
1242
1314
  event("mailbox.held", { claimId: nonEmpty6, entryIds }),
@@ -1244,7 +1316,7 @@ var init_events = __esm({
1244
1316
  event("mailbox.completed", {
1245
1317
  entryIds,
1246
1318
  claimId: nonEmpty6.optional(),
1247
- outcome: z12.enum(["passed"]).optional()
1319
+ outcome: z13.enum(["passed"]).optional()
1248
1320
  }),
1249
1321
  event("mailbox.cancelled", { entryIds, reason: nonEmpty6 }),
1250
1322
  // A person asked for what's waiting to be delivered again. The entries stay waiting.
@@ -1261,15 +1333,15 @@ var init_events = __esm({
1261
1333
  // The message it was delivering, when it was one of the conversation's own messages.
1262
1334
  messageId: nonEmpty6.optional(),
1263
1335
  // For `kind: "files"`, which of that message's files didn't arrive.
1264
- fileIds: z12.array(nonEmpty6).optional()
1336
+ fileIds: z13.array(nonEmpty6).optional()
1265
1337
  }),
1266
1338
  event("status.changed", { status: agentStatusSchema }),
1267
1339
  // A work object was added or changed: the whole of it as it now stands, which fields changed, and
1268
1340
  // whether the agent or a provider changed them. Recording one never wakes the conversation.
1269
1341
  event("work.recorded", {
1270
1342
  work: workObjectSchema.omit({ conversationId: true }),
1271
- changed: z12.array(workFieldSchema),
1272
- added: z12.boolean(),
1343
+ changed: z13.array(workFieldSchema),
1344
+ added: z13.boolean(),
1273
1345
  by: workSourceSchema
1274
1346
  }),
1275
1347
  event("work.removed", { url: nonEmpty6, by: workSourceSchema }),
@@ -1282,7 +1354,7 @@ var init_events = __esm({
1282
1354
  event("prompt.opened", {
1283
1355
  promptId: nonEmpty6,
1284
1356
  ...promptRequestSchema.shape,
1285
- forChild: z12.object({ id: nonEmpty6, worker: nonEmpty6, promptId: nonEmpty6 }).optional()
1357
+ forChild: z13.object({ id: nonEmpty6, worker: nonEmpty6, promptId: nonEmpty6 }).optional()
1286
1358
  }),
1287
1359
  // A reply in the thread answers with its `messageId`, and with `text` when it was taken as the
1288
1360
  // answer in its own words rather than as naming an option.
@@ -1291,12 +1363,12 @@ var init_events = __esm({
1291
1363
  questionId: nonEmpty6,
1292
1364
  optionId: nonEmpty6.optional(),
1293
1365
  messageId: nonEmpty6.optional(),
1294
- text: z12.string().optional()
1366
+ text: z13.string().optional()
1295
1367
  }),
1296
1368
  event("prompt.closed", {
1297
1369
  promptId: nonEmpty6,
1298
1370
  outcome: promptOutcomeSchema,
1299
- reason: z12.string().optional()
1371
+ reason: z13.string().optional()
1300
1372
  }),
1301
1373
  // Dispatch: which machine the conversation was offered to, and which one holds it.
1302
1374
  event("dispatch.offered", {
@@ -1320,19 +1392,19 @@ var init_events = __esm({
1320
1392
  // An agent started a child conversation on another worker, and how the child has gone since.
1321
1393
  event("delegation.started", {
1322
1394
  childId: nonEmpty6,
1323
- workers: z12.array(nonEmpty6),
1324
- routed: z12.boolean()
1395
+ workers: z13.array(nonEmpty6),
1396
+ routed: z13.boolean()
1325
1397
  }),
1326
1398
  event("delegation.settled", { childId: nonEmpty6 }),
1327
1399
  event("delegation.overdue", { childId: nonEmpty6 }),
1328
- event("delegation.waiting", { childId: nonEmpty6, waiting: z12.boolean() }),
1400
+ event("delegation.waiting", { childId: nonEmpty6, waiting: z13.boolean() }),
1329
1401
  // An agent asked for its conversation to move to another worker once its turn ends.
1330
1402
  event("dispatch.handoff_requested", { workerKey: nonEmpty6, workerName: nonEmpty6 }),
1331
1403
  // Terminals on the bound machine. Their output never enters the history, only these facts.
1332
1404
  event("terminal.opened", {
1333
1405
  terminalId: nonEmpty6,
1334
1406
  machineId: nonEmpty6,
1335
- lead: z12.boolean(),
1407
+ lead: z13.boolean(),
1336
1408
  // Only for a conversation from before folders, which works in one repo's worktree.
1337
1409
  worktree: worktreeSchema.optional()
1338
1410
  }),
@@ -1344,9 +1416,9 @@ var init_events = __esm({
1344
1416
  folder: nonEmpty6,
1345
1417
  branch: nonEmpty6,
1346
1418
  base: nonEmpty6.optional(),
1347
- fetchFailed: z12.string().max(1e3).optional()
1419
+ fetchFailed: z13.string().max(1e3).optional()
1348
1420
  }),
1349
- event("terminal.exited", { terminalId: nonEmpty6, exitCode: z12.number().int().nullable() }),
1421
+ event("terminal.exited", { terminalId: nonEmpty6, exitCode: z13.number().int().nullable() }),
1350
1422
  event("terminal.notice_failed", { terminalId: nonEmpty6, reason: nonEmpty6 }),
1351
1423
  /**
1352
1424
  * The agent's start didn't check in with `herd inbox` within its window, so it looks like it
@@ -1357,29 +1429,43 @@ var init_events = __esm({
1357
1429
  terminalId: nonEmpty6,
1358
1430
  agent: nonEmpty6,
1359
1431
  machineName: nonEmpty6,
1360
- detail: z12.string().max(200).optional()
1432
+ detail: z13.string().max(200).optional()
1361
1433
  }),
1362
1434
  /** A start that needed attention checked in after all. */
1363
1435
  event("terminal.checked_in", { terminalId: nonEmpty6 }),
1364
1436
  /** The daemon closed one of Claude Code's own dialogs that it has recorded, named by its title. */
1365
1437
  event("terminal.dialog_closed", { terminalId: nonEmpty6, dialog: nonEmpty6 }),
1438
+ /**
1439
+ * Someone watched the conversation's terminal from the web, or typed into it, from `startedAt`
1440
+ * until `endedAt`, and why it ended. Nothing of what was shown or typed is ever recorded.
1441
+ */
1442
+ event("terminal.watched", {
1443
+ startedAt: z13.number().int(),
1444
+ endedAt: z13.number().int(),
1445
+ reason: nonEmpty6
1446
+ }),
1447
+ event("terminal.driven", {
1448
+ startedAt: z13.number().int(),
1449
+ endedAt: z13.number().int(),
1450
+ reason: nonEmpty6
1451
+ }),
1366
1452
  // A subscribed event that didn't wake the conversation, with the reason. One that woke it is a
1367
1453
  // quiet inbound message carrying `github`, so it waits like any waking work.
1368
1454
  event("github.event", githubEventSummarySchema.shape),
1369
1455
  // A pull request's status card, queued for the conversation's thread.
1370
1456
  event("github.card", {
1371
1457
  resource: nonEmpty6,
1372
- url: z12.url(),
1458
+ url: z13.url(),
1373
1459
  label: nonEmpty6,
1374
- title: z12.string(),
1460
+ title: z13.string(),
1375
1461
  phase: pullRequestPhaseSchema,
1376
1462
  move: pullRequestMoveSchema.nullable(),
1377
- detail: z12.string().nullable()
1463
+ detail: z13.string().nullable()
1378
1464
  }),
1379
1465
  event("subscription.created", {
1380
1466
  resource: nonEmpty6,
1381
1467
  label: nonEmpty6,
1382
- url: z12.url(),
1468
+ url: z13.url(),
1383
1469
  subscriber: nonEmpty6,
1384
1470
  createdBy: subscriptionOriginSchema
1385
1471
  }),
@@ -1391,72 +1477,72 @@ var init_events = __esm({
1391
1477
  // A subscription reached its hourly limit of wakes, noted once each hour.
1392
1478
  event("subscription.limited", { resource: nonEmpty6 })
1393
1479
  ]);
1394
- conversationVisibilitySchema = z12.enum(["public", "private"]);
1395
- conversationStatusSchema = z12.enum(["idle", "waiting", "working"]);
1396
- conversationSummarySchema = z12.object({
1480
+ conversationVisibilitySchema = z13.enum(["public", "private"]);
1481
+ conversationStatusSchema = z13.enum(["idle", "waiting", "working"]);
1482
+ conversationSummarySchema = z13.object({
1397
1483
  id: nonEmpty6,
1398
1484
  provider: nonEmpty6,
1399
1485
  visibility: conversationVisibilitySchema,
1400
1486
  title: nonEmpty6,
1401
1487
  // Where the conversation lives on its platform, when it has a link.
1402
- placeUrl: z12.string().nullable(),
1488
+ placeUrl: z13.string().nullable(),
1403
1489
  status: conversationStatusSchema,
1404
- waitingCount: z12.number().int().nonnegative(),
1405
- createdAt: z12.number().int(),
1406
- lastActivityAt: z12.number().int(),
1407
- expiresAt: z12.number().int()
1408
- });
1409
- placementSchema = z12.discriminatedUnion("kind", [
1410
- z12.object({
1411
- kind: z12.literal("bound"),
1412
- machine: z12.object({ name: nonEmpty6, online: z12.boolean() }),
1490
+ waitingCount: z13.number().int().nonnegative(),
1491
+ createdAt: z13.number().int(),
1492
+ lastActivityAt: z13.number().int(),
1493
+ expiresAt: z13.number().int()
1494
+ });
1495
+ placementSchema = z13.discriminatedUnion("kind", [
1496
+ z13.object({
1497
+ kind: z13.literal("bound"),
1498
+ machine: z13.object({ name: nonEmpty6, online: z13.boolean() }),
1413
1499
  // The worker's name, such as `mac-mini/claude`, and never its configuration or capabilities.
1414
1500
  worker: nonEmpty6.optional()
1415
1501
  }),
1416
- z12.object({ kind: z12.literal("waiting_for_machine") }),
1417
- z12.object({ kind: z12.literal("author_not_linked") })
1502
+ z13.object({ kind: z13.literal("waiting_for_machine") }),
1503
+ z13.object({ kind: z13.literal("author_not_linked") })
1418
1504
  ]);
1419
- treeSummarySchema = z12.object({
1505
+ treeSummarySchema = z13.object({
1420
1506
  parent: nonEmpty6.nullable(),
1421
1507
  root: nonEmpty6,
1422
- children: z12.array(
1423
- z12.object({
1508
+ children: z13.array(
1509
+ z13.object({
1424
1510
  id: nonEmpty6,
1425
1511
  title: nonEmpty6,
1426
- state: z12.string().nullable(),
1427
- createdAt: z12.number()
1512
+ state: z13.string().nullable(),
1513
+ createdAt: z13.number()
1428
1514
  })
1429
1515
  )
1430
1516
  });
1431
- conversationSnapshotSchema = z12.object({
1517
+ conversationSnapshotSchema = z13.object({
1432
1518
  conversation: conversationSummarySchema,
1433
- events: z12.array(conversationEventSchema),
1519
+ events: z13.array(conversationEventSchema),
1434
1520
  /**
1435
1521
  * Each person actor's display name, by ID, as it is now. A person is shown by this, never by
1436
1522
  * the name stored with an event, which for older events was their address.
1437
1523
  */
1438
- people: z12.record(z12.string(), z12.string()).optional(),
1524
+ people: z13.record(z13.string(), z13.string()).optional(),
1439
1525
  placement: placementSchema.nullable().optional(),
1440
1526
  tree: treeSummarySchema.optional()
1441
1527
  });
1442
- liveFrameSchema = z12.discriminatedUnion("type", [
1443
- z12.object({ type: z12.literal("event"), event: conversationEventSchema }),
1444
- z12.object({ type: z12.literal("reconnect") }),
1445
- z12.object({ type: z12.literal("expired") })
1528
+ liveFrameSchema = z13.discriminatedUnion("type", [
1529
+ z13.object({ type: z13.literal("event"), event: conversationEventSchema }),
1530
+ z13.object({ type: z13.literal("reconnect") }),
1531
+ z13.object({ type: z13.literal("expired") })
1446
1532
  ]);
1447
- adapterCapabilitiesSchema = z12.object({
1448
- messages: z12.enum(["push", "window"]),
1449
- edits: z12.enum(["push", "rescan"]),
1450
- deletes: z12.enum(["push", "rescan"]),
1451
- reactions: z12.enum(["push", "counts"]),
1452
- status: z12.boolean(),
1453
- search: z12.boolean()
1533
+ adapterCapabilitiesSchema = z13.object({
1534
+ messages: z13.enum(["push", "window"]),
1535
+ edits: z13.enum(["push", "rescan"]),
1536
+ deletes: z13.enum(["push", "rescan"]),
1537
+ reactions: z13.enum(["push", "counts"]),
1538
+ status: z13.boolean(),
1539
+ search: z13.boolean()
1454
1540
  });
1455
1541
  }
1456
1542
  });
1457
1543
 
1458
1544
  // ../common-chat/src/conversation-state.ts
1459
- import { z as z13 } from "zod";
1545
+ import { z as z14 } from "zod";
1460
1546
  function openRank(item) {
1461
1547
  if (item.state === "stuck") return 0;
1462
1548
  if (leadOpen(item.lead) && item.lead?.move === "you") return 1;
@@ -1493,8 +1579,8 @@ var init_conversation_state = __esm({
1493
1579
  init_machines();
1494
1580
  init_pull_requests();
1495
1581
  init_work_objects();
1496
- nonEmpty7 = z13.string().min(1);
1497
- time5 = z13.number().int().nonnegative();
1582
+ nonEmpty7 = z14.string().min(1);
1583
+ time5 = z14.number().int().nonnegative();
1498
1584
  REACTIONS = {
1499
1585
  waiting: "eyes",
1500
1586
  working: "hourglass_flowing_sand",
@@ -1503,14 +1589,14 @@ var init_conversation_state = __esm({
1503
1589
  // Stuck because it's waiting on a person's answer, approval or decision, rather than on a fault.
1504
1590
  asking: "question"
1505
1591
  };
1506
- conversationStateSchema = z13.enum([
1592
+ conversationStateSchema = z14.enum([
1507
1593
  "waiting",
1508
1594
  "working",
1509
1595
  "stuck",
1510
1596
  "unanswered",
1511
1597
  "done"
1512
1598
  ]);
1513
- stuckReasonSchema = z13.enum([
1599
+ stuckReasonSchema = z14.enum([
1514
1600
  "approval",
1515
1601
  "waiting_on_someone",
1516
1602
  // A delegate has an open prompt or is waiting on a person.
@@ -1533,43 +1619,43 @@ var init_conversation_state = __esm({
1533
1619
  "awaiting_answer"
1534
1620
  ]);
1535
1621
  STUCK_REASONS = stuckReasonSchema.options;
1536
- placeKindSchema = z13.enum(["channel", "direct", "group", "web"]);
1537
- conversationSourceSchema = z13.object({
1622
+ placeKindSchema = z14.enum(["channel", "direct", "group", "web"]);
1623
+ conversationSourceSchema = z14.object({
1538
1624
  provider: nonEmpty7,
1539
1625
  kind: placeKindSchema,
1540
1626
  /** Such as a Slack channel's name, without its `#`. Left out where it's unknown or hidden. */
1541
- name: z13.string().optional()
1627
+ name: z14.string().optional()
1542
1628
  });
1543
1629
  LATEST_MESSAGE_LENGTH = 200;
1544
- latestMessageSchema = z13.object({
1545
- text: z13.string().max(LATEST_MESSAGE_LENGTH),
1630
+ latestMessageSchema = z14.object({
1631
+ text: z14.string().max(LATEST_MESSAGE_LENGTH),
1546
1632
  /** A person wrote it, or the agent did. */
1547
- from: z13.enum(["person", "agent"]),
1633
+ from: z14.enum(["person", "agent"]),
1548
1634
  at: time5
1549
1635
  });
1550
1636
  listMachineSchema = machinePresenceSchema.extend({
1551
- mine: z13.boolean().optional(),
1637
+ mine: z14.boolean().optional(),
1552
1638
  /** The agent holding it on that machine, such as `Claude Code`, when it's known. */
1553
- agent: z13.string().optional()
1639
+ agent: z14.string().optional()
1554
1640
  });
1555
- conversationListItemSchema = z13.object({
1641
+ conversationListItemSchema = z14.object({
1556
1642
  id: nonEmpty7,
1557
1643
  title: nonEmpty7,
1558
1644
  visibility: conversationVisibilitySchema,
1559
1645
  /** The conversation's page. */
1560
1646
  url: nonEmpty7,
1561
1647
  /** Its thread on its platform, when it has a link. */
1562
- placeUrl: z13.string().nullable(),
1648
+ placeUrl: z14.string().nullable(),
1563
1649
  state: conversationStateSchema,
1564
1650
  // A reason this version no longer gives, such as one stored before it, reads as none.
1565
1651
  reason: stuckReasonSchema.nullable().catch(null),
1566
1652
  /** The start of the latest waking message. */
1567
- latestRequest: z13.string().nullable(),
1653
+ latestRequest: z14.string().nullable(),
1568
1654
  lastRequestAt: time5.nullable(),
1569
1655
  /** When the bot last posted in the thread. */
1570
1656
  lastReplyAt: time5.nullable(),
1571
1657
  /** What the agent says it's doing, while it works. */
1572
- activity: z13.string().nullable(),
1658
+ activity: z14.string().nullable(),
1573
1659
  /** The machine holding it, by name and presence only, and whether it's the reader's own. */
1574
1660
  machine: listMachineSchema.nullable(),
1575
1661
  lastActivityAt: time5,
@@ -1580,28 +1666,28 @@ var init_conversation_state = __esm({
1580
1666
  /** When its activity last changed, which says how long an agent has been quiet. */
1581
1667
  activityAt: time5.nullable().optional(),
1582
1668
  /** Set when the title, latest request, link and activity were left out because it's private. */
1583
- hidden: z13.boolean().optional(),
1669
+ hidden: z14.boolean().optional(),
1584
1670
  /**
1585
1671
  * What it's about, its delegates' included: at most 5, open ones first. Missing, from servers
1586
1672
  * older than work objects, means none.
1587
1673
  */
1588
- work: z13.array(workObjectSummarySchema).optional(),
1674
+ work: z14.array(workObjectSummarySchema).optional(),
1589
1675
  /** How many more work objects it holds than `work` carries. */
1590
- moreWork: z13.number().int().nonnegative().optional(),
1676
+ moreWork: z14.number().int().nonnegative().optional(),
1591
1677
  /** The pull request it leads with, from all of its tree's, not only those in `work`. */
1592
1678
  lead: leadChangeSchema.nullable().optional()
1593
1679
  });
1594
- conversationListSchema = z13.object({
1595
- items: z13.array(conversationListItemSchema),
1680
+ conversationListSchema = z14.object({
1681
+ items: z14.array(conversationListItemSchema),
1596
1682
  /** Present when there's more, to pass back as `next` for the following page. */
1597
- next: z13.string().optional()
1683
+ next: z14.string().optional()
1598
1684
  });
1599
- listFrameSchema = z13.discriminatedUnion("type", [
1600
- z13.object({ type: z13.literal("changed"), conversations: z13.array(nonEmpty7).min(1) }),
1685
+ listFrameSchema = z14.discriminatedUnion("type", [
1686
+ z14.object({ type: z14.literal("changed"), conversations: z14.array(nonEmpty7).min(1) }),
1601
1687
  /** A machine went online or offline, or a worker's usage changed. */
1602
- z13.object({ type: z13.literal("machines") }),
1603
- z13.object({ type: z13.literal("reconnect") }),
1604
- z13.object({ type: z13.literal("expired") })
1688
+ z14.object({ type: z14.literal("machines") }),
1689
+ z14.object({ type: z14.literal("reconnect") }),
1690
+ z14.object({ type: z14.literal("expired") })
1605
1691
  ]);
1606
1692
  STATE_REACTIONS = {
1607
1693
  stuck: REACTIONS.stuck,
@@ -1642,7 +1728,7 @@ var init_conversation_state = __esm({
1642
1728
  });
1643
1729
 
1644
1730
  // ../common-chat/src/board.ts
1645
- import { z as z14 } from "zod";
1731
+ import { z as z15 } from "zod";
1646
1732
  var nonEmpty8, time6, BOARD_ITEMS, boardItemSchema, boardWorkerSchema, boardMachineSchema, boardSchema;
1647
1733
  var init_board = __esm({
1648
1734
  "../common-chat/src/board.ts"() {
@@ -1651,27 +1737,27 @@ var init_board = __esm({
1651
1737
  init_conversation_state();
1652
1738
  init_pull_requests();
1653
1739
  init_usage();
1654
- nonEmpty8 = z14.string().min(1);
1655
- time6 = z14.number().int().nonnegative();
1740
+ nonEmpty8 = z15.string().min(1);
1741
+ time6 = z15.number().int().nonnegative();
1656
1742
  BOARD_ITEMS = 8;
1657
- boardItemSchema = z14.object({
1743
+ boardItemSchema = z15.object({
1658
1744
  id: nonEmpty8,
1659
1745
  /** `HIDDEN_TITLE` when the item is private and the board doesn't show private titles. */
1660
1746
  title: nonEmpty8,
1661
1747
  state: conversationStateSchema,
1662
1748
  reason: stuckReasonSchema.nullable().catch(null),
1663
1749
  /** Where the work came from, such as `#herd-dev` or a direct message, when it's known. */
1664
- source: z14.string().nullable(),
1750
+ source: z15.string().nullable(),
1665
1751
  /** What the agent says it's doing, while it works. */
1666
- activity: z14.string().nullable(),
1752
+ activity: z15.string().nullable(),
1667
1753
  lastActivityAt: time6,
1668
1754
  /** The machine and agent holding it, such as `mac-mini` and `Claude Code`, once it's bound. */
1669
- heldBy: z14.object({ machine: nonEmpty8, agent: nonEmpty8 }).nullable().optional(),
1755
+ heldBy: z15.object({ machine: nonEmpty8, agent: nonEmpty8 }).nullable().optional(),
1670
1756
  /** The pull request it leads with, and how many more are the person's move. */
1671
1757
  change: leadChangeSchema.nullable().optional(),
1672
- hidden: z14.boolean().optional()
1758
+ hidden: z15.boolean().optional()
1673
1759
  });
1674
- boardWorkerSchema = z14.object({
1760
+ boardWorkerSchema = z15.object({
1675
1761
  /** The worker's short name, such as `claude`, under its machine. */
1676
1762
  name: nonEmpty8,
1677
1763
  /** Its agent CLI, such as `claude-code`, which names it on the board. */
@@ -1680,33 +1766,33 @@ var init_board = __esm({
1680
1766
  usage: usageSchema.nullable(),
1681
1767
  reportedAt: time6.nullable(),
1682
1768
  /** What it's great at, from its profile: its owner's statements, or herd's defaults. */
1683
- strengths: z14.array(z14.string().min(1).max(100)).max(3).optional()
1769
+ strengths: z15.array(z15.string().min(1).max(100)).max(3).optional()
1684
1770
  });
1685
- boardMachineSchema = z14.object({
1771
+ boardMachineSchema = z15.object({
1686
1772
  name: nonEmpty8,
1687
- online: z14.boolean(),
1688
- workers: z14.array(boardWorkerSchema).max(8)
1773
+ online: z15.boolean(),
1774
+ workers: z15.array(boardWorkerSchema).max(8)
1689
1775
  });
1690
- boardSchema = z14.object({
1776
+ boardSchema = z15.object({
1691
1777
  /** How many are in each open state: every state but `done`, which is counted for the last day. */
1692
- counts: z14.object({
1693
- stuck: z14.number().int().nonnegative(),
1694
- unanswered: z14.number().int().nonnegative(),
1695
- waiting: z14.number().int().nonnegative(),
1696
- working: z14.number().int().nonnegative(),
1778
+ counts: z15.object({
1779
+ stuck: z15.number().int().nonnegative(),
1780
+ unanswered: z15.number().int().nonnegative(),
1781
+ waiting: z15.number().int().nonnegative(),
1782
+ working: z15.number().int().nonnegative(),
1697
1783
  /** Open pull requests the person's conversations made that are their move, each counted. */
1698
- pullRequests: z14.number().int().nonnegative().optional()
1784
+ pullRequests: z15.number().int().nonnegative().optional()
1699
1785
  }),
1700
1786
  /** How many became `done` in the last 24 hours. */
1701
- doneToday: z14.number().int().nonnegative(),
1787
+ doneToday: z15.number().int().nonnegative(),
1702
1788
  /**
1703
1789
  * What needs the person (stuck, then pull requests that are their move), then what's working or
1704
1790
  * has a pull request under way, then what's queued, then the latest finished to fill the rest.
1705
1791
  */
1706
- items: z14.array(boardItemSchema).max(BOARD_ITEMS),
1707
- machines: z14.array(boardMachineSchema).max(16),
1792
+ items: z15.array(boardItemSchema).max(BOARD_ITEMS),
1793
+ machines: z15.array(boardMachineSchema).max(16),
1708
1794
  /** Changes whenever anything the board shows changes, and only then. */
1709
- stamp: z14.string().regex(/^[0-9a-f]{12}$/),
1795
+ stamp: z15.string().regex(/^[0-9a-f]{12}$/),
1710
1796
  /** When its content last changed. */
1711
1797
  changedAt: time6
1712
1798
  });
@@ -1728,31 +1814,31 @@ var init_bot = __esm({
1728
1814
  });
1729
1815
 
1730
1816
  // ../common-chat/src/builds.ts
1731
- import { z as z15 } from "zod";
1817
+ import { z as z16 } from "zod";
1732
1818
  var nonEmpty9, time7, BUILD_LEASE_MS, BUILD_CLAIM_WINDOW_MS, MAX_LOG_CHUNK_BYTES, MAX_LOG_BYTES, MAX_NODE_MODULES_PART_BYTES, shaSchema, buildOfferSchema, buildCancelReasonSchema, runnerMessageSchema, serviceMessageSchema, runnerRegisterRequestSchema, runnerRegisterResponseSchema, runnerPollRequestSchema, runnerPollResponseSchema, buildStepSchema, buildFinishSchema, sharedPassSchema, passesResponseSchema, deployCredentialsSchema, deployedSchema, healthSchema;
1733
1819
  var init_builds = __esm({
1734
1820
  "../common-chat/src/builds.ts"() {
1735
1821
  "use strict";
1736
1822
  init_define_HERD_PACKAGE();
1737
1823
  init_workers();
1738
- nonEmpty9 = z15.string().min(1);
1739
- time7 = z15.number().int().nonnegative();
1824
+ nonEmpty9 = z16.string().min(1);
1825
+ time7 = z16.number().int().nonnegative();
1740
1826
  BUILD_LEASE_MS = 5 * 60 * 1e3;
1741
1827
  BUILD_CLAIM_WINDOW_MS = 15 * 1e3;
1742
1828
  MAX_LOG_CHUNK_BYTES = 256 * 1024;
1743
1829
  MAX_LOG_BYTES = 5 * 1024 * 1024;
1744
1830
  MAX_NODE_MODULES_PART_BYTES = 95 * 1024 * 1024;
1745
- shaSchema = z15.string().regex(/^[0-9a-f]{40}$/);
1746
- buildOfferSchema = z15.object({
1831
+ shaSchema = z16.string().regex(/^[0-9a-f]{40}$/);
1832
+ buildOfferSchema = z16.object({
1747
1833
  id: nonEmpty9,
1748
1834
  offerId: nonEmpty9,
1749
1835
  repo: nonEmpty9,
1750
1836
  sha: shaSchema,
1751
1837
  ref: nonEmpty9,
1752
- main: z15.boolean(),
1838
+ main: z16.boolean(),
1753
1839
  expiresAt: time7
1754
1840
  });
1755
- buildCancelReasonSchema = z15.enum([
1841
+ buildCancelReasonSchema = z16.enum([
1756
1842
  // A newer push to the same branch replaced it.
1757
1843
  "superseded",
1758
1844
  // The branch was deleted.
@@ -1762,7 +1848,7 @@ var init_builds = __esm({
1762
1848
  // Stopped for another reason, such as the repo being removed.
1763
1849
  "cancelled"
1764
1850
  ]);
1765
- runnerMessageSchema = z15.discriminatedUnion("type", [
1851
+ runnerMessageSchema = z16.discriminatedUnion("type", [
1766
1852
  /**
1767
1853
  * Sent first, and again whenever any of it changes. `capacity` comes from `herd.config.ts`'s
1768
1854
  * `builds` through `runnerCapacity`, `repos` are the normalized remotes of the repos herd has
@@ -1770,82 +1856,82 @@ var init_builds = __esm({
1770
1856
  * any of its owner's repos, cloning one it hasn't got, and `repos` only puts it first for those.
1771
1857
  * A daemon from before herd's root sent its configured checkouts here, which it builds from.
1772
1858
  */
1773
- z15.object({
1774
- type: z15.literal("hello"),
1859
+ z16.object({
1860
+ type: z16.literal("hello"),
1775
1861
  /** How many builds at once. 0 when the machine can't sandbox a build, so it takes none. */
1776
- capacity: z15.number().int().min(0).max(BUILDS_MAX),
1777
- repos: z15.array(nonEmpty9.max(300)).max(100),
1778
- running: z15.array(nonEmpty9.max(100)).max(BUILDS_MAX * 2)
1862
+ capacity: z16.number().int().min(0).max(BUILDS_MAX),
1863
+ repos: z16.array(nonEmpty9.max(300)).max(100),
1864
+ running: z16.array(nonEmpty9.max(100)).max(BUILDS_MAX * 2)
1779
1865
  }),
1780
1866
  /** An answer to an offer, before its `expiresAt`. A refusal may say why. */
1781
- z15.object({
1782
- type: z15.literal("answer"),
1867
+ z16.object({
1868
+ type: z16.literal("answer"),
1783
1869
  buildId: nonEmpty9,
1784
1870
  offerId: nonEmpty9,
1785
- answer: z15.enum(["accept", "refuse"]),
1786
- reason: z15.string().max(500).optional()
1871
+ answer: z16.enum(["accept", "refuse"]),
1872
+ reason: z16.string().max(500).optional()
1787
1873
  })
1788
1874
  ]);
1789
- serviceMessageSchema = z15.discriminatedUnion("type", [
1790
- z15.object({ type: z15.literal("build"), build: buildOfferSchema }),
1875
+ serviceMessageSchema = z16.discriminatedUnion("type", [
1876
+ z16.object({ type: z16.literal("build"), build: buildOfferSchema }),
1791
1877
  /** An accepted offer: the build's own secret, and how long its claim lasts between renewals. */
1792
- z15.object({
1793
- type: z15.literal("accepted"),
1878
+ z16.object({
1879
+ type: z16.literal("accepted"),
1794
1880
  buildId: nonEmpty9,
1795
1881
  secret: nonEmpty9,
1796
- leaseMs: z15.number().int().positive()
1882
+ leaseMs: z16.number().int().positive()
1797
1883
  }),
1798
1884
  /**
1799
1885
  * Stop a build this runner holds, within 5 seconds. An accept that came too late, for an offer
1800
1886
  * that had expired or was withdrawn, gets this too, with the reason `cancelled`.
1801
1887
  */
1802
- z15.object({ type: z15.literal("build-cancel"), buildId: nonEmpty9, reason: buildCancelReasonSchema }),
1888
+ z16.object({ type: z16.literal("build-cancel"), buildId: nonEmpty9, reason: buildCancelReasonSchema }),
1803
1889
  /** Connect again. Sent before the service closes a socket that another replaced. */
1804
- z15.object({ type: z15.literal("reconnect") })
1890
+ z16.object({ type: z16.literal("reconnect") })
1805
1891
  ]);
1806
- runnerRegisterRequestSchema = z15.object({ name: z15.string().trim().min(1).max(100) });
1807
- runnerRegisterResponseSchema = z15.object({
1892
+ runnerRegisterRequestSchema = z16.object({ name: z16.string().trim().min(1).max(100) });
1893
+ runnerRegisterResponseSchema = z16.object({
1808
1894
  /** Shown to the owner, so they can match the approval page to the machine. */
1809
1895
  code: nonEmpty9,
1810
1896
  /** The page the owner opens, signed in, to approve it. */
1811
- approveUrl: z15.url(),
1897
+ approveUrl: z16.url(),
1812
1898
  /** Sent to `POST /runners/register/poll`. Only this machine has it. */
1813
1899
  pollToken: nonEmpty9,
1814
1900
  expiresAt: time7.optional(),
1815
1901
  /** How often to poll. */
1816
- pollMs: z15.number().int().positive().optional()
1902
+ pollMs: z16.number().int().positive().optional()
1817
1903
  });
1818
- runnerPollRequestSchema = z15.object({ pollToken: nonEmpty9.max(200) });
1819
- runnerPollResponseSchema = z15.discriminatedUnion("status", [
1820
- z15.object({ status: z15.literal("waiting") }),
1904
+ runnerPollRequestSchema = z16.object({ pollToken: nonEmpty9.max(200) });
1905
+ runnerPollResponseSchema = z16.discriminatedUnion("status", [
1906
+ z16.object({ status: z16.literal("waiting") }),
1821
1907
  /** Approved. The key is returned this once, and the service keeps only its hash. */
1822
- z15.object({ status: z15.literal("approved"), runnerId: nonEmpty9, key: nonEmpty9 }),
1908
+ z16.object({ status: z16.literal("approved"), runnerId: nonEmpty9, key: nonEmpty9 }),
1823
1909
  /** Expired, or the key was already collected. Start again. */
1824
- z15.object({ status: z15.literal("expired") })
1910
+ z16.object({ status: z16.literal("expired") })
1825
1911
  ]);
1826
- buildStepSchema = z15.object({
1827
- label: z15.string().min(1).max(200),
1828
- key: z15.string().regex(/^[0-9a-zA-Z_-]{8,128}$/),
1829
- status: z15.enum(["passed", "failed", "remembered"]),
1830
- ms: z15.number().int().nonnegative(),
1912
+ buildStepSchema = z16.object({
1913
+ label: z16.string().min(1).max(200),
1914
+ key: z16.string().regex(/^[0-9a-zA-Z_-]{8,128}$/),
1915
+ status: z16.enum(["passed", "failed", "remembered"]),
1916
+ ms: z16.number().int().nonnegative(),
1831
1917
  /** Only some of the step's tests ran, so its pass isn't shared. */
1832
- partial: z15.boolean().default(false),
1833
- budgetMs: z15.number().int().positive().nullable().default(null)
1918
+ partial: z16.boolean().default(false),
1919
+ budgetMs: z16.number().int().positive().nullable().default(null)
1834
1920
  });
1835
- buildFinishSchema = z15.object({
1836
- status: z15.enum(["success", "failure", "error"]),
1837
- summary: z15.string().max(2e3).default(""),
1838
- deployed: z15.boolean().default(false)
1921
+ buildFinishSchema = z16.object({
1922
+ status: z16.enum(["success", "failure", "error"]),
1923
+ summary: z16.string().max(2e3).default(""),
1924
+ deployed: z16.boolean().default(false)
1839
1925
  });
1840
- sharedPassSchema = z15.object({
1926
+ sharedPassSchema = z16.object({
1841
1927
  step: nonEmpty9,
1842
1928
  passedAt: time7,
1843
1929
  sha: nonEmpty9,
1844
1930
  runner: nonEmpty9,
1845
- partial: z15.boolean()
1931
+ partial: z16.boolean()
1846
1932
  });
1847
- passesResponseSchema = z15.object({ passes: z15.record(z15.string(), sharedPassSchema) });
1848
- deployCredentialsSchema = z15.object({
1933
+ passesResponseSchema = z16.object({ passes: z16.record(z16.string(), sharedPassSchema) });
1934
+ deployCredentialsSchema = z16.object({
1849
1935
  cloudflareToken: nonEmpty9,
1850
1936
  /** Publishes `@herdingchats/friday`. Missing when the build service has none set. */
1851
1937
  npmToken: nonEmpty9.optional(),
@@ -1854,20 +1940,20 @@ var init_builds = __esm({
1854
1940
  /** `owner/name`, for moving `deployed`. */
1855
1941
  repo: nonEmpty9,
1856
1942
  /** The commit being built, which `deployed` moves to. Older services don't send it. */
1857
- sha: z15.string().regex(/^[0-9a-f]{40}$/).optional(),
1943
+ sha: z16.string().regex(/^[0-9a-f]{40}$/).optional(),
1858
1944
  /** Each Worker's key at its last successful deploy. */
1859
- lastDeployed: z15.record(z15.string(), z15.string())
1945
+ lastDeployed: z16.record(z16.string(), z16.string())
1860
1946
  });
1861
- deployedSchema = z15.object({
1862
- worker: z15.string().regex(/^[a-z][a-z0-9-]{0,62}$/),
1863
- key: z15.string().regex(/^[0-9a-zA-Z_-]{8,128}$/)
1947
+ deployedSchema = z16.object({
1948
+ worker: z16.string().regex(/^[a-z][a-z0-9-]{0,62}$/),
1949
+ key: z16.string().regex(/^[0-9a-zA-Z_-]{8,128}$/)
1864
1950
  });
1865
- healthSchema = z15.object({ ok: z15.boolean(), version: z15.string() });
1951
+ healthSchema = z16.object({ ok: z16.boolean(), version: z16.string() });
1866
1952
  }
1867
1953
  });
1868
1954
 
1869
1955
  // ../common-chat/src/setup.ts
1870
- import { z as z16 } from "zod";
1956
+ import { z as z17 } from "zod";
1871
1957
  function actionText(action) {
1872
1958
  if (action.kind === "link") return `${action.label}: ${action.url}`;
1873
1959
  if (action.kind === "sign_in") {
@@ -1902,42 +1988,42 @@ var init_setup = __esm({
1902
1988
  init_activation();
1903
1989
  init_bot();
1904
1990
  SETUP_STEP_IDS = ["slack", "machine", "github", "repos"];
1905
- setupActionSchema = z16.discriminatedUnion("kind", [
1991
+ setupActionSchema = z17.discriminatedUnion("kind", [
1906
1992
  /** A page to open, which signs in to HerdingChats first. */
1907
- z16.object({ kind: z16.literal("link"), url: z16.string(), label: z16.string() }),
1993
+ z17.object({ kind: z17.literal("link"), url: z17.string(), label: z17.string() }),
1908
1994
  /** A command to run on the computer. */
1909
- z16.object({ kind: z16.literal("command"), command: z16.string() }),
1995
+ z17.object({ kind: z17.literal("command"), command: z17.string() }),
1910
1996
  /**
1911
1997
  * A sign-in herd starts on one of the person's machines, from Slack or the page, whose code
1912
1998
  * Friday sends to their direct message.
1913
1999
  */
1914
- z16.object({
1915
- kind: z16.literal("sign_in"),
1916
- machineId: z16.string(),
2000
+ z17.object({
2001
+ kind: z17.literal("sign_in"),
2002
+ machineId: z17.string(),
1917
2003
  tool: signInToolSchema,
1918
- label: z16.string()
2004
+ label: z17.string()
1919
2005
  })
1920
2006
  ]);
1921
- setupStepSchema = z16.object({
1922
- id: z16.enum(SETUP_STEP_IDS),
2007
+ setupStepSchema = z17.object({
2008
+ id: z17.enum(SETUP_STEP_IDS),
1923
2009
  /** `unavailable` is a step nobody can take yet, such as GitHub linking before an admin turns it on. */
1924
- state: z16.enum(["done", "todo", "unavailable"]),
1925
- optional: z16.boolean(),
1926
- title: z16.string(),
2010
+ state: z17.enum(["done", "todo", "unavailable"]),
2011
+ optional: z17.boolean(),
2012
+ title: z17.string(),
1927
2013
  /** What was found, such as the machine and whether it's online, or why it can't be done yet. */
1928
- detail: z16.string().nullable(),
2014
+ detail: z17.string().nullable(),
1929
2015
  /** What to do next. None once it's done, or while it's unavailable. */
1930
2016
  action: setupActionSchema.nullable(),
1931
2017
  /**
1932
2018
  * More that can be done, which doesn't decide whether the step is done, such as signing in a
1933
2019
  * computer's GitHub CLI. Shown whatever the step's state.
1934
2020
  */
1935
- extra: z16.array(setupActionSchema).optional()
2021
+ extra: z17.array(setupActionSchema).optional()
1936
2022
  });
1937
- setupStatusSchema = z16.object({
1938
- steps: z16.array(setupStepSchema),
2023
+ setupStatusSchema = z17.object({
2024
+ steps: z17.array(setupStepSchema),
1939
2025
  /** Whether every step that isn't optional is done, so Friday can take work. */
1940
- ready: z16.boolean()
2026
+ ready: z17.boolean()
1941
2027
  });
1942
2028
  READY_TEXT = `You're set up: mention @${BOT_NAME} in any channel it's in, or message it directly.`;
1943
2029
  READY_SUGGESTIONS_TITLE = "Some things to try:";
@@ -1979,6 +2065,7 @@ var init_src = __esm({
1979
2065
  init_pull_requests();
1980
2066
  init_setup();
1981
2067
  init_state();
2068
+ init_terminals();
1982
2069
  init_usage();
1983
2070
  init_work_objects();
1984
2071
  init_workers();
@@ -2158,7 +2245,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
2158
2245
  function Text({
2159
2246
  theme,
2160
2247
  children,
2161
- size = "md",
2248
+ size: size2 = "md",
2162
2249
  bold,
2163
2250
  muted,
2164
2251
  faint,
@@ -2171,7 +2258,7 @@ function Text({
2171
2258
  {
2172
2259
  style: {
2173
2260
  display: "flex",
2174
- fontSize: theme.size[size],
2261
+ fontSize: theme.size[size2],
2175
2262
  fontWeight: bold ? 700 : 400,
2176
2263
  color: faint ? theme.faint : muted ? theme.muted : theme.ink,
2177
2264
  lineHeight: 1.2,
@@ -2183,9 +2270,9 @@ function Text({
2183
2270
  }
2184
2271
  );
2185
2272
  }
2186
- function Icon({ icon: icon2, color, size }) {
2273
+ function Icon({ icon: icon2, color, size: size2 }) {
2187
2274
  const { d, label: label3 } = ICON_PATHS[icon2];
2188
- return /* @__PURE__ */ jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", role: "img", "aria-label": label3, children: /* @__PURE__ */ jsx(
2275
+ return /* @__PURE__ */ jsx("svg", { width: size2, height: size2, viewBox: "0 0 24 24", role: "img", "aria-label": label3, children: /* @__PURE__ */ jsx(
2189
2276
  "path",
2190
2277
  {
2191
2278
  d,
@@ -2388,7 +2475,7 @@ var init_widget = __esm({
2388
2475
  });
2389
2476
 
2390
2477
  // ../common-board/src/widgets/conversations.tsx
2391
- import { z as z29 } from "zod";
2478
+ import { z as z30 } from "zod";
2392
2479
  import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
2393
2480
  function badge(item) {
2394
2481
  if (pullRequestBadge(item)) {
@@ -2432,10 +2519,10 @@ var init_conversations = __esm({
2432
2519
  conversations2 = defineWidget({
2433
2520
  kind: "conversations",
2434
2521
  describe: "Blocked, working and queued conversations, then the latest done, with what each is doing, where it came from and who holds it",
2435
- options: z29.object({
2436
- states: z29.array(conversationStateSchema).min(1).default(["stuck", "working", "waiting", "done"]),
2437
- limit: z29.number().int().min(1).max(BOARD_ITEMS).default(4),
2438
- show: z29.array(z29.enum(DETAILS)).default([...DETAILS])
2522
+ options: z30.object({
2523
+ states: z30.array(conversationStateSchema).min(1).default(["stuck", "working", "waiting", "done"]),
2524
+ limit: z30.number().int().min(1).max(BOARD_ITEMS).default(4),
2525
+ show: z30.array(z30.enum(DETAILS)).default([...DETAILS])
2439
2526
  }),
2440
2527
  reads: ["items", "machines"],
2441
2528
  Component: ({ board, options, theme, now }) => {
@@ -2479,7 +2566,7 @@ var init_conversations = __esm({
2479
2566
  });
2480
2567
 
2481
2568
  // ../common-board/src/widgets/counts.tsx
2482
- import { z as z30 } from "zod";
2569
+ import { z as z31 } from "zod";
2483
2570
  import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
2484
2571
  var COUNTS, LABELS2, counts;
2485
2572
  var init_counts = __esm({
@@ -2499,8 +2586,8 @@ var init_counts = __esm({
2499
2586
  counts = defineWidget({
2500
2587
  kind: "counts",
2501
2588
  describe: "How many conversations are stuck, unanswered, waiting and working, and done today",
2502
- options: z30.object({
2503
- show: z30.array(z30.enum(COUNTS)).min(1).max(5).default([...COUNTS])
2589
+ options: z31.object({
2590
+ show: z31.array(z31.enum(COUNTS)).min(1).max(5).default([...COUNTS])
2504
2591
  }),
2505
2592
  reads: ["counts", "doneToday"],
2506
2593
  Component: ({ board, options, theme }) => {
@@ -2539,7 +2626,7 @@ var init_counts = __esm({
2539
2626
  });
2540
2627
 
2541
2628
  // ../common-board/src/widgets/header.tsx
2542
- import { z as z31 } from "zod";
2629
+ import { z as z32 } from "zod";
2543
2630
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
2544
2631
  function summary(board) {
2545
2632
  const parts = [
@@ -2564,9 +2651,9 @@ var init_header = __esm({
2564
2651
  header = defineWidget({
2565
2652
  kind: "header",
2566
2653
  describe: "The board's title, a line of how much is open, and when it was drawn",
2567
- options: z31.object({
2568
- title: z31.string().min(1).max(40).default(`@${BOT_NAME}`),
2569
- summary: z31.boolean().default(true)
2654
+ options: z32.object({
2655
+ title: z32.string().min(1).max(40).default(`@${BOT_NAME}`),
2656
+ summary: z32.boolean().default(true)
2570
2657
  }),
2571
2658
  reads: ["counts"],
2572
2659
  Component: ({ board, options, theme, now }) => {
@@ -2584,7 +2671,7 @@ var init_header = __esm({
2584
2671
  });
2585
2672
 
2586
2673
  // ../common-board/src/widgets/machines.tsx
2587
- import { z as z32 } from "zod";
2674
+ import { z as z33 } from "zod";
2588
2675
  import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
2589
2676
  function usageText(worker) {
2590
2677
  const usage = worker.usage;
@@ -2615,7 +2702,7 @@ var init_machines2 = __esm({
2615
2702
  machines = defineWidget({
2616
2703
  kind: "machines",
2617
2704
  describe: "One bubble per agent on an online machine, with its usage, most recently active first",
2618
- options: z32.object({ limit: z32.number().int().min(1).max(8).default(3) }),
2705
+ options: z33.object({ limit: z33.number().int().min(1).max(8).default(3) }),
2619
2706
  reads: ["machines"],
2620
2707
  Component: ({ board, options, theme }) => {
2621
2708
  const workers2 = board.machines.filter((machine) => machine.online).flatMap((machine) => machine.workers.map((worker) => ({ ...worker, machine: machine.name }))).sort((a, b) => (b.reportedAt ?? 0) - (a.reportedAt ?? 0));
@@ -2732,9 +2819,9 @@ var init_board2 = __esm({
2732
2819
  });
2733
2820
 
2734
2821
  // ../common-board/src/composition.ts
2735
- import { z as z33 } from "zod";
2822
+ import { z as z34 } from "zod";
2736
2823
  function readComposition(stored) {
2737
- const shape = z33.object({ widgets: z33.array(placedWidgetSchema) }).safeParse(stored);
2824
+ const shape = z34.object({ widgets: z34.array(placedWidgetSchema) }).safeParse(stored);
2738
2825
  if (!shape.success) return DEFAULT_COMPOSITION;
2739
2826
  const known = shape.data.widgets.filter(
2740
2827
  (widget) => WIDGETS[widget.kind]?.options.safeParse(widget.options).success
@@ -2749,11 +2836,11 @@ var init_composition = __esm({
2749
2836
  init_registry();
2750
2837
  MAX_WIDGETS = 12;
2751
2838
  MAX_COMPOSITION_BYTES = 4096;
2752
- placedWidgetSchema = z33.object({
2753
- kind: z33.string().min(1),
2754
- options: z33.record(z33.string(), z33.unknown()).default({})
2839
+ placedWidgetSchema = z34.object({
2840
+ kind: z34.string().min(1),
2841
+ options: z34.record(z34.string(), z34.unknown()).default({})
2755
2842
  });
2756
- compositionSchema = z33.object({ widgets: z33.array(placedWidgetSchema).max(MAX_WIDGETS) }).superRefine((composition, context2) => {
2843
+ compositionSchema = z34.object({ widgets: z34.array(placedWidgetSchema).max(MAX_WIDGETS) }).superRefine((composition, context2) => {
2757
2844
  if (JSON.stringify(composition).length > MAX_COMPOSITION_BYTES) {
2758
2845
  context2.addIssue({
2759
2846
  code: "custom",
@@ -3213,7 +3300,7 @@ import { existsSync as existsSync12, readFileSync as readFileSync10 } from "node
3213
3300
  import { homedir as homedir5 } from "node:os";
3214
3301
  import { dirname as dirname10, join as join16 } from "node:path";
3215
3302
  import { createInterface } from "node:readline/promises";
3216
- import { z as z22 } from "zod";
3303
+ import { z as z23 } from "zod";
3217
3304
 
3218
3305
  // src/auth.ts
3219
3306
  init_define_HERD_PACKAGE();
@@ -3222,21 +3309,21 @@ import { chmodSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:
3222
3309
  import { createServer } from "node:http";
3223
3310
  import { homedir } from "node:os";
3224
3311
  import { join } from "node:path";
3225
- import { z as z17 } from "zod";
3312
+ import { z as z18 } from "zod";
3226
3313
  var herdHome = () => process.env.HERD_HOME ?? join(homedir(), ".herd");
3227
3314
  var apiUrl = () => (process.env.HERD_API_URL ?? "https://api.herdingchats.com").replace(/\/+$/, "");
3228
3315
  var isLocal = (url) => /^http:\/\/localhost:\d+\/?$/.test(url);
3229
3316
  var localSignIn = () => process.env.HERD_LOCAL_SLACK ? { "X-Herd-Local-Slack": process.env.HERD_LOCAL_SLACK } : {};
3230
3317
  var HerdError = class extends Error {
3231
3318
  };
3232
- var credentialsSchema = z17.object({
3233
- api: z17.string(),
3234
- tokenEndpoint: z17.string(),
3235
- revocationEndpoint: z17.string().optional(),
3236
- clientId: z17.string(),
3237
- accessToken: z17.string(),
3238
- accessTokenExpiresAt: z17.number(),
3239
- refreshToken: z17.string()
3319
+ var credentialsSchema = z18.object({
3320
+ api: z18.string(),
3321
+ tokenEndpoint: z18.string(),
3322
+ revocationEndpoint: z18.string().optional(),
3323
+ clientId: z18.string(),
3324
+ accessToken: z18.string(),
3325
+ accessTokenExpiresAt: z18.number(),
3326
+ refreshToken: z18.string()
3240
3327
  });
3241
3328
  var credentialsPath = () => join(herdHome(), "credentials.json");
3242
3329
  function readCredentials() {
@@ -3252,16 +3339,16 @@ function writeCredentials(credentials) {
3252
3339
  writeFileSync(credentialsPath(), JSON.stringify(credentials, null, 2), { mode: 384 });
3253
3340
  chmodSync(credentialsPath(), 384);
3254
3341
  }
3255
- var metadataSchema = z17.object({
3256
- authorization_endpoint: z17.string(),
3257
- token_endpoint: z17.string(),
3258
- registration_endpoint: z17.string(),
3259
- revocation_endpoint: z17.string().optional()
3342
+ var metadataSchema = z18.object({
3343
+ authorization_endpoint: z18.string(),
3344
+ token_endpoint: z18.string(),
3345
+ registration_endpoint: z18.string(),
3346
+ revocation_endpoint: z18.string().optional()
3260
3347
  });
3261
- var tokenSchema = z17.object({
3262
- access_token: z17.string().min(1),
3263
- refresh_token: z17.string().min(1),
3264
- expires_in: z17.number()
3348
+ var tokenSchema = z18.object({
3349
+ access_token: z18.string().min(1),
3350
+ refresh_token: z18.string().min(1),
3351
+ expires_in: z18.number()
3265
3352
  });
3266
3353
  var base64url = (bytes) => bytes.toString("base64url");
3267
3354
  async function postForm(url, fields) {
@@ -3293,7 +3380,7 @@ async function login(openBrowser2, { api = apiUrl(), timeoutMs = 10 * 60 * 1e3 }
3293
3380
  token_endpoint_auth_method: "none"
3294
3381
  })
3295
3382
  });
3296
- const client = z17.object({ client_id: z17.string() }).safeParse(await registration2.json());
3383
+ const client = z18.object({ client_id: z18.string() }).safeParse(await registration2.json());
3297
3384
  if (!registration2.ok || !client.success) {
3298
3385
  throw new HerdError("The sign-in server refused to register this tool.");
3299
3386
  }
@@ -3527,7 +3614,7 @@ import { randomUUID } from "node:crypto";
3527
3614
  import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync4, realpathSync as realpathSync2, writeFileSync as writeFileSync3 } from "node:fs";
3528
3615
  import { homedir as homedir3, hostname } from "node:os";
3529
3616
  import { basename, dirname as dirname4, join as join6, resolve } from "node:path";
3530
- import { z as z18 } from "zod";
3617
+ import { z as z19 } from "zod";
3531
3618
 
3532
3619
  // src/login-shell.ts
3533
3620
  init_define_HERD_PACKAGE();
@@ -3653,16 +3740,16 @@ function recordTime(line2) {
3653
3740
  return Number.isNaN(time8) ? 0 : time8;
3654
3741
  }
3655
3742
  function readNew(path, offset) {
3656
- let size;
3743
+ let size2;
3657
3744
  try {
3658
- size = statSync(path).size;
3745
+ size2 = statSync(path).size;
3659
3746
  } catch {
3660
3747
  return { events: [], offset };
3661
3748
  }
3662
- if (size <= offset) return { events: [], offset };
3749
+ if (size2 <= offset) return { events: [], offset };
3663
3750
  const fd = openSync(path, "r");
3664
3751
  try {
3665
- const buffer = Buffer.alloc(size - offset);
3752
+ const buffer = Buffer.alloc(size2 - offset);
3666
3753
  const read = readSync(fd, buffer, 0, buffer.length, offset);
3667
3754
  const chunk = buffer.subarray(0, read);
3668
3755
  const end = chunk.lastIndexOf(10);
@@ -3763,9 +3850,9 @@ function latestCodexUsage(home = codexHome()) {
3763
3850
  if (!newest) return null;
3764
3851
  let tail3;
3765
3852
  try {
3766
- const size = statSync(newest).size;
3767
- const start = Math.max(0, size - USAGE_TAIL_BYTES);
3768
- const buffer = Buffer.alloc(size - start);
3853
+ const size2 = statSync(newest).size;
3854
+ const start = Math.max(0, size2 - USAGE_TAIL_BYTES);
3855
+ const buffer = Buffer.alloc(size2 - start);
3769
3856
  const fd = openSync(newest, "r");
3770
3857
  try {
3771
3858
  readSync(fd, buffer, 0, buffer.length, start);
@@ -4306,13 +4393,13 @@ function hasUnpushed(path) {
4306
4393
 
4307
4394
  // src/config.ts
4308
4395
  init_self();
4309
- var repoSchema = z18.object({ name: z18.string(), path: z18.string(), remote: z18.string() });
4310
- var configSchema = z18.object({
4311
- machineId: z18.string(),
4312
- machineName: z18.string(),
4313
- repos: z18.array(repoSchema),
4396
+ var repoSchema = z19.object({ name: z19.string(), path: z19.string(), remote: z19.string() });
4397
+ var configSchema = z19.object({
4398
+ machineId: z19.string(),
4399
+ machineName: z19.string(),
4400
+ repos: z19.array(repoSchema),
4314
4401
  /** The machine's root folder, holding herd's clones and its conversations' folders. */
4315
- root: z18.string().optional()
4402
+ root: z19.string().optional()
4316
4403
  });
4317
4404
  var configPath = () => join6(herdHome(), "config.json");
4318
4405
  function save(config) {
@@ -4528,23 +4615,23 @@ init_src();
4528
4615
  import { randomBytes as randomBytes4, randomUUID as randomUUID3 } from "node:crypto";
4529
4616
  import { mkdirSync as mkdirSync6, readFileSync as readFileSync5, renameSync as renameSync2, rmSync as rmSync6, statSync as statSync4, writeFileSync as writeFileSync4 } from "node:fs";
4530
4617
  import { dirname as dirname5, join as join8 } from "node:path";
4531
- import { z as z21 } from "zod";
4618
+ import { z as z22 } from "zod";
4532
4619
 
4533
4620
  // src/permissions.ts
4534
4621
  init_define_HERD_PACKAGE();
4535
4622
  init_src();
4536
4623
  import { randomUUID as randomUUID2 } from "node:crypto";
4537
- import { z as z20 } from "zod";
4624
+ import { z as z21 } from "zod";
4538
4625
 
4539
4626
  // src/local-socket.ts
4540
4627
  init_define_HERD_PACKAGE();
4541
4628
  import { randomBytes as randomBytes3 } from "node:crypto";
4542
4629
  import { chmodSync as chmodSync2, existsSync as existsSync4, rmSync as rmSync4 } from "node:fs";
4543
4630
  import { connect, createServer as createServer2 } from "node:net";
4544
- import { z as z19 } from "zod";
4545
- var localRequestSchema = z19.object({
4546
- secret: z19.string().min(1),
4547
- op: z19.enum([
4631
+ import { z as z20 } from "zod";
4632
+ var localRequestSchema = z20.object({
4633
+ secret: z20.string().min(1),
4634
+ op: z20.enum([
4548
4635
  "inbox",
4549
4636
  "send",
4550
4637
  "run",
@@ -4576,32 +4663,32 @@ var localRequestSchema = z19.object({
4576
4663
  "activate"
4577
4664
  ]),
4578
4665
  // The key of the agent's start, from `HERD_START`, which `herd inbox` proves the start with.
4579
- start: z19.string().min(1).max(100).optional(),
4666
+ start: z20.string().min(1).max(100).optional(),
4580
4667
  // `herd repo`: the repo it added to the conversation's folder, for the daemon to record.
4581
- repo: z19.object({
4582
- remote: z19.string().min(1).max(500),
4583
- folder: z19.string().min(1).max(100),
4584
- base: z19.string().min(1).max(300).optional(),
4585
- fetchFailed: z19.string().max(1e3).optional()
4668
+ repo: z20.object({
4669
+ remote: z20.string().min(1).max(500),
4670
+ folder: z20.string().min(1).max(100),
4671
+ base: z20.string().min(1).max(300).optional(),
4672
+ fetchFailed: z20.string().max(1e3).optional()
4586
4673
  }).optional(),
4587
4674
  // `herd repo`: what the agent named and the folder it asked for, for the daemon to add.
4588
- repoAdd: z19.object({
4589
- asked: z19.string().min(1).max(500),
4590
- folder: z19.string().min(1).max(100).optional()
4675
+ repoAdd: z20.object({
4676
+ asked: z20.string().min(1).max(500),
4677
+ folder: z20.string().min(1).max(100).optional()
4591
4678
  }).optional(),
4592
4679
  // `herd delegate --repo`, given once for each repo the delegate works in.
4593
- repos: z19.array(z19.string().min(1).max(500)).max(10).optional(),
4680
+ repos: z20.array(z20.string().min(1).max(500)).max(10).optional(),
4594
4681
  // `herd watch`, `herd unwatch` and `herd watching`: what to do, and the pull request.
4595
- watch: z19.object({
4596
- action: z19.enum(["watch", "unwatch", "list"]),
4597
- url: z19.string().min(1).max(500).optional()
4682
+ watch: z20.object({
4683
+ action: z20.enum(["watch", "unwatch", "list"]),
4684
+ url: z20.string().min(1).max(500).optional()
4598
4685
  }).optional(),
4599
4686
  // `herd delegate`, `herd tell` and `herd handoff`: the worker or conversation they name.
4600
- worker: z19.string().min(1).max(200).optional(),
4601
- to: z19.string().min(1).max(200).optional(),
4687
+ worker: z20.string().min(1).max(200).optional(),
4688
+ to: z20.string().min(1).max(200).optional(),
4602
4689
  // `herd automations`: what to do, to which automation, and the definition or change it sends.
4603
- automation: z19.object({
4604
- action: z19.enum([
4690
+ automation: z20.object({
4691
+ action: z20.enum([
4605
4692
  "list",
4606
4693
  "show",
4607
4694
  "create",
@@ -4612,47 +4699,47 @@ var localRequestSchema = z19.object({
4612
4699
  "test",
4613
4700
  "rotate"
4614
4701
  ]),
4615
- id: z19.string().min(1).max(100).optional(),
4616
- body: z19.record(z19.string(), z19.unknown()).optional(),
4617
- waitMs: z19.number().int().min(0).max(6e5).optional()
4702
+ id: z20.string().min(1).max(100).optional(),
4703
+ body: z20.record(z20.string(), z20.unknown()).optional(),
4704
+ waitMs: z20.number().int().min(0).max(6e5).optional()
4618
4705
  }).optional(),
4619
4706
  // `herd work`: list, record or remove one, with the change the daemon checks again.
4620
- work: z19.object({
4621
- action: z19.enum(["list", "record", "remove"]),
4622
- change: z19.unknown().optional(),
4623
- url: z19.string().min(1).max(2048).optional()
4707
+ work: z20.object({
4708
+ action: z20.enum(["list", "record", "remove"]),
4709
+ change: z20.unknown().optional(),
4710
+ url: z20.string().min(1).max(2048).optional()
4624
4711
  }).optional(),
4625
4712
  // `herd conversations --about <url>`: only the owner's conversations about that URL.
4626
- about: z19.string().min(1).max(2048).optional(),
4713
+ about: z20.string().min(1).max(2048).optional(),
4627
4714
  // `herd investigate screen` or `herd investigate propose`, with the proposal the daemon checks.
4628
- action: z19.enum(["screen", "propose"]).optional(),
4629
- proposal: z19.unknown().optional(),
4715
+ action: z20.enum(["screen", "propose"]).optional(),
4716
+ proposal: z20.unknown().optional(),
4630
4717
  // Commands may name a conversation, but only their own is ever allowed.
4631
- conversationId: z19.string().optional(),
4718
+ conversationId: z20.string().optional(),
4632
4719
  // Where `conversations` is shown, which decides whether private titles are. Only the terminal's
4633
4720
  // own conversation is ever allowed, so a terminal can't pick one that shows more.
4634
- for: z19.string().optional(),
4635
- text: z19.string().optional(),
4721
+ for: z20.string().optional(),
4722
+ text: z20.string().optional(),
4636
4723
  // A whole message, from `herd send --json`, which the daemon checks again.
4637
- message: z19.unknown().optional(),
4638
- idempotencyKey: z19.string().optional(),
4639
- command: z19.array(z19.string()).optional(),
4724
+ message: z20.unknown().optional(),
4725
+ idempotencyKey: z20.string().optional(),
4726
+ command: z20.array(z20.string()).optional(),
4640
4727
  // `status --clear`.
4641
- clear: z19.boolean().optional(),
4728
+ clear: z20.boolean().optional(),
4642
4729
  // What an agent's status line reported, checked by the daemon.
4643
- usage: z19.unknown().optional(),
4730
+ usage: z20.unknown().optional(),
4644
4731
  // Which agent and session a status line ran for. Its reports count only from the session herd
4645
4732
  // started in the conversation's lead terminal.
4646
- agent: z19.enum(["claude-code", "codex", "agy"]).optional(),
4647
- sessionId: z19.string().min(1).max(200).optional(),
4733
+ agent: z20.enum(["claude-code", "codex", "agy"]).optional(),
4734
+ sessionId: z20.string().min(1).max(200).optional(),
4648
4735
  // What agy's status line says its agent is doing: `working` or `idle`.
4649
- state: z19.enum(["working", "idle"]).optional(),
4736
+ state: z20.enum(["working", "idle"]).optional(),
4650
4737
  // A permission request from Claude Code's hook, with the key it keeps across reconnects.
4651
- key: z19.string().min(1).max(200).optional(),
4652
- request: z19.unknown().optional(),
4738
+ key: z20.string().min(1).max(200).optional(),
4739
+ request: z20.unknown().optional(),
4653
4740
  // For one of Claude Code's other hooks: which event, and the JSON Claude Code gave it.
4654
- event: z19.string().optional(),
4655
- input: z19.record(z19.string(), z19.unknown()).optional()
4741
+ event: z20.string().optional(),
4742
+ input: z20.record(z20.string(), z20.unknown()).optional()
4656
4743
  });
4657
4744
  var LocalSocket = class {
4658
4745
  constructor(path, handle) {
@@ -4774,10 +4861,10 @@ function isAnswering(path) {
4774
4861
  }
4775
4862
 
4776
4863
  // src/permissions.ts
4777
- var hookRequestSchema = z20.looseObject({
4778
- tool_name: z20.string().min(1),
4779
- tool_input: z20.record(z20.string(), z20.unknown()).default({}),
4780
- permission_suggestions: z20.array(z20.unknown()).optional()
4864
+ var hookRequestSchema = z21.looseObject({
4865
+ tool_name: z21.string().min(1),
4866
+ tool_input: z21.record(z21.string(), z21.unknown()).default({}),
4867
+ permission_suggestions: z21.array(z21.unknown()).optional()
4781
4868
  });
4782
4869
  var DETAIL_LIMIT = 2800;
4783
4870
  var REPLY_MESSAGE_LIMIT = 2e3;
@@ -5227,9 +5314,9 @@ var activationTerminal = (agent) => `herd-activate-${agentShortName(agent)}`;
5227
5314
  var activationFolder = (root, agent) => join8(convosHome(root), ".activate", agentShortName(agent));
5228
5315
  var recordSchema = agentActivationSchema.extend({
5229
5316
  /** While it's waiting: the terminal it runs in, which `friday start` can attach to. */
5230
- terminal: z21.string().optional()
5317
+ terminal: z22.string().optional()
5231
5318
  });
5232
- var storeSchema = z21.object({ agents: z21.record(z21.string(), recordSchema) });
5319
+ var storeSchema = z22.object({ agents: z22.record(z22.string(), recordSchema) });
5233
5320
  var activationsPath = (home = herdHome()) => join8(home, "activations.json");
5234
5321
  var activationRequestPath = (home = herdHome()) => join8(home, "activate-request");
5235
5322
  function readActivations(path = activationsPath()) {
@@ -6966,7 +7053,7 @@ function defaults() {
6966
7053
  print: (line2) => console.log(line2)
6967
7054
  };
6968
7055
  }
6969
- var releaseSchema = z22.object({ version: z22.string().min(1), integrity: z22.string().min(1) });
7056
+ var releaseSchema = z23.object({ version: z23.string().min(1), integrity: z23.string().min(1) });
6970
7057
  async function fetchRelease() {
6971
7058
  const response = await apiFetch("/api/daemon/release");
6972
7059
  if (response.status === 404) return null;
@@ -7607,11 +7694,11 @@ init_define_HERD_PACKAGE();
7607
7694
  // src/investigator.ts
7608
7695
  init_define_HERD_PACKAGE();
7609
7696
  init_src();
7610
- import { z as z23 } from "zod";
7697
+ import { z as z24 } from "zod";
7611
7698
  var INVESTIGATE_KEYS = ["escape", "up", "down", "enter", "tab"];
7612
- var proposalSchema = z23.object({
7613
- key: z23.enum([...INVESTIGATE_KEYS, "none"]),
7614
- reason: z23.string().trim().min(1).max(300)
7699
+ var proposalSchema = z24.object({
7700
+ key: z24.enum([...INVESTIGATE_KEYS, "none"]),
7701
+ reason: z24.string().trim().min(1).max(300)
7615
7702
  });
7616
7703
  var KEY_LABELS = {
7617
7704
  escape: "Esc",
@@ -8021,12 +8108,12 @@ init_define_HERD_PACKAGE();
8021
8108
  init_src();
8022
8109
  import { chmodSync as chmodSync3, existsSync as existsSync14, mkdirSync as mkdirSync14, readFileSync as readFileSync14, writeFileSync as writeFileSync10 } from "node:fs";
8023
8110
  import { join as join19 } from "node:path";
8024
- import { z as z24 } from "zod";
8111
+ import { z as z25 } from "zod";
8025
8112
  var BUILDS_URL = "https://builds.herdingchats.com";
8026
- var runnerKeySchema = z24.object({
8027
- runnerId: z24.string().min(1),
8028
- key: z24.string().min(20),
8029
- url: z24.string().url()
8113
+ var runnerKeySchema = z25.object({
8114
+ runnerId: z25.string().min(1),
8115
+ key: z25.string().min(20),
8116
+ url: z25.string().url()
8030
8117
  });
8031
8118
  var runnerKeyPath = () => join19(herdHome(), "build-runner.json");
8032
8119
  function readRunnerKey() {
@@ -8095,33 +8182,33 @@ async function registerRunner({
8095
8182
 
8096
8183
  // src/build-speed.ts
8097
8184
  init_define_HERD_PACKAGE();
8098
- import { z as z25 } from "zod";
8099
- var ms = z25.number().int().nullable();
8100
- var figuresSchema = z25.object({ count: z25.number().int(), median: ms, p90: ms });
8101
- var buildTimesSchema = z25.object({ run: figuresSchema, push: figuresSchema });
8102
- var stepFiguresSchema = z25.object({
8103
- ran: z25.number().int(),
8104
- remembered: z25.number().int(),
8185
+ import { z as z26 } from "zod";
8186
+ var ms = z26.number().int().nullable();
8187
+ var figuresSchema = z26.object({ count: z26.number().int(), median: ms, p90: ms });
8188
+ var buildTimesSchema = z26.object({ run: figuresSchema, push: figuresSchema });
8189
+ var stepFiguresSchema = z26.object({
8190
+ ran: z26.number().int(),
8191
+ remembered: z26.number().int(),
8105
8192
  median: ms,
8106
8193
  p90: ms,
8107
- overBudget: z25.number().int()
8194
+ overBudget: z26.number().int()
8108
8195
  });
8109
- var kindSchema = z25.object({
8110
- builds: z25.object({ current: buildTimesSchema, previous: buildTimesSchema }),
8111
- steps: z25.array(
8112
- z25.object({ label: z25.string(), current: stepFiguresSchema, previous: stepFiguresSchema })
8196
+ var kindSchema = z26.object({
8197
+ builds: z26.object({ current: buildTimesSchema, previous: buildTimesSchema }),
8198
+ steps: z26.array(
8199
+ z26.object({ label: z26.string(), current: stepFiguresSchema, previous: stepFiguresSchema })
8113
8200
  ),
8114
- overBudget: z25.array(
8115
- z25.object({ label: z25.string(), current: z25.number().int(), previous: z25.number().int() })
8201
+ overBudget: z26.array(
8202
+ z26.object({ label: z26.string(), current: z26.number().int(), previous: z26.number().int() })
8116
8203
  )
8117
8204
  });
8118
- var range = z25.object({ from: z25.number(), to: z25.number() });
8119
- var speedReportSchema = z25.object({
8120
- periods: z25.object({ current: range, previous: range }),
8121
- repos: z25.array(
8122
- z25.object({
8123
- repo: z25.string(),
8124
- capped: z25.boolean(),
8205
+ var range = z26.object({ from: z26.number(), to: z26.number() });
8206
+ var speedReportSchema = z26.object({
8207
+ periods: z26.object({ current: range, previous: range }),
8208
+ repos: z26.array(
8209
+ z26.object({
8210
+ repo: z26.string(),
8211
+ capped: z26.boolean(),
8125
8212
  pullRequests: kindSchema,
8126
8213
  main: kindSchema
8127
8214
  })
@@ -10847,7 +10934,7 @@ init_define_HERD_PACKAGE();
10847
10934
  init_src();
10848
10935
  init_self();
10849
10936
  import { join as join28 } from "node:path";
10850
- import { z as z26 } from "zod";
10937
+ import { z as z27 } from "zod";
10851
10938
  function hasThread(events) {
10852
10939
  return events.some(
10853
10940
  (event2) => event2.type === "prompt.opened" || event2.type === "message.created" && !(event2.payload.direction === "inbound" && event2.payload.automation) && !event2.payload.quiet && !event2.payload.post
@@ -10913,16 +11000,16 @@ var WAITING_NOTIFICATIONS = /* @__PURE__ */ new Set([
10913
11000
  "agent_needs_input",
10914
11001
  "elicitation_dialog"
10915
11002
  ]);
10916
- var agentMessageSchema = z26.object({
10917
- text: z26.string().trim().min(1).max(12e3),
10918
- files: z26.array(z26.object({ path: z26.string().min(1), title: z26.string().optional() })).max(10).optional()
11003
+ var agentMessageSchema = z27.object({
11004
+ text: z27.string().trim().min(1).max(12e3),
11005
+ files: z27.array(z27.object({ path: z27.string().min(1), title: z27.string().optional() })).max(10).optional()
10919
11006
  });
10920
- var workspaceRepoSchema = z26.object({
10921
- folder: z26.string(),
10922
- remote: z26.string(),
10923
- branch: z26.string(),
11007
+ var workspaceRepoSchema = z27.object({
11008
+ folder: z27.string(),
11009
+ remote: z27.string(),
11010
+ branch: z27.string(),
10924
11011
  /** For a conversation from before folders: the name of the repo it was allowed as. */
10925
- name: z26.string().optional()
11012
+ name: z27.string().optional()
10926
11013
  });
10927
11014
  function fromBeforeFolders(raw) {
10928
11015
  if (!raw || typeof raw !== "object" || "folder" in raw) return raw;
@@ -10943,106 +11030,106 @@ function fromBeforeFolders(raw) {
10943
11030
  legacy: true
10944
11031
  };
10945
11032
  }
10946
- var workspaceFields = z26.object({
10947
- conversationId: z26.string(),
11033
+ var workspaceFields = z27.object({
11034
+ conversationId: z27.string(),
10948
11035
  /** The conversation's own folder, where its terminals start. */
10949
- folder: z26.string(),
11036
+ folder: z27.string(),
10950
11037
  /** The repos in it, in the order they were added. */
10951
- worktrees: z26.array(workspaceRepoSchema).default([]),
11038
+ worktrees: z27.array(workspaceRepoSchema).default([]),
10952
11039
  /** A conversation from before folders, which works in its one repo's worktree. */
10953
- legacy: z26.boolean().default(false),
10954
- lead: z26.string(),
10955
- secret: z26.string(),
10956
- readSeq: z26.number(),
10957
- claimId: z26.string().nullable(),
10958
- claimRenewedAt: z26.number(),
10959
- started: z26.boolean(),
11040
+ legacy: z27.boolean().default(false),
11041
+ lead: z27.string(),
11042
+ secret: z27.string(),
11043
+ readSeq: z27.number(),
11044
+ claimId: z27.string().nullable(),
11045
+ claimRenewedAt: z27.number(),
11046
+ started: z27.boolean(),
10960
11047
  /** Messages to deliver once the current turn ends. */
10961
- deferred: z26.boolean(),
11048
+ deferred: z27.boolean(),
10962
11049
  /** A `herd run` command finished, which the agent hears about even with nothing to claim. */
10963
- terminalNotice: z26.boolean().default(false),
10964
- status: z26.string().nullable(),
11050
+ terminalNotice: z27.boolean().default(false),
11051
+ status: z27.string().nullable(),
10965
11052
  /** Set once the thread has been told the agent is waiting, so it's told once per wait. */
10966
- toldWaiting: z26.boolean(),
10967
- runs: z26.array(z26.object({ name: z26.string(), secret: z26.string(), reported: z26.boolean() })),
11053
+ toldWaiting: z27.boolean(),
11054
+ runs: z27.array(z27.object({ name: z27.string(), secret: z27.string(), reported: z27.boolean() })),
10968
11055
  /** The subscription usage Claude Code last reported in this worktree. */
10969
11056
  usage: usageSchema.nullable().default(null),
10970
11057
  /** When that usage was reported, or 0 if it was before this was kept. */
10971
- usageAt: z26.number().default(0),
11058
+ usageAt: z27.number().default(0),
10972
11059
  /** The lead agent's Claude Code session, as its `SessionStart` hook reported it. */
10973
- sessionId: z26.string().nullable().default(null),
11060
+ sessionId: z27.string().nullable().default(null),
10974
11061
  /** When the agent's last turn ended with nothing left to do, for shutting it down later. */
10975
- idleSince: z26.number().nullable().default(null),
11062
+ idleSince: z27.number().nullable().default(null),
10976
11063
  /** The agent ran `herd exit`, so its session ends after this turn. */
10977
- exitRequested: z26.boolean().default(false),
11064
+ exitRequested: z27.boolean().default(false),
10978
11065
  /** Whether the agent sent anything with `herd send` this turn. */
10979
- sentThisTurn: z26.boolean().default(false),
11066
+ sentThisTurn: z27.boolean().default(false),
10980
11067
  /** Whether it's been asked this turn to reply. */
10981
- askedToReply: z26.boolean().default(false),
11068
+ askedToReply: z27.boolean().default(false),
10982
11069
  /** Whether it ran `herd handled` this turn, which handles the turn's messages with no reply. */
10983
- handledThisTurn: z26.boolean().default(false),
11070
+ handledThisTurn: z27.boolean().default(false),
10984
11071
  /** The newest waiting message it's been pointed at, so one arrival is pointed out once. */
10985
- nudgedSeq: z26.number().default(0),
11072
+ nudgedSeq: z27.number().default(0),
10986
11073
  /** When a `Stop` hook last ended a turn. */
10987
- hookIdleAt: z26.number().default(0),
11074
+ hookIdleAt: z27.number().default(0),
10988
11075
  /** When a turn last ended with background work still running, which keeps its messages held. */
10989
- pausedAt: z26.number().nullable().default(null),
11076
+ pausedAt: z27.number().nullable().default(null),
10990
11077
  /** The version of the terminal host the lead terminal was opened in, if it was recorded. */
10991
- hostVersion: z26.string().nullable().default(null),
11078
+ hostVersion: z27.string().nullable().default(null),
10992
11079
  /** When a notice last failed for a reason other than someone's draft, to wait before retrying. */
10993
- noticeFailedAt: z26.number().nullable().default(null),
11080
+ noticeFailedAt: z27.number().nullable().default(null),
10994
11081
  /** Why the last notice failed, so the history records each reason once, not every attempt. */
10995
- noticeFailure: z26.string().nullable().default(null),
11082
+ noticeFailure: z27.string().nullable().default(null),
10996
11083
  /** A recorded dialog herd pressed its way out of, so a dialog that stays isn't pressed again. */
10997
- closedDialog: z26.string().nullable().default(null),
11084
+ closedDialog: z27.string().nullable().default(null),
10998
11085
  /**
10999
11086
  * Prompts Claude Code's hooks reported that haven't had their `Stop`. A turn is open while this
11000
11087
  * is above zero. It's a count because a prompt queued mid-turn is reported as it's queued, and
11001
11088
  * runs as a turn of its own, ending with a second `Stop`.
11002
11089
  */
11003
- promptsOpen: z26.number().default(0),
11090
+ promptsOpen: z27.number().default(0),
11004
11091
  /** The messages the latest claim or addition took, for choosing which notice to type. */
11005
- claimedSeqs: z26.array(z26.number()).default([]),
11092
+ claimedSeqs: z27.array(z27.number()).default([]),
11006
11093
  /** The investigator looking at a screen herd can't read, from opening to the owner's answer. */
11007
- investigation: z26.object({
11008
- terminal: z26.string(),
11009
- secret: z26.string(),
11010
- startedAt: z26.number(),
11094
+ investigation: z27.object({
11095
+ terminal: z27.string(),
11096
+ secret: z27.string(),
11097
+ startedAt: z27.number(),
11011
11098
  /** The stuck screen when it opened, saved with the key if the owner approves one. */
11012
- screen: z26.array(z26.string()),
11013
- key: z26.string().nullable(),
11014
- promptId: z26.string().nullable()
11099
+ screen: z27.array(z27.string()),
11100
+ key: z27.string().nullable(),
11101
+ promptId: z27.string().nullable()
11015
11102
  }).nullable().default(null),
11016
11103
  /** The failed notice an investigator was opened for, so each failure gets one. */
11017
- investigatedFailure: z26.number().nullable().default(null),
11104
+ investigatedFailure: z27.number().nullable().default(null),
11018
11105
  /** The agent CLI this conversation's worker runs, as its offer named it. */
11019
- agent: z26.string().default("claude-code"),
11106
+ agent: z27.string().default("claude-code"),
11020
11107
  /** Whether what the current claim took needs a reply, which other agents' messages don't. */
11021
- replyWanted: z26.boolean().default(true),
11108
+ replyWanted: z27.boolean().default(true),
11022
11109
  /** For a delegate: the conversation that started it, which its starting prompt names. */
11023
- parent: z26.string().nullable().default(null),
11110
+ parent: z27.string().nullable().default(null),
11024
11111
  /** Codex's session file for this worktree, once found, and how far the daemon has read it. */
11025
- codexFile: z26.string().nullable().default(null),
11026
- codexOffset: z26.number().default(0),
11112
+ codexFile: z27.string().nullable().default(null),
11113
+ codexOffset: z27.number().default(0),
11027
11114
  /** When the agent was last started, so Codex's new session file is told from older ones. */
11028
- agentStartedAt: z26.number().default(0),
11115
+ agentStartedAt: z27.number().default(0),
11029
11116
  /**
11030
11117
  * The key the agent was last started with, as `HERD_START`. Its `herd inbox` carrying this key
11031
11118
  * is what proves the start works: never a hook, a prompt being taken, or the screen.
11032
11119
  */
11033
- startKey: z26.string().nullable().default(null),
11120
+ startKey: z27.string().nullable().default(null),
11034
11121
  /** Whether the current start has checked in. One from before keys counts as proven. */
11035
- startProven: z26.boolean().default(true),
11122
+ startProven: z27.boolean().default(true),
11036
11123
  /** When the check-in window of an unproven start began, or null once it's proven or for none. */
11037
- checkInFrom: z26.number().nullable().default(null),
11124
+ checkInFrom: z27.number().nullable().default(null),
11038
11125
  /** Whether this start has been flagged as needing someone at its terminal, so it's said once. */
11039
- needsAttention: z26.boolean().default(false),
11126
+ needsAttention: z27.boolean().default(false),
11040
11127
  /** What agy's status line last said its agent was doing, and when. */
11041
- agentState: z26.enum(["working", "idle"]).nullable().default(null),
11042
- agentStateAt: z26.number().default(0)
11128
+ agentState: z27.enum(["working", "idle"]).nullable().default(null),
11129
+ agentStateAt: z27.number().default(0)
11043
11130
  });
11044
- var workspaceSchema = z26.preprocess(fromBeforeFolders, workspaceFields);
11045
- var stateSchema = z26.object({ workspaces: z26.record(z26.string(), workspaceSchema) });
11131
+ var workspaceSchema = z27.preprocess(fromBeforeFolders, workspaceFields);
11132
+ var stateSchema = z27.object({ workspaces: z27.record(z27.string(), workspaceSchema) });
11046
11133
 
11047
11134
  // src/workspaces/claims.ts
11048
11135
  var holder = (ws, workspace) => `${ws.options.machineName()}/${workspace.lead}`;
@@ -11123,7 +11210,7 @@ import { join as join29 } from "node:path";
11123
11210
 
11124
11211
  // src/commands/repo.ts
11125
11212
  init_define_HERD_PACKAGE();
11126
- import { z as z27 } from "zod";
11213
+ import { z as z28 } from "zod";
11127
11214
  var REPO_HELP = `Usage: herd repo <url or owner/name> [folder]
11128
11215
 
11129
11216
  Checks a repo out in this conversation's folder, on a branch named for the conversation, started
@@ -11137,16 +11224,16 @@ var REPOS_HELP = `Usage: herd repos [--json]
11137
11224
 
11138
11225
  Lists the repos in this conversation's folder, the repos checked out in this machine's root, and
11139
11226
  the repos your owner's herd.config.ts describes, with what each is for. Add one with herd repo.`;
11140
- var repoContextSchema = z27.object({
11141
- folder: z27.string(),
11142
- root: z27.string(),
11143
- branch: z27.string(),
11144
- legacy: z27.boolean(),
11145
- legacyReason: z27.string().optional(),
11146
- recorded: z27.array(z27.object({ folder: z27.string(), remote: z27.string(), branch: z27.string() })),
11147
- cloned: z27.array(z27.object({ key: z27.string(), remote: z27.string() })),
11148
- described: z27.array(
11149
- z27.object({ remote: z27.string(), key: z27.string().nullable(), about: z27.string().optional() })
11227
+ var repoContextSchema = z28.object({
11228
+ folder: z28.string(),
11229
+ root: z28.string(),
11230
+ branch: z28.string(),
11231
+ legacy: z28.boolean(),
11232
+ legacyReason: z28.string().optional(),
11233
+ recorded: z28.array(z28.object({ folder: z28.string(), remote: z28.string(), branch: z28.string() })),
11234
+ cloned: z28.array(z28.object({ key: z28.string(), remote: z28.string() })),
11235
+ described: z28.array(
11236
+ z28.object({ remote: z28.string(), key: z28.string().nullable(), about: z28.string().optional() })
11150
11237
  )
11151
11238
  });
11152
11239
  var isUrl = (text4) => /^[a-z][a-z0-9+.-]*:\/\//i.test(text4) || text4.startsWith("/") || /^[^@/\s]+@[^:/\s]+:/.test(text4);
@@ -11203,7 +11290,7 @@ async function runRepo(rest) {
11203
11290
  op: "repo-add",
11204
11291
  repoAdd: { asked, ...folderName !== void 0 ? { folder: folderName } : {} }
11205
11292
  });
11206
- const lines = z27.array(z27.string()).safeParse(reply.lines);
11293
+ const lines = z28.array(z28.string()).safeParse(reply.lines);
11207
11294
  if (!lines.success) throw new HerdError("The daemon's answer about this repo wasn't readable.");
11208
11295
  console.log(lines.data.join("\n"));
11209
11296
  return 0;
@@ -12382,21 +12469,21 @@ function resolveAttachments(worktree, files) {
12382
12469
  // src/workers.ts
12383
12470
  init_define_HERD_PACKAGE();
12384
12471
  init_src();
12385
- import { z as z28 } from "zod";
12386
- var workerListingSchema = z28.object({
12387
- workers: z28.array(workerSchema),
12388
- machines: z28.array(
12389
- z28.object({
12390
- id: z28.string(),
12391
- name: z28.string(),
12392
- online: z28.boolean(),
12393
- missing: z28.array(z28.string()),
12394
- configError: z28.string().optional(),
12472
+ import { z as z29 } from "zod";
12473
+ var workerListingSchema = z29.object({
12474
+ workers: z29.array(workerSchema),
12475
+ machines: z29.array(
12476
+ z29.object({
12477
+ id: z29.string(),
12478
+ name: z29.string(),
12479
+ online: z29.boolean(),
12480
+ missing: z29.array(z29.string()),
12481
+ configError: z29.string().optional(),
12395
12482
  // Servers from before versions were reported send none.
12396
- herdVersion: z28.string().nullable().optional()
12483
+ herdVersion: z29.string().nullable().optional()
12397
12484
  })
12398
12485
  ),
12399
- configType: z28.string()
12486
+ configType: z29.string()
12400
12487
  });
12401
12488
  async function readWorkers(fetch2) {
12402
12489
  const response = await fetch2("/api/workers");
@@ -12464,20 +12551,20 @@ function formatWorkers(listing, current = null) {
12464
12551
  );
12465
12552
  return lines.join("\n");
12466
12553
  }
12467
- var routingCheckSchema = z28.object({
12468
- suits: z28.array(z28.object({ key: z28.string(), name: z28.string() })),
12469
- eligible: z28.array(z28.object({ key: z28.string(), name: z28.string() })),
12470
- removed: z28.array(z28.object({ key: z28.string(), name: z28.string(), rule: z28.string() })),
12471
- questions: z28.array(
12472
- z28.object({ id: z28.string(), question: z28.string(), probability: z28.number().nullable() })
12554
+ var routingCheckSchema = z29.object({
12555
+ suits: z29.array(z29.object({ key: z29.string(), name: z29.string() })),
12556
+ eligible: z29.array(z29.object({ key: z29.string(), name: z29.string() })),
12557
+ removed: z29.array(z29.object({ key: z29.string(), name: z29.string(), rule: z29.string() })),
12558
+ questions: z29.array(
12559
+ z29.object({ id: z29.string(), question: z29.string(), probability: z29.number().nullable() })
12473
12560
  ),
12474
- fallback: z28.string().optional(),
12475
- fits: z28.array(
12476
- z28.object({
12477
- key: z28.string(),
12478
- fit: z28.number(),
12479
- statement: z28.string().optional(),
12480
- level: z28.string().optional()
12561
+ fallback: z29.string().optional(),
12562
+ fits: z29.array(
12563
+ z29.object({
12564
+ key: z29.string(),
12565
+ fit: z29.number(),
12566
+ statement: z29.string().optional(),
12567
+ level: z29.string().optional()
12481
12568
  })
12482
12569
  ).optional()
12483
12570
  });
@@ -13332,8 +13419,8 @@ async function download(ws, workspace, file) {
13332
13419
  Readable.fromWeb(response.body),
13333
13420
  createWriteStream(partial, { flags: "wx" })
13334
13421
  );
13335
- const { size } = statSync10(partial);
13336
- if (size !== file.size) throw new Error(`it came to ${size} bytes, not ${file.size}`);
13422
+ const { size: size2 } = statSync10(partial);
13423
+ if (size2 !== file.size) throw new Error(`it came to ${size2} bytes, not ${file.size}`);
13337
13424
  renameSync7(partial, target);
13338
13425
  } finally {
13339
13426
  rmSync17(partial, { force: true });
@@ -14598,7 +14685,7 @@ var DETACH_KEY = "";
14598
14685
  function attach(name, { stdin, stdout } = { stdin: process.stdin, stdout: process.stdout }, path = currentHostSocketPath(), { watch: watch2 = false } = {}) {
14599
14686
  return new Promise((resolve8, reject) => {
14600
14687
  const socket = connect4(path);
14601
- const size = () => ({ cols: stdout.columns || 120, rows: stdout.rows || 40 });
14688
+ const size2 = () => ({ cols: stdout.columns || 120, rows: stdout.rows || 40 });
14602
14689
  let buffer = "";
14603
14690
  let started = false;
14604
14691
  let ended = false;
@@ -14623,12 +14710,12 @@ function attach(name, { stdin, stdout } = { stdin: process.stdin, stdout: proces
14623
14710
  finish("detached");
14624
14711
  }
14625
14712
  };
14626
- const onResize = () => socket.write(`${JSON.stringify({ type: "resize", ...size() })}
14713
+ const onResize = () => socket.write(`${JSON.stringify({ type: "resize", ...size2() })}
14627
14714
  `);
14628
14715
  socket.on(
14629
14716
  "connect",
14630
14717
  () => socket.write(
14631
- `${JSON.stringify(watch2 ? { op: "watch", name } : { op: "attach", name, ...size() })}
14718
+ `${JSON.stringify(watch2 ? { op: "watch", name } : { op: "attach", name, ...size2() })}
14632
14719
  `
14633
14720
  )
14634
14721
  );
@@ -14901,7 +14988,7 @@ async function runWatch(command, rest) {
14901
14988
  // src/commands/work.ts
14902
14989
  init_define_HERD_PACKAGE();
14903
14990
  init_src();
14904
- import { z as z34 } from "zod";
14991
+ import { z as z35 } from "zod";
14905
14992
  var WORK_HELP = `Usage: herd work <url> [--kind <kind>] [--title "<title>"] [--status <status>]
14906
14993
  [--detail "<detail>"] [--made] [--phase <phase>]
14907
14994
  herd work --remove <url>
@@ -14993,9 +15080,9 @@ ${WORK_HELP}`
14993
15080
  };
14994
15081
  return { kind: "record", change, json };
14995
15082
  }
14996
- var followSchema = z34.union([
14997
- z34.object({ following: z34.literal(true) }),
14998
- z34.object({ following: z34.literal(false), reason: z34.string() })
15083
+ var followSchema = z35.union([
15084
+ z35.object({ following: z35.literal(true) }),
15085
+ z35.object({ following: z35.literal(false), reason: z35.string() })
14999
15086
  ]);
15000
15087
  function formatFollow(follow) {
15001
15088
  return follow.following ? "Following it: its reviews, CI and merge will reach herd inbox." : `Not followed: ${follow.reason}`;
@@ -15011,7 +15098,7 @@ function formatWork(work, own) {
15011
15098
  return ` ${parts.join(" \xB7 ")}${work.made ? " made here" : ""}
15012
15099
  ${work.url}${whose}`;
15013
15100
  }
15014
- var listSchema = z34.array(workObjectSchema);
15101
+ var listSchema = z35.array(workObjectSchema);
15015
15102
  async function runWork(rest) {
15016
15103
  const parsed = parseWork(rest);
15017
15104
  if (parsed.kind === "help") {