@paradow/ledge 0.36.0 → 0.38.0

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.
@@ -728,8 +728,12 @@ var ProjectsSchema = z14.object({ projects: z14.array(ProjectSchema).max(100), r
728
728
  for (const problem of projectsProblems(p)) ctx.addIssue({ code: "custom", message: problem.code, path: problem.path });
729
729
  });
730
730
 
731
+ // ../protocol/src/broadcast.ts
732
+ var BROADCAST_SESSIONS_MAX = 32;
733
+ var BROADCAST_LABEL_MAX = 120;
734
+
731
735
  // ../protocol/src/messages.ts
732
- import { z as z22 } from "zod";
736
+ import { z as z24 } from "zod";
733
737
 
734
738
  // ../protocol/src/repos.ts
735
739
  import { z as z15 } from "zod";
@@ -742,437 +746,724 @@ var ReposInspectSchema = z15.object({
742
746
  var RepoInfoSchema = z15.object({ path: z15.string(), exists: z15.boolean(), branch: z15.string().nullable() });
743
747
  var ReposInfoSchema = z15.object({ type: z15.literal("repos.info"), requestId: z15.string(), repos: z15.array(RepoInfoSchema) });
744
748
 
745
- // ../protocol/src/scan.ts
749
+ // ../protocol/src/commands.ts
746
750
  import { z as z16 } from "zod";
747
- var ReposScanSchema = z16.object({ type: z16.literal("repos.scan"), requestId: z16.string().min(1).max(100), machineId: z16.string().optional() });
748
- var FoundRepoSchema = z16.object({ path: z16.string(), branch: z16.string().nullable(), remote: z16.string().optional(), manifest: z16.string().max(200).optional() });
749
- var ReposFoundSchema = z16.object({ type: z16.literal("repos.found"), requestId: z16.string(), repos: z16.array(FoundRepoSchema).max(500), truncated: z16.boolean(), error: z16.string().optional() });
751
+ var SlashSourceSchema = z16.enum(["builtin", "project", "user", "plugin", "extension"]);
752
+ var SLASH_COMMANDS_MAX = 400;
753
+ var SLASH_DESCRIPTION_MAX = 300;
754
+ var SlashCommandSchema = z16.object({
755
+ name: z16.string().min(1).max(200),
756
+ description: z16.string().max(SLASH_DESCRIPTION_MAX).optional(),
757
+ argumentHint: z16.string().max(200).optional(),
758
+ aliases: z16.array(z16.string().min(1).max(200)).max(10).optional(),
759
+ source: SlashSourceSchema,
760
+ blocked: z16.enum(["panel", "close"]).optional(),
761
+ bare: z16.literal("panel").optional()
762
+ });
763
+ var SessionCommandsSchema = z16.object({ type: z16.literal("session.commands"), requestId: z16.string().min(1).max(100), id: z16.string() });
764
+ var SessionCommandsListingSchema = z16.object({
765
+ type: z16.literal("session.commands.listing"),
766
+ requestId: z16.string(),
767
+ id: z16.string(),
768
+ tool: ToolSchema.optional(),
769
+ commands: z16.array(SlashCommandSchema).max(SLASH_COMMANDS_MAX),
770
+ error: z16.string().max(200).optional()
771
+ });
750
772
 
751
- // ../protocol/src/openrig.ts
773
+ // ../protocol/src/scan.ts
752
774
  import { z as z17 } from "zod";
753
- var RigNameSchema = z17.string().min(1).max(100).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "not a rig name");
754
- var RigSeatNameSchema = z17.string().min(3).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*@[A-Za-z0-9][A-Za-z0-9._-]*$/, "not a seat");
755
- var SeatPermissionsSchema = z17.enum(["inherit", "floor", "auto", "full_bypass"]);
756
- var RigSeatSchema = z17.object({
757
- logicalId: z17.string(),
758
- session: z17.string(),
759
- runtime: z17.string(),
760
- model: z17.string().nullable(),
761
- sessionStatus: z17.string(),
762
- lifecycleState: z17.string(),
763
- activity: z17.string(),
764
- stopped: z17.boolean(),
765
- work: z17.number().int().min(0)
766
- });
767
- var RigSchema = z17.object({
768
- id: z17.string(),
769
- name: z17.string(),
770
- status: z17.string(),
771
- lifecycleState: z17.string(),
772
- seats: z17.number().int().min(0),
773
- running: z17.number().int().min(0),
774
- attention: z17.number().int().min(0),
775
- uptime: z17.string().nullable(),
776
- snapshot: z17.string().nullable(),
777
- nodes: z17.array(RigSeatSchema)
778
- });
779
- var RigDaemonStateSchema = z17.enum(["running", "stopped", "stale", "unknown"]);
780
- var RigKernelStateSchema = z17.enum(["ready", "starting", "stopped", "skipped", "absent", "unknown"]);
781
- var OpenRigStateSchema = z17.object({
782
- installed: z17.boolean(),
783
- version: z17.string().optional(),
784
- daemon: z17.object({ state: RigDaemonStateSchema, pid: z17.number().int().optional(), port: z17.number().int().optional(), message: z17.string().optional() }),
785
- kernel: z17.object({ state: RigKernelStateSchema }),
786
- rigs: z17.array(RigSchema),
775
+ var ReposScanSchema = z17.object({ type: z17.literal("repos.scan"), requestId: z17.string().min(1).max(100), machineId: z17.string().optional() });
776
+ var FoundRepoSchema = z17.object({ path: z17.string(), branch: z17.string().nullable(), remote: z17.string().optional(), manifest: z17.string().max(200).optional() });
777
+ var ReposFoundSchema = z17.object({ type: z17.literal("repos.found"), requestId: z17.string(), repos: z17.array(FoundRepoSchema).max(500), truncated: z17.boolean(), error: z17.string().optional() });
778
+
779
+ // ../protocol/src/openrig.ts
780
+ import { z as z18 } from "zod";
781
+ var RigNameSchema = z18.string().min(1).max(100).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "not a rig name");
782
+ var RigSeatNameSchema = z18.string().min(3).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._-]*@[A-Za-z0-9][A-Za-z0-9._-]*$/, "not a seat");
783
+ var SeatPermissionsSchema = z18.enum(["inherit", "floor", "auto", "full_bypass"]);
784
+ var RigSeatSchema = z18.object({
785
+ logicalId: z18.string(),
786
+ session: z18.string(),
787
+ runtime: z18.string(),
788
+ model: z18.string().nullable(),
789
+ sessionStatus: z18.string(),
790
+ lifecycleState: z18.string(),
791
+ activity: z18.string(),
792
+ stopped: z18.boolean(),
793
+ work: z18.number().int().min(0)
794
+ });
795
+ var RigSchema = z18.object({
796
+ id: z18.string(),
797
+ name: z18.string(),
798
+ status: z18.string(),
799
+ lifecycleState: z18.string(),
800
+ seats: z18.number().int().min(0),
801
+ running: z18.number().int().min(0),
802
+ attention: z18.number().int().min(0),
803
+ uptime: z18.string().nullable(),
804
+ snapshot: z18.string().nullable(),
805
+ nodes: z18.array(RigSeatSchema)
806
+ });
807
+ var RigDaemonStateSchema = z18.enum(["running", "stopped", "stale", "unknown"]);
808
+ var RigKernelStateSchema = z18.enum(["ready", "starting", "stopped", "skipped", "absent", "unknown"]);
809
+ var OpenRigStateSchema = z18.object({
810
+ installed: z18.boolean(),
811
+ version: z18.string().optional(),
812
+ daemon: z18.object({ state: RigDaemonStateSchema, pid: z18.number().int().optional(), port: z18.number().int().optional(), message: z18.string().optional() }),
813
+ kernel: z18.object({ state: RigKernelStateSchema }),
814
+ rigs: z18.array(RigSchema),
787
815
  /** When it was read (ISO). */
788
- at: z17.string()
816
+ at: z18.string()
789
817
  });
790
- var OpenRigActionSchema = z17.discriminatedUnion("kind", [
818
+ var OpenRigActionSchema = z18.discriminatedUnion("kind", [
791
819
  /** `restore` `last`: `rig start --last` (the rigs that were running come back); `none`: `rig daemon start`. */
792
- z17.object({ kind: z17.literal("daemon.start"), restore: z17.enum(["last", "none"]).optional(), noKernel: z17.boolean().optional() }),
793
- z17.object({ kind: z17.literal("daemon.stop") }),
794
- z17.object({ kind: z17.literal("daemon.restart"), restore: z17.enum(["last", "none"]).optional() }),
795
- z17.object({ kind: z17.literal("kernel.start") }),
796
- z17.object({ kind: z17.literal("kernel.stop") }),
797
- z17.object({ kind: z17.literal("kernel.restart") }),
798
- z17.object({ kind: z17.literal("rig.start"), rig: RigNameSchema }),
799
- z17.object({ kind: z17.literal("rig.stop"), rig: RigNameSchema, snapshot: z17.boolean().optional(), force: z17.boolean().optional(), delete: z17.boolean().optional() }),
800
- z17.object({ kind: z17.literal("rig.restart"), rig: RigNameSchema }),
820
+ z18.object({ kind: z18.literal("daemon.start"), restore: z18.enum(["last", "none"]).optional(), noKernel: z18.boolean().optional() }),
821
+ z18.object({ kind: z18.literal("daemon.stop") }),
822
+ z18.object({ kind: z18.literal("daemon.restart"), restore: z18.enum(["last", "none"]).optional() }),
823
+ z18.object({ kind: z18.literal("kernel.start") }),
824
+ z18.object({ kind: z18.literal("kernel.stop") }),
825
+ z18.object({ kind: z18.literal("kernel.restart") }),
826
+ z18.object({ kind: z18.literal("rig.start"), rig: RigNameSchema }),
827
+ z18.object({ kind: z18.literal("rig.stop"), rig: RigNameSchema, snapshot: z18.boolean().optional(), force: z18.boolean().optional(), delete: z18.boolean().optional() }),
828
+ z18.object({ kind: z18.literal("rig.restart"), rig: RigNameSchema }),
801
829
  /** A seat's settings (docs/mockups/ledge-openrig-groups.html, view 2). `runtime`: moves it now to the other harness (a successor
802
830
  * takes its context, `rig seat set-runtime`), `model` and `effort` going with it; without it, `model`, `effort` and `permissions`
803
831
  * apply at its next resume. `dryRun`: the move's plan only. */
804
- z17.object({
805
- kind: z17.literal("seat.set"),
832
+ z18.object({
833
+ kind: z18.literal("seat.set"),
806
834
  seat: RigSeatNameSchema,
807
- runtime: z17.enum(["claude-code", "codex"]).optional(),
835
+ runtime: z18.enum(["claude-code", "codex"]).optional(),
808
836
  model: ModelIdSchema.optional(),
809
837
  effort: EffortSchema.optional(),
810
838
  permissions: SeatPermissionsSchema.optional(),
811
- dryRun: z17.boolean().optional()
839
+ dryRun: z18.boolean().optional()
812
840
  })
813
841
  ]);
814
- var OpenRigStatusSchema = z17.object({ type: z17.literal("openrig.status"), requestId: z17.string().min(1).max(100), machineId: z17.string().optional() });
815
- var OpenRigActSchema = z17.object({ type: z17.literal("openrig.act"), requestId: z17.string().min(1).max(100), action: OpenRigActionSchema, machineId: z17.string().optional() });
816
- var OpenRigUnreachableSchema = z17.enum(["offline", "outdated"]);
817
- var OpenRigStateMessageSchema = z17.object({
818
- type: z17.literal("openrig.state"),
819
- requestId: z17.string().optional(),
820
- machineId: z17.string().optional(),
842
+ var OpenRigStatusSchema = z18.object({ type: z18.literal("openrig.status"), requestId: z18.string().min(1).max(100), machineId: z18.string().optional() });
843
+ var OpenRigActSchema = z18.object({ type: z18.literal("openrig.act"), requestId: z18.string().min(1).max(100), action: OpenRigActionSchema, machineId: z18.string().optional() });
844
+ var OpenRigUnreachableSchema = z18.enum(["offline", "outdated"]);
845
+ var OpenRigStateMessageSchema = z18.object({
846
+ type: z18.literal("openrig.state"),
847
+ requestId: z18.string().optional(),
848
+ machineId: z18.string().optional(),
821
849
  state: OpenRigStateSchema.optional(),
822
850
  error: OpenRigUnreachableSchema.optional()
823
851
  });
824
- var OpenRigDoneSchema = z17.object({
825
- type: z17.literal("openrig.done"),
826
- requestId: z17.string(),
827
- machineId: z17.string().optional(),
828
- ok: z17.boolean(),
829
- commands: z17.array(z17.string()),
830
- output: z17.string().optional(),
831
- error: z17.string().optional()
832
- });
833
- var RigSpecMemberSchema = z17.object({
834
- id: z17.string(),
835
- runtime: z17.string(),
836
- model: z17.string().optional(),
837
- agent: z17.string(),
852
+ var OpenRigDoneSchema = z18.object({
853
+ type: z18.literal("openrig.done"),
854
+ requestId: z18.string(),
855
+ machineId: z18.string().optional(),
856
+ ok: z18.boolean(),
857
+ commands: z18.array(z18.string()),
858
+ output: z18.string().optional(),
859
+ error: z18.string().optional()
860
+ });
861
+ var RigSpecMemberSchema = z18.object({
862
+ id: z18.string(),
863
+ runtime: z18.string(),
864
+ model: z18.string().optional(),
865
+ agent: z18.string(),
838
866
  /** Its `permission_policy`, as written. */
839
- policy: z17.string().optional()
840
- });
841
- var RigSpecPodSchema = z17.object({ id: z17.string(), label: z17.string().optional(), members: z17.array(RigSpecMemberSchema) });
842
- var RigSpecSchema = z17.object({
843
- name: z17.string(),
844
- source: z17.string(),
845
- summary: z17.string().optional(),
846
- path: z17.string(),
867
+ policy: z18.string().optional()
868
+ });
869
+ var RigSpecPodSchema = z18.object({ id: z18.string(), label: z18.string().optional(), members: z18.array(RigSpecMemberSchema) });
870
+ var RigSpecSchema = z18.object({
871
+ name: z18.string(),
872
+ source: z18.string(),
873
+ summary: z18.string().optional(),
874
+ path: z18.string(),
847
875
  /** The rig's `permission_policy`, as written (`builtin:auto`, a file…). */
848
- policy: z17.string().optional(),
849
- pods: z17.array(RigSpecPodSchema),
850
- edges: z17.number().int().min(0)
851
- });
852
- var OpenRigSpecsSchema = z17.object({ type: z17.literal("openrig.specs"), requestId: z17.string().min(1).max(100), machineId: z17.string().optional() });
853
- var OpenRigSpecListSchema = z17.object({
854
- type: z17.literal("openrig.specList"),
855
- requestId: z17.string(),
856
- machineId: z17.string().optional(),
857
- specs: z17.array(RigSpecSchema),
858
- error: z17.string().optional()
859
- });
860
- var RigRoleSchema = z17.string().min(3).max(201).regex(/^[A-Za-z0-9][A-Za-z0-9_-]*\.[A-Za-z0-9][A-Za-z0-9_-]*$/, "not a role");
861
- var RuntimeSchema = z17.enum(["claude-code", "codex"]);
862
- var RigPolicySchema = z17.enum(["auto", "standard", "open", "yolo", "locked"]);
876
+ policy: z18.string().optional(),
877
+ pods: z18.array(RigSpecPodSchema),
878
+ edges: z18.number().int().min(0)
879
+ });
880
+ var OpenRigSpecsSchema = z18.object({ type: z18.literal("openrig.specs"), requestId: z18.string().min(1).max(100), machineId: z18.string().optional() });
881
+ var OpenRigSpecListSchema = z18.object({
882
+ type: z18.literal("openrig.specList"),
883
+ requestId: z18.string(),
884
+ machineId: z18.string().optional(),
885
+ specs: z18.array(RigSpecSchema),
886
+ error: z18.string().optional()
887
+ });
888
+ var RigRoleSchema = z18.string().min(3).max(201).regex(/^[A-Za-z0-9][A-Za-z0-9_-]*\.[A-Za-z0-9][A-Za-z0-9_-]*$/, "not a role");
889
+ var RuntimeSchema = z18.enum(["claude-code", "codex"]);
890
+ var RigPolicySchema = z18.enum(["auto", "standard", "open", "yolo", "locked"]);
863
891
  var RIG_POLICIES = RigPolicySchema.options;
864
- var RigLaunchSchema = z17.object({
892
+ var RigLaunchSchema = z18.object({
865
893
  spec: RigNameSchema,
866
- cwd: z17.string().min(1).max(4096),
894
+ cwd: z18.string().min(1).max(4096),
867
895
  name: RigNameSchema,
868
- seats: z17.record(RigRoleSchema, z17.number().int().min(0).max(9)).optional(),
869
- runtimes: z17.record(RigRoleSchema, RuntimeSchema).optional(),
870
- models: z17.record(RigRoleSchema, z17.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:/@[\]=,+-]*$/)).optional(),
871
- delegation: z17.enum(["pairs", "all"]).optional(),
872
- save: z17.boolean().optional(),
873
- plan: z17.boolean().optional(),
896
+ seats: z18.record(RigRoleSchema, z18.number().int().min(0).max(9)).optional(),
897
+ runtimes: z18.record(RigRoleSchema, RuntimeSchema).optional(),
898
+ models: z18.record(RigRoleSchema, z18.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:/@[\]=,+-]*$/)).optional(),
899
+ delegation: z18.enum(["pairs", "all"]).optional(),
900
+ save: z18.boolean().optional(),
901
+ plan: z18.boolean().optional(),
874
902
  /** The rig's permission policy, in place of the spec's; `policies`: a role's, over the rig's. */
875
903
  policy: RigPolicySchema.optional(),
876
- policies: z17.record(RigRoleSchema, RigPolicySchema).optional(),
904
+ policies: z18.record(RigRoleSchema, RigPolicySchema).optional(),
877
905
  /** Accept the harnesses' first-launch warnings (`rig up --non-interruptive`), so a bypassing seat does not stop on Claude's dialog. */
878
- nonInterruptive: z17.boolean().optional()
879
- });
880
- var OpenRigLaunchSchema = z17.object({ type: z17.literal("openrig.launch"), requestId: z17.string().min(1).max(100), launch: RigLaunchSchema, machineId: z17.string().optional() });
881
- var OpenRigLaunchedSchema = z17.object({
882
- type: z17.literal("openrig.launched"),
883
- requestId: z17.string(),
884
- machineId: z17.string().optional(),
885
- ok: z17.boolean(),
886
- plan: z17.boolean(),
887
- commands: z17.array(z17.string()),
888
- yaml: z17.string().optional(),
889
- seats: z17.number().int().optional(),
890
- output: z17.string().optional(),
891
- error: z17.string().optional(),
906
+ nonInterruptive: z18.boolean().optional()
907
+ });
908
+ var OpenRigLaunchSchema = z18.object({ type: z18.literal("openrig.launch"), requestId: z18.string().min(1).max(100), launch: RigLaunchSchema, machineId: z18.string().optional() });
909
+ var OpenRigLaunchedSchema = z18.object({
910
+ type: z18.literal("openrig.launched"),
911
+ requestId: z18.string(),
912
+ machineId: z18.string().optional(),
913
+ ok: z18.boolean(),
914
+ plan: z18.boolean(),
915
+ commands: z18.array(z18.string()),
916
+ yaml: z18.string().optional(),
917
+ seats: z18.number().int().optional(),
918
+ output: z18.string().optional(),
919
+ error: z18.string().optional(),
892
920
  /** What `rig up --plan` concluded: its status (`planned`…), its errors and its warnings (one per seat without a permission policy…). */
893
- check: z17.object({ status: z17.string(), errors: z17.array(z17.string()), warnings: z17.array(z17.string()) }).optional()
921
+ check: z18.object({ status: z18.string(), errors: z18.array(z18.string()), warnings: z18.array(z18.string()) }).optional()
894
922
  });
895
- var OpenRigSeatsSchema = z17.object({
896
- type: z17.literal("openrig.seats"),
897
- requestId: z17.string().min(1).max(100),
898
- machineId: z17.string().optional(),
923
+ var OpenRigSeatsSchema = z18.object({
924
+ type: z18.literal("openrig.seats"),
925
+ requestId: z18.string().min(1).max(100),
926
+ machineId: z18.string().optional(),
899
927
  rig: RigNameSchema,
900
- seats: z17.record(RigRoleSchema, z17.number().int().min(0).max(9)),
928
+ seats: z18.record(RigRoleSchema, z18.number().int().min(0).max(9)),
901
929
  /** How the added seats are linked, where OpenRig can add links to a running rig (0.7+): like a launch's. */
902
- delegation: z17.enum(["pairs", "all"]).optional()
903
- });
904
- var OpenRigReseatedSchema = z17.object({
905
- type: z17.literal("openrig.reseated"),
906
- requestId: z17.string(),
907
- machineId: z17.string().optional(),
908
- ok: z17.boolean(),
909
- commands: z17.array(z17.string()),
910
- added: z17.array(z17.string()),
911
- removed: z17.array(z17.string()),
912
- output: z17.string().optional(),
913
- error: z17.string().optional(),
930
+ delegation: z18.enum(["pairs", "all"]).optional()
931
+ });
932
+ var OpenRigReseatedSchema = z18.object({
933
+ type: z18.literal("openrig.reseated"),
934
+ requestId: z18.string(),
935
+ machineId: z18.string().optional(),
936
+ ok: z18.boolean(),
937
+ commands: z18.array(z18.string()),
938
+ added: z18.array(z18.string()),
939
+ removed: z18.array(z18.string()),
940
+ output: z18.string().optional(),
941
+ error: z18.string().optional(),
914
942
  /** The links ensured between the seats; `linksUnsupported`: this OpenRig cannot add links to a running rig (before 0.7). */
915
- links: z17.number().int().optional(),
916
- linksUnsupported: z17.boolean().optional()
943
+ links: z18.number().int().optional(),
944
+ linksUnsupported: z18.boolean().optional()
945
+ });
946
+ var HumanQuestionAnswerSchema = z18.discriminatedUnion("kind", [
947
+ z18.object({ kind: z18.literal("option"), id: z18.string() }),
948
+ z18.object({ kind: z18.literal("words"), text: z18.string() })
949
+ ]);
950
+ var HumanQuestionSchema = z18.object({
951
+ id: z18.string(),
952
+ question: z18.string(),
953
+ options: z18.array(z18.object({ id: z18.string(), label: z18.string(), recommended: z18.boolean() })),
954
+ answer: HumanQuestionAnswerSchema.nullable()
955
+ });
956
+ var TeamProposalSchema = z18.object({
957
+ /** `existing`: the goal goes to a team that exists; `launch`: a new rig is launched, with what that does in `launch`. */
958
+ kind: z18.enum(["existing", "launch"]),
959
+ rig: z18.string(),
960
+ running: z18.boolean().nullable(),
961
+ folder: z18.string().nullable(),
962
+ seats: z18.array(z18.object({ seat: z18.string(), name: z18.string().nullable(), role: z18.string().nullable(), note: z18.string().nullable() })),
963
+ reason: z18.string().nullable(),
964
+ /** For a launch, before any yes: agents, runtimes, `rig up --plan`'s summary, what it writes in the folder, the seats' permissions. */
965
+ launch: z18.object({ agents: z18.number().int().nullable(), runtimes: z18.array(z18.string()), plan: z18.string().nullable(), writes: z18.array(z18.string()), permissions: z18.string().nullable() }).nullable()
966
+ });
967
+ var HumanAskSchema = z18.object({
968
+ id: z18.string(),
969
+ kind: z18.enum(["decision", "update", "parked"]),
970
+ alert: z18.boolean(),
971
+ priority: z18.enum(["routine", "urgent", "critical"]),
972
+ from: z18.object({ seat: z18.string(), rig: z18.string().nullable(), role: z18.string().nullable() }),
973
+ summary: z18.string(),
974
+ body: z18.string(),
975
+ bodyTruncated: z18.boolean(),
976
+ detail: z18.string().nullable(),
977
+ /** The detail was cut (on the phone, to fit its message): its end, which may decide, is not shown. */
978
+ detailTruncated: z18.literal(true).optional(),
979
+ evidenceRef: z18.string().nullable(),
980
+ questions: z18.array(HumanQuestionSchema),
981
+ createdAt: z18.string(),
982
+ updatedAt: z18.string(),
983
+ /** Max's proposal for this goal (the ask's `ledge-goal:<id>` tag), and the team it names when its block reads. */
984
+ goalId: z18.string().optional(),
985
+ team: TeamProposalSchema.optional()
986
+ });
987
+ var HumanChannelSchema = z18.object({
988
+ /** `no_default`: several people are registered and none is the default, so whose asks they are is unknown (nothing is shown). */
989
+ state: z18.enum(["ready", "no_person", "no_default", "openrig_stopped", "not_installed", "unreachable"]),
990
+ person: z18.object({ address: z18.string(), name: z18.string() }).nullable(),
991
+ /** Slack still posts the person's asks too. */
992
+ slack: z18.boolean(),
993
+ message: z18.string().optional()
994
+ });
995
+ var OpenRigAsksSchema = z18.object({ type: z18.literal("openrig.asks"), requestId: z18.string().min(1).max(100), machineId: z18.string().optional() });
996
+ var OpenRigAsksChangedSchema = z18.object({
997
+ type: z18.literal("openrig.asksChanged"),
998
+ requestId: z18.string().optional(),
999
+ machineId: z18.string().optional(),
1000
+ channel: HumanChannelSchema.optional(),
1001
+ asks: z18.array(HumanAskSchema),
1002
+ truncated: z18.boolean().optional(),
1003
+ /** A read failed (OpenRig unreachable, a row or a source not read): the asks known before are kept; none missing is settled. */
1004
+ partial: z18.boolean().optional(),
1005
+ error: z18.enum(["offline", "outdated"]).optional()
1006
+ });
1007
+ var HumanAnswerSchema = z18.discriminatedUnion("kind", [
1008
+ z18.object({ kind: z18.literal("choice"), questionId: z18.string().min(1).max(200), optionId: z18.string().min(1).max(200) }),
1009
+ z18.object({ kind: z18.literal("words"), text: z18.string().trim().min(1).max(8e3) }),
1010
+ z18.object({ kind: z18.literal("seen") }),
1011
+ z18.object({ kind: z18.literal("resolve"), text: z18.string().trim().min(1).max(8e3) })
1012
+ ]);
1013
+ var OpenRigAnswerSchema = z18.object({
1014
+ type: z18.literal("openrig.answer"),
1015
+ requestId: z18.string().min(1).max(100),
1016
+ machineId: z18.string().optional(),
1017
+ qitemId: z18.string().min(1).max(200),
1018
+ answer: HumanAnswerSchema
1019
+ });
1020
+ var HumanAnswerErrorSchema = z18.enum(["not_found", "closed", "refused", "not_closed", "unreachable", "openrig_stopped", "uncertain", "offline", "outdated"]);
1021
+ var OpenRigAnsweredSchema = z18.object({
1022
+ type: z18.literal("openrig.answered"),
1023
+ requestId: z18.string(),
1024
+ machineId: z18.string().optional(),
1025
+ qitemId: z18.string(),
1026
+ ok: z18.boolean(),
1027
+ outcome: z18.enum(["recorded", "answered", "already"]).optional(),
1028
+ remaining: z18.array(z18.string()).optional(),
1029
+ replyId: z18.string().optional(),
1030
+ error: HumanAnswerErrorSchema.optional(),
1031
+ message: z18.string().optional()
1032
+ });
1033
+ var GoalErrorSchema = z18.enum(["no_operator", "openrig_stopped", "unreachable", "uncertain", "refused", "offline", "outdated"]);
1034
+ var GoalIdSchema = z18.string().regex(/^[A-Za-z0-9-]{8,64}$/, "not a goal id");
1035
+ var GoalSchema = z18.object({
1036
+ goalId: z18.string(),
1037
+ qitemId: z18.string(),
1038
+ text: z18.string(),
1039
+ folder: z18.string().nullable(),
1040
+ sentAt: z18.string(),
1041
+ to: z18.string(),
1042
+ state: z18.enum(["sent", "taken", "asking", "proposed", "running", "done", "closed"]),
1043
+ /** The latest proposal: after « Changer d'équipe » Max makes a new one. */
1044
+ proposal: z18.object({
1045
+ askId: z18.string(),
1046
+ team: TeamProposalSchema.nullable(),
1047
+ text: z18.string(),
1048
+ answer: HumanQuestionAnswerSchema.nullable(),
1049
+ answeredAt: z18.string().nullable()
1050
+ }).nullable(),
1051
+ /** Max's question still open (no folder, no fitting team): it waits in « À toi ». */
1052
+ question: z18.object({ askId: z18.string(), text: z18.string() }).nullable(),
1053
+ trail: z18.array(z18.object({
1054
+ at: z18.string(),
1055
+ kind: z18.enum(["sent", "taken", "note", "handed", "closed"]),
1056
+ seat: z18.string(),
1057
+ to: z18.string().optional(),
1058
+ text: z18.string().optional(),
1059
+ qitemId: z18.string()
1060
+ })),
1061
+ current: z18.object({ qitemId: z18.string(), seat: z18.string(), state: z18.string() }).nullable()
1062
+ });
1063
+ var OpenRigGoalSendSchema = z18.object({
1064
+ type: z18.literal("openrig.goal.send"),
1065
+ requestId: z18.string().min(1).max(100),
1066
+ machineId: z18.string().optional(),
1067
+ goalId: GoalIdSchema,
1068
+ text: z18.string().trim().min(1).max(8e3),
1069
+ folder: z18.string().min(1).max(4096).optional()
1070
+ });
1071
+ var OpenRigGoalSentSchema = z18.object({
1072
+ type: z18.literal("openrig.goal.sent"),
1073
+ requestId: z18.string(),
1074
+ machineId: z18.string().optional(),
1075
+ goalId: z18.string(),
1076
+ ok: z18.boolean(),
1077
+ qitemId: z18.string().optional(),
1078
+ error: GoalErrorSchema.optional(),
1079
+ message: z18.string().optional()
1080
+ });
1081
+ var OpenRigGoalsSchema = z18.object({ type: z18.literal("openrig.goals"), requestId: z18.string().min(1).max(100), machineId: z18.string().optional() });
1082
+ var OpenRigGoalsChangedSchema = z18.object({
1083
+ type: z18.literal("openrig.goalsChanged"),
1084
+ requestId: z18.string().optional(),
1085
+ machineId: z18.string().optional(),
1086
+ goals: z18.array(GoalSchema),
1087
+ partial: z18.boolean().optional(),
1088
+ error: z18.enum(["offline", "outdated"]).optional()
1089
+ });
1090
+ var OpenRigGoalReplySchema = z18.object({
1091
+ type: z18.literal("openrig.goal.reply"),
1092
+ requestId: z18.string().min(1).max(100),
1093
+ machineId: z18.string().optional(),
1094
+ goalId: GoalIdSchema,
1095
+ replyId: GoalIdSchema,
1096
+ text: z18.string().trim().min(1).max(8e3)
1097
+ });
1098
+ var OpenRigGoalRepliedSchema = z18.object({
1099
+ type: z18.literal("openrig.goal.replied"),
1100
+ requestId: z18.string(),
1101
+ machineId: z18.string().optional(),
1102
+ goalId: z18.string(),
1103
+ /** The reply's own id, always: sending it again after `uncertain` reuses it, and never wakes Max twice. */
1104
+ replyId: z18.string(),
1105
+ ok: z18.boolean(),
1106
+ qitemId: z18.string().optional(),
1107
+ error: GoalErrorSchema.optional(),
1108
+ message: z18.string().optional()
1109
+ });
1110
+
1111
+ // ../protocol/src/rigMessages.ts
1112
+ import { z as z19 } from "zod";
1113
+ var QitemIdSchema = z19.string().regex(/^qitem-[A-Za-z0-9-]{1,120}$/, "not a qitem");
1114
+ var QITEM = "qitem-[A-Za-z0-9-]+";
1115
+ var RigKindSchema = z19.enum(["message", "handoff", "unblocked", "openrig", "unreadable"]);
1116
+ var RigInfoSchema = z19.object({
1117
+ kind: RigKindSchema,
1118
+ /** The envelope's From, as written (`pilot-lead@ledge-dev-2`, `daemon@kernel`, `ledge@external`, `<unknown sender>`).
1119
+ * On the seat's own `sent`: absent (it is the seat). The item's `peer` is the Ledge session of that seat, when known. */
1120
+ from: z19.string().optional(),
1121
+ /** The envelope's To, as written (a seat, a list `a, b`, or `broadcast to <rig> (n seats)`); on an outgoing item, the
1122
+ * destination the command named. */
1123
+ to: z19.string().optional(),
1124
+ /** The envelope's `Sent:` stamp as an ISO time (OpenRig gives no year: the year of receipt, or the year before when
1125
+ * that would put it in the future). Absent when the envelope has no `Sent:` line. */
1126
+ sentAt: z19.string().datetime().optional(),
1127
+ /** The sender's generation (8 hex), when the stamp carries one. */
1128
+ gen: z19.string().optional(),
1129
+ /** The row the item is about. `handoff`: the row handed (outgoing: the new row, when the command's output names it);
1130
+ * `unblocked`: the parked row now pending; `openrig`: the row it names (a stuck sweep: the stalled row). */
1131
+ qitem: QitemIdSchema.optional(),
1132
+ /** `handoff`: the row's summary as OpenRig carried it (one line, at most 120 characters, `…` when cut). */
1133
+ summary: z19.string().optional(),
1134
+ /** `unblocked`: the row whose closing unblocked it. */
1135
+ blocker: QitemIdSchema.optional(),
1136
+ /** `openrig`: the recovery row OpenRig opened for it (a stuck sweep comes as a handoff of a `qitem-recovery-…` row). */
1137
+ recovery: QitemIdSchema.optional(),
1138
+ /** `openrig`: `stalled` a stuck sweep (a seat that does not move: amber), `custody` a custody check; else absent. */
1139
+ alert: z19.enum(["stalled", "custody"]).optional(),
1140
+ /** `openrig` with an alert: how long, in minutes, as OpenRig said. */
1141
+ minutes: z19.number().int().nonnegative().optional(),
1142
+ /** The seat's own command (an outgoing `sent` or `handoff`): the Bash command, as run. */
1143
+ command: z19.string().optional(),
1144
+ /** OpenRig said the delivery may repeat (`Recovered queue notification`). */
1145
+ recovered: z19.literal(true).optional(),
1146
+ /** Received that many times (2 or more): the same block came again, and this item stands for all of them. */
1147
+ count: z19.number().int().min(2).optional(),
1148
+ /** Blocks pasted together in one prompt: the prompt's id, this block's place and how many there were. The front shows
1149
+ * one raw for the packet, the raws of its items joined. */
1150
+ packet: z19.object({ id: z19.string().min(1), index: z19.number().int().nonnegative(), count: z19.number().int().min(2) }).optional(),
1151
+ /** The block exactly as received (every delivery, separated by a blank line, when `count` is set); outgoing: the command
1152
+ * and what it printed. Always there. */
1153
+ raw: z19.string()
1154
+ });
1155
+ var HANDOFF = new RegExp(`^Queue handoff: (${QITEM}) - check your queue\\.(?: Summary: (.*))?$`);
1156
+ var BLOCKER = new RegExp(`^Blocker (${QITEM}) resolved; parked qitem (${QITEM}) is pending\\.`);
1157
+ var STALLED = new RegExp(`^Stuck sweep: \\S+ on (${QITEM}) \\((\\d+) min\\)`);
1158
+ var CUSTODY = new RegExp(`^Custody not checked\\b.*?(?:for |of )(${QITEM}).*?\\((\\d+) min\\)`);
1159
+ var RigRowSchema = z19.object({
1160
+ id: QitemIdSchema,
1161
+ state: z19.string().min(1),
1162
+ summary: z19.string().optional(),
1163
+ /** Who made it and who holds it (seats). */
1164
+ from: z19.string(),
1165
+ to: z19.string(),
1166
+ /** `handed-off`: the seat it went to. */
1167
+ handedOffTo: z19.string().optional(),
1168
+ /** `blocked`: the row it waits on. */
1169
+ blockedOn: z19.string().optional(),
1170
+ createdAt: z19.string(),
1171
+ claimedAt: z19.string().optional(),
1172
+ updatedAt: z19.string(),
1173
+ /** When Ledge read it. */
1174
+ at: z19.string()
1175
+ });
1176
+ var OpenRigRowSchema = z19.object({ type: z19.literal("openrig.row"), requestId: z19.string().min(1).max(100), qitem: QitemIdSchema, machineId: z19.string().optional() });
1177
+ var OpenRigRowStateSchema = z19.object({
1178
+ type: z19.literal("openrig.rowState"),
1179
+ requestId: z19.string(),
1180
+ machineId: z19.string().optional(),
1181
+ qitem: z19.string(),
1182
+ row: RigRowSchema.optional(),
1183
+ error: z19.string().optional()
917
1184
  });
918
1185
 
919
1186
  // ../protocol/src/openrigRoles.ts
920
- import { z as z18 } from "zod";
921
- var RoleUnknownWhySchema = z18.enum(["resolved_at_launch", "not_exposed", "unreadable", "ambiguous", "not_found", "missing_from_guidance"]);
922
- var RoleFromSchema = z18.enum(["import", "defaults", "profile", "rig", "pod", "member", "launch", "openrig", "plugin", "seat"]);
923
- var OriginSchema = z18.discriminatedUnion("kind", [
924
- z18.object({ kind: z18.literal("here"), key: z18.string().optional() }),
925
- z18.object({ kind: z18.literal("inherited"), from: RoleFromSchema, ref: z18.string().optional(), key: z18.string().optional(), path: z18.string().optional() }),
926
- z18.object({ kind: z18.literal("absent") }),
927
- z18.object({ kind: z18.literal("unknown"), why: RoleUnknownWhySchema, detail: z18.string().optional() })
1187
+ import { z as z20 } from "zod";
1188
+ var RoleUnknownWhySchema = z20.enum(["resolved_at_launch", "not_exposed", "unreadable", "ambiguous", "not_found", "missing_from_guidance"]);
1189
+ var RoleFromSchema = z20.enum(["import", "defaults", "profile", "rig", "pod", "member", "launch", "openrig", "plugin", "seat"]);
1190
+ var OriginSchema = z20.discriminatedUnion("kind", [
1191
+ z20.object({ kind: z20.literal("here"), key: z20.string().optional() }),
1192
+ z20.object({ kind: z20.literal("inherited"), from: RoleFromSchema, ref: z20.string().optional(), key: z20.string().optional(), path: z20.string().optional() }),
1193
+ z20.object({ kind: z20.literal("absent") }),
1194
+ z20.object({ kind: z20.literal("unknown"), why: RoleUnknownWhySchema, detail: z20.string().optional() })
928
1195
  ]);
929
- var SourcedStringSchema = z18.object({ value: z18.string().nullable(), origin: OriginSchema });
930
- var RoleResourceCategorySchema = z18.enum(["skill", "guidance", "plugin", "subagent", "runtime_resource"]);
931
- var RoleResourceSchema = z18.object({
1196
+ var SourcedStringSchema = z20.object({ value: z20.string().nullable(), origin: OriginSchema });
1197
+ var RoleResourceCategorySchema = z20.enum(["skill", "guidance", "plugin", "subagent", "runtime_resource"]);
1198
+ var RoleResourceSchema = z20.object({
932
1199
  category: RoleResourceCategorySchema,
933
- id: z18.string(),
934
- path: z18.string().optional(),
935
- absolutePath: z18.string().optional(),
936
- runtime: z18.string().optional(),
937
- type: z18.string().optional(),
938
- target: z18.string().optional(),
939
- plugin: z18.object({ version: z18.string().optional(), skills: z18.array(z18.string()), hooks: z18.number().int().min(0) }).optional(),
1200
+ id: z20.string(),
1201
+ path: z20.string().optional(),
1202
+ absolutePath: z20.string().optional(),
1203
+ runtime: z20.string().optional(),
1204
+ type: z20.string().optional(),
1205
+ target: z20.string().optional(),
1206
+ plugin: z20.object({ version: z20.string().optional(), skills: z20.array(z20.string()), hooks: z20.number().int().min(0) }).optional(),
940
1207
  origin: OriginSchema
941
1208
  });
942
- var RoleUsesListSchema = z18.object({ declared: z18.boolean(), key: z18.string(), items: z18.array(RoleResourceSchema) });
943
- var StartupLayerSchema = z18.enum(["agent", "profile", "culture", "rig", "pod", "member", "openrig", "seat", "unknown"]);
944
- var StartupEntrySchema = z18.object({
945
- kind: z18.enum(["file", "action"]),
946
- path: z18.string().optional(),
947
- absolutePath: z18.string().optional(),
948
- size: z18.number().int().min(0).optional(),
949
- value: z18.string().optional(),
950
- builtin: z18.string().optional(),
1209
+ var RoleUsesListSchema = z20.object({ declared: z20.boolean(), key: z20.string(), items: z20.array(RoleResourceSchema) });
1210
+ var StartupLayerSchema = z20.enum(["agent", "profile", "culture", "rig", "pod", "member", "openrig", "seat", "unknown"]);
1211
+ var StartupEntrySchema = z20.object({
1212
+ kind: z20.enum(["file", "action"]),
1213
+ path: z20.string().optional(),
1214
+ absolutePath: z20.string().optional(),
1215
+ size: z20.number().int().min(0).optional(),
1216
+ value: z20.string().optional(),
1217
+ builtin: z20.string().optional(),
951
1218
  layer: StartupLayerSchema,
952
- layerInferred: z18.boolean(),
953
- delivery: z18.string(),
954
- into: z18.string().optional(),
955
- delivered: z18.boolean().optional(),
956
- required: z18.boolean().optional(),
957
- orientation: z18.string().optional(),
958
- appliesOn: z18.array(z18.string()),
1219
+ layerInferred: z20.boolean(),
1220
+ delivery: z20.string(),
1221
+ into: z20.string().optional(),
1222
+ delivered: z20.boolean().optional(),
1223
+ required: z20.boolean().optional(),
1224
+ orientation: z20.string().optional(),
1225
+ appliesOn: z20.array(z20.string()),
959
1226
  origin: OriginSchema
960
1227
  });
961
- var RoleFileErrorSchema = z18.object({ kind: z18.enum(["missing", "invalid"]), message: z18.string(), line: z18.number().int().optional(), col: z18.number().int().optional() });
962
- var RoleSummarySchema = z18.object({
963
- id: z18.string(),
964
- name: z18.string(),
965
- version: z18.string().optional(),
966
- description: z18.string().optional(),
967
- source: z18.enum(["builtin", "user"]),
968
- path: z18.string(),
969
- runtime: z18.string().optional(),
970
- importOnly: z18.boolean(),
971
- seats: z18.number().int().min(0),
972
- running: z18.number().int().min(0),
973
- skills: z18.array(z18.string()),
974
- startupFiles: z18.array(z18.string()),
1228
+ var RoleFileErrorSchema = z20.object({ kind: z20.enum(["missing", "invalid"]), message: z20.string(), line: z20.number().int().optional(), col: z20.number().int().optional() });
1229
+ var RoleSummarySchema = z20.object({
1230
+ id: z20.string(),
1231
+ name: z20.string(),
1232
+ version: z20.string().optional(),
1233
+ description: z20.string().optional(),
1234
+ source: z20.enum(["builtin", "user"]),
1235
+ path: z20.string(),
1236
+ runtime: z20.string().optional(),
1237
+ importOnly: z20.boolean(),
1238
+ seats: z20.number().int().min(0),
1239
+ running: z20.number().int().min(0),
1240
+ skills: z20.array(z20.string()),
1241
+ startupFiles: z20.array(z20.string()),
975
1242
  /** The seats that run it, so a seat of the Rigs page opens its role « seen from » it (`openrig.role` with `id`, then the seat by `rig` + `logicalId`). */
976
- seatRefs: z18.array(z18.object({ rig: z18.string(), logicalId: z18.string(), session: z18.string().optional() })),
977
- error: z18.enum(["missing", "invalid"]).optional()
978
- });
979
- var RoleImportSchema = z18.object({
980
- ref: z18.string(),
981
- key: z18.string(),
982
- name: z18.string().optional(),
983
- path: z18.string().optional(),
984
- version: z18.string().optional(),
985
- resolved: z18.boolean(),
986
- error: z18.string().optional()
987
- });
988
- var RoleProfileSchema = z18.object({
989
- name: z18.string(),
990
- description: z18.string().optional(),
1243
+ seatRefs: z20.array(z20.object({ rig: z20.string(), logicalId: z20.string(), session: z20.string().optional() })),
1244
+ error: z20.enum(["missing", "invalid"]).optional()
1245
+ });
1246
+ var RoleImportSchema = z20.object({
1247
+ ref: z20.string(),
1248
+ key: z20.string(),
1249
+ name: z20.string().optional(),
1250
+ path: z20.string().optional(),
1251
+ version: z20.string().optional(),
1252
+ resolved: z20.boolean(),
1253
+ error: z20.string().optional()
1254
+ });
1255
+ var RoleProfileSchema = z20.object({
1256
+ name: z20.string(),
1257
+ description: z20.string().optional(),
991
1258
  runtime: SourcedStringSchema,
992
1259
  model: SourcedStringSchema,
993
1260
  effort: SourcedStringSchema,
994
- uses: z18.object({ skills: RoleUsesListSchema, guidance: RoleUsesListSchema, subagents: RoleUsesListSchema, plugins: RoleUsesListSchema, runtimeResources: RoleUsesListSchema }),
1261
+ uses: z20.object({ skills: RoleUsesListSchema, guidance: RoleUsesListSchema, subagents: RoleUsesListSchema, plugins: RoleUsesListSchema, runtimeResources: RoleUsesListSchema }),
995
1262
  /** The role's share of the startup: agent then profile files and actions, in that order. */
996
- startup: z18.array(StartupEntrySchema)
997
- });
998
- var RoleSeatSchema = z18.object({
999
- rig: z18.string(),
1000
- rigId: z18.string(),
1001
- rigSpecPath: z18.string().optional(),
1002
- composed: z18.boolean(),
1003
- logicalId: z18.string(),
1004
- session: z18.string().optional(),
1005
- label: z18.string().optional(),
1006
- profile: z18.string(),
1007
- running: z18.boolean(),
1008
- activity: z18.string(),
1263
+ startup: z20.array(StartupEntrySchema)
1264
+ });
1265
+ var RoleSeatSchema = z20.object({
1266
+ rig: z20.string(),
1267
+ rigId: z20.string(),
1268
+ rigSpecPath: z20.string().optional(),
1269
+ composed: z20.boolean(),
1270
+ logicalId: z20.string(),
1271
+ session: z20.string().optional(),
1272
+ label: z20.string().optional(),
1273
+ profile: z20.string(),
1274
+ running: z20.boolean(),
1275
+ activity: z20.string(),
1009
1276
  runtime: SourcedStringSchema,
1010
1277
  model: SourcedStringSchema,
1011
1278
  effort: SourcedStringSchema,
1012
1279
  cwd: SourcedStringSchema,
1013
1280
  cultureFile: SourcedStringSchema,
1014
- member: z18.string().optional(),
1015
- memberStartup: z18.array(StartupEntrySchema),
1281
+ member: z20.string().optional(),
1282
+ memberStartup: z20.array(StartupEntrySchema),
1016
1283
  /** The Role tab of this seat: its role guidance (`role.md`), then the startup files of its own (member layer), in delivery
1017
1284
  * order — OpenRig's when the seat was launched, else the spec's. */
1018
- roleDocs: z18.array(StartupEntrySchema),
1019
- live: z18.object({
1020
- resolvedSpec: z18.object({ name: z18.string().optional(), version: z18.string().optional(), hash: z18.string().optional() }),
1021
- resources: z18.array(RoleResourceSchema),
1285
+ roleDocs: z20.array(StartupEntrySchema),
1286
+ live: z20.object({
1287
+ resolvedSpec: z20.object({ name: z20.string().optional(), version: z20.string().optional(), hash: z20.string().optional() }),
1288
+ resources: z20.array(RoleResourceSchema),
1022
1289
  /** In the order OpenRig returns them. */
1023
- startup: z18.array(StartupEntrySchema),
1290
+ startup: z20.array(StartupEntrySchema),
1024
1291
  /** `rig skill loadout --seat`: the skills projected for this seat; absent when it could not be read. */
1025
- skills: z18.array(z18.object({ id: z18.string(), trigger: z18.string().optional() })).optional()
1292
+ skills: z20.array(z20.object({ id: z20.string(), trigger: z20.string().optional() })).optional()
1026
1293
  }).optional()
1027
1294
  });
1028
- var RoleUnavailableSchema = z18.enum(["harness_prompt", "effective_settings", "delivered_content", "harness_own_files"]);
1029
- var RoleDetailSchema = z18.object({
1295
+ var RoleUnavailableSchema = z20.enum(["harness_prompt", "effective_settings", "delivered_content", "harness_own_files"]);
1296
+ var RoleDetailSchema = z20.object({
1030
1297
  summary: RoleSummarySchema,
1031
- file: z18.object({
1032
- path: z18.string(),
1033
- relativePath: z18.string().optional(),
1034
- modifiedAt: z18.string().optional(),
1035
- copies: z18.array(z18.object({ kind: z18.literal("repo"), path: z18.string(), identical: z18.boolean(), modifiedAt: z18.string().optional() }))
1298
+ file: z20.object({
1299
+ path: z20.string(),
1300
+ relativePath: z20.string().optional(),
1301
+ modifiedAt: z20.string().optional(),
1302
+ copies: z20.array(z20.object({ kind: z20.literal("repo"), path: z20.string(), identical: z20.boolean(), modifiedAt: z20.string().optional() }))
1036
1303
  }),
1037
1304
  error: RoleFileErrorSchema.optional(),
1038
- role: z18.object({ path: z18.string(), absolutePath: z18.string(), origin: OriginSchema }).nullable(),
1039
- defaults: z18.object({ runtime: SourcedStringSchema, model: SourcedStringSchema, effort: SourcedStringSchema }),
1040
- imports: z18.array(RoleImportSchema),
1041
- importedBy: z18.array(z18.string()),
1042
- profiles: z18.array(RoleProfileSchema),
1305
+ role: z20.object({ path: z20.string(), absolutePath: z20.string(), origin: OriginSchema }).nullable(),
1306
+ defaults: z20.object({ runtime: SourcedStringSchema, model: SourcedStringSchema, effort: SourcedStringSchema }),
1307
+ imports: z20.array(RoleImportSchema),
1308
+ importedBy: z20.array(z20.string()),
1309
+ profiles: z20.array(RoleProfileSchema),
1043
1310
  /** What the file declares in `resources`. */
1044
- resources: z18.array(RoleResourceSchema),
1045
- seats: z18.array(RoleSeatSchema),
1046
- unavailable: z18.array(RoleUnavailableSchema),
1047
- warnings: z18.array(z18.string()),
1048
- openrigVersion: z18.string().optional()
1049
- });
1050
- var RoleErrorSchema = z18.string();
1051
- var LibraryIdSchema = z18.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/, "not a library id");
1052
- var OpenRigRolesSchema = z18.object({ type: z18.literal("openrig.roles"), requestId: z18.string().min(1).max(100), machineId: z18.string().optional() });
1053
- var OpenRigRoleListSchema = z18.object({
1054
- type: z18.literal("openrig.roleList"),
1055
- requestId: z18.string(),
1056
- machineId: z18.string().optional(),
1057
- roles: z18.array(RoleSummarySchema),
1058
- openrigVersion: z18.string().optional(),
1311
+ resources: z20.array(RoleResourceSchema),
1312
+ seats: z20.array(RoleSeatSchema),
1313
+ unavailable: z20.array(RoleUnavailableSchema),
1314
+ warnings: z20.array(z20.string()),
1315
+ openrigVersion: z20.string().optional()
1316
+ });
1317
+ var RoleErrorSchema = z20.string();
1318
+ var LibraryIdSchema = z20.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:-]*$/, "not a library id");
1319
+ var OpenRigRolesSchema = z20.object({ type: z20.literal("openrig.roles"), requestId: z20.string().min(1).max(100), machineId: z20.string().optional() });
1320
+ var OpenRigRoleListSchema = z20.object({
1321
+ type: z20.literal("openrig.roleList"),
1322
+ requestId: z20.string(),
1323
+ machineId: z20.string().optional(),
1324
+ roles: z20.array(RoleSummarySchema),
1325
+ openrigVersion: z20.string().optional(),
1059
1326
  error: RoleErrorSchema.optional()
1060
1327
  });
1061
- var OpenRigRoleSchema = z18.object({ type: z18.literal("openrig.role"), requestId: z18.string().min(1).max(100), machineId: z18.string().optional(), roleId: LibraryIdSchema });
1062
- var OpenRigRoleDetailSchema = z18.object({
1063
- type: z18.literal("openrig.roleDetail"),
1064
- requestId: z18.string(),
1065
- machineId: z18.string().optional(),
1066
- roleId: z18.string(),
1328
+ var OpenRigRoleSchema = z20.object({ type: z20.literal("openrig.role"), requestId: z20.string().min(1).max(100), machineId: z20.string().optional(), roleId: LibraryIdSchema });
1329
+ var OpenRigRoleDetailSchema = z20.object({
1330
+ type: z20.literal("openrig.roleDetail"),
1331
+ requestId: z20.string(),
1332
+ machineId: z20.string().optional(),
1333
+ roleId: z20.string(),
1067
1334
  role: RoleDetailSchema.optional(),
1068
1335
  error: RoleErrorSchema.optional()
1069
1336
  });
1070
- var OpenRigRoleFileSchema = z18.object({
1071
- type: z18.literal("openrig.roleFile"),
1072
- requestId: z18.string().min(1).max(100),
1073
- machineId: z18.string().optional(),
1337
+ var OpenRigRoleFileSchema = z20.object({
1338
+ type: z20.literal("openrig.roleFile"),
1339
+ requestId: z20.string().min(1).max(100),
1340
+ machineId: z20.string().optional(),
1074
1341
  roleId: LibraryIdSchema,
1075
- path: z18.string().min(1).max(4096)
1076
- });
1077
- var OpenRigRoleFileContentSchema = z18.object({
1078
- type: z18.literal("openrig.roleFileContent"),
1079
- requestId: z18.string(),
1080
- machineId: z18.string().optional(),
1081
- roleId: z18.string(),
1082
- path: z18.string(),
1083
- content: z18.string().optional(),
1084
- size: z18.number().int().min(0).optional(),
1085
- truncated: z18.boolean().optional(),
1342
+ path: z20.string().min(1).max(4096)
1343
+ });
1344
+ var OpenRigRoleFileContentSchema = z20.object({
1345
+ type: z20.literal("openrig.roleFileContent"),
1346
+ requestId: z20.string(),
1347
+ machineId: z20.string().optional(),
1348
+ roleId: z20.string(),
1349
+ path: z20.string(),
1350
+ content: z20.string().optional(),
1351
+ size: z20.number().int().min(0).optional(),
1352
+ truncated: z20.boolean().optional(),
1086
1353
  error: RoleErrorSchema.optional()
1087
1354
  });
1088
1355
  var ROLE_FILE_MAX = 512 * 1024;
1089
1356
 
1090
1357
  // ../protocol/src/routing.ts
1091
- import { z as z19 } from "zod";
1092
- var MachineInventorySchema = z19.object({
1093
- id: z19.string().min(1).max(80),
1094
- label: z19.string().min(1).max(120),
1095
- online: z19.boolean(),
1096
- local: z19.boolean(),
1097
- sessions: z19.array(z19.object({ id: z19.string(), name: z19.string(), project: z19.string(), cwd: z19.string(), topic: z19.string().optional(), state: z19.string(), readOnly: z19.boolean() })).max(500),
1098
- folders: z19.array(z19.object({ project: z19.string(), cwd: z19.string() })).max(100)
1099
- });
1100
- var RoutingContextSchema = z19.object({
1101
- machines: z19.array(MachineInventorySchema).min(1).max(20),
1102
- history: z19.array(z19.object({ question: z19.string().max(2e4), answer: z19.string().max(2e4).optional(), machineId: z19.string().optional() })).max(50)
1103
- });
1104
- var RouteResultSchema = z19.object({
1358
+ import { z as z21 } from "zod";
1359
+ var MachineInventorySchema = z21.object({
1360
+ id: z21.string().min(1).max(80),
1361
+ label: z21.string().min(1).max(120),
1362
+ online: z21.boolean(),
1363
+ local: z21.boolean(),
1364
+ sessions: z21.array(z21.object({ id: z21.string(), name: z21.string(), project: z21.string(), cwd: z21.string(), topic: z21.string().optional(), state: z21.string(), readOnly: z21.boolean() })).max(500),
1365
+ folders: z21.array(z21.object({ project: z21.string(), cwd: z21.string() })).max(100)
1366
+ });
1367
+ var RoutingContextSchema = z21.object({
1368
+ machines: z21.array(MachineInventorySchema).min(1).max(20),
1369
+ history: z21.array(z21.object({ question: z21.string().max(2e4), answer: z21.string().max(2e4).optional(), machineId: z21.string().optional() })).max(50)
1370
+ });
1371
+ var RouteResultSchema = z21.object({
1105
1372
  /** Null means an answer or a clarification, never an implicit local destination. */
1106
- machineId: z19.string().nullable(),
1107
- text: z19.string().min(1).max(2e4),
1108
- choices: z19.array(z19.string()).max(20).optional()
1373
+ machineId: z21.string().nullable(),
1374
+ text: z21.string().min(1).max(2e4),
1375
+ choices: z21.array(z21.string()).max(20).optional()
1109
1376
  });
1110
1377
 
1111
1378
  // ../protocol/src/thread.ts
1112
- import { z as z20 } from "zod";
1113
- var ToolStatusSchema = z20.enum(["running", "success", "failed", "unknown"]);
1114
- var FileChangeSchema = z20.object({ path: z20.string().min(1), from: z20.string().min(1).optional(), change: z20.enum(["add", "edit", "delete", "write"]), diff: z20.string().optional() });
1115
- var base = { id: z20.string().min(1), at: z20.string().datetime(), turn: z20.number().int().nonnegative(), helperId: z20.string().optional() };
1116
- var ThreadItemSchema = z20.discriminatedUnion("kind", [
1117
- z20.object({ kind: z20.literal("prompt"), ...base, text: z20.string(), images: z20.array(AttachmentRefSchema).optional() }),
1118
- z20.object({ kind: z20.literal("message"), ...base, text: z20.string() }),
1379
+ import { z as z22 } from "zod";
1380
+ var ToolStatusSchema = z22.enum(["running", "success", "failed", "unknown"]);
1381
+ var FileChangeSchema = z22.object({ path: z22.string().min(1), from: z22.string().min(1).optional(), change: z22.enum(["add", "edit", "delete", "write"]), diff: z22.string().optional() });
1382
+ var base = { id: z22.string().min(1), at: z22.string().datetime(), turn: z22.number().int().nonnegative(), helperId: z22.string().optional() };
1383
+ var ThreadItemSchema = z22.discriminatedUnion("kind", [
1384
+ z22.object({ kind: z22.literal("prompt"), ...base, text: z22.string(), images: z22.array(AttachmentRefSchema).optional() }),
1385
+ z22.object({ kind: z22.literal("message"), ...base, text: z22.string() }),
1119
1386
  /** `id` is the harness's tool_use_id when it gives one, so the result updates the same row; `byClose`: a question
1120
1387
  * dismissed by Ledge closing the session. */
1121
- z20.object({
1122
- kind: z20.literal("tool"),
1388
+ z22.object({
1389
+ kind: z22.literal("tool"),
1123
1390
  ...base,
1124
- tool: z20.string(),
1125
- label: z20.string(),
1126
- input: z20.string().optional(),
1127
- output: z20.string().optional(),
1128
- error: z20.string().optional(),
1391
+ tool: z22.string(),
1392
+ label: z22.string(),
1393
+ input: z22.string().optional(),
1394
+ output: z22.string().optional(),
1395
+ error: z22.string().optional(),
1129
1396
  status: ToolStatusSchema,
1130
- durationMs: z20.number().nonnegative().optional(),
1131
- files: z20.array(FileChangeSchema).default([]),
1132
- byClose: z20.literal(true).optional(),
1397
+ durationMs: z22.number().nonnegative().optional(),
1398
+ files: z22.array(FileChangeSchema).default([]),
1399
+ byClose: z22.literal(true).optional(),
1133
1400
  /** Images the tool returned (a browser screenshot), in order; `imagesDropped`: some were not kept. */
1134
- images: z20.array(AttachmentRefSchema).max(ATTACHMENTS_MAX).optional(),
1135
- imagesDropped: z20.literal(true).optional()
1401
+ images: z22.array(AttachmentRefSchema).max(ATTACHMENTS_MAX).optional(),
1402
+ imagesDropped: z22.literal(true).optional()
1136
1403
  }),
1137
1404
  /** `unknown`: answered in the terminal, the daemon only saw the prompt go away; `always`: allowed and not asked again;
1138
1405
  * `byClose`: denied by Ledge closing the session. */
1139
- z20.object({ kind: z20.literal("permission"), ...base, tool: z20.string(), text: z20.string(), decision: z20.enum(["accept", "deny", "always", "unknown"]).optional(), byClose: z20.literal(true).optional() }),
1140
- z20.object({ kind: z20.literal("reply"), ...base, text: z20.string() }),
1141
- z20.object({ kind: z20.literal("helper"), ...base, task: z20.string(), agentType: z20.string().optional(), state: z20.enum(["working", "exited"]) }),
1406
+ z22.object({ kind: z22.literal("permission"), ...base, tool: z22.string(), text: z22.string(), decision: z22.enum(["accept", "deny", "always", "unknown"]).optional(), byClose: z22.literal(true).optional() }),
1407
+ z22.object({ kind: z22.literal("reply"), ...base, text: z22.string() }),
1408
+ z22.object({ kind: z22.literal("helper"), ...base, task: z22.string(), agentType: z22.string().optional(), state: z22.enum(["working", "exited"]) }),
1142
1409
  /** A message this session sent to another agent; `id` is the tool_use_id, `to` the address it used, `peer` the Ledge session id, `received` the paired item's id in the peer's thread, `via` set when Ledge's mailbox carries it. */
1143
- z20.object({ kind: z20.literal("sent"), ...base, to: z20.string(), peer: z20.string().optional(), summary: z20.string().optional(), text: z20.string(), status: z20.enum(["sending", "delivered", "read", "failed"]), received: z20.string().optional(), via: z20.literal("ledge").optional() }),
1410
+ z22.object({
1411
+ kind: z22.literal("sent"),
1412
+ ...base,
1413
+ to: z22.string(),
1414
+ peer: z22.string().optional(),
1415
+ summary: z22.string().optional(),
1416
+ text: z22.string(),
1417
+ status: z22.enum(["sending", "delivered", "read", "failed"]),
1418
+ received: z22.string().optional(),
1419
+ via: z22.literal("ledge").optional(),
1420
+ /** The seat's own `rig send` (its Bash call), docs/mockups/ledge-openrig-messages.html: `rig.command` is what it ran. */
1421
+ rig: RigInfoSchema.optional()
1422
+ }),
1144
1423
  /** A message another agent sent to this session; `from` is its from-name (else its address), `sent` the paired item's id in the peer's thread. */
1145
- z20.object({ kind: z20.literal("received"), ...base, from: z20.string(), peer: z20.string().optional(), text: z20.string(), sent: z20.string().optional() }),
1424
+ z22.object({
1425
+ kind: z22.literal("received"),
1426
+ ...base,
1427
+ from: z22.string(),
1428
+ peer: z22.string().optional(),
1429
+ text: z22.string(),
1430
+ sent: z22.string().optional(),
1431
+ /** An OpenRig `rig send` typed into this seat (`rig.kind` `message`): `from` is the envelope's sender, `text` its body. */
1432
+ rig: RigInfoSchema.optional()
1433
+ }),
1146
1434
  /** An automated notice of the agent's harness about messages between sessions (Claude Code's `[Cross-session idle
1147
1435
  * notice]` / `[Cross-session delivery notice]`): a system event, never the user's words. `name` is the session it is
1148
1436
  * about as quoted, `peer` its Ledge session id; a delivery notice says the outcome of `count` messages to `recipients`. */
1149
- z20.object({
1150
- kind: z20.literal("notice"),
1437
+ z22.object({
1438
+ kind: z22.literal("notice"),
1151
1439
  ...base,
1152
- notice: z20.enum(["idle", "exited", "unavailable", "expired", "delivery", "other"]),
1440
+ notice: z22.enum(["idle", "exited", "unavailable", "expired", "delivery", "other"]),
1153
1441
  /** An `other` notice from Ledge: `task`, the task a `<ledge-task>` is about. An older front, which does not know it, shows it as any other notice. */
1154
- task: z20.string().optional(),
1442
+ task: z22.string().optional(),
1155
1443
  /** A task this session handed over (`outgoing`), and how (issue #92). */
1156
- taskOp: z20.enum(TRANSMISSION_OPS).optional(),
1157
- outgoing: z20.literal(true).optional(),
1158
- name: z20.string().optional(),
1159
- peer: z20.string().optional(),
1160
- time: z20.string().optional(),
1161
- summary: z20.string().optional(),
1162
- status: z20.enum(["held", "denied", "expired", "delivered", "refused", "dropped", "unknown"]).optional(),
1163
- count: z20.number().int().positive().optional(),
1164
- recipients: z20.array(z20.string()).optional(),
1165
- reason: z20.string().optional(),
1166
- text: z20.string()
1444
+ taskOp: z22.enum(TRANSMISSION_OPS).optional(),
1445
+ outgoing: z22.literal(true).optional(),
1446
+ name: z22.string().optional(),
1447
+ peer: z22.string().optional(),
1448
+ time: z22.string().optional(),
1449
+ summary: z22.string().optional(),
1450
+ status: z22.enum(["held", "denied", "expired", "delivered", "refused", "dropped", "unknown"]).optional(),
1451
+ count: z22.number().int().positive().optional(),
1452
+ recipients: z22.array(z22.string()).optional(),
1453
+ reason: z22.string().optional(),
1454
+ text: z22.string(),
1455
+ /** An OpenRig block that is not a message: a row handed to this seat or passed by it (`handoff`, `outgoing` for its own),
1456
+ * a row unblocked, OpenRig's own notice, or an unreadable block; `text` is the body (unreadable: the block as is). */
1457
+ rig: RigInfoSchema.optional()
1167
1458
  })
1168
1459
  ]);
1169
1460
 
1170
1461
  // ../protocol/src/mobile.ts
1171
- import { z as z21 } from "zod";
1172
- var RelayUrlSchema = z21.string().transform((v, ctx) => {
1462
+ import { z as z23 } from "zod";
1463
+ var RelayUrlSchema = z23.string().transform((v, ctx) => {
1173
1464
  const bad = () => {
1174
- ctx.addIssue({ code: z21.ZodIssueCode.custom, message: "invalid relay URL" });
1175
- return z21.NEVER;
1465
+ ctx.addIssue({ code: z23.ZodIssueCode.custom, message: "invalid relay URL" });
1466
+ return z23.NEVER;
1176
1467
  };
1177
1468
  let u;
1178
1469
  try {
@@ -1185,116 +1476,128 @@ var RelayUrlSchema = z21.string().transform((v, ctx) => {
1185
1476
  if (u.username || u.password || u.pathname !== "/" || u.search || u.hash) return bad();
1186
1477
  return u.origin;
1187
1478
  });
1188
- var MobileConfigSchema = z21.object({ enabled: z21.boolean(), relayUrl: RelayUrlSchema });
1189
- var MobileLinkStateSchema = z21.discriminatedUnion("state", [
1190
- z21.object({ state: z21.literal("off") }),
1191
- z21.object({ state: z21.literal("connecting") }),
1192
- z21.object({ state: z21.literal("online") }),
1193
- z21.object({ state: z21.literal("offline"), retryAt: z21.string().datetime(), error: z21.string() }),
1194
- z21.object({ state: z21.literal("signed_out"), reason: z21.enum(["other_pc", "session_invalid"]) }),
1479
+ var MobileConfigSchema = z23.object({ enabled: z23.boolean(), relayUrl: RelayUrlSchema, terminalInput: z23.boolean().optional() });
1480
+ var MobileLinkStateSchema = z23.discriminatedUnion("state", [
1481
+ z23.object({ state: z23.literal("off") }),
1482
+ z23.object({ state: z23.literal("connecting") }),
1483
+ z23.object({ state: z23.literal("online") }),
1484
+ z23.object({ state: z23.literal("offline"), retryAt: z23.string().datetime(), error: z23.string() }),
1485
+ z23.object({ state: z23.literal("signed_out"), reason: z23.enum(["other_pc", "session_invalid"]) }),
1195
1486
  /** The mobile service did not start (a broken mobile.json, a missing key store): nothing is linked until the daemon restarts. */
1196
- z21.object({ state: z21.literal("unavailable"), error: z21.string().max(200) })
1487
+ z23.object({ state: z23.literal("unavailable"), error: z23.string().max(200) })
1197
1488
  ]);
1198
- var MobilePairingSchema = z21.object({
1199
- id: z21.string(),
1200
- label: z21.string(),
1201
- code: z21.string().nullable(),
1202
- expiresAt: z21.string().datetime(),
1203
- state: z21.enum(["waiting", "confirm", "approved", "linked", "expired", "refused"])
1204
- });
1205
- var MobileStateSchema = z21.object({
1206
- enabled: z21.boolean(),
1207
- relayUrl: z21.string(),
1208
- account: z21.object({ login: z21.string(), accountId: z21.string() }).nullable(),
1209
- signin: z21.object({ userCode: z21.string(), verificationUri: z21.string(), expiresAt: z21.string().datetime() }).nullable(),
1489
+ var MobilePairingSchema = z23.object({
1490
+ id: z23.string(),
1491
+ label: z23.string(),
1492
+ code: z23.string().nullable(),
1493
+ expiresAt: z23.string().datetime(),
1494
+ state: z23.enum(["waiting", "confirm", "approved", "linked", "expired", "refused"])
1495
+ });
1496
+ var MobileStateSchema = z23.object({
1497
+ enabled: z23.boolean(),
1498
+ relayUrl: z23.string(),
1499
+ account: z23.object({ login: z23.string(), accountId: z23.string() }).nullable(),
1500
+ signin: z23.object({ userCode: z23.string(), verificationUri: z23.string(), expiresAt: z23.string().datetime() }).nullable(),
1210
1501
  /** The last sign-in that did not end with a session; cleared by the next one. */
1211
- signinError: z21.enum(["expired", "denied", "not_allowed", "failed"]).nullable(),
1502
+ signinError: z23.enum(["expired", "denied", "not_allowed", "failed"]).nullable(),
1212
1503
  link: MobileLinkStateSchema,
1213
- devices: z21.array(z21.object({ id: z21.string(), label: z21.string(), approvedAt: z21.string(), online: z21.boolean(), lastSeenAt: z21.string().optional() })),
1214
- pairings: z21.array(MobilePairingSchema)
1504
+ devices: z23.array(z23.object({ id: z23.string(), label: z23.string(), approvedAt: z23.string(), online: z23.boolean(), lastSeenAt: z23.string().optional() })),
1505
+ pairings: z23.array(MobilePairingSchema),
1506
+ /** « Taper dans les terminaux depuis le téléphone »: absent from an older daemon, which has no phone terminal. */
1507
+ terminalInput: z23.boolean().optional()
1215
1508
  });
1216
1509
 
1217
1510
  // ../protocol/src/messages.ts
1218
- var RefusalCodeSchema = z22.enum(["stale", "read_only", "no_prompt", "not_taken", "busy", "unknown_session", "nothing_to_decide", "not_offered", "free_text", "note_not_typed", "unavailable", "invalid", "attachment_missing", "attachments_not_accepted"]);
1219
- var SessionEventSchema = z22.object({
1220
- name: z22.enum(["SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", "Notification", "Stop", "SessionEnd", "PaneChanged", "PaneGone", "PanePrompt", "PaneIdle", "InjectFailed", "Decided", "PostToolUse", "PostToolUseFailure", "StopFailure", "SubagentStart", "SubagentStop", "PaneTitle", "Renamed", "NativeRequest", "AgentMessage", "QueueUpdate"]),
1221
- at: z22.string().datetime(),
1222
- source: z22.enum(["hook", "pane", "daemon"]),
1223
- tool: z22.string().optional(),
1224
- text: z22.string().optional(),
1225
- options: z22.array(z22.string()).optional(),
1511
+ var RefusalCodeSchema = z24.enum(["stale", "read_only", "no_prompt", "not_taken", "busy", "unknown_session", "nothing_to_decide", "not_offered", "free_text", "note_not_typed", "unavailable", "invalid", "attachment_missing", "attachments_not_accepted"]);
1512
+ var SessionEventSchema = z24.object({
1513
+ name: z24.enum(["SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", "Notification", "Stop", "SessionEnd", "PaneChanged", "PaneGone", "PanePrompt", "PaneIdle", "InjectFailed", "Decided", "PostToolUse", "PostToolUseFailure", "StopFailure", "SubagentStart", "SubagentStop", "PaneTitle", "Renamed", "NativeRequest", "AgentMessage", "QueueUpdate"]),
1514
+ at: z24.string().datetime(),
1515
+ source: z24.enum(["hook", "pane", "daemon"]),
1516
+ tool: z24.string().optional(),
1517
+ text: z24.string().optional(),
1518
+ options: z24.array(z24.string()).optional(),
1226
1519
  /** Each option's description, by index ('' when it has none); left out when no option has one. */
1227
- optionDetails: z22.array(z22.string()).optional(),
1228
- kind: z22.enum(["question", "permission", "plan", "diff"]).optional(),
1520
+ optionDetails: z24.array(z24.string()).optional(),
1521
+ kind: z24.enum(["question", "permission", "plan", "diff"]).optional(),
1229
1522
  /** PanePrompt: what to review in full before deciding (a plan read in the terminal), when `text` is its summary. */
1230
- body: z22.string().optional(),
1231
- exitCode: z22.number().int().nullable().optional(),
1232
- helperId: z22.string().optional(),
1523
+ body: z24.string().optional(),
1524
+ exitCode: z24.number().int().nullable().optional(),
1525
+ helperId: z24.string().optional(),
1233
1526
  /** The helper's description, once known (Claude Code: its `.meta.json`, written after SubagentStart). */
1234
- task: z22.string().optional(),
1527
+ task: z24.string().optional(),
1235
1528
  /** PostToolUseFailure: the user interrupted the turn (Esc); Claude then waits for input with no Stop. */
1236
- interrupt: z22.boolean().optional(),
1529
+ interrupt: z24.boolean().optional(),
1237
1530
  /** UserPromptSubmit, PostToolUse: the images the prompt or the tool result carried, by attachment id. */
1238
- attachments: z22.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(),
1531
+ attachments: z24.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(),
1239
1532
  /** PostToolUse: some of the result's images were not kept. */
1240
- imagesDropped: z22.boolean().optional(),
1533
+ imagesDropped: z24.boolean().optional(),
1241
1534
  /** QueueUpdate: OMP's queue as it stands. */
1242
- queue: z22.array(z22.object({ text: z22.string(), mode: z22.enum(["steer", "follow_up"]) })).optional(),
1535
+ queue: z24.array(z24.object({ text: z24.string(), mode: z24.enum(["steer", "follow_up"]) })).optional(),
1243
1536
  /** AgentMessage: the harness's own message, its text so far (`streaming`) or whole. `messageId` is unique for the session's life. */
1244
- messageId: z22.string().optional(),
1245
- streaming: z22.boolean().optional(),
1537
+ messageId: z24.string().optional(),
1538
+ streaming: z24.boolean().optional(),
1246
1539
  /** NativeRequest: the dialog's id, and OMP's `ask` questions when it is one. */
1247
- requestId: z22.string().optional(),
1248
- questions: z22.array(AskQuestionSchema).optional(),
1540
+ requestId: z24.string().optional(),
1541
+ questions: z24.array(AskQuestionSchema).optional(),
1249
1542
  /** Stop: its text is already in the thread as AgentMessage cards, which the reply card must not repeat. */
1250
- streamed: z22.boolean().optional(),
1543
+ streamed: z24.boolean().optional(),
1251
1544
  /** Native tracking (spec 2026-10-13 §2): the harness's id of the tool call, so its result lands on the same row. */
1252
- toolUseId: z22.string().optional(),
1545
+ toolUseId: z24.string().optional(),
1253
1546
  /** The tool's input as the harness gave it, every string capped by the hook. */
1254
- toolInput: z22.record(z22.string(), z22.unknown()).optional(),
1547
+ toolInput: z24.record(z24.string(), z24.unknown()).optional(),
1255
1548
  /** PostToolUse: the result as text; SubagentStop: nothing (the report travels in `text`). */
1256
- output: z22.string().optional(),
1257
- durationMs: z22.number().nonnegative().optional(),
1549
+ output: z24.string().optional(),
1550
+ durationMs: z24.number().nonnegative().optional(),
1258
1551
  /** PostToolUseFailure: the harness's error message. */
1259
- error: z22.string().optional(),
1552
+ error: z24.string().optional(),
1260
1553
  /** The session's transcript, or the helper's on SubagentStop; the daemon reads its tail for the agent's messages. */
1261
- transcriptPath: z22.string().optional(),
1554
+ transcriptPath: z24.string().optional(),
1262
1555
  /** Decided: what was chosen when the daemon knows it. */
1263
1556
  decision: DecisionSchema.optional(),
1264
1557
  /** Decided: the request was refused by Ledge closing the session (its interrupt keys), not by the user's answer. */
1265
- byClose: z22.literal(true).optional(),
1558
+ byClose: z24.literal(true).optional(),
1266
1559
  /** The agent's own session id when the hook names it, so the daemon can resume that conversation. */
1267
- agentSessionId: z22.string().optional()
1560
+ agentSessionId: z24.string().optional()
1268
1561
  });
1269
- var RecentSchema = z22.object({ cwd: z22.string().min(1), project: z22.string().min(1), lastAt: z22.string().datetime() });
1562
+ var RecentSchema = z24.object({ cwd: z24.string().min(1), project: z24.string().min(1), lastAt: z24.string().datetime() });
1270
1563
  var SEMVER = /^\d+\.\d+\.\d+$/;
1271
- var DaemonInfoSchema = z22.object({
1272
- version: z22.string(),
1273
- install: z22.enum(["npm", "git", "unknown"]),
1274
- systemd: z22.boolean(),
1275
- manual: z22.string().optional(),
1276
- routing: z22.boolean().optional(),
1277
- archive: z22.boolean().optional(),
1564
+ var DaemonInfoSchema = z24.object({
1565
+ version: z24.string(),
1566
+ install: z24.enum(["npm", "git", "unknown"]),
1567
+ systemd: z24.boolean(),
1568
+ manual: z24.string().optional(),
1569
+ routing: z24.boolean().optional(),
1570
+ archive: z24.boolean().optional(),
1278
1571
  /** Takes `model` and `effort` on `session.launch` and answers `models.list` (#58). */
1279
- models: z22.boolean().optional(),
1572
+ models: z24.boolean().optional(),
1280
1573
  /** Drives OMP over its RPC: launching `omp` sessions is possible when the binary is there (`models.list` says so). */
1281
- omp: z22.boolean().optional(),
1574
+ omp: z24.boolean().optional(),
1282
1575
  /** Takes `session.model`: a live session's model and effort changed (#58, lot 2). */
1283
- modelSwitch: z22.boolean().optional(),
1576
+ modelSwitch: z24.boolean().optional(),
1577
+ /** Answers `session.commands`: the slash commands a session's agent offers. */
1578
+ commands: z24.boolean().optional(),
1284
1579
  /** Takes `approval` on an OMP `session.launch` (auto mode). */
1285
- ompApproval: z22.boolean().optional(),
1580
+ ompApproval: z24.boolean().optional(),
1286
1581
  /** Its home folder, so a client shows the folders under it as `~` (absent from older daemons). */
1287
- home: z22.string().optional(),
1288
- mobile: z22.boolean().optional(),
1582
+ home: z24.string().optional(),
1583
+ mobile: z24.boolean().optional(),
1289
1584
  /** Answers `openrig.status` and `openrig.act`: drives OpenRig on its machine. */
1290
- openrig: z22.boolean().optional(),
1585
+ openrig: z24.boolean().optional(),
1291
1586
  /** Answers `openrig.roles`, `openrig.role` and `openrig.roleFile`: reads OpenRig's roles (agent specs). */
1292
- openrigRoles: z22.boolean().optional()
1293
- });
1294
- var UpdateFailureSchema = z22.enum(["git-install", "no-systemd", "sessions-at-risk", "npm-failed", "busy"]);
1295
- var ServerMessageSchema = z22.discriminatedUnion("type", [
1587
+ openrigRoles: z24.boolean().optional(),
1588
+ /** Answers `openrig.row`: a queue row's state, for the OpenRig task cards of a thread. */
1589
+ openrigRows: z24.boolean().optional(),
1590
+ /** Answers `openrig.asks` and `openrig.answer`: what OpenRig asks the person, and their answers (« À toi »). */
1591
+ openrigAsks: z24.boolean().optional(),
1592
+ /** Answers `openrig.goal.send`, `openrig.goals` and `openrig.goal.reply`: goals given to Max (lot 2). */
1593
+ openrigGoals: z24.boolean().optional(),
1594
+ /** Takes `session.broadcast` (its `ledge bridge` too, on this machine): a client sends it only when this is set. */
1595
+ broadcast: z24.boolean().optional()
1596
+ });
1597
+ var UpdateFailureSchema = z24.enum(["git-install", "no-systemd", "sessions-at-risk", "npm-failed", "busy"]);
1598
+ var ServerMessageSchema = z24.discriminatedUnion("type", [
1296
1599
  SessionModelAcceptedSchema,
1297
- z22.object({ type: z22.literal("chat.routed"), qid: z22.string(), result: RouteResultSchema }),
1600
+ z24.object({ type: z24.literal("chat.routed"), qid: z24.string(), result: RouteResultSchema }),
1298
1601
  DocumentContentSchema,
1299
1602
  DocumentErrorSchema,
1300
1603
  AttachmentStoredSchema,
@@ -1303,7 +1606,9 @@ var ServerMessageSchema = z22.discriminatedUnion("type", [
1303
1606
  ReposInfoSchema,
1304
1607
  ReposFoundSchema,
1305
1608
  ModelsListingSchema,
1609
+ SessionCommandsListingSchema,
1306
1610
  OpenRigStateMessageSchema,
1611
+ OpenRigRowStateSchema,
1307
1612
  OpenRigDoneSchema,
1308
1613
  OpenRigSpecListSchema,
1309
1614
  OpenRigLaunchedSchema,
@@ -1311,97 +1616,113 @@ var ServerMessageSchema = z22.discriminatedUnion("type", [
1311
1616
  OpenRigRoleListSchema,
1312
1617
  OpenRigRoleDetailSchema,
1313
1618
  OpenRigRoleFileContentSchema,
1619
+ OpenRigAsksChangedSchema,
1620
+ OpenRigAnsweredSchema,
1621
+ OpenRigGoalSentSchema,
1622
+ OpenRigGoalsChangedSchema,
1623
+ OpenRigGoalRepliedSchema,
1314
1624
  /** `recents`: the folders of past sessions, most recent first. `launcher`: the command that runs `ledge` inside WSL
1315
1625
  * (`[node, cli]`), so the overlay can attach a terminal to a session with `<launcher> attach <id>`. `daemon`: absent
1316
1626
  * from daemons older than the auto-update. */
1317
- z22.object({ type: z22.literal("snapshot"), sessions: z22.array(SessionSchema), recents: z22.array(RecentSchema).optional(), launcher: z22.array(z22.string()).optional(), daemon: DaemonInfoSchema.optional(), sshAlias: SshAliasSchema.optional() }),
1318
- z22.object({ type: z22.literal("session.updated"), session: SessionSchema }),
1627
+ z24.object({ type: z24.literal("snapshot"), sessions: z24.array(SessionSchema), recents: z24.array(RecentSchema).optional(), launcher: z24.array(z24.string()).optional(), daemon: DaemonInfoSchema.optional(), sshAlias: SshAliasSchema.optional() }),
1628
+ z24.object({ type: z24.literal("session.updated"), session: SessionSchema }),
1319
1629
  /** OMP: the instructions taken back from its queue by an interrupt that restores it; the asker puts them back in its draft. */
1320
- z22.object({
1321
- type: z22.literal("session.queue.restored"),
1322
- id: z22.string(),
1323
- texts: z22.array(z22.string()),
1630
+ z24.object({
1631
+ type: z24.literal("session.queue.restored"),
1632
+ id: z24.string(),
1633
+ texts: z24.array(z24.string()),
1324
1634
  /** The same instructions with the images they carried; `imagesDropped`: some images could not be put back. */
1325
- entries: z22.array(z22.object({ text: z22.string(), attachments: z22.array(AttachmentIdSchema).optional() })).optional(),
1326
- imagesDropped: z22.boolean().optional()
1635
+ entries: z24.array(z24.object({ text: z24.string(), attachments: z24.array(AttachmentIdSchema).optional() })).optional(),
1636
+ imagesDropped: z24.boolean().optional()
1327
1637
  }),
1328
- z22.object({ type: z22.literal("session.removed"), id: z22.string() }),
1329
- z22.object({ type: z22.literal("session.preview"), id: z22.string(), lines: z22.array(z22.string()) }),
1638
+ z24.object({ type: z24.literal("session.removed"), id: z24.string() }),
1639
+ z24.object({ type: z24.literal("session.preview"), id: z24.string(), lines: z24.array(z24.string()) }),
1330
1640
  /** A session's thread, on request (spec 2026-10-13 §5); then each created or updated item, broadcast. */
1331
- z22.object({ type: z22.literal("session.thread"), id: z22.string(), items: z22.array(ThreadItemSchema) }),
1332
- z22.object({ type: z22.literal("session.thread.item"), id: z22.string(), item: ThreadItemSchema }),
1641
+ z24.object({ type: z24.literal("session.thread"), id: z24.string(), items: z24.array(ThreadItemSchema) }),
1642
+ z24.object({ type: z24.literal("session.thread.item"), id: z24.string(), item: ThreadItemSchema }),
1333
1643
  /** Answer to the requester of a `session.launch`: the session exists (its `session.updated` is broadcast as usual). */
1334
- z22.object({ type: z22.literal("session.launched"), id: z22.string() }),
1644
+ z24.object({ type: z24.literal("session.launched"), id: z24.string() }),
1335
1645
  /** Answer to the requester of a `session.close`, once per row closed: the session `id` and how it ended. */
1336
- z22.object({ type: z22.literal("session.closed"), qid: z22.string(), row: z22.number().int().min(0), id: z22.string(), how: z22.enum(["exit", "killed"]) }),
1337
- z22.object({ type: z22.literal("recents"), recents: z22.array(RecentSchema) }),
1646
+ z24.object({ type: z24.literal("session.closed"), qid: z24.string(), row: z24.number().int().min(0), id: z24.string(), how: z24.enum(["exit", "killed"]) }),
1647
+ z24.object({ type: z24.literal("recents"), recents: z24.array(RecentSchema) }),
1338
1648
  /** Answer to the requester of a `folder.list` or `folder.create`: `path` resolved (`~` expanded), `parent` null at the
1339
1649
  * root, `entries` its subfolders by name (hidden ones left out). A failure keeps the asked path and says why in `error`,
1340
1650
  * never in an `error` message, which the launch form reads as a failed launch. */
1341
- z22.object({
1342
- type: z22.literal("folder.listing"),
1343
- path: z22.string(),
1344
- parent: z22.string().nullable(),
1345
- entries: z22.array(z22.string()),
1346
- error: z22.string().optional(),
1651
+ z24.object({
1652
+ type: z24.literal("folder.listing"),
1653
+ path: z24.string(),
1654
+ parent: z24.string().nullable(),
1655
+ entries: z24.array(z24.string()),
1656
+ error: z24.string().optional(),
1347
1657
  /** The request this answers, when it carried one. */
1348
- requestId: z22.string().optional(),
1658
+ requestId: z24.string().optional(),
1349
1659
  /** Those `entries` that are Git repositories, with their branch (the short commit when HEAD is detached). */
1350
- repos: z22.array(z22.object({ name: z22.string(), branch: z22.string() })).optional()
1660
+ repos: z24.array(z24.object({ name: z24.string(), branch: z24.string() })).optional()
1351
1661
  }),
1352
1662
  /** The chat (spec 2026-10-11 §5): what Ledge reads, its words as they come, the final text, or why it stopped; the day's turns after each snapshot. */
1353
- z22.object({ type: z22.literal("chat.step"), qid: z22.string(), step: ChatStepSchema }),
1354
- z22.object({ type: z22.literal("chat.delta"), qid: z22.string(), text: z22.string() }),
1355
- z22.object({ type: z22.literal("chat.done"), qid: z22.string(), text: z22.string(), at: z22.string().datetime(), proposal: ChatProposalSchema.optional(), proposals: ChatProposalsSchema.optional(), relay: ChatRelaySchema.optional(), closes: ChatClosesSchema.optional(), projectProposal: ChatProjectProposalSchema.optional(), tasks: ChatTasksSchema.optional(), actions: ChatActionsSchema.optional() }),
1663
+ z24.object({ type: z24.literal("chat.step"), qid: z24.string(), step: ChatStepSchema }),
1664
+ z24.object({ type: z24.literal("chat.delta"), qid: z24.string(), text: z24.string() }),
1665
+ z24.object({ type: z24.literal("chat.done"), qid: z24.string(), text: z24.string(), at: z24.string().datetime(), proposal: ChatProposalSchema.optional(), proposals: ChatProposalsSchema.optional(), relay: ChatRelaySchema.optional(), closes: ChatClosesSchema.optional(), projectProposal: ChatProjectProposalSchema.optional(), tasks: ChatTasksSchema.optional(), actions: ChatActionsSchema.optional() }),
1356
1666
  /** What a `chat.act` applied: the rows done, and the one that failed with why (the rows after it stay proposed). */
1357
- z22.object({ type: z22.literal("chat.acted"), rid: z22.string(), qid: z22.string(), done: z22.array(z22.number().int().min(0)), failed: z22.array(z22.object({
1358
- row: z22.number().int().min(0),
1359
- message: z22.string(),
1667
+ z24.object({ type: z24.literal("chat.acted"), rid: z24.string(), qid: z24.string(), done: z24.array(z24.number().int().min(0)), failed: z24.array(z24.object({
1668
+ row: z24.number().int().min(0),
1669
+ message: z24.string(),
1360
1670
  /** nothing was sent */
1361
- refused: z22.literal(true).optional()
1671
+ refused: z24.literal(true).optional()
1362
1672
  })) }),
1363
1673
  /** What an `action.run` came to: `row` the action as the daemon resolved it (its summary, its risk); `reason` why it was not
1364
1674
  * done, with `code` (`refused`: not possible now; `agent`: a session may not run it; `confirm_required`: destructive, ask
1365
1675
  * again; `failed`: the handler turned it down; a free string, as an `error`'s). */
1366
- z22.object({ type: z22.literal("action.result"), rid: z22.string(), action: z22.string().min(1).max(40), row: ChatActionSchema.optional(), reason: z22.string().optional(), code: z22.string().optional() }),
1367
- z22.object({ type: z22.literal("chat.error"), qid: z22.string(), message: z22.string() }),
1368
- z22.object({ type: z22.literal("chat.history"), turns: z22.array(ChatTurnSchema) }),
1676
+ z24.object({ type: z24.literal("action.result"), rid: z24.string(), action: z24.string().min(1).max(40), row: ChatActionSchema.optional(), reason: z24.string().optional(), code: z24.string().optional() }),
1677
+ z24.object({ type: z24.literal("chat.error"), qid: z24.string(), message: z24.string() }),
1678
+ z24.object({ type: z24.literal("chat.history"), turns: z24.array(ChatTurnSchema) }),
1369
1679
  /** The daemon updating itself: npm is running, then the service restarts (the socket closes right after). */
1370
- z22.object({ type: z22.literal("update.progress"), version: z22.string(), step: z22.enum(["installing", "restarting"]) }),
1680
+ z24.object({ type: z24.literal("update.progress"), version: z24.string(), step: z24.enum(["installing", "restarting"]) }),
1371
1681
  /** Nothing was changed. `detail`: the useful end of npm's output; `command`: what the person can run instead. */
1372
- z22.object({ type: z22.literal("update.failed"), version: z22.string(), reason: UpdateFailureSchema, detail: z22.string().optional(), command: z22.string().optional() }),
1682
+ z24.object({ type: z24.literal("update.failed"), version: z24.string(), reason: UpdateFailureSchema, detail: z24.string().optional(), command: z24.string().optional() }),
1373
1683
  /** The shared machines list (spec 2026-10-14 §5), sent to local clients only. */
1374
- z22.object({ type: z22.literal("machines"), machines: MachinesSchema }),
1684
+ z24.object({ type: z24.literal("machines"), machines: MachinesSchema }),
1375
1685
  /** The local daemon's projects and folder rules (spec 2026-10-16 build §5), sent to local clients only. */
1376
- z22.object({ type: z22.literal("projects"), projects: ProjectsSchema }),
1686
+ z24.object({ type: z24.literal("projects"), projects: ProjectsSchema }),
1377
1687
  /** The island's settings shared by the local fronts; null until a front sets them (the island then sends its own). Local clients only. */
1378
- z22.object({ type: z22.literal("island"), prefs: IslandPrefsSchema.nullable() }),
1688
+ z24.object({ type: z24.literal("island"), prefs: IslandPrefsSchema.nullable() }),
1379
1689
  /** Mobile access (lot 3), after the island in each snapshot and on every change. Local clients only. */
1380
- z22.object({ type: z22.literal("mobile"), state: MobileStateSchema }),
1690
+ z24.object({ type: z24.literal("mobile"), state: MobileStateSchema }),
1691
+ /** The sessions a phone types into (« Téléphone au clavier »), after each snapshot and each change; `device` is its label. */
1692
+ z24.object({ type: z24.literal("terminal.holders"), holds: z24.array(z24.object({ id: z24.string(), device: z24.string() })) }),
1381
1693
  /** The daemon's immediate answer to a `session.message`: delivered (`accepted`), held for later (`queued`), left to Claude's own SendMessage (`native`), or refused with a `reason`. */
1382
- z22.object({ type: z22.literal("message.ack"), rid: z22.string(), outcome: z22.enum(["accepted", "queued", "native", "refused"]), reason: z22.string().optional() }),
1694
+ z24.object({
1695
+ type: z24.literal("message.ack"),
1696
+ rid: z24.string(),
1697
+ outcome: z24.enum(["accepted", "queued", "native", "refused"]),
1698
+ reason: z24.string().optional(),
1699
+ /** A broadcast's per-recipient outcome, by name. */
1700
+ recipients: z24.object({ sent: z24.array(z24.string()), refused: z24.array(z24.object({ name: z24.string(), reason: z24.string() })) }).optional()
1701
+ }),
1702
+ /** The answer to a `session.broadcast`: who got it (`sent`) and who did not; `reason`: the whole broadcast was refused. */
1703
+ z24.object({ type: z24.literal("session.broadcast.result"), rid: z24.string(), sent: z24.array(z24.object({ id: z24.string(), name: z24.string() })), refused: z24.array(z24.object({ name: z24.string(), reason: z24.string() })), reason: z24.string().optional() }),
1383
1704
  /** The answer to a `message.read`: the body with its sender, target and time, or the refusal's `reason`. */
1384
- z22.object({ type: z22.literal("message.body"), id: z22.string(), from: z22.string().optional(), to: z22.string().optional(), at: z22.string().optional(), text: z22.string().optional(), reason: z22.string().optional() }),
1705
+ z24.object({ type: z24.literal("message.body"), id: z24.string(), from: z24.string().optional(), to: z24.string().optional(), at: z24.string().optional(), text: z24.string().optional(), reason: z24.string().optional() }),
1385
1706
  TaskResultSchema,
1386
1707
  SessionHandoverResultSchema,
1387
1708
  ContextPrefsMessageSchema,
1388
1709
  HandoverResultSchema,
1389
1710
  TaskUpdatedSchema,
1390
- z22.object({
1391
- type: z22.literal("error"),
1392
- message: z22.string(),
1393
- id: z22.string().optional(),
1711
+ z24.object({
1712
+ type: z24.literal("error"),
1713
+ message: z24.string(),
1714
+ id: z24.string().optional(),
1394
1715
  /** Le type du message client refusé. */
1395
- request: z22.string().optional(),
1716
+ request: z24.string().optional(),
1396
1717
  /** Ce que le front doit reconnaître au-delà du texte (NOTE_NOT_TYPED) ; une chaîne libre, qu'un front plus ancien ignore. */
1397
- code: z22.string().optional()
1718
+ code: z24.string().optional()
1398
1719
  })
1399
1720
  ]);
1400
1721
  var MESSAGE_MAX = 2e4;
1401
1722
  var SUMMARY_MAX = 500;
1402
- var launchRows = z22.array(z22.number().int().min(0).max(MAX_PROPOSALS - 1)).min(1).max(MAX_PROPOSALS).refine((r) => new Set(r).size === r.length, "a row twice");
1403
- var ClientMessageSchema = z22.discriminatedUnion("type", [
1404
- z22.object({ type: z22.literal("chat.route"), qid: z22.string().min(1).max(100), text: z22.string().min(1).max(2e4), tool: ToolSchema.optional(), context: RoutingContextSchema }),
1723
+ var launchRows = z24.array(z24.number().int().min(0).max(MAX_PROPOSALS - 1)).min(1).max(MAX_PROPOSALS).refine((r) => new Set(r).size === r.length, "a row twice");
1724
+ var ClientMessageSchema = z24.discriminatedUnion("type", [
1725
+ z24.object({ type: z24.literal("chat.route"), qid: z24.string().min(1).max(100), text: z24.string().min(1).max(2e4), tool: ToolSchema.optional(), context: RoutingContextSchema }),
1405
1726
  DocumentReadSchema,
1406
1727
  AttachmentPutSchema,
1407
1728
  AttachmentCaptureSchema,
@@ -1409,7 +1730,9 @@ var ClientMessageSchema = z22.discriminatedUnion("type", [
1409
1730
  ReposInspectSchema,
1410
1731
  ReposScanSchema,
1411
1732
  ModelsListSchema,
1733
+ SessionCommandsSchema,
1412
1734
  OpenRigStatusSchema,
1735
+ OpenRigRowSchema,
1413
1736
  OpenRigActSchema,
1414
1737
  OpenRigSpecsSchema,
1415
1738
  OpenRigLaunchSchema,
@@ -1417,155 +1740,174 @@ var ClientMessageSchema = z22.discriminatedUnion("type", [
1417
1740
  OpenRigRolesSchema,
1418
1741
  OpenRigRoleSchema,
1419
1742
  OpenRigRoleFileSchema,
1743
+ OpenRigAsksSchema,
1744
+ OpenRigAnswerSchema,
1745
+ OpenRigGoalSendSchema,
1746
+ OpenRigGoalsSchema,
1747
+ OpenRigGoalReplySchema,
1420
1748
  /** The overlay starts a session: `cwd` is a WSL path (`~` allowed), `name` a preferred bot name (the daemon picks a
1421
1749
  * free one otherwise), `prompt` the agent's first instruction, `continue` resumes the folder's last conversation.
1422
1750
  * With `qid` it is the chat card of that turn: the daemon launches the turn's proposal and ignores the other fields
1423
1751
  * but `rows`, `model` and `effort`. */
1424
- z22.object({
1425
- type: z22.literal("session.launch"),
1752
+ z24.object({
1753
+ type: z24.literal("session.launch"),
1426
1754
  tool: ToolSchema,
1427
- cwd: z22.string().min(1),
1428
- name: z22.string().optional(),
1429
- prompt: z22.string().optional(),
1430
- continue: z22.boolean().optional(),
1431
- qid: z22.string().min(1).optional(),
1755
+ cwd: z24.string().min(1),
1756
+ name: z24.string().optional(),
1757
+ prompt: z24.string().optional(),
1758
+ continue: z24.boolean().optional(),
1759
+ qid: z24.string().min(1).optional(),
1432
1760
  /** With `qid`: the card's rows to launch (#24), indexes into the turn's `proposals`, each once; the first row without it. */
1433
1761
  rows: launchRows.optional(),
1434
1762
  /** Folders in addition to `cwd` (Claude: `--add-dir`); resolved like `cwd`. */
1435
- dirs: z22.array(z22.string().min(1)).max(20).optional(),
1763
+ dirs: z24.array(z24.string().min(1)).max(20).optional(),
1436
1764
  /** The agent's model and effort (#58), the agent's own default when left out; with `qid`, for every row launched. */
1437
1765
  model: ModelIdSchema.optional(),
1438
1766
  effort: EffortSchema.optional(),
1439
1767
  /** OMP only: its approval mode, `always-ask` when left out. */
1440
1768
  approval: OmpApprovalSchema.optional(),
1441
1769
  /** Routing by the fleet, removed before the message reaches the daemon. */
1442
- machineId: z22.string().optional()
1770
+ machineId: z24.string().optional()
1443
1771
  }),
1444
1772
  /** The launch form's folder browser: list a folder's subfolders (home when no `path`), or make `name` inside `parent`
1445
1773
  * and list it. Both are answered with a `folder.listing`. */
1446
- z22.object({
1447
- type: z22.literal("folder.list"),
1448
- path: z22.string().optional(),
1774
+ z24.object({
1775
+ type: z24.literal("folder.list"),
1776
+ path: z24.string().optional(),
1449
1777
  /** Routing by the fleet, removed before the message reaches the daemon. */
1450
- machineId: z22.string().optional(),
1778
+ machineId: z24.string().optional(),
1451
1779
  /** Copied into the `folder.listing` that answers; the fleet relays only that listing, from the machine asked. */
1452
- requestId: z22.string().min(1).max(100).optional()
1780
+ requestId: z24.string().min(1).max(100).optional()
1453
1781
  }),
1454
- z22.object({
1455
- type: z22.literal("folder.create"),
1456
- parent: z22.string().min(1),
1457
- name: z22.string().min(1),
1782
+ z24.object({
1783
+ type: z24.literal("folder.create"),
1784
+ parent: z24.string().min(1),
1785
+ name: z24.string().min(1),
1458
1786
  /** As for `folder.list`: routing by the fleet, and the request its `folder.listing` answers. */
1459
- machineId: z22.string().optional(),
1460
- requestId: z22.string().min(1).max(100).optional()
1787
+ machineId: z24.string().optional(),
1788
+ requestId: z24.string().min(1).max(100).optional()
1461
1789
  }),
1462
1790
  /** `steer`: OMP only, redirect the turn running now instead of queueing the text after it. */
1463
1791
  /** OMP's `ask`: the answers to every question of the dialog `requestId`, in order (`selected` labels, and/or free `text`); `cancel` declines it. */
1464
- z22.object({ type: z22.literal("session.answer"), id: z22.string(), requestId: z22.string().min(1).max(200), answers: z22.array(z22.object({ id: z22.string(), selected: z22.array(z22.string().max(2e3)).max(100), text: z22.string().max(2e4).optional() })).max(50), cancel: z22.boolean().optional() }),
1465
- z22.object({ type: z22.literal("session.reply"), id: z22.string(), text: z22.string(), attachments: z22.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(), steer: z22.boolean().optional() }),
1792
+ z24.object({ type: z24.literal("session.answer"), id: z24.string(), requestId: z24.string().min(1).max(200), answers: z24.array(z24.object({ id: z24.string(), selected: z24.array(z24.string().max(2e3)).max(100), text: z24.string().max(2e4).optional() })).max(50), cancel: z24.boolean().optional() }),
1793
+ z24.object({ type: z24.literal("session.reply"), id: z24.string(), text: z24.string(), attachments: z24.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(), steer: z24.boolean().optional() }),
1466
1794
  /** The chat card's instruction (spec 2026-10-12 relay §4): sent now if the session is free, else queued until it is. */
1467
- z22.object({ type: z22.literal("session.relay"), qid: z22.string().min(1) }),
1795
+ z24.object({ type: z24.literal("session.relay"), qid: z24.string().min(1) }),
1468
1796
  /** Takes the card's queued instruction back out of the queue. */
1469
- z22.object({ type: z22.literal("session.relay.cancel"), qid: z22.string().min(1) }),
1797
+ z24.object({ type: z24.literal("session.relay.cancel"), qid: z24.string().min(1) }),
1470
1798
  /** The chat's generic card (action registry spec §5.1): applies its rows in order (all of them without `rows`), stopping at
1471
1799
  * the first failure. `confirmed` says the front asked again; refused without it when a row is destructive. */
1472
- z22.object({
1473
- type: z22.literal("chat.act"),
1474
- rid: z22.string().min(1).max(100),
1475
- qid: z22.string().min(1),
1800
+ z24.object({
1801
+ type: z24.literal("chat.act"),
1802
+ rid: z24.string().min(1).max(100),
1803
+ qid: z24.string().min(1),
1476
1804
  rows: launchRows.optional(),
1477
- confirmed: z22.literal(true).optional(),
1805
+ confirmed: z24.literal(true).optional(),
1478
1806
  /** « Refuser »: each row (session.decide only) answers its session's request with deny, whatever its own decision; never
1479
1807
  * confirmed, and allowed on a request shown cut. The rows become `denied`. */
1480
- deny: z22.literal(true).optional()
1808
+ deny: z24.literal(true).optional()
1481
1809
  }),
1482
1810
  /** « Ignorer » the turn's cards, for every device and for Ledge (who is told at the next question); `undo` opens them
1483
1811
  * again (« Revoir »). Refused while one of them is under way. Every client gets the turn's `ignoredAt` through chat.history. */
1484
- z22.object({ type: z22.literal("chat.ignore"), qid: z22.string().min(1), undo: z22.literal(true).optional() }),
1812
+ z24.object({ type: z24.literal("chat.ignore"), qid: z24.string().min(1), undo: z24.literal(true).optional() }),
1485
1813
  /** A registry action run outside the chat (#93, the CLI): the daemon resolves `args` as it does a generic card's row, then
1486
1814
  * applies it through its own handler. `by` the session that asks, left out for the user; `confirmed` for a destructive one. */
1487
- z22.object({
1488
- type: z22.literal("action.run"),
1489
- rid: z22.string().min(1).max(100),
1490
- by: z22.string().min(1).optional(),
1815
+ z24.object({
1816
+ type: z24.literal("action.run"),
1817
+ rid: z24.string().min(1).max(100),
1818
+ by: z24.string().min(1).optional(),
1491
1819
  /** `by`'s key (LEDGE_SESSION_KEY) */
1492
- key: z22.string().max(128).optional(),
1820
+ key: z24.string().max(128).optional(),
1493
1821
  action: ActionIdSchema,
1494
- args: z22.record(z22.unknown()),
1495
- confirmed: z22.literal(true).optional()
1822
+ args: z24.record(z24.unknown()),
1823
+ confirmed: z24.literal(true).optional()
1496
1824
  }),
1497
1825
  /** The chat's close card: closes the turn's sessions, `rows` (indexes into its `closes`) or all of them. */
1498
- z22.object({ type: z22.literal("session.close"), qid: z22.string().min(1), rows: launchRows.optional() }),
1826
+ z24.object({ type: z24.literal("session.close"), qid: z24.string().min(1), rows: launchRows.optional() }),
1499
1827
  /** `always` and `note` only where the harness offers them (`offers`); a note goes with `deny`, for the agent to read. */
1500
- z22.object({
1501
- type: z22.literal("session.decide"),
1502
- id: z22.string(),
1828
+ z24.object({
1829
+ type: z24.literal("session.decide"),
1830
+ id: z24.string(),
1503
1831
  decision: DecisionSchema,
1504
- note: z22.string().trim().min(1).max(NOTE_MAX).optional(),
1832
+ note: z24.string().trim().min(1).max(NOTE_MAX).optional(),
1505
1833
  /** The request the user saw when deciding: refused (the request changed) unless it is still the pending one. Left out by older fronts and the island.
1506
1834
  * `key` (pendingKey) covers its whole content; older fronts send kind and text only. */
1507
- expect: PendingSchema.pick({ kind: true, text: true }).extend({ key: z22.string().max(64).optional() }).optional()
1835
+ expect: PendingSchema.pick({ kind: true, text: true }).extend({ key: z24.string().max(64).optional() }).optional()
1508
1836
  }),
1509
- z22.object({ type: z22.literal("session.focus"), id: z22.string() }),
1510
- z22.object({ type: z22.literal("session.kill"), id: z22.string() }),
1837
+ z24.object({ type: z24.literal("session.focus"), id: z24.string() }),
1838
+ z24.object({ type: z24.literal("session.kill"), id: z24.string() }),
1511
1839
  /** `restoreQueue` (OMP): also take back what waits in its queue, returned as `session.queue.restored` to put in the draft. */
1512
- z22.object({ type: z22.literal("session.interrupt"), id: z22.string(), restoreQueue: z22.boolean().optional() }),
1840
+ z24.object({ type: z24.literal("session.interrupt"), id: z24.string(), restoreQueue: z24.boolean().optional() }),
1513
1841
  /** Removes a finished (exited) or read-only (hook_only) session from the list; refused for a live launcher session. */
1514
- z22.object({ type: z22.literal("session.dismiss"), id: z22.string() }),
1842
+ z24.object({ type: z24.literal("session.dismiss"), id: z24.string() }),
1515
1843
  /** Puts a session in the archive: it leaves the live list but is kept. */
1516
- z22.object({ type: z22.literal("session.archive"), id: z22.string() }),
1844
+ z24.object({ type: z24.literal("session.archive"), id: z24.string() }),
1517
1845
  /** Takes an archived session back out of the archive, as it was. */
1518
- z22.object({ type: z22.literal("session.restore"), id: z22.string() }),
1846
+ z24.object({ type: z24.literal("session.restore"), id: z24.string() }),
1519
1847
  /** Starts the agent again on an archived session's conversation. */
1520
- z22.object({ type: z22.literal("session.resume"), id: z22.string() }),
1848
+ z24.object({ type: z24.literal("session.resume"), id: z24.string() }),
1521
1849
  /** Changes a live session's model and effort (#58, lot 2), `null` for the agent's own default: the daemon restarts the
1522
1850
  * agent on the same conversation with them, at once when the session is free, else at its next free moment. */
1523
- z22.object({ type: z22.literal("session.model"), id: z22.string(), model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
1851
+ z24.object({ type: z24.literal("session.model"), id: z24.string(), model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
1524
1852
  /** Deletes a session for good, archived or not. */
1525
- z22.object({ type: z22.literal("session.delete"), id: z22.string() }),
1853
+ z24.object({ type: z24.literal("session.delete"), id: z24.string() }),
1526
1854
  /** The user names the session's topic from the overlay (500 characters at most, the hook's prompt cap); an empty topic hands back to the automatic sources. */
1527
- z22.object({ type: z22.literal("session.rename"), id: z22.string(), topic: z22.string().max(500) }),
1528
- z22.object({ type: z22.literal("session.thread"), id: z22.string() }),
1529
- z22.object({ type: z22.literal("session.register"), session: SessionSchema }),
1855
+ z24.object({ type: z24.literal("session.rename"), id: z24.string(), topic: z24.string().max(500) }),
1856
+ z24.object({ type: z24.literal("session.thread"), id: z24.string() }),
1857
+ z24.object({ type: z24.literal("session.register"), session: SessionSchema }),
1530
1858
  /** `agent` and `cwd` describe the session when the daemon does not know it yet (a hook from an agent started without ledge). */
1531
- z22.object({
1532
- type: z22.literal("session.event"),
1533
- id: z22.string(),
1859
+ z24.object({
1860
+ type: z24.literal("session.event"),
1861
+ id: z24.string(),
1534
1862
  event: SessionEventSchema,
1535
1863
  agent: ToolSchema.optional(),
1536
- cwd: z22.string().optional(),
1864
+ cwd: z24.string().optional(),
1537
1865
  /** The OpenRig seat the agent runs in (`OPENRIG_SESSION_NAME`, `pod-member@rig`), when OpenRig launched it. */
1538
1866
  rigSeat: RigSeatNameSchema.optional()
1539
1867
  }),
1540
- z22.object({ type: z22.literal("session.unregister"), id: z22.string(), exitCode: z22.number().int().nullable() }),
1541
- z22.object({ type: z22.literal("snapshot.request") }),
1542
- z22.object({ type: z22.literal("chat.ask"), qid: z22.string().min(1), text: z22.string(), images: z22.array(ImageUploadSchema).max(ATTACHMENTS_MAX).optional(), tool: ToolSchema.optional() }),
1543
- z22.object({ type: z22.literal("chat.cancel"), qid: z22.string().min(1) }),
1868
+ z24.object({ type: z24.literal("session.unregister"), id: z24.string(), exitCode: z24.number().int().nullable() }),
1869
+ z24.object({ type: z24.literal("snapshot.request") }),
1870
+ z24.object({ type: z24.literal("chat.ask"), qid: z24.string().min(1), text: z24.string(), images: z24.array(ImageUploadSchema).max(ATTACHMENTS_MAX).optional(), tool: ToolSchema.optional() }),
1871
+ z24.object({ type: z24.literal("chat.cancel"), qid: z24.string().min(1) }),
1544
1872
  /** Starts a new conversation with Ledge: the day's turns are cleared and the next question opens a new harness session. */
1545
- z22.object({ type: z22.literal("chat.reset") }),
1873
+ z24.object({ type: z24.literal("chat.reset") }),
1546
1874
  /** Installs `@paradow/ledge@version` and restarts the service (spec 2026-10-12 auto-update §6). */
1547
- z22.object({ type: z22.literal("update.daemon"), version: z22.string().regex(SEMVER) }),
1875
+ z24.object({ type: z24.literal("update.daemon"), version: z24.string().regex(SEMVER) }),
1548
1876
  /** Replaces the daemon's machines list (first connected front wins); refused unless valid. */
1549
- z22.object({ type: z22.literal("machines.set"), machines: MachinesSchema }),
1877
+ z24.object({ type: z24.literal("machines.set"), machines: MachinesSchema }),
1550
1878
  /** Replaces the local daemon's projects and rules as a whole; refused unless valid. */
1551
- z22.object({ type: z22.literal("projects.set"), projects: ProjectsSchema }),
1879
+ z24.object({ type: z24.literal("projects.set"), projects: ProjectsSchema }),
1552
1880
  /** Replaces the island's settings as a whole; refused unless valid. */
1553
- z22.object({ type: z22.literal("island.set"), prefs: IslandPrefsSchema }),
1881
+ z24.object({ type: z24.literal("island.set"), prefs: IslandPrefsSchema }),
1554
1882
  /** Mobile access (lot 3), local fronts only. A changed `relayUrl` drops the relay session. */
1555
- z22.object({ type: z22.literal("mobile.set"), enabled: z22.boolean(), relayUrl: RelayUrlSchema }),
1556
- z22.object({ type: z22.literal("mobile.signin") }),
1557
- z22.object({ type: z22.literal("mobile.signin.cancel") }),
1558
- z22.object({ type: z22.literal("mobile.signout") }),
1883
+ z24.object({ type: z24.literal("mobile.set"), enabled: z24.boolean(), relayUrl: RelayUrlSchema }),
1884
+ z24.object({ type: z24.literal("mobile.signin") }),
1885
+ z24.object({ type: z24.literal("mobile.signin.cancel") }),
1886
+ z24.object({ type: z24.literal("mobile.signout") }),
1559
1887
  /** While the link is offline: try again now. */
1560
- z22.object({ type: z22.literal("mobile.retry") }),
1561
- z22.object({ type: z22.literal("mobile.pairing.approve"), id: z22.string().min(1).max(100) }),
1562
- z22.object({ type: z22.literal("mobile.pairing.deny"), id: z22.string().min(1).max(100) }),
1888
+ z24.object({ type: z24.literal("mobile.retry") }),
1889
+ z24.object({ type: z24.literal("mobile.pairing.approve"), id: z24.string().min(1).max(100) }),
1890
+ z24.object({ type: z24.literal("mobile.pairing.deny"), id: z24.string().min(1).max(100) }),
1563
1891
  /** `id`: the device's fingerprint. */
1564
- z22.object({ type: z22.literal("mobile.device.revoke"), id: z22.string().min(1).max(100) }),
1892
+ z24.object({ type: z24.literal("mobile.device.revoke"), id: z24.string().min(1).max(100) }),
1893
+ /** « Taper dans les terminaux depuis le téléphone »; turned off, every phone loses the hand. */
1894
+ z24.object({ type: z24.literal("mobile.terminal"), input: z24.boolean() }),
1895
+ /** « Reprendre la main »: the phone typing into the session's terminal goes back to reading it. */
1896
+ z24.object({ type: z24.literal("terminal.release"), id: z24.string().min(1) }),
1565
1897
  /** One session writing to another by Ledge name (`to` may end in ` [ref]`); `intercept` (the Claude hook): answer `native` unless `to` is a live non-Claude session. */
1566
- z22.object({ type: z22.literal("session.message"), rid: z22.string().min(1), from: z22.string().min(1), to: z22.string().min(1), text: z22.string().min(1).max(MESSAGE_MAX), summary: z22.string().max(SUMMARY_MAX).optional(), intercept: z22.boolean().optional() }),
1898
+ z24.object({ type: z24.literal("session.message"), rid: z24.string().min(1), from: z24.string().min(1), to: z24.string().min(1), text: z24.string().min(1).max(MESSAGE_MAX), summary: z24.string().max(SUMMARY_MAX).optional(), intercept: z24.boolean().optional() }),
1899
+ /** The user writing to every session of a project, or to several sessions (ids or names). */
1900
+ z24.object({
1901
+ type: z24.literal("session.broadcast"),
1902
+ rid: z24.string().min(1).max(100),
1903
+ to: z24.union([z24.object({ project: z24.string().min(1).max(80) }), z24.object({ sessions: z24.array(z24.string().min(1)).min(1).max(BROADCAST_SESSIONS_MAX) })]),
1904
+ text: z24.string().trim().min(1).max(MESSAGE_MAX),
1905
+ summary: z24.string().max(SUMMARY_MAX).optional(),
1906
+ /** How the recipients are told who it went to (« (à <label>) »), instead of the names: a project the fleet turned into sessions. */
1907
+ label: z24.string().min(1).max(BROADCAST_LABEL_MAX).optional()
1908
+ }),
1567
1909
  /** `ledge read <id>`: a message's whole body, for its receiver or its sender (`by`, a session id). */
1568
- z22.object({ type: z22.literal("message.read"), id: z22.string().min(1).max(40), by: z22.string().min(1) }),
1910
+ z24.object({ type: z24.literal("message.read"), id: z24.string().min(1).max(40), by: z24.string().min(1) }),
1569
1911
  TaskCmdSchema,
1570
1912
  SessionHandoverSchema,
1571
1913
  ContextSetSchema,
@@ -1574,79 +1916,79 @@ var ClientMessageSchema = z22.discriminatedUnion("type", [
1574
1916
  ]);
1575
1917
 
1576
1918
  // ../protocol/src/relay.ts
1577
- import { z as z23 } from "zod";
1919
+ import { z as z25 } from "zod";
1578
1920
  var SEALED_MAX = 1048576;
1579
- var RelayPeerSchema = z23.union([z23.literal("pc"), z23.string().regex(/^d_[A-Za-z0-9_-]{16,40}$/)]);
1580
- var RelayClientMessageSchema = z23.object({
1581
- type: z23.literal("send"),
1921
+ var RelayPeerSchema = z25.union([z25.literal("pc"), z25.string().regex(/^d_[A-Za-z0-9_-]{16,40}$/)]);
1922
+ var RelayClientMessageSchema = z25.object({
1923
+ type: z25.literal("send"),
1582
1924
  to: RelayPeerSchema,
1583
- body: z23.string().max(SEALED_MAX)
1925
+ body: z25.string().max(SEALED_MAX)
1584
1926
  });
1585
- var RelayServerMessageSchema = z23.discriminatedUnion("type", [
1586
- z23.object({ type: z23.literal("welcome"), accountId: z23.string(), self: RelayPeerSchema, online: z23.array(RelayPeerSchema) }),
1587
- z23.object({ type: z23.literal("deliver"), from: RelayPeerSchema, body: z23.string() }),
1588
- z23.object({ type: z23.literal("presence"), peer: RelayPeerSchema, online: z23.boolean() }),
1927
+ var RelayServerMessageSchema = z25.discriminatedUnion("type", [
1928
+ z25.object({ type: z25.literal("welcome"), accountId: z25.string(), self: RelayPeerSchema, online: z25.array(RelayPeerSchema) }),
1929
+ z25.object({ type: z25.literal("deliver"), from: RelayPeerSchema, body: z25.string() }),
1930
+ z25.object({ type: z25.literal("presence"), peer: RelayPeerSchema, online: z25.boolean() }),
1589
1931
  /**
1590
1932
  * A frame was refused; `to` names the target when it is known.
1591
1933
  * Contract: an error concerning a sealed body (`offline`, `too_large`, or a socket closed with 4008
1592
1934
  * `rate_limited`) means that body was not delivered, so the sequence on that channel is lost: the
1593
1935
  * sender must re-handshake with that peer before sending to it again.
1594
1936
  */
1595
- z23.object({
1596
- type: z23.literal("error"),
1597
- code: z23.enum(["bad_frame", "too_large", "bad_target", "offline", "rate_limited"]),
1937
+ z25.object({
1938
+ type: z25.literal("error"),
1939
+ code: z25.enum(["bad_frame", "too_large", "bad_target", "offline", "rate_limited"]),
1598
1940
  to: RelayPeerSchema.optional()
1599
1941
  })
1600
1942
  ]);
1601
1943
  var PAIR_LABEL_MAX = 40;
1602
- var KeyB64 = z23.string().regex(/^[A-Za-z0-9_-]{87}$/);
1603
- var Nonce = z23.string().regex(/^[A-Za-z0-9_-]{43}$/);
1604
- var Fingerprint = z23.string().regex(/^[A-Za-z0-9_-]{22}$/);
1605
- var SealedFrameSchema = z23.discriminatedUnion("k", [
1944
+ var KeyB64 = z25.string().regex(/^[A-Za-z0-9_-]{87}$/);
1945
+ var Nonce = z25.string().regex(/^[A-Za-z0-9_-]{43}$/);
1946
+ var Fingerprint = z25.string().regex(/^[A-Za-z0-9_-]{22}$/);
1947
+ var SealedFrameSchema = z25.discriminatedUnion("k", [
1606
1948
  /** `e` is the ephemeral key, `f` the fingerprint of the sender's static key. */
1607
- z23.object({ k: z23.literal("hello"), e: KeyB64, f: Fingerprint }),
1608
- z23.object({ k: z23.literal("msg"), s: z23.string() }),
1609
- z23.object({ k: z23.literal("pair_commit"), c: Nonce, label: z23.string().trim().min(1).max(PAIR_LABEL_MAX) }),
1610
- z23.object({ k: z23.literal("pair_offer"), pc: KeyB64, n: Nonce }),
1611
- z23.object({ k: z23.literal("pair_reveal"), d: KeyB64, n: Nonce }),
1612
- z23.object({ k: z23.literal("pair_ok") }),
1613
- z23.object({ k: z23.literal("pair_no") }),
1614
- z23.object({ k: z23.literal("denied") }),
1615
- z23.object({ k: z23.literal("rekey") })
1949
+ z25.object({ k: z25.literal("hello"), e: KeyB64, f: Fingerprint }),
1950
+ z25.object({ k: z25.literal("msg"), s: z25.string() }),
1951
+ z25.object({ k: z25.literal("pair_commit"), c: Nonce, label: z25.string().trim().min(1).max(PAIR_LABEL_MAX) }),
1952
+ z25.object({ k: z25.literal("pair_offer"), pc: KeyB64, n: Nonce }),
1953
+ z25.object({ k: z25.literal("pair_reveal"), d: KeyB64, n: Nonce }),
1954
+ z25.object({ k: z25.literal("pair_ok") }),
1955
+ z25.object({ k: z25.literal("pair_no") }),
1956
+ z25.object({ k: z25.literal("denied") }),
1957
+ z25.object({ k: z25.literal("rekey") })
1616
1958
  ]);
1617
1959
 
1618
1960
  // ../protocol/src/relayAuth.ts
1619
- import { z as z24 } from "zod";
1620
- var DeviceStartResponseSchema = z24.object({
1621
- deviceCode: z24.string().min(1),
1622
- userCode: z24.string().min(1),
1623
- verificationUri: z24.string().min(1),
1624
- expiresIn: z24.number().int().positive(),
1625
- interval: z24.number().int().positive()
1626
- });
1627
- var DevicePollResponseSchema = z24.discriminatedUnion("status", [
1628
- z24.object({ status: z24.literal("pending") }),
1629
- z24.object({ status: z24.literal("slow_down"), interval: z24.number().int().positive() }),
1961
+ import { z as z26 } from "zod";
1962
+ var DeviceStartResponseSchema = z26.object({
1963
+ deviceCode: z26.string().min(1),
1964
+ userCode: z26.string().min(1),
1965
+ verificationUri: z26.string().min(1),
1966
+ expiresIn: z26.number().int().positive(),
1967
+ interval: z26.number().int().positive()
1968
+ });
1969
+ var DevicePollResponseSchema = z26.discriminatedUnion("status", [
1970
+ z26.object({ status: z26.literal("pending") }),
1971
+ z26.object({ status: z26.literal("slow_down"), interval: z26.number().int().positive() }),
1630
1972
  /** `token` is the relay session token, shown this once only. */
1631
- z24.object({ status: z24.literal("ok"), token: z24.string().min(1), accountId: z24.string().min(1), login: z24.string().min(1) }),
1632
- z24.object({ status: z24.literal("expired") }),
1633
- z24.object({ status: z24.literal("denied") }),
1634
- z24.object({ status: z24.literal("not_allowed") })
1973
+ z26.object({ status: z26.literal("ok"), token: z26.string().min(1), accountId: z26.string().min(1), login: z26.string().min(1) }),
1974
+ z26.object({ status: z26.literal("expired") }),
1975
+ z26.object({ status: z26.literal("denied") }),
1976
+ z26.object({ status: z26.literal("not_allowed") })
1635
1977
  ]);
1636
- var DeviceRevokeResponseSchema = z24.object({ revoked: z24.number().int().min(0) });
1637
- var MeResponseSchema = z24.object({
1638
- accountId: z24.string().min(1),
1639
- login: z24.string().min(1),
1978
+ var DeviceRevokeResponseSchema = z26.object({ revoked: z26.number().int().min(0) });
1979
+ var MeResponseSchema = z26.object({
1980
+ accountId: z26.string().min(1),
1981
+ login: z26.string().min(1),
1640
1982
  peer: RelayPeerSchema,
1641
- kind: z24.enum(["pc", "device"])
1983
+ kind: z26.enum(["pc", "device"])
1642
1984
  });
1643
1985
 
1644
1986
  // ../protocol/src/phone.ts
1645
- import { z as z26 } from "zod";
1987
+ import { z as z28 } from "zod";
1646
1988
 
1647
1989
  // ../protocol/src/push.ts
1648
- import { z as z25 } from "zod";
1649
- var B64U = z25.string().regex(/^[A-Za-z0-9_-]*$/);
1990
+ import { z as z27 } from "zod";
1991
+ var B64U = z27.string().regex(/^[A-Za-z0-9_-]*$/);
1650
1992
  var PUSH_HOSTS = ["*.push.apple.com", "fcm.googleapis.com", "updates.push.services.mozilla.com", "*.notify.windows.com"];
1651
1993
  function pushEndpointAllowed(url) {
1652
1994
  let u;
@@ -1663,67 +2005,70 @@ function pushEndpointAllowed(url) {
1663
2005
  return host.length > suffix.length && host.endsWith(suffix);
1664
2006
  });
1665
2007
  }
1666
- var PushSendSchema = z25.object({
1667
- endpoint: z25.string().url().max(1024),
2008
+ var PushSendSchema = z27.object({
2009
+ endpoint: z27.string().url().max(1024),
1668
2010
  body: B64U.max(5462),
1669
- ttl: z25.number().int().min(0).max(86400),
1670
- urgency: z25.enum(["normal", "high"]),
1671
- topic: z25.string().regex(/^[A-Za-z0-9_-]{1,32}$/)
1672
- });
1673
- var PushSendResultSchema = z25.object({
1674
- result: z25.enum(["sent", "gone", "failed"]),
1675
- status: z25.number().int().optional()
1676
- });
1677
- var PushSubscriptionSchema = z25.object({
1678
- endpoint: z25.string().url().max(1024).refine(pushEndpointAllowed),
1679
- keys: z25.object({ p256dh: B64U.length(87), auth: B64U.length(22) })
1680
- });
1681
- var PushPayloadSchema = z25.object({
1682
- v: z25.literal(1),
1683
- kind: z25.enum(["request", "question", "finished", "chat", "decision"]),
1684
- title: z25.string().max(80),
1685
- body: z25.string().max(120),
1686
- url: z25.string().regex(/^\/#\/[A-Za-z0-9/%._~-]*$/).max(300),
1687
- badge: z25.number().int().min(0).max(999),
1688
- tag: z25.string().regex(/^[A-Za-z0-9_-]{1,32}$/)
2011
+ ttl: z27.number().int().min(0).max(86400),
2012
+ urgency: z27.enum(["normal", "high"]),
2013
+ topic: z27.string().regex(/^[A-Za-z0-9_-]{1,32}$/)
2014
+ });
2015
+ var PushSendResultSchema = z27.object({
2016
+ result: z27.enum(["sent", "gone", "failed"]),
2017
+ status: z27.number().int().optional()
2018
+ });
2019
+ var PushSubscriptionSchema = z27.object({
2020
+ endpoint: z27.string().url().max(1024).refine(pushEndpointAllowed),
2021
+ keys: z27.object({ p256dh: B64U.length(87), auth: B64U.length(22) })
2022
+ });
2023
+ var PushPayloadSchema = z27.object({
2024
+ v: z27.literal(1),
2025
+ kind: z27.enum(["request", "question", "finished", "chat", "decision"]),
2026
+ title: z27.string().max(80),
2027
+ body: z27.string().max(120),
2028
+ url: z27.string().regex(/^\/#\/[A-Za-z0-9/%._~-]*$/).max(300),
2029
+ badge: z27.number().int().min(0).max(999),
2030
+ tag: z27.string().regex(/^[A-Za-z0-9_-]{1,32}$/)
1689
2031
  });
1690
2032
 
1691
2033
  // ../protocol/src/phone.ts
2034
+ var PHONE_ROW_SUMMARY_MAX = 200;
2035
+ var PhoneRigRowSchema = RigRowSchema.extend({ summary: z28.string().max(PHONE_ROW_SUMMARY_MAX).optional() });
2036
+ var PhoneRowErrorSchema = z28.enum(["not_found", "unavailable"]);
1692
2037
  var PHONE_PROTOCOL = 1;
1693
2038
  var utf8 = new TextEncoder();
1694
2039
  var THREAD_TEXT_MAX = 8192;
1695
2040
  var TOOL_TEXT_MAX = 2048;
1696
2041
  var CHECKLIST_TASKS_MAX = 50;
1697
2042
  var CHECKLIST_TEXT_MAX = 200;
1698
- var ChecklistStatusSchema = z26.enum(["pending", "in_progress", "completed"]);
1699
- var PhoneChecklistSchema = z26.object({
1700
- tasks: z26.array(z26.object({ text: z26.string().max(CHECKLIST_TEXT_MAX), status: ChecklistStatusSchema })).max(CHECKLIST_TASKS_MAX),
1701
- done: z26.number().int().nonnegative(),
1702
- total: z26.number().int().nonnegative(),
1703
- cut: z26.literal(true).optional()
1704
- });
1705
- var PhoneChecklistSummarySchema = z26.object({
1706
- done: z26.number().int().nonnegative(),
1707
- total: z26.number().int().nonnegative(),
1708
- current: z26.string().max(CHECKLIST_TEXT_MAX).optional(),
1709
- cut: z26.literal(true).optional()
1710
- });
1711
- var RiskSchema = z26.enum(["low", "high"]);
1712
- var RiskReasonSchema = z26.enum(["question", "read_only_command", "edit_inside_folder", "pushes", "destroys", "deploys", "publishes", "pipes_to_shell", "network", "writes_outside_folder", "sensitive_path", "unsafe_flag", "shell_syntax", "script", "plan", "unknown"]);
1713
- var OperationIdSchema = z26.string().uuid();
1714
- var OperationStatusSchema = z26.enum(["received", "applied", "rejected", "failed"]);
1715
- var OperationReasonSchema = z26.enum([...RefusalCodeSchema.options, "untypable", "confirm_required", "conflict", "assertion_invalid", "assertion_expired", "scheduled", ...ModelRefusalSchema.options]);
1716
- var CapabilitiesSchema = z26.object({
2043
+ var ChecklistStatusSchema = z28.enum(["pending", "in_progress", "completed"]);
2044
+ var PhoneChecklistSchema = z28.object({
2045
+ tasks: z28.array(z28.object({ text: z28.string().max(CHECKLIST_TEXT_MAX), status: ChecklistStatusSchema })).max(CHECKLIST_TASKS_MAX),
2046
+ done: z28.number().int().nonnegative(),
2047
+ total: z28.number().int().nonnegative(),
2048
+ cut: z28.literal(true).optional()
2049
+ });
2050
+ var PhoneChecklistSummarySchema = z28.object({
2051
+ done: z28.number().int().nonnegative(),
2052
+ total: z28.number().int().nonnegative(),
2053
+ current: z28.string().max(CHECKLIST_TEXT_MAX).optional(),
2054
+ cut: z28.literal(true).optional()
2055
+ });
2056
+ var RiskSchema = z28.enum(["low", "high"]);
2057
+ var RiskReasonSchema = z28.enum(["question", "read_only_command", "edit_inside_folder", "pushes", "destroys", "deploys", "publishes", "pipes_to_shell", "network", "writes_outside_folder", "sensitive_path", "unsafe_flag", "shell_syntax", "script", "plan", "unknown"]);
2058
+ var OperationIdSchema = z28.string().uuid();
2059
+ var OperationStatusSchema = z28.enum(["received", "applied", "rejected", "failed"]);
2060
+ var OperationReasonSchema = z28.enum([...RefusalCodeSchema.options, "untypable", "confirm_required", "conflict", "assertion_invalid", "assertion_expired", "scheduled", ...ModelRefusalSchema.options]);
2061
+ var CapabilitiesSchema = z28.object({
1717
2062
  /** A question can be answered in free text. */
1718
- freeTextAnswer: z26.boolean(),
2063
+ freeTextAnswer: z28.boolean(),
1719
2064
  /** The session's accept/deny can be typed; absent = true. */
1720
- decide: z26.boolean().optional(),
2065
+ decide: z28.boolean().optional(),
1721
2066
  /** OMP's dialog questions can be answered from the phone; absent = false. */
1722
- questions: z26.boolean().optional()
2067
+ questions: z28.boolean().optional()
1723
2068
  });
1724
- var CapabilitiesByToolSchema = z26.object({ claude: CapabilitiesSchema, codex: CapabilitiesSchema, cursor: CapabilitiesSchema, omp: CapabilitiesSchema });
1725
- var PhonePendingSchema = PendingSchema.extend({ key: z26.string().max(64), risk: RiskSchema, riskReason: RiskReasonSchema, cut: z26.literal(true).optional() });
1726
- var SwitchableSessionSchema = SessionSchema.extend({ canSwitch: z26.literal(true).optional() });
2069
+ var CapabilitiesByToolSchema = z28.object({ claude: CapabilitiesSchema, codex: CapabilitiesSchema, cursor: CapabilitiesSchema, omp: CapabilitiesSchema });
2070
+ var PhonePendingSchema = PendingSchema.extend({ key: z28.string().max(64), risk: RiskSchema, riskReason: RiskReasonSchema, cut: z28.literal(true).optional() });
2071
+ var SwitchableSessionSchema = SessionSchema.extend({ canSwitch: z28.literal(true).optional() });
1727
2072
  var PhoneSessionSchema = SwitchableSessionSchema.pick({
1728
2073
  id: true,
1729
2074
  name: true,
@@ -1751,290 +2096,403 @@ var PhoneSessionSchema = SwitchableSessionSchema.pick({
1751
2096
  exitedAt: true
1752
2097
  }).extend({
1753
2098
  pending: PhonePendingSchema.optional(),
1754
- unread: z26.boolean(),
1755
- handover: z26.object({ state: HandoverStateSchema, toName: z26.string().max(80).optional() }).strict().optional(),
2099
+ unread: z28.boolean(),
2100
+ handover: z28.object({ state: HandoverStateSchema, toName: z28.string().max(80).optional() }).strict().optional(),
1756
2101
  /** Absent: the agent has no checklist. */
1757
2102
  checklist: PhoneChecklistSummarySchema.optional(),
1758
2103
  /** Started without Ledge (`hook_only`): the phone can neither close nor resume it. */
1759
- readOnly: z26.literal(true).optional()
2104
+ readOnly: z28.literal(true).optional()
1760
2105
  });
1761
- var B64U2 = z26.string().regex(/^[A-Za-z0-9_-]*$/);
1762
- var CredentialSchema = z26.object({
2106
+ var B64U2 = z28.string().regex(/^[A-Za-z0-9_-]*$/);
2107
+ var CredentialSchema = z28.object({
1763
2108
  id: B64U2.max(1366),
1764
2109
  publicKey: B64U2.max(2048),
1765
- alg: z26.union([z26.literal(-7), z26.literal(-257)]),
2110
+ alg: z28.union([z28.literal(-7), z28.literal(-257)]),
1766
2111
  clientDataJSON: B64U2.max(4096),
1767
2112
  authenticatorData: B64U2.max(4096),
1768
- transports: z26.array(z26.string().max(20)).max(8).optional()
2113
+ transports: z28.array(z28.string().max(20)).max(8).optional()
1769
2114
  });
1770
- var AssertionSchema = z26.object({
2115
+ var AssertionSchema = z28.object({
1771
2116
  id: B64U2.max(1366),
1772
2117
  clientDataJSON: B64U2.max(4096),
1773
2118
  authenticatorData: B64U2.max(4096),
1774
2119
  signature: B64U2.max(1024)
1775
2120
  });
1776
- var ConfirmPurposeSchema = z26.enum(["register", "decide", "launch", "close", "act", "pc"]);
2121
+ var ConfirmPurposeSchema = z28.enum(["register", "decide", "launch", "close", "act", "pc", "terminal", "rig"]);
1777
2122
  var PhoneChatStepSchema = ChatStepSchema.pick({ kind: true, id: true, name: true }).strict();
1778
- var PhoneChatProposalSchema = z26.object({
1779
- project: z26.string().max(80),
2123
+ var PhoneChatProposalSchema = z28.object({
2124
+ project: z28.string().max(80),
1780
2125
  tool: ToolSchema,
1781
- prompt: z26.string().max(TOOL_TEXT_MAX).optional(),
1782
- launchedId: z26.string().optional(),
1783
- failed: z26.literal(true).optional()
2126
+ prompt: z28.string().max(TOOL_TEXT_MAX).optional(),
2127
+ launchedId: z28.string().optional(),
2128
+ failed: z28.literal(true).optional()
1784
2129
  }).strict();
1785
- var PhoneChatRelaySchema = z26.object({
1786
- id: z26.string().min(1),
1787
- name: z26.string(),
2130
+ var PhoneChatRelaySchema = z28.object({
2131
+ id: z28.string().min(1),
2132
+ name: z28.string(),
1788
2133
  tool: ToolSchema,
1789
- text: z26.string().max(TOOL_TEXT_MAX),
1790
- status: z26.enum(["queued", "sent"]).optional(),
1791
- sentAt: z26.string().datetime().optional(),
1792
- failed: z26.literal(true).optional(),
2134
+ text: z28.string().max(TOOL_TEXT_MAX),
2135
+ status: z28.enum(["queued", "sent"]).optional(),
2136
+ sentAt: z28.string().datetime().optional(),
2137
+ failed: z28.literal(true).optional(),
1793
2138
  /** With `failed`: why, as the PC's code (never its text). */
1794
- code: z26.string().max(40).optional()
2139
+ code: z28.string().max(40).optional()
1795
2140
  }).strict();
1796
- var CloseHowSchema = z26.enum(["exit", "killed"]);
1797
- var PhoneChatCloseSchema = z26.object({
1798
- id: z26.string().min(1),
1799
- name: z26.string(),
2141
+ var CloseHowSchema = z28.enum(["exit", "killed"]);
2142
+ var PhoneChatCloseSchema = z28.object({
2143
+ id: z28.string().min(1),
2144
+ name: z28.string(),
1800
2145
  tool: ToolSchema,
1801
2146
  how: CloseHowSchema.optional(),
1802
- closedAt: z26.string().datetime().optional(),
1803
- failed: z26.literal(true).optional()
2147
+ closedAt: z28.string().datetime().optional(),
2148
+ failed: z28.literal(true).optional()
1804
2149
  }).strict();
1805
- var PhoneChatTaskSchema = z26.object({
1806
- to: z26.string().max(80),
1807
- toName: z26.string().max(80).optional(),
1808
- title: z26.string().max(200),
1809
- text: z26.string().max(TOOL_TEXT_MAX).optional(),
1810
- taskId: z26.string().max(40).optional(),
1811
- ownerName: z26.string().max(80).optional(),
1812
- state: z26.enum(["open", "taken", "done", "refused", "dropped"]).optional(),
1813
- failed: z26.literal(true).optional()
2150
+ var PhoneChatTaskSchema = z28.object({
2151
+ to: z28.string().max(80),
2152
+ toName: z28.string().max(80).optional(),
2153
+ title: z28.string().max(200),
2154
+ text: z28.string().max(TOOL_TEXT_MAX).optional(),
2155
+ taskId: z28.string().max(40).optional(),
2156
+ ownerName: z28.string().max(80).optional(),
2157
+ state: z28.enum(["open", "taken", "done", "refused", "dropped"]).optional(),
2158
+ failed: z28.literal(true).optional()
1814
2159
  }).strict();
1815
- var PhoneChatActionSchema = z26.object({
1816
- action: z26.string().min(1).max(40),
1817
- summary: z26.string().max(300),
2160
+ var PhoneChatActionSchema = z28.object({
2161
+ action: z28.string().min(1).max(40),
2162
+ summary: z28.string().max(300),
1818
2163
  vars: ActionVarsSchema.optional(),
1819
- detail: z26.string().max(TOOL_TEXT_MAX).optional(),
1820
- detailCut: z26.literal(true).optional(),
2164
+ detail: z28.string().max(TOOL_TEXT_MAX).optional(),
2165
+ detailCut: z28.literal(true).optional(),
1821
2166
  risk: ActionRiskSchema,
1822
- session: z26.string().max(100).optional(),
2167
+ session: z28.string().max(100).optional(),
1823
2168
  state: ChatActionStateSchema.optional(),
1824
- doneAt: z26.string().datetime().optional(),
1825
- code: z26.string().max(40).optional()
2169
+ doneAt: z28.string().datetime().optional(),
2170
+ code: z28.string().max(40).optional()
1826
2171
  }).strict();
1827
- var PhoneTaskSchema = z26.object({
1828
- id: z26.string().max(40),
1829
- title: z26.string().max(200),
1830
- owner: z26.string().max(100),
1831
- ownerName: z26.string().max(80),
2172
+ var PhoneTaskSchema = z28.object({
2173
+ id: z28.string().max(40),
2174
+ title: z28.string().max(200),
2175
+ owner: z28.string().max(100),
2176
+ ownerName: z28.string().max(80),
1832
2177
  /** Who gave it: `ledge` for Ledge's own; a session for a decision it put to the user (owner `ledge`), with its detail (the options). */
1833
- giver: z26.string().max(100).optional(),
1834
- giverName: z26.string().max(80).optional(),
1835
- text: z26.string().max(TOOL_TEXT_MAX).optional(),
1836
- state: z26.enum(["open", "taken", "done", "refused", "dropped"]),
1837
- result: z26.string().max(TOOL_TEXT_MAX).optional(),
1838
- cut: z26.literal(true).optional(),
1839
- at: z26.string(),
1840
- updatedAt: z26.string(),
1841
- seen: z26.literal(true).optional()
2178
+ giver: z28.string().max(100).optional(),
2179
+ giverName: z28.string().max(80).optional(),
2180
+ text: z28.string().max(TOOL_TEXT_MAX).optional(),
2181
+ state: z28.enum(["open", "taken", "done", "refused", "dropped"]),
2182
+ result: z28.string().max(TOOL_TEXT_MAX).optional(),
2183
+ cut: z28.literal(true).optional(),
2184
+ at: z28.string(),
2185
+ updatedAt: z28.string(),
2186
+ seen: z28.literal(true).optional()
1842
2187
  }).strict();
1843
- var ChatErrorCodeSchema = z26.enum(["busy", "timeout", "cancelled", "failed"]);
1844
- var PhoneChatTurnSchema = z26.object({
2188
+ var ChatErrorCodeSchema = z28.enum(["busy", "timeout", "cancelled", "failed"]);
2189
+ var PhoneChatTurnSchema = z28.object({
1845
2190
  qid: OperationIdSchema,
1846
- question: z26.string().max(MESSAGE_MAX),
1847
- askedAt: z26.string().datetime(),
1848
- steps: z26.array(PhoneChatStepSchema).max(50),
1849
- answer: z26.string().max(THREAD_TEXT_MAX).optional(),
1850
- answeredAt: z26.string().datetime().optional(),
2191
+ question: z28.string().max(MESSAGE_MAX),
2192
+ askedAt: z28.string().datetime(),
2193
+ steps: z28.array(PhoneChatStepSchema).max(50),
2194
+ answer: z28.string().max(THREAD_TEXT_MAX).optional(),
2195
+ answeredAt: z28.string().datetime().optional(),
1851
2196
  error: ChatErrorCodeSchema.optional(),
1852
- proposals: z26.array(PhoneChatProposalSchema).max(MAX_PROPOSALS).optional(),
2197
+ proposals: z28.array(PhoneChatProposalSchema).max(MAX_PROPOSALS).optional(),
1853
2198
  relay: PhoneChatRelaySchema.optional(),
1854
- closes: z26.array(PhoneChatCloseSchema).min(1).max(MAX_PROPOSALS).optional(),
1855
- cut: z26.literal(true).optional(),
1856
- tasks: z26.array(PhoneChatTaskSchema).min(1).max(MAX_PROPOSALS).optional(),
1857
- actions: z26.array(PhoneChatActionSchema).min(1).max(MAX_PROPOSALS).optional(),
1858
- ignoredAt: z26.string().datetime().optional(),
1859
- attachments: z26.array(AttachmentRefSchema).max(ATTACHMENTS_MAX).optional()
2199
+ closes: z28.array(PhoneChatCloseSchema).min(1).max(MAX_PROPOSALS).optional(),
2200
+ cut: z28.literal(true).optional(),
2201
+ tasks: z28.array(PhoneChatTaskSchema).min(1).max(MAX_PROPOSALS).optional(),
2202
+ actions: z28.array(PhoneChatActionSchema).min(1).max(MAX_PROPOSALS).optional(),
2203
+ ignoredAt: z28.string().datetime().optional(),
2204
+ attachments: z28.array(AttachmentRefSchema).max(ATTACHMENTS_MAX).optional()
1860
2205
  }).strict();
1861
- var sessionId = z26.string().min(1).max(100);
1862
- var PhoneExpectSchema = PendingSchema.pick({ kind: true, text: true }).extend({ key: z26.string().min(1).max(64) });
1863
- var CardRowsSchema = z26.array(z26.number().int().min(0).max(MAX_PROPOSALS - 1)).min(1).max(MAX_PROPOSALS).refine((r) => new Set(r).size === r.length, "a row twice");
2206
+ var sessionId = z28.string().min(1).max(100);
2207
+ var PhoneExpectSchema = PendingSchema.pick({ kind: true, text: true }).extend({ key: z28.string().min(1).max(64) });
2208
+ var CardRowsSchema = z28.array(z28.number().int().min(0).max(MAX_PROPOSALS - 1)).min(1).max(MAX_PROPOSALS).refine((r) => new Set(r).size === r.length, "a row twice");
1864
2209
  var pcOp = { op: OperationIdSchema, assertion: AssertionSchema.optional() };
1865
- var PcActionSchema = z26.enum(["update", "restart"]);
1866
- var PhoneClientMessageSchema = z26.discriminatedUnion("type", [
1867
- z26.object({ type: z26.literal("snapshot.request") }),
1868
- z26.object({ type: z26.literal("session.thread"), id: sessionId }),
2210
+ var PcActionSchema = z28.enum(["update", "restart"]);
2211
+ var TerminalIdSchema = z28.string().regex(/^t_[A-Za-z0-9_-]{8,40}$/);
2212
+ var TERM_INPUT_MAX = 4096;
2213
+ var TERM_SCREEN_MAX = 65536;
2214
+ var TERM_OUTPUT_MAX = 32768;
2215
+ var TermDimSchema = z28.number().int().min(1).max(1e4);
2216
+ var TermReleaseWhySchema = z28.enum(["asked", "pc", "idle", "expired", "background", "link"]);
2217
+ var TermExitWhySchema = z28.enum(["ended", "gone", "closed", "superseded", "failed"]);
2218
+ var PhoneClientMessageSchema = z28.discriminatedUnion("type", [
2219
+ z28.object({ type: z28.literal("snapshot.request") }),
2220
+ z28.object({ type: z28.literal("session.thread"), id: sessionId }),
1869
2221
  /** The session's request with its whole body (up to `PENDING_BODY_MAX`). */
1870
- z26.object({ type: z26.literal("session.pending"), id: sessionId }),
2222
+ z28.object({ type: z28.literal("session.pending"), id: sessionId }),
1871
2223
  /** The session whose terminal the phone shows; null when it shows none. */
1872
- z26.object({ type: z26.literal("session.watch"), id: sessionId.nullable() }),
1873
- z26.object({ type: z26.literal("session.read"), id: sessionId, at: z26.string().datetime() }),
2224
+ z28.object({ type: z28.literal("session.watch"), id: sessionId.nullable() }),
2225
+ z28.object({ type: z28.literal("session.read"), id: sessionId, at: z28.string().datetime() }),
1874
2226
  /**
1875
2227
  * Asks for a challenge. One object for every purpose: the gateway refuses a `decide` without `id` and `expect`. A `close`
1876
2228
  * or `act` names a turn of the chat (`qid`) or a session (`id`, for `session.close` and `session.resume`).
1877
2229
  */
1878
- z26.object({
1879
- type: z26.literal("confirm.prepare"),
2230
+ z28.object({
2231
+ type: z28.literal("confirm.prepare"),
1880
2232
  purpose: ConfirmPurposeSchema,
1881
2233
  id: sessionId.optional(),
1882
2234
  expect: PhoneExpectSchema.optional(),
1883
2235
  qid: OperationIdSchema.optional(),
1884
2236
  /** A `pc` challenge: what it is for, and for an update the version it covers. */
1885
2237
  action: PcActionSchema.optional(),
1886
- version: z26.string().regex(SEMVER).optional()
2238
+ version: z28.string().regex(SEMVER).optional(),
2239
+ /** A `rig` challenge: the OpenRig row and the exact answer it covers. */
2240
+ qitem: z28.string().min(1).max(200).optional(),
2241
+ answer: HumanAnswerSchema.optional()
1887
2242
  }),
1888
- z26.object({ type: z26.literal("credential.register"), op: OperationIdSchema, credential: CredentialSchema }),
1889
- z26.object({
1890
- type: z26.literal("session.decide"),
2243
+ z28.object({ type: z28.literal("credential.register"), op: OperationIdSchema, credential: CredentialSchema }),
2244
+ z28.object({
2245
+ type: z28.literal("session.decide"),
1891
2246
  op: OperationIdSchema,
1892
2247
  id: sessionId,
1893
2248
  decision: DecisionSchema,
1894
- note: z26.string().trim().min(1).max(NOTE_MAX).optional(),
2249
+ note: z28.string().trim().min(1).max(NOTE_MAX).optional(),
1895
2250
  /** The request the phone showed: refused unless it is still the pending one. */
1896
2251
  expect: PhoneExpectSchema,
1897
2252
  /** The device check over the challenge of `confirm.prepare`; required by the daemon for a high-risk accept. */
1898
2253
  assertion: AssertionSchema.optional()
1899
2254
  }),
1900
- z26.object({
1901
- type: z26.literal("session.reply"),
2255
+ z28.object({
2256
+ type: z28.literal("session.reply"),
1902
2257
  op: OperationIdSchema,
1903
2258
  id: sessionId,
1904
- text: z26.string().max(MESSAGE_MAX),
1905
- attachments: z26.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(),
2259
+ text: z28.string().max(MESSAGE_MAX),
2260
+ attachments: z28.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(),
1906
2261
  /** The request the reply answers, or null when the phone showed none: refused if the session's request is no longer that one. */
1907
2262
  expect: PhoneExpectSchema.nullable(),
1908
2263
  assertion: AssertionSchema.optional()
1909
2264
  }),
1910
2265
  /** OMP's `ask`: the answers to every question of the dialog `requestId`, in order; `cancel` declines it. Bounds as the local `session.answer`. */
1911
- z26.object({
1912
- type: z26.literal("session.answer"),
2266
+ z28.object({
2267
+ type: z28.literal("session.answer"),
1913
2268
  op: OperationIdSchema,
1914
2269
  id: sessionId,
1915
- requestId: z26.string().min(1).max(200),
1916
- answers: z26.array(z26.object({ id: z26.string().max(200), selected: z26.array(z26.string().max(2e3)).max(100), text: z26.string().max(2e4).optional() })).max(50),
1917
- cancel: z26.literal(true).optional(),
2270
+ requestId: z28.string().min(1).max(200),
2271
+ answers: z28.array(z28.object({ id: z28.string().max(200), selected: z28.array(z28.string().max(2e3)).max(100), text: z28.string().max(2e4).optional() })).max(50),
2272
+ cancel: z28.literal(true).optional(),
1918
2273
  expect: PhoneExpectSchema
1919
2274
  }),
1920
- z26.object({ type: z26.literal("session.interrupt"), op: OperationIdSchema, id: sessionId }),
2275
+ z28.object({ type: z28.literal("session.interrupt"), op: OperationIdSchema, id: sessionId }),
1921
2276
  /** Ends a live session as `/exit` would, killed as a last resort; answered with its `how`. Passkey, purpose `close`, over the session. */
1922
- z26.object({ type: z26.literal("session.close"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
2277
+ z28.object({ type: z28.literal("session.close"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
1923
2278
  /** Starts an ended session again on its conversation. Passkey, purpose `act`, over the session. */
1924
- z26.object({ type: z26.literal("session.resume"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
2279
+ z28.object({ type: z28.literal("session.resume"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
1925
2280
  /** Changes a live session's model and effort, `null` for the agent's own default; answered by `operation.result` and, when refused, `session.model.failed`. */
1926
- z26.object({ type: z26.literal("session.model"), op: OperationIdSchema, id: sessionId, model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
2281
+ z28.object({ type: z28.literal("session.model"), op: OperationIdSchema, id: sessionId, model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
2282
+ /** One message to several sessions (ids); answered by `operation.result` with `sent` and `refused`. */
2283
+ z28.object({ type: z28.literal("session.broadcast"), op: OperationIdSchema, sessions: z28.array(sessionId).min(1).max(BROADCAST_SESSIONS_MAX), text: z28.string().trim().min(1).max(MESSAGE_MAX) }).strict(),
1927
2284
  /** The models an agent offers on the PC. */
1928
- z26.object({ type: z26.literal("models.list"), tool: ToolSchema }),
2285
+ z28.object({ type: z28.literal("models.list"), tool: ToolSchema }),
2286
+ /** The slash commands of a session's agent, for the « / » list of its field. */
2287
+ z28.object({ type: z28.literal("session.commands"), id: sessionId }),
2288
+ /** A queue row's state, for an OpenRig task card: asked while the card shows and every `RIG_ROW_REFRESH_MS` (`daemon.rigRows`). */
2289
+ z28.object({ type: z28.literal("openrig.row"), qitem: QitemIdSchema }),
1929
2290
  /** The phone drops its passkey from the daemon. */
1930
- z26.object({ type: z26.literal("device.forget"), op: OperationIdSchema }),
2291
+ z28.object({ type: z28.literal("device.forget"), op: OperationIdSchema }),
1931
2292
  /** The phone's push subscription, with the VAPID key it was made with (so a key change is seen). */
1932
- z26.object({ type: z26.literal("push.subscribe"), op: OperationIdSchema, subscription: PushSubscriptionSchema, key: B64U2.length(87) }),
1933
- z26.object({ type: z26.literal("push.unsubscribe"), op: OperationIdSchema }),
2293
+ z28.object({ type: z28.literal("push.subscribe"), op: OperationIdSchema, subscription: PushSubscriptionSchema, key: B64U2.length(87) }),
2294
+ z28.object({ type: z28.literal("push.unsubscribe"), op: OperationIdSchema }),
1934
2295
  /** The phone's own chat with Ledge. */
1935
- z26.object({ type: z26.literal("chat.ask"), qid: OperationIdSchema, text: z26.string().trim().max(MESSAGE_MAX), attachments: z26.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional() }),
1936
- z26.object({ type: z26.literal("chat.cancel"), qid: OperationIdSchema }),
1937
- z26.object({ type: z26.literal("chat.reset") }),
1938
- z26.object({ type: z26.literal("chat.history") }),
2296
+ z28.object({ type: z28.literal("chat.ask"), qid: OperationIdSchema, text: z28.string().trim().max(MESSAGE_MAX), attachments: z28.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional() }),
2297
+ z28.object({ type: z28.literal("chat.cancel"), qid: OperationIdSchema }),
2298
+ z28.object({ type: z28.literal("chat.reset") }),
2299
+ z28.object({ type: z28.literal("chat.history") }),
1939
2300
  /** An image to store, sent alone before the message that names it; no `id`, and at most `ATTACHMENT_MAX` bytes. */
1940
- AttachmentPutSchema.pick({ type: true, requestId: true }).extend({ image: ImageUploadSchema.extend({ data: z26.string().min(1).max(b64Max(ATTACHMENT_MAX)) }) }),
2301
+ AttachmentPutSchema.pick({ type: true, requestId: true }).extend({ image: ImageUploadSchema.extend({ data: z28.string().min(1).max(b64Max(ATTACHMENT_MAX)) }) }),
1941
2302
  AttachmentGetSchema.pick({ type: true, requestId: true, attachment: true, preview: true }),
1942
- z26.object({ type: z26.literal("chat.relay"), op: OperationIdSchema, qid: OperationIdSchema }),
2303
+ z28.object({ type: z28.literal("chat.relay"), op: OperationIdSchema, qid: OperationIdSchema }),
1943
2304
  /** Takes the card's queued instruction back out of the queue, as the local `session.relay.cancel`. */
1944
- z26.object({ type: z26.literal("chat.relay.cancel"), op: OperationIdSchema, qid: OperationIdSchema }),
1945
- z26.object({ type: z26.literal("chat.launch"), op: OperationIdSchema, qid: OperationIdSchema, rows: CardRowsSchema.optional(), assertion: AssertionSchema.optional() }),
1946
- z26.object({ type: z26.literal("chat.close"), op: OperationIdSchema, qid: OperationIdSchema, rows: CardRowsSchema.optional(), assertion: AssertionSchema.optional() }),
2305
+ z28.object({ type: z28.literal("chat.relay.cancel"), op: OperationIdSchema, qid: OperationIdSchema }),
2306
+ z28.object({ type: z28.literal("chat.launch"), op: OperationIdSchema, qid: OperationIdSchema, rows: CardRowsSchema.optional(), assertion: AssertionSchema.optional() }),
2307
+ z28.object({ type: z28.literal("chat.close"), op: OperationIdSchema, qid: OperationIdSchema, rows: CardRowsSchema.optional(), assertion: AssertionSchema.optional() }),
1947
2308
  /** A row of the turn's task card: given by Ledge. */
1948
- z26.object({ type: z26.literal("chat.task"), op: OperationIdSchema, qid: OperationIdSchema, row: z26.number().int().min(0).max(MAX_PROPOSALS - 1) }),
2309
+ z28.object({ type: z28.literal("chat.task"), op: OperationIdSchema, qid: OperationIdSchema, row: z28.number().int().min(0).max(MAX_PROPOSALS - 1) }),
1949
2310
  /** Rows of the turn's generic card (action registry spec §5): `confirmed` as the local `chat.act`; a row whose action asks
1950
2311
  * for a device check (`phone`) needs one assertion, purpose `act`, over the turn. */
1951
- z26.object({
1952
- type: z26.literal("chat.act"),
2312
+ z28.object({
2313
+ type: z28.literal("chat.act"),
1953
2314
  op: OperationIdSchema,
1954
2315
  qid: OperationIdSchema,
1955
2316
  rows: CardRowsSchema.optional(),
1956
- confirmed: z26.literal(true).optional(),
2317
+ confirmed: z28.literal(true).optional(),
1957
2318
  assertion: AssertionSchema.optional(),
1958
2319
  /** « Refuser », as the local `chat.act`: no passkey, no confirmation. */
1959
- deny: z26.literal(true).optional()
2320
+ deny: z28.literal(true).optional()
1960
2321
  }),
1961
2322
  /** « Ignorer » the turn's cards, or `undo` (« Revoir »), as the local `chat.ignore`. */
1962
- z26.object({ type: z26.literal("chat.ignore"), op: OperationIdSchema, qid: OperationIdSchema, undo: z26.literal(true).optional() }),
2323
+ z28.object({ type: z28.literal("chat.ignore"), op: OperationIdSchema, qid: OperationIdSchema, undo: z28.literal(true).optional() }),
1963
2324
  /** Puts a closed task Ledge gave away from « À traiter ». */
1964
- z26.object({ type: z26.literal("task.seen"), op: OperationIdSchema, task: z26.string().min(1).max(40) }),
2325
+ z28.object({ type: z28.literal("task.seen"), op: OperationIdSchema, task: z28.string().min(1).max(40) }),
2326
+ /** Streams a session's pane, read-only; answered by `term.opened` or `operation.result` (rejected). */
2327
+ z28.object({ type: z28.literal("term.open"), op: OperationIdSchema, id: sessionId }),
2328
+ /** « Prendre la main »: passkey, purpose `terminal`, over the session; answered by `term.held` or `operation.result` (rejected). */
2329
+ z28.object({ type: z28.literal("term.hold"), op: OperationIdSchema, tid: TerminalIdSchema, assertion: AssertionSchema.optional() }),
2330
+ /** Keys to type, as xterm produced them; `n` counts from 0 for the terminal, so a duplicate is dropped and a gap seen. Refused unless held. */
2331
+ z28.object({ type: z28.literal("term.input"), tid: TerminalIdSchema, n: z28.number().int().nonnegative(), data: z28.string().min(1).max(TERM_INPUT_MAX) }),
2332
+ /** « Rendre la main »: back to read-only. */
2333
+ z28.object({ type: z28.literal("term.release"), tid: TerminalIdSchema }),
2334
+ /** The phone saw a gap in `seq`: a fresh `term.opened`, please. */
2335
+ z28.object({ type: z28.literal("term.resync"), tid: TerminalIdSchema }),
2336
+ z28.object({ type: z28.literal("term.close"), tid: TerminalIdSchema }),
1965
2337
  /** Whether the phone's app is in front: a device that is visible gets no push. */
1966
- z26.object({ type: z26.literal("presence"), visible: z26.boolean() }),
2338
+ z28.object({ type: z28.literal("presence"), visible: z28.boolean() }),
2339
+ /** « À toi » (lot 3): what OpenRig on this PC asks the person, then pushed whole when it changes (`openrig.asks`). */
2340
+ z28.object({ type: z28.literal("openrig.asks") }),
2341
+ /** The person's answer to an OpenRig row. A choice, words or a resolve carries an assertion of purpose `rig` bound to that row and that
2342
+ * answer; « Vu » (`seen`) needs none. */
2343
+ z28.object({ type: z28.literal("openrig.answer"), op: OperationIdSchema, qitemId: z28.string().min(1).max(200), answer: HumanAnswerSchema, assertion: AssertionSchema.optional() }),
1967
2344
  /** Installs `version` on the PC, then restarts its daemon; the phone asks for its own build's version. Passkey, purpose `pc`. */
1968
- z26.object({ type: z26.literal("daemon.update"), ...pcOp, version: z26.string().regex(SEMVER) }).strict(),
2345
+ z28.object({ type: z28.literal("daemon.update"), ...pcOp, version: z28.string().regex(SEMVER) }).strict(),
1969
2346
  /** Restarts the PC's daemon without installing anything. Passkey, purpose `pc`. */
1970
- z26.object({ type: z26.literal("daemon.restart"), ...pcOp }).strict()
2347
+ z28.object({ type: z28.literal("daemon.restart"), ...pcOp }).strict()
1971
2348
  ]);
1972
- var PhoneModelChoiceSchema = z26.object({
2349
+ var PhoneModelChoiceSchema = z28.object({
1973
2350
  id: ModelChoiceSchema.shape.id.max(120),
1974
- label: z26.string().max(80),
1975
- description: z26.string().max(200).optional(),
1976
- efforts: z26.array(EffortSchema).max(8).optional(),
2351
+ label: z28.string().max(80),
2352
+ description: z28.string().max(200).optional(),
2353
+ efforts: z28.array(EffortSchema).max(8).optional(),
1977
2354
  defaultEffort: EffortSchema.optional(),
1978
- isDefault: z26.boolean().optional()
2355
+ isDefault: z28.boolean().optional()
1979
2356
  }).strict();
1980
- var PhoneServerMessageSchema = z26.discriminatedUnion("type", [
1981
- z26.object({ type: z26.literal("snapshot"), protocol: z26.literal(PHONE_PROTOCOL), sessions: z26.array(PhoneSessionSchema), capabilities: CapabilitiesByToolSchema, daemon: z26.object({
1982
- version: z26.string(),
1983
- name: z26.string().max(40),
1984
- boot: z26.string().uuid().optional(),
2357
+ var PHONE_COMMANDS_MAX = 300;
2358
+ var PhoneSlashCommandSchema = SlashCommandSchema.extend({ description: z28.string().max(200).optional() }).strict();
2359
+ var PhoneServerMessageSchema = z28.discriminatedUnion("type", [
2360
+ z28.object({ type: z28.literal("snapshot"), protocol: z28.literal(PHONE_PROTOCOL), sessions: z28.array(PhoneSessionSchema), capabilities: CapabilitiesByToolSchema, daemon: z28.object({
2361
+ version: z28.string(),
2362
+ name: z28.string().max(40),
2363
+ boot: z28.string().uuid().optional(),
1985
2364
  /** The daemon takes `session.model`. */
1986
- models: z26.literal(true).optional(),
2365
+ models: z28.literal(true).optional(),
1987
2366
  /** The daemon sends `session.checklist` and a session's `checklist` summary. */
1988
- checklist: z26.literal(true).optional(),
2367
+ checklist: z28.literal(true).optional(),
1989
2368
  /** `update`: the daemon can install a version and restart (npm, systemd); `restart`: it can restart (systemd). */
1990
- update: z26.literal(true).optional(),
1991
- restart: z26.literal(true).optional(),
2369
+ update: z28.literal(true).optional(),
2370
+ restart: z28.literal(true).optional(),
1992
2371
  /** The daemon takes `session.close` and `session.resume`. */
1993
- sessionClose: z26.literal(true).optional()
1994
- }), device: z26.object({ confirm: z26.boolean(), push: z26.enum(["on", "off", "stale", "unavailable"]).optional(), chat: z26.literal(true).optional(), contextNear: ContextPrefsSchema.shape.near.optional() }).optional() }),
1995
- z26.object({ type: z26.literal("confirm.challenge"), purpose: ConfirmPurposeSchema, challenge: B64U2.max(64), rpId: z26.string().max(253), credentialId: B64U2.max(1366).optional(), expiresInMs: z26.number().int().positive() }),
1996
- z26.object({ type: z26.literal("session.updated"), session: PhoneSessionSchema }),
1997
- z26.object({ type: z26.literal("session.removed"), id: z26.string() }),
2372
+ sessionClose: z28.literal(true).optional(),
2373
+ /** The daemon streams a session's terminal (`term.open`). */
2374
+ terminal: z28.literal(true).optional(),
2375
+ /** The PC lets a phone type into a terminal (`term.hold`): its setting is on. */
2376
+ terminalInput: z28.literal(true).optional(),
2377
+ /** The daemon answers `session.commands`. */
2378
+ commands: z28.literal(true).optional(),
2379
+ /** The daemon answers `openrig.row`. */
2380
+ rigRows: z28.literal(true).optional(),
2381
+ /** The daemon answers `openrig.asks` and `openrig.answer` (« À toi »). */
2382
+ openrig: z28.literal(true).optional(),
2383
+ /** The daemon takes `session.broadcast` (« Écrire au groupe »). */
2384
+ broadcast: z28.literal(true).optional()
2385
+ }), device: z28.object({ confirm: z28.boolean(), push: z28.enum(["on", "off", "stale", "unavailable"]).optional(), chat: z28.literal(true).optional(), contextNear: ContextPrefsSchema.shape.near.optional() }).optional() }),
2386
+ /** « À toi » on this PC: the answer to `openrig.asks`, then each change, whole. */
2387
+ z28.object({ type: z28.literal("openrig.asks"), channel: HumanChannelSchema, asks: z28.array(HumanAskSchema), partial: z28.literal(true).optional(), truncated: z28.literal(true).optional() }),
2388
+ /** An answer's end, as on the desktop (`openrig.answered`), under the phone's `op`. `rejected`: the device check refused it (`reason`). */
2389
+ z28.object({
2390
+ type: z28.literal("openrig.answered"),
2391
+ op: OperationIdSchema,
2392
+ qitemId: z28.string(),
2393
+ ok: z28.boolean(),
2394
+ outcome: z28.enum(["recorded", "answered", "already"]).optional(),
2395
+ remaining: z28.array(z28.string()).optional(),
2396
+ replyId: z28.string().optional(),
2397
+ error: HumanAnswerErrorSchema.optional(),
2398
+ message: z28.string().max(500).optional(),
2399
+ rejected: z28.enum(["confirm_required", "assertion_invalid", "assertion_expired", "unavailable"]).optional()
2400
+ }),
2401
+ z28.object({ type: z28.literal("confirm.challenge"), purpose: ConfirmPurposeSchema, challenge: B64U2.max(64), rpId: z28.string().max(253), credentialId: B64U2.max(1366).optional(), expiresInMs: z28.number().int().positive() }),
2402
+ z28.object({ type: z28.literal("session.updated"), session: PhoneSessionSchema }),
2403
+ z28.object({ type: z28.literal("session.removed"), id: z28.string() }),
1998
2404
  /** A session's checklist, sent to the phone that watches it; `null`: it has none (any more). */
1999
- z26.object({ type: z26.literal("session.checklist"), id: z26.string(), checklist: PhoneChecklistSchema.nullable() }),
2405
+ z28.object({ type: z28.literal("session.checklist"), id: z28.string(), checklist: PhoneChecklistSchema.nullable() }),
2000
2406
  /** `pending.cut` is set when even this body was shortened. */
2001
- z26.object({ type: z26.literal("session.pending"), id: z26.string(), pending: PhonePendingSchema }),
2002
- z26.object({ type: z26.literal("session.preview"), id: z26.string(), lines: z26.array(z26.string()) }),
2407
+ z28.object({ type: z28.literal("session.pending"), id: z28.string(), pending: PhonePendingSchema }),
2408
+ z28.object({ type: z28.literal("session.preview"), id: z28.string(), lines: z28.array(z28.string()) }),
2003
2409
  /** `cut`: the ids of the items shortened; `more`: older items were left out. */
2004
- z26.object({ type: z26.literal("session.thread"), id: z26.string(), items: z26.array(ThreadItemSchema), cut: z26.array(z26.string()), more: z26.boolean() }),
2005
- z26.object({ type: z26.literal("session.thread.item"), id: z26.string(), item: ThreadItemSchema, cut: z26.literal(true).optional() }),
2006
- z26.object({
2007
- type: z26.literal("operation.result"),
2410
+ z28.object({ type: z28.literal("session.thread"), id: z28.string(), items: z28.array(ThreadItemSchema), cut: z28.array(z28.string()), more: z28.boolean() }),
2411
+ z28.object({ type: z28.literal("session.thread.item"), id: z28.string(), item: ThreadItemSchema, cut: z28.literal(true).optional() }),
2412
+ z28.object({
2413
+ type: z28.literal("operation.result"),
2008
2414
  op: OperationIdSchema,
2009
2415
  status: OperationStatusSchema,
2010
2416
  reason: OperationReasonSchema.optional(),
2011
2417
  /** How an applied `session.close` ended the agent: `killed` when it had to be forced. */
2012
- how: CloseHowSchema.optional()
2418
+ how: CloseHowSchema.optional(),
2419
+ /** An applied `session.broadcast`: the names that got it and those that did not. */
2420
+ sent: z28.array(z28.string().max(100)).max(BROADCAST_SESSIONS_MAX).optional(),
2421
+ refused: z28.array(z28.object({ name: z28.string().max(100), reason: z28.string().max(200) })).max(BROADCAST_SESSIONS_MAX).optional()
2013
2422
  }),
2014
2423
  /** The models an agent offers; `error`: it could not be asked, `models` is then what Ledge knows without it. */
2015
- z26.object({ type: z26.literal("models.listing"), tool: ToolSchema, models: z26.array(PhoneModelChoiceSchema).max(40), error: z26.literal(true).optional() }),
2424
+ z28.object({ type: z28.literal("models.listing"), tool: ToolSchema, models: z28.array(PhoneModelChoiceSchema).max(40), error: z28.literal(true).optional() }),
2016
2425
  /** A model change that was accepted and then failed (the agent could not restart). */
2017
- z26.object({ type: z26.literal("session.model.failed"), id: z26.string(), reason: ModelRefusalSchema }),
2018
- z26.object({ type: z26.literal("chat.history"), turns: z26.array(PhoneChatTurnSchema).max(50) }),
2019
- z26.object({ type: z26.literal("chat.step"), qid: OperationIdSchema, step: PhoneChatStepSchema }),
2426
+ z28.object({ type: z28.literal("session.model.failed"), id: z28.string(), reason: ModelRefusalSchema }),
2427
+ /** A session's slash commands; `error`: they could not be read (the agent is not listed, or did not answer in time): a command typed by hand still goes. */
2428
+ z28.object({ type: z28.literal("session.commands.listing"), id: z28.string(), commands: z28.array(PhoneSlashCommandSchema).max(PHONE_COMMANDS_MAX), error: z28.literal(true).optional() }),
2429
+ /** A queue row's state, answering `openrig.row`: `row`, or `error`. */
2430
+ z28.object({ type: z28.literal("openrig.rowState"), qitem: z28.string(), row: PhoneRigRowSchema.optional(), error: PhoneRowErrorSchema.optional() }),
2431
+ z28.object({ type: z28.literal("chat.history"), turns: z28.array(PhoneChatTurnSchema).max(50) }),
2432
+ z28.object({ type: z28.literal("chat.step"), qid: OperationIdSchema, step: PhoneChatStepSchema }),
2020
2433
  /** The whole text so far, not an increment. */
2021
- z26.object({ type: z26.literal("chat.delta"), qid: OperationIdSchema, text: z26.string().max(THREAD_TEXT_MAX) }),
2022
- z26.object({ type: z26.literal("chat.done"), qid: OperationIdSchema, turn: PhoneChatTurnSchema }),
2023
- z26.object({ type: z26.literal("chat.error"), qid: OperationIdSchema, code: ChatErrorCodeSchema }),
2434
+ z28.object({ type: z28.literal("chat.delta"), qid: OperationIdSchema, text: z28.string().max(THREAD_TEXT_MAX) }),
2435
+ z28.object({ type: z28.literal("chat.done"), qid: OperationIdSchema, turn: PhoneChatTurnSchema }),
2436
+ z28.object({ type: z28.literal("chat.error"), qid: OperationIdSchema, code: ChatErrorCodeSchema }),
2024
2437
  /** The daemon updating or restarting itself, whoever asked: npm runs, then the service restarts (the link drops right after). */
2025
- z26.object({ type: z26.literal("daemon.progress"), version: z26.string().max(40), step: z26.enum(["installing", "restarting"]) }),
2438
+ z28.object({ type: z28.literal("daemon.progress"), version: z28.string().max(40), step: z28.enum(["installing", "restarting"]) }),
2026
2439
  /** Nothing was changed. Never npm's output nor a command: both hold the PC's paths. */
2027
- z26.object({ type: z26.literal("daemon.failed"), version: z26.string().max(40), reason: UpdateFailureSchema }),
2440
+ z28.object({ type: z28.literal("daemon.failed"), version: z28.string().max(40), reason: UpdateFailureSchema }),
2028
2441
  /** The tasks Ledge gave, open or closed lately, after each snapshot; then each change. */
2029
- z26.object({ type: z26.literal("tasks"), tasks: z26.array(PhoneTaskSchema).max(200) }),
2030
- z26.object({ type: z26.literal("task.updated"), task: PhoneTaskSchema }),
2442
+ z28.object({ type: z28.literal("tasks"), tasks: z28.array(PhoneTaskSchema).max(200) }),
2443
+ z28.object({ type: z28.literal("task.updated"), task: PhoneTaskSchema }),
2031
2444
  AttachmentStoredSchema,
2032
2445
  AttachmentDataSchema,
2033
2446
  AttachmentErrorSchema,
2447
+ /** A terminal's first screen (also the answer to `term.resync`, then without `op`): the pane's size, the cursor, and the `seq` the next output takes. */
2448
+ z28.object({
2449
+ type: z28.literal("term.opened"),
2450
+ op: OperationIdSchema.optional(),
2451
+ tid: TerminalIdSchema,
2452
+ id: z28.string(),
2453
+ cols: TermDimSchema,
2454
+ rows: TermDimSchema,
2455
+ screen: z28.string().max(TERM_SCREEN_MAX),
2456
+ cursor: z28.object({ x: z28.number().int().nonnegative(), y: z28.number().int().nonnegative() }),
2457
+ seq: z28.number().int().nonnegative(),
2458
+ /** Read-only for good: a subagent's page shows its parent's pane. */
2459
+ readOnly: z28.literal(true).optional()
2460
+ }),
2461
+ /** What the pane printed since the last one; `seq` + 1 each time. */
2462
+ z28.object({ type: z28.literal("term.output"), tid: TerminalIdSchema, seq: z28.number().int().nonnegative(), data: z28.string().min(1).max(TERM_OUTPUT_MAX) }),
2463
+ z28.object({ type: z28.literal("term.size"), tid: TerminalIdSchema, cols: TermDimSchema, rows: TermDimSchema }),
2464
+ /** The phone holds the hand until `until`, pushed back by each key (5 min), never past 30 min from the hold. */
2465
+ z28.object({ type: z28.literal("term.held"), tid: TerminalIdSchema, until: z28.string().datetime() }),
2466
+ z28.object({ type: z28.literal("term.released"), tid: TerminalIdSchema, why: TermReleaseWhySchema }),
2467
+ z28.object({ type: z28.literal("term.exit"), tid: TerminalIdSchema, why: TermExitWhySchema }),
2034
2468
  /** Never carries free text. */
2035
- z26.object({ type: z26.literal("error"), code: z26.enum(["invalid", "unknown_session", "too_large"]), request: z26.string().max(40).optional() })
2469
+ z28.object({ type: z28.literal("error"), code: z28.enum(["invalid", "unknown_session", "too_large"]), request: z28.string().max(40).optional() })
2036
2470
  ]);
2037
2471
 
2472
+ // ../protocol/src/media.ts
2473
+ import { z as z29 } from "zod";
2474
+ var MediaCommandSchema = z29.enum(["previous", "play_pause", "next"]);
2475
+ var ARTWORK_MAX_BYTES = 512 * 1024;
2476
+ var NowPlayingSchema = z29.object({
2477
+ /** The track's title; a session without one is not reported (nothing to show). */
2478
+ title: z29.string().min(1),
2479
+ /** '' when the player gives none (a web video often has no artist). */
2480
+ artist: z29.string(),
2481
+ album: z29.string().optional(),
2482
+ /** The cover as a `data:image/…;base64,` URL; left out when the player has none, or it is over ARTWORK_MAX_BYTES. It can
2483
+ * arrive in a later event than the track itself: players often publish the thumbnail a moment after the title. */
2484
+ artwork: z29.string().startsWith("data:image/").optional(),
2485
+ /** True while it plays; a paused session is still reported (with false), `null` means no media session at all. */
2486
+ playing: z29.boolean(),
2487
+ /** What the player accepts now; a control it refuses is disabled, not hidden, at the front's choice. */
2488
+ can: z29.object({ previous: z29.boolean(), playPause: z29.boolean(), next: z29.boolean() }),
2489
+ /** The player: SMTC's source app id (`Spotify.exe`, `MSEdge`, a packaged app's AUMID), and its display name when
2490
+ * Windows knows one. Several players can hold a session: the one reported is the one playing (Windows' current one
2491
+ * first), else Windows' current one. Commands go to that same player. */
2492
+ player: z29.object({ id: z29.string().min(1), name: z29.string().optional() })
2493
+ });
2494
+ var NowPlayingStateSchema = NowPlayingSchema.nullable();
2495
+
2038
2496
  // src/imageInfo.ts
2039
2497
  var ok = (mime, width, height) => width > 0 && height > 0 ? { mime, width, height } : null;
2040
2498
  function jpeg(b) {