@paradow/ledge 0.35.0 → 0.36.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.
@@ -729,7 +729,7 @@ var ProjectsSchema = z14.object({ projects: z14.array(ProjectSchema).max(100), r
729
729
  });
730
730
 
731
731
  // ../protocol/src/messages.ts
732
- import { z as z21 } from "zod";
732
+ import { z as z22 } from "zod";
733
733
 
734
734
  // ../protocol/src/repos.ts
735
735
  import { z as z15 } from "zod";
@@ -916,92 +916,263 @@ var OpenRigReseatedSchema = z17.object({
916
916
  linksUnsupported: z17.boolean().optional()
917
917
  });
918
918
 
919
- // ../protocol/src/routing.ts
919
+ // ../protocol/src/openrigRoles.ts
920
920
  import { z as z18 } from "zod";
921
- var MachineInventorySchema = z18.object({
922
- id: z18.string().min(1).max(80),
923
- label: z18.string().min(1).max(120),
924
- online: z18.boolean(),
925
- local: z18.boolean(),
926
- sessions: z18.array(z18.object({ id: z18.string(), name: z18.string(), project: z18.string(), cwd: z18.string(), topic: z18.string().optional(), state: z18.string(), readOnly: z18.boolean() })).max(500),
927
- folders: z18.array(z18.object({ project: z18.string(), cwd: z18.string() })).max(100)
928
- });
929
- var RoutingContextSchema = z18.object({
930
- machines: z18.array(MachineInventorySchema).min(1).max(20),
931
- history: z18.array(z18.object({ question: z18.string().max(2e4), answer: z18.string().max(2e4).optional(), machineId: z18.string().optional() })).max(50)
932
- });
933
- var RouteResultSchema = z18.object({
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() })
928
+ ]);
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({
932
+ 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(),
940
+ origin: OriginSchema
941
+ });
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(),
951
+ 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()),
959
+ origin: OriginSchema
960
+ });
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()),
975
+ /** 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(),
991
+ runtime: SourcedStringSchema,
992
+ model: SourcedStringSchema,
993
+ effort: SourcedStringSchema,
994
+ uses: z18.object({ skills: RoleUsesListSchema, guidance: RoleUsesListSchema, subagents: RoleUsesListSchema, plugins: RoleUsesListSchema, runtimeResources: RoleUsesListSchema }),
995
+ /** 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(),
1009
+ runtime: SourcedStringSchema,
1010
+ model: SourcedStringSchema,
1011
+ effort: SourcedStringSchema,
1012
+ cwd: SourcedStringSchema,
1013
+ cultureFile: SourcedStringSchema,
1014
+ member: z18.string().optional(),
1015
+ memberStartup: z18.array(StartupEntrySchema),
1016
+ /** The Role tab of this seat: its role guidance (`role.md`), then the startup files of its own (member layer), in delivery
1017
+ * 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),
1022
+ /** In the order OpenRig returns them. */
1023
+ startup: z18.array(StartupEntrySchema),
1024
+ /** `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()
1026
+ }).optional()
1027
+ });
1028
+ var RoleUnavailableSchema = z18.enum(["harness_prompt", "effective_settings", "delivered_content", "harness_own_files"]);
1029
+ var RoleDetailSchema = z18.object({
1030
+ 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() }))
1036
+ }),
1037
+ 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),
1043
+ /** 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(),
1059
+ error: RoleErrorSchema.optional()
1060
+ });
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(),
1067
+ role: RoleDetailSchema.optional(),
1068
+ error: RoleErrorSchema.optional()
1069
+ });
1070
+ var OpenRigRoleFileSchema = z18.object({
1071
+ type: z18.literal("openrig.roleFile"),
1072
+ requestId: z18.string().min(1).max(100),
1073
+ machineId: z18.string().optional(),
1074
+ 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(),
1086
+ error: RoleErrorSchema.optional()
1087
+ });
1088
+ var ROLE_FILE_MAX = 512 * 1024;
1089
+
1090
+ // ../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({
934
1105
  /** Null means an answer or a clarification, never an implicit local destination. */
935
- machineId: z18.string().nullable(),
936
- text: z18.string().min(1).max(2e4),
937
- choices: z18.array(z18.string()).max(20).optional()
1106
+ machineId: z19.string().nullable(),
1107
+ text: z19.string().min(1).max(2e4),
1108
+ choices: z19.array(z19.string()).max(20).optional()
938
1109
  });
939
1110
 
940
1111
  // ../protocol/src/thread.ts
941
- import { z as z19 } from "zod";
942
- var ToolStatusSchema = z19.enum(["running", "success", "failed", "unknown"]);
943
- var FileChangeSchema = z19.object({ path: z19.string().min(1), from: z19.string().min(1).optional(), change: z19.enum(["add", "edit", "delete", "write"]), diff: z19.string().optional() });
944
- var base = { id: z19.string().min(1), at: z19.string().datetime(), turn: z19.number().int().nonnegative(), helperId: z19.string().optional() };
945
- var ThreadItemSchema = z19.discriminatedUnion("kind", [
946
- z19.object({ kind: z19.literal("prompt"), ...base, text: z19.string(), images: z19.array(AttachmentRefSchema).optional() }),
947
- z19.object({ kind: z19.literal("message"), ...base, text: z19.string() }),
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() }),
948
1119
  /** `id` is the harness's tool_use_id when it gives one, so the result updates the same row; `byClose`: a question
949
1120
  * dismissed by Ledge closing the session. */
950
- z19.object({
951
- kind: z19.literal("tool"),
1121
+ z20.object({
1122
+ kind: z20.literal("tool"),
952
1123
  ...base,
953
- tool: z19.string(),
954
- label: z19.string(),
955
- input: z19.string().optional(),
956
- output: z19.string().optional(),
957
- error: z19.string().optional(),
1124
+ tool: z20.string(),
1125
+ label: z20.string(),
1126
+ input: z20.string().optional(),
1127
+ output: z20.string().optional(),
1128
+ error: z20.string().optional(),
958
1129
  status: ToolStatusSchema,
959
- durationMs: z19.number().nonnegative().optional(),
960
- files: z19.array(FileChangeSchema).default([]),
961
- byClose: z19.literal(true).optional(),
1130
+ durationMs: z20.number().nonnegative().optional(),
1131
+ files: z20.array(FileChangeSchema).default([]),
1132
+ byClose: z20.literal(true).optional(),
962
1133
  /** Images the tool returned (a browser screenshot), in order; `imagesDropped`: some were not kept. */
963
- images: z19.array(AttachmentRefSchema).max(ATTACHMENTS_MAX).optional(),
964
- imagesDropped: z19.literal(true).optional()
1134
+ images: z20.array(AttachmentRefSchema).max(ATTACHMENTS_MAX).optional(),
1135
+ imagesDropped: z20.literal(true).optional()
965
1136
  }),
966
1137
  /** `unknown`: answered in the terminal, the daemon only saw the prompt go away; `always`: allowed and not asked again;
967
1138
  * `byClose`: denied by Ledge closing the session. */
968
- z19.object({ kind: z19.literal("permission"), ...base, tool: z19.string(), text: z19.string(), decision: z19.enum(["accept", "deny", "always", "unknown"]).optional(), byClose: z19.literal(true).optional() }),
969
- z19.object({ kind: z19.literal("reply"), ...base, text: z19.string() }),
970
- z19.object({ kind: z19.literal("helper"), ...base, task: z19.string(), agentType: z19.string().optional(), state: z19.enum(["working", "exited"]) }),
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"]) }),
971
1142
  /** 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. */
972
- z19.object({ kind: z19.literal("sent"), ...base, to: z19.string(), peer: z19.string().optional(), summary: z19.string().optional(), text: z19.string(), status: z19.enum(["sending", "delivered", "read", "failed"]), received: z19.string().optional(), via: z19.literal("ledge").optional() }),
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() }),
973
1144
  /** 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. */
974
- z19.object({ kind: z19.literal("received"), ...base, from: z19.string(), peer: z19.string().optional(), text: z19.string(), sent: z19.string().optional() }),
1145
+ z20.object({ kind: z20.literal("received"), ...base, from: z20.string(), peer: z20.string().optional(), text: z20.string(), sent: z20.string().optional() }),
975
1146
  /** An automated notice of the agent's harness about messages between sessions (Claude Code's `[Cross-session idle
976
1147
  * notice]` / `[Cross-session delivery notice]`): a system event, never the user's words. `name` is the session it is
977
1148
  * about as quoted, `peer` its Ledge session id; a delivery notice says the outcome of `count` messages to `recipients`. */
978
- z19.object({
979
- kind: z19.literal("notice"),
1149
+ z20.object({
1150
+ kind: z20.literal("notice"),
980
1151
  ...base,
981
- notice: z19.enum(["idle", "exited", "unavailable", "expired", "delivery", "other"]),
1152
+ notice: z20.enum(["idle", "exited", "unavailable", "expired", "delivery", "other"]),
982
1153
  /** 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. */
983
- task: z19.string().optional(),
1154
+ task: z20.string().optional(),
984
1155
  /** A task this session handed over (`outgoing`), and how (issue #92). */
985
- taskOp: z19.enum(TRANSMISSION_OPS).optional(),
986
- outgoing: z19.literal(true).optional(),
987
- name: z19.string().optional(),
988
- peer: z19.string().optional(),
989
- time: z19.string().optional(),
990
- summary: z19.string().optional(),
991
- status: z19.enum(["held", "denied", "expired", "delivered", "refused", "dropped", "unknown"]).optional(),
992
- count: z19.number().int().positive().optional(),
993
- recipients: z19.array(z19.string()).optional(),
994
- reason: z19.string().optional(),
995
- text: z19.string()
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()
996
1167
  })
997
1168
  ]);
998
1169
 
999
1170
  // ../protocol/src/mobile.ts
1000
- import { z as z20 } from "zod";
1001
- var RelayUrlSchema = z20.string().transform((v, ctx) => {
1171
+ import { z as z21 } from "zod";
1172
+ var RelayUrlSchema = z21.string().transform((v, ctx) => {
1002
1173
  const bad = () => {
1003
- ctx.addIssue({ code: z20.ZodIssueCode.custom, message: "invalid relay URL" });
1004
- return z20.NEVER;
1174
+ ctx.addIssue({ code: z21.ZodIssueCode.custom, message: "invalid relay URL" });
1175
+ return z21.NEVER;
1005
1176
  };
1006
1177
  let u;
1007
1178
  try {
@@ -1014,114 +1185,116 @@ var RelayUrlSchema = z20.string().transform((v, ctx) => {
1014
1185
  if (u.username || u.password || u.pathname !== "/" || u.search || u.hash) return bad();
1015
1186
  return u.origin;
1016
1187
  });
1017
- var MobileConfigSchema = z20.object({ enabled: z20.boolean(), relayUrl: RelayUrlSchema });
1018
- var MobileLinkStateSchema = z20.discriminatedUnion("state", [
1019
- z20.object({ state: z20.literal("off") }),
1020
- z20.object({ state: z20.literal("connecting") }),
1021
- z20.object({ state: z20.literal("online") }),
1022
- z20.object({ state: z20.literal("offline"), retryAt: z20.string().datetime(), error: z20.string() }),
1023
- z20.object({ state: z20.literal("signed_out"), reason: z20.enum(["other_pc", "session_invalid"]) }),
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"]) }),
1024
1195
  /** The mobile service did not start (a broken mobile.json, a missing key store): nothing is linked until the daemon restarts. */
1025
- z20.object({ state: z20.literal("unavailable"), error: z20.string().max(200) })
1196
+ z21.object({ state: z21.literal("unavailable"), error: z21.string().max(200) })
1026
1197
  ]);
1027
- var MobilePairingSchema = z20.object({
1028
- id: z20.string(),
1029
- label: z20.string(),
1030
- code: z20.string().nullable(),
1031
- expiresAt: z20.string().datetime(),
1032
- state: z20.enum(["waiting", "confirm", "approved", "linked", "expired", "refused"])
1033
- });
1034
- var MobileStateSchema = z20.object({
1035
- enabled: z20.boolean(),
1036
- relayUrl: z20.string(),
1037
- account: z20.object({ login: z20.string(), accountId: z20.string() }).nullable(),
1038
- signin: z20.object({ userCode: z20.string(), verificationUri: z20.string(), expiresAt: z20.string().datetime() }).nullable(),
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(),
1039
1210
  /** The last sign-in that did not end with a session; cleared by the next one. */
1040
- signinError: z20.enum(["expired", "denied", "not_allowed", "failed"]).nullable(),
1211
+ signinError: z21.enum(["expired", "denied", "not_allowed", "failed"]).nullable(),
1041
1212
  link: MobileLinkStateSchema,
1042
- devices: z20.array(z20.object({ id: z20.string(), label: z20.string(), approvedAt: z20.string(), online: z20.boolean(), lastSeenAt: z20.string().optional() })),
1043
- pairings: z20.array(MobilePairingSchema)
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)
1044
1215
  });
1045
1216
 
1046
1217
  // ../protocol/src/messages.ts
1047
- var RefusalCodeSchema = z21.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"]);
1048
- var SessionEventSchema = z21.object({
1049
- name: z21.enum(["SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", "Notification", "Stop", "SessionEnd", "PaneChanged", "PaneGone", "PanePrompt", "PaneIdle", "InjectFailed", "Decided", "PostToolUse", "PostToolUseFailure", "StopFailure", "SubagentStart", "SubagentStop", "PaneTitle", "Renamed", "NativeRequest", "AgentMessage", "QueueUpdate"]),
1050
- at: z21.string().datetime(),
1051
- source: z21.enum(["hook", "pane", "daemon"]),
1052
- tool: z21.string().optional(),
1053
- text: z21.string().optional(),
1054
- options: z21.array(z21.string()).optional(),
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(),
1055
1226
  /** Each option's description, by index ('' when it has none); left out when no option has one. */
1056
- optionDetails: z21.array(z21.string()).optional(),
1057
- kind: z21.enum(["question", "permission", "plan", "diff"]).optional(),
1227
+ optionDetails: z22.array(z22.string()).optional(),
1228
+ kind: z22.enum(["question", "permission", "plan", "diff"]).optional(),
1058
1229
  /** PanePrompt: what to review in full before deciding (a plan read in the terminal), when `text` is its summary. */
1059
- body: z21.string().optional(),
1060
- exitCode: z21.number().int().nullable().optional(),
1061
- helperId: z21.string().optional(),
1230
+ body: z22.string().optional(),
1231
+ exitCode: z22.number().int().nullable().optional(),
1232
+ helperId: z22.string().optional(),
1062
1233
  /** The helper's description, once known (Claude Code: its `.meta.json`, written after SubagentStart). */
1063
- task: z21.string().optional(),
1234
+ task: z22.string().optional(),
1064
1235
  /** PostToolUseFailure: the user interrupted the turn (Esc); Claude then waits for input with no Stop. */
1065
- interrupt: z21.boolean().optional(),
1236
+ interrupt: z22.boolean().optional(),
1066
1237
  /** UserPromptSubmit, PostToolUse: the images the prompt or the tool result carried, by attachment id. */
1067
- attachments: z21.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(),
1238
+ attachments: z22.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(),
1068
1239
  /** PostToolUse: some of the result's images were not kept. */
1069
- imagesDropped: z21.boolean().optional(),
1240
+ imagesDropped: z22.boolean().optional(),
1070
1241
  /** QueueUpdate: OMP's queue as it stands. */
1071
- queue: z21.array(z21.object({ text: z21.string(), mode: z21.enum(["steer", "follow_up"]) })).optional(),
1242
+ queue: z22.array(z22.object({ text: z22.string(), mode: z22.enum(["steer", "follow_up"]) })).optional(),
1072
1243
  /** AgentMessage: the harness's own message, its text so far (`streaming`) or whole. `messageId` is unique for the session's life. */
1073
- messageId: z21.string().optional(),
1074
- streaming: z21.boolean().optional(),
1244
+ messageId: z22.string().optional(),
1245
+ streaming: z22.boolean().optional(),
1075
1246
  /** NativeRequest: the dialog's id, and OMP's `ask` questions when it is one. */
1076
- requestId: z21.string().optional(),
1077
- questions: z21.array(AskQuestionSchema).optional(),
1247
+ requestId: z22.string().optional(),
1248
+ questions: z22.array(AskQuestionSchema).optional(),
1078
1249
  /** Stop: its text is already in the thread as AgentMessage cards, which the reply card must not repeat. */
1079
- streamed: z21.boolean().optional(),
1250
+ streamed: z22.boolean().optional(),
1080
1251
  /** Native tracking (spec 2026-10-13 §2): the harness's id of the tool call, so its result lands on the same row. */
1081
- toolUseId: z21.string().optional(),
1252
+ toolUseId: z22.string().optional(),
1082
1253
  /** The tool's input as the harness gave it, every string capped by the hook. */
1083
- toolInput: z21.record(z21.string(), z21.unknown()).optional(),
1254
+ toolInput: z22.record(z22.string(), z22.unknown()).optional(),
1084
1255
  /** PostToolUse: the result as text; SubagentStop: nothing (the report travels in `text`). */
1085
- output: z21.string().optional(),
1086
- durationMs: z21.number().nonnegative().optional(),
1256
+ output: z22.string().optional(),
1257
+ durationMs: z22.number().nonnegative().optional(),
1087
1258
  /** PostToolUseFailure: the harness's error message. */
1088
- error: z21.string().optional(),
1259
+ error: z22.string().optional(),
1089
1260
  /** The session's transcript, or the helper's on SubagentStop; the daemon reads its tail for the agent's messages. */
1090
- transcriptPath: z21.string().optional(),
1261
+ transcriptPath: z22.string().optional(),
1091
1262
  /** Decided: what was chosen when the daemon knows it. */
1092
1263
  decision: DecisionSchema.optional(),
1093
1264
  /** Decided: the request was refused by Ledge closing the session (its interrupt keys), not by the user's answer. */
1094
- byClose: z21.literal(true).optional(),
1265
+ byClose: z22.literal(true).optional(),
1095
1266
  /** The agent's own session id when the hook names it, so the daemon can resume that conversation. */
1096
- agentSessionId: z21.string().optional()
1267
+ agentSessionId: z22.string().optional()
1097
1268
  });
1098
- var RecentSchema = z21.object({ cwd: z21.string().min(1), project: z21.string().min(1), lastAt: z21.string().datetime() });
1269
+ var RecentSchema = z22.object({ cwd: z22.string().min(1), project: z22.string().min(1), lastAt: z22.string().datetime() });
1099
1270
  var SEMVER = /^\d+\.\d+\.\d+$/;
1100
- var DaemonInfoSchema = z21.object({
1101
- version: z21.string(),
1102
- install: z21.enum(["npm", "git", "unknown"]),
1103
- systemd: z21.boolean(),
1104
- manual: z21.string().optional(),
1105
- routing: z21.boolean().optional(),
1106
- archive: z21.boolean().optional(),
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(),
1107
1278
  /** Takes `model` and `effort` on `session.launch` and answers `models.list` (#58). */
1108
- models: z21.boolean().optional(),
1279
+ models: z22.boolean().optional(),
1109
1280
  /** Drives OMP over its RPC: launching `omp` sessions is possible when the binary is there (`models.list` says so). */
1110
- omp: z21.boolean().optional(),
1281
+ omp: z22.boolean().optional(),
1111
1282
  /** Takes `session.model`: a live session's model and effort changed (#58, lot 2). */
1112
- modelSwitch: z21.boolean().optional(),
1283
+ modelSwitch: z22.boolean().optional(),
1113
1284
  /** Takes `approval` on an OMP `session.launch` (auto mode). */
1114
- ompApproval: z21.boolean().optional(),
1285
+ ompApproval: z22.boolean().optional(),
1115
1286
  /** Its home folder, so a client shows the folders under it as `~` (absent from older daemons). */
1116
- home: z21.string().optional(),
1117
- mobile: z21.boolean().optional(),
1287
+ home: z22.string().optional(),
1288
+ mobile: z22.boolean().optional(),
1118
1289
  /** Answers `openrig.status` and `openrig.act`: drives OpenRig on its machine. */
1119
- openrig: z21.boolean().optional()
1290
+ openrig: z22.boolean().optional(),
1291
+ /** Answers `openrig.roles`, `openrig.role` and `openrig.roleFile`: reads OpenRig's roles (agent specs). */
1292
+ openrigRoles: z22.boolean().optional()
1120
1293
  });
1121
- var UpdateFailureSchema = z21.enum(["git-install", "no-systemd", "sessions-at-risk", "npm-failed", "busy"]);
1122
- var ServerMessageSchema = z21.discriminatedUnion("type", [
1294
+ var UpdateFailureSchema = z22.enum(["git-install", "no-systemd", "sessions-at-risk", "npm-failed", "busy"]);
1295
+ var ServerMessageSchema = z22.discriminatedUnion("type", [
1123
1296
  SessionModelAcceptedSchema,
1124
- z21.object({ type: z21.literal("chat.routed"), qid: z21.string(), result: RouteResultSchema }),
1297
+ z22.object({ type: z22.literal("chat.routed"), qid: z22.string(), result: RouteResultSchema }),
1125
1298
  DocumentContentSchema,
1126
1299
  DocumentErrorSchema,
1127
1300
  AttachmentStoredSchema,
@@ -1135,97 +1308,100 @@ var ServerMessageSchema = z21.discriminatedUnion("type", [
1135
1308
  OpenRigSpecListSchema,
1136
1309
  OpenRigLaunchedSchema,
1137
1310
  OpenRigReseatedSchema,
1311
+ OpenRigRoleListSchema,
1312
+ OpenRigRoleDetailSchema,
1313
+ OpenRigRoleFileContentSchema,
1138
1314
  /** `recents`: the folders of past sessions, most recent first. `launcher`: the command that runs `ledge` inside WSL
1139
1315
  * (`[node, cli]`), so the overlay can attach a terminal to a session with `<launcher> attach <id>`. `daemon`: absent
1140
1316
  * from daemons older than the auto-update. */
1141
- z21.object({ type: z21.literal("snapshot"), sessions: z21.array(SessionSchema), recents: z21.array(RecentSchema).optional(), launcher: z21.array(z21.string()).optional(), daemon: DaemonInfoSchema.optional(), sshAlias: SshAliasSchema.optional() }),
1142
- z21.object({ type: z21.literal("session.updated"), session: SessionSchema }),
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 }),
1143
1319
  /** OMP: the instructions taken back from its queue by an interrupt that restores it; the asker puts them back in its draft. */
1144
- z21.object({
1145
- type: z21.literal("session.queue.restored"),
1146
- id: z21.string(),
1147
- texts: z21.array(z21.string()),
1320
+ z22.object({
1321
+ type: z22.literal("session.queue.restored"),
1322
+ id: z22.string(),
1323
+ texts: z22.array(z22.string()),
1148
1324
  /** The same instructions with the images they carried; `imagesDropped`: some images could not be put back. */
1149
- entries: z21.array(z21.object({ text: z21.string(), attachments: z21.array(AttachmentIdSchema).optional() })).optional(),
1150
- imagesDropped: z21.boolean().optional()
1325
+ entries: z22.array(z22.object({ text: z22.string(), attachments: z22.array(AttachmentIdSchema).optional() })).optional(),
1326
+ imagesDropped: z22.boolean().optional()
1151
1327
  }),
1152
- z21.object({ type: z21.literal("session.removed"), id: z21.string() }),
1153
- z21.object({ type: z21.literal("session.preview"), id: z21.string(), lines: z21.array(z21.string()) }),
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()) }),
1154
1330
  /** A session's thread, on request (spec 2026-10-13 §5); then each created or updated item, broadcast. */
1155
- z21.object({ type: z21.literal("session.thread"), id: z21.string(), items: z21.array(ThreadItemSchema) }),
1156
- z21.object({ type: z21.literal("session.thread.item"), id: z21.string(), item: ThreadItemSchema }),
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 }),
1157
1333
  /** Answer to the requester of a `session.launch`: the session exists (its `session.updated` is broadcast as usual). */
1158
- z21.object({ type: z21.literal("session.launched"), id: z21.string() }),
1334
+ z22.object({ type: z22.literal("session.launched"), id: z22.string() }),
1159
1335
  /** Answer to the requester of a `session.close`, once per row closed: the session `id` and how it ended. */
1160
- z21.object({ type: z21.literal("session.closed"), qid: z21.string(), row: z21.number().int().min(0), id: z21.string(), how: z21.enum(["exit", "killed"]) }),
1161
- z21.object({ type: z21.literal("recents"), recents: z21.array(RecentSchema) }),
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) }),
1162
1338
  /** Answer to the requester of a `folder.list` or `folder.create`: `path` resolved (`~` expanded), `parent` null at the
1163
1339
  * root, `entries` its subfolders by name (hidden ones left out). A failure keeps the asked path and says why in `error`,
1164
1340
  * never in an `error` message, which the launch form reads as a failed launch. */
1165
- z21.object({
1166
- type: z21.literal("folder.listing"),
1167
- path: z21.string(),
1168
- parent: z21.string().nullable(),
1169
- entries: z21.array(z21.string()),
1170
- error: z21.string().optional(),
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(),
1171
1347
  /** The request this answers, when it carried one. */
1172
- requestId: z21.string().optional(),
1348
+ requestId: z22.string().optional(),
1173
1349
  /** Those `entries` that are Git repositories, with their branch (the short commit when HEAD is detached). */
1174
- repos: z21.array(z21.object({ name: z21.string(), branch: z21.string() })).optional()
1350
+ repos: z22.array(z22.object({ name: z22.string(), branch: z22.string() })).optional()
1175
1351
  }),
1176
1352
  /** 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. */
1177
- z21.object({ type: z21.literal("chat.step"), qid: z21.string(), step: ChatStepSchema }),
1178
- z21.object({ type: z21.literal("chat.delta"), qid: z21.string(), text: z21.string() }),
1179
- z21.object({ type: z21.literal("chat.done"), qid: z21.string(), text: z21.string(), at: z21.string().datetime(), proposal: ChatProposalSchema.optional(), proposals: ChatProposalsSchema.optional(), relay: ChatRelaySchema.optional(), closes: ChatClosesSchema.optional(), projectProposal: ChatProjectProposalSchema.optional(), tasks: ChatTasksSchema.optional(), actions: ChatActionsSchema.optional() }),
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() }),
1180
1356
  /** What a `chat.act` applied: the rows done, and the one that failed with why (the rows after it stay proposed). */
1181
- z21.object({ type: z21.literal("chat.acted"), rid: z21.string(), qid: z21.string(), done: z21.array(z21.number().int().min(0)), failed: z21.array(z21.object({
1182
- row: z21.number().int().min(0),
1183
- message: z21.string(),
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(),
1184
1360
  /** nothing was sent */
1185
- refused: z21.literal(true).optional()
1361
+ refused: z22.literal(true).optional()
1186
1362
  })) }),
1187
1363
  /** What an `action.run` came to: `row` the action as the daemon resolved it (its summary, its risk); `reason` why it was not
1188
1364
  * done, with `code` (`refused`: not possible now; `agent`: a session may not run it; `confirm_required`: destructive, ask
1189
1365
  * again; `failed`: the handler turned it down; a free string, as an `error`'s). */
1190
- z21.object({ type: z21.literal("action.result"), rid: z21.string(), action: z21.string().min(1).max(40), row: ChatActionSchema.optional(), reason: z21.string().optional(), code: z21.string().optional() }),
1191
- z21.object({ type: z21.literal("chat.error"), qid: z21.string(), message: z21.string() }),
1192
- z21.object({ type: z21.literal("chat.history"), turns: z21.array(ChatTurnSchema) }),
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) }),
1193
1369
  /** The daemon updating itself: npm is running, then the service restarts (the socket closes right after). */
1194
- z21.object({ type: z21.literal("update.progress"), version: z21.string(), step: z21.enum(["installing", "restarting"]) }),
1370
+ z22.object({ type: z22.literal("update.progress"), version: z22.string(), step: z22.enum(["installing", "restarting"]) }),
1195
1371
  /** Nothing was changed. `detail`: the useful end of npm's output; `command`: what the person can run instead. */
1196
- z21.object({ type: z21.literal("update.failed"), version: z21.string(), reason: UpdateFailureSchema, detail: z21.string().optional(), command: z21.string().optional() }),
1372
+ z22.object({ type: z22.literal("update.failed"), version: z22.string(), reason: UpdateFailureSchema, detail: z22.string().optional(), command: z22.string().optional() }),
1197
1373
  /** The shared machines list (spec 2026-10-14 §5), sent to local clients only. */
1198
- z21.object({ type: z21.literal("machines"), machines: MachinesSchema }),
1374
+ z22.object({ type: z22.literal("machines"), machines: MachinesSchema }),
1199
1375
  /** The local daemon's projects and folder rules (spec 2026-10-16 build §5), sent to local clients only. */
1200
- z21.object({ type: z21.literal("projects"), projects: ProjectsSchema }),
1376
+ z22.object({ type: z22.literal("projects"), projects: ProjectsSchema }),
1201
1377
  /** The island's settings shared by the local fronts; null until a front sets them (the island then sends its own). Local clients only. */
1202
- z21.object({ type: z21.literal("island"), prefs: IslandPrefsSchema.nullable() }),
1378
+ z22.object({ type: z22.literal("island"), prefs: IslandPrefsSchema.nullable() }),
1203
1379
  /** Mobile access (lot 3), after the island in each snapshot and on every change. Local clients only. */
1204
- z21.object({ type: z21.literal("mobile"), state: MobileStateSchema }),
1380
+ z22.object({ type: z22.literal("mobile"), state: MobileStateSchema }),
1205
1381
  /** 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`. */
1206
- z21.object({ type: z21.literal("message.ack"), rid: z21.string(), outcome: z21.enum(["accepted", "queued", "native", "refused"]), reason: z21.string().optional() }),
1382
+ z22.object({ type: z22.literal("message.ack"), rid: z22.string(), outcome: z22.enum(["accepted", "queued", "native", "refused"]), reason: z22.string().optional() }),
1207
1383
  /** The answer to a `message.read`: the body with its sender, target and time, or the refusal's `reason`. */
1208
- z21.object({ type: z21.literal("message.body"), id: z21.string(), from: z21.string().optional(), to: z21.string().optional(), at: z21.string().optional(), text: z21.string().optional(), reason: z21.string().optional() }),
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() }),
1209
1385
  TaskResultSchema,
1210
1386
  SessionHandoverResultSchema,
1211
1387
  ContextPrefsMessageSchema,
1212
1388
  HandoverResultSchema,
1213
1389
  TaskUpdatedSchema,
1214
- z21.object({
1215
- type: z21.literal("error"),
1216
- message: z21.string(),
1217
- id: z21.string().optional(),
1390
+ z22.object({
1391
+ type: z22.literal("error"),
1392
+ message: z22.string(),
1393
+ id: z22.string().optional(),
1218
1394
  /** Le type du message client refusé. */
1219
- request: z21.string().optional(),
1395
+ request: z22.string().optional(),
1220
1396
  /** Ce que le front doit reconnaître au-delà du texte (NOTE_NOT_TYPED) ; une chaîne libre, qu'un front plus ancien ignore. */
1221
- code: z21.string().optional()
1397
+ code: z22.string().optional()
1222
1398
  })
1223
1399
  ]);
1224
1400
  var MESSAGE_MAX = 2e4;
1225
1401
  var SUMMARY_MAX = 500;
1226
- var launchRows = z21.array(z21.number().int().min(0).max(MAX_PROPOSALS - 1)).min(1).max(MAX_PROPOSALS).refine((r) => new Set(r).size === r.length, "a row twice");
1227
- var ClientMessageSchema = z21.discriminatedUnion("type", [
1228
- z21.object({ type: z21.literal("chat.route"), qid: z21.string().min(1).max(100), text: z21.string().min(1).max(2e4), tool: ToolSchema.optional(), context: RoutingContextSchema }),
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 }),
1229
1405
  DocumentReadSchema,
1230
1406
  AttachmentPutSchema,
1231
1407
  AttachmentCaptureSchema,
@@ -1238,155 +1414,158 @@ var ClientMessageSchema = z21.discriminatedUnion("type", [
1238
1414
  OpenRigSpecsSchema,
1239
1415
  OpenRigLaunchSchema,
1240
1416
  OpenRigSeatsSchema,
1417
+ OpenRigRolesSchema,
1418
+ OpenRigRoleSchema,
1419
+ OpenRigRoleFileSchema,
1241
1420
  /** The overlay starts a session: `cwd` is a WSL path (`~` allowed), `name` a preferred bot name (the daemon picks a
1242
1421
  * free one otherwise), `prompt` the agent's first instruction, `continue` resumes the folder's last conversation.
1243
1422
  * With `qid` it is the chat card of that turn: the daemon launches the turn's proposal and ignores the other fields
1244
1423
  * but `rows`, `model` and `effort`. */
1245
- z21.object({
1246
- type: z21.literal("session.launch"),
1424
+ z22.object({
1425
+ type: z22.literal("session.launch"),
1247
1426
  tool: ToolSchema,
1248
- cwd: z21.string().min(1),
1249
- name: z21.string().optional(),
1250
- prompt: z21.string().optional(),
1251
- continue: z21.boolean().optional(),
1252
- qid: z21.string().min(1).optional(),
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(),
1253
1432
  /** With `qid`: the card's rows to launch (#24), indexes into the turn's `proposals`, each once; the first row without it. */
1254
1433
  rows: launchRows.optional(),
1255
1434
  /** Folders in addition to `cwd` (Claude: `--add-dir`); resolved like `cwd`. */
1256
- dirs: z21.array(z21.string().min(1)).max(20).optional(),
1435
+ dirs: z22.array(z22.string().min(1)).max(20).optional(),
1257
1436
  /** The agent's model and effort (#58), the agent's own default when left out; with `qid`, for every row launched. */
1258
1437
  model: ModelIdSchema.optional(),
1259
1438
  effort: EffortSchema.optional(),
1260
1439
  /** OMP only: its approval mode, `always-ask` when left out. */
1261
1440
  approval: OmpApprovalSchema.optional(),
1262
1441
  /** Routing by the fleet, removed before the message reaches the daemon. */
1263
- machineId: z21.string().optional()
1442
+ machineId: z22.string().optional()
1264
1443
  }),
1265
1444
  /** The launch form's folder browser: list a folder's subfolders (home when no `path`), or make `name` inside `parent`
1266
1445
  * and list it. Both are answered with a `folder.listing`. */
1267
- z21.object({
1268
- type: z21.literal("folder.list"),
1269
- path: z21.string().optional(),
1446
+ z22.object({
1447
+ type: z22.literal("folder.list"),
1448
+ path: z22.string().optional(),
1270
1449
  /** Routing by the fleet, removed before the message reaches the daemon. */
1271
- machineId: z21.string().optional(),
1450
+ machineId: z22.string().optional(),
1272
1451
  /** Copied into the `folder.listing` that answers; the fleet relays only that listing, from the machine asked. */
1273
- requestId: z21.string().min(1).max(100).optional()
1452
+ requestId: z22.string().min(1).max(100).optional()
1274
1453
  }),
1275
- z21.object({
1276
- type: z21.literal("folder.create"),
1277
- parent: z21.string().min(1),
1278
- name: z21.string().min(1),
1454
+ z22.object({
1455
+ type: z22.literal("folder.create"),
1456
+ parent: z22.string().min(1),
1457
+ name: z22.string().min(1),
1279
1458
  /** As for `folder.list`: routing by the fleet, and the request its `folder.listing` answers. */
1280
- machineId: z21.string().optional(),
1281
- requestId: z21.string().min(1).max(100).optional()
1459
+ machineId: z22.string().optional(),
1460
+ requestId: z22.string().min(1).max(100).optional()
1282
1461
  }),
1283
1462
  /** `steer`: OMP only, redirect the turn running now instead of queueing the text after it. */
1284
1463
  /** OMP's `ask`: the answers to every question of the dialog `requestId`, in order (`selected` labels, and/or free `text`); `cancel` declines it. */
1285
- z21.object({ type: z21.literal("session.answer"), id: z21.string(), requestId: z21.string().min(1).max(200), answers: z21.array(z21.object({ id: z21.string(), selected: z21.array(z21.string().max(2e3)).max(100), text: z21.string().max(2e4).optional() })).max(50), cancel: z21.boolean().optional() }),
1286
- z21.object({ type: z21.literal("session.reply"), id: z21.string(), text: z21.string(), attachments: z21.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(), steer: z21.boolean().optional() }),
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() }),
1287
1466
  /** The chat card's instruction (spec 2026-10-12 relay §4): sent now if the session is free, else queued until it is. */
1288
- z21.object({ type: z21.literal("session.relay"), qid: z21.string().min(1) }),
1467
+ z22.object({ type: z22.literal("session.relay"), qid: z22.string().min(1) }),
1289
1468
  /** Takes the card's queued instruction back out of the queue. */
1290
- z21.object({ type: z21.literal("session.relay.cancel"), qid: z21.string().min(1) }),
1469
+ z22.object({ type: z22.literal("session.relay.cancel"), qid: z22.string().min(1) }),
1291
1470
  /** The chat's generic card (action registry spec §5.1): applies its rows in order (all of them without `rows`), stopping at
1292
1471
  * the first failure. `confirmed` says the front asked again; refused without it when a row is destructive. */
1293
- z21.object({
1294
- type: z21.literal("chat.act"),
1295
- rid: z21.string().min(1).max(100),
1296
- qid: z21.string().min(1),
1472
+ z22.object({
1473
+ type: z22.literal("chat.act"),
1474
+ rid: z22.string().min(1).max(100),
1475
+ qid: z22.string().min(1),
1297
1476
  rows: launchRows.optional(),
1298
- confirmed: z21.literal(true).optional(),
1477
+ confirmed: z22.literal(true).optional(),
1299
1478
  /** « Refuser »: each row (session.decide only) answers its session's request with deny, whatever its own decision; never
1300
1479
  * confirmed, and allowed on a request shown cut. The rows become `denied`. */
1301
- deny: z21.literal(true).optional()
1480
+ deny: z22.literal(true).optional()
1302
1481
  }),
1303
1482
  /** « Ignorer » the turn's cards, for every device and for Ledge (who is told at the next question); `undo` opens them
1304
1483
  * again (« Revoir »). Refused while one of them is under way. Every client gets the turn's `ignoredAt` through chat.history. */
1305
- z21.object({ type: z21.literal("chat.ignore"), qid: z21.string().min(1), undo: z21.literal(true).optional() }),
1484
+ z22.object({ type: z22.literal("chat.ignore"), qid: z22.string().min(1), undo: z22.literal(true).optional() }),
1306
1485
  /** A registry action run outside the chat (#93, the CLI): the daemon resolves `args` as it does a generic card's row, then
1307
1486
  * applies it through its own handler. `by` the session that asks, left out for the user; `confirmed` for a destructive one. */
1308
- z21.object({
1309
- type: z21.literal("action.run"),
1310
- rid: z21.string().min(1).max(100),
1311
- by: z21.string().min(1).optional(),
1487
+ z22.object({
1488
+ type: z22.literal("action.run"),
1489
+ rid: z22.string().min(1).max(100),
1490
+ by: z22.string().min(1).optional(),
1312
1491
  /** `by`'s key (LEDGE_SESSION_KEY) */
1313
- key: z21.string().max(128).optional(),
1492
+ key: z22.string().max(128).optional(),
1314
1493
  action: ActionIdSchema,
1315
- args: z21.record(z21.unknown()),
1316
- confirmed: z21.literal(true).optional()
1494
+ args: z22.record(z22.unknown()),
1495
+ confirmed: z22.literal(true).optional()
1317
1496
  }),
1318
1497
  /** The chat's close card: closes the turn's sessions, `rows` (indexes into its `closes`) or all of them. */
1319
- z21.object({ type: z21.literal("session.close"), qid: z21.string().min(1), rows: launchRows.optional() }),
1498
+ z22.object({ type: z22.literal("session.close"), qid: z22.string().min(1), rows: launchRows.optional() }),
1320
1499
  /** `always` and `note` only where the harness offers them (`offers`); a note goes with `deny`, for the agent to read. */
1321
- z21.object({
1322
- type: z21.literal("session.decide"),
1323
- id: z21.string(),
1500
+ z22.object({
1501
+ type: z22.literal("session.decide"),
1502
+ id: z22.string(),
1324
1503
  decision: DecisionSchema,
1325
- note: z21.string().trim().min(1).max(NOTE_MAX).optional(),
1504
+ note: z22.string().trim().min(1).max(NOTE_MAX).optional(),
1326
1505
  /** 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.
1327
1506
  * `key` (pendingKey) covers its whole content; older fronts send kind and text only. */
1328
- expect: PendingSchema.pick({ kind: true, text: true }).extend({ key: z21.string().max(64).optional() }).optional()
1507
+ expect: PendingSchema.pick({ kind: true, text: true }).extend({ key: z22.string().max(64).optional() }).optional()
1329
1508
  }),
1330
- z21.object({ type: z21.literal("session.focus"), id: z21.string() }),
1331
- z21.object({ type: z21.literal("session.kill"), id: z21.string() }),
1509
+ z22.object({ type: z22.literal("session.focus"), id: z22.string() }),
1510
+ z22.object({ type: z22.literal("session.kill"), id: z22.string() }),
1332
1511
  /** `restoreQueue` (OMP): also take back what waits in its queue, returned as `session.queue.restored` to put in the draft. */
1333
- z21.object({ type: z21.literal("session.interrupt"), id: z21.string(), restoreQueue: z21.boolean().optional() }),
1512
+ z22.object({ type: z22.literal("session.interrupt"), id: z22.string(), restoreQueue: z22.boolean().optional() }),
1334
1513
  /** Removes a finished (exited) or read-only (hook_only) session from the list; refused for a live launcher session. */
1335
- z21.object({ type: z21.literal("session.dismiss"), id: z21.string() }),
1514
+ z22.object({ type: z22.literal("session.dismiss"), id: z22.string() }),
1336
1515
  /** Puts a session in the archive: it leaves the live list but is kept. */
1337
- z21.object({ type: z21.literal("session.archive"), id: z21.string() }),
1516
+ z22.object({ type: z22.literal("session.archive"), id: z22.string() }),
1338
1517
  /** Takes an archived session back out of the archive, as it was. */
1339
- z21.object({ type: z21.literal("session.restore"), id: z21.string() }),
1518
+ z22.object({ type: z22.literal("session.restore"), id: z22.string() }),
1340
1519
  /** Starts the agent again on an archived session's conversation. */
1341
- z21.object({ type: z21.literal("session.resume"), id: z21.string() }),
1520
+ z22.object({ type: z22.literal("session.resume"), id: z22.string() }),
1342
1521
  /** Changes a live session's model and effort (#58, lot 2), `null` for the agent's own default: the daemon restarts the
1343
1522
  * agent on the same conversation with them, at once when the session is free, else at its next free moment. */
1344
- z21.object({ type: z21.literal("session.model"), id: z21.string(), model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
1523
+ z22.object({ type: z22.literal("session.model"), id: z22.string(), model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
1345
1524
  /** Deletes a session for good, archived or not. */
1346
- z21.object({ type: z21.literal("session.delete"), id: z21.string() }),
1525
+ z22.object({ type: z22.literal("session.delete"), id: z22.string() }),
1347
1526
  /** 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. */
1348
- z21.object({ type: z21.literal("session.rename"), id: z21.string(), topic: z21.string().max(500) }),
1349
- z21.object({ type: z21.literal("session.thread"), id: z21.string() }),
1350
- z21.object({ type: z21.literal("session.register"), session: SessionSchema }),
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 }),
1351
1530
  /** `agent` and `cwd` describe the session when the daemon does not know it yet (a hook from an agent started without ledge). */
1352
- z21.object({
1353
- type: z21.literal("session.event"),
1354
- id: z21.string(),
1531
+ z22.object({
1532
+ type: z22.literal("session.event"),
1533
+ id: z22.string(),
1355
1534
  event: SessionEventSchema,
1356
1535
  agent: ToolSchema.optional(),
1357
- cwd: z21.string().optional(),
1536
+ cwd: z22.string().optional(),
1358
1537
  /** The OpenRig seat the agent runs in (`OPENRIG_SESSION_NAME`, `pod-member@rig`), when OpenRig launched it. */
1359
1538
  rigSeat: RigSeatNameSchema.optional()
1360
1539
  }),
1361
- z21.object({ type: z21.literal("session.unregister"), id: z21.string(), exitCode: z21.number().int().nullable() }),
1362
- z21.object({ type: z21.literal("snapshot.request") }),
1363
- z21.object({ type: z21.literal("chat.ask"), qid: z21.string().min(1), text: z21.string(), images: z21.array(ImageUploadSchema).max(ATTACHMENTS_MAX).optional(), tool: ToolSchema.optional() }),
1364
- z21.object({ type: z21.literal("chat.cancel"), qid: z21.string().min(1) }),
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) }),
1365
1544
  /** Starts a new conversation with Ledge: the day's turns are cleared and the next question opens a new harness session. */
1366
- z21.object({ type: z21.literal("chat.reset") }),
1545
+ z22.object({ type: z22.literal("chat.reset") }),
1367
1546
  /** Installs `@paradow/ledge@version` and restarts the service (spec 2026-10-12 auto-update §6). */
1368
- z21.object({ type: z21.literal("update.daemon"), version: z21.string().regex(SEMVER) }),
1547
+ z22.object({ type: z22.literal("update.daemon"), version: z22.string().regex(SEMVER) }),
1369
1548
  /** Replaces the daemon's machines list (first connected front wins); refused unless valid. */
1370
- z21.object({ type: z21.literal("machines.set"), machines: MachinesSchema }),
1549
+ z22.object({ type: z22.literal("machines.set"), machines: MachinesSchema }),
1371
1550
  /** Replaces the local daemon's projects and rules as a whole; refused unless valid. */
1372
- z21.object({ type: z21.literal("projects.set"), projects: ProjectsSchema }),
1551
+ z22.object({ type: z22.literal("projects.set"), projects: ProjectsSchema }),
1373
1552
  /** Replaces the island's settings as a whole; refused unless valid. */
1374
- z21.object({ type: z21.literal("island.set"), prefs: IslandPrefsSchema }),
1553
+ z22.object({ type: z22.literal("island.set"), prefs: IslandPrefsSchema }),
1375
1554
  /** Mobile access (lot 3), local fronts only. A changed `relayUrl` drops the relay session. */
1376
- z21.object({ type: z21.literal("mobile.set"), enabled: z21.boolean(), relayUrl: RelayUrlSchema }),
1377
- z21.object({ type: z21.literal("mobile.signin") }),
1378
- z21.object({ type: z21.literal("mobile.signin.cancel") }),
1379
- z21.object({ type: z21.literal("mobile.signout") }),
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") }),
1380
1559
  /** While the link is offline: try again now. */
1381
- z21.object({ type: z21.literal("mobile.retry") }),
1382
- z21.object({ type: z21.literal("mobile.pairing.approve"), id: z21.string().min(1).max(100) }),
1383
- z21.object({ type: z21.literal("mobile.pairing.deny"), id: z21.string().min(1).max(100) }),
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) }),
1384
1563
  /** `id`: the device's fingerprint. */
1385
- z21.object({ type: z21.literal("mobile.device.revoke"), id: z21.string().min(1).max(100) }),
1564
+ z22.object({ type: z22.literal("mobile.device.revoke"), id: z22.string().min(1).max(100) }),
1386
1565
  /** 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. */
1387
- z21.object({ type: z21.literal("session.message"), rid: z21.string().min(1), from: z21.string().min(1), to: z21.string().min(1), text: z21.string().min(1).max(MESSAGE_MAX), summary: z21.string().max(SUMMARY_MAX).optional(), intercept: z21.boolean().optional() }),
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() }),
1388
1567
  /** `ledge read <id>`: a message's whole body, for its receiver or its sender (`by`, a session id). */
1389
- z21.object({ type: z21.literal("message.read"), id: z21.string().min(1).max(40), by: z21.string().min(1) }),
1568
+ z22.object({ type: z22.literal("message.read"), id: z22.string().min(1).max(40), by: z22.string().min(1) }),
1390
1569
  TaskCmdSchema,
1391
1570
  SessionHandoverSchema,
1392
1571
  ContextSetSchema,
@@ -1395,79 +1574,79 @@ var ClientMessageSchema = z21.discriminatedUnion("type", [
1395
1574
  ]);
1396
1575
 
1397
1576
  // ../protocol/src/relay.ts
1398
- import { z as z22 } from "zod";
1577
+ import { z as z23 } from "zod";
1399
1578
  var SEALED_MAX = 1048576;
1400
- var RelayPeerSchema = z22.union([z22.literal("pc"), z22.string().regex(/^d_[A-Za-z0-9_-]{16,40}$/)]);
1401
- var RelayClientMessageSchema = z22.object({
1402
- type: z22.literal("send"),
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"),
1403
1582
  to: RelayPeerSchema,
1404
- body: z22.string().max(SEALED_MAX)
1583
+ body: z23.string().max(SEALED_MAX)
1405
1584
  });
1406
- var RelayServerMessageSchema = z22.discriminatedUnion("type", [
1407
- z22.object({ type: z22.literal("welcome"), accountId: z22.string(), self: RelayPeerSchema, online: z22.array(RelayPeerSchema) }),
1408
- z22.object({ type: z22.literal("deliver"), from: RelayPeerSchema, body: z22.string() }),
1409
- z22.object({ type: z22.literal("presence"), peer: RelayPeerSchema, online: z22.boolean() }),
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() }),
1410
1589
  /**
1411
1590
  * A frame was refused; `to` names the target when it is known.
1412
1591
  * Contract: an error concerning a sealed body (`offline`, `too_large`, or a socket closed with 4008
1413
1592
  * `rate_limited`) means that body was not delivered, so the sequence on that channel is lost: the
1414
1593
  * sender must re-handshake with that peer before sending to it again.
1415
1594
  */
1416
- z22.object({
1417
- type: z22.literal("error"),
1418
- code: z22.enum(["bad_frame", "too_large", "bad_target", "offline", "rate_limited"]),
1595
+ z23.object({
1596
+ type: z23.literal("error"),
1597
+ code: z23.enum(["bad_frame", "too_large", "bad_target", "offline", "rate_limited"]),
1419
1598
  to: RelayPeerSchema.optional()
1420
1599
  })
1421
1600
  ]);
1422
1601
  var PAIR_LABEL_MAX = 40;
1423
- var KeyB64 = z22.string().regex(/^[A-Za-z0-9_-]{87}$/);
1424
- var Nonce = z22.string().regex(/^[A-Za-z0-9_-]{43}$/);
1425
- var Fingerprint = z22.string().regex(/^[A-Za-z0-9_-]{22}$/);
1426
- var SealedFrameSchema = z22.discriminatedUnion("k", [
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", [
1427
1606
  /** `e` is the ephemeral key, `f` the fingerprint of the sender's static key. */
1428
- z22.object({ k: z22.literal("hello"), e: KeyB64, f: Fingerprint }),
1429
- z22.object({ k: z22.literal("msg"), s: z22.string() }),
1430
- z22.object({ k: z22.literal("pair_commit"), c: Nonce, label: z22.string().trim().min(1).max(PAIR_LABEL_MAX) }),
1431
- z22.object({ k: z22.literal("pair_offer"), pc: KeyB64, n: Nonce }),
1432
- z22.object({ k: z22.literal("pair_reveal"), d: KeyB64, n: Nonce }),
1433
- z22.object({ k: z22.literal("pair_ok") }),
1434
- z22.object({ k: z22.literal("pair_no") }),
1435
- z22.object({ k: z22.literal("denied") }),
1436
- z22.object({ k: z22.literal("rekey") })
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") })
1437
1616
  ]);
1438
1617
 
1439
1618
  // ../protocol/src/relayAuth.ts
1440
- import { z as z23 } from "zod";
1441
- var DeviceStartResponseSchema = z23.object({
1442
- deviceCode: z23.string().min(1),
1443
- userCode: z23.string().min(1),
1444
- verificationUri: z23.string().min(1),
1445
- expiresIn: z23.number().int().positive(),
1446
- interval: z23.number().int().positive()
1447
- });
1448
- var DevicePollResponseSchema = z23.discriminatedUnion("status", [
1449
- z23.object({ status: z23.literal("pending") }),
1450
- z23.object({ status: z23.literal("slow_down"), interval: z23.number().int().positive() }),
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() }),
1451
1630
  /** `token` is the relay session token, shown this once only. */
1452
- z23.object({ status: z23.literal("ok"), token: z23.string().min(1), accountId: z23.string().min(1), login: z23.string().min(1) }),
1453
- z23.object({ status: z23.literal("expired") }),
1454
- z23.object({ status: z23.literal("denied") }),
1455
- z23.object({ status: z23.literal("not_allowed") })
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") })
1456
1635
  ]);
1457
- var DeviceRevokeResponseSchema = z23.object({ revoked: z23.number().int().min(0) });
1458
- var MeResponseSchema = z23.object({
1459
- accountId: z23.string().min(1),
1460
- login: z23.string().min(1),
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),
1461
1640
  peer: RelayPeerSchema,
1462
- kind: z23.enum(["pc", "device"])
1641
+ kind: z24.enum(["pc", "device"])
1463
1642
  });
1464
1643
 
1465
1644
  // ../protocol/src/phone.ts
1466
- import { z as z25 } from "zod";
1645
+ import { z as z26 } from "zod";
1467
1646
 
1468
1647
  // ../protocol/src/push.ts
1469
- import { z as z24 } from "zod";
1470
- var B64U = z24.string().regex(/^[A-Za-z0-9_-]*$/);
1648
+ import { z as z25 } from "zod";
1649
+ var B64U = z25.string().regex(/^[A-Za-z0-9_-]*$/);
1471
1650
  var PUSH_HOSTS = ["*.push.apple.com", "fcm.googleapis.com", "updates.push.services.mozilla.com", "*.notify.windows.com"];
1472
1651
  function pushEndpointAllowed(url) {
1473
1652
  let u;
@@ -1484,29 +1663,29 @@ function pushEndpointAllowed(url) {
1484
1663
  return host.length > suffix.length && host.endsWith(suffix);
1485
1664
  });
1486
1665
  }
1487
- var PushSendSchema = z24.object({
1488
- endpoint: z24.string().url().max(1024),
1666
+ var PushSendSchema = z25.object({
1667
+ endpoint: z25.string().url().max(1024),
1489
1668
  body: B64U.max(5462),
1490
- ttl: z24.number().int().min(0).max(86400),
1491
- urgency: z24.enum(["normal", "high"]),
1492
- topic: z24.string().regex(/^[A-Za-z0-9_-]{1,32}$/)
1493
- });
1494
- var PushSendResultSchema = z24.object({
1495
- result: z24.enum(["sent", "gone", "failed"]),
1496
- status: z24.number().int().optional()
1497
- });
1498
- var PushSubscriptionSchema = z24.object({
1499
- endpoint: z24.string().url().max(1024).refine(pushEndpointAllowed),
1500
- keys: z24.object({ p256dh: B64U.length(87), auth: B64U.length(22) })
1501
- });
1502
- var PushPayloadSchema = z24.object({
1503
- v: z24.literal(1),
1504
- kind: z24.enum(["request", "question", "finished", "chat", "decision"]),
1505
- title: z24.string().max(80),
1506
- body: z24.string().max(120),
1507
- url: z24.string().regex(/^\/#\/[A-Za-z0-9/%._~-]*$/).max(300),
1508
- badge: z24.number().int().min(0).max(999),
1509
- tag: z24.string().regex(/^[A-Za-z0-9_-]{1,32}$/)
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}$/)
1510
1689
  });
1511
1690
 
1512
1691
  // ../protocol/src/phone.ts
@@ -1516,35 +1695,35 @@ var THREAD_TEXT_MAX = 8192;
1516
1695
  var TOOL_TEXT_MAX = 2048;
1517
1696
  var CHECKLIST_TASKS_MAX = 50;
1518
1697
  var CHECKLIST_TEXT_MAX = 200;
1519
- var ChecklistStatusSchema = z25.enum(["pending", "in_progress", "completed"]);
1520
- var PhoneChecklistSchema = z25.object({
1521
- tasks: z25.array(z25.object({ text: z25.string().max(CHECKLIST_TEXT_MAX), status: ChecklistStatusSchema })).max(CHECKLIST_TASKS_MAX),
1522
- done: z25.number().int().nonnegative(),
1523
- total: z25.number().int().nonnegative(),
1524
- cut: z25.literal(true).optional()
1525
- });
1526
- var PhoneChecklistSummarySchema = z25.object({
1527
- done: z25.number().int().nonnegative(),
1528
- total: z25.number().int().nonnegative(),
1529
- current: z25.string().max(CHECKLIST_TEXT_MAX).optional(),
1530
- cut: z25.literal(true).optional()
1531
- });
1532
- var RiskSchema = z25.enum(["low", "high"]);
1533
- var RiskReasonSchema = z25.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"]);
1534
- var OperationIdSchema = z25.string().uuid();
1535
- var OperationStatusSchema = z25.enum(["received", "applied", "rejected", "failed"]);
1536
- var OperationReasonSchema = z25.enum([...RefusalCodeSchema.options, "untypable", "confirm_required", "conflict", "assertion_invalid", "assertion_expired", "scheduled", ...ModelRefusalSchema.options]);
1537
- var CapabilitiesSchema = z25.object({
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({
1538
1717
  /** A question can be answered in free text. */
1539
- freeTextAnswer: z25.boolean(),
1718
+ freeTextAnswer: z26.boolean(),
1540
1719
  /** The session's accept/deny can be typed; absent = true. */
1541
- decide: z25.boolean().optional(),
1720
+ decide: z26.boolean().optional(),
1542
1721
  /** OMP's dialog questions can be answered from the phone; absent = false. */
1543
- questions: z25.boolean().optional()
1722
+ questions: z26.boolean().optional()
1544
1723
  });
1545
- var CapabilitiesByToolSchema = z25.object({ claude: CapabilitiesSchema, codex: CapabilitiesSchema, cursor: CapabilitiesSchema, omp: CapabilitiesSchema });
1546
- var PhonePendingSchema = PendingSchema.extend({ key: z25.string().max(64), risk: RiskSchema, riskReason: RiskReasonSchema, cut: z25.literal(true).optional() });
1547
- var SwitchableSessionSchema = SessionSchema.extend({ canSwitch: z25.literal(true).optional() });
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() });
1548
1727
  var PhoneSessionSchema = SwitchableSessionSchema.pick({
1549
1728
  id: true,
1550
1729
  name: true,
@@ -1572,260 +1751,260 @@ var PhoneSessionSchema = SwitchableSessionSchema.pick({
1572
1751
  exitedAt: true
1573
1752
  }).extend({
1574
1753
  pending: PhonePendingSchema.optional(),
1575
- unread: z25.boolean(),
1576
- handover: z25.object({ state: HandoverStateSchema, toName: z25.string().max(80).optional() }).strict().optional(),
1754
+ unread: z26.boolean(),
1755
+ handover: z26.object({ state: HandoverStateSchema, toName: z26.string().max(80).optional() }).strict().optional(),
1577
1756
  /** Absent: the agent has no checklist. */
1578
1757
  checklist: PhoneChecklistSummarySchema.optional(),
1579
1758
  /** Started without Ledge (`hook_only`): the phone can neither close nor resume it. */
1580
- readOnly: z25.literal(true).optional()
1759
+ readOnly: z26.literal(true).optional()
1581
1760
  });
1582
- var B64U2 = z25.string().regex(/^[A-Za-z0-9_-]*$/);
1583
- var CredentialSchema = z25.object({
1761
+ var B64U2 = z26.string().regex(/^[A-Za-z0-9_-]*$/);
1762
+ var CredentialSchema = z26.object({
1584
1763
  id: B64U2.max(1366),
1585
1764
  publicKey: B64U2.max(2048),
1586
- alg: z25.union([z25.literal(-7), z25.literal(-257)]),
1765
+ alg: z26.union([z26.literal(-7), z26.literal(-257)]),
1587
1766
  clientDataJSON: B64U2.max(4096),
1588
1767
  authenticatorData: B64U2.max(4096),
1589
- transports: z25.array(z25.string().max(20)).max(8).optional()
1768
+ transports: z26.array(z26.string().max(20)).max(8).optional()
1590
1769
  });
1591
- var AssertionSchema = z25.object({
1770
+ var AssertionSchema = z26.object({
1592
1771
  id: B64U2.max(1366),
1593
1772
  clientDataJSON: B64U2.max(4096),
1594
1773
  authenticatorData: B64U2.max(4096),
1595
1774
  signature: B64U2.max(1024)
1596
1775
  });
1597
- var ConfirmPurposeSchema = z25.enum(["register", "decide", "launch", "close", "act", "pc"]);
1776
+ var ConfirmPurposeSchema = z26.enum(["register", "decide", "launch", "close", "act", "pc"]);
1598
1777
  var PhoneChatStepSchema = ChatStepSchema.pick({ kind: true, id: true, name: true }).strict();
1599
- var PhoneChatProposalSchema = z25.object({
1600
- project: z25.string().max(80),
1778
+ var PhoneChatProposalSchema = z26.object({
1779
+ project: z26.string().max(80),
1601
1780
  tool: ToolSchema,
1602
- prompt: z25.string().max(TOOL_TEXT_MAX).optional(),
1603
- launchedId: z25.string().optional(),
1604
- failed: z25.literal(true).optional()
1781
+ prompt: z26.string().max(TOOL_TEXT_MAX).optional(),
1782
+ launchedId: z26.string().optional(),
1783
+ failed: z26.literal(true).optional()
1605
1784
  }).strict();
1606
- var PhoneChatRelaySchema = z25.object({
1607
- id: z25.string().min(1),
1608
- name: z25.string(),
1785
+ var PhoneChatRelaySchema = z26.object({
1786
+ id: z26.string().min(1),
1787
+ name: z26.string(),
1609
1788
  tool: ToolSchema,
1610
- text: z25.string().max(TOOL_TEXT_MAX),
1611
- status: z25.enum(["queued", "sent"]).optional(),
1612
- sentAt: z25.string().datetime().optional(),
1613
- failed: z25.literal(true).optional(),
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(),
1614
1793
  /** With `failed`: why, as the PC's code (never its text). */
1615
- code: z25.string().max(40).optional()
1794
+ code: z26.string().max(40).optional()
1616
1795
  }).strict();
1617
- var CloseHowSchema = z25.enum(["exit", "killed"]);
1618
- var PhoneChatCloseSchema = z25.object({
1619
- id: z25.string().min(1),
1620
- name: z25.string(),
1796
+ var CloseHowSchema = z26.enum(["exit", "killed"]);
1797
+ var PhoneChatCloseSchema = z26.object({
1798
+ id: z26.string().min(1),
1799
+ name: z26.string(),
1621
1800
  tool: ToolSchema,
1622
1801
  how: CloseHowSchema.optional(),
1623
- closedAt: z25.string().datetime().optional(),
1624
- failed: z25.literal(true).optional()
1802
+ closedAt: z26.string().datetime().optional(),
1803
+ failed: z26.literal(true).optional()
1625
1804
  }).strict();
1626
- var PhoneChatTaskSchema = z25.object({
1627
- to: z25.string().max(80),
1628
- toName: z25.string().max(80).optional(),
1629
- title: z25.string().max(200),
1630
- text: z25.string().max(TOOL_TEXT_MAX).optional(),
1631
- taskId: z25.string().max(40).optional(),
1632
- ownerName: z25.string().max(80).optional(),
1633
- state: z25.enum(["open", "taken", "done", "refused", "dropped"]).optional(),
1634
- failed: z25.literal(true).optional()
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()
1635
1814
  }).strict();
1636
- var PhoneChatActionSchema = z25.object({
1637
- action: z25.string().min(1).max(40),
1638
- summary: z25.string().max(300),
1815
+ var PhoneChatActionSchema = z26.object({
1816
+ action: z26.string().min(1).max(40),
1817
+ summary: z26.string().max(300),
1639
1818
  vars: ActionVarsSchema.optional(),
1640
- detail: z25.string().max(TOOL_TEXT_MAX).optional(),
1641
- detailCut: z25.literal(true).optional(),
1819
+ detail: z26.string().max(TOOL_TEXT_MAX).optional(),
1820
+ detailCut: z26.literal(true).optional(),
1642
1821
  risk: ActionRiskSchema,
1643
- session: z25.string().max(100).optional(),
1822
+ session: z26.string().max(100).optional(),
1644
1823
  state: ChatActionStateSchema.optional(),
1645
- doneAt: z25.string().datetime().optional(),
1646
- code: z25.string().max(40).optional()
1824
+ doneAt: z26.string().datetime().optional(),
1825
+ code: z26.string().max(40).optional()
1647
1826
  }).strict();
1648
- var PhoneTaskSchema = z25.object({
1649
- id: z25.string().max(40),
1650
- title: z25.string().max(200),
1651
- owner: z25.string().max(100),
1652
- ownerName: z25.string().max(80),
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),
1653
1832
  /** 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). */
1654
- giver: z25.string().max(100).optional(),
1655
- giverName: z25.string().max(80).optional(),
1656
- text: z25.string().max(TOOL_TEXT_MAX).optional(),
1657
- state: z25.enum(["open", "taken", "done", "refused", "dropped"]),
1658
- result: z25.string().max(TOOL_TEXT_MAX).optional(),
1659
- cut: z25.literal(true).optional(),
1660
- at: z25.string(),
1661
- updatedAt: z25.string(),
1662
- seen: z25.literal(true).optional()
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()
1663
1842
  }).strict();
1664
- var ChatErrorCodeSchema = z25.enum(["busy", "timeout", "cancelled", "failed"]);
1665
- var PhoneChatTurnSchema = z25.object({
1843
+ var ChatErrorCodeSchema = z26.enum(["busy", "timeout", "cancelled", "failed"]);
1844
+ var PhoneChatTurnSchema = z26.object({
1666
1845
  qid: OperationIdSchema,
1667
- question: z25.string().max(MESSAGE_MAX),
1668
- askedAt: z25.string().datetime(),
1669
- steps: z25.array(PhoneChatStepSchema).max(50),
1670
- answer: z25.string().max(THREAD_TEXT_MAX).optional(),
1671
- answeredAt: z25.string().datetime().optional(),
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(),
1672
1851
  error: ChatErrorCodeSchema.optional(),
1673
- proposals: z25.array(PhoneChatProposalSchema).max(MAX_PROPOSALS).optional(),
1852
+ proposals: z26.array(PhoneChatProposalSchema).max(MAX_PROPOSALS).optional(),
1674
1853
  relay: PhoneChatRelaySchema.optional(),
1675
- closes: z25.array(PhoneChatCloseSchema).min(1).max(MAX_PROPOSALS).optional(),
1676
- cut: z25.literal(true).optional(),
1677
- tasks: z25.array(PhoneChatTaskSchema).min(1).max(MAX_PROPOSALS).optional(),
1678
- actions: z25.array(PhoneChatActionSchema).min(1).max(MAX_PROPOSALS).optional(),
1679
- ignoredAt: z25.string().datetime().optional(),
1680
- attachments: z25.array(AttachmentRefSchema).max(ATTACHMENTS_MAX).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()
1681
1860
  }).strict();
1682
- var sessionId = z25.string().min(1).max(100);
1683
- var PhoneExpectSchema = PendingSchema.pick({ kind: true, text: true }).extend({ key: z25.string().min(1).max(64) });
1684
- var CardRowsSchema = z25.array(z25.number().int().min(0).max(MAX_PROPOSALS - 1)).min(1).max(MAX_PROPOSALS).refine((r) => new Set(r).size === r.length, "a row twice");
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");
1685
1864
  var pcOp = { op: OperationIdSchema, assertion: AssertionSchema.optional() };
1686
- var PcActionSchema = z25.enum(["update", "restart"]);
1687
- var PhoneClientMessageSchema = z25.discriminatedUnion("type", [
1688
- z25.object({ type: z25.literal("snapshot.request") }),
1689
- z25.object({ type: z25.literal("session.thread"), id: sessionId }),
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 }),
1690
1869
  /** The session's request with its whole body (up to `PENDING_BODY_MAX`). */
1691
- z25.object({ type: z25.literal("session.pending"), id: sessionId }),
1870
+ z26.object({ type: z26.literal("session.pending"), id: sessionId }),
1692
1871
  /** The session whose terminal the phone shows; null when it shows none. */
1693
- z25.object({ type: z25.literal("session.watch"), id: sessionId.nullable() }),
1694
- z25.object({ type: z25.literal("session.read"), id: sessionId, at: z25.string().datetime() }),
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() }),
1695
1874
  /**
1696
1875
  * Asks for a challenge. One object for every purpose: the gateway refuses a `decide` without `id` and `expect`. A `close`
1697
1876
  * or `act` names a turn of the chat (`qid`) or a session (`id`, for `session.close` and `session.resume`).
1698
1877
  */
1699
- z25.object({
1700
- type: z25.literal("confirm.prepare"),
1878
+ z26.object({
1879
+ type: z26.literal("confirm.prepare"),
1701
1880
  purpose: ConfirmPurposeSchema,
1702
1881
  id: sessionId.optional(),
1703
1882
  expect: PhoneExpectSchema.optional(),
1704
1883
  qid: OperationIdSchema.optional(),
1705
1884
  /** A `pc` challenge: what it is for, and for an update the version it covers. */
1706
1885
  action: PcActionSchema.optional(),
1707
- version: z25.string().regex(SEMVER).optional()
1886
+ version: z26.string().regex(SEMVER).optional()
1708
1887
  }),
1709
- z25.object({ type: z25.literal("credential.register"), op: OperationIdSchema, credential: CredentialSchema }),
1710
- z25.object({
1711
- type: z25.literal("session.decide"),
1888
+ z26.object({ type: z26.literal("credential.register"), op: OperationIdSchema, credential: CredentialSchema }),
1889
+ z26.object({
1890
+ type: z26.literal("session.decide"),
1712
1891
  op: OperationIdSchema,
1713
1892
  id: sessionId,
1714
1893
  decision: DecisionSchema,
1715
- note: z25.string().trim().min(1).max(NOTE_MAX).optional(),
1894
+ note: z26.string().trim().min(1).max(NOTE_MAX).optional(),
1716
1895
  /** The request the phone showed: refused unless it is still the pending one. */
1717
1896
  expect: PhoneExpectSchema,
1718
1897
  /** The device check over the challenge of `confirm.prepare`; required by the daemon for a high-risk accept. */
1719
1898
  assertion: AssertionSchema.optional()
1720
1899
  }),
1721
- z25.object({
1722
- type: z25.literal("session.reply"),
1900
+ z26.object({
1901
+ type: z26.literal("session.reply"),
1723
1902
  op: OperationIdSchema,
1724
1903
  id: sessionId,
1725
- text: z25.string().max(MESSAGE_MAX),
1726
- attachments: z25.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(),
1904
+ text: z26.string().max(MESSAGE_MAX),
1905
+ attachments: z26.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional(),
1727
1906
  /** The request the reply answers, or null when the phone showed none: refused if the session's request is no longer that one. */
1728
1907
  expect: PhoneExpectSchema.nullable(),
1729
1908
  assertion: AssertionSchema.optional()
1730
1909
  }),
1731
1910
  /** OMP's `ask`: the answers to every question of the dialog `requestId`, in order; `cancel` declines it. Bounds as the local `session.answer`. */
1732
- z25.object({
1733
- type: z25.literal("session.answer"),
1911
+ z26.object({
1912
+ type: z26.literal("session.answer"),
1734
1913
  op: OperationIdSchema,
1735
1914
  id: sessionId,
1736
- requestId: z25.string().min(1).max(200),
1737
- answers: z25.array(z25.object({ id: z25.string().max(200), selected: z25.array(z25.string().max(2e3)).max(100), text: z25.string().max(2e4).optional() })).max(50),
1738
- cancel: z25.literal(true).optional(),
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(),
1739
1918
  expect: PhoneExpectSchema
1740
1919
  }),
1741
- z25.object({ type: z25.literal("session.interrupt"), op: OperationIdSchema, id: sessionId }),
1920
+ z26.object({ type: z26.literal("session.interrupt"), op: OperationIdSchema, id: sessionId }),
1742
1921
  /** Ends a live session as `/exit` would, killed as a last resort; answered with its `how`. Passkey, purpose `close`, over the session. */
1743
- z25.object({ type: z25.literal("session.close"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
1922
+ z26.object({ type: z26.literal("session.close"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
1744
1923
  /** Starts an ended session again on its conversation. Passkey, purpose `act`, over the session. */
1745
- z25.object({ type: z25.literal("session.resume"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
1924
+ z26.object({ type: z26.literal("session.resume"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
1746
1925
  /** 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`. */
1747
- z25.object({ type: z25.literal("session.model"), op: OperationIdSchema, id: sessionId, model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
1926
+ z26.object({ type: z26.literal("session.model"), op: OperationIdSchema, id: sessionId, model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
1748
1927
  /** The models an agent offers on the PC. */
1749
- z25.object({ type: z25.literal("models.list"), tool: ToolSchema }),
1928
+ z26.object({ type: z26.literal("models.list"), tool: ToolSchema }),
1750
1929
  /** The phone drops its passkey from the daemon. */
1751
- z25.object({ type: z25.literal("device.forget"), op: OperationIdSchema }),
1930
+ z26.object({ type: z26.literal("device.forget"), op: OperationIdSchema }),
1752
1931
  /** The phone's push subscription, with the VAPID key it was made with (so a key change is seen). */
1753
- z25.object({ type: z25.literal("push.subscribe"), op: OperationIdSchema, subscription: PushSubscriptionSchema, key: B64U2.length(87) }),
1754
- z25.object({ type: z25.literal("push.unsubscribe"), op: OperationIdSchema }),
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 }),
1755
1934
  /** The phone's own chat with Ledge. */
1756
- z25.object({ type: z25.literal("chat.ask"), qid: OperationIdSchema, text: z25.string().trim().max(MESSAGE_MAX), attachments: z25.array(AttachmentIdSchema).max(ATTACHMENTS_MAX).optional() }),
1757
- z25.object({ type: z25.literal("chat.cancel"), qid: OperationIdSchema }),
1758
- z25.object({ type: z25.literal("chat.reset") }),
1759
- z25.object({ type: z25.literal("chat.history") }),
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") }),
1760
1939
  /** An image to store, sent alone before the message that names it; no `id`, and at most `ATTACHMENT_MAX` bytes. */
1761
- AttachmentPutSchema.pick({ type: true, requestId: true }).extend({ image: ImageUploadSchema.extend({ data: z25.string().min(1).max(b64Max(ATTACHMENT_MAX)) }) }),
1940
+ AttachmentPutSchema.pick({ type: true, requestId: true }).extend({ image: ImageUploadSchema.extend({ data: z26.string().min(1).max(b64Max(ATTACHMENT_MAX)) }) }),
1762
1941
  AttachmentGetSchema.pick({ type: true, requestId: true, attachment: true, preview: true }),
1763
- z25.object({ type: z25.literal("chat.relay"), op: OperationIdSchema, qid: OperationIdSchema }),
1942
+ z26.object({ type: z26.literal("chat.relay"), op: OperationIdSchema, qid: OperationIdSchema }),
1764
1943
  /** Takes the card's queued instruction back out of the queue, as the local `session.relay.cancel`. */
1765
- z25.object({ type: z25.literal("chat.relay.cancel"), op: OperationIdSchema, qid: OperationIdSchema }),
1766
- z25.object({ type: z25.literal("chat.launch"), op: OperationIdSchema, qid: OperationIdSchema, rows: CardRowsSchema.optional(), assertion: AssertionSchema.optional() }),
1767
- z25.object({ type: z25.literal("chat.close"), op: OperationIdSchema, qid: OperationIdSchema, rows: CardRowsSchema.optional(), assertion: AssertionSchema.optional() }),
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() }),
1768
1947
  /** A row of the turn's task card: given by Ledge. */
1769
- z25.object({ type: z25.literal("chat.task"), op: OperationIdSchema, qid: OperationIdSchema, row: z25.number().int().min(0).max(MAX_PROPOSALS - 1) }),
1948
+ z26.object({ type: z26.literal("chat.task"), op: OperationIdSchema, qid: OperationIdSchema, row: z26.number().int().min(0).max(MAX_PROPOSALS - 1) }),
1770
1949
  /** Rows of the turn's generic card (action registry spec §5): `confirmed` as the local `chat.act`; a row whose action asks
1771
1950
  * for a device check (`phone`) needs one assertion, purpose `act`, over the turn. */
1772
- z25.object({
1773
- type: z25.literal("chat.act"),
1951
+ z26.object({
1952
+ type: z26.literal("chat.act"),
1774
1953
  op: OperationIdSchema,
1775
1954
  qid: OperationIdSchema,
1776
1955
  rows: CardRowsSchema.optional(),
1777
- confirmed: z25.literal(true).optional(),
1956
+ confirmed: z26.literal(true).optional(),
1778
1957
  assertion: AssertionSchema.optional(),
1779
1958
  /** « Refuser », as the local `chat.act`: no passkey, no confirmation. */
1780
- deny: z25.literal(true).optional()
1959
+ deny: z26.literal(true).optional()
1781
1960
  }),
1782
1961
  /** « Ignorer » the turn's cards, or `undo` (« Revoir »), as the local `chat.ignore`. */
1783
- z25.object({ type: z25.literal("chat.ignore"), op: OperationIdSchema, qid: OperationIdSchema, undo: z25.literal(true).optional() }),
1962
+ z26.object({ type: z26.literal("chat.ignore"), op: OperationIdSchema, qid: OperationIdSchema, undo: z26.literal(true).optional() }),
1784
1963
  /** Puts a closed task Ledge gave away from « À traiter ». */
1785
- z25.object({ type: z25.literal("task.seen"), op: OperationIdSchema, task: z25.string().min(1).max(40) }),
1964
+ z26.object({ type: z26.literal("task.seen"), op: OperationIdSchema, task: z26.string().min(1).max(40) }),
1786
1965
  /** Whether the phone's app is in front: a device that is visible gets no push. */
1787
- z25.object({ type: z25.literal("presence"), visible: z25.boolean() }),
1966
+ z26.object({ type: z26.literal("presence"), visible: z26.boolean() }),
1788
1967
  /** Installs `version` on the PC, then restarts its daemon; the phone asks for its own build's version. Passkey, purpose `pc`. */
1789
- z25.object({ type: z25.literal("daemon.update"), ...pcOp, version: z25.string().regex(SEMVER) }).strict(),
1968
+ z26.object({ type: z26.literal("daemon.update"), ...pcOp, version: z26.string().regex(SEMVER) }).strict(),
1790
1969
  /** Restarts the PC's daemon without installing anything. Passkey, purpose `pc`. */
1791
- z25.object({ type: z25.literal("daemon.restart"), ...pcOp }).strict()
1970
+ z26.object({ type: z26.literal("daemon.restart"), ...pcOp }).strict()
1792
1971
  ]);
1793
- var PhoneModelChoiceSchema = z25.object({
1972
+ var PhoneModelChoiceSchema = z26.object({
1794
1973
  id: ModelChoiceSchema.shape.id.max(120),
1795
- label: z25.string().max(80),
1796
- description: z25.string().max(200).optional(),
1797
- efforts: z25.array(EffortSchema).max(8).optional(),
1974
+ label: z26.string().max(80),
1975
+ description: z26.string().max(200).optional(),
1976
+ efforts: z26.array(EffortSchema).max(8).optional(),
1798
1977
  defaultEffort: EffortSchema.optional(),
1799
- isDefault: z25.boolean().optional()
1978
+ isDefault: z26.boolean().optional()
1800
1979
  }).strict();
1801
- var PhoneServerMessageSchema = z25.discriminatedUnion("type", [
1802
- z25.object({ type: z25.literal("snapshot"), protocol: z25.literal(PHONE_PROTOCOL), sessions: z25.array(PhoneSessionSchema), capabilities: CapabilitiesByToolSchema, daemon: z25.object({
1803
- version: z25.string(),
1804
- name: z25.string().max(40),
1805
- boot: z25.string().uuid().optional(),
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(),
1806
1985
  /** The daemon takes `session.model`. */
1807
- models: z25.literal(true).optional(),
1986
+ models: z26.literal(true).optional(),
1808
1987
  /** The daemon sends `session.checklist` and a session's `checklist` summary. */
1809
- checklist: z25.literal(true).optional(),
1988
+ checklist: z26.literal(true).optional(),
1810
1989
  /** `update`: the daemon can install a version and restart (npm, systemd); `restart`: it can restart (systemd). */
1811
- update: z25.literal(true).optional(),
1812
- restart: z25.literal(true).optional(),
1990
+ update: z26.literal(true).optional(),
1991
+ restart: z26.literal(true).optional(),
1813
1992
  /** The daemon takes `session.close` and `session.resume`. */
1814
- sessionClose: z25.literal(true).optional()
1815
- }), device: z25.object({ confirm: z25.boolean(), push: z25.enum(["on", "off", "stale", "unavailable"]).optional(), chat: z25.literal(true).optional(), contextNear: ContextPrefsSchema.shape.near.optional() }).optional() }),
1816
- z25.object({ type: z25.literal("confirm.challenge"), purpose: ConfirmPurposeSchema, challenge: B64U2.max(64), rpId: z25.string().max(253), credentialId: B64U2.max(1366).optional(), expiresInMs: z25.number().int().positive() }),
1817
- z25.object({ type: z25.literal("session.updated"), session: PhoneSessionSchema }),
1818
- z25.object({ type: z25.literal("session.removed"), id: z25.string() }),
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() }),
1819
1998
  /** A session's checklist, sent to the phone that watches it; `null`: it has none (any more). */
1820
- z25.object({ type: z25.literal("session.checklist"), id: z25.string(), checklist: PhoneChecklistSchema.nullable() }),
1999
+ z26.object({ type: z26.literal("session.checklist"), id: z26.string(), checklist: PhoneChecklistSchema.nullable() }),
1821
2000
  /** `pending.cut` is set when even this body was shortened. */
1822
- z25.object({ type: z25.literal("session.pending"), id: z25.string(), pending: PhonePendingSchema }),
1823
- z25.object({ type: z25.literal("session.preview"), id: z25.string(), lines: z25.array(z25.string()) }),
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()) }),
1824
2003
  /** `cut`: the ids of the items shortened; `more`: older items were left out. */
1825
- z25.object({ type: z25.literal("session.thread"), id: z25.string(), items: z25.array(ThreadItemSchema), cut: z25.array(z25.string()), more: z25.boolean() }),
1826
- z25.object({ type: z25.literal("session.thread.item"), id: z25.string(), item: ThreadItemSchema, cut: z25.literal(true).optional() }),
1827
- z25.object({
1828
- type: z25.literal("operation.result"),
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"),
1829
2008
  op: OperationIdSchema,
1830
2009
  status: OperationStatusSchema,
1831
2010
  reason: OperationReasonSchema.optional(),
@@ -1833,27 +2012,27 @@ var PhoneServerMessageSchema = z25.discriminatedUnion("type", [
1833
2012
  how: CloseHowSchema.optional()
1834
2013
  }),
1835
2014
  /** The models an agent offers; `error`: it could not be asked, `models` is then what Ledge knows without it. */
1836
- z25.object({ type: z25.literal("models.listing"), tool: ToolSchema, models: z25.array(PhoneModelChoiceSchema).max(40), error: z25.literal(true).optional() }),
2015
+ z26.object({ type: z26.literal("models.listing"), tool: ToolSchema, models: z26.array(PhoneModelChoiceSchema).max(40), error: z26.literal(true).optional() }),
1837
2016
  /** A model change that was accepted and then failed (the agent could not restart). */
1838
- z25.object({ type: z25.literal("session.model.failed"), id: z25.string(), reason: ModelRefusalSchema }),
1839
- z25.object({ type: z25.literal("chat.history"), turns: z25.array(PhoneChatTurnSchema).max(50) }),
1840
- z25.object({ type: z25.literal("chat.step"), qid: OperationIdSchema, step: PhoneChatStepSchema }),
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 }),
1841
2020
  /** The whole text so far, not an increment. */
1842
- z25.object({ type: z25.literal("chat.delta"), qid: OperationIdSchema, text: z25.string().max(THREAD_TEXT_MAX) }),
1843
- z25.object({ type: z25.literal("chat.done"), qid: OperationIdSchema, turn: PhoneChatTurnSchema }),
1844
- z25.object({ type: z25.literal("chat.error"), qid: OperationIdSchema, code: ChatErrorCodeSchema }),
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 }),
1845
2024
  /** The daemon updating or restarting itself, whoever asked: npm runs, then the service restarts (the link drops right after). */
1846
- z25.object({ type: z25.literal("daemon.progress"), version: z25.string().max(40), step: z25.enum(["installing", "restarting"]) }),
2025
+ z26.object({ type: z26.literal("daemon.progress"), version: z26.string().max(40), step: z26.enum(["installing", "restarting"]) }),
1847
2026
  /** Nothing was changed. Never npm's output nor a command: both hold the PC's paths. */
1848
- z25.object({ type: z25.literal("daemon.failed"), version: z25.string().max(40), reason: UpdateFailureSchema }),
2027
+ z26.object({ type: z26.literal("daemon.failed"), version: z26.string().max(40), reason: UpdateFailureSchema }),
1849
2028
  /** The tasks Ledge gave, open or closed lately, after each snapshot; then each change. */
1850
- z25.object({ type: z25.literal("tasks"), tasks: z25.array(PhoneTaskSchema).max(200) }),
1851
- z25.object({ type: z25.literal("task.updated"), task: PhoneTaskSchema }),
2029
+ z26.object({ type: z26.literal("tasks"), tasks: z26.array(PhoneTaskSchema).max(200) }),
2030
+ z26.object({ type: z26.literal("task.updated"), task: PhoneTaskSchema }),
1852
2031
  AttachmentStoredSchema,
1853
2032
  AttachmentDataSchema,
1854
2033
  AttachmentErrorSchema,
1855
2034
  /** Never carries free text. */
1856
- z25.object({ type: z25.literal("error"), code: z25.enum(["invalid", "unknown_session", "too_large"]), request: z25.string().max(40).optional() })
2035
+ z26.object({ type: z26.literal("error"), code: z26.enum(["invalid", "unknown_session", "too_large"]), request: z26.string().max(40).optional() })
1857
2036
  ]);
1858
2037
 
1859
2038
  // src/imageInfo.ts