@songsid/agend 2.3.4-beta.2 → 2.3.4-beta.4
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/auth-api.js +3 -0
- package/dist/auth-api.js.map +1 -1
- package/dist/backend/claude-code.js +1 -1
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex-session-lookup.d.ts +35 -0
- package/dist/backend/codex-session-lookup.js +93 -0
- package/dist/backend/codex-session-lookup.js.map +1 -1
- package/dist/backend/codex.d.ts +27 -0
- package/dist/backend/codex.js +116 -20
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.d.ts +2 -0
- package/dist/backend/grok.js +22 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/types.d.ts +2 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.js +3 -1
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.js +3 -1
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/inbox-temp-name.d.ts +9 -0
- package/dist/channel/inbox-temp-name.js +13 -0
- package/dist/channel/inbox-temp-name.js.map +1 -0
- package/dist/channel/mcp-tools.js +1 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/daemon.d.ts +10 -1
- package/dist/daemon.js +196 -26
- package/dist/daemon.js.map +1 -1
- package/dist/delivery-outbox.test.js +2 -2
- package/dist/delivery-outbox.test.js.map +1 -1
- package/dist/dialog-screen-text.d.ts +16 -0
- package/dist/dialog-screen-text.js +51 -0
- package/dist/dialog-screen-text.js.map +1 -0
- package/dist/fleet-manager.d.ts +4 -0
- package/dist/fleet-manager.js +46 -12
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/web-appearance/SKILL.md +1 -1
- package/dist/general-knowledge/skills/web-dashboard/SKILL.md +3 -2
- package/dist/install-stream.d.ts +53 -0
- package/dist/install-stream.js +134 -0
- package/dist/install-stream.js.map +1 -0
- package/dist/instance-lifecycle.d.ts +12 -0
- package/dist/instance-lifecycle.js +31 -2
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/locale.js +26 -6
- package/dist/locale.js.map +1 -1
- package/dist/log-service.d.ts +2 -0
- package/dist/log-service.js +7 -3
- package/dist/log-service.js.map +1 -1
- package/dist/login-manager.d.ts +6 -0
- package/dist/login-manager.js +10 -1
- package/dist/login-manager.js.map +1 -1
- package/dist/office-share-page.d.ts +1 -1
- package/dist/office-share-page.js +6 -2
- package/dist/office-share-page.js.map +1 -1
- package/dist/outbound-handlers.js +56 -0
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +1 -0
- package/dist/outbound-schemas.js +4 -1
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/selection-card.d.ts +2 -3
- package/dist/selection-card.js +99 -26
- package/dist/selection-card.js.map +1 -1
- package/dist/tmux-manager.d.ts +6 -0
- package/dist/tmux-manager.js +17 -0
- package/dist/tmux-manager.js.map +1 -1
- package/dist/ui/chat-store.js +20 -3
- package/dist/ui/fleet-canvas.js +4 -3
- package/dist/ui/fleet-office-model.js +55 -22
- package/dist/ui/fleet-office-overview.js +6 -38
- package/dist/ui/fleet-office-pack.js +4 -3
- package/dist/ui/fleet-office-skin.js +114 -21
- package/dist/ui/fleet-office-store.js +5 -0
- package/dist/ui/fleet-office-zones.js +2 -2
- package/dist/ui/fleet-office.js +41 -9
- package/dist/ui/panel-log.js +7 -1
- package/dist/ui/shared/app-i18n.js +2 -2
- package/dist/ui/shared/app-shell.js +4 -2
- package/dist/ui/shared/app-stream.js +26 -0
- package/dist/ui/shared/app.css +21 -1
- package/dist/ui/shared/office/guild.png +0 -0
- package/dist/ui/shared/office/school.png +0 -0
- package/dist/ui/shared/panel-view.js +185 -10
- package/dist/ui/shared/view-strings.js +23 -0
- package/dist/unattended-install.d.ts +6 -0
- package/dist/unattended-install.js +65 -0
- package/dist/unattended-install.js.map +1 -0
- package/dist/view-api.d.ts +15 -0
- package/dist/view-api.js +94 -33
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.js +7 -2
- package/dist/web-api.js.map +1 -1
- package/dist/web-chat-history.d.ts +20 -0
- package/dist/web-chat-history.js +21 -0
- package/dist/web-chat-history.js.map +1 -1
- package/dist/web-guest-access.js +5 -1
- package/dist/web-guest-access.js.map +1 -1
- package/dist/web-office-pack-tools.d.ts +1 -1
- package/dist/web-office-pack-tools.js +1 -1
- package/dist/web-office-pack-tools.js.map +1 -1
- package/package.json +1 -1
|
@@ -311,7 +311,7 @@ tools are not in your list), you can publish them yourself instead of asking a p
|
|
|
311
311
|
refused and you send the change again (#2695).
|
|
312
312
|
- `office_pack_restore { id }` brings back the previous version (the replaced one becomes the previous);
|
|
313
313
|
`office_pack_delete { id, keep_previous? }`; `office_set_style { office, pack }` points a stored office at a pack or a
|
|
314
|
-
built-in style (pixel, studio, cozy).
|
|
314
|
+
built-in style (pixel, studio, cozy, guild, school).
|
|
315
315
|
- Every change is logged with each picture's sha256 and told to the fleet's admins. At most **20 batches and 200 MiB an
|
|
316
316
|
hour**: one call is one batch (up to 16 packs), so send a whole set of fixes in one `packs: [...]`.
|
|
317
317
|
- `office_pack_check` has its own allowance: at most **60 checks and 1 GiB (as sent) an hour**. Every check counts,
|
|
@@ -291,8 +291,9 @@ buttons in General); every change is logged and told in General. **Style** (per
|
|
|
291
291
|
**Studio** (one scene — Work, Lounge, Help desk, Nap corner — where each instance walks to the area for its state),
|
|
292
292
|
**Cozy** (#2631: the same in a warm pixel-art office drawn as one picture; its notice board says a skin pack can
|
|
293
293
|
restyle it; the default for a browser that has not picked a style and for a new office — a saved office keeps its
|
|
294
|
-
own)
|
|
295
|
-
|
|
294
|
+
own), **Guild** and **School** (#2947: two more pictures on the Cozy's arrangement — an adventurers' guild hall and a
|
|
295
|
+
classroom) or an uploaded pack; one the page cannot load is drawn as Desks with a note. On a stored office in Studio,
|
|
296
|
+
Cozy, Guild, School or a pack,
|
|
296
297
|
**Edit layout** (admin only) shows a 1280×720 coordinate grid and lets you drag seats, furniture, the door, the mail drop
|
|
297
298
|
(an envelope: where letters from other offices land; dashed on a pack without a `mailDrop`, #2736) and
|
|
298
299
|
waypoints (or Tab to one and use the arrow keys, Shift for 10), add or remove waypoints and join or unjoin
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
export declare const INSTALL_STREAM_LINES = 15;
|
|
2
|
+
export declare const INSTALL_STREAM_BYTES = 1500;
|
|
3
|
+
export declare const INSTALL_STREAM_EDIT_MIN_MS = 5000;
|
|
4
|
+
export interface InstallStreamSink {
|
|
5
|
+
/** Post the message (its plain status line); its id is what the edits change. */
|
|
6
|
+
send(text: string): Promise<{
|
|
7
|
+
messageId: string;
|
|
8
|
+
} | undefined>;
|
|
9
|
+
/** Replace the message's text: a code block under the status line, in the stream's style (markdown or html). */
|
|
10
|
+
edit(messageId: string, text: string): Promise<void>;
|
|
11
|
+
warn?(message: string, err: unknown): void;
|
|
12
|
+
}
|
|
13
|
+
export interface InstallStreamClock {
|
|
14
|
+
now(): number;
|
|
15
|
+
setTimeout(fn: () => void, ms: number): unknown;
|
|
16
|
+
clearTimeout(handle: unknown): void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The window's own text, without what tmux adds to it: a dead pane's "Pane is dead (status N, <date>)" line (drawn on
|
|
20
|
+
* the bottom row, below a screenful of blank rows), and runs of blank rows collapsed to one — else the last lines of a
|
|
21
|
+
* finished install would be blanks and that line.
|
|
22
|
+
*/
|
|
23
|
+
export declare function installerOutput(pane: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* How a frame is written: "markdown" (a fenced code block — Discord) or "html" (Telegram's own `<pre>`: its markdown
|
|
26
|
+
* conversion keeps a fence as literal backticks).
|
|
27
|
+
*/
|
|
28
|
+
export type InstallFrameStyle = "markdown" | "html";
|
|
29
|
+
/** The window's last lines as a code block under a status line; just the status line when there are none. */
|
|
30
|
+
export declare function renderInstallFrame(header: string, pane: string, style?: InstallFrameStyle): string;
|
|
31
|
+
export declare class InstallStream {
|
|
32
|
+
private readonly sink;
|
|
33
|
+
private readonly header;
|
|
34
|
+
private readonly clock;
|
|
35
|
+
private readonly editMinMs;
|
|
36
|
+
private readonly style;
|
|
37
|
+
private messageId;
|
|
38
|
+
private shown;
|
|
39
|
+
private wanted;
|
|
40
|
+
private pane;
|
|
41
|
+
private lastAt;
|
|
42
|
+
private timer;
|
|
43
|
+
private inFlight;
|
|
44
|
+
private closed;
|
|
45
|
+
constructor(sink: InstallStreamSink, header: string, clock?: InstallStreamClock, editMinMs?: number, style?: InstallFrameStyle);
|
|
46
|
+
/** A new capture of the window. Never awaits; nothing is posted until the window shows something. */
|
|
47
|
+
update(pane: string): void;
|
|
48
|
+
/** Stop editing and write the final frame (the last capture, unless a later one is given) over the message. */
|
|
49
|
+
finish(header: string, pane?: string): Promise<void>;
|
|
50
|
+
private schedule;
|
|
51
|
+
/** `header`: the frame's status line as plain text — what a new message is first posted as. */
|
|
52
|
+
private write;
|
|
53
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M-2281 (#2980): the installer's output, live, in the chat that asked `/login` to install a CLI. No page shows the
|
|
3
|
+
* `agend-login-<backend>` window (it is not an instance), so the chat is where its progress is seen.
|
|
4
|
+
*
|
|
5
|
+
* One message, edited in place: the last INSTALL_STREAM_LINES lines of the window, ANSI stripped and secrets masked
|
|
6
|
+
* (dialogScreenText — the whole capture is masked before its bottom is kept), under INSTALL_STREAM_BYTES so it fits
|
|
7
|
+
* a Discord (2000) or Telegram (4096) message. At most one edit per INSTALL_STREAM_EDIT_MIN_MS, one in flight, none
|
|
8
|
+
* for an unchanged frame. The frames come from the session's own poll capture — nothing here reads the pane.
|
|
9
|
+
*
|
|
10
|
+
* Fire-and-forget from the poll: update() only records the frame and arms a timer. finish() stops the edits and
|
|
11
|
+
* writes the final frame (success / failed / timed out / cancelled) over the same message.
|
|
12
|
+
*/
|
|
13
|
+
import { dialogScreenText } from "./dialog-screen-text.js";
|
|
14
|
+
export const INSTALL_STREAM_LINES = 15;
|
|
15
|
+
export const INSTALL_STREAM_BYTES = 1_500;
|
|
16
|
+
export const INSTALL_STREAM_EDIT_MIN_MS = 5_000;
|
|
17
|
+
const realClock = {
|
|
18
|
+
now: () => performance.now(),
|
|
19
|
+
setTimeout: (fn, ms) => { const t = setTimeout(fn, ms); t.unref?.(); return t; },
|
|
20
|
+
clearTimeout: handle => clearTimeout(handle),
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* The window's own text, without what tmux adds to it: a dead pane's "Pane is dead (status N, <date>)" line (drawn on
|
|
24
|
+
* the bottom row, below a screenful of blank rows), and runs of blank rows collapsed to one — else the last lines of a
|
|
25
|
+
* finished install would be blanks and that line.
|
|
26
|
+
*/
|
|
27
|
+
export function installerOutput(pane) {
|
|
28
|
+
return pane.replace(/^Pane is dead\b.*$/gm, "").replace(/\n(?:[ \t]*\n){2,}/g, "\n\n");
|
|
29
|
+
}
|
|
30
|
+
const escapeHtml = (s) => s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
31
|
+
/** The window's last lines as a code block under a status line; just the status line when there are none. */
|
|
32
|
+
export function renderInstallFrame(header, pane, style = "markdown") {
|
|
33
|
+
const body = dialogScreenText(installerOutput(pane), { lines: INSTALL_STREAM_LINES, bytes: INSTALL_STREAM_BYTES });
|
|
34
|
+
if (!body)
|
|
35
|
+
return style === "html" ? escapeHtml(header) : header;
|
|
36
|
+
// HTML: everything escaped, the only tag is ours. Markdown: a fence inside the output would close the block early,
|
|
37
|
+
// so its backticks become look-alikes.
|
|
38
|
+
return style === "html"
|
|
39
|
+
? `${escapeHtml(header)}\n<pre>${escapeHtml(body)}</pre>`
|
|
40
|
+
: `${header}\n\`\`\`\n${body.replace(/`/g, "ˋ")}\n\`\`\``;
|
|
41
|
+
}
|
|
42
|
+
export class InstallStream {
|
|
43
|
+
sink;
|
|
44
|
+
header;
|
|
45
|
+
clock;
|
|
46
|
+
editMinMs;
|
|
47
|
+
style;
|
|
48
|
+
messageId;
|
|
49
|
+
shown = "";
|
|
50
|
+
wanted = "";
|
|
51
|
+
pane = "";
|
|
52
|
+
lastAt = Number.NEGATIVE_INFINITY;
|
|
53
|
+
timer = null;
|
|
54
|
+
inFlight = null;
|
|
55
|
+
closed = false;
|
|
56
|
+
constructor(sink, header, clock = realClock, editMinMs = INSTALL_STREAM_EDIT_MIN_MS, style = "markdown") {
|
|
57
|
+
this.sink = sink;
|
|
58
|
+
this.header = header;
|
|
59
|
+
this.clock = clock;
|
|
60
|
+
this.editMinMs = editMinMs;
|
|
61
|
+
this.style = style;
|
|
62
|
+
}
|
|
63
|
+
/** A new capture of the window. Never awaits; nothing is posted until the window shows something. */
|
|
64
|
+
update(pane) {
|
|
65
|
+
if (this.closed)
|
|
66
|
+
return;
|
|
67
|
+
this.pane = pane;
|
|
68
|
+
const frame = renderInstallFrame(this.header, pane, this.style);
|
|
69
|
+
if (frame === renderInstallFrame(this.header, "", this.style) && this.messageId === undefined)
|
|
70
|
+
return;
|
|
71
|
+
this.wanted = frame;
|
|
72
|
+
this.schedule();
|
|
73
|
+
}
|
|
74
|
+
/** Stop editing and write the final frame (the last capture, unless a later one is given) over the message. */
|
|
75
|
+
async finish(header, pane) {
|
|
76
|
+
this.closed = true;
|
|
77
|
+
if (this.timer !== null) {
|
|
78
|
+
this.clock.clearTimeout(this.timer);
|
|
79
|
+
this.timer = null;
|
|
80
|
+
}
|
|
81
|
+
await this.inFlight;
|
|
82
|
+
const frame = renderInstallFrame(header, pane ?? this.pane, this.style);
|
|
83
|
+
// Nothing was ever shown: the result message says it all.
|
|
84
|
+
if (this.messageId === undefined && frame === renderInstallFrame(header, "", this.style))
|
|
85
|
+
return;
|
|
86
|
+
// The final edit keeps the rate too: it waits out what is left of the interval rather than skip it.
|
|
87
|
+
const wait = this.lastAt + this.editMinMs - this.clock.now();
|
|
88
|
+
if (wait > 0)
|
|
89
|
+
await new Promise(resolve => this.clock.setTimeout(resolve, wait));
|
|
90
|
+
await this.write(frame, header);
|
|
91
|
+
}
|
|
92
|
+
schedule() {
|
|
93
|
+
if (this.timer !== null || this.inFlight || this.wanted === this.shown)
|
|
94
|
+
return;
|
|
95
|
+
const delay = Math.max(0, this.lastAt + this.editMinMs - this.clock.now());
|
|
96
|
+
this.timer = this.clock.setTimeout(() => {
|
|
97
|
+
this.timer = null;
|
|
98
|
+
if (this.closed)
|
|
99
|
+
return;
|
|
100
|
+
const frame = this.wanted;
|
|
101
|
+
this.inFlight = this.write(frame, this.header).finally(() => {
|
|
102
|
+
this.inFlight = null;
|
|
103
|
+
if (!this.closed)
|
|
104
|
+
this.schedule();
|
|
105
|
+
});
|
|
106
|
+
}, delay);
|
|
107
|
+
}
|
|
108
|
+
/** `header`: the frame's status line as plain text — what a new message is first posted as. */
|
|
109
|
+
async write(frame, header) {
|
|
110
|
+
if (frame === this.shown)
|
|
111
|
+
return;
|
|
112
|
+
this.lastAt = this.clock.now();
|
|
113
|
+
try {
|
|
114
|
+
if (this.messageId === undefined) {
|
|
115
|
+
// Posted as its plain status line, and every frame goes in by an edit: the message is then one kind from start
|
|
116
|
+
// to end (Telegram posts a text with a code block as a rich message, but edits text with HTML).
|
|
117
|
+
const sent = await this.sink.send(header);
|
|
118
|
+
if (!sent?.messageId)
|
|
119
|
+
return;
|
|
120
|
+
this.messageId = sent.messageId;
|
|
121
|
+
await this.sink.edit(this.messageId, frame);
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
await this.sink.edit(this.messageId, frame);
|
|
125
|
+
}
|
|
126
|
+
this.shown = frame;
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
// A refused edit (rate limit, a reconnect) is tried again with the next frame, after the interval.
|
|
130
|
+
this.sink.warn?.("install output edit failed", err);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=install-stream.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-stream.js","sourceRoot":"","sources":["../src/install-stream.ts"],"names":[],"mappings":"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"}
|
|
@@ -41,6 +41,11 @@ export interface BackendInstallationInfo {
|
|
|
41
41
|
export declare const BACKEND_INSTALLATION_INFO: Readonly<Record<string, BackendInstallationInfo>>;
|
|
42
42
|
/** Check one executable using the same PATH visible to the fleet process. */
|
|
43
43
|
export declare function checkBinaryInstalled(binary: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* M-2281 (#2980): the same check without holding the fleet loop — for paths a chat click runs (`/login`'s install
|
|
46
|
+
* routing), where a slow PATH (WSL's /mnt/c entries) would otherwise stall every adapter for up to the timeout.
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkBinaryInstalledAsync(binary: string): Promise<boolean>;
|
|
44
49
|
/**
|
|
45
50
|
* Return why an instance daemon PID must not receive SIGTERM, or null when the
|
|
46
51
|
* stale-process cleanup may proceed. daemon.pid historically stores the shared
|
|
@@ -366,6 +371,13 @@ export declare class InstanceLifecycle {
|
|
|
366
371
|
/** Max retries before giving up and pausing. */
|
|
367
372
|
private static readonly CAPACITY_BACKOFF_MAX;
|
|
368
373
|
constructor(ctx: LifecycleContext);
|
|
374
|
+
/** M-2269: the last dialog text logged per instance — the same screen seen again on later scans is not logged again. */
|
|
375
|
+
private readonly lastLoggedScreen;
|
|
376
|
+
/**
|
|
377
|
+
* M-2269: `{ screen }` for a dialog/prompt event's Log row (the daemon already stripped, masked and capped it), or
|
|
378
|
+
* nothing when there is none or it is the same text this instance's Log already has. Bookkeeping only.
|
|
379
|
+
*/
|
|
380
|
+
private screenForLog;
|
|
369
381
|
/** Seed only the Codex daemon replacing a scheduled capacity retry. */
|
|
370
382
|
private applyCapacityBackoffBaseline;
|
|
371
383
|
/**
|
|
@@ -5,6 +5,7 @@ import { existsSync, readFileSync, mkdirSync, realpathSync, writeFileSync, statS
|
|
|
5
5
|
import { ensureInstanceDir } from "./private-dir.js";
|
|
6
6
|
import { assertNoSessionOomStop } from "./session-oom-stop.js";
|
|
7
7
|
import { execFileSync } from "node:child_process";
|
|
8
|
+
import { execFile } from "./child-process.js";
|
|
8
9
|
import { join, basename, dirname, resolve, sep as pathSep } from "node:path";
|
|
9
10
|
import { access } from "node:fs/promises";
|
|
10
11
|
import { getAgendHome, ensureWorkspaceGit } from "./paths.js";
|
|
@@ -65,6 +66,20 @@ export const BACKEND_INSTALLATION_INFO = {
|
|
|
65
66
|
export function checkBinaryInstalled(binary) {
|
|
66
67
|
return measureSyncWork("lifecycle.checkBinaryInstalled", () => checkBinaryInstalledSync(binary));
|
|
67
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* M-2281 (#2980): the same check without holding the fleet loop — for paths a chat click runs (`/login`'s install
|
|
71
|
+
* routing), where a slow PATH (WSL's /mnt/c entries) would otherwise stall every adapter for up to the timeout.
|
|
72
|
+
*/
|
|
73
|
+
export function checkBinaryInstalledAsync(binary) {
|
|
74
|
+
return new Promise(resolve => {
|
|
75
|
+
try {
|
|
76
|
+
execFile("which", [binary], { timeout: 2000 }, err => resolve(!err));
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
resolve(false);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
68
83
|
function checkBinaryInstalledSync(binary) {
|
|
69
84
|
try {
|
|
70
85
|
execFileSync("which", [binary], { stdio: "pipe", timeout: 2000 });
|
|
@@ -322,6 +337,20 @@ export class InstanceLifecycle {
|
|
|
322
337
|
constructor(ctx) {
|
|
323
338
|
this.ctx = ctx;
|
|
324
339
|
}
|
|
340
|
+
/** M-2269: the last dialog text logged per instance — the same screen seen again on later scans is not logged again. */
|
|
341
|
+
lastLoggedScreen = new Map();
|
|
342
|
+
/**
|
|
343
|
+
* M-2269: `{ screen }` for a dialog/prompt event's Log row (the daemon already stripped, masked and capped it), or
|
|
344
|
+
* nothing when there is none or it is the same text this instance's Log already has. Bookkeeping only.
|
|
345
|
+
*/
|
|
346
|
+
screenForLog(name, screen) {
|
|
347
|
+
if (typeof screen !== "string" || !screen)
|
|
348
|
+
return {};
|
|
349
|
+
if (this.lastLoggedScreen.get(name) === screen)
|
|
350
|
+
return {};
|
|
351
|
+
this.lastLoggedScreen.set(name, screen);
|
|
352
|
+
return { screen };
|
|
353
|
+
}
|
|
325
354
|
/** Seed only the Codex daemon replacing a scheduled capacity retry. */
|
|
326
355
|
applyCapacityBackoffBaseline(name, backendName, daemon) {
|
|
327
356
|
if (backendName !== "codex")
|
|
@@ -937,7 +966,7 @@ export class InstanceLifecycle {
|
|
|
937
966
|
// position, so the human must LOOK and pick the option explicitly — no
|
|
938
967
|
// fixed key sequence; a known dialog whose auto-dismiss did not take gets
|
|
939
968
|
// the keys we would have pressed.
|
|
940
|
-
this.ctx.eventLog?.insert(name, "dialog_parked", { description: data.description, holdOnly: data.holdOnly });
|
|
969
|
+
this.ctx.eventLog?.insert(name, "dialog_parked", { description: data.description, holdOnly: data.holdOnly, ...this.screenForLog(name, data.screen) });
|
|
941
970
|
this.ctx.logger.warn({ name, description: data.description, holdOnly: data.holdOnly }, "Instance is parked on a CLI dialog — not auto-answering");
|
|
942
971
|
if (this.ctx.isPlannedRestart())
|
|
943
972
|
return;
|
|
@@ -983,7 +1012,7 @@ export class InstanceLifecycle {
|
|
|
983
1012
|
// #2822: a usage-limit hold began or ended — Needs you lists it while it lasts.
|
|
984
1013
|
daemon.on("usage_hold", () => this.ctx.onAttentionChanged?.(name));
|
|
985
1014
|
daemon.on("interactive_prompt", safeHandler(async (data) => {
|
|
986
|
-
this.ctx.eventLog?.insert(name, "interactive_prompt", { kind: data.kind });
|
|
1015
|
+
this.ctx.eventLog?.insert(name, "interactive_prompt", { kind: data.kind, ...this.screenForLog(name, data.screen) });
|
|
987
1016
|
this.ctx.logger.warn({ name, kind: data.kind, prompt: data.prompt }, "Instance is waiting for interactive terminal input");
|
|
988
1017
|
if (this.ctx.isPlannedRestart()) {
|
|
989
1018
|
this.ctx.logger.info({ name }, "Interactive prompt notification suppressed — planned restart in progress");
|