@songsid/agend 2.2.0-beta.15 → 2.2.0-beta.16
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.js +19 -0
- package/dist/cli.js.map +1 -1
- package/dist/compact-watch.d.ts +78 -0
- package/dist/compact-watch.js +247 -0
- package/dist/compact-watch.js.map +1 -0
- package/dist/daemon.js +45 -5
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +3 -0
- package/dist/fleet-manager.js +47 -2
- package/dist/fleet-manager.js.map +1 -1
- package/dist/service-installer.d.ts +24 -0
- package/dist/service-installer.js +49 -1
- package/dist/service-installer.js.map +1 -1
- package/dist/topic-commands.d.ts +14 -0
- package/dist/topic-commands.js +30 -13
- package/dist/topic-commands.js.map +1 -1
- package/dist/transcript-jsonl.d.ts +7 -2
- package/dist/transcript-jsonl.js +13 -7
- package/dist/transcript-jsonl.js.map +1 -1
- package/dist/ui/chat-store.js +32 -2
- package/dist/ui/chat-strings.js +8 -2
- package/dist/ui/panel-chat.js +4 -1
- package/dist/ui/shared/app.css +1 -0
- package/dist/usage/providers.d.ts +28 -8
- package/dist/usage/providers.js +96 -41
- package/dist/usage/providers.js.map +1 -1
- package/dist/web-api.js +1 -1
- package/dist/web-api.js.map +1 -1
- package/dist/web-commands.d.ts +14 -1
- package/dist/web-commands.js +6 -3
- package/dist/web-commands.js.map +1 -1
- package/dist/web-upload.d.ts +7 -3
- package/dist/web-upload.js +20 -8
- package/dist/web-upload.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export declare const COMPACT_WATCH_POLL_MS = 2000;
|
|
2
|
+
/** A long session's compaction can take minutes (one of 1M tokens took about two); ten is well past that. */
|
|
3
|
+
export declare const COMPACT_WATCH_TIMEOUT_MS: number;
|
|
4
|
+
export declare const COMPACT_WATCH_KEEP_MS: number;
|
|
5
|
+
export type CompactFormat = "claude" | "codex";
|
|
6
|
+
export type CompactState = "running" | "done" | "timeout" | "lost";
|
|
7
|
+
export interface CompactWatchView {
|
|
8
|
+
id: string;
|
|
9
|
+
state: CompactState;
|
|
10
|
+
}
|
|
11
|
+
/** The transcript's end just before the command was written (the daemon's). */
|
|
12
|
+
export interface CompactCheckpoint {
|
|
13
|
+
path: string;
|
|
14
|
+
ino: number;
|
|
15
|
+
size: number;
|
|
16
|
+
}
|
|
17
|
+
/** One launch of an instance, as a value: a respawn, pause/wake or new fence is another. */
|
|
18
|
+
export declare function launchIdentity(o: {
|
|
19
|
+
bootId: unknown;
|
|
20
|
+
spawnGeneration: unknown;
|
|
21
|
+
launchAttempt: unknown;
|
|
22
|
+
launchFenceEpoch: unknown;
|
|
23
|
+
}): string;
|
|
24
|
+
/** Whether one whole transcript record says the conversation was compacted (its own top-level fields only). */
|
|
25
|
+
export declare function isCompactionRecord(format: CompactFormat, line: string): boolean;
|
|
26
|
+
export interface CompactWatchDeps {
|
|
27
|
+
/** The instance's transcript now, as the Log resolves it; format null: none AgEnD can read. */
|
|
28
|
+
source(name: string): {
|
|
29
|
+
path: string | null;
|
|
30
|
+
format: CompactFormat | null;
|
|
31
|
+
};
|
|
32
|
+
/** The launch that runs the instance now (launchIdentity); null: none. */
|
|
33
|
+
owner(name: string): string | null;
|
|
34
|
+
/** A watch ended (done, lost or timed out): the status frame should go out again. */
|
|
35
|
+
changed(name: string): void;
|
|
36
|
+
now?(): number;
|
|
37
|
+
setInterval?(fn: () => void, ms: number): unknown;
|
|
38
|
+
clearInterval?(handle: unknown): void;
|
|
39
|
+
}
|
|
40
|
+
export declare class CompactWatch {
|
|
41
|
+
private readonly deps;
|
|
42
|
+
private readonly watches;
|
|
43
|
+
constructor(deps: CompactWatchDeps);
|
|
44
|
+
private now;
|
|
45
|
+
private every;
|
|
46
|
+
private clear;
|
|
47
|
+
/**
|
|
48
|
+
* Before a /compact is handed to the daemon: a watch that waits for the daemon to say the command was written.
|
|
49
|
+
* Returns its id (sent along with the paste), or null when this backend's compaction cannot be seen.
|
|
50
|
+
*/
|
|
51
|
+
begin(name: string): string | null;
|
|
52
|
+
/**
|
|
53
|
+
* The daemon wrote (or gave up on) the command with this id. Written: it says under which launch, and where the
|
|
54
|
+
* transcript ended just before the write. Both must be this instance's now — the launch running it and the transcript
|
|
55
|
+
* the watch reads — or the watch is lost.
|
|
56
|
+
*/
|
|
57
|
+
pasted(name: string, id: string, written: boolean, report?: {
|
|
58
|
+
owner?: unknown;
|
|
59
|
+
checkpoint?: unknown;
|
|
60
|
+
}): void;
|
|
61
|
+
/** The command was not handed over after all: forget its watch (nothing was announced for it). */
|
|
62
|
+
cancel(name: string, id: string): void;
|
|
63
|
+
/** What the status frame says about the instance's last /compact — or nothing. */
|
|
64
|
+
view(name: string): CompactWatchView | null;
|
|
65
|
+
/** The instance went away, or the fleet stops. */
|
|
66
|
+
forget(name: string): void;
|
|
67
|
+
stopAll(): void;
|
|
68
|
+
private drop;
|
|
69
|
+
private finish;
|
|
70
|
+
/**
|
|
71
|
+
* Whether the watch still stands as `base` was set: the same watch and base, running, the same launch, the source
|
|
72
|
+
* still this format with a transcript (else lost, said here) — and still this transcript: one that moved meanwhile
|
|
73
|
+
* stops this look, and the next look starts at the new one's end. Checked after every await and before it ends.
|
|
74
|
+
*/
|
|
75
|
+
private standing;
|
|
76
|
+
/** One look at the transcript: the watch's timer calls it (tests call it directly). */
|
|
77
|
+
poll(name: string, id: string): Promise<void>;
|
|
78
|
+
}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Board 003648ac: whether a /compact sent from the web chat has finished. The chat said only "sent", forever.
|
|
3
|
+
*
|
|
4
|
+
* - **Only what the CLI writes.** Claude Code appends a `system` `compact_boundary` record to the session's JSONL and
|
|
5
|
+
* Codex a `compacted` record to its rollout (the same records the Log tab shows as "compacted", log-steps.ts). Only
|
|
6
|
+
* a record's own top-level fields count: a long record is read whole (≤ WHOLE_LINE_MAX_BYTES, also when it spans
|
|
7
|
+
* several reads) and parsed, never judged by text in its head; one that can't be read whole stays unknown. Other
|
|
8
|
+
* backends (kiro included) record nothing AgEnD can attribute to the instance, so their compaction is never called
|
|
9
|
+
* finished: `begin` answers null.
|
|
10
|
+
* - **From just before the command's own write.** The daemon queues a paste behind its lock and a wake; just before
|
|
11
|
+
* it writes this one, it takes the transcript's end (`checkpoint`), and once written it sends that with the launch it
|
|
12
|
+
* wrote under (`raw_paste_written`). So neither an older boundary nor one written while the command waited counts,
|
|
13
|
+
* and a compaction that finishes fast is not missed.
|
|
14
|
+
* - **One transcript, one launch.** The watch is bound to that launch (boot, spawn generation, attempt, fence) and to
|
|
15
|
+
* the transcript's format and path; it is rechecked before every read and after every await, and before it ends.
|
|
16
|
+
* Another launch, another backend or no transcript ends it as lost. Each look reads through one opened file whose
|
|
17
|
+
* identity was checked; another file at the path, or this one cut short, starts again at its end: a boundary may then
|
|
18
|
+
* be missed (the watch times out), never invented.
|
|
19
|
+
* - **Bounded.** One watch per instance (a new /compact replaces it), a look every COMPACT_WATCH_POLL_MS of at most
|
|
20
|
+
* LOOKS_PER_POLL bounded reads (readNewLines), and an end: done, lost, or timed out after COMPACT_WATCH_TIMEOUT_MS
|
|
21
|
+
* from the command. A finished watch stays in view for COMPACT_WATCH_KEEP_MS so a page that was away still learns it.
|
|
22
|
+
*/
|
|
23
|
+
import { randomBytes } from "node:crypto";
|
|
24
|
+
import { open, stat } from "node:fs/promises";
|
|
25
|
+
import { LOOKS_PER_POLL, readNewLines, readWholeLine, WHOLE_LINE_MAX_BYTES } from "./transcript-jsonl.js";
|
|
26
|
+
export const COMPACT_WATCH_POLL_MS = 2_000;
|
|
27
|
+
/** A long session's compaction can take minutes (one of 1M tokens took about two); ten is well past that. */
|
|
28
|
+
export const COMPACT_WATCH_TIMEOUT_MS = 10 * 60_000;
|
|
29
|
+
export const COMPACT_WATCH_KEEP_MS = 2 * 60_000;
|
|
30
|
+
/** One launch of an instance, as a value: a respawn, pause/wake or new fence is another. */
|
|
31
|
+
export function launchIdentity(o) {
|
|
32
|
+
return JSON.stringify([o.bootId, o.spawnGeneration, o.launchAttempt, o.launchFenceEpoch]);
|
|
33
|
+
}
|
|
34
|
+
/** Whether one whole transcript record says the conversation was compacted (its own top-level fields only). */
|
|
35
|
+
export function isCompactionRecord(format, line) {
|
|
36
|
+
let e;
|
|
37
|
+
try {
|
|
38
|
+
e = JSON.parse(line);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
if (!e || typeof e !== "object" || Array.isArray(e))
|
|
44
|
+
return false;
|
|
45
|
+
const r = e;
|
|
46
|
+
return format === "claude" ? r.type === "system" && r.subtype === "compact_boundary" && r.isSidechain !== true : r.type === "compacted";
|
|
47
|
+
}
|
|
48
|
+
/** A long record worth reading whole: its head mentions the record at all (anything else is skipped unread). */
|
|
49
|
+
const mayBeCompaction = (format, head) => head.includes(format === "claude" ? "compact_boundary" : "compacted");
|
|
50
|
+
export class CompactWatch {
|
|
51
|
+
deps;
|
|
52
|
+
watches = new Map();
|
|
53
|
+
constructor(deps) {
|
|
54
|
+
this.deps = deps;
|
|
55
|
+
}
|
|
56
|
+
now() { return this.deps.now ? this.deps.now() : performance.now(); }
|
|
57
|
+
every(fn, ms) { return this.deps.setInterval ? this.deps.setInterval(fn, ms) : setInterval(fn, ms); }
|
|
58
|
+
clear(handle) {
|
|
59
|
+
if (this.deps.clearInterval)
|
|
60
|
+
this.deps.clearInterval(handle);
|
|
61
|
+
else
|
|
62
|
+
clearInterval(handle);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Before a /compact is handed to the daemon: a watch that waits for the daemon to say the command was written.
|
|
66
|
+
* Returns its id (sent along with the paste), or null when this backend's compaction cannot be seen.
|
|
67
|
+
*/
|
|
68
|
+
begin(name) {
|
|
69
|
+
const src = this.deps.source(name);
|
|
70
|
+
if (!src.format || !src.path)
|
|
71
|
+
return null;
|
|
72
|
+
this.drop(name);
|
|
73
|
+
const id = randomBytes(8).toString("hex");
|
|
74
|
+
const w = { id, state: "running", deadline: this.now() + COMPACT_WATCH_TIMEOUT_MS, endedAt: null, timer: null, reading: false, base: null };
|
|
75
|
+
w.timer = this.every(() => { void this.poll(name, id); }, COMPACT_WATCH_POLL_MS);
|
|
76
|
+
this.watches.set(name, w);
|
|
77
|
+
return id;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* The daemon wrote (or gave up on) the command with this id. Written: it says under which launch, and where the
|
|
81
|
+
* transcript ended just before the write. Both must be this instance's now — the launch running it and the transcript
|
|
82
|
+
* the watch reads — or the watch is lost.
|
|
83
|
+
*/
|
|
84
|
+
pasted(name, id, written, report = {}) {
|
|
85
|
+
const w = this.watches.get(name);
|
|
86
|
+
if (!w || w.id !== id || w.state !== "running" || w.base)
|
|
87
|
+
return;
|
|
88
|
+
if (!written) {
|
|
89
|
+
this.finish(name, w, "lost");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const owner = this.deps.owner(name);
|
|
93
|
+
const src = this.deps.source(name);
|
|
94
|
+
const cp = report.checkpoint;
|
|
95
|
+
const valid = !!cp && typeof cp === "object" && typeof cp.path === "string" && Number.isSafeInteger(cp.ino) && Number.isSafeInteger(cp.size) && cp.size >= 0;
|
|
96
|
+
if (owner === null || report.owner !== owner || !src.format || !src.path || !valid || cp.path !== src.path) {
|
|
97
|
+
this.finish(name, w, "lost");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
w.base = { format: src.format, path: src.path, ino: cp.ino, offset: cp.size, skipping: false, owner, pending: null };
|
|
101
|
+
}
|
|
102
|
+
/** The command was not handed over after all: forget its watch (nothing was announced for it). */
|
|
103
|
+
cancel(name, id) {
|
|
104
|
+
if (this.watches.get(name)?.id === id)
|
|
105
|
+
this.drop(name);
|
|
106
|
+
}
|
|
107
|
+
/** What the status frame says about the instance's last /compact — or nothing. */
|
|
108
|
+
view(name) {
|
|
109
|
+
const w = this.watches.get(name);
|
|
110
|
+
if (!w)
|
|
111
|
+
return null;
|
|
112
|
+
if (w.endedAt !== null && this.now() - w.endedAt >= COMPACT_WATCH_KEEP_MS) {
|
|
113
|
+
this.watches.delete(name);
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
return { id: w.id, state: w.state };
|
|
117
|
+
}
|
|
118
|
+
/** The instance went away, or the fleet stops. */
|
|
119
|
+
forget(name) { this.drop(name); }
|
|
120
|
+
stopAll() { for (const name of [...this.watches.keys()])
|
|
121
|
+
this.drop(name); }
|
|
122
|
+
drop(name) {
|
|
123
|
+
const w = this.watches.get(name);
|
|
124
|
+
if (!w)
|
|
125
|
+
return;
|
|
126
|
+
if (w.timer !== null)
|
|
127
|
+
this.clear(w.timer);
|
|
128
|
+
this.watches.delete(name);
|
|
129
|
+
}
|
|
130
|
+
finish(name, w, state) {
|
|
131
|
+
if (this.watches.get(name) !== w || w.state !== "running")
|
|
132
|
+
return;
|
|
133
|
+
if (w.timer !== null) {
|
|
134
|
+
this.clear(w.timer);
|
|
135
|
+
w.timer = null;
|
|
136
|
+
}
|
|
137
|
+
w.state = state;
|
|
138
|
+
w.endedAt = this.now();
|
|
139
|
+
this.deps.changed(name);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Whether the watch still stands as `base` was set: the same watch and base, running, the same launch, the source
|
|
143
|
+
* still this format with a transcript (else lost, said here) — and still this transcript: one that moved meanwhile
|
|
144
|
+
* stops this look, and the next look starts at the new one's end. Checked after every await and before it ends.
|
|
145
|
+
*/
|
|
146
|
+
standing(name, w, base) {
|
|
147
|
+
if (this.watches.get(name) !== w || w.state !== "running" || w.base !== base)
|
|
148
|
+
return false;
|
|
149
|
+
const src = this.deps.source(name);
|
|
150
|
+
if (this.deps.owner(name) !== base.owner || src.format !== base.format || !src.path) {
|
|
151
|
+
this.finish(name, w, "lost");
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
return src.path === base.path;
|
|
155
|
+
}
|
|
156
|
+
/** One look at the transcript: the watch's timer calls it (tests call it directly). */
|
|
157
|
+
async poll(name, id) {
|
|
158
|
+
const w = this.watches.get(name);
|
|
159
|
+
if (!w || w.id !== id || w.state !== "running" || w.reading)
|
|
160
|
+
return;
|
|
161
|
+
if (this.now() >= w.deadline) {
|
|
162
|
+
this.finish(name, w, "timeout");
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const base = w.base;
|
|
166
|
+
if (!base)
|
|
167
|
+
return; // the command has not reached the pane yet
|
|
168
|
+
w.reading = true;
|
|
169
|
+
try {
|
|
170
|
+
const src = this.deps.source(name);
|
|
171
|
+
if (this.deps.owner(name) !== base.owner || src.format !== base.format || !src.path) {
|
|
172
|
+
this.finish(name, w, "lost");
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (src.path !== base.path) {
|
|
176
|
+
// Another transcript of the same launch: only what is written to it from now on.
|
|
177
|
+
const moved = src.path;
|
|
178
|
+
const { size, ino } = await stat(moved);
|
|
179
|
+
const now = this.deps.source(name);
|
|
180
|
+
if (this.watches.get(name) !== w || w.state !== "running" || w.base !== base)
|
|
181
|
+
return;
|
|
182
|
+
if (this.deps.owner(name) !== base.owner || now.format !== base.format || !now.path) {
|
|
183
|
+
this.finish(name, w, "lost");
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (now.path === moved)
|
|
187
|
+
Object.assign(base, { path: moved, ino, offset: size, skipping: false, pending: null });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const fh = await open(base.path, "r");
|
|
191
|
+
try {
|
|
192
|
+
const st = await fh.stat();
|
|
193
|
+
if (!this.standing(name, w, base))
|
|
194
|
+
return;
|
|
195
|
+
if (st.ino !== base.ino || st.size < base.offset) {
|
|
196
|
+
Object.assign(base, { ino: st.ino, offset: st.size, skipping: false, pending: null });
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
// Every read below goes through this handle: the file whose identity was just checked, whatever the path holds now.
|
|
200
|
+
const whole = async (offset, bytes) => (await readWholeLine(base.path, offset, bytes, WHOLE_LINE_MAX_BYTES, fh).catch(() => null)) ?? "";
|
|
201
|
+
for (let look = 0; look < LOOKS_PER_POLL; look++) {
|
|
202
|
+
const read = await readNewLines(base.path, base.offset, { skipping: base.skipping, handle: fh });
|
|
203
|
+
if (!this.standing(name, w, base))
|
|
204
|
+
return;
|
|
205
|
+
let found = read.lines.some(l => isCompactionRecord(base.format, l));
|
|
206
|
+
// A long record that began in an earlier read ends in this one: read it whole now.
|
|
207
|
+
if (base.pending !== null && read.longEnd !== undefined) {
|
|
208
|
+
if (!found && isCompactionRecord(base.format, await whole(base.pending, read.longEnd - 1 - base.pending)))
|
|
209
|
+
found = true;
|
|
210
|
+
base.pending = null;
|
|
211
|
+
}
|
|
212
|
+
for (const l of read.long) {
|
|
213
|
+
if (found || !mayBeCompaction(base.format, l.head))
|
|
214
|
+
continue;
|
|
215
|
+
if (!l.complete) {
|
|
216
|
+
base.pending = l.offset;
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (isCompactionRecord(base.format, await whole(l.offset, l.bytes)))
|
|
220
|
+
found = true;
|
|
221
|
+
}
|
|
222
|
+
if (!this.standing(name, w, base))
|
|
223
|
+
return;
|
|
224
|
+
const moved = read.newOffset !== base.offset;
|
|
225
|
+
base.offset = read.newOffset;
|
|
226
|
+
base.skipping = read.skipping;
|
|
227
|
+
if (found) {
|
|
228
|
+
this.finish(name, w, "done");
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
if (!moved || !read.more)
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
finally {
|
|
236
|
+
await fh.close();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// A look that fails is tried again on the next tick; the deadline still ends the watch.
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
w.reading = false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=compact-watch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compact-watch.js","sourceRoot":"","sources":["../src/compact-watch.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AGENT_WHATS_NEW, agendVersion, planWhatsNew, readWhatsNewRecord, recordWhatsNew, whatsNewNotice } from "./agent-whats-new.js";
|
|
2
2
|
import { join, dirname, basename, resolve } from "node:path";
|
|
3
3
|
import { mkdirSync, writeFileSync, readFileSync, readdirSync, existsSync, unlinkSync, rmSync, appendFileSync, statSync, renameSync } from "node:fs";
|
|
4
|
+
import { launchIdentity } from "./compact-watch.js";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { ensureInstanceDir } from "./private-dir.js";
|
|
6
7
|
import { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
@@ -3782,21 +3783,51 @@ export class Daemon extends EventEmitter {
|
|
|
3782
3783
|
isDeliveryEpochCurrent(epoch) {
|
|
3783
3784
|
return epoch === this.deliveryEpoch;
|
|
3784
3785
|
}
|
|
3785
|
-
queueRawPaste(rawText, deliveryEpoch = this.deliveryEpoch, confirmClear = false, durableAttempt, ownSwitch) {
|
|
3786
|
+
queueRawPaste(rawText, deliveryEpoch = this.deliveryEpoch, confirmClear = false, durableAttempt, ownSwitch, notifyWritten) {
|
|
3786
3787
|
const reportSwitch = (result) => {
|
|
3787
3788
|
if (!ownSwitch)
|
|
3788
3789
|
return;
|
|
3789
3790
|
this.ipcServer?.broadcast({ type: "runtime_switch_result", id: ownSwitch.id, ...result });
|
|
3790
3791
|
};
|
|
3792
|
+
// Board 003648ac: the fleet follows a web /compact from just before its paste is written: the transcript's end then
|
|
3793
|
+
// (taken here, under this launch, before the write) and the launch it was written under ride with the notice — once.
|
|
3794
|
+
// The checkpoint and the launch are taken together, right before the paste (each attempt takes them again); the
|
|
3795
|
+
// notice carries those — never the launch at notice time, which a respawn in between would relabel.
|
|
3796
|
+
let told = false;
|
|
3797
|
+
let checkpoint = null;
|
|
3798
|
+
let owner = null;
|
|
3799
|
+
const tellWritten = (written) => {
|
|
3800
|
+
if (!notifyWritten || told)
|
|
3801
|
+
return;
|
|
3802
|
+
told = true;
|
|
3803
|
+
this.ipcServer?.broadcast({ type: "raw_paste_written", id: notifyWritten, outcome: written ? "written" : "not_written",
|
|
3804
|
+
...(written ? { owner, checkpoint } : {}) });
|
|
3805
|
+
};
|
|
3806
|
+
const takeCheckpoint = () => {
|
|
3807
|
+
owner = launchIdentity(this.interactionOwner());
|
|
3808
|
+
const path = this.logTranscriptPath();
|
|
3809
|
+
checkpoint = null;
|
|
3810
|
+
if (!path)
|
|
3811
|
+
return;
|
|
3812
|
+
try {
|
|
3813
|
+
const st = statSync(path);
|
|
3814
|
+
checkpoint = { path, ino: st.ino, size: st.size };
|
|
3815
|
+
}
|
|
3816
|
+
catch {
|
|
3817
|
+
checkpoint = null;
|
|
3818
|
+
}
|
|
3819
|
+
};
|
|
3791
3820
|
if (!this.tmux || !this.isDeliveryEpochCurrent(deliveryEpoch)) {
|
|
3792
3821
|
if (durableAttempt)
|
|
3793
3822
|
this.retryDurableDeliveryBeforeBegin(durableAttempt, "raw_paste target unavailable before pane queue");
|
|
3794
3823
|
reportSwitch({ outcome: "not_sent" });
|
|
3824
|
+
tellWritten(false);
|
|
3795
3825
|
return;
|
|
3796
3826
|
}
|
|
3797
3827
|
this.pasteLock = this.pasteLock.then(async () => {
|
|
3798
3828
|
if (!this.isDeliveryEpochCurrent(deliveryEpoch)) {
|
|
3799
3829
|
reportSwitch({ outcome: "not_sent" });
|
|
3830
|
+
tellWritten(false);
|
|
3800
3831
|
this.logger.info("Pending raw delivery dropped by user cancel");
|
|
3801
3832
|
if (durableAttempt)
|
|
3802
3833
|
this.retryDurableDeliveryBeforeBegin(durableAttempt, "raw_paste epoch changed while queued");
|
|
@@ -3809,6 +3840,7 @@ export class Daemon extends EventEmitter {
|
|
|
3809
3840
|
if (durableAttempt)
|
|
3810
3841
|
this.retryDurableDeliveryBeforeBegin(durableAttempt, "raw_paste epoch changed while waking");
|
|
3811
3842
|
reportSwitch({ outcome: "not_sent" }); // #1690: cancelled before anything was typed — said at once, nothing saved
|
|
3843
|
+
tellWritten(false);
|
|
3812
3844
|
return;
|
|
3813
3845
|
}
|
|
3814
3846
|
const delivered = await this.deliverMessage(rawText, undefined, {
|
|
@@ -3818,8 +3850,11 @@ export class Daemon extends EventEmitter {
|
|
|
3818
3850
|
preserveExactBytes: true,
|
|
3819
3851
|
// #1690: our own /model holds every other delivery from its write on — before the lock is released, so a steer
|
|
3820
3852
|
// or /btw waiting on it cannot type into the gap before claude paints "Switch model?" (default cursor: Yes).
|
|
3821
|
-
...(ownSwitch ? { onPaneWritten: () => {
|
|
3853
|
+
...(ownSwitch || notifyWritten ? { onPaneWritten: () => { if (ownSwitch)
|
|
3854
|
+
this.ownSwitch = ownSwitch; tellWritten(true); } } : {}),
|
|
3855
|
+
...(notifyWritten ? { beforePaneWrite: takeCheckpoint } : {}),
|
|
3822
3856
|
});
|
|
3857
|
+
tellWritten(false); // never written (once told, this says nothing)
|
|
3823
3858
|
if (delivered)
|
|
3824
3859
|
this.finishDurableSubmission(durableAttempt ?? null, verdict);
|
|
3825
3860
|
else if (durableAttempt && verdict.paneWriteStarted) {
|
|
@@ -3856,6 +3891,7 @@ export class Daemon extends EventEmitter {
|
|
|
3856
3891
|
this.ownSwitch = null;
|
|
3857
3892
|
reportSwitch({ outcome: "not_confirmed" });
|
|
3858
3893
|
}
|
|
3894
|
+
tellWritten(false);
|
|
3859
3895
|
return;
|
|
3860
3896
|
}
|
|
3861
3897
|
if (confirmClear)
|
|
@@ -3897,7 +3933,8 @@ export class Daemon extends EventEmitter {
|
|
|
3897
3933
|
const sw = msg.runtime_switch;
|
|
3898
3934
|
const ownSwitch = sw && typeof sw.id === "string" && sw.kind === "model" && typeof sw.requested === "string"
|
|
3899
3935
|
? { id: sw.id, kind: "model", requested: sw.requested } : undefined;
|
|
3900
|
-
|
|
3936
|
+
const notifyWritten = typeof msg.notify_written === "string" && /^[0-9a-f]{16}$/.test(msg.notify_written) ? msg.notify_written : undefined;
|
|
3937
|
+
this.queueRawPaste(msg.content, this.captureDeliveryEpoch(msg.delivery_epoch), msg.confirm_clear === true, durableAttempt ? { ...durableAttempt, submissionMode: "raw_paste", silentSchedule: msg.silent_schedule === true } : undefined, ownSwitch, notifyWritten);
|
|
3901
3938
|
}
|
|
3902
3939
|
/**
|
|
3903
3940
|
* #1690 (the user's choice A): after AgEnD's own `/model <name>`, claude may ask "Switch model?" (a warm cache for
|
|
@@ -6969,7 +7006,7 @@ export class Daemon extends EventEmitter {
|
|
|
6969
7006
|
return stale();
|
|
6970
7007
|
if (residue !== "clear")
|
|
6971
7008
|
return this.failDelivery(verdict, status, "input-residue", residue);
|
|
6972
|
-
const written = await this.writeMessageToPane(formatted, windowId, handingOffToNativeQueue, status, opts?.submissionId, verdict, opts?.durableAttempt, opts?.steer === true, writeCurrent, opts?.humanVerificationId);
|
|
7009
|
+
const written = await this.writeMessageToPane(formatted, windowId, handingOffToNativeQueue, status, opts?.submissionId, verdict, opts?.durableAttempt, opts?.steer === true, writeCurrent, opts?.humanVerificationId, opts?.beforePaneWrite);
|
|
6973
7010
|
// #1690: still under the lock — whatever waits on it next must already see what this write started.
|
|
6974
7011
|
if (verdict.paneWriteStarted)
|
|
6975
7012
|
opts?.onPaneWritten?.();
|
|
@@ -8485,7 +8522,9 @@ export class Daemon extends EventEmitter {
|
|
|
8485
8522
|
verdict = { reached: false }, durableAttempt, steer = false,
|
|
8486
8523
|
// #829: the caller's fence, asked once more after the last await before the
|
|
8487
8524
|
// first side effect. Stale means unwritten: false, with no failure verdict.
|
|
8488
|
-
stillCurrent, humanVerificationId
|
|
8525
|
+
stillCurrent, humanVerificationId,
|
|
8526
|
+
// Board 003648ac: called synchronously right before each paste — after the last await and fence of that attempt.
|
|
8527
|
+
beforePaste) {
|
|
8489
8528
|
const signature = this.submissionSignature(formatted, humanVerificationId ?? submissionId, humanVerificationId !== undefined);
|
|
8490
8529
|
const rawPaste = durableAttempt?.submissionMode === "raw_paste";
|
|
8491
8530
|
const humanAttempt = verdict.humanReceipt;
|
|
@@ -8614,6 +8653,7 @@ export class Daemon extends EventEmitter {
|
|
|
8614
8653
|
// same pane; the write-ahead Enter marker later separates safe pre-Enter
|
|
8615
8654
|
// recovery from a possibly executed command.
|
|
8616
8655
|
const pasteGeneration = this.spawnGeneration;
|
|
8656
|
+
beforePaste?.();
|
|
8617
8657
|
const pasted = await this.tmux.pasteBuffer(formatted);
|
|
8618
8658
|
if (pasted)
|
|
8619
8659
|
this.rememberPaste(formatted, pasteGeneration);
|