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