@paradow/ledge 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/cli/{action-7SJJTIEA.js → action-MAPPYLUM.js} +4 -4
  2. package/dist/cli/{attach-V7UPHVB2.js → attach-OC64CLB2.js} +8 -8
  3. package/dist/cli/{bridge-JK3PMG7T.js → bridge-TWX4V37E.js} +1 -1
  4. package/dist/cli/{chunk-IGAGJVRZ.js → chunk-353WRRGG.js} +3 -3
  5. package/dist/cli/{chunk-UPKJO3BZ.js → chunk-73YNZ3BN.js} +1 -1
  6. package/dist/cli/{chunk-37G5F75H.js → chunk-7S7ZLGIY.js} +150 -13
  7. package/dist/cli/{chunk-TOSPL5H2.js → chunk-ETGOWBUL.js} +3 -3
  8. package/dist/cli/chunk-JZEWCO6X.js +6 -0
  9. package/dist/cli/{chunk-ADAGKOFO.js → chunk-K3SDHHZF.js} +1 -1
  10. package/dist/cli/{chunk-RA3OIXEQ.js → chunk-MZVMW356.js} +2 -2
  11. package/dist/cli/{chunk-7GIUG73R.js → chunk-RFFTWAAF.js} +1 -1
  12. package/dist/cli/{chunk-7OGFH6KJ.js → chunk-TNYBWWRO.js} +2 -2
  13. package/dist/cli/{chunk-CVHX7GUB.js → chunk-TREGH6WM.js} +353 -49
  14. package/dist/cli/{chunk-7JRQCKBP.js → chunk-UWDE365N.js} +2 -2
  15. package/dist/cli/{chunk-YLN3VOGV.js → chunk-WCBXS3EU.js} +2 -2
  16. package/dist/cli/{chunk-ISNHG5SJ.js → chunk-WIUJNSAZ.js} +5 -5
  17. package/dist/cli/{chunk-2N7PSP7C.js → chunk-XZYQMKKO.js} +3 -3
  18. package/dist/cli/{daemon-YUPB5NUG.js → daemon-ZTZ7VMYA.js} +7 -7
  19. package/dist/cli/{decide-HFI2WQXI.js → decide-4BIYS3Y2.js} +3 -3
  20. package/dist/cli/{handover-GKORMXZ2.js → handover-IS7BJYGZ.js} +4 -4
  21. package/dist/cli/{hook-TJJEFV54.js → hook-3VKVD4IP.js} +9 -9
  22. package/dist/cli/index.js +16 -16
  23. package/dist/cli/{launch-QKQZZSIM.js → launch-XAPN2M3Q.js} +8 -8
  24. package/dist/cli/{send-RI7JOO5K.js → send-ZLF2ZXMJ.js} +4 -4
  25. package/dist/cli/{status-RQRS26S2.js → status-NONO6E2S.js} +2 -2
  26. package/dist/cli/{task-U2XHBUKW.js → task-47MVWDCY.js} +4 -4
  27. package/dist/cli/{team-NFC4XEIA.js → team-EJ4YIXJH.js} +6 -6
  28. package/dist/cli/{tui-UWR7SDYF.js → tui-CAP4O4YQ.js} +8 -8
  29. package/dist/cli/{version-YYNMMWKJ.js → version-EHBPJO7K.js} +1 -1
  30. package/dist/cli/{who-WW6IL4KD.js → who-FHAXYCM2.js} +3 -3
  31. package/package.json +1 -1
  32. package/dist/cli/chunk-HMTOPOJG.js +0 -6
@@ -8,10 +8,10 @@ import {
8
8
  resultLine,
9
9
  runClose,
10
10
  runOnClient
11
- } from "./chunk-IGAGJVRZ.js";
12
- import "./chunk-ADAGKOFO.js";
13
- import "./chunk-7GIUG73R.js";
14
- import "./chunk-37G5F75H.js";
11
+ } from "./chunk-353WRRGG.js";
12
+ import "./chunk-K3SDHHZF.js";
13
+ import "./chunk-RFFTWAAF.js";
14
+ import "./chunk-7S7ZLGIY.js";
15
15
  import "./chunk-HOOHS3MX.js";
16
16
  import "./chunk-U67V476Y.js";
17
17
  export {
@@ -1,19 +1,19 @@
1
1
  import {
2
2
  attachEnv
3
- } from "./chunk-ISNHG5SJ.js";
4
- import "./chunk-CVHX7GUB.js";
3
+ } from "./chunk-WIUJNSAZ.js";
4
+ import "./chunk-TREGH6WM.js";
5
5
  import "./chunk-OLLQBK6N.js";
6
- import "./chunk-YLN3VOGV.js";
7
- import "./chunk-7JRQCKBP.js";
8
- import "./chunk-UPKJO3BZ.js";
9
- import "./chunk-ADAGKOFO.js";
6
+ import "./chunk-WCBXS3EU.js";
7
+ import "./chunk-UWDE365N.js";
8
+ import "./chunk-73YNZ3BN.js";
9
+ import "./chunk-K3SDHHZF.js";
10
10
  import {
11
11
  connect
12
- } from "./chunk-7GIUG73R.js";
12
+ } from "./chunk-RFFTWAAF.js";
13
13
  import {
14
14
  PROTOCOL_PORT,
15
15
  backendOf
16
- } from "./chunk-37G5F75H.js";
16
+ } from "./chunk-7S7ZLGIY.js";
17
17
  import {
18
18
  realTmux
19
19
  } from "./chunk-NLL2EQJ2.js";
@@ -7,7 +7,7 @@ import {
7
7
  parseClientMessage,
8
8
  parseServerMessage,
9
9
  readDaemonToken
10
- } from "./chunk-37G5F75H.js";
10
+ } from "./chunk-7S7ZLGIY.js";
11
11
  import "./chunk-HOOHS3MX.js";
12
12
  import "./chunk-U67V476Y.js";
13
13
 
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-ADAGKOFO.js";
3
+ } from "./chunk-K3SDHHZF.js";
4
4
  import {
5
5
  connect
6
- } from "./chunk-7GIUG73R.js";
6
+ } from "./chunk-RFFTWAAF.js";
7
7
  import {
8
8
  SESSION_KEY_VAR,
9
9
  actionById
10
- } from "./chunk-37G5F75H.js";
10
+ } from "./chunk-7S7ZLGIY.js";
11
11
 
12
12
  // src/cli/action.ts
13
13
  import { randomUUID } from "crypto";
@@ -2,7 +2,7 @@ import {
2
2
  ROLE_LABEL_MAX,
3
3
  ROLE_PROMPT_MAX,
4
4
  RoleSchema
5
- } from "./chunk-37G5F75H.js";
5
+ } from "./chunk-7S7ZLGIY.js";
6
6
  import {
7
7
  log
8
8
  } from "./chunk-6IYPRUQG.js";
@@ -203,6 +203,8 @@ var ModelsListingSchema = z3.object({
203
203
  models: z3.array(ModelChoiceSchema),
204
204
  error: z3.string().optional()
205
205
  });
206
+ var ModelRefusalSchema = z3.enum(["not_launched", "ended", "no_conversation", "not_running", "effort_in_model", "restart_failed", "refused"]);
207
+ var SessionModelAcceptedSchema = z3.object({ type: z3.literal("session.model.accepted"), id: z3.string(), when: z3.enum(["now", "turn", "none"]) });
206
208
 
207
209
  // ../protocol/src/projects.ts
208
210
  import { z as z6 } from "zod";
@@ -412,7 +414,8 @@ var DefinitionsListingSchema = z7.object({
412
414
  }))
413
415
  });
414
416
  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() });
417
+ var SeatModelOutcomeSchema = z7.object({ role: z7.string(), session: z7.string(), when: z7.enum(["now", "turn"]).optional(), code: ModelRefusalSchema.optional() });
418
+ var TeamChangedSchema = z7.object({ type: z7.literal("team.changed"), rid: z7.string(), team: TeamSchema.optional(), reason: z7.string().optional(), models: z7.array(SeatModelOutcomeSchema).max(16).optional() });
416
419
  var TeamsMessageSchema = z7.object({ type: z7.literal("teams"), teams: z7.array(TeamSchema) });
417
420
  var TeamUpdatedSchema = z7.object({ type: z7.literal("team.updated"), team: TeamSchema });
418
421
  var TeamLaunchedSchema = z7.object({ type: z7.literal("team.launched"), rid: z7.string(), team: TeamSchema });
@@ -514,12 +517,12 @@ var TaskBlockSchema = z9.object({
514
517
  var BLOCK = /```ledge-(session|relay|project|close|team|task|action)[ \t]*\n?([\s\S]*?)(?:```|$)/g;
515
518
  function extractProposal(answer) {
516
519
  const found = [];
517
- const text = answer.replace(BLOCK, (_m, kind, body) => {
520
+ const text2 = answer.replace(BLOCK, (_m, kind, body) => {
518
521
  found.push({ kind, raw: body.trim() });
519
522
  return "";
520
523
  });
521
524
  const last = found.at(-1);
522
- return last ? { text: text.replace(/\n{3,}/g, "\n\n").trim(), kind: last.kind, raw: last.raw, blocks: found } : { text: answer, kind: null, raw: null, blocks: [] };
525
+ 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
526
  }
524
527
  function parseRelayBlock(raw) {
525
528
  try {
@@ -1343,6 +1346,7 @@ var DaemonInfoSchema = z21.object({
1343
1346
  });
1344
1347
  var UpdateFailureSchema = z21.enum(["git-install", "no-systemd", "sessions-at-risk", "npm-failed", "busy"]);
1345
1348
  var ServerMessageSchema = z21.discriminatedUnion("type", [
1349
+ SessionModelAcceptedSchema,
1346
1350
  z21.object({ type: z21.literal("chat.routed"), qid: z21.string(), result: RouteResultSchema }),
1347
1351
  DocumentContentSchema,
1348
1352
  DocumentErrorSchema,
@@ -1717,8 +1721,8 @@ function pickName(taken, preferred) {
1717
1721
 
1718
1722
  // ../protocol/src/topic.ts
1719
1723
  var TOPIC_MAX = 80;
1720
- function cleanTopic(text) {
1721
- const line = text.split(/\r?\n/).map((l) => l.trim()).find((l) => l.length > 0) ?? "";
1724
+ function cleanTopic(text2) {
1725
+ const line = text2.split(/\r?\n/).map((l) => l.trim()).find((l) => l.length > 0) ?? "";
1722
1726
  const flat = line.replace(/\s+/g, " ");
1723
1727
  return flat.length > TOPIC_MAX ? `${flat.slice(0, TOPIC_MAX - 1).trimEnd()}\u2026` : flat;
1724
1728
  }
@@ -1903,13 +1907,28 @@ var THREAD_ITEMS_MAX = 200;
1903
1907
  var THREAD_BUDGET = 524288;
1904
1908
  var THREAD_TEXT_MAX = 8192;
1905
1909
  var TOOL_TEXT_MAX = 2048;
1910
+ var CHECKLIST_TASKS_MAX = 50;
1911
+ var CHECKLIST_TEXT_MAX = 200;
1912
+ var ChecklistStatusSchema = z26.enum(["pending", "in_progress", "completed"]);
1913
+ var PhoneChecklistSchema = z26.object({
1914
+ tasks: z26.array(z26.object({ text: z26.string().max(CHECKLIST_TEXT_MAX), status: ChecklistStatusSchema })).max(CHECKLIST_TASKS_MAX),
1915
+ done: z26.number().int().nonnegative(),
1916
+ total: z26.number().int().nonnegative(),
1917
+ cut: z26.literal(true).optional()
1918
+ });
1919
+ var PhoneChecklistSummarySchema = z26.object({
1920
+ done: z26.number().int().nonnegative(),
1921
+ total: z26.number().int().nonnegative(),
1922
+ current: z26.string().max(CHECKLIST_TEXT_MAX).optional(),
1923
+ cut: z26.literal(true).optional()
1924
+ });
1906
1925
  var PENDING_BODY_MAX = 65536;
1907
1926
  var SNAPSHOT_BODY_MAX = 2048;
1908
1927
  var RiskSchema = z26.enum(["low", "high"]);
1909
1928
  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
1929
  var OperationIdSchema = z26.string().uuid();
1911
1930
  var OperationStatusSchema = z26.enum(["received", "applied", "rejected", "failed"]);
1912
- var OperationReasonSchema = z26.enum([...RefusalCodeSchema.options, "untypable", "confirm_required", "conflict", "assertion_invalid", "assertion_expired", "changed", "exists", "unknown_project", "seat_failed"]);
1931
+ var OperationReasonSchema = z26.enum([...RefusalCodeSchema.options, "untypable", "confirm_required", "conflict", "assertion_invalid", "assertion_expired", "changed", "exists", "unknown_project", "seat_failed", "scheduled", ...ModelRefusalSchema.options]);
1913
1932
  var CapabilitiesSchema = z26.object({
1914
1933
  /** A question can be answered in free text. */
1915
1934
  freeTextAnswer: z26.boolean(),
@@ -1921,7 +1940,8 @@ var CapabilitiesSchema = z26.object({
1921
1940
  var UNTYPABLE = /[\u0000-\u001f\u007f-\u009f\u200b\u200e\u200f\u2028-\u202e\u2066-\u2069\ufeff]/;
1922
1941
  var CapabilitiesByToolSchema = z26.object({ claude: CapabilitiesSchema, codex: CapabilitiesSchema, cursor: CapabilitiesSchema, omp: CapabilitiesSchema });
1923
1942
  var PhonePendingSchema = PendingSchema.extend({ key: z26.string().max(64), risk: RiskSchema, riskReason: RiskReasonSchema, cut: z26.literal(true).optional() });
1924
- var PhoneSessionSchema = SessionSchema.pick({
1943
+ var SwitchableSessionSchema = SessionSchema.extend({ canSwitch: z26.literal(true).optional() });
1944
+ var PhoneSessionSchema = SwitchableSessionSchema.pick({
1925
1945
  id: true,
1926
1946
  name: true,
1927
1947
  tool: true,
@@ -1936,14 +1956,29 @@ var PhoneSessionSchema = SessionSchema.pick({
1936
1956
  lastReply: true,
1937
1957
  startedAt: true,
1938
1958
  lastActivityAt: true,
1959
+ /** Its model, effort and the change waiting for its next free moment: the phone shows them and offers to change them. */
1960
+ model: true,
1961
+ effort: true,
1962
+ modelNext: true,
1963
+ canSwitch: true,
1939
1964
  /** Its role and its live team (ledge home spec §2.4): the agents screen groups a project's sessions by table. */
1940
1965
  role: true,
1941
1966
  roleLabel: true,
1942
1967
  team: true,
1943
1968
  /** Its context and its relief (context handover spec §3.2): the phone shows the gauge; the relief is started from the PC. */
1944
1969
  context: true,
1945
- relieves: true
1946
- }).extend({ pending: PhonePendingSchema.optional(), unread: z26.boolean(), handover: z26.object({ state: HandoverStateSchema, toName: z26.string().max(80).optional() }).strict().optional() });
1970
+ relieves: true,
1971
+ /** When it ended: « Terminée · à 18:42 » in the list. */
1972
+ exitedAt: true
1973
+ }).extend({
1974
+ pending: PhonePendingSchema.optional(),
1975
+ unread: z26.boolean(),
1976
+ handover: z26.object({ state: HandoverStateSchema, toName: z26.string().max(80).optional() }).strict().optional(),
1977
+ /** Absent: the agent has no checklist. */
1978
+ checklist: PhoneChecklistSummarySchema.optional(),
1979
+ /** Started without Ledge (`hook_only`): the phone can neither close nor resume it. */
1980
+ readOnly: z26.literal(true).optional()
1981
+ });
1947
1982
  var B64U2 = z26.string().regex(/^[A-Za-z0-9_-]*$/);
1948
1983
  var CredentialSchema = z26.object({
1949
1984
  id: B64U2.max(1366),
@@ -1978,11 +2013,12 @@ var PhoneChatRelaySchema = z26.object({
1978
2013
  sentAt: z26.string().datetime().optional(),
1979
2014
  failed: z26.literal(true).optional()
1980
2015
  }).strict();
2016
+ var CloseHowSchema = z26.enum(["exit", "killed"]);
1981
2017
  var PhoneChatCloseSchema = z26.object({
1982
2018
  id: z26.string().min(1),
1983
2019
  name: z26.string(),
1984
2020
  tool: ToolSchema,
1985
- how: z26.enum(["exit", "killed"]).optional(),
2021
+ how: CloseHowSchema.optional(),
1986
2022
  closedAt: z26.string().datetime().optional(),
1987
2023
  failed: z26.literal(true).optional()
1988
2024
  }).strict();
@@ -2088,7 +2124,10 @@ var PhoneClientMessageSchema = z26.discriminatedUnion("type", [
2088
2124
  /** The session whose terminal the phone shows; null when it shows none. */
2089
2125
  z26.object({ type: z26.literal("session.watch"), id: sessionId.nullable() }),
2090
2126
  z26.object({ type: z26.literal("session.read"), id: sessionId, at: z26.string().datetime() }),
2091
- /** Asks for a challenge. One object for both purposes: the gateway refuses a `decide` without `id` and `expect`. */
2127
+ /**
2128
+ * Asks for a challenge. One object for every purpose: the gateway refuses a `decide` without `id` and `expect`. A `close`
2129
+ * or `act` names a turn of the chat (`qid`) or a session (`id`, for `session.close` and `session.resume`).
2130
+ */
2092
2131
  z26.object({
2093
2132
  type: z26.literal("confirm.prepare"),
2094
2133
  purpose: ConfirmPurposeSchema,
@@ -2134,6 +2173,14 @@ var PhoneClientMessageSchema = z26.discriminatedUnion("type", [
2134
2173
  expect: PhoneExpectSchema
2135
2174
  }),
2136
2175
  z26.object({ type: z26.literal("session.interrupt"), op: OperationIdSchema, id: sessionId }),
2176
+ /** Ends a live session as `/exit` would, killed as a last resort; answered with its `how`. Passkey, purpose `close`, over the session. */
2177
+ z26.object({ type: z26.literal("session.close"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
2178
+ /** Starts an ended session again on its conversation. Passkey, purpose `act`, over the session. */
2179
+ z26.object({ type: z26.literal("session.resume"), op: OperationIdSchema, id: sessionId, assertion: AssertionSchema.optional() }),
2180
+ /** 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`. */
2181
+ z26.object({ type: z26.literal("session.model"), op: OperationIdSchema, id: sessionId, model: ModelIdSchema.nullable(), effort: EffortSchema.nullable() }),
2182
+ /** The models an agent offers on the PC. */
2183
+ z26.object({ type: z26.literal("models.list"), tool: ToolSchema }),
2137
2184
  /** The phone drops its passkey from the daemon. */
2138
2185
  z26.object({ type: z26.literal("device.forget"), op: OperationIdSchema }),
2139
2186
  /** The phone's push subscription, with the VAPID key it was made with (so a key change is seen). */
@@ -2195,15 +2242,30 @@ var PhoneClientMessageSchema = z26.discriminatedUnion("type", [
2195
2242
  const issue = "scope" in m ? scopeIssue(m) : null;
2196
2243
  if (issue) ctx.addIssue({ code: z26.ZodIssueCode.custom, message: issue, path: ["project"] });
2197
2244
  });
2245
+ var PhoneModelChoiceSchema = z26.object({
2246
+ id: ModelChoiceSchema.shape.id.max(120),
2247
+ label: z26.string().max(80),
2248
+ description: z26.string().max(200).optional(),
2249
+ efforts: z26.array(EffortSchema).max(8).optional(),
2250
+ defaultEffort: EffortSchema.optional(),
2251
+ isDefault: z26.boolean().optional()
2252
+ }).strict();
2253
+ var PhoneSeatModelSchema = z26.object({ role: z26.string().max(40), session: sessionId, status: z26.enum(["applied", "scheduled", "refused"]), reason: ModelRefusalSchema.optional() });
2198
2254
  var PhoneServerMessageSchema = z26.discriminatedUnion("type", [
2199
2255
  z26.object({ type: z26.literal("snapshot"), protocol: z26.literal(PHONE_PROTOCOL), sessions: z26.array(PhoneSessionSchema), capabilities: CapabilitiesByToolSchema, daemon: z26.object({
2200
2256
  version: z26.string(),
2201
2257
  name: z26.string().max(40),
2202
2258
  boot: z26.string().uuid().optional(),
2203
2259
  teams: z26.literal(true).optional(),
2260
+ /** The daemon takes `session.model`. */
2261
+ models: z26.literal(true).optional(),
2262
+ /** The daemon sends `session.checklist` and a session's `checklist` summary. */
2263
+ checklist: z26.literal(true).optional(),
2204
2264
  /** `update`: the daemon can install a version and restart (npm, systemd); `restart`: it can restart (systemd). */
2205
2265
  update: z26.literal(true).optional(),
2206
- restart: z26.literal(true).optional()
2266
+ restart: z26.literal(true).optional(),
2267
+ /** The daemon takes `session.close` and `session.resume`. */
2268
+ sessionClose: z26.literal(true).optional()
2207
2269
  }), 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() }),
2208
2270
  z26.object({
2209
2271
  type: z26.literal("confirm.challenge"),
@@ -2217,13 +2279,27 @@ var PhoneServerMessageSchema = z26.discriminatedUnion("type", [
2217
2279
  }),
2218
2280
  z26.object({ type: z26.literal("session.updated"), session: PhoneSessionSchema }),
2219
2281
  z26.object({ type: z26.literal("session.removed"), id: z26.string() }),
2282
+ /** A session's checklist, sent to the phone that watches it; `null`: it has none (any more). */
2283
+ z26.object({ type: z26.literal("session.checklist"), id: z26.string(), checklist: PhoneChecklistSchema.nullable() }),
2220
2284
  /** `pending.cut` is set when even this body was shortened. */
2221
2285
  z26.object({ type: z26.literal("session.pending"), id: z26.string(), pending: PhonePendingSchema }),
2222
2286
  z26.object({ type: z26.literal("session.preview"), id: z26.string(), lines: z26.array(z26.string()) }),
2223
2287
  /** `cut`: the ids of the items shortened; `more`: older items were left out. */
2224
2288
  z26.object({ type: z26.literal("session.thread"), id: z26.string(), items: z26.array(ThreadItemSchema), cut: z26.array(z26.string()), more: z26.boolean() }),
2225
2289
  z26.object({ type: z26.literal("session.thread.item"), id: z26.string(), item: ThreadItemSchema, cut: z26.literal(true).optional() }),
2226
- z26.object({ type: z26.literal("operation.result"), op: OperationIdSchema, status: OperationStatusSchema, reason: OperationReasonSchema.optional() }),
2290
+ z26.object({
2291
+ type: z26.literal("operation.result"),
2292
+ op: OperationIdSchema,
2293
+ status: OperationStatusSchema,
2294
+ reason: OperationReasonSchema.optional(),
2295
+ models: z26.array(PhoneSeatModelSchema).max(16).optional(),
2296
+ /** How an applied `session.close` ended the agent: `killed` when it had to be forced. */
2297
+ how: CloseHowSchema.optional()
2298
+ }),
2299
+ /** The models an agent offers; `error`: it could not be asked, `models` is then what Ledge knows without it. */
2300
+ z26.object({ type: z26.literal("models.listing"), tool: ToolSchema, models: z26.array(PhoneModelChoiceSchema).max(40), error: z26.literal(true).optional() }),
2301
+ /** A model change that was accepted and then failed (the agent could not restart). */
2302
+ z26.object({ type: z26.literal("session.model.failed"), id: z26.string(), reason: ModelRefusalSchema }),
2227
2303
  z26.object({ type: z26.literal("chat.history"), turns: z26.array(PhoneChatTurnSchema).max(50) }),
2228
2304
  z26.object({ type: z26.literal("chat.step"), qid: OperationIdSchema, step: PhoneChatStepSchema }),
2229
2305
  /** The whole text so far, not an increment. */
@@ -2256,6 +2332,60 @@ async function teamsDigest(m) {
2256
2332
  return Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
2257
2333
  }
2258
2334
 
2335
+ // ../protocol/src/todos.ts
2336
+ var TODO_TOOLS = /* @__PURE__ */ new Set(["TodoWrite", "update_plan", "todo"]);
2337
+ var STATUSES = /* @__PURE__ */ new Set(["pending", "in_progress", "completed"]);
2338
+ var statusOf = (s) => typeof s === "string" && STATUSES.has(s) ? s : "pending";
2339
+ var text = (s) => typeof s === "string" && s.trim() !== "" ? s : null;
2340
+ var record = (v) => v && typeof v === "object" ? v : {};
2341
+ function omp(input) {
2342
+ if (!Array.isArray(input.phases)) return void 0;
2343
+ const phases = input.phases.map(record);
2344
+ const out = [];
2345
+ for (const ph of phases) {
2346
+ for (const raw of Array.isArray(ph.tasks) ? ph.tasks : []) {
2347
+ const e = record(raw);
2348
+ const said = text(e.content);
2349
+ if (said === null) continue;
2350
+ const blocked = e.status === "blocked";
2351
+ const name = phases.length > 1 ? text(ph.name) : null;
2352
+ out.push({ text: `${name ? `${name} \xB7 ` : ""}${said}${blocked && text(e.blocker) ? ` (blocked: ${e.blocker})` : ""}`, status: blocked ? "pending" : statusOf(e.status) });
2353
+ }
2354
+ }
2355
+ return out;
2356
+ }
2357
+ function listOf(t) {
2358
+ if (!TODO_TOOLS.has(t.tool) || t.input === void 0) return void 0;
2359
+ let input;
2360
+ try {
2361
+ input = record(JSON.parse(t.input));
2362
+ } catch {
2363
+ return void 0;
2364
+ }
2365
+ if (t.tool === "todo") return omp(input);
2366
+ const claude = t.tool === "TodoWrite";
2367
+ const list = claude ? input.todos : input.plan;
2368
+ if (!Array.isArray(list)) return void 0;
2369
+ const out = [];
2370
+ for (const raw of list) {
2371
+ const e = record(raw);
2372
+ const status = statusOf(e.status);
2373
+ const said = claude ? status === "in_progress" ? text(e.activeForm) ?? text(e.content) : text(e.content) : text(e.step);
2374
+ if (said !== null) out.push({ text: said, status });
2375
+ }
2376
+ return out;
2377
+ }
2378
+ function latestTodos(items, helperId) {
2379
+ for (let i = items.length - 1; i >= 0; i--) {
2380
+ const it = items[i];
2381
+ if (it.kind !== "tool" || it.helperId !== helperId || !TODO_TOOLS.has(it.tool)) continue;
2382
+ const list = listOf(it);
2383
+ if (list) return list.length > 0 ? list : null;
2384
+ }
2385
+ return null;
2386
+ }
2387
+ var doneCount = (todos) => todos.filter((x) => x.status === "completed").length;
2388
+
2259
2389
  // src/auth.ts
2260
2390
  import { createHash, createHmac, randomBytes, timingSafeEqual } from "crypto";
2261
2391
  import { chmod, link, mkdir, readFile, unlink, writeFile } from "fs/promises";
@@ -2400,6 +2530,7 @@ export {
2400
2530
  isArchived,
2401
2531
  ModelIdSchema,
2402
2532
  EffortSchema,
2533
+ ModelRefusalSchema,
2403
2534
  extractProposal,
2404
2535
  parseRelayBlock,
2405
2536
  parseCloseBlock,
@@ -2480,6 +2611,8 @@ export {
2480
2611
  THREAD_BUDGET,
2481
2612
  THREAD_TEXT_MAX,
2482
2613
  TOOL_TEXT_MAX,
2614
+ CHECKLIST_TASKS_MAX,
2615
+ CHECKLIST_TEXT_MAX,
2483
2616
  PENDING_BODY_MAX,
2484
2617
  SNAPSHOT_BODY_MAX,
2485
2618
  OperationIdSchema,
@@ -2487,8 +2620,12 @@ export {
2487
2620
  CHAT_HISTORY_BUDGET,
2488
2621
  pcSubject,
2489
2622
  PhoneClientMessageSchema,
2623
+ PhoneModelChoiceSchema,
2490
2624
  teamsPurpose,
2491
2625
  teamsDigest,
2626
+ TODO_TOOLS,
2627
+ latestTodos,
2628
+ doneCount,
2492
2629
  tokenEquals,
2493
2630
  hostAllowed,
2494
2631
  requestAuthorized,
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-ADAGKOFO.js";
3
+ } from "./chunk-K3SDHHZF.js";
4
4
  import {
5
5
  connect
6
- } from "./chunk-7GIUG73R.js";
6
+ } from "./chunk-RFFTWAAF.js";
7
7
  import {
8
8
  LEDGE_GIVER,
9
9
  TASK_TEXT_MAX,
10
10
  TASK_TITLE_MAX
11
- } from "./chunk-37G5F75H.js";
11
+ } from "./chunk-7S7ZLGIY.js";
12
12
 
13
13
  // src/cli/task.ts
14
14
  import { randomUUID } from "crypto";
@@ -0,0 +1,6 @@
1
+ // src/version.ts
2
+ var LEDGE_VERSION = true ? "0.29.0" : "0.0.0-dev";
3
+
4
+ export {
5
+ LEDGE_VERSION
6
+ };
@@ -3,7 +3,7 @@ import {
3
3
  SESSION_KEY_VAR,
4
4
  pickName,
5
5
  sessionKey
6
- } from "./chunk-37G5F75H.js";
6
+ } from "./chunk-7S7ZLGIY.js";
7
7
  import {
8
8
  paths
9
9
  } from "./chunk-HOOHS3MX.js";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  CODEX_HOOK_VAR
3
- } from "./chunk-ADAGKOFO.js";
3
+ } from "./chunk-K3SDHHZF.js";
4
4
  import {
5
5
  connect,
6
6
  sendMessageAndAwaitAck
7
- } from "./chunk-7GIUG73R.js";
7
+ } from "./chunk-RFFTWAAF.js";
8
8
 
9
9
  // src/cli/send.ts
10
10
  import { randomUUID } from "crypto";
@@ -4,7 +4,7 @@ import {
4
4
  SUMMARY_MAX,
5
5
  parseServerMessage,
6
6
  readDaemonToken
7
- } from "./chunk-37G5F75H.js";
7
+ } from "./chunk-7S7ZLGIY.js";
8
8
 
9
9
  // src/client.ts
10
10
  import WebSocket from "ws";
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  connect
3
- } from "./chunk-7GIUG73R.js";
3
+ } from "./chunk-RFFTWAAF.js";
4
4
  import {
5
5
  isArchived
6
- } from "./chunk-37G5F75H.js";
6
+ } from "./chunk-7S7ZLGIY.js";
7
7
 
8
8
  // src/cli/who.ts
9
9
  import { basename } from "path";