@paradow/ledge 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/{attach-KTZOG7E5.js → attach-HPGWEUKX.js} +4 -4
- package/dist/cli/{bridge-QKQW7UD6.js → bridge-2CVD7BMI.js} +1 -1
- package/dist/cli/{chunk-ZPANTZKC.js → chunk-564TJJZ6.js} +6 -2
- package/dist/cli/{chunk-Y5TCZTFL.js → chunk-JVELEEIO.js} +89 -4
- package/dist/cli/chunk-LWPKX7SB.js +6 -0
- package/dist/cli/{chunk-7AKUPFMS.js → chunk-N3MPPCON.js} +3 -3
- package/dist/cli/{chunk-KJWMK65Y.js → chunk-WM4MAV46.js} +32 -7
- package/dist/cli/{chunk-6ZKNEJND.js → chunk-XPWGZIYL.js} +1 -1
- package/dist/cli/{daemon-SRNTDIZW.js → daemon-SGTQRTHV.js} +283 -147
- package/dist/cli/{hook-BBVUY4RK.js → hook-WQYL4YFH.js} +46 -11
- package/dist/cli/index.js +16 -8
- package/dist/cli/{launch-RWT4EWWI.js → launch-I4T5MFWF.js} +4 -4
- package/dist/cli/{status-L2GROM4J.js → status-GGXF4DSQ.js} +2 -2
- package/dist/cli/{version-M6IZZGUV.js → version-XFBINYKQ.js} +1 -1
- package/dist/cli/who-EJWN7HM6.js +42 -0
- package/package.json +1 -1
- package/dist/cli/chunk-3KKTSYHP.js +0 -6
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
attachEnv
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-N3MPPCON.js";
|
|
4
|
+
import "./chunk-564TJJZ6.js";
|
|
5
5
|
import {
|
|
6
6
|
realTmux
|
|
7
7
|
} from "./chunk-3TNPEAMR.js";
|
|
8
8
|
import "./chunk-L6IGH4LF.js";
|
|
9
9
|
import {
|
|
10
10
|
connect
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-XPWGZIYL.js";
|
|
12
12
|
import {
|
|
13
13
|
PROTOCOL_PORT
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-WM4MAV46.js";
|
|
15
15
|
|
|
16
16
|
// src/cli/attach.ts
|
|
17
17
|
import { spawn } from "child_process";
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-L6IGH4LF.js";
|
|
4
4
|
import {
|
|
5
5
|
pickName
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WM4MAV46.js";
|
|
7
7
|
|
|
8
8
|
// src/daemon/transcript.ts
|
|
9
9
|
import { closeSync, fstatSync, openSync, readSync } from "fs";
|
|
@@ -105,6 +105,10 @@ var CODEX_HOOK_VAR = "LEDGE_CODEX_HOOK_SESSION";
|
|
|
105
105
|
function agentIdArgs(tool, id) {
|
|
106
106
|
return tool === "codex" ? ["-c", `shell_environment_policy.set.${CODEX_HOOK_VAR}="${id}"`] : [];
|
|
107
107
|
}
|
|
108
|
+
var CLAUDE_OWN_NAME = /^(-n|--name)(=|$)/;
|
|
109
|
+
function agentNameArgs(tool, name, args) {
|
|
110
|
+
return tool === "claude" && !args.some((a) => CLAUDE_OWN_NAME.test(a)) ? ["-n", name] : [];
|
|
111
|
+
}
|
|
108
112
|
var CLAUDE_OWN_SESSION = /^(--resume|-r|--continue|-c|--session-id|--fork-session)(=|$)/;
|
|
109
113
|
function claudeSessionId(tool, args) {
|
|
110
114
|
return tool === "claude" && !args.some((a) => CLAUDE_OWN_SESSION.test(a)) ? randomUUID() : void 0;
|
|
@@ -128,7 +132,7 @@ async function spawnSession(opts) {
|
|
|
128
132
|
const project = basename(opts.cwd) || opts.cwd;
|
|
129
133
|
const tmuxSession = `ledge-${id}`;
|
|
130
134
|
const agentSessionId = opts.command ? void 0 : claudeSessionId(opts.tool, opts.args);
|
|
131
|
-
const agent = opts.command ?? [AGENT_BIN[opts.tool], ...agentIdArgs(opts.tool, id), ...agentSessionId ? ["--session-id", agentSessionId] : [], ...opts.args];
|
|
135
|
+
const agent = opts.command ?? [AGENT_BIN[opts.tool], ...agentIdArgs(opts.tool, id), ...agentSessionId ? ["--session-id", agentSessionId] : [], ...agentNameArgs(opts.tool, name, opts.args), ...opts.args];
|
|
132
136
|
const env = opts.env ?? process.env;
|
|
133
137
|
const transcriptPath = agentSessionId ? claudeTranscriptPath(opts.cwd, agentSessionId, env) : void 0;
|
|
134
138
|
const command = opts.recordExit ? ["sh", "-c", '"$@"; echo $? > "$0"', exitFile(id), ...agent] : agent;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
cleanTopic,
|
|
3
3
|
sessionTitle
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-WM4MAV46.js";
|
|
5
5
|
|
|
6
6
|
// src/daemon/crossSession.ts
|
|
7
7
|
var FIRST_LINE = /^Another Claude session sent a message:\s*\n/;
|
|
@@ -19,6 +19,44 @@ function crossSession(text) {
|
|
|
19
19
|
}
|
|
20
20
|
return out.length ? out : void 0;
|
|
21
21
|
}
|
|
22
|
+
var NOTICE_HEAD = /^\[Cross-session ([\w -]+?) notice\]/;
|
|
23
|
+
var NOTICE_SPLIT = /\n\s*(?=\[Cross-session [\w -]+? notice\])/;
|
|
24
|
+
var DELIVERY = [
|
|
25
|
+
[/\bheld by that session\b/, "held"],
|
|
26
|
+
[/\bdenied by the recipient\b/, "denied"],
|
|
27
|
+
[/\bnot approved before expiry\b/, "expired"],
|
|
28
|
+
[/\bapproved and released\b/, "delivered"],
|
|
29
|
+
[/\bdropped at that session's inbox\b/, "dropped"],
|
|
30
|
+
[/\b(?:was|were) refused\b/, "refused"]
|
|
31
|
+
];
|
|
32
|
+
function crossSessionNotices(text) {
|
|
33
|
+
const body = text.trim();
|
|
34
|
+
if (!NOTICE_HEAD.test(body)) return void 0;
|
|
35
|
+
return body.split(NOTICE_SPLIT).map((part) => notice(part.trim()));
|
|
36
|
+
}
|
|
37
|
+
function notice(text) {
|
|
38
|
+
const kind = NOTICE_HEAD.exec(text)[1];
|
|
39
|
+
if (kind === "idle") {
|
|
40
|
+
const peer = /"([^"]*)"/.exec(text)?.[1] ?? "";
|
|
41
|
+
if (/^\[[^\]]*\]\s*No idle signal arrived from "/.test(text)) return { kind: "expired", peer, text };
|
|
42
|
+
const exited = /\bhas exited(?: \(at ([^)]+)\))?/.exec(text);
|
|
43
|
+
if (exited) return { kind: "exited", peer, ...exited[1] ? { time: exited[1] } : {}, text };
|
|
44
|
+
const unavailable = /is not holding your idle subscription(?: \(([^)]*)\))?/.exec(text);
|
|
45
|
+
if (unavailable) return { kind: "unavailable", peer, ...unavailable[1] ? { reason: unavailable[1] } : {}, text };
|
|
46
|
+
const time = /\bfinished a turn at (.+?)\.(?=\s|$)/.exec(text)?.[1];
|
|
47
|
+
const summary = /Its harness reports:\s*«([\s\S]*?)»/.exec(text)?.[1]?.trim();
|
|
48
|
+
return { kind: "idle", peer, ...time ? { time } : {}, ...summary ? { summary } : {}, text };
|
|
49
|
+
}
|
|
50
|
+
if (kind === "delivery") {
|
|
51
|
+
const status = DELIVERY.find(([re]) => re.test(text))?.[1] ?? "unknown";
|
|
52
|
+
const many = /\b(\d+) of your messages\b/.exec(text);
|
|
53
|
+
const to = /\brecipients?:\s*([^;)]*)/.exec(text)?.[1];
|
|
54
|
+
const recipients = to ? to.split(",").map((r) => r.trim()).filter((r) => r && r !== "\u2026") : [];
|
|
55
|
+
const reason = status === "dropped" ? /NOT delivered \(([^)]*)\)/.exec(text)?.[1] : void 0;
|
|
56
|
+
return { kind: "delivery", status, count: many ? Number(many[1]) : 1, recipients, ...reason ? { reason } : {}, text };
|
|
57
|
+
}
|
|
58
|
+
return { kind: "other", text };
|
|
59
|
+
}
|
|
22
60
|
|
|
23
61
|
// src/daemon/state.ts
|
|
24
62
|
var HOOK_PRIORITY_MS = 2e3;
|
|
@@ -235,7 +273,8 @@ function reduceEvent(s, ev) {
|
|
|
235
273
|
case "PreToolUse":
|
|
236
274
|
case "PermissionRequest":
|
|
237
275
|
case "Notification": {
|
|
238
|
-
|
|
276
|
+
const notice2 = ev.name === "UserPromptSubmit" && !!ev.text && !!crossSessionNotices(ev.text);
|
|
277
|
+
if (ev.name === "UserPromptSubmit" && ev.text && !s.topic && !notice2 && !crossSession(ev.text)) s = withTopic(s, ev.text, "prompt");
|
|
239
278
|
const incoming = pendingFor(ev);
|
|
240
279
|
if (incoming) {
|
|
241
280
|
if (ev.name === "Notification" && s.pending?.source === "hook") return { ...s, lastHookAt: at, lastActivityAt: at };
|
|
@@ -244,7 +283,7 @@ function reduceEvent(s, ev) {
|
|
|
244
283
|
return { ...s, state, pending, lastHookAt: at, lastActivityAt: at };
|
|
245
284
|
}
|
|
246
285
|
if (ev.name === "Notification" || ev.name === "SessionStart") return { ...s, lastHookAt: at, lastActivityAt: at };
|
|
247
|
-
const prompted = ev.name === "UserPromptSubmit" && s.lastReply ? withoutReply(s) : s;
|
|
286
|
+
const prompted = ev.name === "UserPromptSubmit" && s.lastReply && !notice2 ? withoutReply(s) : s;
|
|
248
287
|
if (prompted.pending?.helperId) return underHelper(prompted, "working", at);
|
|
249
288
|
if (prompted === s && s.state === "working" && s.lastActivityAt === at && !s.pending) return s;
|
|
250
289
|
return { ...prompted, state: "working", pending: void 0, lastHookAt: at, lastActivityAt: at };
|
|
@@ -252,8 +291,54 @@ function reduceEvent(s, ev) {
|
|
|
252
291
|
}
|
|
253
292
|
}
|
|
254
293
|
|
|
294
|
+
// src/daemon/git.ts
|
|
295
|
+
import { execFile } from "child_process";
|
|
296
|
+
import { basename, dirname, resolve } from "path";
|
|
297
|
+
function repositoryId(remote) {
|
|
298
|
+
const value = remote.trim();
|
|
299
|
+
try {
|
|
300
|
+
const url = new URL(value);
|
|
301
|
+
if (!["https:", "http:", "ssh:", "git:"].includes(url.protocol)) return void 0;
|
|
302
|
+
return `${url.hostname.toLowerCase()}${url.pathname.replace(/\.git\/?$/, "").replace(/\/$/, "")}`;
|
|
303
|
+
} catch {
|
|
304
|
+
const scp = value.match(/^(?:[^@\s]+@)?([a-zA-Z0-9.-]+):([^\s]+)$/);
|
|
305
|
+
return scp ? `${scp[1].toLowerCase()}/${scp[2].replace(/\.git$/, "").replace(/\/$/, "")}` : void 0;
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
var execGit = (file, args, cwd) => new Promise((res) => {
|
|
309
|
+
execFile(file, args, { cwd, timeout: 3e3, maxBuffer: 1024 * 1024 }, (err, stdout) => res({ code: err ? 1 : 0, stdout: String(stdout) }));
|
|
310
|
+
});
|
|
311
|
+
async function gitInfo(cwd, exec = execGit) {
|
|
312
|
+
const r = await exec("git", ["rev-parse", "--path-format=absolute", "--show-toplevel", "--git-common-dir", "--abbrev-ref", "HEAD"], cwd);
|
|
313
|
+
if (r.code !== 0) return null;
|
|
314
|
+
const [toplevel = "", common = "", abbrev = ""] = r.stdout.split("\n").map((l) => l.trim());
|
|
315
|
+
if (!toplevel || !common || !abbrev) return null;
|
|
316
|
+
const worktree = resolve(common) !== resolve(toplevel, ".git");
|
|
317
|
+
const repoPath = worktree ? dirname(resolve(common)) : resolve(toplevel);
|
|
318
|
+
let branch = abbrev;
|
|
319
|
+
if (abbrev === "HEAD") {
|
|
320
|
+
const sha = await exec("git", ["rev-parse", "--short", "HEAD"], cwd);
|
|
321
|
+
if (sha.code !== 0 || !sha.stdout.trim()) return null;
|
|
322
|
+
branch = sha.stdout.trim();
|
|
323
|
+
}
|
|
324
|
+
const remote = await exec("git", ["config", "--get", "remote.origin.url"], cwd);
|
|
325
|
+
const repoId = remote.code === 0 ? repositoryId(remote.stdout) : void 0;
|
|
326
|
+
return { repo: basename(repoPath), repoPath, branch, worktree, ...repoId ? { repoId } : {} };
|
|
327
|
+
}
|
|
328
|
+
async function gitSummary(cwd, exec = execGit) {
|
|
329
|
+
const status = await exec("git", ["status", "--short", "--branch"], cwd);
|
|
330
|
+
if (status.code !== 0) return null;
|
|
331
|
+
const log = await exec("git", ["log", "--oneline", "-10"], cwd);
|
|
332
|
+
const diff = await exec("git", ["diff", "--stat"], cwd);
|
|
333
|
+
return [`# git status --short --branch`, status.stdout.trimEnd(), "", "# git log --oneline -10", log.stdout.trimEnd(), "", "# git diff --stat", diff.stdout.trimEnd() || "(clean)"].join("\n");
|
|
334
|
+
}
|
|
335
|
+
|
|
255
336
|
export {
|
|
256
337
|
crossSession,
|
|
338
|
+
crossSessionNotices,
|
|
257
339
|
QUESTION_TOOLS,
|
|
258
|
-
reduce
|
|
340
|
+
reduce,
|
|
341
|
+
repositoryId,
|
|
342
|
+
gitInfo,
|
|
343
|
+
gitSummary
|
|
259
344
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
exitFile,
|
|
3
3
|
spawnSession
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-564TJJZ6.js";
|
|
5
5
|
import {
|
|
6
6
|
realTmux
|
|
7
7
|
} from "./chunk-3TNPEAMR.js";
|
|
@@ -11,10 +11,10 @@ import {
|
|
|
11
11
|
} from "./chunk-L6IGH4LF.js";
|
|
12
12
|
import {
|
|
13
13
|
connect
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XPWGZIYL.js";
|
|
15
15
|
import {
|
|
16
16
|
PROTOCOL_PORT
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-WM4MAV46.js";
|
|
18
18
|
|
|
19
19
|
// src/cli/launch.ts
|
|
20
20
|
import { spawn } from "child_process";
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
// ../protocol/src/messages.ts
|
|
2
|
-
import { z as z13 } from "zod";
|
|
3
|
-
|
|
4
1
|
// ../protocol/src/session.ts
|
|
5
2
|
import { z } from "zod";
|
|
6
3
|
var ToolSchema = z.enum(["claude", "codex", "cursor"]);
|
|
@@ -83,6 +80,9 @@ function isArchived(s) {
|
|
|
83
80
|
return s.archivedAt !== void 0;
|
|
84
81
|
}
|
|
85
82
|
|
|
83
|
+
// ../protocol/src/messages.ts
|
|
84
|
+
import { z as z13 } from "zod";
|
|
85
|
+
|
|
86
86
|
// ../protocol/src/chat.ts
|
|
87
87
|
import { z as z2 } from "zod";
|
|
88
88
|
var ChatStepSchema = z2.object({
|
|
@@ -99,6 +99,8 @@ var ChatProposalSchema = z2.object({
|
|
|
99
99
|
launchedId: z2.string().optional(),
|
|
100
100
|
error: z2.string().optional()
|
|
101
101
|
});
|
|
102
|
+
var MAX_PROPOSALS = 8;
|
|
103
|
+
var ChatProposalsSchema = z2.array(ChatProposalSchema).min(1).max(MAX_PROPOSALS);
|
|
102
104
|
var ChatRelaySchema = z2.object({
|
|
103
105
|
id: z2.string().min(1),
|
|
104
106
|
name: z2.string(),
|
|
@@ -126,9 +128,11 @@ var ChatTurnSchema = z2.object({
|
|
|
126
128
|
answeredAt: z2.string().datetime().optional(),
|
|
127
129
|
error: z2.string().optional(),
|
|
128
130
|
proposal: ChatProposalSchema.optional(),
|
|
131
|
+
proposals: ChatProposalsSchema.optional(),
|
|
129
132
|
relay: ChatRelaySchema.optional(),
|
|
130
133
|
projectProposal: ChatProjectProposalSchema.optional()
|
|
131
134
|
});
|
|
135
|
+
var proposalRows = (t) => t?.proposals ?? (t?.proposal ? [t.proposal] : []);
|
|
132
136
|
|
|
133
137
|
// ../protocol/src/repos.ts
|
|
134
138
|
import { z as z3 } from "zod";
|
|
@@ -144,7 +148,7 @@ var ReposInfoSchema = z3.object({ type: z3.literal("repos.info"), requestId: z3.
|
|
|
144
148
|
// ../protocol/src/scan.ts
|
|
145
149
|
import { z as z4 } from "zod";
|
|
146
150
|
var ReposScanSchema = z4.object({ type: z4.literal("repos.scan"), requestId: z4.string().min(1).max(100), machineId: z4.string().optional() });
|
|
147
|
-
var FoundRepoSchema = z4.object({ path: z4.string(), branch: z4.string().nullable(), remote: z4.string().optional() });
|
|
151
|
+
var FoundRepoSchema = z4.object({ path: z4.string(), branch: z4.string().nullable(), remote: z4.string().optional(), manifest: z4.string().max(200).optional() });
|
|
148
152
|
var ReposFoundSchema = z4.object({ type: z4.literal("repos.found"), requestId: z4.string(), repos: z4.array(FoundRepoSchema).max(500), truncated: z4.boolean(), error: z4.string().optional() });
|
|
149
153
|
|
|
150
154
|
// ../protocol/src/documents.ts
|
|
@@ -339,7 +343,24 @@ var ThreadItemSchema = z11.discriminatedUnion("kind", [
|
|
|
339
343
|
/** A message this session sent to another agent; `id` is the tool_use_id, `to` the address it used, `peer` the Ledge session id, `received` the paired item's id in the peer's thread. */
|
|
340
344
|
z11.object({ kind: z11.literal("sent"), ...base, to: z11.string(), peer: z11.string().optional(), summary: z11.string().optional(), text: z11.string(), status: z11.enum(["sending", "delivered", "read", "failed"]), received: z11.string().optional() }),
|
|
341
345
|
/** A message another agent sent to this session; `from` is its from-name (else its address), `sent` the paired item's id in the peer's thread. */
|
|
342
|
-
z11.object({ kind: z11.literal("received"), ...base, from: z11.string(), peer: z11.string().optional(), text: z11.string(), sent: z11.string().optional() })
|
|
346
|
+
z11.object({ kind: z11.literal("received"), ...base, from: z11.string(), peer: z11.string().optional(), text: z11.string(), sent: z11.string().optional() }),
|
|
347
|
+
/** An automated notice of the agent's harness about messages between sessions (Claude Code's `[Cross-session idle
|
|
348
|
+
* notice]` / `[Cross-session delivery notice]`): a system event, never the user's words. `name` is the session it is
|
|
349
|
+
* about as quoted, `peer` its Ledge session id; a delivery notice says the outcome of `count` messages to `recipients`. */
|
|
350
|
+
z11.object({
|
|
351
|
+
kind: z11.literal("notice"),
|
|
352
|
+
...base,
|
|
353
|
+
notice: z11.enum(["idle", "exited", "unavailable", "expired", "delivery", "other"]),
|
|
354
|
+
name: z11.string().optional(),
|
|
355
|
+
peer: z11.string().optional(),
|
|
356
|
+
time: z11.string().optional(),
|
|
357
|
+
summary: z11.string().optional(),
|
|
358
|
+
status: z11.enum(["held", "denied", "expired", "delivered", "refused", "dropped", "unknown"]).optional(),
|
|
359
|
+
count: z11.number().int().positive().optional(),
|
|
360
|
+
recipients: z11.array(z11.string()).optional(),
|
|
361
|
+
reason: z11.string().optional(),
|
|
362
|
+
text: z11.string()
|
|
363
|
+
})
|
|
343
364
|
]);
|
|
344
365
|
|
|
345
366
|
// ../protocol/src/decisions.ts
|
|
@@ -447,7 +468,7 @@ var ServerMessageSchema = z13.discriminatedUnion("type", [
|
|
|
447
468
|
/** 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. */
|
|
448
469
|
z13.object({ type: z13.literal("chat.step"), qid: z13.string(), step: ChatStepSchema }),
|
|
449
470
|
z13.object({ type: z13.literal("chat.delta"), qid: z13.string(), text: z13.string() }),
|
|
450
|
-
z13.object({ type: z13.literal("chat.done"), qid: z13.string(), text: z13.string(), at: z13.string().datetime(), proposal: ChatProposalSchema.optional(), relay: ChatRelaySchema.optional(), projectProposal: ChatProjectProposalSchema.optional() }),
|
|
471
|
+
z13.object({ type: z13.literal("chat.done"), qid: z13.string(), text: z13.string(), at: z13.string().datetime(), proposal: ChatProposalSchema.optional(), proposals: ChatProposalsSchema.optional(), relay: ChatRelaySchema.optional(), projectProposal: ChatProjectProposalSchema.optional() }),
|
|
451
472
|
z13.object({ type: z13.literal("chat.error"), qid: z13.string(), message: z13.string() }),
|
|
452
473
|
z13.object({ type: z13.literal("chat.history"), turns: z13.array(ChatTurnSchema) }),
|
|
453
474
|
/** The daemon updating itself: npm is running, then the service restarts (the socket closes right after). */
|
|
@@ -486,6 +507,8 @@ var ClientMessageSchema = z13.discriminatedUnion("type", [
|
|
|
486
507
|
prompt: z13.string().optional(),
|
|
487
508
|
continue: z13.boolean().optional(),
|
|
488
509
|
qid: z13.string().min(1).optional(),
|
|
510
|
+
/** With `qid`: the card's rows to launch (#24), indexes into the turn's `proposals`, each once; the first row without it. */
|
|
511
|
+
rows: z13.array(z13.number().int().min(0).max(MAX_PROPOSALS - 1)).min(1).max(MAX_PROPOSALS).refine((r) => new Set(r).size === r.length, "a row twice").optional(),
|
|
489
512
|
/** Folders in addition to `cwd` (Claude: `--add-dir`); resolved like `cwd`. */
|
|
490
513
|
dirs: z13.array(z13.string().min(1)).max(20).optional(),
|
|
491
514
|
/** Routing by the fleet, removed before the message reaches the daemon. */
|
|
@@ -658,7 +681,7 @@ function extractProposal(answer) {
|
|
|
658
681
|
return "";
|
|
659
682
|
});
|
|
660
683
|
const last = found.at(-1);
|
|
661
|
-
return last ? { text: text.replace(/\n{3,}/g, "\n\n").trim(), kind: last.kind, raw: last.raw } : { text: answer, kind: null, raw: null };
|
|
684
|
+
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: [] };
|
|
662
685
|
}
|
|
663
686
|
function parseProposalBlock(raw) {
|
|
664
687
|
try {
|
|
@@ -699,6 +722,8 @@ function sessionTitle(s) {
|
|
|
699
722
|
export {
|
|
700
723
|
SessionSchema,
|
|
701
724
|
isArchived,
|
|
725
|
+
MAX_PROPOSALS,
|
|
726
|
+
proposalRows,
|
|
702
727
|
NOTE_NOT_TYPED,
|
|
703
728
|
offers,
|
|
704
729
|
pendingKey,
|