@paradow/ledge 0.27.0 → 0.29.0-snapshot.41297455946.1
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/README.md +8 -0
- package/dist/cli/{action-7SJJTIEA.js → action-MCR4BCSE.js} +5 -5
- package/dist/cli/ask-L3PSQZ2K.js +17 -0
- package/dist/cli/{attach-V7UPHVB2.js → attach-R7FT7LFH.js} +9 -14
- package/dist/cli/brain-BJTBN2ZK.js +20 -0
- package/dist/cli/{bridge-JK3PMG7T.js → bridge-YBHXFEFX.js} +2 -2
- package/dist/cli/{chunk-37G5F75H.js → chunk-2X56ZRK7.js} +1229 -1156
- package/dist/cli/{chunk-7OGFH6KJ.js → chunk-6EW2FD2U.js} +3 -5
- package/dist/cli/chunk-DJMFCYF4.js +60 -0
- package/dist/cli/chunk-DLKJOK3B.js +6 -0
- package/dist/cli/{chunk-7GIUG73R.js → chunk-FWLT3SAN.js} +1 -1
- package/dist/cli/{chunk-6IYPRUQG.js → chunk-G3ST5WKR.js} +1 -1
- package/dist/cli/{chunk-7JRQCKBP.js → chunk-GY35ZR5I.js} +102 -72
- package/dist/cli/{chunk-NLL2EQJ2.js → chunk-KBSXP63H.js} +22 -7
- package/dist/cli/chunk-LOXLGCGN.js +57 -0
- package/dist/cli/{chunk-ADAGKOFO.js → chunk-O4MUYFPH.js} +6 -7
- package/dist/cli/{chunk-2N7PSP7C.js → chunk-OR2NHT5O.js} +4 -4
- package/dist/cli/chunk-S6BZV7AY.js +57 -0
- package/dist/cli/{chunk-IGAGJVRZ.js → chunk-TCQ5PYIF.js} +3 -3
- package/dist/cli/{chunk-ISNHG5SJ.js → chunk-UMQGRTA4.js} +17 -39
- package/dist/cli/{chunk-RA3OIXEQ.js → chunk-VQR5ME75.js} +4 -3
- package/dist/cli/{chunk-HOOHS3MX.js → chunk-W724IVDC.js} +1 -1
- package/dist/cli/{chunk-K7UEKSB2.js → chunk-WYRQZA4G.js} +2 -2
- package/dist/cli/chunk-XTDE2URL.js +365 -0
- package/dist/cli/daemon-ICC6LBCO.js +16562 -0
- package/dist/cli/{decide-HFI2WQXI.js → decide-JSY46QZC.js} +14 -16
- package/dist/cli/{handover-GKORMXZ2.js → handover-5RUSRVAD.js} +5 -5
- package/dist/cli/{hook-TJJEFV54.js → hook-QQP3ENGA.js} +87 -81
- package/dist/cli/index.js +40 -28
- package/dist/cli/launch-RTBGUJSC.js +28 -0
- package/dist/cli/{send-RI7JOO5K.js → send-BIIH6SQW.js} +5 -5
- package/dist/cli/{setup-K42IVMHS.js → setup-OLVRJLJE.js} +4 -4
- package/dist/cli/{status-RQRS26S2.js → status-Z3I33KZJ.js} +3 -3
- package/dist/cli/{tui-UWR7SDYF.js → tui-AIXCETOB.js} +6036 -3629
- package/dist/cli/{uninstall-4IMMR55T.js → uninstall-X65CWHIJ.js} +4 -4
- package/dist/cli/{version-YYNMMWKJ.js → version-QMHFVP3N.js} +1 -1
- package/dist/cli/who-C2VMEM35.js +12 -0
- package/package.json +21 -6
- package/dist/cli/chunk-CVHX7GUB.js +0 -9226
- package/dist/cli/chunk-HMTOPOJG.js +0 -6
- package/dist/cli/chunk-TOSPL5H2.js +0 -118
- package/dist/cli/chunk-UPKJO3BZ.js +0 -159
- package/dist/cli/chunk-YLN3VOGV.js +0 -198
- package/dist/cli/daemon-YUPB5NUG.js +0 -2322
- package/dist/cli/launch-QKQZZSIM.js +0 -35
- package/dist/cli/task-U2XHBUKW.js +0 -19
- package/dist/cli/team-NFC4XEIA.js +0 -205
- package/dist/cli/who-WW6IL4KD.js +0 -12
|
@@ -1,42 +1,208 @@
|
|
|
1
1
|
import {
|
|
2
2
|
paths
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-W724IVDC.js";
|
|
4
4
|
|
|
5
|
-
//
|
|
5
|
+
// src/auth.ts
|
|
6
|
+
import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
7
|
+
import { chmod, link, mkdir, readFile, unlink, writeFile } from "fs/promises";
|
|
8
|
+
import { readFileSync } from "fs";
|
|
9
|
+
import { dirname } from "path";
|
|
10
|
+
var TOKEN_RE = /^[0-9a-f]{64}$/;
|
|
11
|
+
var DAEMON_PROTOCOL_PREFIX = "ledge.";
|
|
12
|
+
function isDaemonToken(value) {
|
|
13
|
+
return TOKEN_RE.test(value);
|
|
14
|
+
}
|
|
15
|
+
function tokenEquals(presented, expected) {
|
|
16
|
+
const a = createHash("sha256").update(presented.slice(0, 256), "utf8").digest();
|
|
17
|
+
const b = createHash("sha256").update(expected, "utf8").digest();
|
|
18
|
+
return timingSafeEqual(a, b);
|
|
19
|
+
}
|
|
20
|
+
function hostAllowed(hostHeader) {
|
|
21
|
+
const raw = Array.isArray(hostHeader) ? hostHeader[0] : hostHeader;
|
|
22
|
+
if (!raw || raw.length > 255) return false;
|
|
23
|
+
const host = raw.trim().toLowerCase();
|
|
24
|
+
if (!host || host.includes(" ") || host.endsWith(".")) return false;
|
|
25
|
+
let name;
|
|
26
|
+
if (host.startsWith("[")) {
|
|
27
|
+
const end = host.indexOf("]");
|
|
28
|
+
if (end < 0) return false;
|
|
29
|
+
name = host.slice(1, end);
|
|
30
|
+
const rest = host.slice(end + 1);
|
|
31
|
+
if (rest !== "" && !/^:\d{1,5}$/.test(rest)) return false;
|
|
32
|
+
} else {
|
|
33
|
+
const colon = host.lastIndexOf(":");
|
|
34
|
+
if (colon >= 0) {
|
|
35
|
+
if (!/^\d{1,5}$/.test(host.slice(colon + 1))) return false;
|
|
36
|
+
name = host.slice(0, colon);
|
|
37
|
+
} else name = host;
|
|
38
|
+
}
|
|
39
|
+
return name === "localhost" || name === "127.0.0.1" || name === "::1";
|
|
40
|
+
}
|
|
41
|
+
function headerValue(value, max) {
|
|
42
|
+
const raw = Array.isArray(value) ? value.join(",") : value;
|
|
43
|
+
return !raw || raw.length > max ? "" : raw;
|
|
44
|
+
}
|
|
45
|
+
function bearerToken(authorization) {
|
|
46
|
+
if (!authorization || authorization.length > 512) return "";
|
|
47
|
+
return /^Bearer[ \t]+(\S+)$/i.exec(authorization)?.[1] ?? "";
|
|
48
|
+
}
|
|
49
|
+
function protocolToken(header) {
|
|
50
|
+
const raw = headerValue(header, 512);
|
|
51
|
+
if (!raw) return "";
|
|
52
|
+
for (const part of raw.split(",").slice(0, 8)) {
|
|
53
|
+
const protocol = part.trim();
|
|
54
|
+
if (protocol.startsWith(DAEMON_PROTOCOL_PREFIX)) return protocol.slice(DAEMON_PROTOCOL_PREFIX.length);
|
|
55
|
+
}
|
|
56
|
+
return "";
|
|
57
|
+
}
|
|
58
|
+
function requestAuthorized(headers, expected) {
|
|
59
|
+
const bearerOk = tokenEquals(bearerToken(typeof headers.authorization === "string" ? headers.authorization : void 0), expected);
|
|
60
|
+
const presented = protocolToken(headers["sec-websocket-protocol"]);
|
|
61
|
+
return bearerOk || presented !== "" && tokenEquals(presented, expected);
|
|
62
|
+
}
|
|
63
|
+
function selectDaemonProtocol(protocols, expected) {
|
|
64
|
+
for (const protocol of protocols) {
|
|
65
|
+
if (protocol.startsWith(DAEMON_PROTOCOL_PREFIX) && tokenEquals(protocol.slice(DAEMON_PROTOCOL_PREFIX.length), expected)) return protocol;
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
async function readTokenFile(file) {
|
|
70
|
+
try {
|
|
71
|
+
const raw = (await readFile(file, "utf8")).trim();
|
|
72
|
+
return isDaemonToken(raw) ? raw : void 0;
|
|
73
|
+
} catch (e) {
|
|
74
|
+
if (e.code === "ENOENT") return void 0;
|
|
75
|
+
throw e;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function lockTokenFile(file) {
|
|
79
|
+
await chmod(file, 384);
|
|
80
|
+
}
|
|
81
|
+
async function ensureDaemonToken() {
|
|
82
|
+
const file = paths().token;
|
|
83
|
+
await mkdir(dirname(file), { recursive: true });
|
|
84
|
+
const current = await readTokenFile(file);
|
|
85
|
+
if (current) {
|
|
86
|
+
await lockTokenFile(file);
|
|
87
|
+
return current;
|
|
88
|
+
}
|
|
89
|
+
const token = randomBytes(32).toString("hex");
|
|
90
|
+
const tmp = `${file}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
|
|
91
|
+
await writeFile(tmp, `${token}
|
|
92
|
+
`, { mode: 384, flag: "wx" });
|
|
93
|
+
await chmod(tmp, 384);
|
|
94
|
+
try {
|
|
95
|
+
await link(tmp, file);
|
|
96
|
+
} catch (e) {
|
|
97
|
+
await unlink(tmp).catch(() => {
|
|
98
|
+
});
|
|
99
|
+
if (e.code !== "EEXIST") throw e;
|
|
100
|
+
const raced = await readTokenFile(file);
|
|
101
|
+
if (raced) {
|
|
102
|
+
await lockTokenFile(file);
|
|
103
|
+
return raced;
|
|
104
|
+
}
|
|
105
|
+
await writeFile(file, `${token}
|
|
106
|
+
`, { mode: 384 });
|
|
107
|
+
}
|
|
108
|
+
await unlink(tmp).catch(() => {
|
|
109
|
+
});
|
|
110
|
+
await lockTokenFile(file);
|
|
111
|
+
const stored = await readTokenFile(file);
|
|
112
|
+
if (!stored) throw new Error("daemon token was not stored");
|
|
113
|
+
return stored;
|
|
114
|
+
}
|
|
115
|
+
var SESSION_KEY_VAR = "LEDGE_SESSION_KEY";
|
|
116
|
+
function sessionKey(id2, token = readDaemonToken()) {
|
|
117
|
+
return token ? createHmac("sha256", token).update(`ledge-session:${id2}`).digest("hex") : void 0;
|
|
118
|
+
}
|
|
119
|
+
function readDaemonToken() {
|
|
120
|
+
try {
|
|
121
|
+
const raw = readFileSync(paths().token, "utf8").trim();
|
|
122
|
+
return isDaemonToken(raw) ? raw : void 0;
|
|
123
|
+
} catch {
|
|
124
|
+
return void 0;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// ../protocol/src/asks.ts
|
|
6
129
|
import { z } from "zod";
|
|
7
|
-
var
|
|
130
|
+
var ASK_QUESTION_MAX = 2e3;
|
|
131
|
+
var ASK_OPTIONS_MAX = 4e3;
|
|
132
|
+
var ASK_ANSWER_MAX = 4e3;
|
|
133
|
+
var AskIdSchema = z.string().regex(/^a[0-9a-f]{6}$/);
|
|
134
|
+
var AskSchema = z.object({
|
|
135
|
+
id: AskIdSchema,
|
|
136
|
+
from: z.string().min(1),
|
|
137
|
+
fromName: z.string(),
|
|
138
|
+
question: z.string().min(1).max(ASK_QUESTION_MAX),
|
|
139
|
+
options: z.string().max(ASK_OPTIONS_MAX),
|
|
140
|
+
at: z.string().datetime(),
|
|
141
|
+
state: z.enum(["open", "answered", "dropped"]),
|
|
142
|
+
answer: z.object({ text: z.string().min(1).max(ASK_ANSWER_MAX), at: z.string().datetime() }).optional(),
|
|
143
|
+
closedAt: z.string().datetime().optional()
|
|
144
|
+
});
|
|
145
|
+
var AskRefusalSchema = z.enum(["unknown", "closed", "dropped", "not_session", "invalid"]);
|
|
146
|
+
var AskCreateSchema = z.object({
|
|
147
|
+
type: z.literal("ask.create"),
|
|
148
|
+
rid: z.string().min(1).max(100),
|
|
149
|
+
by: z.string().min(1),
|
|
150
|
+
question: z.string().trim().min(1).max(ASK_QUESTION_MAX),
|
|
151
|
+
options: AskSchema.shape.options
|
|
152
|
+
});
|
|
153
|
+
var AskAnswerSchema = z.object({
|
|
154
|
+
type: z.literal("ask.answer"),
|
|
155
|
+
rid: z.string().min(1).max(100),
|
|
156
|
+
id: AskIdSchema,
|
|
157
|
+
text: z.string().trim().min(1).max(ASK_ANSWER_MAX),
|
|
158
|
+
machineId: z.string().optional()
|
|
159
|
+
});
|
|
160
|
+
var AsksMessageSchema = z.object({ type: z.literal("asks"), asks: z.array(AskSchema) });
|
|
161
|
+
var AskUpdatedSchema = z.object({ type: z.literal("ask.updated"), ask: AskSchema });
|
|
162
|
+
var AskResultSchema = z.object({
|
|
163
|
+
type: z.literal("ask.result"),
|
|
164
|
+
rid: z.string(),
|
|
165
|
+
ask: AskSchema.optional(),
|
|
166
|
+
code: AskRefusalSchema.optional(),
|
|
167
|
+
reason: z.string().optional()
|
|
168
|
+
});
|
|
169
|
+
var askShown = (a) => a.state === "open";
|
|
170
|
+
|
|
171
|
+
// ../protocol/src/handover.ts
|
|
172
|
+
import { z as z2 } from "zod";
|
|
173
|
+
var ContextSchema = z2.object({ used: z2.number().int().min(0), window: z2.number().int().positive(), at: z2.string().datetime() });
|
|
8
174
|
var CONTEXT_NEAR = 0.8;
|
|
9
175
|
var CONTEXT_NEAR_MIN = 0.5;
|
|
10
176
|
var CONTEXT_NEAR_MAX = 0.95;
|
|
11
|
-
var ContextPrefsSchema =
|
|
177
|
+
var ContextPrefsSchema = z2.object({ near: z2.number().min(CONTEXT_NEAR_MIN).max(CONTEXT_NEAR_MAX) });
|
|
12
178
|
var contextShare = (c) => c ? Math.min(1, c.used / c.window) : void 0;
|
|
13
179
|
var contextNear = (c, near = CONTEXT_NEAR) => (contextShare(c) ?? 0) >= near;
|
|
14
|
-
var HandoverStateSchema =
|
|
15
|
-
var HandoverSchema =
|
|
180
|
+
var HandoverStateSchema = z2.enum(["briefing", "launching", "done", "failed"]);
|
|
181
|
+
var HandoverSchema = z2.object({
|
|
16
182
|
state: HandoverStateSchema,
|
|
17
|
-
at:
|
|
183
|
+
at: z2.string().datetime(),
|
|
18
184
|
/** The relief, once launched. */
|
|
19
|
-
to:
|
|
20
|
-
toName:
|
|
21
|
-
reason:
|
|
185
|
+
to: z2.string().optional(),
|
|
186
|
+
toName: z2.string().optional(),
|
|
187
|
+
reason: z2.string().optional(),
|
|
22
188
|
/** Started by Ledge itself (a seat working without asking), not by the user. */
|
|
23
|
-
auto:
|
|
189
|
+
auto: z2.literal(true).optional()
|
|
24
190
|
});
|
|
25
|
-
var RelievesSchema =
|
|
191
|
+
var RelievesSchema = z2.object({ id: z2.string(), name: z2.string(), at: z2.string().datetime() });
|
|
26
192
|
var BRIEF_MAX = 2e4;
|
|
27
|
-
var ContextSetSchema =
|
|
28
|
-
var ContextPrefsMessageSchema =
|
|
29
|
-
var SessionHandoverSchema =
|
|
30
|
-
var HandoverBriefSchema =
|
|
31
|
-
var HandoverShowSchema =
|
|
32
|
-
var SessionHandoverResultSchema =
|
|
33
|
-
var HandoverResultSchema =
|
|
193
|
+
var ContextSetSchema = z2.object({ type: z2.literal("context.set"), prefs: ContextPrefsSchema });
|
|
194
|
+
var ContextPrefsMessageSchema = z2.object({ type: z2.literal("context.prefs"), prefs: ContextPrefsSchema });
|
|
195
|
+
var SessionHandoverSchema = z2.object({ type: z2.literal("session.handover"), rid: z2.string().min(1).max(100), id: z2.string().min(1) });
|
|
196
|
+
var HandoverBriefSchema = z2.object({ type: z2.literal("handover.brief"), rid: z2.string().min(1).max(100), by: z2.string().min(1), text: z2.string().min(1).max(BRIEF_MAX) });
|
|
197
|
+
var HandoverShowSchema = z2.object({ type: z2.literal("handover.show"), rid: z2.string().min(1).max(100), by: z2.string().min(1) });
|
|
198
|
+
var SessionHandoverResultSchema = z2.object({ type: z2.literal("session.handover.result"), rid: z2.string(), ok: z2.boolean(), reason: z2.string().optional() });
|
|
199
|
+
var HandoverResultSchema = z2.object({ type: z2.literal("handover.result"), rid: z2.string(), text: z2.string().optional(), reason: z2.string().optional() });
|
|
34
200
|
|
|
35
201
|
// ../protocol/src/session.ts
|
|
36
|
-
import { z as
|
|
37
|
-
var ToolSchema =
|
|
38
|
-
var OmpApprovalSchema =
|
|
39
|
-
var AutonomySchema =
|
|
202
|
+
import { z as z3 } from "zod";
|
|
203
|
+
var ToolSchema = z3.enum(["claude", "codex", "cursor", "omp"]);
|
|
204
|
+
var OmpApprovalSchema = z3.enum(["always-ask", "write", "yolo"]);
|
|
205
|
+
var AutonomySchema = z3.enum(["ask", "edits", "auto"]);
|
|
40
206
|
function autonomyArgs(tool, autonomy) {
|
|
41
207
|
if (!autonomy || autonomy === "ask") return [];
|
|
42
208
|
switch (tool) {
|
|
@@ -53,97 +219,95 @@ function autonomyArgs(tool, autonomy) {
|
|
|
53
219
|
function ompApprovalFor(autonomy) {
|
|
54
220
|
return autonomy === "auto" ? "yolo" : autonomy ? "always-ask" : void 0;
|
|
55
221
|
}
|
|
56
|
-
var BackendSchema =
|
|
57
|
-
var SessionStateSchema =
|
|
58
|
-
var AskQuestionSchema =
|
|
59
|
-
id:
|
|
60
|
-
question:
|
|
61
|
-
header:
|
|
62
|
-
multi:
|
|
63
|
-
options:
|
|
64
|
-
});
|
|
65
|
-
var PendingSchema =
|
|
66
|
-
kind:
|
|
67
|
-
text:
|
|
222
|
+
var BackendSchema = z3.enum(["tmux", "omp-rpc"]);
|
|
223
|
+
var SessionStateSchema = z3.enum(["starting", "working", "waiting_input", "waiting_permission", "idle", "exited", "error"]);
|
|
224
|
+
var AskQuestionSchema = z3.object({
|
|
225
|
+
id: z3.string(),
|
|
226
|
+
question: z3.string(),
|
|
227
|
+
header: z3.string().optional(),
|
|
228
|
+
multi: z3.boolean().optional(),
|
|
229
|
+
options: z3.array(z3.object({ label: z3.string(), description: z3.string().optional() }))
|
|
230
|
+
});
|
|
231
|
+
var PendingSchema = z3.object({
|
|
232
|
+
kind: z3.enum(["question", "permission", "plan", "diff"]),
|
|
233
|
+
text: z3.string(),
|
|
68
234
|
/** What to review in full before deciding, when `text` is only its summary: a plan's markdown. */
|
|
69
|
-
body:
|
|
70
|
-
tool:
|
|
71
|
-
options:
|
|
235
|
+
body: z3.string().optional(),
|
|
236
|
+
tool: z3.string().optional(),
|
|
237
|
+
options: z3.array(z3.string()).optional(),
|
|
72
238
|
/** Each option's description, by index ('' when it has none); left out when no option has one. */
|
|
73
|
-
optionDetails:
|
|
239
|
+
optionDetails: z3.array(z3.string()).optional(),
|
|
74
240
|
/** `rpc`: the harness's own protocol asked (OMP): answered on its request id, never by typing. */
|
|
75
|
-
source:
|
|
241
|
+
source: z3.enum(["hook", "pane", "rpc"]),
|
|
76
242
|
/** OMP: every question of one `ask` call, answered together with `session.answer`; `requestId` is the dialog it answers. */
|
|
77
|
-
questions:
|
|
78
|
-
requestId:
|
|
243
|
+
questions: z3.array(AskQuestionSchema).optional(),
|
|
244
|
+
requestId: z3.string().optional(),
|
|
79
245
|
/** Set when the request comes from a helper (subagent): it is routed through its parent. */
|
|
80
|
-
helperId:
|
|
246
|
+
helperId: z3.string().optional(),
|
|
81
247
|
/** For a helper-routed request: the state the parent returns to once it is answered (main thread may stop meanwhile). */
|
|
82
248
|
parentState: SessionStateSchema.optional()
|
|
83
249
|
});
|
|
84
|
-
var ReplySchema =
|
|
85
|
-
text:
|
|
86
|
-
at:
|
|
250
|
+
var ReplySchema = z3.object({
|
|
251
|
+
text: z3.string(),
|
|
252
|
+
at: z3.string().datetime(),
|
|
87
253
|
/** The reply is a plan the agent proposes (Codex Plan mode): nothing in it is done yet. */
|
|
88
|
-
plan:
|
|
254
|
+
plan: z3.boolean().optional()
|
|
89
255
|
});
|
|
90
|
-
var HelperSchema =
|
|
91
|
-
id:
|
|
92
|
-
kind:
|
|
93
|
-
task:
|
|
256
|
+
var HelperSchema = z3.object({
|
|
257
|
+
id: z3.string(),
|
|
258
|
+
kind: z3.string(),
|
|
259
|
+
task: z3.string(),
|
|
94
260
|
state: SessionStateSchema,
|
|
95
261
|
/** When this helper finished; retained across daemon restarts until its five-minute expiry. */
|
|
96
|
-
finishedAt:
|
|
262
|
+
finishedAt: z3.string().datetime().optional()
|
|
97
263
|
});
|
|
98
|
-
var TopicSourceSchema =
|
|
99
|
-
var
|
|
264
|
+
var TopicSourceSchema = z3.enum(["user", "pane", "prompt"]);
|
|
265
|
+
var SessionRigSchema = z3.object({ machine: z3.string(), rigId: z3.string(), rigName: z3.string(), seat: z3.string(), pod: z3.string(), member: z3.string() });
|
|
266
|
+
var SessionSchema = z3.object({
|
|
100
267
|
/** Origin is annotated by the overlay, never used as an unqualified session id on the wire. */
|
|
101
|
-
machineId:
|
|
102
|
-
machineName:
|
|
103
|
-
repoId:
|
|
268
|
+
machineId: z3.string().optional(),
|
|
269
|
+
machineName: z3.string().optional(),
|
|
270
|
+
repoId: z3.string().optional(),
|
|
104
271
|
/** Annotated by the fleet when its machine is unreachable and the last snapshot is kept (keepStale, spec 2026-10-14 §6). */
|
|
105
|
-
offline:
|
|
106
|
-
|
|
107
|
-
|
|
272
|
+
offline: z3.boolean().optional(),
|
|
273
|
+
/** The permanent Ledge brain session (Lot 7). */
|
|
274
|
+
brain: z3.literal(true).optional(),
|
|
275
|
+
id: z3.string().min(1),
|
|
276
|
+
name: z3.string().min(1),
|
|
108
277
|
tool: ToolSchema,
|
|
109
|
-
cwd:
|
|
110
|
-
project:
|
|
111
|
-
title:
|
|
278
|
+
cwd: z3.string(),
|
|
279
|
+
project: z3.string(),
|
|
280
|
+
title: z3.string(),
|
|
112
281
|
/** One line saying what the session is about (spec 2026-10-11 §3). */
|
|
113
|
-
topic:
|
|
282
|
+
topic: z3.string().optional(),
|
|
114
283
|
topicSource: TopicSourceSchema.optional(),
|
|
115
284
|
/** The repository (its main worktree's folder name and absolute path), the checked-out branch, and whether `cwd` is a linked worktree (§4). */
|
|
116
|
-
repo:
|
|
117
|
-
repoPath:
|
|
118
|
-
branch:
|
|
119
|
-
worktree:
|
|
285
|
+
repo: z3.string().optional(),
|
|
286
|
+
repoPath: z3.string().optional(),
|
|
287
|
+
branch: z3.string().optional(),
|
|
288
|
+
worktree: z3.boolean().optional(),
|
|
120
289
|
/** The folder the agent works in now, as its last hook reported it: `cwd` stays where it started, this follows a worktree it entered. */
|
|
121
|
-
workdir:
|
|
122
|
-
tmuxSession:
|
|
290
|
+
workdir: z3.string().optional(),
|
|
291
|
+
tmuxSession: z3.string().nullable(),
|
|
123
292
|
/** Left out for a tmux session. `omp-rpc`: no pane, nothing to attach to; the daemon holds the process (see `agentSessionFile`). */
|
|
124
293
|
backend: BackendSchema.optional(),
|
|
125
294
|
state: SessionStateSchema,
|
|
126
295
|
pending: PendingSchema.optional(),
|
|
127
|
-
helpers:
|
|
296
|
+
helpers: z3.array(HelperSchema).default([]),
|
|
128
297
|
/** OMP: the instructions waiting in its own queue (typed while it works), as it reports them; left out when none. */
|
|
129
|
-
queue:
|
|
298
|
+
queue: z3.array(z3.object({ text: z3.string(), mode: z3.enum(["steer", "follow_up"]) })).optional(),
|
|
130
299
|
lastReply: ReplySchema.optional(),
|
|
131
300
|
/** The last message this session sent to another agent: its tool_use_id, the address, the peer's Ledge session id, a one-line summary. */
|
|
132
|
-
lastMessage:
|
|
133
|
-
startedAt:
|
|
134
|
-
lastActivityAt:
|
|
135
|
-
lastHookAt:
|
|
301
|
+
lastMessage: z3.object({ id: z3.string(), to: z3.string(), peer: z3.string().optional(), summary: z3.string(), at: z3.string().datetime() }).optional(),
|
|
302
|
+
startedAt: z3.string().datetime(),
|
|
303
|
+
lastActivityAt: z3.string().datetime(),
|
|
304
|
+
lastHookAt: z3.string().datetime().optional(),
|
|
136
305
|
/** The model and effort Ledge launched the agent with (#58); left out, the agent's own default. */
|
|
137
|
-
model:
|
|
138
|
-
effort:
|
|
306
|
+
model: z3.string().optional(),
|
|
307
|
+
effort: z3.string().optional(),
|
|
139
308
|
/** OMP: the approval mode it was launched with, kept by a resume; left out, `always-ask`. */
|
|
140
309
|
approval: OmpApprovalSchema.optional(),
|
|
141
|
-
/**
|
|
142
|
-
role: z2.string().optional(),
|
|
143
|
-
roleLabel: z2.string().optional(),
|
|
144
|
-
/** The live team it sits in (`team-…`); left out, the project's common table. */
|
|
145
|
-
team: z2.string().optional(),
|
|
146
|
-
/** Its role's autonomy, as launched (kept by a resume); left out, `ask`. */
|
|
310
|
+
/** Its autonomy, as launched (kept by a resume); left out, `ask`. */
|
|
147
311
|
autonomy: AutonomySchema.optional(),
|
|
148
312
|
/** Its context as its agent last reported it, after a turn (context handover spec §3.1); left out, not measured. */
|
|
149
313
|
context: ContextSchema.optional(),
|
|
@@ -152,21 +316,23 @@ var SessionSchema = z2.object({
|
|
|
152
316
|
/** The session it relieves, when it is a relief. */
|
|
153
317
|
relieves: RelievesSchema.optional(),
|
|
154
318
|
/** A model change asked while the agent worked (`session.model`), applied at its next free moment; a field left out is the agent's default. */
|
|
155
|
-
modelNext:
|
|
319
|
+
modelNext: z3.object({ model: z3.string().optional(), effort: z3.string().optional() }).optional(),
|
|
156
320
|
/** The agent's own session id when Ledge chose it at launch (Claude Code `--session-id`). */
|
|
157
|
-
agentSessionId:
|
|
321
|
+
agentSessionId: z3.string().optional(),
|
|
158
322
|
/** OMP: the exact journal file of the conversation, what a resume names (never "the latest of the folder"). */
|
|
159
|
-
agentSessionFile:
|
|
323
|
+
agentSessionFile: z3.string().optional(),
|
|
160
324
|
/** The agent's transcript: the latest one a hook named (it follows /clear and --resume), else the one the launch implies. */
|
|
161
|
-
transcriptPath:
|
|
162
|
-
exitCode:
|
|
163
|
-
exitedAt:
|
|
164
|
-
lastError:
|
|
165
|
-
source:
|
|
325
|
+
transcriptPath: z3.string().optional(),
|
|
326
|
+
exitCode: z3.number().int().nullable().optional(),
|
|
327
|
+
exitedAt: z3.string().datetime().optional(),
|
|
328
|
+
lastError: z3.string().optional(),
|
|
329
|
+
source: z3.enum(["launcher", "hook_only"]),
|
|
166
330
|
/** When the session was put in the archive (session management): set, it leaves the live list and waits to be restored, resumed or deleted. */
|
|
167
|
-
archivedAt:
|
|
331
|
+
archivedAt: z3.string().datetime().optional(),
|
|
168
332
|
/** When the session was last taken out of the archive: the poller's retirement clock restarts from it, not from `exitedAt`. */
|
|
169
|
-
restoredAt:
|
|
333
|
+
restoredAt: z3.string().datetime().optional(),
|
|
334
|
+
/** The OpenRig seat this session runs in (paired from the hook's `openrig.sessionName`). */
|
|
335
|
+
rig: SessionRigSchema.optional()
|
|
170
336
|
});
|
|
171
337
|
function backendOf(s) {
|
|
172
338
|
return s.backend ?? "tmux";
|
|
@@ -175,351 +341,29 @@ function isArchived(s) {
|
|
|
175
341
|
return s.archivedAt !== void 0;
|
|
176
342
|
}
|
|
177
343
|
|
|
178
|
-
// ../protocol/src/
|
|
344
|
+
// ../protocol/src/actions.ts
|
|
179
345
|
import { z as z7 } from "zod";
|
|
180
346
|
|
|
181
|
-
// ../protocol/src/
|
|
182
|
-
import { z as z3 } from "zod";
|
|
183
|
-
var ModelIdSchema = z3.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:/@[\]=,+-]*$/, "not a model id");
|
|
184
|
-
var EffortSchema = z3.string().min(1).max(20).regex(/^[a-z]+$/, "not an effort");
|
|
185
|
-
var ModelChoiceSchema = z3.object({
|
|
186
|
-
id: ModelIdSchema,
|
|
187
|
-
label: z3.string(),
|
|
188
|
-
description: z3.string().optional(),
|
|
189
|
-
efforts: z3.array(EffortSchema).optional(),
|
|
190
|
-
defaultEffort: EffortSchema.optional(),
|
|
191
|
-
isDefault: z3.boolean().optional()
|
|
192
|
-
});
|
|
193
|
-
var ModelsListSchema = z3.object({
|
|
194
|
-
type: z3.literal("models.list"),
|
|
195
|
-
requestId: z3.string().min(1).max(100),
|
|
196
|
-
tool: ToolSchema,
|
|
197
|
-
machineId: z3.string().optional()
|
|
198
|
-
});
|
|
199
|
-
var ModelsListingSchema = z3.object({
|
|
200
|
-
type: z3.literal("models.listing"),
|
|
201
|
-
requestId: z3.string(),
|
|
202
|
-
tool: ToolSchema,
|
|
203
|
-
models: z3.array(ModelChoiceSchema),
|
|
204
|
-
error: z3.string().optional()
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
// ../protocol/src/projects.ts
|
|
208
|
-
import { z as z6 } from "zod";
|
|
209
|
-
|
|
210
|
-
// ../protocol/src/machines.ts
|
|
211
|
-
import { z as z5 } from "zod";
|
|
212
|
-
|
|
213
|
-
// ../protocol/src/ssh.ts
|
|
347
|
+
// ../protocol/src/proposal.ts
|
|
214
348
|
import { z as z4 } from "zod";
|
|
215
|
-
var
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
ssh: SshAliasSchema.optional()
|
|
223
|
-
});
|
|
224
|
-
var MachinesSchema = z5.array(MachineSchema).min(1).max(20).superRefine((list, ctx) => {
|
|
225
|
-
if (list[0]?.id !== "local" || list[0].ssh !== void 0) ctx.addIssue({ code: "custom", message: "the first machine is local, without ssh", path: [0] });
|
|
226
|
-
const ids = /* @__PURE__ */ new Set(), aliases = /* @__PURE__ */ new Set();
|
|
227
|
-
list.forEach((m, i) => {
|
|
228
|
-
if (i > 0 && !m.ssh) ctx.addIssue({ code: "custom", message: "a remote machine needs an ssh alias", path: [i, "ssh"] });
|
|
229
|
-
if (ids.has(m.id)) ctx.addIssue({ code: "custom", message: `duplicate id ${m.id}`, path: [i, "id"] });
|
|
230
|
-
ids.add(m.id);
|
|
231
|
-
if (m.ssh) {
|
|
232
|
-
if (aliases.has(m.ssh)) ctx.addIssue({ code: "custom", message: `duplicate ssh alias ${m.ssh}`, path: [i, "ssh"] });
|
|
233
|
-
aliases.add(m.ssh);
|
|
234
|
-
}
|
|
235
|
-
});
|
|
349
|
+
var ProposalBlockSchema = z4.object({ cwd: z4.string().trim().min(1), prompt: z4.string().optional() });
|
|
350
|
+
var RelayBlockSchema = z4.object({ session: z4.string().trim().min(1), text: z4.string().trim().min(1) });
|
|
351
|
+
var ProjectBlockSchema = z4.object({
|
|
352
|
+
name: z4.string().trim().min(1).max(80),
|
|
353
|
+
description: z4.string().max(500).optional(),
|
|
354
|
+
repos: z4.array(z4.object({ path: z4.string().min(1).max(4096), why: z4.string().trim().min(1).max(200) })).min(1).max(50),
|
|
355
|
+
addTo: z4.string().trim().max(80).optional()
|
|
236
356
|
});
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
var PROJECT_COLORS = { blue: "#3b82f6", green: "#10b981", amber: "#f59e0b", violet: "#8b5cf6", teal: "#14b8a6", pink: "#ec4899", red: "#ef4444", slate: "#64748b" };
|
|
240
|
-
var ProjectColorSchema = z6.enum(["blue", "green", "amber", "violet", "teal", "pink", "red", "slate"]);
|
|
241
|
-
var ProjectIdSchema = z6.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/);
|
|
242
|
-
function normalizePath(raw) {
|
|
243
|
-
const p = raw.trim().replace(/\/+/g, "/");
|
|
244
|
-
return p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
|
|
245
|
-
}
|
|
246
|
-
var PathSchema = z6.string().max(4096).refine((p) => p.startsWith("/") && p === normalizePath(p), "an absolute, normalized path");
|
|
247
|
-
var RepoSchema = z6.object({ machine: MachineIdSchema, path: PathSchema });
|
|
248
|
-
var ProjectSchema = z6.object({
|
|
249
|
-
id: ProjectIdSchema,
|
|
250
|
-
name: z6.string().trim().min(1).max(80),
|
|
251
|
-
color: ProjectColorSchema,
|
|
252
|
-
description: z6.string().max(500).default(""),
|
|
253
|
-
repos: z6.array(RepoSchema).max(50)
|
|
254
|
-
});
|
|
255
|
-
var RuleSchema = z6.object({ machine: MachineIdSchema, path: PathSchema, project: ProjectIdSchema });
|
|
256
|
-
function projectsProblems(p) {
|
|
257
|
-
const out = [];
|
|
258
|
-
const ids = /* @__PURE__ */ new Set(), names = /* @__PURE__ */ new Set(), repos = /* @__PURE__ */ new Set(), rules = /* @__PURE__ */ new Set();
|
|
259
|
-
p.projects.forEach((project, i) => {
|
|
260
|
-
if (ids.has(project.id)) out.push({ code: "duplicate_id", path: ["projects", i, "id"] });
|
|
261
|
-
ids.add(project.id);
|
|
262
|
-
const name = project.name.trim().toLocaleLowerCase();
|
|
263
|
-
if (names.has(name)) out.push({ code: "duplicate_name", path: ["projects", i, "name"] });
|
|
264
|
-
names.add(name);
|
|
265
|
-
project.repos.forEach((repo, j) => {
|
|
266
|
-
const key = `${repo.machine}
|
|
267
|
-
${repo.path}`;
|
|
268
|
-
if (repos.has(key)) out.push({ code: "duplicate_repo", path: ["projects", i, "repos", j] });
|
|
269
|
-
repos.add(key);
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
p.rules.forEach((rule, i) => {
|
|
273
|
-
const key = `${rule.machine}
|
|
274
|
-
${rule.path}`;
|
|
275
|
-
if (rules.has(key)) out.push({ code: "duplicate_rule", path: ["rules", i] });
|
|
276
|
-
rules.add(key);
|
|
277
|
-
if (!ids.has(rule.project)) out.push({ code: "unknown_project", path: ["rules", i, "project"] });
|
|
278
|
-
});
|
|
279
|
-
return out;
|
|
280
|
-
}
|
|
281
|
-
var ProjectsSchema = z6.object({ projects: z6.array(ProjectSchema).max(100), rules: z6.array(RuleSchema).max(1e3) }).superRefine((p, ctx) => {
|
|
282
|
-
for (const problem of projectsProblems(p)) ctx.addIssue({ code: "custom", message: problem.code, path: problem.path });
|
|
283
|
-
});
|
|
284
|
-
var DEFAULT_PROJECTS = { projects: [], rules: [] };
|
|
285
|
-
var under = (cwd, path2) => path2 === "/" || cwd === path2 || cwd.startsWith(`${path2}/`);
|
|
286
|
-
function projectOf(session, state) {
|
|
287
|
-
const machine = session.machineId ?? "local";
|
|
288
|
-
const cwd = normalizePath(session.cwd);
|
|
289
|
-
const known = new Set(state.projects.map((p) => p.id));
|
|
290
|
-
const candidates = [
|
|
291
|
-
...state.projects.flatMap((p) => p.repos.filter((r) => r.machine === machine).map((r) => ({ project: p.id, path: r.path, rule: false }))),
|
|
292
|
-
...state.rules.filter((r) => r.machine === machine && known.has(r.project)).map((r) => ({ project: r.project, path: r.path, rule: true }))
|
|
293
|
-
].filter((c) => under(cwd, c.path));
|
|
294
|
-
candidates.sort((x, y) => y.path.length - x.path.length || Number(y.rule) - Number(x.rule));
|
|
295
|
-
return candidates[0]?.project ?? null;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// ../protocol/src/teams.ts
|
|
299
|
-
var RoleIdSchema = z7.string().regex(/^[a-z0-9][a-z0-9_-]{0,39}$/);
|
|
300
|
-
var ROLE_LABEL_MAX = 40;
|
|
301
|
-
var ROLE_PROMPT_MAX = 8e3;
|
|
302
|
-
var DefinitionHashSchema = z7.string().regex(/^[0-9a-f]{16}$/);
|
|
303
|
-
var RoleSchema = z7.object({
|
|
304
|
-
id: RoleIdSchema,
|
|
305
|
-
label: z7.string().min(1).max(ROLE_LABEL_MAX),
|
|
306
|
-
prompt: z7.string().max(ROLE_PROMPT_MAX),
|
|
307
|
-
tool: ToolSchema.optional(),
|
|
308
|
-
model: ModelIdSchema.optional(),
|
|
309
|
-
effort: EffortSchema.optional(),
|
|
310
|
-
autonomy: AutonomySchema.optional(),
|
|
311
|
-
source: z7.enum(["repo", "home"]),
|
|
312
|
-
path: z7.string(),
|
|
313
|
-
shadows: z7.string().optional(),
|
|
314
|
-
/** 16 hex chars of the file's text: what a write or delete must name as its base (absent from older daemons). */
|
|
315
|
-
hash: DefinitionHashSchema.optional()
|
|
316
|
-
});
|
|
317
|
-
var DefinitionProblemSchema = z7.object({ path: z7.string(), reason: z7.string() });
|
|
318
|
-
var TEAM_SEATS_MAX = 8;
|
|
319
|
-
var SeatSchema = z7.object({
|
|
320
|
-
role: RoleIdSchema,
|
|
321
|
-
tool: ToolSchema.optional(),
|
|
322
|
-
model: ModelIdSchema.optional(),
|
|
323
|
-
effort: EffortSchema.optional(),
|
|
324
|
-
name: z7.string().min(1).max(40).optional()
|
|
325
|
-
});
|
|
326
|
-
var uniqueRoles = (seats) => new Set(seats.map((s) => s.role)).size === seats.length;
|
|
327
|
-
var SeatsSchema = z7.array(SeatSchema).min(1).max(TEAM_SEATS_MAX).refine(uniqueRoles, "a role twice in one team");
|
|
328
|
-
var TeamNameSchema = z7.string().trim().min(1).max(60);
|
|
329
|
-
var TemplateIdSchema = z7.string().regex(/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/);
|
|
330
|
-
var TeamTemplateSchema = z7.object({ id: z7.string().min(1).max(64), name: TeamNameSchema, seats: SeatsSchema, source: z7.enum(["repo", "home"]), path: z7.string(), hash: DefinitionHashSchema.optional() });
|
|
331
|
-
var TeamIdSchema = z7.string().regex(/^team-[0-9a-f]{4,8}$/);
|
|
332
|
-
var TeamStateSchema = z7.enum(["active", "resting", "dissolved"]);
|
|
333
|
-
var TeamSchema = z7.object({
|
|
334
|
-
id: TeamIdSchema,
|
|
335
|
-
name: TeamNameSchema,
|
|
336
|
-
template: z7.string().optional(),
|
|
337
|
-
project: z7.string().nullable(),
|
|
338
|
-
machine: z7.string(),
|
|
339
|
-
cwd: z7.string(),
|
|
340
|
-
state: TeamStateSchema,
|
|
341
|
-
/** A live seat: `tool`, `model` and `effort` are what it was composed with over the role's defaults; `leaving` marks a seat removed
|
|
342
|
-
* from the composition that finishes its turn and then is closed. */
|
|
343
|
-
seats: z7.array(z7.object({
|
|
344
|
-
role: RoleIdSchema,
|
|
345
|
-
sessionId: z7.string().nullable(),
|
|
346
|
-
tool: ToolSchema.optional(),
|
|
347
|
-
model: ModelIdSchema.optional(),
|
|
348
|
-
effort: EffortSchema.optional(),
|
|
349
|
-
leaving: z7.literal(true).optional()
|
|
350
|
-
})).max(TEAM_SEATS_MAX * 2),
|
|
351
|
-
createdAt: z7.string(),
|
|
352
|
-
updatedAt: z7.string(),
|
|
353
|
-
restingAt: z7.string().optional(),
|
|
354
|
-
dissolvedAt: z7.string().optional()
|
|
355
|
-
});
|
|
356
|
-
var RolesListSchema = z7.object({ type: z7.literal("roles.list"), cwd: z7.string().min(1).optional(), requestId: z7.string().max(100).optional(), machineId: z7.string().optional() });
|
|
357
|
-
var RolesListingSchema = z7.object({
|
|
358
|
-
type: z7.literal("roles.listing"),
|
|
359
|
-
requestId: z7.string().optional(),
|
|
360
|
-
roles: z7.array(RoleSchema),
|
|
361
|
-
templates: z7.array(TeamTemplateSchema).default([]),
|
|
362
|
-
problems: z7.array(DefinitionProblemSchema),
|
|
363
|
-
/** Set by the fleet when the project's machine could not answer (#99): 'offline', or 'outdated' for a daemon without roles.list. */
|
|
364
|
-
error: z7.string().optional()
|
|
365
|
-
});
|
|
366
|
-
var TeamLaunchSchema = z7.object({
|
|
367
|
-
type: z7.literal("team.launch"),
|
|
368
|
-
rid: z7.string().min(1).max(100),
|
|
369
|
-
cwd: z7.string().min(1).optional(),
|
|
370
|
-
template: z7.string().min(1).max(64).optional(),
|
|
371
|
-
seats: SeatsSchema.optional(),
|
|
372
|
-
name: TeamNameSchema.optional(),
|
|
373
|
-
qid: z7.string().min(1).optional(),
|
|
374
|
-
machineId: z7.string().optional(),
|
|
375
|
-
/** The project's name, for a client that holds no path (the phone): the daemon resolves its folder. */
|
|
376
|
-
project: ProjectIdSchema.optional()
|
|
377
|
-
});
|
|
378
|
-
var TeamJoinSchema = z7.object({ type: z7.literal("team.join"), team: TeamIdSchema, session: z7.string().min(1), role: RoleIdSchema });
|
|
379
|
-
var TeamLeaveSchema = z7.object({ type: z7.literal("team.leave"), team: TeamIdSchema, session: z7.string().min(1) });
|
|
380
|
-
var TeamResumeSchema = z7.object({ type: z7.literal("team.resume"), team: TeamIdSchema });
|
|
381
|
-
var TeamDissolveSchema = z7.object({ type: z7.literal("team.dissolve"), team: TeamIdSchema });
|
|
382
|
-
var TeamSaveSchema = z7.object({ type: z7.literal("team.save"), rid: z7.string().min(1).max(100), name: TeamNameSchema, seats: SeatsSchema, qid: z7.string().min(1).optional() });
|
|
383
|
-
var DefinitionScopeSchema = z7.enum(["home", "repo"]);
|
|
384
|
-
var RoleDraftSchema = RoleSchema.pick({ id: true, label: true, prompt: true, tool: true, model: true, effort: true, autonomy: true });
|
|
385
|
-
var DefinitionCodeSchema = z7.enum(["changed", "exists", "missing", "unknown_project", "invalid"]);
|
|
386
|
-
var scopeFields = { rid: z7.string().min(1).max(100), scope: DefinitionScopeSchema, project: ProjectIdSchema.optional() };
|
|
387
|
-
var scopeIssue = (m) => m.scope === void 0 || m.scope === "repo" === (m.project !== void 0) ? null : "a repo scope names a project, a home scope none";
|
|
388
|
-
var DefinitionBaseSchema = DefinitionHashSchema;
|
|
389
|
-
var DefinitionsListSchema = z7.object({ type: z7.literal("definitions.list"), requestId: z7.string().max(100).optional() });
|
|
390
|
-
var RoleWriteSchema = z7.object({ type: z7.literal("role.write"), ...scopeFields, role: RoleDraftSchema, base: DefinitionBaseSchema.nullable() });
|
|
391
|
-
var RoleDeleteSchema = z7.object({ type: z7.literal("role.delete"), ...scopeFields, id: RoleIdSchema, base: DefinitionBaseSchema });
|
|
392
|
-
var TemplateWriteSchema = z7.object({
|
|
393
|
-
type: z7.literal("template.write"),
|
|
394
|
-
...scopeFields,
|
|
395
|
-
id: TemplateIdSchema.optional(),
|
|
396
|
-
name: TeamNameSchema,
|
|
397
|
-
seats: SeatsSchema,
|
|
398
|
-
base: DefinitionBaseSchema.nullable()
|
|
399
|
-
});
|
|
400
|
-
var TemplateDeleteSchema = z7.object({ type: z7.literal("template.delete"), ...scopeFields, id: TemplateIdSchema, base: DefinitionBaseSchema });
|
|
401
|
-
var TeamComposeSchema = z7.object({ type: z7.literal("team.compose"), rid: z7.string().min(1).max(100), team: TeamIdSchema, seats: SeatsSchema });
|
|
402
|
-
var TeamSeatSchema = z7.object({ type: z7.literal("team.seat"), rid: z7.string().min(1).max(100), team: TeamIdSchema, role: RoleIdSchema, action: z7.enum(["start", "restart"]) });
|
|
403
|
-
var DefinitionsListingSchema = z7.object({
|
|
404
|
-
type: z7.literal("definitions.listing"),
|
|
405
|
-
requestId: z7.string().optional(),
|
|
406
|
-
scopes: z7.array(z7.object({
|
|
407
|
-
scope: DefinitionScopeSchema,
|
|
408
|
-
project: z7.string().nullable(),
|
|
409
|
-
roles: z7.array(RoleSchema),
|
|
410
|
-
templates: z7.array(TeamTemplateSchema),
|
|
411
|
-
problems: z7.array(DefinitionProblemSchema)
|
|
412
|
-
}))
|
|
413
|
-
});
|
|
414
|
-
var DefinitionResultSchema = z7.object({ type: z7.literal("definition.result"), rid: z7.string(), id: z7.string().optional(), hash: DefinitionHashSchema.optional(), code: DefinitionCodeSchema.optional(), reason: z7.string().optional() });
|
|
415
|
-
var TeamChangedSchema = z7.object({ type: z7.literal("team.changed"), rid: z7.string(), team: TeamSchema.optional(), reason: z7.string().optional() });
|
|
416
|
-
var TeamsMessageSchema = z7.object({ type: z7.literal("teams"), teams: z7.array(TeamSchema) });
|
|
417
|
-
var TeamUpdatedSchema = z7.object({ type: z7.literal("team.updated"), team: TeamSchema });
|
|
418
|
-
var TeamLaunchedSchema = z7.object({ type: z7.literal("team.launched"), rid: z7.string(), team: TeamSchema });
|
|
419
|
-
var TeamFailedSchema = z7.object({ type: z7.literal("team.failed"), rid: z7.string(), reason: z7.string(), team: TeamSchema.optional() });
|
|
420
|
-
var TeamSavedSchema = z7.object({ type: z7.literal("team.saved"), rid: z7.string(), path: z7.string().optional(), reason: z7.string().optional() });
|
|
421
|
-
var isTeamLive = (t) => t.state !== "dissolved";
|
|
422
|
-
|
|
423
|
-
// ../protocol/src/tasks.ts
|
|
424
|
-
import { z as z8 } from "zod";
|
|
425
|
-
var TASK_TITLE_MAX = 200;
|
|
426
|
-
var TASK_TEXT_MAX = 2e4;
|
|
427
|
-
var LEDGE_GIVER = "ledge";
|
|
428
|
-
var TASK_OPS = ["give", "take", "pass", "done", "refuse", "cancel", "drop"];
|
|
429
|
-
var TRANSMISSION_OPS = ["give", "pass", "done", "refuse", "cancel"];
|
|
430
|
-
var TaskLogEntrySchema = z8.object({
|
|
431
|
-
at: z8.string(),
|
|
432
|
-
by: z8.string(),
|
|
433
|
-
what: z8.string(),
|
|
434
|
-
op: z8.enum(TASK_OPS).optional(),
|
|
435
|
-
from: z8.string().optional(),
|
|
436
|
-
to: z8.string().optional(),
|
|
437
|
-
fromName: z8.string().optional(),
|
|
438
|
-
toName: z8.string().optional(),
|
|
439
|
-
note: z8.string().optional()
|
|
440
|
-
});
|
|
441
|
-
var TaskSchema = z8.object({
|
|
442
|
-
id: z8.string(),
|
|
443
|
-
title: z8.string(),
|
|
444
|
-
text: z8.string().optional(),
|
|
445
|
-
giver: z8.string(),
|
|
446
|
-
giverName: z8.string(),
|
|
447
|
-
owner: z8.string(),
|
|
448
|
-
ownerName: z8.string(),
|
|
449
|
-
state: z8.enum(["open", "taken", "done", "refused", "dropped"]),
|
|
450
|
-
result: z8.string().optional(),
|
|
451
|
-
/** The live team its owner sat in when it was given (or passed), so a team's tasks can be listed. */
|
|
452
|
-
team: z8.string().optional(),
|
|
453
|
-
/** A task Ledge gave and the user put away from « À toi » once closed. */
|
|
454
|
-
seen: z8.boolean().optional(),
|
|
455
|
-
at: z8.string(),
|
|
456
|
-
updatedAt: z8.string(),
|
|
457
|
-
log: z8.array(TaskLogEntrySchema)
|
|
458
|
-
});
|
|
459
|
-
var handOver = (op) => TRANSMISSION_OPS.includes(op ?? "");
|
|
460
|
-
function transmissions(t) {
|
|
461
|
-
return t.log.flatMap((e, index) => handOver(e.op) && e.from !== void 0 && e.to !== void 0 ? [{ index, at: e.at, op: e.op, from: e.from, to: e.to, fromName: e.fromName ?? "", toName: e.toName ?? "", ...e.note !== void 0 ? { note: e.note } : {} }] : []);
|
|
462
|
-
}
|
|
463
|
-
var givenByLedge = (t) => t.giver === LEDGE_GIVER;
|
|
464
|
-
var taskClosed = (t) => t.state === "done" || t.state === "refused" || t.state === "dropped";
|
|
465
|
-
var TaskCmdSchema = z8.object({
|
|
466
|
-
type: z8.literal("task.cmd"),
|
|
467
|
-
rid: z8.string().min(1),
|
|
468
|
-
by: z8.string().min(1),
|
|
469
|
-
op: z8.enum(["give", "take", "done", "refuse", "pass", "show", "list", "seen", "cancel"]),
|
|
470
|
-
task: z8.string().min(1).max(40).optional(),
|
|
471
|
-
to: z8.string().min(1).optional(),
|
|
472
|
-
title: z8.string().min(1).max(TASK_TITLE_MAX).optional(),
|
|
473
|
-
text: z8.string().max(TASK_TEXT_MAX).optional(),
|
|
474
|
-
all: z8.boolean().optional(),
|
|
475
|
-
team: z8.string().min(1).max(40).optional(),
|
|
476
|
-
qid: z8.string().min(1).optional(),
|
|
477
|
-
row: z8.number().int().min(0).max(7).optional()
|
|
478
|
-
});
|
|
479
|
-
var TaskUpdatedSchema = z8.object({ type: z8.literal("task.updated"), task: TaskSchema });
|
|
480
|
-
var TaskResultSchema = z8.object({
|
|
481
|
-
type: z8.literal("task.result"),
|
|
482
|
-
rid: z8.string(),
|
|
483
|
-
task: TaskSchema.optional(),
|
|
484
|
-
tasks: z8.array(TaskSchema).optional(),
|
|
485
|
-
reason: z8.string().optional()
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
// ../protocol/src/actions.ts
|
|
489
|
-
import { z as z11 } from "zod";
|
|
490
|
-
|
|
491
|
-
// ../protocol/src/proposal.ts
|
|
492
|
-
import { z as z9 } from "zod";
|
|
493
|
-
var ProposalBlockSchema = z9.object({ cwd: z9.string().trim().min(1), prompt: z9.string().optional() });
|
|
494
|
-
var RelayBlockSchema = z9.object({ session: z9.string().trim().min(1), text: z9.string().trim().min(1) });
|
|
495
|
-
var ProjectBlockSchema = z9.object({
|
|
496
|
-
name: z9.string().trim().min(1).max(80),
|
|
497
|
-
description: z9.string().max(500).optional(),
|
|
498
|
-
repos: z9.array(z9.object({ path: z9.string().min(1).max(4096), why: z9.string().trim().min(1).max(200) })).min(1).max(50),
|
|
499
|
-
addTo: z9.string().trim().max(80).optional()
|
|
500
|
-
});
|
|
501
|
-
var CloseBlockSchema = z9.object({ session: z9.string().trim().min(1) });
|
|
502
|
-
var TeamBlockSchema = z9.object({
|
|
503
|
-
cwd: z9.string().trim().min(1),
|
|
504
|
-
template: z9.string().trim().min(1).max(64).optional(),
|
|
505
|
-
name: z9.string().trim().min(1).max(60).optional(),
|
|
506
|
-
seats: z9.array(z9.object({ role: z9.string().trim().min(1).max(40), tool: z9.enum(["claude", "codex", "cursor", "omp"]).optional(), model: z9.string().max(200).optional(), effort: z9.string().max(20).optional(), name: z9.string().max(40).optional() })).min(1).max(8).optional()
|
|
507
|
-
}).refine((b) => !!b.template || !!b.seats?.length, "a template or seats");
|
|
508
|
-
var TaskBlockSchema = z9.object({
|
|
509
|
-
to: z9.string().trim().min(1).max(80),
|
|
510
|
-
team: z9.string().trim().max(40).optional(),
|
|
511
|
-
title: z9.string().trim().min(1).max(200),
|
|
512
|
-
text: z9.string().max(2e4).optional()
|
|
513
|
-
});
|
|
514
|
-
var BLOCK = /```ledge-(session|relay|project|close|team|task|action)[ \t]*\n?([\s\S]*?)(?:```|$)/g;
|
|
357
|
+
var CloseBlockSchema = z4.object({ session: z4.string().trim().min(1) });
|
|
358
|
+
var BLOCK = /```ledge-(session|relay|project|close|action)[ \t]*\n?([\s\S]*?)(?:```|$)/g;
|
|
515
359
|
function extractProposal(answer) {
|
|
516
360
|
const found = [];
|
|
517
|
-
const
|
|
361
|
+
const text2 = answer.replace(BLOCK, (_m, kind, body) => {
|
|
518
362
|
found.push({ kind, raw: body.trim() });
|
|
519
363
|
return "";
|
|
520
364
|
});
|
|
521
365
|
const last = found.at(-1);
|
|
522
|
-
return last ? { text:
|
|
366
|
+
return last ? { text: text2.replace(/\n{3,}/g, "\n\n").trim(), kind: last.kind, raw: last.raw, blocks: found } : { text: answer, kind: null, raw: null, blocks: [] };
|
|
523
367
|
}
|
|
524
368
|
function parseRelayBlock(raw) {
|
|
525
369
|
try {
|
|
@@ -537,22 +381,6 @@ function parseCloseBlock(raw) {
|
|
|
537
381
|
return null;
|
|
538
382
|
}
|
|
539
383
|
}
|
|
540
|
-
function parseTeamBlock(raw) {
|
|
541
|
-
try {
|
|
542
|
-
const r = TeamBlockSchema.safeParse(JSON.parse(raw));
|
|
543
|
-
return r.success ? r.data : null;
|
|
544
|
-
} catch {
|
|
545
|
-
return null;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
function parseTaskBlock(raw) {
|
|
549
|
-
try {
|
|
550
|
-
const r = TaskBlockSchema.safeParse(JSON.parse(raw));
|
|
551
|
-
return r.success ? r.data : null;
|
|
552
|
-
} catch {
|
|
553
|
-
return null;
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
384
|
function parseProjectBlock(raw) {
|
|
557
385
|
try {
|
|
558
386
|
const r = ProjectBlockSchema.safeParse(JSON.parse(raw));
|
|
@@ -562,9 +390,37 @@ function parseProjectBlock(raw) {
|
|
|
562
390
|
}
|
|
563
391
|
}
|
|
564
392
|
|
|
393
|
+
// ../protocol/src/models.ts
|
|
394
|
+
import { z as z5 } from "zod";
|
|
395
|
+
var ModelIdSchema = z5.string().min(1).max(200).regex(/^[A-Za-z0-9][A-Za-z0-9._:/@[\]=,+-]*$/, "not a model id");
|
|
396
|
+
var EffortSchema = z5.string().min(1).max(20).regex(/^[a-z]+$/, "not an effort");
|
|
397
|
+
var ModelChoiceSchema = z5.object({
|
|
398
|
+
id: ModelIdSchema,
|
|
399
|
+
label: z5.string(),
|
|
400
|
+
description: z5.string().optional(),
|
|
401
|
+
efforts: z5.array(EffortSchema).optional(),
|
|
402
|
+
defaultEffort: EffortSchema.optional(),
|
|
403
|
+
isDefault: z5.boolean().optional()
|
|
404
|
+
});
|
|
405
|
+
var ModelsListSchema = z5.object({
|
|
406
|
+
type: z5.literal("models.list"),
|
|
407
|
+
requestId: z5.string().min(1).max(100),
|
|
408
|
+
tool: ToolSchema,
|
|
409
|
+
machineId: z5.string().optional()
|
|
410
|
+
});
|
|
411
|
+
var ModelsListingSchema = z5.object({
|
|
412
|
+
type: z5.literal("models.listing"),
|
|
413
|
+
requestId: z5.string(),
|
|
414
|
+
tool: ToolSchema,
|
|
415
|
+
models: z5.array(ModelChoiceSchema),
|
|
416
|
+
error: z5.string().optional()
|
|
417
|
+
});
|
|
418
|
+
var ModelRefusalSchema = z5.enum(["not_launched", "ended", "no_conversation", "not_running", "effort_in_model", "restart_failed", "refused"]);
|
|
419
|
+
var SessionModelAcceptedSchema = z5.object({ type: z5.literal("session.model.accepted"), id: z5.string(), when: z5.enum(["now", "turn", "none"]) });
|
|
420
|
+
|
|
565
421
|
// ../protocol/src/decisions.ts
|
|
566
|
-
import { z as
|
|
567
|
-
var DecisionSchema =
|
|
422
|
+
import { z as z6 } from "zod";
|
|
423
|
+
var DecisionSchema = z6.enum(["accept", "deny", "always"]);
|
|
568
424
|
var NOTE_MAX = 4e3;
|
|
569
425
|
var NOTE_NOT_TYPED = "note_not_typed";
|
|
570
426
|
var DECISION_OFFERS = {
|
|
@@ -594,33 +450,22 @@ function pendingKey(p) {
|
|
|
594
450
|
}
|
|
595
451
|
|
|
596
452
|
// ../protocol/src/actions.ts
|
|
597
|
-
var ActionRiskSchema =
|
|
453
|
+
var ActionRiskSchema = z7.enum(["read", "reversible", "destructive"]);
|
|
598
454
|
var ACTION_IDS = [
|
|
599
455
|
"session.launch",
|
|
600
456
|
"session.relay",
|
|
601
457
|
"session.close",
|
|
602
458
|
"project.propose",
|
|
603
|
-
"team.launch",
|
|
604
|
-
"task.give",
|
|
605
459
|
"session.model",
|
|
606
460
|
"session.interrupt",
|
|
607
461
|
"session.archive",
|
|
608
462
|
"session.restore",
|
|
609
463
|
"session.resume",
|
|
610
|
-
"session.decide"
|
|
611
|
-
"team.join",
|
|
612
|
-
"team.leave",
|
|
613
|
-
"team.resume",
|
|
614
|
-
"team.dissolve",
|
|
615
|
-
"team.save",
|
|
616
|
-
"task.cancel",
|
|
617
|
-
"task.pass"
|
|
464
|
+
"session.decide"
|
|
618
465
|
];
|
|
619
|
-
var ActionIdSchema =
|
|
466
|
+
var ActionIdSchema = z7.enum(ACTION_IDS);
|
|
620
467
|
var def = (d) => d;
|
|
621
|
-
var SessionRef =
|
|
622
|
-
var TeamRef = z11.string().trim().min(1).max(60);
|
|
623
|
-
var TaskRef = z11.string().trim().min(1).max(40);
|
|
468
|
+
var SessionRef = z7.string().trim().min(1).max(80);
|
|
624
469
|
var LaunchArgs = ProposalBlockSchema.extend({ model: ModelIdSchema.optional(), effort: EffortSchema.optional() });
|
|
625
470
|
var ACTIONS = [
|
|
626
471
|
def({
|
|
@@ -668,44 +513,20 @@ var ACTIONS = [
|
|
|
668
513
|
when: "seulement si l'utilisateur demande explicitement de cr\xE9er ou de compl\xE9ter un projet : lis projects.md, ne cite que des chemins absolus lus dans sessions.md, folders.md ou projects.md, jamais un d\xE9p\xF4t qui appartient d\xE9j\xE0 \xE0 un projet ; ta r\xE9ponse dit le nom, chaque d\xE9p\xF4t et pourquoi",
|
|
669
514
|
example: { name: "Facturation", description: "Le service et son front", repos: [{ path: "/home/alice/projets/billing-api", why: "le service" }] }
|
|
670
515
|
}),
|
|
671
|
-
def({
|
|
672
|
-
id: "team.launch",
|
|
673
|
-
args: TeamBlockSchema,
|
|
674
|
-
card: "team",
|
|
675
|
-
phone: "launch",
|
|
676
|
-
risk: "reversible",
|
|
677
|
-
max: 1,
|
|
678
|
-
cli: "ledge team up <mod\xE8le> --cwd <dossier>",
|
|
679
|
-
summary: "monter une \xE9quipe dans un dossier : un mod\xE8le de teams.md (template), ou des si\xE8ges (r\xF4le de roles.md, agent, et si demand\xE9 model, effort)",
|
|
680
|
-
when: "quand l'utilisateur demande explicitement de monter, lancer ou composer une \xE9quipe, avec la m\xEAme r\xE8gle de dossier s\xFBr qu'une session ; 8 si\xE8ges au plus, un r\xF4le une seule fois, seulement des r\xF4les de roles.md disponibles dans ce dossier (s'il en manque un, dis lequel et le fichier \xE0 \xE9crire, ~/.ledge/roles/<id>.md). Ne choisis jamais l'autonomie : c'est celle du r\xF4le",
|
|
681
|
-
example: { cwd: "/home/alice/projets/api", name: "api", seats: [{ role: "dev-back", tool: "claude" }, { role: "rev-back", tool: "codex" }] }
|
|
682
|
-
}),
|
|
683
|
-
def({
|
|
684
|
-
id: "task.give",
|
|
685
|
-
args: TaskBlockSchema,
|
|
686
|
-
card: "task",
|
|
687
|
-
phone: null,
|
|
688
|
-
risk: "reversible",
|
|
689
|
-
max: 8,
|
|
690
|
-
cli: 'ledge task give <session|@r\xF4le> "<titre>" "<d\xE9tail>"',
|
|
691
|
-
summary: "confier une t\xE2che \xE0 une session, ou \xE0 un @r\xF4le d'une \xE9quipe (team : son id dans teams.md ; sans team, un si\xE8ge de l'\xE9quipe propos\xE9e dans la m\xEAme r\xE9ponse)",
|
|
692
|
-
when: "quand l'utilisateur demande explicitement de confier une t\xE2che, ou juste apr\xE8s team.launch quand il a dit ce que l'\xE9quipe doit faire. Une fois l'\xE9quipe lanc\xE9e, ne propose rien pour ce que les si\xE8ges se confient entre eux",
|
|
693
|
-
example: { to: "@dev-back", title: "Pagination de /invoices", text: "Ajoute la pagination par curseur et ses tests" }
|
|
694
|
-
}),
|
|
695
516
|
def({
|
|
696
517
|
id: "session.model",
|
|
697
518
|
card: "generic",
|
|
698
519
|
phone: null,
|
|
699
520
|
risk: "reversible",
|
|
700
521
|
max: 8,
|
|
701
|
-
args:
|
|
522
|
+
args: z7.object({ session: SessionRef, model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
|
|
702
523
|
summary: "changer le mod\xE8le et l'effort d'une session en cours (null : le d\xE9faut de l'agent) ; elle red\xE9marre sur la m\xEAme conversation, \xE0 son prochain moment libre",
|
|
703
524
|
when: "quand l'utilisateur demande de passer une session sur un autre mod\xE8le ou un autre effort",
|
|
704
525
|
example: { session: "Nova", model: "claude-opus-5-5", effort: "high" }
|
|
705
526
|
}),
|
|
706
527
|
def({
|
|
707
528
|
id: "session.interrupt",
|
|
708
|
-
args:
|
|
529
|
+
args: z7.object({ session: SessionRef }),
|
|
709
530
|
card: "generic",
|
|
710
531
|
phone: null,
|
|
711
532
|
risk: "reversible",
|
|
@@ -716,7 +537,7 @@ var ACTIONS = [
|
|
|
716
537
|
}),
|
|
717
538
|
def({
|
|
718
539
|
id: "session.archive",
|
|
719
|
-
args:
|
|
540
|
+
args: z7.object({ session: SessionRef }),
|
|
720
541
|
card: "generic",
|
|
721
542
|
phone: null,
|
|
722
543
|
risk: "reversible",
|
|
@@ -727,7 +548,7 @@ var ACTIONS = [
|
|
|
727
548
|
}),
|
|
728
549
|
def({
|
|
729
550
|
id: "session.restore",
|
|
730
|
-
args:
|
|
551
|
+
args: z7.object({ session: SessionRef }),
|
|
731
552
|
card: "generic",
|
|
732
553
|
phone: null,
|
|
733
554
|
risk: "reversible",
|
|
@@ -738,7 +559,7 @@ var ACTIONS = [
|
|
|
738
559
|
}),
|
|
739
560
|
def({
|
|
740
561
|
id: "session.resume",
|
|
741
|
-
args:
|
|
562
|
+
args: z7.object({ session: SessionRef }),
|
|
742
563
|
card: "generic",
|
|
743
564
|
phone: "act",
|
|
744
565
|
risk: "reversible",
|
|
@@ -752,102 +573,22 @@ var ACTIONS = [
|
|
|
752
573
|
card: "generic",
|
|
753
574
|
phone: "act",
|
|
754
575
|
max: 1,
|
|
755
|
-
args:
|
|
576
|
+
args: z7.object({ session: SessionRef, decision: z7.enum(["accept", "deny"]), note: z7.string().trim().min(1).max(NOTE_MAX).optional() }),
|
|
756
577
|
risk: (a) => a.decision === "accept" ? "destructive" : "reversible",
|
|
757
578
|
summary: "accepter ou refuser la demande en attente d'une session (permission, diff ou plan), note possible avec un refus ; jamais \xAB toujours \xBB",
|
|
758
579
|
when: "seulement quand l'utilisateur demande explicitement d'accepter ou de refuser la demande d'une session pr\xE9cise, et que sessions.md montre une demande en attente pour elle ; cite la demande telle quelle dans ta r\xE9ponse",
|
|
759
580
|
example: { session: "Nova", decision: "deny", note: "Pas sur main : cr\xE9e une branche" }
|
|
760
|
-
}),
|
|
761
|
-
def({
|
|
762
|
-
id: "team.join",
|
|
763
|
-
args: z11.object({ team: TeamRef, session: SessionRef, role: RoleIdSchema }),
|
|
764
|
-
card: "generic",
|
|
765
|
-
phone: null,
|
|
766
|
-
risk: "reversible",
|
|
767
|
-
max: 8,
|
|
768
|
-
summary: "faire entrer une session dans une \xE9quipe en cours, \xE0 un r\xF4le de roles.md",
|
|
769
|
-
when: "quand l'utilisateur demande d'ajouter une session existante \xE0 une \xE9quipe",
|
|
770
|
-
example: { team: "team-3fa2", session: "Nova", role: "dev-back" }
|
|
771
|
-
}),
|
|
772
|
-
def({
|
|
773
|
-
id: "team.leave",
|
|
774
|
-
args: z11.object({ team: TeamRef, session: SessionRef }),
|
|
775
|
-
card: "generic",
|
|
776
|
-
phone: null,
|
|
777
|
-
risk: "reversible",
|
|
778
|
-
max: 8,
|
|
779
|
-
summary: "faire sortir une session d'une \xE9quipe (la session continue)",
|
|
780
|
-
when: "quand l'utilisateur demande de retirer une session d'une \xE9quipe",
|
|
781
|
-
example: { team: "team-3fa2", session: "Nova" }
|
|
782
|
-
}),
|
|
783
|
-
def({
|
|
784
|
-
id: "team.resume",
|
|
785
|
-
args: z11.object({ team: TeamRef }),
|
|
786
|
-
card: "generic",
|
|
787
|
-
phone: "act",
|
|
788
|
-
risk: "reversible",
|
|
789
|
-
max: 1,
|
|
790
|
-
summary: "reprendre une \xE9quipe au repos : chaque si\xE8ge reprend sa conversation",
|
|
791
|
-
when: "quand l'utilisateur demande de reprendre ou relancer une \xE9quipe au repos",
|
|
792
|
-
example: { team: "team-3fa2" }
|
|
793
|
-
}),
|
|
794
|
-
def({
|
|
795
|
-
id: "team.dissolve",
|
|
796
|
-
args: z11.object({ team: TeamRef }),
|
|
797
|
-
card: "generic",
|
|
798
|
-
phone: "act",
|
|
799
|
-
risk: "destructive",
|
|
800
|
-
max: 1,
|
|
801
|
-
cli: "ledge team dissolve <\xE9quipe>",
|
|
802
|
-
summary: "dissoudre une \xE9quipe : elle dispara\xEEt, ses sessions restent ; irr\xE9versible",
|
|
803
|
-
when: "seulement quand l'utilisateur demande explicitement de dissoudre une \xE9quipe pr\xE9cise",
|
|
804
|
-
example: { team: "team-3fa2" }
|
|
805
|
-
}),
|
|
806
|
-
def({
|
|
807
|
-
id: "team.save",
|
|
808
|
-
args: z11.object({ team: TeamRef, name: TeamNameSchema }),
|
|
809
|
-
card: "generic",
|
|
810
|
-
phone: null,
|
|
811
|
-
risk: "reversible",
|
|
812
|
-
max: 1,
|
|
813
|
-
summary: "enregistrer une \xE9quipe en cours comme mod\xE8le (~/.ledge/teams/<nom>.yaml)",
|
|
814
|
-
when: "quand l'utilisateur demande d'enregistrer ou de garder la composition d'une \xE9quipe",
|
|
815
|
-
example: { team: "team-3fa2", name: "api" }
|
|
816
|
-
}),
|
|
817
|
-
def({
|
|
818
|
-
id: "task.cancel",
|
|
819
|
-
args: z11.object({ task: TaskRef, reason: z11.string().trim().min(1).max(500).optional() }),
|
|
820
|
-
card: "generic",
|
|
821
|
-
phone: "act",
|
|
822
|
-
risk: "destructive",
|
|
823
|
-
max: 8,
|
|
824
|
-
summary: "annuler une t\xE2che ouverte ou prise ; la session qui la tient est pr\xE9venue ; irr\xE9versible",
|
|
825
|
-
when: "seulement quand l'utilisateur demande explicitement d'annuler une t\xE2che de tasks.md",
|
|
826
|
-
example: { task: "t91b0d4", reason: "Plus n\xE9cessaire" }
|
|
827
|
-
}),
|
|
828
|
-
def({
|
|
829
|
-
id: "task.pass",
|
|
830
|
-
args: z11.object({ task: TaskRef, to: SessionRef, note: z11.string().trim().min(1).max(TASK_TEXT_MAX).optional() }),
|
|
831
|
-
card: "generic",
|
|
832
|
-
phone: null,
|
|
833
|
-
risk: "reversible",
|
|
834
|
-
max: 8,
|
|
835
|
-
summary: "passer une t\xE2che de tasks.md \xE0 une autre session (elle redevient ouverte)",
|
|
836
|
-
when: "quand l'utilisateur demande de r\xE9assigner ou de passer une t\xE2che \xE0 une autre session",
|
|
837
|
-
example: { task: "t91b0d4", to: "Bix" }
|
|
838
581
|
})
|
|
839
582
|
];
|
|
840
583
|
var byId = new Map(ACTIONS.map((a) => [a.id, a]));
|
|
841
|
-
var actionById = (
|
|
584
|
+
var actionById = (id2) => byId.get(id2);
|
|
842
585
|
var riskOf = (a, args) => typeof a.risk === "function" ? a.risk(args) : a.risk;
|
|
843
|
-
var ActionBlockSchema =
|
|
586
|
+
var ActionBlockSchema = z7.object({ action: z7.string().trim().min(1).max(40), args: z7.record(z7.unknown()).default({}) });
|
|
844
587
|
var LEGACY_FENCE_ACTION = {
|
|
845
588
|
session: "session.launch",
|
|
846
589
|
relay: "session.relay",
|
|
847
590
|
close: "session.close",
|
|
848
|
-
project: "project.propose"
|
|
849
|
-
team: "team.launch",
|
|
850
|
-
task: "task.give"
|
|
591
|
+
project: "project.propose"
|
|
851
592
|
};
|
|
852
593
|
function parseActionBlock(kind, raw) {
|
|
853
594
|
let json;
|
|
@@ -856,21 +597,21 @@ function parseActionBlock(kind, raw) {
|
|
|
856
597
|
} catch {
|
|
857
598
|
return { error: "invalid JSON" };
|
|
858
599
|
}
|
|
859
|
-
let
|
|
600
|
+
let id2;
|
|
860
601
|
let args;
|
|
861
602
|
if (kind === "action") {
|
|
862
603
|
const b = ActionBlockSchema.safeParse(json);
|
|
863
604
|
if (!b.success) return { error: "not an {action, args} object" };
|
|
864
|
-
|
|
605
|
+
id2 = b.data.action;
|
|
865
606
|
args = b.data.args;
|
|
866
607
|
} else {
|
|
867
|
-
|
|
608
|
+
id2 = LEGACY_FENCE_ACTION[kind];
|
|
868
609
|
args = json;
|
|
869
610
|
}
|
|
870
|
-
const action = actionById(
|
|
871
|
-
if (!action) return { error: `unknown action ${
|
|
611
|
+
const action = actionById(id2);
|
|
612
|
+
if (!action) return { error: `unknown action ${id2}` };
|
|
872
613
|
const parsed = action.args.safeParse(args);
|
|
873
|
-
if (!parsed.success) return { error: `invalid args for ${
|
|
614
|
+
if (!parsed.success) return { error: `invalid args for ${id2}: ${parsed.error.issues.map((i) => `${i.path.join(".") || "(root)"} ${i.message}`).join("; ")}` };
|
|
874
615
|
return { action, args: parsed.data };
|
|
875
616
|
}
|
|
876
617
|
var NEVER_PROPOSED = [
|
|
@@ -882,123 +623,89 @@ var NEVER_PROPOSED = [
|
|
|
882
623
|
"r\xE9pondre \xAB toujours \xBB \xE0 une demande, ou r\xE9pondre aux questions \xE0 choix d'OMP"
|
|
883
624
|
];
|
|
884
625
|
|
|
885
|
-
// ../protocol/src/
|
|
886
|
-
import { z as
|
|
626
|
+
// ../protocol/src/openrig.ts
|
|
627
|
+
import { z as z10 } from "zod";
|
|
887
628
|
|
|
888
629
|
// ../protocol/src/chat.ts
|
|
889
|
-
import { z as
|
|
630
|
+
import { z as z9 } from "zod";
|
|
890
631
|
|
|
891
632
|
// ../protocol/src/attachments.ts
|
|
892
|
-
import { z as
|
|
633
|
+
import { z as z8 } from "zod";
|
|
893
634
|
var ATTACHMENT_ID = /^[0-9a-f]{64}$/;
|
|
894
|
-
var AttachmentIdSchema =
|
|
635
|
+
var AttachmentIdSchema = z8.string().regex(ATTACHMENT_ID);
|
|
895
636
|
var IMAGE_MIMES = ["image/webp", "image/jpeg", "image/png", "image/gif"];
|
|
896
|
-
var ImageMimeSchema =
|
|
637
|
+
var ImageMimeSchema = z8.enum(IMAGE_MIMES);
|
|
897
638
|
var ATTACHMENT_MAX = 4e5;
|
|
898
639
|
var ATTACHMENT_LOCAL_MAX = 2e6;
|
|
899
640
|
var PREVIEW_MAX = 4e4;
|
|
900
641
|
var ATTACHMENTS_MAX = 5;
|
|
901
642
|
var b64Max = (bytes) => Math.ceil(bytes / 3) * 4;
|
|
902
|
-
var AttachmentRefSchema =
|
|
643
|
+
var AttachmentRefSchema = z8.object({
|
|
903
644
|
id: AttachmentIdSchema,
|
|
904
645
|
mime: ImageMimeSchema,
|
|
905
|
-
width:
|
|
906
|
-
height:
|
|
907
|
-
bytes:
|
|
908
|
-
preview:
|
|
646
|
+
width: z8.number().int().positive(),
|
|
647
|
+
height: z8.number().int().positive(),
|
|
648
|
+
bytes: z8.number().int().positive(),
|
|
649
|
+
preview: z8.boolean()
|
|
909
650
|
});
|
|
910
|
-
var ImageUploadSchema =
|
|
651
|
+
var ImageUploadSchema = z8.object({
|
|
911
652
|
mime: ImageMimeSchema,
|
|
912
|
-
data:
|
|
913
|
-
preview:
|
|
914
|
-
});
|
|
915
|
-
var AttachmentErrorReasonSchema =
|
|
916
|
-
var requestId =
|
|
917
|
-
var AttachmentPutSchema =
|
|
918
|
-
var AttachmentGetSchema =
|
|
919
|
-
var AttachmentStoredSchema =
|
|
920
|
-
var AttachmentDataSchema =
|
|
921
|
-
var AttachmentErrorSchema =
|
|
653
|
+
data: z8.string().min(1).max(b64Max(ATTACHMENT_LOCAL_MAX)),
|
|
654
|
+
preview: z8.object({ mime: ImageMimeSchema, data: z8.string().min(1).max(b64Max(PREVIEW_MAX)) }).optional()
|
|
655
|
+
});
|
|
656
|
+
var AttachmentErrorReasonSchema = z8.enum(["too_large", "not_image", "unreadable", "not_found", "offline"]);
|
|
657
|
+
var requestId = z8.string().min(1).max(100);
|
|
658
|
+
var AttachmentPutSchema = z8.object({ type: z8.literal("attachment.put"), requestId, id: z8.string().optional(), image: ImageUploadSchema });
|
|
659
|
+
var AttachmentGetSchema = z8.object({ type: z8.literal("attachment.get"), requestId, attachment: AttachmentIdSchema, preview: z8.boolean().optional(), id: z8.string().optional(), machine: z8.string().optional() });
|
|
660
|
+
var AttachmentStoredSchema = z8.object({ type: z8.literal("attachment.stored"), requestId, ref: AttachmentRefSchema });
|
|
661
|
+
var AttachmentDataSchema = z8.object({ type: z8.literal("attachment.data"), requestId, attachment: AttachmentIdSchema, mime: ImageMimeSchema, data: z8.string() });
|
|
662
|
+
var AttachmentErrorSchema = z8.object({ type: z8.literal("attachment.error"), requestId, reason: AttachmentErrorReasonSchema });
|
|
922
663
|
|
|
923
664
|
// ../protocol/src/chat.ts
|
|
924
|
-
var ChatStepSchema =
|
|
925
|
-
kind:
|
|
926
|
-
id:
|
|
927
|
-
name:
|
|
928
|
-
path:
|
|
929
|
-
});
|
|
930
|
-
var ChatProposalSchema =
|
|
931
|
-
cwd:
|
|
932
|
-
project:
|
|
933
|
-
prompt:
|
|
665
|
+
var ChatStepSchema = z9.object({
|
|
666
|
+
kind: z9.enum(["sessions", "pane", "reply", "git", "repo"]),
|
|
667
|
+
id: z9.string().optional(),
|
|
668
|
+
name: z9.string().optional(),
|
|
669
|
+
path: z9.string().optional()
|
|
670
|
+
});
|
|
671
|
+
var ChatProposalSchema = z9.object({
|
|
672
|
+
cwd: z9.string().min(1),
|
|
673
|
+
project: z9.string(),
|
|
674
|
+
prompt: z9.string().optional(),
|
|
934
675
|
tool: ToolSchema,
|
|
935
676
|
/** What Ledge proposed on the card's picker (spec 2026-10-26 action registry §4), the agent's own default when left out. */
|
|
936
677
|
model: ModelIdSchema.optional(),
|
|
937
678
|
effort: EffortSchema.optional(),
|
|
938
|
-
launchedId:
|
|
939
|
-
error:
|
|
679
|
+
launchedId: z9.string().optional(),
|
|
680
|
+
error: z9.string().optional()
|
|
940
681
|
});
|
|
941
682
|
var MAX_PROPOSALS = 8;
|
|
942
|
-
var ChatProposalsSchema =
|
|
943
|
-
var ChatRelaySchema =
|
|
944
|
-
id:
|
|
945
|
-
name:
|
|
946
|
-
tool: ToolSchema,
|
|
947
|
-
text: z13.string().min(1),
|
|
948
|
-
status: z13.enum(["queued", "sent"]).optional(),
|
|
949
|
-
sentAt: z13.string().datetime().optional(),
|
|
950
|
-
error: z13.string().optional()
|
|
951
|
-
});
|
|
952
|
-
var ChatCloseSchema = z13.object({
|
|
953
|
-
id: z13.string().min(1),
|
|
954
|
-
name: z13.string(),
|
|
683
|
+
var ChatProposalsSchema = z9.array(ChatProposalSchema).min(1).max(MAX_PROPOSALS);
|
|
684
|
+
var ChatRelaySchema = z9.object({
|
|
685
|
+
id: z9.string().min(1),
|
|
686
|
+
name: z9.string(),
|
|
955
687
|
tool: ToolSchema,
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
var
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
repos: z13.array(z13.object({ path: z13.string().min(1).max(4096), why: z13.string().min(1).max(200) })).min(1).max(50),
|
|
965
|
-
addTo: z13.string().min(1).max(80).optional()
|
|
966
|
-
});
|
|
967
|
-
var ChatTeamSeatSchema = z13.object({
|
|
968
|
-
role: z13.string().min(1),
|
|
969
|
-
label: z13.string(),
|
|
688
|
+
text: z9.string().min(1),
|
|
689
|
+
status: z9.enum(["queued", "sent"]).optional(),
|
|
690
|
+
sentAt: z9.string().datetime().optional(),
|
|
691
|
+
error: z9.string().optional()
|
|
692
|
+
});
|
|
693
|
+
var ChatCloseSchema = z9.object({
|
|
694
|
+
id: z9.string().min(1),
|
|
695
|
+
name: z9.string(),
|
|
970
696
|
tool: ToolSchema,
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
var
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
teamId: z13.string().optional(),
|
|
984
|
-
launchedAt: z13.string().datetime().optional(),
|
|
985
|
-
error: z13.string().optional(),
|
|
986
|
-
savedPath: z13.string().optional()
|
|
987
|
-
});
|
|
988
|
-
var ChatTaskProposalSchema = z13.object({
|
|
989
|
-
to: z13.string().min(1),
|
|
990
|
-
toName: z13.string().optional(),
|
|
991
|
-
team: z13.string().optional(),
|
|
992
|
-
title: z13.string().min(1).max(200),
|
|
993
|
-
text: z13.string().max(2e4).optional(),
|
|
994
|
-
taskId: z13.string().optional(),
|
|
995
|
-
ownerName: z13.string().optional(),
|
|
996
|
-
state: z13.enum(["open", "taken", "done", "refused", "dropped"]).optional(),
|
|
997
|
-
givenAt: z13.string().datetime().optional(),
|
|
998
|
-
error: z13.string().optional()
|
|
999
|
-
});
|
|
1000
|
-
var ChatTasksSchema = z13.array(ChatTaskProposalSchema).min(1).max(MAX_PROPOSALS);
|
|
1001
|
-
var ActionVarsSchema = z13.record(z13.string().max(40), z13.string().max(300));
|
|
697
|
+
closedAt: z9.string().datetime().optional(),
|
|
698
|
+
how: z9.enum(["exit", "killed"]).optional(),
|
|
699
|
+
error: z9.string().optional()
|
|
700
|
+
});
|
|
701
|
+
var ChatClosesSchema = z9.array(ChatCloseSchema).min(1).max(MAX_PROPOSALS);
|
|
702
|
+
var ChatProjectProposalSchema = z9.object({
|
|
703
|
+
name: z9.string().min(1).max(80),
|
|
704
|
+
description: z9.string().max(500).optional(),
|
|
705
|
+
repos: z9.array(z9.object({ path: z9.string().min(1).max(4096), why: z9.string().min(1).max(200) })).min(1).max(50),
|
|
706
|
+
addTo: z9.string().min(1).max(80).optional()
|
|
707
|
+
});
|
|
708
|
+
var ActionVarsSchema = z9.record(z9.string().max(40), z9.string().max(300));
|
|
1002
709
|
var DETAIL_MAX = 4e3;
|
|
1003
710
|
var ACTION_ERROR_CODES = [
|
|
1004
711
|
"unknown",
|
|
@@ -1013,98 +720,381 @@ var ACTION_ERROR_CODES = [
|
|
|
1013
720
|
"no_request",
|
|
1014
721
|
"in_session",
|
|
1015
722
|
"no_note",
|
|
1016
|
-
"member",
|
|
1017
|
-
"not_member",
|
|
1018
|
-
"unknown_role",
|
|
1019
|
-
"not_resting",
|
|
1020
|
-
"dissolved",
|
|
1021
|
-
"no_seat",
|
|
1022
|
-
"closed",
|
|
1023
|
-
"holder",
|
|
1024
723
|
"changed",
|
|
1025
724
|
"cut",
|
|
1026
725
|
"failed"
|
|
1027
726
|
];
|
|
1028
|
-
var ChatActionStateSchema =
|
|
1029
|
-
var ChatActionSchema =
|
|
1030
|
-
action:
|
|
1031
|
-
args:
|
|
1032
|
-
summary:
|
|
727
|
+
var ChatActionStateSchema = z9.enum(["running", "done", "denied", "failed", "refused"]);
|
|
728
|
+
var ChatActionSchema = z9.object({
|
|
729
|
+
action: z9.string().min(1).max(40),
|
|
730
|
+
args: z9.record(z9.unknown()),
|
|
731
|
+
summary: z9.string().min(1).max(300),
|
|
1033
732
|
vars: ActionVarsSchema.optional(),
|
|
1034
|
-
detail:
|
|
1035
|
-
detailCut:
|
|
733
|
+
detail: z9.string().max(DETAIL_MAX).optional(),
|
|
734
|
+
detailCut: z9.literal(true).optional(),
|
|
1036
735
|
risk: ActionRiskSchema,
|
|
1037
|
-
session:
|
|
1038
|
-
team: z13.string().optional(),
|
|
736
|
+
session: z9.string().optional(),
|
|
1039
737
|
state: ChatActionStateSchema.optional(),
|
|
1040
|
-
doneAt:
|
|
1041
|
-
error:
|
|
1042
|
-
code:
|
|
738
|
+
doneAt: z9.string().datetime().optional(),
|
|
739
|
+
error: z9.string().optional(),
|
|
740
|
+
code: z9.string().max(40).optional()
|
|
1043
741
|
});
|
|
1044
|
-
var ChatActionsSchema =
|
|
1045
|
-
var
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
742
|
+
var ChatActionsSchema = z9.array(ChatActionSchema).min(1).max(MAX_PROPOSALS);
|
|
743
|
+
var ChatRigLaunchSchema = z9.object({
|
|
744
|
+
spec: z9.string().min(1).max(200).optional(),
|
|
745
|
+
goal: z9.string().min(1).max(8e3),
|
|
746
|
+
project: z9.string().min(1).optional(),
|
|
747
|
+
off: z9.string().min(1).max(40).optional(),
|
|
748
|
+
machine: z9.string().min(1).optional()
|
|
749
|
+
});
|
|
750
|
+
var ChatTurnSchema = z9.object({
|
|
751
|
+
machineId: z9.string().optional(),
|
|
752
|
+
machineName: z9.string().optional(),
|
|
753
|
+
choices: z9.array(z9.object({ id: z9.string(), label: z9.string() })).optional(),
|
|
754
|
+
qid: z9.string().min(1),
|
|
755
|
+
question: z9.string(),
|
|
756
|
+
askedAt: z9.string().datetime(),
|
|
757
|
+
steps: z9.array(ChatStepSchema),
|
|
758
|
+
answer: z9.string().optional(),
|
|
759
|
+
answeredAt: z9.string().datetime().optional(),
|
|
760
|
+
error: z9.string().optional(),
|
|
1056
761
|
proposal: ChatProposalSchema.optional(),
|
|
1057
762
|
proposals: ChatProposalsSchema.optional(),
|
|
1058
763
|
relay: ChatRelaySchema.optional(),
|
|
1059
764
|
closes: ChatClosesSchema.optional(),
|
|
1060
765
|
projectProposal: ChatProjectProposalSchema.optional(),
|
|
1061
|
-
team: ChatTeamProposalSchema.optional(),
|
|
1062
|
-
tasks: ChatTasksSchema.optional(),
|
|
1063
766
|
actions: ChatActionsSchema.optional(),
|
|
1064
|
-
|
|
1065
|
-
|
|
767
|
+
rigLaunch: ChatRigLaunchSchema.optional(),
|
|
768
|
+
ignoredAt: z9.string().datetime().optional(),
|
|
769
|
+
attachments: z9.array(AttachmentRefSchema).optional()
|
|
1066
770
|
});
|
|
1067
771
|
var proposalRows = (t) => t?.proposals ?? (t?.proposal ? [t.proposal] : []);
|
|
1068
772
|
|
|
773
|
+
// ../protocol/src/openrig.ts
|
|
774
|
+
var MandateCategorySchema = z10.enum(["git", "tests", "context", "code", "design", "architecture", "critical"]);
|
|
775
|
+
var ALWAYS_USER = ["design", "architecture", "critical"];
|
|
776
|
+
var MANDATE_CATEGORY_LABEL = {
|
|
777
|
+
git: { fr: "Git et branches", en: "Git and branches" },
|
|
778
|
+
tests: { fr: "Tests et relectures", en: "Tests and reviews" },
|
|
779
|
+
context: { fr: "Contexte et rel\xE8ves", en: "Context and handovers" },
|
|
780
|
+
code: { fr: "Petits choix de code", en: "Small code choices" },
|
|
781
|
+
design: { fr: "Design", en: "Design" },
|
|
782
|
+
architecture: { fr: "Architecture", en: "Architecture" },
|
|
783
|
+
critical: { fr: "Critique", en: "Critical" }
|
|
784
|
+
};
|
|
785
|
+
var OpenRigStateSchema = z10.enum(["absent", "stopped", "starting", "running", "unsupported", "error", "unreachable"]);
|
|
786
|
+
var OpenRigStatusSchema = z10.object({
|
|
787
|
+
machine: z10.string(),
|
|
788
|
+
state: OpenRigStateSchema,
|
|
789
|
+
version: z10.string().optional(),
|
|
790
|
+
human: z10.enum(["registered", "missing", "failed"]).optional(),
|
|
791
|
+
detail: z10.string().optional(),
|
|
792
|
+
install: z10.string().optional()
|
|
793
|
+
});
|
|
794
|
+
var SeatStateSchema = z10.enum(["starting", "trust", "attention", "ready", "working", "idle", "stopped", "crashed", "unreachable"]);
|
|
795
|
+
var RigSeatSchema = z10.object({
|
|
796
|
+
ref: z10.string(),
|
|
797
|
+
// OpenRig session name: "dev-build@starter"
|
|
798
|
+
address: z10.string(),
|
|
799
|
+
// "@build"
|
|
800
|
+
name: z10.string(),
|
|
801
|
+
runtime: z10.string(),
|
|
802
|
+
model: z10.string().optional(),
|
|
803
|
+
state: SeatStateSchema,
|
|
804
|
+
contextPct: z10.number().min(0).max(100).optional(),
|
|
805
|
+
sessionId: z10.string().optional()
|
|
806
|
+
});
|
|
807
|
+
var RigRepoSchema = z10.object({
|
|
808
|
+
path: z10.string(),
|
|
809
|
+
name: z10.string(),
|
|
810
|
+
branch: z10.string().optional(),
|
|
811
|
+
remote: z10.string().optional(),
|
|
812
|
+
modified: z10.number().int().min(0),
|
|
813
|
+
by: z10.string().optional(),
|
|
814
|
+
how: z10.enum(["cloned", "opened", "created"]).optional()
|
|
815
|
+
});
|
|
816
|
+
var RigLifecycleSchema = z10.enum(["launching", "running", "partial", "stopped", "unreachable"]);
|
|
817
|
+
var RIG_NAME = /^[a-z0-9][a-z0-9-]{0,39}$/;
|
|
818
|
+
var RigLaunchInfoSchema = z10.object({
|
|
819
|
+
planId: z10.string(),
|
|
820
|
+
goal: z10.string(),
|
|
821
|
+
lead: z10.string(),
|
|
822
|
+
startedAt: z10.string().datetime(),
|
|
823
|
+
goalSentAt: z10.string().datetime().optional(),
|
|
824
|
+
lateNotice: z10.boolean().optional()
|
|
825
|
+
});
|
|
826
|
+
var RigSchema = z10.object({
|
|
827
|
+
id: z10.string(),
|
|
828
|
+
name: z10.string(),
|
|
829
|
+
machine: z10.string(),
|
|
830
|
+
spec: z10.string().optional(),
|
|
831
|
+
cwd: z10.string(),
|
|
832
|
+
projectId: z10.string().nullable(),
|
|
833
|
+
offProject: z10.boolean(),
|
|
834
|
+
branch: z10.string().optional(),
|
|
835
|
+
lifecycle: RigLifecycleSchema,
|
|
836
|
+
kernel: z10.boolean(),
|
|
837
|
+
seats: z10.array(RigSeatSchema),
|
|
838
|
+
repos: z10.array(RigRepoSchema),
|
|
839
|
+
launch: RigLaunchInfoSchema.optional()
|
|
840
|
+
});
|
|
841
|
+
var EscalationQuestionSchema = z10.object({
|
|
842
|
+
id: z10.string(),
|
|
843
|
+
question: z10.string(),
|
|
844
|
+
options: z10.array(z10.object({ id: z10.string(), label: z10.string(), recommended: z10.boolean().optional() })).min(2).max(4)
|
|
845
|
+
});
|
|
846
|
+
var EscalationStateSchema = z10.enum(["pending", "grace", "answered", "closed"]);
|
|
847
|
+
var EscalationSchema = z10.object({
|
|
848
|
+
id: z10.string(),
|
|
849
|
+
// OpenRig qitemId, or "ask-<id>" for `ledge ask`
|
|
850
|
+
source: z10.enum(["rig", "operator", "ask"]),
|
|
851
|
+
machine: z10.string(),
|
|
852
|
+
rigId: z10.string().optional(),
|
|
853
|
+
from: z10.string(),
|
|
854
|
+
// seat ref, or the Ledge session name for `ask`
|
|
855
|
+
intent: z10.enum(["decision", "update"]),
|
|
856
|
+
summary: z10.string(),
|
|
857
|
+
detail: z10.string().optional(),
|
|
858
|
+
evidenceRef: z10.string().optional(),
|
|
859
|
+
questions: z10.array(EscalationQuestionSchema).max(4),
|
|
860
|
+
replyTo: z10.string().optional(),
|
|
861
|
+
createdAt: z10.string().datetime(),
|
|
862
|
+
state: EscalationStateSchema,
|
|
863
|
+
graceUntil: z10.string().datetime().optional(),
|
|
864
|
+
correcting: z10.string().optional(),
|
|
865
|
+
// id of the decision being corrected (Revenir dessus)
|
|
866
|
+
category: MandateCategorySchema.optional(),
|
|
867
|
+
advice: z10.string().optional(),
|
|
868
|
+
answer: z10.object({
|
|
869
|
+
by: z10.enum(["ledge", "user"]),
|
|
870
|
+
answers: z10.record(z10.string()),
|
|
871
|
+
at: z10.string().datetime(),
|
|
872
|
+
rule: z10.string().optional(),
|
|
873
|
+
delivery: z10.enum(["queued", "sent"]).optional()
|
|
874
|
+
}).optional()
|
|
875
|
+
});
|
|
876
|
+
var ExchangeSchema = z10.object({
|
|
877
|
+
id: z10.string(),
|
|
878
|
+
machine: z10.string(),
|
|
879
|
+
rigId: z10.string(),
|
|
880
|
+
from: z10.string(),
|
|
881
|
+
to: z10.string(),
|
|
882
|
+
kind: z10.enum(["message", "task", "handoff", "ledge"]),
|
|
883
|
+
text: z10.string(),
|
|
884
|
+
at: z10.string().datetime()
|
|
885
|
+
});
|
|
886
|
+
var EXCHANGES_MAX = 200;
|
|
887
|
+
var EXCHANGE_GROUP_MS = 6e5;
|
|
888
|
+
var THREAD_PAGE = 50;
|
|
889
|
+
var LedgeDecisionSchema = z10.object({
|
|
890
|
+
id: z10.string(),
|
|
891
|
+
escalationId: z10.string(),
|
|
892
|
+
by: z10.enum(["ledge", "user"]),
|
|
893
|
+
category: MandateCategorySchema.optional(),
|
|
894
|
+
// absent: a user answer on an uncategorised escalation (never guessed)
|
|
895
|
+
summary: z10.string(),
|
|
896
|
+
answers: z10.record(z10.string()),
|
|
897
|
+
rule: z10.string().optional(),
|
|
898
|
+
from: z10.string().optional(),
|
|
899
|
+
rigId: z10.string().optional(),
|
|
900
|
+
// the seat and rig the decision was for
|
|
901
|
+
why: z10.string().optional(),
|
|
902
|
+
at: z10.string().datetime(),
|
|
903
|
+
revisitedBy: z10.string().optional()
|
|
904
|
+
});
|
|
905
|
+
var LedgeRuleSchema = z10.object({
|
|
906
|
+
id: z10.string(),
|
|
907
|
+
text: z10.string(),
|
|
908
|
+
category: MandateCategorySchema,
|
|
909
|
+
since: z10.string(),
|
|
910
|
+
from: z10.string(),
|
|
911
|
+
appliedCount: z10.number().int().min(0),
|
|
912
|
+
status: z10.enum(["active", "proposed"])
|
|
913
|
+
});
|
|
914
|
+
var LedgeThreadItemSchema = z10.discriminatedUnion("kind", [
|
|
915
|
+
z10.object({
|
|
916
|
+
kind: z10.literal("user"),
|
|
917
|
+
id: z10.string(),
|
|
918
|
+
at: z10.string().datetime(),
|
|
919
|
+
text: z10.string(),
|
|
920
|
+
to: z10.string().optional(),
|
|
921
|
+
// to = "@build"
|
|
922
|
+
qid: z10.string().optional()
|
|
923
|
+
}),
|
|
924
|
+
z10.object({
|
|
925
|
+
kind: z10.literal("ledge"),
|
|
926
|
+
id: z10.string(),
|
|
927
|
+
at: z10.string().datetime(),
|
|
928
|
+
text: z10.string(),
|
|
929
|
+
qid: z10.string().optional(),
|
|
930
|
+
pending: z10.literal(true).optional()
|
|
931
|
+
}),
|
|
932
|
+
z10.object({ kind: z10.literal("escalation"), id: z10.string(), at: z10.string().datetime(), escalationId: z10.string() }),
|
|
933
|
+
z10.object({ kind: z10.literal("decided"), id: z10.string(), at: z10.string().datetime(), decisionId: z10.string() }),
|
|
934
|
+
z10.object({
|
|
935
|
+
kind: z10.literal("exchanges"),
|
|
936
|
+
id: z10.string(),
|
|
937
|
+
at: z10.string().datetime(),
|
|
938
|
+
machine: z10.string(),
|
|
939
|
+
rigId: z10.string(),
|
|
940
|
+
from: z10.string().datetime(),
|
|
941
|
+
to: z10.string().datetime(),
|
|
942
|
+
exchangeIds: z10.array(z10.string())
|
|
943
|
+
}),
|
|
944
|
+
z10.object({ kind: z10.literal("card"), id: z10.string(), at: z10.string().datetime(), action: ChatActionSchema })
|
|
945
|
+
// existing action card
|
|
946
|
+
]);
|
|
947
|
+
var BrainStatusSchema = z10.object({
|
|
948
|
+
state: z10.enum(["off", "starting", "on", "down"]),
|
|
949
|
+
tool: ToolSchema,
|
|
950
|
+
contextPct: z10.number().optional(),
|
|
951
|
+
sessionId: z10.string().optional(),
|
|
952
|
+
enabled: z10.boolean().nullable().optional(),
|
|
953
|
+
// null: the user was never asked
|
|
954
|
+
restarts: z10.number().int().min(0).optional(),
|
|
955
|
+
reason: z10.string().optional()
|
|
956
|
+
});
|
|
957
|
+
var RigLaunchWhereSchema = z10.discriminatedUnion("kind", [
|
|
958
|
+
z10.object({ kind: z10.literal("project"), projectId: z10.string(), repo: z10.string(), branch: z10.string(), copy: z10.boolean() }),
|
|
959
|
+
z10.object({ kind: z10.literal("off-project"), name: z10.string() })
|
|
960
|
+
]);
|
|
961
|
+
var RigPlanSchema = z10.object({
|
|
962
|
+
id: z10.string(),
|
|
963
|
+
machine: z10.string(),
|
|
964
|
+
spec: z10.string(),
|
|
965
|
+
goal: z10.string(),
|
|
966
|
+
where: RigLaunchWhereSchema,
|
|
967
|
+
cwd: z10.string(),
|
|
968
|
+
seats: z10.array(z10.object({ address: z10.string(), runtime: z10.string(), model: z10.string().optional(), autonomy: z10.string() })),
|
|
969
|
+
writes: z10.array(z10.string()),
|
|
970
|
+
command: z10.string(),
|
|
971
|
+
required: z10.boolean()
|
|
972
|
+
});
|
|
973
|
+
var RigVerbSchema = z10.enum(["up", "down", "restore", "restart", "stop", "handover"]);
|
|
974
|
+
var RIG_RESULT_CODES = ["rig_managed", "already_answered", "openrig_down", "unsupported", "mandate", "unreachable", "failed", "invalid"];
|
|
975
|
+
var RigResultCodeSchema = z10.enum(RIG_RESULT_CODES);
|
|
976
|
+
var BRAIN_OPS = ["say", "decide", "ask", "rig", "send", "propose", "remember", "who", "rigs", "escalations", "rules", "handover"];
|
|
977
|
+
var BRAIN_RESULT_CODES = ["not_brain", "identity", "mandate", "grace", "invalid", "refused", "already_answered", "failed", "unreachable", "openrig_down"];
|
|
978
|
+
var BrainResultCodeSchema = z10.enum(BRAIN_RESULT_CODES);
|
|
979
|
+
var BRAIN_STOPPED_TEXT = "Ledge est arr\xEAt\xE9 \xB7 D\xE9marrer";
|
|
980
|
+
var OpenRigStatusMessageSchema = z10.object({ type: z10.literal("openrig.status"), status: OpenRigStatusSchema });
|
|
981
|
+
var RigSnapshotSchema = z10.object({ type: z10.literal("rig.snapshot"), machine: z10.string(), rigs: z10.array(RigSchema) });
|
|
982
|
+
var RigUpdatedSchema = z10.object({ type: z10.literal("rig.updated"), rig: RigSchema });
|
|
983
|
+
var RigRemovedSchema = z10.object({ type: z10.literal("rig.removed"), machine: z10.string(), rigId: z10.string() });
|
|
984
|
+
var RigExchangeSchema = z10.object({ type: z10.literal("rig.exchange"), exchange: ExchangeSchema });
|
|
985
|
+
var RigExchangesSchema = z10.object({ type: z10.literal("rig.exchanges"), machine: z10.string(), rigId: z10.string(), items: z10.array(ExchangeSchema) });
|
|
986
|
+
var EscalationUpdatedSchema = z10.object({ type: z10.literal("escalation.updated"), escalation: EscalationSchema });
|
|
987
|
+
var EscalationRemovedSchema = z10.object({ type: z10.literal("escalation.removed"), id: z10.string() });
|
|
988
|
+
var LedgeThreadItemMessageSchema = z10.object({ type: z10.literal("ledge.thread.item"), item: LedgeThreadItemSchema });
|
|
989
|
+
var LedgeThreadHistorySchema = z10.object({ type: z10.literal("ledge.thread.history"), items: z10.array(LedgeThreadItemSchema), before: z10.string().optional() });
|
|
990
|
+
var DecisionsMessageSchema = z10.object({ type: z10.literal("decisions"), items: z10.array(LedgeDecisionSchema) });
|
|
991
|
+
var RulesMessageSchema = z10.object({ type: z10.literal("rules"), items: z10.array(LedgeRuleSchema) });
|
|
992
|
+
var MandateMessageSchema = z10.object({ type: z10.literal("mandate"), text: z10.string(), path: z10.string() });
|
|
993
|
+
var BrainStatusMessageSchema = z10.object({ type: z10.literal("brain.status"), status: BrainStatusSchema });
|
|
994
|
+
var RigPlanMessageSchema = z10.object({ type: z10.literal("rig.plan"), rid: z10.string(), plan: RigPlanSchema });
|
|
995
|
+
var BrainResultSchema = z10.object({ type: z10.literal("brain.result"), rid: z10.string(), ok: z10.boolean(), line: z10.string(), code: BrainResultCodeSchema.optional() });
|
|
996
|
+
var BrainDelegateClaimSchema = z10.object({ type: z10.literal("brain.delegate.claim"), rid: z10.string().min(1).max(100), id: z10.string().min(1).max(200) });
|
|
997
|
+
var BrainDelegateDecideSchema = z10.object({ type: z10.literal("brain.delegate.decide"), rid: z10.string().min(1).max(100), id: z10.string().min(1).max(200), token: z10.string().min(1).max(100), answers: z10.record(z10.string().max(8e3)), category: MandateCategorySchema });
|
|
998
|
+
var BrainDelegateQuerySchema = z10.object({ type: z10.literal("brain.delegate.query"), rid: z10.string().min(1).max(100), operation: z10.string().min(1).max(100), token: z10.string().min(1).max(100) });
|
|
999
|
+
var BrainDelegateReleaseSchema = z10.object({ type: z10.literal("brain.delegate.release"), rid: z10.string().min(1).max(100), id: z10.string().min(1).max(200), token: z10.string().min(1).max(100), advice: z10.string().max(8e3).optional(), category: MandateCategorySchema.optional() });
|
|
1000
|
+
var BrainDelegateResultSchema = z10.object({ type: z10.literal("brain.delegate.result"), rid: z10.string().min(1).max(100), ok: z10.boolean(), token: z10.string().optional(), graceUntil: z10.string().datetime().optional(), status: z10.enum(["applied"]).optional(), code: z10.string().optional(), reason: z10.string().optional() });
|
|
1001
|
+
var RigResultSchema = z10.object({ type: z10.literal("rig.result"), rid: z10.string(), ok: z10.boolean(), confirmed: z10.literal(true).optional(), code: RigResultCodeSchema.optional(), reason: z10.string().optional() });
|
|
1002
|
+
var RigActSchema = z10.object({ type: z10.literal("rig.act"), rid: z10.string(), machine: z10.string(), rigId: z10.string().optional(), seatRef: z10.string().optional(), verb: RigVerbSchema });
|
|
1003
|
+
var RigPrepareSchema = z10.object({ type: z10.literal("rig.prepare"), rid: z10.string(), machine: z10.string(), spec: z10.string(), goal: z10.string().max(8e3), where: RigLaunchWhereSchema });
|
|
1004
|
+
var RigLaunchSchema = z10.object({ type: z10.literal("rig.launch"), rid: z10.string(), planId: z10.string() });
|
|
1005
|
+
var RigAdoptSchema = z10.object({ type: z10.literal("rig.adopt"), rid: z10.string(), machine: z10.string(), rigId: z10.string(), projectId: z10.string() });
|
|
1006
|
+
var RigSendSchema = z10.object({ type: z10.literal("rig.send"), rid: z10.string(), machine: z10.string(), seatRef: z10.string(), text: z10.string() });
|
|
1007
|
+
var RigSpecSeatSchema = z10.object({
|
|
1008
|
+
address: z10.string(),
|
|
1009
|
+
member: z10.string(),
|
|
1010
|
+
pod: z10.string(),
|
|
1011
|
+
runtime: z10.string(),
|
|
1012
|
+
model: z10.string().optional(),
|
|
1013
|
+
effort: z10.string().optional(),
|
|
1014
|
+
profile: z10.string().optional()
|
|
1015
|
+
});
|
|
1016
|
+
var RigSpecInfoSchema = z10.object({
|
|
1017
|
+
id: z10.string(),
|
|
1018
|
+
name: z10.string(),
|
|
1019
|
+
summary: z10.string().optional(),
|
|
1020
|
+
source: z10.enum(["builtin", "library", "registry"]),
|
|
1021
|
+
path: z10.string().optional(),
|
|
1022
|
+
seats: z10.array(RigSpecSeatSchema)
|
|
1023
|
+
});
|
|
1024
|
+
var RigSpecsRequestSchema = z10.object({ type: z10.literal("rig.specs.request"), requestId: z10.string(), machineId: z10.string().optional() });
|
|
1025
|
+
var RigSpecsSchema = z10.object({
|
|
1026
|
+
type: z10.literal("rig.specs"),
|
|
1027
|
+
requestId: z10.string(),
|
|
1028
|
+
machine: z10.string(),
|
|
1029
|
+
specs: z10.array(RigSpecInfoSchema),
|
|
1030
|
+
error: z10.enum(["openrig_down", "unsupported", "failed"]).optional()
|
|
1031
|
+
});
|
|
1032
|
+
var RigExchangesRequestSchema = z10.object({ type: z10.literal("rig.exchanges.request"), machine: z10.string(), rigId: z10.string() });
|
|
1033
|
+
var EscalationAnswerSchema = z10.object({ type: z10.literal("escalation.answer"), rid: z10.string(), id: z10.string(), answers: z10.record(z10.string()), by: z10.literal("user") });
|
|
1034
|
+
var LedgeSaySchema = z10.object({ type: z10.literal("ledge.say"), rid: z10.string(), text: z10.string(), about: z10.string().optional() });
|
|
1035
|
+
var LedgeThreadRequestSchema = z10.object({ type: z10.literal("ledge.thread.request"), before: z10.string().optional() });
|
|
1036
|
+
var MandateUpdateSchema = z10.object({ type: z10.literal("mandate.update"), rid: z10.string(), text: z10.string() });
|
|
1037
|
+
var RuleSetSchema = z10.object({ type: z10.literal("rule.set"), rid: z10.string(), id: z10.string(), status: z10.enum(["active", "rejected"]) });
|
|
1038
|
+
var DecisionRevisitSchema = z10.object({ type: z10.literal("decision.revisit"), rid: z10.string(), id: z10.string(), text: z10.string().optional() });
|
|
1039
|
+
var CategoryEscalateSchema = z10.object({ type: z10.literal("category.escalate"), rid: z10.string(), category: MandateCategorySchema });
|
|
1040
|
+
var BrainSetSchema = z10.object({
|
|
1041
|
+
type: z10.literal("brain.set"),
|
|
1042
|
+
rid: z10.string(),
|
|
1043
|
+
enabled: z10.boolean(),
|
|
1044
|
+
tool: ToolSchema.optional(),
|
|
1045
|
+
first: z10.literal(true).optional()
|
|
1046
|
+
});
|
|
1047
|
+
var BrainCmdSchema = z10.object({
|
|
1048
|
+
type: z10.literal("brain.cmd"),
|
|
1049
|
+
rid: z10.string(),
|
|
1050
|
+
by: z10.string(),
|
|
1051
|
+
key: z10.string(),
|
|
1052
|
+
op: z10.enum(BRAIN_OPS),
|
|
1053
|
+
args: z10.array(z10.string()).max(40)
|
|
1054
|
+
});
|
|
1055
|
+
|
|
1056
|
+
// ../protocol/src/messages.ts
|
|
1057
|
+
import { z as z21 } from "zod";
|
|
1058
|
+
|
|
1069
1059
|
// ../protocol/src/repos.ts
|
|
1070
|
-
import { z as
|
|
1071
|
-
var ReposInspectSchema =
|
|
1072
|
-
type:
|
|
1073
|
-
requestId:
|
|
1074
|
-
paths:
|
|
1075
|
-
machineId:
|
|
1076
|
-
});
|
|
1077
|
-
var RepoInfoSchema =
|
|
1078
|
-
var ReposInfoSchema =
|
|
1060
|
+
import { z as z11 } from "zod";
|
|
1061
|
+
var ReposInspectSchema = z11.object({
|
|
1062
|
+
type: z11.literal("repos.inspect"),
|
|
1063
|
+
requestId: z11.string().min(1).max(100),
|
|
1064
|
+
paths: z11.array(z11.string().min(1)).min(1).max(50),
|
|
1065
|
+
machineId: z11.string().optional()
|
|
1066
|
+
});
|
|
1067
|
+
var RepoInfoSchema = z11.object({ path: z11.string(), exists: z11.boolean(), branch: z11.string().nullable() });
|
|
1068
|
+
var ReposInfoSchema = z11.object({ type: z11.literal("repos.info"), requestId: z11.string(), repos: z11.array(RepoInfoSchema) });
|
|
1079
1069
|
|
|
1080
1070
|
// ../protocol/src/scan.ts
|
|
1081
|
-
import { z as
|
|
1082
|
-
var ReposScanSchema =
|
|
1083
|
-
var FoundRepoSchema =
|
|
1084
|
-
var ReposFoundSchema =
|
|
1071
|
+
import { z as z12 } from "zod";
|
|
1072
|
+
var ReposScanSchema = z12.object({ type: z12.literal("repos.scan"), requestId: z12.string().min(1).max(100), machineId: z12.string().optional() });
|
|
1073
|
+
var FoundRepoSchema = z12.object({ path: z12.string(), branch: z12.string().nullable(), remote: z12.string().optional(), manifest: z12.string().max(200).optional() });
|
|
1074
|
+
var ReposFoundSchema = z12.object({ type: z12.literal("repos.found"), requestId: z12.string(), repos: z12.array(FoundRepoSchema).max(500), truncated: z12.boolean(), error: z12.string().optional() });
|
|
1085
1075
|
|
|
1086
1076
|
// ../protocol/src/documents.ts
|
|
1087
|
-
import { z as
|
|
1077
|
+
import { z as z13 } from "zod";
|
|
1088
1078
|
var DOCUMENT_MAX_BYTES = 1048576;
|
|
1089
|
-
var path =
|
|
1090
|
-
var requestId2 =
|
|
1091
|
-
var DocumentReadSchema =
|
|
1092
|
-
type:
|
|
1079
|
+
var path = z13.string().min(1).max(4096);
|
|
1080
|
+
var requestId2 = z13.string().min(1);
|
|
1081
|
+
var DocumentReadSchema = z13.object({
|
|
1082
|
+
type: z13.literal("document.read"),
|
|
1093
1083
|
requestId: requestId2,
|
|
1094
1084
|
path,
|
|
1095
|
-
machineId:
|
|
1096
|
-
sessionId:
|
|
1085
|
+
machineId: z13.string().optional(),
|
|
1086
|
+
sessionId: z13.string().min(1).optional(),
|
|
1097
1087
|
basePath: path.optional()
|
|
1098
1088
|
});
|
|
1099
|
-
var DocumentContentSchema =
|
|
1100
|
-
type:
|
|
1089
|
+
var DocumentContentSchema = z13.object({
|
|
1090
|
+
type: z13.literal("document.content"),
|
|
1101
1091
|
requestId: requestId2,
|
|
1102
1092
|
path,
|
|
1103
|
-
text:
|
|
1104
|
-
bytes:
|
|
1105
|
-
modifiedAt:
|
|
1093
|
+
text: z13.string(),
|
|
1094
|
+
bytes: z13.number().int().nonnegative(),
|
|
1095
|
+
modifiedAt: z13.string().datetime()
|
|
1106
1096
|
});
|
|
1107
|
-
var DocumentErrorCodeSchema =
|
|
1097
|
+
var DocumentErrorCodeSchema = z13.enum([
|
|
1108
1098
|
"not_found",
|
|
1109
1099
|
"not_file",
|
|
1110
1100
|
"unsupported_path",
|
|
@@ -1116,62 +1106,155 @@ var DocumentErrorCodeSchema = z16.enum([
|
|
|
1116
1106
|
"session_missing",
|
|
1117
1107
|
"read_failed"
|
|
1118
1108
|
]);
|
|
1119
|
-
var DocumentErrorSchema =
|
|
1120
|
-
type:
|
|
1109
|
+
var DocumentErrorSchema = z13.object({
|
|
1110
|
+
type: z13.literal("document.error"),
|
|
1121
1111
|
requestId: requestId2,
|
|
1122
1112
|
path,
|
|
1123
1113
|
code: DocumentErrorCodeSchema
|
|
1124
1114
|
});
|
|
1125
1115
|
|
|
1126
1116
|
// ../protocol/src/routing.ts
|
|
1127
|
-
import { z as
|
|
1128
|
-
var MachineInventorySchema =
|
|
1129
|
-
id:
|
|
1130
|
-
label:
|
|
1131
|
-
online:
|
|
1132
|
-
local:
|
|
1133
|
-
sessions:
|
|
1134
|
-
folders:
|
|
1135
|
-
});
|
|
1136
|
-
var RoutingContextSchema =
|
|
1137
|
-
machines:
|
|
1138
|
-
history:
|
|
1139
|
-
});
|
|
1140
|
-
var RouteResultSchema =
|
|
1117
|
+
import { z as z14 } from "zod";
|
|
1118
|
+
var MachineInventorySchema = z14.object({
|
|
1119
|
+
id: z14.string().min(1).max(80),
|
|
1120
|
+
label: z14.string().min(1).max(120),
|
|
1121
|
+
online: z14.boolean(),
|
|
1122
|
+
local: z14.boolean(),
|
|
1123
|
+
sessions: z14.array(z14.object({ id: z14.string(), name: z14.string(), project: z14.string(), cwd: z14.string(), topic: z14.string().optional(), state: z14.string(), readOnly: z14.boolean() })).max(500),
|
|
1124
|
+
folders: z14.array(z14.object({ project: z14.string(), cwd: z14.string() })).max(100)
|
|
1125
|
+
});
|
|
1126
|
+
var RoutingContextSchema = z14.object({
|
|
1127
|
+
machines: z14.array(MachineInventorySchema).min(1).max(20),
|
|
1128
|
+
history: z14.array(z14.object({ question: z14.string().max(2e4), answer: z14.string().max(2e4).optional(), machineId: z14.string().optional() })).max(50)
|
|
1129
|
+
});
|
|
1130
|
+
var RouteResultSchema = z14.object({
|
|
1141
1131
|
/** Null means an answer or a clarification, never an implicit local destination. */
|
|
1142
|
-
machineId:
|
|
1143
|
-
text:
|
|
1144
|
-
choices:
|
|
1132
|
+
machineId: z14.string().nullable(),
|
|
1133
|
+
text: z14.string().min(1).max(2e4),
|
|
1134
|
+
choices: z14.array(z14.string()).max(20).optional()
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
// ../protocol/src/ssh.ts
|
|
1138
|
+
import { z as z15 } from "zod";
|
|
1139
|
+
var SshAliasSchema = z15.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/);
|
|
1140
|
+
|
|
1141
|
+
// ../protocol/src/machines.ts
|
|
1142
|
+
import { z as z16 } from "zod";
|
|
1143
|
+
var MachineIdSchema = z16.string().regex(/^[a-zA-Z0-9_-]{1,64}$/);
|
|
1144
|
+
var MachineSchema = z16.object({
|
|
1145
|
+
id: MachineIdSchema,
|
|
1146
|
+
label: z16.string().trim().min(1).max(80),
|
|
1147
|
+
ssh: SshAliasSchema.optional()
|
|
1148
|
+
});
|
|
1149
|
+
var MachinesSchema = z16.array(MachineSchema).min(1).max(20).superRefine((list, ctx) => {
|
|
1150
|
+
if (list[0]?.id !== "local" || list[0].ssh !== void 0) ctx.addIssue({ code: "custom", message: "the first machine is local, without ssh", path: [0] });
|
|
1151
|
+
const ids = /* @__PURE__ */ new Set(), aliases = /* @__PURE__ */ new Set();
|
|
1152
|
+
list.forEach((m, i) => {
|
|
1153
|
+
if (i > 0 && !m.ssh) ctx.addIssue({ code: "custom", message: "a remote machine needs an ssh alias", path: [i, "ssh"] });
|
|
1154
|
+
if (ids.has(m.id)) ctx.addIssue({ code: "custom", message: `duplicate id ${m.id}`, path: [i, "id"] });
|
|
1155
|
+
ids.add(m.id);
|
|
1156
|
+
if (m.ssh) {
|
|
1157
|
+
if (aliases.has(m.ssh)) ctx.addIssue({ code: "custom", message: `duplicate ssh alias ${m.ssh}`, path: [i, "ssh"] });
|
|
1158
|
+
aliases.add(m.ssh);
|
|
1159
|
+
}
|
|
1160
|
+
});
|
|
1145
1161
|
});
|
|
1146
1162
|
|
|
1147
1163
|
// ../protocol/src/island.ts
|
|
1148
|
-
import { z as
|
|
1149
|
-
var IslandScaleSchema =
|
|
1150
|
-
var IslandPrefsSchema =
|
|
1164
|
+
import { z as z17 } from "zod";
|
|
1165
|
+
var IslandScaleSchema = z17.union([z17.literal("auto"), z17.literal(1), z17.literal(1.25), z17.literal(1.5), z17.literal(2)]);
|
|
1166
|
+
var IslandPrefsSchema = z17.object({
|
|
1151
1167
|
/** Shown at the top of the screen; hidden, Desktop still notifies. */
|
|
1152
|
-
visible:
|
|
1168
|
+
visible: z17.boolean(),
|
|
1153
1169
|
/** `primary` (whichever it is after a reconfiguration), or a monitor's id as the shell lists it (`list_monitors`: the OS
|
|
1154
1170
|
* name, `#index` without one). `second`, written by older fronts, is the first monitor that is not the primary. */
|
|
1155
|
-
screen:
|
|
1156
|
-
position:
|
|
1171
|
+
screen: z17.string().trim().min(1).max(200),
|
|
1172
|
+
position: z17.enum(["center", "left", "right"]),
|
|
1157
1173
|
/** A strip under a maximised window. */
|
|
1158
|
-
discreet:
|
|
1174
|
+
discreet: z17.boolean(),
|
|
1159
1175
|
islandScale: IslandScaleSchema,
|
|
1160
1176
|
panelScale: IslandScaleSchema,
|
|
1161
1177
|
/** What the island shows besides asks and questions, which it always shows. */
|
|
1162
|
-
shows:
|
|
1178
|
+
shows: z17.object({
|
|
1163
1179
|
/** Allow, deny or answer in a line from the island; off, its cards only say « Open in Ledge ». */
|
|
1164
|
-
quick:
|
|
1180
|
+
quick: z17.boolean(),
|
|
1165
1181
|
/** The 6 s bubble when an agent finishes. */
|
|
1166
|
-
finished:
|
|
1182
|
+
finished: z17.boolean(),
|
|
1167
1183
|
/** An agent's sentence in a bubble. */
|
|
1168
|
-
say:
|
|
1184
|
+
say: z17.boolean(),
|
|
1169
1185
|
/** The sub-agents next to their main agent. */
|
|
1170
|
-
helpers:
|
|
1186
|
+
helpers: z17.boolean()
|
|
1171
1187
|
}),
|
|
1172
1188
|
/** The global shortcut that opens the island, as shown (`Ctrl Alt L`). */
|
|
1173
|
-
shortcut:
|
|
1189
|
+
shortcut: z17.string().trim().min(1).max(40)
|
|
1190
|
+
});
|
|
1191
|
+
|
|
1192
|
+
// ../protocol/src/projects.ts
|
|
1193
|
+
import { z as z18 } from "zod";
|
|
1194
|
+
var PROJECT_COLORS = { blue: "#3b82f6", green: "#10b981", amber: "#f59e0b", violet: "#8b5cf6", teal: "#14b8a6", pink: "#ec4899", red: "#ef4444", slate: "#64748b" };
|
|
1195
|
+
var ProjectColorSchema = z18.enum(["blue", "green", "amber", "violet", "teal", "pink", "red", "slate"]);
|
|
1196
|
+
var ProjectIdSchema = z18.string().regex(/^[a-z0-9][a-z0-9-]{0,63}$/);
|
|
1197
|
+
function normalizePath(raw) {
|
|
1198
|
+
const p = raw.trim().replace(/\/+/g, "/");
|
|
1199
|
+
return p.length > 1 && p.endsWith("/") ? p.slice(0, -1) : p;
|
|
1200
|
+
}
|
|
1201
|
+
var PathSchema = z18.string().max(4096).refine((p) => p.startsWith("/") && p === normalizePath(p), "an absolute, normalized path");
|
|
1202
|
+
var RepoSchema = z18.object({ machine: MachineIdSchema, path: PathSchema });
|
|
1203
|
+
var ProjectSchema = z18.object({
|
|
1204
|
+
id: ProjectIdSchema,
|
|
1205
|
+
name: z18.string().trim().min(1).max(80),
|
|
1206
|
+
color: ProjectColorSchema,
|
|
1207
|
+
description: z18.string().max(500).default(""),
|
|
1208
|
+
repos: z18.array(RepoSchema).max(50),
|
|
1209
|
+
/** Ids of the OpenRig rigs filed in this project (a rig lives in one project at most). */
|
|
1210
|
+
rigs: z18.array(z18.string().min(1).max(200)).max(200).default([])
|
|
1211
|
+
});
|
|
1212
|
+
var RuleSchema = z18.object({ machine: MachineIdSchema, path: PathSchema, project: ProjectIdSchema });
|
|
1213
|
+
function projectsProblems(p) {
|
|
1214
|
+
const out = [];
|
|
1215
|
+
const ids = /* @__PURE__ */ new Set(), names = /* @__PURE__ */ new Set(), repos = /* @__PURE__ */ new Set(), rigIds = /* @__PURE__ */ new Set(), rules = /* @__PURE__ */ new Set();
|
|
1216
|
+
p.projects.forEach((project, i) => {
|
|
1217
|
+
if (ids.has(project.id)) out.push({ code: "duplicate_id", path: ["projects", i, "id"] });
|
|
1218
|
+
ids.add(project.id);
|
|
1219
|
+
const name = project.name.trim().toLocaleLowerCase();
|
|
1220
|
+
if (names.has(name)) out.push({ code: "duplicate_name", path: ["projects", i, "name"] });
|
|
1221
|
+
names.add(name);
|
|
1222
|
+
project.repos.forEach((repo, j) => {
|
|
1223
|
+
const key2 = `${repo.machine}
|
|
1224
|
+
${repo.path}`;
|
|
1225
|
+
if (repos.has(key2)) out.push({ code: "duplicate_repo", path: ["projects", i, "repos", j] });
|
|
1226
|
+
repos.add(key2);
|
|
1227
|
+
});
|
|
1228
|
+
project.rigs.forEach((rig, j) => {
|
|
1229
|
+
if (rigIds.has(rig)) out.push({ code: "duplicate_rig", path: ["projects", i, "rigs", j] });
|
|
1230
|
+
rigIds.add(rig);
|
|
1231
|
+
});
|
|
1232
|
+
});
|
|
1233
|
+
p.rules.forEach((rule, i) => {
|
|
1234
|
+
const key2 = `${rule.machine}
|
|
1235
|
+
${rule.path}`;
|
|
1236
|
+
if (rules.has(key2)) out.push({ code: "duplicate_rule", path: ["rules", i] });
|
|
1237
|
+
rules.add(key2);
|
|
1238
|
+
if (!ids.has(rule.project)) out.push({ code: "unknown_project", path: ["rules", i, "project"] });
|
|
1239
|
+
});
|
|
1240
|
+
return out;
|
|
1241
|
+
}
|
|
1242
|
+
var ProjectsSchema = z18.object({ projects: z18.array(ProjectSchema).max(100), rules: z18.array(RuleSchema).max(1e3) }).superRefine((p, ctx) => {
|
|
1243
|
+
for (const problem of projectsProblems(p)) ctx.addIssue({ code: "custom", message: problem.code, path: problem.path });
|
|
1174
1244
|
});
|
|
1245
|
+
var DEFAULT_PROJECTS = { projects: [], rules: [] };
|
|
1246
|
+
var under = (cwd, path2) => path2 === "/" || cwd === path2 || cwd.startsWith(`${path2}/`);
|
|
1247
|
+
function projectOf(session, state) {
|
|
1248
|
+
const machine = session.machineId ?? "local";
|
|
1249
|
+
const cwd = normalizePath(session.cwd);
|
|
1250
|
+
const known2 = new Set(state.projects.map((p) => p.id));
|
|
1251
|
+
const candidates = [
|
|
1252
|
+
...state.projects.flatMap((p) => p.repos.filter((r) => r.machine === machine).map((r) => ({ project: p.id, path: r.path, rule: false }))),
|
|
1253
|
+
...state.rules.filter((r) => r.machine === machine && known2.has(r.project)).map((r) => ({ project: r.project, path: r.path, rule: true }))
|
|
1254
|
+
].filter((c) => under(cwd, c.path));
|
|
1255
|
+
candidates.sort((x, y) => y.path.length - x.path.length || Number(y.rule) - Number(x.rule));
|
|
1256
|
+
return candidates[0]?.project ?? null;
|
|
1257
|
+
}
|
|
1175
1258
|
|
|
1176
1259
|
// ../protocol/src/thread.ts
|
|
1177
1260
|
import { z as z19 } from "zod";
|
|
@@ -1200,13 +1283,6 @@ var ThreadItemSchema = z19.discriminatedUnion("kind", [
|
|
|
1200
1283
|
kind: z19.literal("notice"),
|
|
1201
1284
|
...base,
|
|
1202
1285
|
notice: z19.enum(["idle", "exited", "unavailable", "expired", "delivery", "other"]),
|
|
1203
|
-
/** An `other` notice from Ledge: `task`, the task a `<ledge-task>` is about; `team`, the team a `<ledge-notice team>` seated the
|
|
1204
|
-
* session in (roles spec §3.3). An older front, which knows neither, shows it as any other notice. */
|
|
1205
|
-
task: z19.string().optional(),
|
|
1206
|
-
team: z19.string().optional(),
|
|
1207
|
-
/** A task this session handed over (`outgoing`), and how (issue #92). */
|
|
1208
|
-
taskOp: z19.enum(TRANSMISSION_OPS).optional(),
|
|
1209
|
-
outgoing: z19.literal(true).optional(),
|
|
1210
1286
|
name: z19.string().optional(),
|
|
1211
1287
|
peer: z19.string().optional(),
|
|
1212
1288
|
time: z19.string().optional(),
|
|
@@ -1269,7 +1345,7 @@ var MobileStateSchema = z20.object({
|
|
|
1269
1345
|
|
|
1270
1346
|
// ../protocol/src/messages.ts
|
|
1271
1347
|
var PROTOCOL_PORT = 47831;
|
|
1272
|
-
var RefusalCodeSchema = z21.enum(["stale", "read_only", "no_prompt", "not_taken", "busy", "unknown_session", "nothing_to_decide", "not_offered", "free_text", "note_not_typed", "unavailable", "invalid", "attachment_missing", "attachments_not_accepted"]);
|
|
1348
|
+
var RefusalCodeSchema = z21.enum(["stale", "read_only", "no_prompt", "not_taken", "busy", "unknown_session", "nothing_to_decide", "not_offered", "free_text", "note_not_typed", "unavailable", "invalid", "attachment_missing", "attachments_not_accepted", "rig_managed"]);
|
|
1273
1349
|
var SessionEventSchema = z21.object({
|
|
1274
1350
|
name: z21.enum(["SessionStart", "UserPromptSubmit", "PreToolUse", "PermissionRequest", "Notification", "Stop", "SessionEnd", "PaneChanged", "PaneGone", "PanePrompt", "PaneIdle", "InjectFailed", "Decided", "PostToolUse", "PostToolUseFailure", "StopFailure", "SubagentStart", "SubagentStop", "PaneTitle", "Renamed", "NativeRequest", "AgentMessage", "QueueUpdate"]),
|
|
1275
1351
|
at: z21.string().datetime(),
|
|
@@ -1338,11 +1414,19 @@ var DaemonInfoSchema = z21.object({
|
|
|
1338
1414
|
/** Its home folder, so a client shows the folders under it as `~` (absent from older daemons). */
|
|
1339
1415
|
home: z21.string().optional(),
|
|
1340
1416
|
mobile: z21.boolean().optional(),
|
|
1341
|
-
/** Knows
|
|
1342
|
-
|
|
1417
|
+
/** Knows `ask.create` / `ask.answer`: a session's decision for the user (`ledge ask`). */
|
|
1418
|
+
asks: z21.boolean().optional(),
|
|
1419
|
+
/** Reads OpenRig (rigs, escalations, exchanges) through its local bridge. */
|
|
1420
|
+
openrig: z21.boolean().optional(),
|
|
1421
|
+
/** Takes color-preview subscriptions. */
|
|
1422
|
+
colorPreview: z21.boolean().optional(),
|
|
1423
|
+
/** Relays rigs of remote machines. */
|
|
1424
|
+
openrigFleet: z21.boolean().optional(),
|
|
1425
|
+
brainDelegate: z21.boolean().optional()
|
|
1343
1426
|
});
|
|
1344
1427
|
var UpdateFailureSchema = z21.enum(["git-install", "no-systemd", "sessions-at-risk", "npm-failed", "busy"]);
|
|
1345
1428
|
var ServerMessageSchema = z21.discriminatedUnion("type", [
|
|
1429
|
+
SessionModelAcceptedSchema,
|
|
1346
1430
|
z21.object({ type: z21.literal("chat.routed"), qid: z21.string(), result: RouteResultSchema }),
|
|
1347
1431
|
DocumentContentSchema,
|
|
1348
1432
|
DocumentErrorSchema,
|
|
@@ -1368,6 +1452,8 @@ var ServerMessageSchema = z21.discriminatedUnion("type", [
|
|
|
1368
1452
|
}),
|
|
1369
1453
|
z21.object({ type: z21.literal("session.removed"), id: z21.string() }),
|
|
1370
1454
|
z21.object({ type: z21.literal("session.preview"), id: z21.string(), lines: z21.array(z21.string()) }),
|
|
1455
|
+
/** The session's terminal in color (SGR codes kept), sent only to the client that subscribed to it. */
|
|
1456
|
+
z21.object({ type: z21.literal("session.preview.color"), id: z21.string(), lines: z21.array(z21.string()) }),
|
|
1371
1457
|
/** A session's thread, on request (spec 2026-10-13 §5); then each created or updated item, broadcast. */
|
|
1372
1458
|
z21.object({ type: z21.literal("session.thread"), id: z21.string(), items: z21.array(ThreadItemSchema) }),
|
|
1373
1459
|
z21.object({ type: z21.literal("session.thread.item"), id: z21.string(), item: ThreadItemSchema }),
|
|
@@ -1393,7 +1479,7 @@ var ServerMessageSchema = z21.discriminatedUnion("type", [
|
|
|
1393
1479
|
/** 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. */
|
|
1394
1480
|
z21.object({ type: z21.literal("chat.step"), qid: z21.string(), step: ChatStepSchema }),
|
|
1395
1481
|
z21.object({ type: z21.literal("chat.delta"), qid: z21.string(), text: z21.string() }),
|
|
1396
|
-
z21.object({ type: z21.literal("chat.done"), qid: z21.string(), text: z21.string(), at: z21.string().datetime(), proposal: ChatProposalSchema.optional(), proposals: ChatProposalsSchema.optional(), relay: ChatRelaySchema.optional(), closes: ChatClosesSchema.optional(), projectProposal: ChatProjectProposalSchema.optional(),
|
|
1482
|
+
z21.object({ type: z21.literal("chat.done"), qid: z21.string(), text: z21.string(), at: z21.string().datetime(), proposal: ChatProposalSchema.optional(), proposals: ChatProposalsSchema.optional(), relay: ChatRelaySchema.optional(), closes: ChatClosesSchema.optional(), projectProposal: ChatProjectProposalSchema.optional(), actions: ChatActionsSchema.optional() }),
|
|
1397
1483
|
/** What a `chat.act` applied: the rows done, and the one that failed with why (the rows after it stay proposed). */
|
|
1398
1484
|
z21.object({ type: z21.literal("chat.acted"), rid: z21.string(), qid: z21.string(), done: z21.array(z21.number().int().min(0)), failed: z21.array(z21.object({
|
|
1399
1485
|
row: z21.number().int().min(0),
|
|
@@ -1403,7 +1489,7 @@ var ServerMessageSchema = z21.discriminatedUnion("type", [
|
|
|
1403
1489
|
})) }),
|
|
1404
1490
|
/** What an `action.run` came to: `row` the action as the daemon resolved it (its summary, its risk); `reason` why it was not
|
|
1405
1491
|
* done, with `code` (`refused`: not possible now; `agent`: a session may not run it; `confirm_required`: destructive, ask
|
|
1406
|
-
* again; `failed`: the handler turned it down; a free string, as an `error`'s); `path`
|
|
1492
|
+
* again; `failed`: the handler turned it down; a free string, as an `error`'s); `path` a file the action wrote. */
|
|
1407
1493
|
z21.object({ type: z21.literal("action.result"), rid: z21.string(), action: z21.string().min(1).max(40), row: ChatActionSchema.optional(), reason: z21.string().optional(), code: z21.string().optional(), path: z21.string().optional() }),
|
|
1408
1494
|
z21.object({ type: z21.literal("chat.error"), qid: z21.string(), message: z21.string() }),
|
|
1409
1495
|
z21.object({ type: z21.literal("chat.history"), turns: z21.array(ChatTurnSchema) }),
|
|
@@ -1423,20 +1509,31 @@ var ServerMessageSchema = z21.discriminatedUnion("type", [
|
|
|
1423
1509
|
z21.object({ type: z21.literal("message.ack"), rid: z21.string(), outcome: z21.enum(["accepted", "queued", "native", "refused"]), reason: z21.string().optional() }),
|
|
1424
1510
|
/** The answer to a `message.read`: the body with its sender, target and time, or the refusal's `reason`. */
|
|
1425
1511
|
z21.object({ type: z21.literal("message.body"), id: z21.string(), from: z21.string().optional(), to: z21.string().optional(), at: z21.string().optional(), text: z21.string().optional(), reason: z21.string().optional() }),
|
|
1426
|
-
TaskResultSchema,
|
|
1427
1512
|
SessionHandoverResultSchema,
|
|
1428
1513
|
ContextPrefsMessageSchema,
|
|
1429
1514
|
HandoverResultSchema,
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1515
|
+
AsksMessageSchema,
|
|
1516
|
+
AskUpdatedSchema,
|
|
1517
|
+
AskResultSchema,
|
|
1518
|
+
OpenRigStatusMessageSchema,
|
|
1519
|
+
RigSnapshotSchema,
|
|
1520
|
+
RigUpdatedSchema,
|
|
1521
|
+
RigRemovedSchema,
|
|
1522
|
+
RigExchangeSchema,
|
|
1523
|
+
RigExchangesSchema,
|
|
1524
|
+
RigSpecsSchema,
|
|
1525
|
+
EscalationUpdatedSchema,
|
|
1526
|
+
EscalationRemovedSchema,
|
|
1527
|
+
LedgeThreadItemMessageSchema,
|
|
1528
|
+
LedgeThreadHistorySchema,
|
|
1529
|
+
DecisionsMessageSchema,
|
|
1530
|
+
RulesMessageSchema,
|
|
1531
|
+
MandateMessageSchema,
|
|
1532
|
+
BrainStatusMessageSchema,
|
|
1533
|
+
RigPlanMessageSchema,
|
|
1534
|
+
RigResultSchema,
|
|
1535
|
+
BrainResultSchema,
|
|
1536
|
+
BrainDelegateResultSchema,
|
|
1440
1537
|
z21.object({
|
|
1441
1538
|
type: z21.literal("error"),
|
|
1442
1539
|
message: z21.string(),
|
|
@@ -1479,10 +1576,6 @@ var ClientMessageSchema = z21.discriminatedUnion("type", [
|
|
|
1479
1576
|
effort: EffortSchema.optional(),
|
|
1480
1577
|
/** OMP only: its approval mode, `always-ask` when left out. */
|
|
1481
1578
|
approval: OmpApprovalSchema.optional(),
|
|
1482
|
-
/** A role (spec 2026-10-25 roles §3.4): its prompt reaches the agent at every start, its defaults fill what is left out. */
|
|
1483
|
-
role: RoleIdSchema.optional(),
|
|
1484
|
-
/** A live team the new session joins at once, in `role`. */
|
|
1485
|
-
team: TeamIdSchema.optional(),
|
|
1486
1579
|
/** Routing by the fleet, removed before the message reaches the daemon. */
|
|
1487
1580
|
machineId: z21.string().optional()
|
|
1488
1581
|
}),
|
|
@@ -1570,10 +1663,20 @@ var ClientMessageSchema = z21.discriminatedUnion("type", [
|
|
|
1570
1663
|
z21.object({ type: z21.literal("session.delete"), id: z21.string() }),
|
|
1571
1664
|
/** 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. */
|
|
1572
1665
|
z21.object({ type: z21.literal("session.rename"), id: z21.string(), topic: z21.string().max(500) }),
|
|
1666
|
+
/** The one session this client follows in color; `id: null` follows none. */
|
|
1667
|
+
z21.object({ type: z21.literal("session.preview.subscribe"), id: z21.string().nullable(), color: z21.literal(true) }),
|
|
1573
1668
|
z21.object({ type: z21.literal("session.thread"), id: z21.string() }),
|
|
1574
1669
|
z21.object({ type: z21.literal("session.register"), session: SessionSchema }),
|
|
1575
1670
|
/** `agent` and `cwd` describe the session when the daemon does not know it yet (a hook from an agent started without ledge). */
|
|
1576
|
-
z21.object({
|
|
1671
|
+
z21.object({
|
|
1672
|
+
type: z21.literal("session.event"),
|
|
1673
|
+
id: z21.string(),
|
|
1674
|
+
event: SessionEventSchema,
|
|
1675
|
+
agent: ToolSchema.optional(),
|
|
1676
|
+
cwd: z21.string().optional(),
|
|
1677
|
+
/** The OpenRig seat a hook ran in: its session name (`dev-build@starter`) and node id, what pairs the session with its seat. */
|
|
1678
|
+
openrig: z21.object({ sessionName: z21.string().min(1).max(200), nodeId: z21.string().max(200).optional() }).optional()
|
|
1679
|
+
}),
|
|
1577
1680
|
z21.object({ type: z21.literal("session.unregister"), id: z21.string(), exitCode: z21.number().int().nullable() }),
|
|
1578
1681
|
z21.object({ type: z21.literal("snapshot.request") }),
|
|
1579
1682
|
z21.object({ type: z21.literal("chat.ask"), qid: z21.string().min(1), text: z21.string(), images: z21.array(ImageUploadSchema).max(ATTACHMENTS_MAX).optional(), tool: ToolSchema.optional() }),
|
|
@@ -1603,29 +1706,33 @@ var ClientMessageSchema = z21.discriminatedUnion("type", [
|
|
|
1603
1706
|
z21.object({ type: z21.literal("session.message"), rid: z21.string().min(1), from: z21.string().min(1), to: z21.string().min(1), text: z21.string().min(1).max(MESSAGE_MAX), summary: z21.string().max(SUMMARY_MAX).optional(), intercept: z21.boolean().optional() }),
|
|
1604
1707
|
/** `ledge read <id>`: a message's whole body, for its receiver or its sender (`by`, a session id). */
|
|
1605
1708
|
z21.object({ type: z21.literal("message.read"), id: z21.string().min(1).max(40), by: z21.string().min(1) }),
|
|
1606
|
-
|
|
1709
|
+
AskCreateSchema,
|
|
1710
|
+
AskAnswerSchema,
|
|
1607
1711
|
SessionHandoverSchema,
|
|
1608
1712
|
ContextSetSchema,
|
|
1609
1713
|
HandoverBriefSchema,
|
|
1610
1714
|
HandoverShowSchema,
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1715
|
+
RigActSchema,
|
|
1716
|
+
RigPrepareSchema,
|
|
1717
|
+
RigLaunchSchema,
|
|
1718
|
+
RigAdoptSchema,
|
|
1719
|
+
RigSendSchema,
|
|
1720
|
+
RigExchangesRequestSchema,
|
|
1721
|
+
RigSpecsRequestSchema,
|
|
1722
|
+
EscalationAnswerSchema,
|
|
1723
|
+
LedgeSaySchema,
|
|
1724
|
+
LedgeThreadRequestSchema,
|
|
1725
|
+
MandateUpdateSchema,
|
|
1726
|
+
RuleSetSchema,
|
|
1727
|
+
DecisionRevisitSchema,
|
|
1728
|
+
CategoryEscalateSchema,
|
|
1729
|
+
BrainSetSchema,
|
|
1730
|
+
BrainCmdSchema,
|
|
1731
|
+
BrainDelegateClaimSchema,
|
|
1732
|
+
BrainDelegateDecideSchema,
|
|
1733
|
+
BrainDelegateReleaseSchema,
|
|
1734
|
+
BrainDelegateQuerySchema
|
|
1735
|
+
]);
|
|
1629
1736
|
function parseClientMessage(raw) {
|
|
1630
1737
|
return ClientMessageSchema.parse(raw);
|
|
1631
1738
|
}
|
|
@@ -1717,8 +1824,8 @@ function pickName(taken, preferred) {
|
|
|
1717
1824
|
|
|
1718
1825
|
// ../protocol/src/topic.ts
|
|
1719
1826
|
var TOPIC_MAX = 80;
|
|
1720
|
-
function cleanTopic(
|
|
1721
|
-
const line =
|
|
1827
|
+
function cleanTopic(text2) {
|
|
1828
|
+
const line = text2.split(/\r?\n/).map((l) => l.trim()).find((l) => l.length > 0) ?? "";
|
|
1722
1829
|
const flat = line.replace(/\s+/g, " ");
|
|
1723
1830
|
return flat.length > TOPIC_MAX ? `${flat.slice(0, TOPIC_MAX - 1).trimEnd()}\u2026` : flat;
|
|
1724
1831
|
}
|
|
@@ -1798,9 +1905,61 @@ var MeResponseSchema = z23.object({
|
|
|
1798
1905
|
// ../protocol/src/phone.ts
|
|
1799
1906
|
import { z as z26 } from "zod";
|
|
1800
1907
|
|
|
1801
|
-
// ../protocol/src/
|
|
1908
|
+
// ../protocol/src/phoneOpenrig.ts
|
|
1802
1909
|
import { z as z24 } from "zod";
|
|
1803
|
-
var
|
|
1910
|
+
var id = z24.string().min(1).max(120);
|
|
1911
|
+
var key = z24.string().min(1).max(64);
|
|
1912
|
+
var at = z24.string().datetime();
|
|
1913
|
+
var op = z24.string().uuid();
|
|
1914
|
+
var messageMax = 2e4;
|
|
1915
|
+
var toolTextMax = 2048;
|
|
1916
|
+
var PhoneRigSeatSchema = z24.object({ ref: id, address: id, name: z24.string().max(80), runtime: z24.string().max(80), model: z24.string().max(120).optional(), state: SeatStateSchema, contextPct: z24.number().min(0).max(100).optional(), sessionId: id.optional() }).strict();
|
|
1917
|
+
var PhoneRigSchema = z24.object({ key, name: z24.string().max(80), spec: z24.string().max(80).optional(), project: z24.string().max(80).nullable(), offProject: z24.boolean(), branch: z24.string().max(200).optional(), lifecycle: RigLifecycleSchema, kernel: z24.boolean(), seats: z24.array(PhoneRigSeatSchema).max(16), repos: z24.number().int().nonnegative(), launch: z24.object({ planId: id, goal: z24.string().max(600), lead: id, startedAt: at, goalSentAt: at.optional(), lateNotice: z24.literal(true).optional() }).strict().optional() }).strict();
|
|
1918
|
+
var PhoneExchangeSchema = z24.object({ id, rigKey: key, from: id, to: id, kind: z24.enum(["message", "task", "handoff", "ledge"]), text: z24.string().max(toolTextMax), at, cut: z24.literal(true).optional() }).strict();
|
|
1919
|
+
var PhoneQuestionSchema = z24.object({ id, question: z24.string().max(toolTextMax), options: z24.array(z24.object({ id, label: z24.string().max(200), recommended: z24.boolean().optional() }).strict()).min(2).max(4) }).strict();
|
|
1920
|
+
var PhoneEscalationSchema = z24.object({ id, source: z24.enum(["rig", "operator", "ask"]), rigKey: key.optional(), rigName: z24.string().max(60).optional(), from: id, intent: z24.enum(["decision", "update"]), summary: z24.string().max(toolTextMax), detail: z24.string().max(toolTextMax).optional(), questions: z24.array(PhoneQuestionSchema).max(4), createdAt: at, state: z24.enum(["pending", "grace", "answered", "closed"]), graceUntil: at.optional(), correcting: id.optional(), category: MandateCategorySchema.optional(), advice: z24.string().max(toolTextMax).optional(), rules: z24.array(z24.object({ text: z24.string().max(200), since: z24.string().max(10) }).strict()).max(5).optional(), answer: z24.object({ by: z24.enum(["ledge", "user"]), answers: z24.record(z24.string().max(120), z24.string().max(messageMax)), at, rule: id.optional(), delivery: z24.enum(["queued", "sent"]).optional() }).strict().optional() }).strict();
|
|
1921
|
+
var PhoneLedgeDecisionSchema = z24.object({ id, escalationId: id, by: z24.enum(["ledge", "user"]), category: MandateCategorySchema.optional(), summary: z24.string().max(toolTextMax), answers: z24.record(z24.string().max(120), z24.string().max(messageMax)), rule: id.optional(), from: id.optional(), rigName: z24.string().max(60).optional(), why: z24.string().max(toolTextMax).optional(), at, revisitedBy: id.optional() }).strict();
|
|
1922
|
+
var PhoneRigPlanSchema = z24.object({ id, spec: z24.string().max(80), goal: z24.string().max(600), where: z24.discriminatedUnion("kind", [z24.object({ kind: z24.literal("project"), project: z24.string().max(80), branch: z24.string().max(200), copy: z24.boolean() }).strict(), z24.object({ kind: z24.literal("off-project"), name: z24.string().max(80) }).strict()]), seats: z24.array(z24.object({ address: id, runtime: z24.string().max(80), model: z24.string().max(120).optional(), autonomy: z24.string().max(80) }).strict()).max(16), writes: z24.array(z24.string().max(200)).max(40), required: z24.boolean(), launchedRigKey: key.optional(), launchedAt: at.optional() }).strict();
|
|
1923
|
+
var PhoneThreadItemSchema = z24.discriminatedUnion("kind", [
|
|
1924
|
+
z24.object({ kind: z24.literal("user"), id, at, text: z24.string().max(toolTextMax), to: id.optional(), qid: id.optional() }).strict(),
|
|
1925
|
+
z24.object({ kind: z24.literal("ledge"), id, at, text: z24.string().max(toolTextMax), qid: id.optional(), pending: z24.literal(true).optional() }).strict(),
|
|
1926
|
+
z24.object({ kind: z24.literal("escalation"), id, at, escalation: PhoneEscalationSchema }).strict(),
|
|
1927
|
+
z24.object({ kind: z24.literal("decided"), id, at, decision: PhoneLedgeDecisionSchema }).strict(),
|
|
1928
|
+
z24.object({ kind: z24.literal("exchanges"), id, at, rigKey: key, rigName: z24.string().max(60), from: at, to: at, count: z24.number().int().min(1), items: z24.array(PhoneExchangeSchema).max(20) }).strict(),
|
|
1929
|
+
z24.object({ kind: z24.literal("card"), id, at, action: z24.lazy(() => PhoneChatActionSchema) }).strict(),
|
|
1930
|
+
z24.object({ kind: z24.literal("plan"), id, at, plan: PhoneRigPlanSchema }).strict()
|
|
1931
|
+
]);
|
|
1932
|
+
var PhoneRigActSchema = z24.object({ type: z24.literal("rig.act"), op, key, verb: z24.enum(["down", "restart"]), seatRef: id.optional(), assertion: z24.lazy(() => AssertionSchema).optional() }).strict();
|
|
1933
|
+
var PhoneRigLaunchSchema = z24.object({ type: z24.literal("rig.launch"), op, planId: id, assertion: z24.lazy(() => AssertionSchema).optional() }).strict();
|
|
1934
|
+
var PhoneEscalationAnswerSchema = z24.object({ type: z24.literal("escalation.answer"), op, id, answers: z24.record(z24.string().max(64), z24.string().max(messageMax)).refine((value) => Object.keys(value).length <= 4) }).strict();
|
|
1935
|
+
var rigSubject = (m) => m.type === "rig.launch" ? `launch@${m.planId}` : `${m.verb}@${m.key}${m.seatRef ? `/${m.seatRef}` : ""}`;
|
|
1936
|
+
var phoneOpenRigClientMessages = [
|
|
1937
|
+
z24.object({ type: z24.literal("ledge.say"), op, text: z24.string().trim().min(1).max(messageMax), about: id.optional() }).strict(),
|
|
1938
|
+
z24.object({ type: z24.literal("ledge.thread.request"), before: id.optional() }).strict(),
|
|
1939
|
+
PhoneEscalationAnswerSchema,
|
|
1940
|
+
z24.object({ type: z24.literal("answer.receipt.request"), answer: PhoneEscalationAnswerSchema }).strict(),
|
|
1941
|
+
z24.object({ type: z24.literal("decision.revisit"), op, id, text: z24.string().max(messageMax).optional() }).strict(),
|
|
1942
|
+
z24.object({ type: z24.literal("rig.exchanges.request"), key }).strict(),
|
|
1943
|
+
z24.object({ type: z24.literal("rig.prepare"), op, goal: z24.string().trim().min(1).max(600), spec: z24.string().max(64).optional(), project: z24.string().max(80).nullable() }).strict(),
|
|
1944
|
+
PhoneRigLaunchSchema,
|
|
1945
|
+
PhoneRigActSchema
|
|
1946
|
+
];
|
|
1947
|
+
var phoneOpenRigServerMessages = [
|
|
1948
|
+
z24.object({ type: z24.literal("answer.receipt"), op, status: z24.enum(["received", "applied", "unknown"]) }).strict(),
|
|
1949
|
+
z24.object({ type: z24.literal("rig.updated"), rig: PhoneRigSchema }).strict(),
|
|
1950
|
+
z24.object({ type: z24.literal("rig.removed"), key }).strict(),
|
|
1951
|
+
z24.object({ type: z24.literal("rig.exchanges"), key, items: z24.array(PhoneExchangeSchema).max(EXCHANGES_MAX), cut: z24.literal(true).optional() }).strict(),
|
|
1952
|
+
z24.object({ type: z24.literal("escalation.updated"), escalation: PhoneEscalationSchema }).strict(),
|
|
1953
|
+
z24.object({ type: z24.literal("escalation.removed"), id }).strict(),
|
|
1954
|
+
z24.object({ type: z24.literal("ledge.thread.item"), item: PhoneThreadItemSchema }).strict(),
|
|
1955
|
+
z24.object({ type: z24.literal("ledge.thread.history"), items: z24.array(PhoneThreadItemSchema).max(THREAD_PAGE), before: id.optional() }).strict(),
|
|
1956
|
+
z24.object({ type: z24.literal("decisions"), items: z24.array(PhoneLedgeDecisionSchema).max(50) }).strict(),
|
|
1957
|
+
z24.object({ type: z24.literal("rig.plan"), plan: PhoneRigPlanSchema }).strict()
|
|
1958
|
+
];
|
|
1959
|
+
|
|
1960
|
+
// ../protocol/src/push.ts
|
|
1961
|
+
import { z as z25 } from "zod";
|
|
1962
|
+
var B64U = z25.string().regex(/^[A-Za-z0-9_-]*$/);
|
|
1804
1963
|
var PUSH_HOSTS = ["*.push.apple.com", "fcm.googleapis.com", "updates.push.services.mozilla.com", "*.notify.windows.com"];
|
|
1805
1964
|
function pushEndpointAllowed(url) {
|
|
1806
1965
|
let u;
|
|
@@ -1817,75 +1976,33 @@ function pushEndpointAllowed(url) {
|
|
|
1817
1976
|
return host.length > suffix.length && host.endsWith(suffix);
|
|
1818
1977
|
});
|
|
1819
1978
|
}
|
|
1820
|
-
var PushSendSchema =
|
|
1821
|
-
endpoint:
|
|
1979
|
+
var PushSendSchema = z25.object({
|
|
1980
|
+
endpoint: z25.string().url().max(1024),
|
|
1822
1981
|
body: B64U.max(5462),
|
|
1823
|
-
ttl:
|
|
1824
|
-
urgency:
|
|
1825
|
-
topic:
|
|
1826
|
-
});
|
|
1827
|
-
var PushSendResultSchema =
|
|
1828
|
-
result:
|
|
1829
|
-
status:
|
|
1830
|
-
});
|
|
1831
|
-
var PushSubscriptionSchema =
|
|
1832
|
-
endpoint:
|
|
1833
|
-
keys:
|
|
1834
|
-
});
|
|
1835
|
-
var PushPayloadSchema =
|
|
1836
|
-
v:
|
|
1837
|
-
kind:
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1982
|
+
ttl: z25.number().int().min(0).max(86400),
|
|
1983
|
+
urgency: z25.enum(["normal", "high"]),
|
|
1984
|
+
topic: z25.string().regex(/^[A-Za-z0-9_-]{1,32}$/)
|
|
1985
|
+
});
|
|
1986
|
+
var PushSendResultSchema = z25.object({
|
|
1987
|
+
result: z25.enum(["sent", "gone", "failed"]),
|
|
1988
|
+
status: z25.number().int().optional()
|
|
1989
|
+
});
|
|
1990
|
+
var PushSubscriptionSchema = z25.object({
|
|
1991
|
+
endpoint: z25.string().url().max(1024).refine(pushEndpointAllowed),
|
|
1992
|
+
keys: z25.object({ p256dh: B64U.length(87), auth: B64U.length(22) })
|
|
1993
|
+
});
|
|
1994
|
+
var PushPayloadSchema = z25.object({
|
|
1995
|
+
v: z25.literal(1),
|
|
1996
|
+
kind: z25.enum(["request", "question", "finished", "chat", "escalation", "decided"]),
|
|
1997
|
+
escalationId: z25.string().min(1).max(120).optional(),
|
|
1998
|
+
count: z25.number().int().min(1).max(999).optional(),
|
|
1999
|
+
actions: z25.array(z25.object({ qId: z25.string().min(1).max(64), optId: z25.string().min(1).max(64), label: z25.string().max(40) }).strict()).max(2).optional(),
|
|
2000
|
+
title: z25.string().max(80),
|
|
2001
|
+
body: z25.string().max(120),
|
|
2002
|
+
url: z25.string().regex(/^\/#\/[A-Za-z0-9/%._~-]*$/).max(300),
|
|
2003
|
+
badge: z25.number().int().min(0).max(999),
|
|
2004
|
+
tag: z25.string().regex(/^[A-Za-z0-9_-]{1,32}$/)
|
|
1843
2005
|
});
|
|
1844
|
-
|
|
1845
|
-
// ../protocol/src/phoneTeams.ts
|
|
1846
|
-
import { z as z25 } from "zod";
|
|
1847
|
-
var scope = DefinitionScopeSchema;
|
|
1848
|
-
var PhoneSeatsSchema = z25.array(SeatSchema.strict()).min(1).max(TEAM_SEATS_MAX).refine(uniqueRoles, "a role twice in one team");
|
|
1849
|
-
var PhoneRoleDraftSchema = RoleDraftSchema.strict();
|
|
1850
|
-
var projectName = z25.string().max(80).nullable();
|
|
1851
|
-
var PhoneRoleSchema = z25.object({
|
|
1852
|
-
id: RoleIdSchema,
|
|
1853
|
-
label: z25.string().min(1).max(ROLE_LABEL_MAX),
|
|
1854
|
-
prompt: z25.string().max(ROLE_PROMPT_MAX),
|
|
1855
|
-
cut: z25.literal(true).optional(),
|
|
1856
|
-
tool: ToolSchema.optional(),
|
|
1857
|
-
model: ModelIdSchema.optional(),
|
|
1858
|
-
effort: EffortSchema.optional(),
|
|
1859
|
-
autonomy: AutonomySchema.optional(),
|
|
1860
|
-
scope,
|
|
1861
|
-
project: projectName,
|
|
1862
|
-
hash: DefinitionHashSchema,
|
|
1863
|
-
shadows: z25.literal(true).optional(),
|
|
1864
|
-
shadowed: z25.literal(true).optional(),
|
|
1865
|
-
shadowedIn: z25.array(z25.string().max(80)).min(1).max(8).optional()
|
|
1866
|
-
}).strict();
|
|
1867
|
-
var PhoneTemplateSchema = z25.object({ id: TemplateIdSchema, name: TeamNameSchema, seats: PhoneSeatsSchema, scope, project: projectName, hash: DefinitionHashSchema }).strict();
|
|
1868
|
-
var PhoneProblemSchema = z25.object({ file: z25.string().max(80), scope, project: projectName, reason: z25.string().max(200) }).strict();
|
|
1869
|
-
var PhoneCatalogSchema = z25.object({
|
|
1870
|
-
/** The names of the projects with a local repository: the ones a « Dépôt » scope or a « Lever » can name. */
|
|
1871
|
-
projects: z25.array(z25.string().max(80)).max(50),
|
|
1872
|
-
roles: z25.array(PhoneRoleSchema).max(200),
|
|
1873
|
-
templates: z25.array(PhoneTemplateSchema).max(100),
|
|
1874
|
-
problems: z25.array(PhoneProblemSchema).max(50)
|
|
1875
|
-
}).strict();
|
|
1876
|
-
var TEAMS_OPERATION_TYPES = ["role.write", "role.delete", "template.write", "template.delete", "team.launch", "team.compose", "team.seat", "team.dissolve"];
|
|
1877
|
-
var isTeamsOperation = (m) => TEAMS_OPERATION_TYPES.includes(m.type);
|
|
1878
|
-
function canonicalJson(v) {
|
|
1879
|
-
const sort = (x) => {
|
|
1880
|
-
if (Array.isArray(x)) return x.map(sort);
|
|
1881
|
-
if (x !== null && typeof x === "object") {
|
|
1882
|
-
const o = x;
|
|
1883
|
-
return Object.fromEntries(Object.keys(o).sort().filter((k) => o[k] !== void 0).map((k) => [k, sort(o[k])]));
|
|
1884
|
-
}
|
|
1885
|
-
return x;
|
|
1886
|
-
};
|
|
1887
|
-
return JSON.stringify(sort(v));
|
|
1888
|
-
}
|
|
1889
2006
|
|
|
1890
2007
|
// ../protocol/src/phone.ts
|
|
1891
2008
|
var PHONE_PROTOCOL = 1;
|
|
@@ -1903,13 +2020,28 @@ var THREAD_ITEMS_MAX = 200;
|
|
|
1903
2020
|
var THREAD_BUDGET = 524288;
|
|
1904
2021
|
var THREAD_TEXT_MAX = 8192;
|
|
1905
2022
|
var TOOL_TEXT_MAX = 2048;
|
|
2023
|
+
var CHECKLIST_TASKS_MAX = 50;
|
|
2024
|
+
var CHECKLIST_TEXT_MAX = 200;
|
|
2025
|
+
var ChecklistStatusSchema = z26.enum(["pending", "in_progress", "completed"]);
|
|
2026
|
+
var PhoneChecklistSchema = z26.object({
|
|
2027
|
+
tasks: z26.array(z26.object({ text: z26.string().max(CHECKLIST_TEXT_MAX), status: ChecklistStatusSchema })).max(CHECKLIST_TASKS_MAX),
|
|
2028
|
+
done: z26.number().int().nonnegative(),
|
|
2029
|
+
total: z26.number().int().nonnegative(),
|
|
2030
|
+
cut: z26.literal(true).optional()
|
|
2031
|
+
});
|
|
2032
|
+
var PhoneChecklistSummarySchema = z26.object({
|
|
2033
|
+
done: z26.number().int().nonnegative(),
|
|
2034
|
+
total: z26.number().int().nonnegative(),
|
|
2035
|
+
current: z26.string().max(CHECKLIST_TEXT_MAX).optional(),
|
|
2036
|
+
cut: z26.literal(true).optional()
|
|
2037
|
+
});
|
|
1906
2038
|
var PENDING_BODY_MAX = 65536;
|
|
1907
2039
|
var SNAPSHOT_BODY_MAX = 2048;
|
|
1908
2040
|
var RiskSchema = z26.enum(["low", "high"]);
|
|
1909
2041
|
var RiskReasonSchema = z26.enum(["question", "read_only_command", "edit_inside_folder", "pushes", "destroys", "deploys", "publishes", "pipes_to_shell", "network", "writes_outside_folder", "sensitive_path", "unsafe_flag", "shell_syntax", "script", "plan", "unknown"]);
|
|
1910
2042
|
var OperationIdSchema = z26.string().uuid();
|
|
1911
2043
|
var OperationStatusSchema = z26.enum(["received", "applied", "rejected", "failed"]);
|
|
1912
|
-
var OperationReasonSchema = z26.enum([...RefusalCodeSchema.options, "untypable", "confirm_required", "conflict", "assertion_invalid", "assertion_expired", "
|
|
2044
|
+
var OperationReasonSchema = z26.enum([...RefusalCodeSchema.options, "untypable", "confirm_required", "conflict", "assertion_invalid", "assertion_expired", "scheduled", ...ModelRefusalSchema.options, ...RIG_RESULT_CODES]);
|
|
1913
2045
|
var CapabilitiesSchema = z26.object({
|
|
1914
2046
|
/** A question can be answered in free text. */
|
|
1915
2047
|
freeTextAnswer: z26.boolean(),
|
|
@@ -1921,7 +2053,8 @@ var CapabilitiesSchema = z26.object({
|
|
|
1921
2053
|
var UNTYPABLE = /[\u0000-\u001f\u007f-\u009f\u200b\u200e\u200f\u2028-\u202e\u2066-\u2069\ufeff]/;
|
|
1922
2054
|
var CapabilitiesByToolSchema = z26.object({ claude: CapabilitiesSchema, codex: CapabilitiesSchema, cursor: CapabilitiesSchema, omp: CapabilitiesSchema });
|
|
1923
2055
|
var PhonePendingSchema = PendingSchema.extend({ key: z26.string().max(64), risk: RiskSchema, riskReason: RiskReasonSchema, cut: z26.literal(true).optional() });
|
|
1924
|
-
var
|
|
2056
|
+
var SwitchableSessionSchema = SessionSchema.extend({ canSwitch: z26.literal(true).optional() });
|
|
2057
|
+
var PhoneSessionSchema = SwitchableSessionSchema.pick({
|
|
1925
2058
|
id: true,
|
|
1926
2059
|
name: true,
|
|
1927
2060
|
tool: true,
|
|
@@ -1936,14 +2069,27 @@ var PhoneSessionSchema = SessionSchema.pick({
|
|
|
1936
2069
|
lastReply: true,
|
|
1937
2070
|
startedAt: true,
|
|
1938
2071
|
lastActivityAt: true,
|
|
1939
|
-
/** Its
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
2072
|
+
/** Its model, effort and the change waiting for its next free moment: the phone shows them and offers to change them. */
|
|
2073
|
+
model: true,
|
|
2074
|
+
effort: true,
|
|
2075
|
+
modelNext: true,
|
|
2076
|
+
canSwitch: true,
|
|
1943
2077
|
/** Its context and its relief (context handover spec §3.2): the phone shows the gauge; the relief is started from the PC. */
|
|
1944
2078
|
context: true,
|
|
1945
|
-
relieves: true
|
|
1946
|
-
|
|
2079
|
+
relieves: true,
|
|
2080
|
+
/** When it ended: « Terminée · à 18:42 » in the list. */
|
|
2081
|
+
exitedAt: true
|
|
2082
|
+
}).extend({
|
|
2083
|
+
pending: PhonePendingSchema.optional(),
|
|
2084
|
+
unread: z26.boolean(),
|
|
2085
|
+
handover: z26.object({ state: HandoverStateSchema, toName: z26.string().max(80).optional() }).strict().optional(),
|
|
2086
|
+
/** Absent: the agent has no checklist. */
|
|
2087
|
+
checklist: PhoneChecklistSummarySchema.optional(),
|
|
2088
|
+
/** Started without Ledge (`hook_only`): the phone can neither close nor resume it. */
|
|
2089
|
+
readOnly: z26.literal(true).optional(),
|
|
2090
|
+
rig: z26.object({ rigName: z26.string().max(80), seat: z26.string().max(120) }).strict().optional(),
|
|
2091
|
+
brain: z26.literal(true).optional()
|
|
2092
|
+
});
|
|
1947
2093
|
var B64U2 = z26.string().regex(/^[A-Za-z0-9_-]*$/);
|
|
1948
2094
|
var CredentialSchema = z26.object({
|
|
1949
2095
|
id: B64U2.max(1366),
|
|
@@ -1959,8 +2105,7 @@ var AssertionSchema = z26.object({
|
|
|
1959
2105
|
authenticatorData: B64U2.max(4096),
|
|
1960
2106
|
signature: B64U2.max(1024)
|
|
1961
2107
|
});
|
|
1962
|
-
var
|
|
1963
|
-
var ConfirmPurposeSchema = z26.enum(["register", "decide", "launch", "close", "act", "define", "team", "pc"]);
|
|
2108
|
+
var ConfirmPurposeSchema = z26.enum(["register", "decide", "launch", "close", "act", "pc", "rig"]);
|
|
1964
2109
|
var PhoneChatStepSchema = ChatStepSchema.pick({ kind: true, id: true, name: true }).strict();
|
|
1965
2110
|
var PhoneChatProposalSchema = z26.object({
|
|
1966
2111
|
project: z26.string().max(80),
|
|
@@ -1978,33 +2123,15 @@ var PhoneChatRelaySchema = z26.object({
|
|
|
1978
2123
|
sentAt: z26.string().datetime().optional(),
|
|
1979
2124
|
failed: z26.literal(true).optional()
|
|
1980
2125
|
}).strict();
|
|
2126
|
+
var CloseHowSchema = z26.enum(["exit", "killed"]);
|
|
1981
2127
|
var PhoneChatCloseSchema = z26.object({
|
|
1982
2128
|
id: z26.string().min(1),
|
|
1983
2129
|
name: z26.string(),
|
|
1984
2130
|
tool: ToolSchema,
|
|
1985
|
-
how:
|
|
2131
|
+
how: CloseHowSchema.optional(),
|
|
1986
2132
|
closedAt: z26.string().datetime().optional(),
|
|
1987
2133
|
failed: z26.literal(true).optional()
|
|
1988
2134
|
}).strict();
|
|
1989
|
-
var PhoneChatTeamSchema = z26.object({
|
|
1990
|
-
project: z26.string().max(80),
|
|
1991
|
-
name: z26.string().max(60),
|
|
1992
|
-
template: z26.string().max(64).optional(),
|
|
1993
|
-
seats: z26.array(z26.object({ role: z26.string().max(40), label: z26.string().max(40), tool: ToolSchema, model: z26.string().max(200).optional(), effort: z26.string().max(20).optional(), autonomy: AutonomySchema.optional() }).strict()).min(1).max(8),
|
|
1994
|
-
teamId: z26.string().max(40).optional(),
|
|
1995
|
-
launchedAt: z26.string().datetime().optional(),
|
|
1996
|
-
failed: z26.literal(true).optional()
|
|
1997
|
-
}).strict();
|
|
1998
|
-
var PhoneChatTaskSchema = z26.object({
|
|
1999
|
-
to: z26.string().max(80),
|
|
2000
|
-
toName: z26.string().max(80).optional(),
|
|
2001
|
-
title: z26.string().max(200),
|
|
2002
|
-
text: z26.string().max(TOOL_TEXT_MAX).optional(),
|
|
2003
|
-
taskId: z26.string().max(40).optional(),
|
|
2004
|
-
ownerName: z26.string().max(80).optional(),
|
|
2005
|
-
state: z26.enum(["open", "taken", "done", "refused", "dropped"]).optional(),
|
|
2006
|
-
failed: z26.literal(true).optional()
|
|
2007
|
-
}).strict();
|
|
2008
2135
|
var PhoneChatActionSchema = z26.object({
|
|
2009
2136
|
action: z26.string().min(1).max(40),
|
|
2010
2137
|
summary: z26.string().max(300),
|
|
@@ -2013,46 +2140,10 @@ var PhoneChatActionSchema = z26.object({
|
|
|
2013
2140
|
detailCut: z26.literal(true).optional(),
|
|
2014
2141
|
risk: ActionRiskSchema,
|
|
2015
2142
|
session: z26.string().max(100).optional(),
|
|
2016
|
-
team: z26.string().max(40).optional(),
|
|
2017
2143
|
state: ChatActionStateSchema.optional(),
|
|
2018
2144
|
doneAt: z26.string().datetime().optional(),
|
|
2019
2145
|
code: z26.string().max(40).optional()
|
|
2020
2146
|
}).strict();
|
|
2021
|
-
var PhoneTeamSchema = z26.object({
|
|
2022
|
-
id: z26.string().max(40),
|
|
2023
|
-
name: z26.string().max(60),
|
|
2024
|
-
project: z26.string().max(80).nullable(),
|
|
2025
|
-
state: z26.enum(["active", "resting"]),
|
|
2026
|
-
template: z26.string().max(64).optional(),
|
|
2027
|
-
/** Absent from a daemon older than the phone: the phone then says no start time. */
|
|
2028
|
-
createdAt: z26.string().optional(),
|
|
2029
|
-
/** `tool`, `model` and `effort` are what the seat was composed with; `leaving` is a seat that finishes its turn and is then closed. */
|
|
2030
|
-
seats: z26.array(z26.object({
|
|
2031
|
-
role: z26.string().max(40),
|
|
2032
|
-
sessionId: z26.string().max(100).nullable(),
|
|
2033
|
-
tool: ToolSchema.optional(),
|
|
2034
|
-
model: ModelIdSchema.optional(),
|
|
2035
|
-
effort: EffortSchema.optional(),
|
|
2036
|
-
leaving: z26.literal(true).optional()
|
|
2037
|
-
}).strict()).max(16),
|
|
2038
|
-
done: z26.number().int().min(0),
|
|
2039
|
-
given: z26.number().int().min(0)
|
|
2040
|
-
}).strict();
|
|
2041
|
-
var PhoneTaskSchema = z26.object({
|
|
2042
|
-
id: z26.string().max(40),
|
|
2043
|
-
title: z26.string().max(200),
|
|
2044
|
-
owner: z26.string().max(100),
|
|
2045
|
-
ownerName: z26.string().max(80),
|
|
2046
|
-
ownerRole: z26.string().max(40).optional(),
|
|
2047
|
-
team: z26.string().max(40).optional(),
|
|
2048
|
-
teamName: z26.string().max(60).optional(),
|
|
2049
|
-
state: z26.enum(["open", "taken", "done", "refused", "dropped"]),
|
|
2050
|
-
result: z26.string().max(TOOL_TEXT_MAX).optional(),
|
|
2051
|
-
cut: z26.literal(true).optional(),
|
|
2052
|
-
at: z26.string(),
|
|
2053
|
-
updatedAt: z26.string(),
|
|
2054
|
-
seen: z26.literal(true).optional()
|
|
2055
|
-
}).strict();
|
|
2056
2147
|
var ChatErrorCodeSchema = z26.enum(["busy", "timeout", "cancelled", "failed"]);
|
|
2057
2148
|
var PhoneChatTurnSchema = z26.object({
|
|
2058
2149
|
qid: OperationIdSchema,
|
|
@@ -2066,8 +2157,6 @@ var PhoneChatTurnSchema = z26.object({
|
|
|
2066
2157
|
relay: PhoneChatRelaySchema.optional(),
|
|
2067
2158
|
closes: z26.array(PhoneChatCloseSchema).min(1).max(MAX_PROPOSALS).optional(),
|
|
2068
2159
|
cut: z26.literal(true).optional(),
|
|
2069
|
-
team: PhoneChatTeamSchema.optional(),
|
|
2070
|
-
tasks: z26.array(PhoneChatTaskSchema).min(1).max(MAX_PROPOSALS).optional(),
|
|
2071
2160
|
actions: z26.array(PhoneChatActionSchema).min(1).max(MAX_PROPOSALS).optional(),
|
|
2072
2161
|
ignoredAt: z26.string().datetime().optional(),
|
|
2073
2162
|
attachments: z26.array(AttachmentRefSchema).max(ATTACHMENTS_MAX).optional()
|
|
@@ -2076,30 +2165,32 @@ var CHAT_HISTORY_BUDGET = 393216;
|
|
|
2076
2165
|
var sessionId = z26.string().min(1).max(100);
|
|
2077
2166
|
var PhoneExpectSchema = PendingSchema.pick({ kind: true, text: true }).extend({ key: z26.string().min(1).max(64) });
|
|
2078
2167
|
var CardRowsSchema = z26.array(z26.number().int().min(0).max(MAX_PROPOSALS - 1)).min(1).max(MAX_PROPOSALS).refine((r) => new Set(r).size === r.length, "a row twice");
|
|
2079
|
-
var
|
|
2168
|
+
var signedOp = { op: OperationIdSchema, assertion: AssertionSchema.optional() };
|
|
2080
2169
|
var PcActionSchema = z26.enum(["update", "restart"]);
|
|
2081
2170
|
var pcSubject = (action, version) => action === "update" ? `update@${version ?? ""}` : "restart";
|
|
2082
|
-
var teamsScope = { scope: DefinitionScopeSchema, project: z26.string().min(1).max(80).optional() };
|
|
2083
2171
|
var PhoneClientMessageSchema = z26.discriminatedUnion("type", [
|
|
2084
2172
|
z26.object({ type: z26.literal("snapshot.request") }),
|
|
2173
|
+
...phoneOpenRigClientMessages,
|
|
2085
2174
|
z26.object({ type: z26.literal("session.thread"), id: sessionId }),
|
|
2086
2175
|
/** The session's request with its whole body (up to `PENDING_BODY_MAX`). */
|
|
2087
2176
|
z26.object({ type: z26.literal("session.pending"), id: sessionId }),
|
|
2088
2177
|
/** The session whose terminal the phone shows; null when it shows none. */
|
|
2089
2178
|
z26.object({ type: z26.literal("session.watch"), id: sessionId.nullable() }),
|
|
2090
2179
|
z26.object({ type: z26.literal("session.read"), id: sessionId, at: z26.string().datetime() }),
|
|
2091
|
-
/**
|
|
2180
|
+
/**
|
|
2181
|
+
* Asks for a challenge. One object for every purpose: the gateway refuses a `decide` without `id` and `expect`. A `close`
|
|
2182
|
+
* or `act` names a turn of the chat (`qid`) or a session (`id`, for `session.close` and `session.resume`).
|
|
2183
|
+
*/
|
|
2092
2184
|
z26.object({
|
|
2093
2185
|
type: z26.literal("confirm.prepare"),
|
|
2094
2186
|
purpose: ConfirmPurposeSchema,
|
|
2095
2187
|
id: sessionId.optional(),
|
|
2096
2188
|
expect: PhoneExpectSchema.optional(),
|
|
2097
2189
|
qid: OperationIdSchema.optional(),
|
|
2098
|
-
/** sha256 of the `define` or `team` operation the challenge is for (`teamsDigest`). */
|
|
2099
|
-
digest: TeamsDigestSchema.optional(),
|
|
2100
2190
|
/** A `pc` challenge: what it is for, and for an update the version it covers. */
|
|
2101
2191
|
action: PcActionSchema.optional(),
|
|
2102
|
-
version: z26.string().regex(SEMVER).optional()
|
|
2192
|
+
version: z26.string().regex(SEMVER).optional(),
|
|
2193
|
+
rig: z26.discriminatedUnion("type", [PhoneRigLaunchSchema, PhoneRigActSchema]).optional()
|
|
2103
2194
|
}),
|
|
2104
2195
|
z26.object({ type: z26.literal("credential.register"), op: OperationIdSchema, credential: CredentialSchema }),
|
|
2105
2196
|
z26.object({
|
|
@@ -2134,6 +2225,14 @@ var PhoneClientMessageSchema = z26.discriminatedUnion("type", [
|
|
|
2134
2225
|
expect: PhoneExpectSchema
|
|
2135
2226
|
}),
|
|
2136
2227
|
z26.object({ type: z26.literal("session.interrupt"), op: OperationIdSchema, id: sessionId }),
|
|
2228
|
+
/** Ends a live session as `/exit` would, killed as a last resort; answered with its `how`. Passkey, purpose `close`, over the session. */
|
|
2229
|
+
z26.object({ type: z26.literal("session.close"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
|
|
2230
|
+
/** Starts an ended session again on its conversation. Passkey, purpose `act`, over the session. */
|
|
2231
|
+
z26.object({ type: z26.literal("session.resume"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
|
|
2232
|
+
/** 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`. */
|
|
2233
|
+
z26.object({ type: z26.literal("session.model"), op: OperationIdSchema, id: sessionId, model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
|
|
2234
|
+
/** The models an agent offers on the PC. */
|
|
2235
|
+
z26.object({ type: z26.literal("models.list"), tool: ToolSchema }),
|
|
2137
2236
|
/** The phone drops its passkey from the daemon. */
|
|
2138
2237
|
z26.object({ type: z26.literal("device.forget"), op: OperationIdSchema }),
|
|
2139
2238
|
/** The phone's push subscription, with the VAPID key it was made with (so a key change is seen). */
|
|
@@ -2150,10 +2249,6 @@ var PhoneClientMessageSchema = z26.discriminatedUnion("type", [
|
|
|
2150
2249
|
z26.object({ type: z26.literal("chat.relay"), op: OperationIdSchema, qid: OperationIdSchema }),
|
|
2151
2250
|
z26.object({ type: z26.literal("chat.launch"), op: OperationIdSchema, qid: OperationIdSchema, rows: CardRowsSchema.optional(), assertion: AssertionSchema.optional() }),
|
|
2152
2251
|
z26.object({ type: z26.literal("chat.close"), op: OperationIdSchema, qid: OperationIdSchema, rows: CardRowsSchema.optional(), assertion: AssertionSchema.optional() }),
|
|
2153
|
-
/** The turn's team card (roles spec §3.8): launched like a session card, with the device check (purpose `launch`, the turn). */
|
|
2154
|
-
z26.object({ type: z26.literal("chat.team"), op: OperationIdSchema, qid: OperationIdSchema, assertion: AssertionSchema.optional() }),
|
|
2155
|
-
/** A row of the turn's task card: given by Ledge. */
|
|
2156
|
-
z26.object({ type: z26.literal("chat.task"), op: OperationIdSchema, qid: OperationIdSchema, row: z26.number().int().min(0).max(MAX_PROPOSALS - 1) }),
|
|
2157
2252
|
/** Rows of the turn's generic card (action registry spec §5): `confirmed` as the local `chat.act`; a row whose action asks
|
|
2158
2253
|
* for a device check (`phone`) needs one assertion, purpose `act`, over the turn. */
|
|
2159
2254
|
z26.object({
|
|
@@ -2168,218 +2263,201 @@ var PhoneClientMessageSchema = z26.discriminatedUnion("type", [
|
|
|
2168
2263
|
}),
|
|
2169
2264
|
/** « Ignorer » the turn's cards, or `undo` (« Revoir »), as the local `chat.ignore`. */
|
|
2170
2265
|
z26.object({ type: z26.literal("chat.ignore"), op: OperationIdSchema, qid: OperationIdSchema, undo: z26.literal(true).optional() }),
|
|
2171
|
-
/** « Reprendre » a resting team. */
|
|
2172
|
-
z26.object({ type: z26.literal("team.resume"), op: OperationIdSchema, team: z26.string().min(1).max(40) }),
|
|
2173
|
-
/** Puts a closed task Ledge gave away from « À traiter ». */
|
|
2174
|
-
z26.object({ type: z26.literal("task.seen"), op: OperationIdSchema, task: z26.string().min(1).max(40) }),
|
|
2175
2266
|
/** Whether the phone's app is in front: a device that is visible gets no push. */
|
|
2176
2267
|
z26.object({ type: z26.literal("presence"), visible: z26.boolean() }),
|
|
2177
|
-
/** The roles, templates and problems of every scope the phone may name; then one role whole, when the catalog cut its prompt. */
|
|
2178
|
-
z26.object({ type: z26.literal("teams.catalog") }),
|
|
2179
|
-
z26.object({ type: z26.literal("teams.role"), ...teamsScope, id: RoleIdSchema }).strict(),
|
|
2180
|
-
/** `base` is the hash the phone was shown, null to create. */
|
|
2181
|
-
z26.object({ type: z26.literal("role.write"), ...teamsOp, ...teamsScope, role: PhoneRoleDraftSchema, base: DefinitionHashSchema.nullable() }).strict(),
|
|
2182
|
-
z26.object({ type: z26.literal("role.delete"), ...teamsOp, ...teamsScope, id: RoleIdSchema, base: DefinitionHashSchema }).strict(),
|
|
2183
|
-
/** No `id`: create, the id comes from the name. */
|
|
2184
|
-
z26.object({ type: z26.literal("template.write"), ...teamsOp, ...teamsScope, id: TemplateIdSchema.optional(), name: TeamNameSchema, seats: PhoneSeatsSchema, base: DefinitionHashSchema.nullable() }).strict(),
|
|
2185
|
-
z26.object({ type: z26.literal("template.delete"), ...teamsOp, ...teamsScope, id: TemplateIdSchema, base: DefinitionHashSchema }).strict(),
|
|
2186
|
-
z26.object({ type: z26.literal("team.launch"), ...teamsOp, project: z26.string().min(1).max(80), name: TeamNameSchema, seats: PhoneSeatsSchema, template: z26.string().min(1).max(64).optional() }).strict(),
|
|
2187
|
-
z26.object({ type: z26.literal("team.compose"), ...teamsOp, team: TeamIdSchema, seats: PhoneSeatsSchema }).strict(),
|
|
2188
|
-
z26.object({ type: z26.literal("team.seat"), ...teamsOp, team: TeamIdSchema, role: RoleIdSchema, action: z26.enum(["start", "restart"]) }).strict(),
|
|
2189
|
-
z26.object({ type: z26.literal("team.dissolve"), ...teamsOp, team: TeamIdSchema }).strict(),
|
|
2190
2268
|
/** Installs `version` on the PC, then restarts its daemon; the phone asks for its own build's version. Passkey, purpose `pc`. */
|
|
2191
|
-
z26.object({ type: z26.literal("daemon.update"), ...
|
|
2269
|
+
z26.object({ type: z26.literal("daemon.update"), ...signedOp, version: z26.string().regex(SEMVER) }).strict(),
|
|
2192
2270
|
/** Restarts the PC's daemon without installing anything. Passkey, purpose `pc`. */
|
|
2193
|
-
z26.object({ type: z26.literal("daemon.restart"), ...
|
|
2194
|
-
])
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2271
|
+
z26.object({ type: z26.literal("daemon.restart"), ...signedOp }).strict()
|
|
2272
|
+
]);
|
|
2273
|
+
var PhoneModelChoiceSchema = z26.object({
|
|
2274
|
+
id: ModelChoiceSchema.shape.id.max(120),
|
|
2275
|
+
label: z26.string().max(80),
|
|
2276
|
+
description: z26.string().max(200).optional(),
|
|
2277
|
+
efforts: z26.array(EffortSchema).max(8).optional(),
|
|
2278
|
+
defaultEffort: EffortSchema.optional(),
|
|
2279
|
+
isDefault: z26.boolean().optional()
|
|
2280
|
+
}).strict();
|
|
2198
2281
|
var PhoneServerMessageSchema = z26.discriminatedUnion("type", [
|
|
2199
2282
|
z26.object({ type: z26.literal("snapshot"), protocol: z26.literal(PHONE_PROTOCOL), sessions: z26.array(PhoneSessionSchema), capabilities: CapabilitiesByToolSchema, daemon: z26.object({
|
|
2200
2283
|
version: z26.string(),
|
|
2201
2284
|
name: z26.string().max(40),
|
|
2202
2285
|
boot: z26.string().uuid().optional(),
|
|
2203
|
-
|
|
2286
|
+
/** The daemon takes `session.model`. */
|
|
2287
|
+
models: z26.literal(true).optional(),
|
|
2288
|
+
/** The daemon sends `session.checklist` and a session's `checklist` summary. */
|
|
2289
|
+
checklist: z26.literal(true).optional(),
|
|
2204
2290
|
/** `update`: the daemon can install a version and restart (npm, systemd); `restart`: it can restart (systemd). */
|
|
2205
2291
|
update: z26.literal(true).optional(),
|
|
2206
|
-
restart: z26.literal(true).optional()
|
|
2207
|
-
|
|
2292
|
+
restart: z26.literal(true).optional(),
|
|
2293
|
+
/** The daemon takes `session.close` and `session.resume`. */
|
|
2294
|
+
sessionClose: z26.literal(true).optional(),
|
|
2295
|
+
openrig: z26.literal(true).optional(),
|
|
2296
|
+
answerReceipts: z26.literal(true).optional()
|
|
2297
|
+
}), openrigStatus: z26.object({ state: z26.enum(["absent", "stopped", "starting", "running", "unsupported", "error", "unreachable"]), version: z26.string().max(80).optional() }).strict().optional(), rigs: z26.array(PhoneRigSchema).max(40).optional(), escalations: z26.array(PhoneEscalationSchema).max(40).optional(), decisionsToday: z26.array(PhoneLedgeDecisionSchema).max(50).optional(), projects: z26.array(z26.object({ id: z26.string().min(1).max(80), name: z26.string().min(1).max(80), hasLocalRepo: z26.boolean() }).strict()).max(100).optional(), device: z26.object({ confirm: z26.boolean(), push: z26.enum(["on", "off", "stale", "unavailable"]).optional(), chat: z26.literal(true).optional(), contextNear: ContextPrefsSchema.shape.near.optional() }).optional() }),
|
|
2298
|
+
...phoneOpenRigServerMessages,
|
|
2208
2299
|
z26.object({
|
|
2209
2300
|
type: z26.literal("confirm.challenge"),
|
|
2210
2301
|
purpose: ConfirmPurposeSchema,
|
|
2211
2302
|
challenge: B64U2.max(64),
|
|
2212
2303
|
rpId: z26.string().max(253),
|
|
2213
2304
|
credentialId: B64U2.max(1366).optional(),
|
|
2214
|
-
expiresInMs: z26.number().int().positive()
|
|
2215
|
-
/** Echoed from the `confirm.prepare` of a `define` or `team` challenge, so the phone matches each challenge to its own call. Absent from an older gateway. */
|
|
2216
|
-
digest: TeamsDigestSchema.optional()
|
|
2305
|
+
expiresInMs: z26.number().int().positive()
|
|
2217
2306
|
}),
|
|
2218
2307
|
z26.object({ type: z26.literal("session.updated"), session: PhoneSessionSchema }),
|
|
2219
2308
|
z26.object({ type: z26.literal("session.removed"), id: z26.string() }),
|
|
2309
|
+
/** A session's checklist, sent to the phone that watches it; `null`: it has none (any more). */
|
|
2310
|
+
z26.object({ type: z26.literal("session.checklist"), id: z26.string(), checklist: PhoneChecklistSchema.nullable() }),
|
|
2220
2311
|
/** `pending.cut` is set when even this body was shortened. */
|
|
2221
2312
|
z26.object({ type: z26.literal("session.pending"), id: z26.string(), pending: PhonePendingSchema }),
|
|
2222
2313
|
z26.object({ type: z26.literal("session.preview"), id: z26.string(), lines: z26.array(z26.string()) }),
|
|
2223
2314
|
/** `cut`: the ids of the items shortened; `more`: older items were left out. */
|
|
2224
2315
|
z26.object({ type: z26.literal("session.thread"), id: z26.string(), items: z26.array(ThreadItemSchema), cut: z26.array(z26.string()), more: z26.boolean() }),
|
|
2225
2316
|
z26.object({ type: z26.literal("session.thread.item"), id: z26.string(), item: ThreadItemSchema, cut: z26.literal(true).optional() }),
|
|
2226
|
-
z26.object({
|
|
2317
|
+
z26.object({
|
|
2318
|
+
type: z26.literal("operation.result"),
|
|
2319
|
+
op: OperationIdSchema,
|
|
2320
|
+
status: OperationStatusSchema,
|
|
2321
|
+
reason: OperationReasonSchema.optional(),
|
|
2322
|
+
/** How an applied `session.close` ended the agent: `killed` when it had to be forced. */
|
|
2323
|
+
how: CloseHowSchema.optional()
|
|
2324
|
+
}),
|
|
2325
|
+
/** The models an agent offers; `error`: it could not be asked, `models` is then what Ledge knows without it. */
|
|
2326
|
+
z26.object({ type: z26.literal("models.listing"), tool: ToolSchema, models: z26.array(PhoneModelChoiceSchema).max(40), error: z26.literal(true).optional() }),
|
|
2327
|
+
/** A model change that was accepted and then failed (the agent could not restart). */
|
|
2328
|
+
z26.object({ type: z26.literal("session.model.failed"), id: z26.string(), reason: ModelRefusalSchema }),
|
|
2227
2329
|
z26.object({ type: z26.literal("chat.history"), turns: z26.array(PhoneChatTurnSchema).max(50) }),
|
|
2228
2330
|
z26.object({ type: z26.literal("chat.step"), qid: OperationIdSchema, step: PhoneChatStepSchema }),
|
|
2229
2331
|
/** The whole text so far, not an increment. */
|
|
2230
2332
|
z26.object({ type: z26.literal("chat.delta"), qid: OperationIdSchema, text: z26.string().max(THREAD_TEXT_MAX) }),
|
|
2231
2333
|
z26.object({ type: z26.literal("chat.done"), qid: OperationIdSchema, turn: PhoneChatTurnSchema }),
|
|
2232
2334
|
z26.object({ type: z26.literal("chat.error"), qid: OperationIdSchema, code: ChatErrorCodeSchema }),
|
|
2233
|
-
z26.object({ type: z26.literal("teams.catalog"), catalog: PhoneCatalogSchema }),
|
|
2234
2335
|
/** The daemon updating or restarting itself, whoever asked: npm runs, then the service restarts (the link drops right after). */
|
|
2235
2336
|
z26.object({ type: z26.literal("daemon.progress"), version: z26.string().max(40), step: z26.enum(["installing", "restarting"]) }),
|
|
2236
2337
|
/** Nothing was changed. Never npm's output nor a command: both hold the PC's paths. */
|
|
2237
2338
|
z26.object({ type: z26.literal("daemon.failed"), version: z26.string().max(40), reason: UpdateFailureSchema }),
|
|
2238
|
-
z26.object({ type: z26.literal("teams.role"), role: PhoneRoleSchema }),
|
|
2239
|
-
/** The live teams, after each snapshot and on every change. */
|
|
2240
|
-
z26.object({ type: z26.literal("teams"), teams: z26.array(PhoneTeamSchema).max(50) }),
|
|
2241
|
-
/** The tasks Ledge gave, open or closed lately, after each snapshot; then each change. */
|
|
2242
|
-
z26.object({ type: z26.literal("tasks"), tasks: z26.array(PhoneTaskSchema).max(200) }),
|
|
2243
|
-
z26.object({ type: z26.literal("task.updated"), task: PhoneTaskSchema }),
|
|
2244
2339
|
AttachmentStoredSchema,
|
|
2245
2340
|
AttachmentDataSchema,
|
|
2246
2341
|
AttachmentErrorSchema,
|
|
2247
2342
|
/** Never carries free text. */
|
|
2248
2343
|
z26.object({ type: z26.literal("error"), code: z26.enum(["invalid", "unknown_session", "too_large"]), request: z26.string().max(40).optional() })
|
|
2249
2344
|
]);
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2345
|
+
function canonicalJson(v) {
|
|
2346
|
+
const sort = (x) => {
|
|
2347
|
+
if (Array.isArray(x)) return x.map(sort);
|
|
2348
|
+
if (x !== null && typeof x === "object") {
|
|
2349
|
+
const o = x;
|
|
2350
|
+
return Object.fromEntries(Object.keys(o).sort().filter((k) => o[k] !== void 0).map((k) => [k, sort(o[k])]));
|
|
2351
|
+
}
|
|
2352
|
+
return x;
|
|
2353
|
+
};
|
|
2354
|
+
return JSON.stringify(sort(v));
|
|
2257
2355
|
}
|
|
2258
2356
|
|
|
2259
|
-
// src/
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
var
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
if (!host || host.includes(" ") || host.endsWith(".")) return false;
|
|
2279
|
-
let name;
|
|
2280
|
-
if (host.startsWith("[")) {
|
|
2281
|
-
const end = host.indexOf("]");
|
|
2282
|
-
if (end < 0) return false;
|
|
2283
|
-
name = host.slice(1, end);
|
|
2284
|
-
const rest = host.slice(end + 1);
|
|
2285
|
-
if (rest !== "" && !/^:\d{1,5}$/.test(rest)) return false;
|
|
2286
|
-
} else {
|
|
2287
|
-
const colon = host.lastIndexOf(":");
|
|
2288
|
-
if (colon >= 0) {
|
|
2289
|
-
if (!/^\d{1,5}$/.test(host.slice(colon + 1))) return false;
|
|
2290
|
-
name = host.slice(0, colon);
|
|
2291
|
-
} else name = host;
|
|
2357
|
+
// ../protocol/src/todos.ts
|
|
2358
|
+
var TODO_TOOLS = /* @__PURE__ */ new Set(["TodoWrite", "update_plan", "todo"]);
|
|
2359
|
+
var STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress", "completed"]);
|
|
2360
|
+
var statusOf = (s) => typeof s === "string" && STATUSES.has(s) ? s : "pending";
|
|
2361
|
+
var text = (s) => typeof s === "string" && s.trim() !== "" ? s : null;
|
|
2362
|
+
var record = (v) => v && typeof v === "object" ? v : {};
|
|
2363
|
+
function omp(input) {
|
|
2364
|
+
if (!Array.isArray(input.phases)) return void 0;
|
|
2365
|
+
const phases = input.phases.map(record);
|
|
2366
|
+
const out = [];
|
|
2367
|
+
for (const ph of phases) {
|
|
2368
|
+
for (const raw of Array.isArray(ph.tasks) ? ph.tasks : []) {
|
|
2369
|
+
const e = record(raw);
|
|
2370
|
+
const said = text(e.content);
|
|
2371
|
+
if (said === null) continue;
|
|
2372
|
+
const blocked = e.status === "blocked";
|
|
2373
|
+
const name = phases.length > 1 ? text(ph.name) : null;
|
|
2374
|
+
out.push({ text: `${name ? `${name} \xB7 ` : ""}${said}${blocked && text(e.blocker) ? ` (blocked: ${e.blocker})` : ""}`, status: blocked ? "pending" : statusOf(e.status) });
|
|
2375
|
+
}
|
|
2292
2376
|
}
|
|
2293
|
-
return
|
|
2294
|
-
}
|
|
2295
|
-
function headerValue(value, max) {
|
|
2296
|
-
const raw = Array.isArray(value) ? value.join(",") : value;
|
|
2297
|
-
return !raw || raw.length > max ? "" : raw;
|
|
2298
|
-
}
|
|
2299
|
-
function bearerToken(authorization) {
|
|
2300
|
-
if (!authorization || authorization.length > 512) return "";
|
|
2301
|
-
return /^Bearer[ \t]+(\S+)$/i.exec(authorization)?.[1] ?? "";
|
|
2377
|
+
return out;
|
|
2302
2378
|
}
|
|
2303
|
-
function
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2379
|
+
function listOf(t) {
|
|
2380
|
+
if (!TODO_TOOLS.has(t.tool) || t.input === void 0) return void 0;
|
|
2381
|
+
let input;
|
|
2382
|
+
try {
|
|
2383
|
+
input = record(JSON.parse(t.input));
|
|
2384
|
+
} catch {
|
|
2385
|
+
return void 0;
|
|
2309
2386
|
}
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
const
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
if (
|
|
2387
|
+
if (t.tool === "todo") return omp(input);
|
|
2388
|
+
const claude = t.tool === "TodoWrite";
|
|
2389
|
+
const list = claude ? input.todos : input.plan;
|
|
2390
|
+
if (!Array.isArray(list)) return void 0;
|
|
2391
|
+
const out = [];
|
|
2392
|
+
for (const raw of list) {
|
|
2393
|
+
const e = record(raw);
|
|
2394
|
+
const status = statusOf(e.status);
|
|
2395
|
+
const said = claude ? status === "in_progress" ? text(e.activeForm) ?? text(e.content) : text(e.content) : text(e.step);
|
|
2396
|
+
if (said !== null) out.push({ text: said, status });
|
|
2320
2397
|
}
|
|
2321
|
-
return
|
|
2398
|
+
return out;
|
|
2322
2399
|
}
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
const
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
if (
|
|
2329
|
-
throw e;
|
|
2400
|
+
function latestTodos(items, helperId) {
|
|
2401
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
2402
|
+
const it = items[i];
|
|
2403
|
+
if (it.kind !== "tool" || it.helperId !== helperId || !TODO_TOOLS.has(it.tool)) continue;
|
|
2404
|
+
const list = listOf(it);
|
|
2405
|
+
if (list) return list.length > 0 ? list : null;
|
|
2330
2406
|
}
|
|
2407
|
+
return null;
|
|
2331
2408
|
}
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
try {
|
|
2349
|
-
await link(tmp, file);
|
|
2350
|
-
} catch (e) {
|
|
2351
|
-
await unlink(tmp).catch(() => {
|
|
2352
|
-
});
|
|
2353
|
-
if (e.code !== "EEXIST") throw e;
|
|
2354
|
-
const raced = await readTokenFile(file);
|
|
2355
|
-
if (raced) {
|
|
2356
|
-
await lockTokenFile(file);
|
|
2357
|
-
return raced;
|
|
2409
|
+
var doneCount = (todos) => todos.filter((x) => x.status === "completed").length;
|
|
2410
|
+
|
|
2411
|
+
// ../protocol/src/mandate.ts
|
|
2412
|
+
var SELF_TITLE = "ledge tranche seul";
|
|
2413
|
+
var USER_TITLE = "te revient toujours";
|
|
2414
|
+
var isAlways = (id2) => ALWAYS_USER.includes(id2);
|
|
2415
|
+
function mandateEntries(text2) {
|
|
2416
|
+
const out = { self: [], user: [], always: [], readable: false };
|
|
2417
|
+
let list = null;
|
|
2418
|
+
for (const raw of text2.split("\n")) {
|
|
2419
|
+
const line = raw.trim();
|
|
2420
|
+
if (line.startsWith("#")) {
|
|
2421
|
+
const title = line.replace(/^#+\s*/, "").toLowerCase();
|
|
2422
|
+
list = title.startsWith(SELF_TITLE) ? "self" : title.startsWith(USER_TITLE) ? "user" : null;
|
|
2423
|
+
if (list) out.readable = true;
|
|
2424
|
+
continue;
|
|
2358
2425
|
}
|
|
2359
|
-
|
|
2360
|
-
|
|
2426
|
+
const item = /^[-*]\s+(.+)$/.exec(line)?.[1];
|
|
2427
|
+
if (!list || !item) continue;
|
|
2428
|
+
const m = /^(\S+)\s+:\s+(.+)$/.exec(item);
|
|
2429
|
+
const entry = { id: m?.[1], said: (m?.[2] ?? item).trim() };
|
|
2430
|
+
if (list === "self" && entry.id && isAlways(entry.id)) out.always.push(entry);
|
|
2431
|
+
else out[list].push(entry);
|
|
2361
2432
|
}
|
|
2362
|
-
|
|
2363
|
-
});
|
|
2364
|
-
await lockTokenFile(file);
|
|
2365
|
-
const stored = await readTokenFile(file);
|
|
2366
|
-
if (!stored) throw new Error("daemon token was not stored");
|
|
2367
|
-
return stored;
|
|
2368
|
-
}
|
|
2369
|
-
var SESSION_KEY_VAR = "LEDGE_SESSION_KEY";
|
|
2370
|
-
function sessionKey(id, token = readDaemonToken()) {
|
|
2371
|
-
return token ? createHmac("sha256", token).update(`ledge-session:${id}`).digest("hex") : void 0;
|
|
2433
|
+
return out;
|
|
2372
2434
|
}
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
}
|
|
2435
|
+
var known = (id2) => {
|
|
2436
|
+
const r = MandateCategorySchema.safeParse(id2);
|
|
2437
|
+
return r.success ? r.data : null;
|
|
2438
|
+
};
|
|
2439
|
+
function parseMandate(text2) {
|
|
2440
|
+
const e = mandateEntries(text2);
|
|
2441
|
+
if (!e.readable) return { self: [], user: [], readable: false };
|
|
2442
|
+
const uniq = (xs) => [...new Set(xs.filter((x) => x !== null))];
|
|
2443
|
+
const user = uniq([...e.user, ...e.always].map((x) => known(x.id)));
|
|
2444
|
+
return { self: uniq(e.self.map((x) => known(x.id))).filter((c) => !user.includes(c)), user, readable: true };
|
|
2380
2445
|
}
|
|
2381
2446
|
|
|
2382
2447
|
export {
|
|
2448
|
+
tokenEquals,
|
|
2449
|
+
hostAllowed,
|
|
2450
|
+
requestAuthorized,
|
|
2451
|
+
selectDaemonProtocol,
|
|
2452
|
+
ensureDaemonToken,
|
|
2453
|
+
SESSION_KEY_VAR,
|
|
2454
|
+
sessionKey,
|
|
2455
|
+
readDaemonToken,
|
|
2456
|
+
ASK_QUESTION_MAX,
|
|
2457
|
+
ASK_OPTIONS_MAX,
|
|
2458
|
+
ASK_ANSWER_MAX,
|
|
2459
|
+
AskSchema,
|
|
2460
|
+
askShown,
|
|
2383
2461
|
ATTACHMENT_ID,
|
|
2384
2462
|
ATTACHMENT_MAX,
|
|
2385
2463
|
ATTACHMENT_LOCAL_MAX,
|
|
@@ -2390,6 +2468,7 @@ export {
|
|
|
2390
2468
|
CONTEXT_NEAR_MIN,
|
|
2391
2469
|
CONTEXT_NEAR_MAX,
|
|
2392
2470
|
ContextPrefsSchema,
|
|
2471
|
+
contextShare,
|
|
2393
2472
|
contextNear,
|
|
2394
2473
|
BRIEF_MAX,
|
|
2395
2474
|
ToolSchema,
|
|
@@ -2400,37 +2479,16 @@ export {
|
|
|
2400
2479
|
isArchived,
|
|
2401
2480
|
ModelIdSchema,
|
|
2402
2481
|
EffortSchema,
|
|
2482
|
+
ModelRefusalSchema,
|
|
2403
2483
|
extractProposal,
|
|
2404
2484
|
parseRelayBlock,
|
|
2405
2485
|
parseCloseBlock,
|
|
2406
|
-
parseTeamBlock,
|
|
2407
|
-
parseTaskBlock,
|
|
2408
2486
|
parseProjectBlock,
|
|
2409
|
-
SshAliasSchema,
|
|
2410
|
-
MachinesSchema,
|
|
2411
|
-
PROJECT_COLORS,
|
|
2412
|
-
ProjectsSchema,
|
|
2413
|
-
DEFAULT_PROJECTS,
|
|
2414
|
-
projectOf,
|
|
2415
|
-
RoleIdSchema,
|
|
2416
|
-
ROLE_LABEL_MAX,
|
|
2417
|
-
ROLE_PROMPT_MAX,
|
|
2418
|
-
RoleSchema,
|
|
2419
|
-
SeatsSchema,
|
|
2420
|
-
TeamNameSchema,
|
|
2421
|
-
TemplateIdSchema,
|
|
2422
|
-
TeamSchema,
|
|
2423
|
-
isTeamLive,
|
|
2424
2487
|
NOTE_MAX,
|
|
2425
2488
|
NOTE_NOT_TYPED,
|
|
2426
2489
|
offers,
|
|
2427
2490
|
pendingKey,
|
|
2428
|
-
|
|
2429
|
-
TASK_TEXT_MAX,
|
|
2430
|
-
LEDGE_GIVER,
|
|
2431
|
-
transmissions,
|
|
2432
|
-
givenByLedge,
|
|
2433
|
-
taskClosed,
|
|
2491
|
+
ActionIdSchema,
|
|
2434
2492
|
ACTIONS,
|
|
2435
2493
|
actionById,
|
|
2436
2494
|
riskOf,
|
|
@@ -2443,10 +2501,29 @@ export {
|
|
|
2443
2501
|
ChatTurnSchema,
|
|
2444
2502
|
proposalRows,
|
|
2445
2503
|
DOCUMENT_MAX_BYTES,
|
|
2504
|
+
SshAliasSchema,
|
|
2505
|
+
MachinesSchema,
|
|
2446
2506
|
IslandPrefsSchema,
|
|
2507
|
+
PROJECT_COLORS,
|
|
2508
|
+
ProjectsSchema,
|
|
2509
|
+
DEFAULT_PROJECTS,
|
|
2510
|
+
projectOf,
|
|
2447
2511
|
RouteResultSchema,
|
|
2448
2512
|
DEFAULT_RELAY_URL,
|
|
2449
2513
|
MobileConfigSchema,
|
|
2514
|
+
MandateCategorySchema,
|
|
2515
|
+
ALWAYS_USER,
|
|
2516
|
+
MANDATE_CATEGORY_LABEL,
|
|
2517
|
+
RIG_NAME,
|
|
2518
|
+
EscalationSchema,
|
|
2519
|
+
EXCHANGES_MAX,
|
|
2520
|
+
EXCHANGE_GROUP_MS,
|
|
2521
|
+
THREAD_PAGE,
|
|
2522
|
+
LedgeDecisionSchema,
|
|
2523
|
+
LedgeRuleSchema,
|
|
2524
|
+
LedgeThreadItemSchema,
|
|
2525
|
+
BRAIN_OPS,
|
|
2526
|
+
BRAIN_STOPPED_TEXT,
|
|
2450
2527
|
PROTOCOL_PORT,
|
|
2451
2528
|
RefusalCodeSchema,
|
|
2452
2529
|
RecentSchema,
|
|
@@ -2466,20 +2543,19 @@ export {
|
|
|
2466
2543
|
RELAY_CLOSE_SIGNED_OUT,
|
|
2467
2544
|
DeviceStartResponseSchema,
|
|
2468
2545
|
DevicePollResponseSchema,
|
|
2546
|
+
rigSubject,
|
|
2469
2547
|
pushEndpointAllowed,
|
|
2470
2548
|
PushSendResultSchema,
|
|
2471
2549
|
PushPayloadSchema,
|
|
2472
|
-
PhoneRoleSchema,
|
|
2473
|
-
PhoneTemplateSchema,
|
|
2474
|
-
TEAMS_OPERATION_TYPES,
|
|
2475
|
-
isTeamsOperation,
|
|
2476
|
-
canonicalJson,
|
|
2477
2550
|
PHONE_PROTOCOL,
|
|
2551
|
+
PLAIN_MAX,
|
|
2478
2552
|
padPlain,
|
|
2479
2553
|
THREAD_ITEMS_MAX,
|
|
2480
2554
|
THREAD_BUDGET,
|
|
2481
2555
|
THREAD_TEXT_MAX,
|
|
2482
2556
|
TOOL_TEXT_MAX,
|
|
2557
|
+
CHECKLIST_TASKS_MAX,
|
|
2558
|
+
CHECKLIST_TEXT_MAX,
|
|
2483
2559
|
PENDING_BODY_MAX,
|
|
2484
2560
|
SNAPSHOT_BODY_MAX,
|
|
2485
2561
|
OperationIdSchema,
|
|
@@ -2487,14 +2563,11 @@ export {
|
|
|
2487
2563
|
CHAT_HISTORY_BUDGET,
|
|
2488
2564
|
pcSubject,
|
|
2489
2565
|
PhoneClientMessageSchema,
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
SESSION_KEY_VAR,
|
|
2498
|
-
sessionKey,
|
|
2499
|
-
readDaemonToken
|
|
2566
|
+
PhoneModelChoiceSchema,
|
|
2567
|
+
canonicalJson,
|
|
2568
|
+
TODO_TOOLS,
|
|
2569
|
+
latestTodos,
|
|
2570
|
+
doneCount,
|
|
2571
|
+
mandateEntries,
|
|
2572
|
+
parseMandate
|
|
2500
2573
|
};
|