@songsid/agend 2.1.4 → 2.1.5-beta.10
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/backend/claude-code.js +2 -2
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/types.d.ts +22 -0
- package/dist/backend/types.js +23 -1
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +2 -0
- package/dist/channel/adapters/discord.js +25 -3
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +5 -0
- package/dist/channel/adapters/telegram.js +11 -0
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/types.d.ts +7 -0
- package/dist/cli.js +37 -37
- package/dist/cli.js.map +1 -1
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -1
- package/dist/daemon.d.ts +38 -0
- package/dist/daemon.js +95 -43
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-context.d.ts +5 -0
- package/dist/fleet-manager.d.ts +126 -0
- package/dist/fleet-manager.js +688 -95
- package/dist/fleet-manager.js.map +1 -1
- package/dist/full-restart.d.ts +20 -0
- package/dist/full-restart.js +39 -0
- package/dist/full-restart.js.map +1 -0
- package/dist/locale.js +72 -2
- package/dist/locale.js.map +1 -1
- package/dist/login-controller.d.ts +127 -0
- package/dist/login-controller.js +450 -0
- package/dist/login-controller.js.map +1 -0
- package/dist/login-flows.d.ts +41 -3
- package/dist/login-flows.js +37 -5
- package/dist/login-flows.js.map +1 -1
- package/dist/login-manager.d.ts +12 -1
- package/dist/login-manager.js +64 -7
- package/dist/login-manager.js.map +1 -1
- package/dist/login-window-lock.d.ts +26 -0
- package/dist/login-window-lock.js +64 -0
- package/dist/login-window-lock.js.map +1 -0
- package/dist/restart-progress.d.ts +35 -5
- package/dist/restart-progress.js +195 -34
- package/dist/restart-progress.js.map +1 -1
- package/dist/service-restart-selection.d.ts +27 -0
- package/dist/service-restart-selection.js +25 -0
- package/dist/service-restart-selection.js.map +1 -0
- package/dist/tmux-manager.d.ts +19 -0
- package/dist/tmux-manager.js +79 -12
- package/dist/tmux-manager.js.map +1 -1
- package/dist/topic-commands.js +23 -7
- package/dist/topic-commands.js.map +1 -1
- package/dist/types.d.ts +18 -0
- package/dist/ui/web-terminal/terminal.css +17 -0
- package/dist/ui/web-terminal/terminal.html +44 -0
- package/dist/ui/web-terminal/terminal.js +148 -0
- package/dist/ui/web-terminal/vendor/LICENSE.addon-fit +19 -0
- package/dist/ui/web-terminal/vendor/LICENSE.addon-web-links +19 -0
- package/dist/ui/web-terminal/vendor/LICENSE.xterm +21 -0
- package/dist/ui/web-terminal/vendor/VENDORED.md +22 -0
- package/dist/ui/web-terminal/vendor/addon-fit.js +1 -0
- package/dist/ui/web-terminal/vendor/addon-web-links.js +1 -0
- package/dist/ui/web-terminal/vendor/xterm.css +285 -0
- package/dist/ui/web-terminal/vendor/xterm.js +1 -0
- package/dist/update-marker.d.ts +11 -1
- package/dist/update-marker.js +19 -4
- package/dist/update-marker.js.map +1 -1
- package/dist/update-progress.d.ts +1 -1
- package/dist/update-progress.js +12 -0
- package/dist/update-progress.js.map +1 -1
- package/dist/usage/providers.d.ts +39 -0
- package/dist/usage/providers.js +69 -3
- package/dist/usage/providers.js.map +1 -1
- package/dist/web-terminal-http.d.ts +61 -0
- package/dist/web-terminal-http.js +422 -0
- package/dist/web-terminal-http.js.map +1 -0
- package/dist/web-terminal.d.ts +336 -0
- package/dist/web-terminal.js +888 -0
- package/dist/web-terminal.js.map +1 -0
- package/dist/ws-server.d.ts +69 -0
- package/dist/ws-server.js +392 -0
- package/dist/ws-server.js.map +1 -0
- package/package.json +1 -1
package/dist/daemon.d.ts
CHANGED
|
@@ -11,6 +11,33 @@ import type { StormWindow } from "./storm-window.js";
|
|
|
11
11
|
import type { BackendOutageView } from "./backend-outage.js";
|
|
12
12
|
/** Point a resumed CLI at its one backend-native instruction source. */
|
|
13
13
|
export declare function buildInstructionReloadNotice(binaryName: string, instanceName: string, instanceDir: string): string;
|
|
14
|
+
/**
|
|
15
|
+
* Whether this backend has to be told in its pane that its instructions moved.
|
|
16
|
+
*
|
|
17
|
+
* A backend that re-reads them on resume already received the new ones from the
|
|
18
|
+
* resume itself, so the notice is pure interruption. Both places that can send
|
|
19
|
+
* it — the warmup paste and the deferred pendingInstructionsNotice — ask through
|
|
20
|
+
* here, so the two cannot drift apart again: the warmup path used to omit this
|
|
21
|
+
* check entirely and told claude-code to reload instructions it had just read.
|
|
22
|
+
*/
|
|
23
|
+
export declare function backendNeedsPaneReloadNotice(backend?: {
|
|
24
|
+
instructionsReloadedOnResume?: boolean;
|
|
25
|
+
}): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* What the warmup should do about changed instructions.
|
|
28
|
+
*
|
|
29
|
+
* `skip` — nothing to say, or this backend learns of the change by itself.
|
|
30
|
+
* `defer` — worth saying, but nobody is talking to the instance; say it when a
|
|
31
|
+
* real message next arrives rather than provoking an unsolicited reply.
|
|
32
|
+
* `paste` — say it now, into a pane that already has a delivery in flight.
|
|
33
|
+
*/
|
|
34
|
+
export declare function warmupNoticeAction(opts: {
|
|
35
|
+
warmupNeeded: boolean;
|
|
36
|
+
backend?: {
|
|
37
|
+
instructionsReloadedOnResume?: boolean;
|
|
38
|
+
};
|
|
39
|
+
pasteQueueDepth: number;
|
|
40
|
+
}): "skip" | "defer" | "paste";
|
|
14
41
|
export declare const DEFAULT_STUCK_TIMEOUT_MS: number;
|
|
15
42
|
export declare const DEFAULT_STATE_IDLE_DEBOUNCE_MS = 2000;
|
|
16
43
|
export declare const DEFAULT_STATE_SAFETY_SWEEP_MS = 60000;
|
|
@@ -1172,6 +1199,17 @@ export declare class Daemon extends EventEmitter {
|
|
|
1172
1199
|
* Returns true if CLI is ready, false if it failed or got stuck.
|
|
1173
1200
|
*/
|
|
1174
1201
|
private trySpawn;
|
|
1202
|
+
/**
|
|
1203
|
+
* Tell the agent its instructions moved, once the CLI is idle.
|
|
1204
|
+
*
|
|
1205
|
+
* A named method rather than an inline closure so the wiring itself is
|
|
1206
|
+
* testable: warmupNoticeAction's own tests pass even if this call site stops
|
|
1207
|
+
* consulting it, which is exactly the bug this path had — the decision was
|
|
1208
|
+
* made inline and never asked whether the backend needed telling at all.
|
|
1209
|
+
*
|
|
1210
|
+
* Never throws: a missed reload notice must not fail a spawn.
|
|
1211
|
+
*/
|
|
1212
|
+
private runWarmupInstructionNotice;
|
|
1175
1213
|
private trySpawnInsideGate;
|
|
1176
1214
|
/**
|
|
1177
1215
|
* The last leg of a spawn: confirm the pane is not positively dead, then run
|
package/dist/daemon.js
CHANGED
|
@@ -47,6 +47,33 @@ export function buildInstructionReloadNotice(binaryName, instanceName, instanceD
|
|
|
47
47
|
: join(instanceDir, "fleet-instructions.md");
|
|
48
48
|
return `[system] Your AgEnD instructions have been updated. Reload only ${source}; do not scan other instruction directories. Do not reply to this message.`;
|
|
49
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Whether this backend has to be told in its pane that its instructions moved.
|
|
52
|
+
*
|
|
53
|
+
* A backend that re-reads them on resume already received the new ones from the
|
|
54
|
+
* resume itself, so the notice is pure interruption. Both places that can send
|
|
55
|
+
* it — the warmup paste and the deferred pendingInstructionsNotice — ask through
|
|
56
|
+
* here, so the two cannot drift apart again: the warmup path used to omit this
|
|
57
|
+
* check entirely and told claude-code to reload instructions it had just read.
|
|
58
|
+
*/
|
|
59
|
+
export function backendNeedsPaneReloadNotice(backend) {
|
|
60
|
+
return !backend?.instructionsReloadedOnResume;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* What the warmup should do about changed instructions.
|
|
64
|
+
*
|
|
65
|
+
* `skip` — nothing to say, or this backend learns of the change by itself.
|
|
66
|
+
* `defer` — worth saying, but nobody is talking to the instance; say it when a
|
|
67
|
+
* real message next arrives rather than provoking an unsolicited reply.
|
|
68
|
+
* `paste` — say it now, into a pane that already has a delivery in flight.
|
|
69
|
+
*/
|
|
70
|
+
export function warmupNoticeAction(opts) {
|
|
71
|
+
if (!opts.warmupNeeded)
|
|
72
|
+
return "skip";
|
|
73
|
+
if (!backendNeedsPaneReloadNotice(opts.backend))
|
|
74
|
+
return "skip";
|
|
75
|
+
return opts.pasteQueueDepth === 0 ? "defer" : "paste";
|
|
76
|
+
}
|
|
50
77
|
export const DEFAULT_STUCK_TIMEOUT_MS = 10 * 60_000;
|
|
51
78
|
export const DEFAULT_STATE_IDLE_DEBOUNCE_MS = 2_000;
|
|
52
79
|
export const DEFAULT_STATE_SAFETY_SWEEP_MS = 60_000;
|
|
@@ -1230,48 +1257,7 @@ export class Daemon extends EventEmitter {
|
|
|
1230
1257
|
// the instructions actually changed since the agent last saw them.
|
|
1231
1258
|
// Skipping the no-op reload saves 10-30s of agent time on every restart
|
|
1232
1259
|
// where instructions are unchanged.
|
|
1233
|
-
|
|
1234
|
-
try {
|
|
1235
|
-
if (!this.warmupNeeded) {
|
|
1236
|
-
this.logger.debug("Warmup skipped — instructions unchanged");
|
|
1237
|
-
return;
|
|
1238
|
-
}
|
|
1239
|
-
// Skip warmup if no one is talking to this instance (avoid triggering
|
|
1240
|
-
// unsolicited agent replies on idle instances after fleet restart).
|
|
1241
|
-
if (this.pasteQueueDepth === 0) {
|
|
1242
|
-
this.logger.debug("Warmup deferred — no pending inbound messages");
|
|
1243
|
-
// Convert to pendingInstructionsNotice so it fires on next real message.
|
|
1244
|
-
this.pendingInstructionsNotice = true;
|
|
1245
|
-
try {
|
|
1246
|
-
writeFileSync(join(this.instanceDir, "prev-instructions"), this.lastBuiltInstructions);
|
|
1247
|
-
}
|
|
1248
|
-
catch { }
|
|
1249
|
-
return;
|
|
1250
|
-
}
|
|
1251
|
-
const wid = existsSync(join(this.instanceDir, "window-id"))
|
|
1252
|
-
? readFileSync(join(this.instanceDir, "window-id"), "utf-8").trim() : "";
|
|
1253
|
-
if (wid && this.controlClient) {
|
|
1254
|
-
await this.controlClient.waitForIdle(wid, 120_000);
|
|
1255
|
-
}
|
|
1256
|
-
else {
|
|
1257
|
-
await new Promise(r => setTimeout(r, 5000));
|
|
1258
|
-
}
|
|
1259
|
-
// This path only runs when pasteQueueDepth > 0 — i.e. exactly when a real
|
|
1260
|
-
// delivery is already in flight or queued. Without the lock the notice and
|
|
1261
|
-
// that delivery race into the same pane.
|
|
1262
|
-
await this.paneWriteLock.run(async () => {
|
|
1263
|
-
await this.tmux?.pasteText(buildInstructionReloadNotice(this.backend?.binaryName ?? "unknown", this.name, this.instanceDir), this.systemPasteOptions());
|
|
1264
|
-
});
|
|
1265
|
-
// Record the value the agent has now been told about so the next
|
|
1266
|
-
// unchanged restart skips the reload.
|
|
1267
|
-
try {
|
|
1268
|
-
writeFileSync(join(this.instanceDir, "prev-instructions"), this.lastBuiltInstructions);
|
|
1269
|
-
}
|
|
1270
|
-
catch { /* best effort */ }
|
|
1271
|
-
this.logger.debug("Warmup sent after idle");
|
|
1272
|
-
}
|
|
1273
|
-
catch { /* non-fatal */ }
|
|
1274
|
-
})();
|
|
1260
|
+
void this.runWarmupInstructionNotice();
|
|
1275
1261
|
if (!this.config.lightweight) {
|
|
1276
1262
|
// 3. Pipe-pane for prompt detection. Rotate first so a ballooned log from a
|
|
1277
1263
|
// previous stuck splash (hundreds of MB of ANSI frames) is truncated before
|
|
@@ -5270,6 +5256,72 @@ export class Daemon extends EventEmitter {
|
|
|
5270
5256
|
reason: reuseWindow ? "wake" : this.lastSpawnAt > 0 ? "recovery" : "startup",
|
|
5271
5257
|
}, () => this.trySpawnInsideGate(reuseWindow, startupTimeoutMs));
|
|
5272
5258
|
}
|
|
5259
|
+
/**
|
|
5260
|
+
* Tell the agent its instructions moved, once the CLI is idle.
|
|
5261
|
+
*
|
|
5262
|
+
* A named method rather than an inline closure so the wiring itself is
|
|
5263
|
+
* testable: warmupNoticeAction's own tests pass even if this call site stops
|
|
5264
|
+
* consulting it, which is exactly the bug this path had — the decision was
|
|
5265
|
+
* made inline and never asked whether the backend needed telling at all.
|
|
5266
|
+
*
|
|
5267
|
+
* Never throws: a missed reload notice must not fail a spawn.
|
|
5268
|
+
*/
|
|
5269
|
+
async runWarmupInstructionNotice() {
|
|
5270
|
+
try {
|
|
5271
|
+
const action = warmupNoticeAction({
|
|
5272
|
+
warmupNeeded: this.warmupNeeded,
|
|
5273
|
+
backend: this.backend ?? undefined,
|
|
5274
|
+
pasteQueueDepth: this.pasteQueueDepth,
|
|
5275
|
+
});
|
|
5276
|
+
if (action === "skip") {
|
|
5277
|
+
this.logger.debug(this.warmupNeeded
|
|
5278
|
+
? "Warmup skipped — this backend reloads instructions on resume"
|
|
5279
|
+
: "Warmup skipped — instructions unchanged");
|
|
5280
|
+
// When the backend learns of the change on its own, record what it now
|
|
5281
|
+
// holds: leaving prev-instructions behind would keep every later
|
|
5282
|
+
// restart comparing against a value the agent has long since replaced.
|
|
5283
|
+
if (this.warmupNeeded) {
|
|
5284
|
+
try {
|
|
5285
|
+
writeFileSync(join(this.instanceDir, "prev-instructions"), this.lastBuiltInstructions);
|
|
5286
|
+
}
|
|
5287
|
+
catch { /* best effort */ }
|
|
5288
|
+
}
|
|
5289
|
+
return;
|
|
5290
|
+
}
|
|
5291
|
+
if (action === "defer") {
|
|
5292
|
+
this.logger.debug("Warmup deferred — no pending inbound messages");
|
|
5293
|
+
// Convert to pendingInstructionsNotice so it fires on next real message.
|
|
5294
|
+
this.pendingInstructionsNotice = true;
|
|
5295
|
+
try {
|
|
5296
|
+
writeFileSync(join(this.instanceDir, "prev-instructions"), this.lastBuiltInstructions);
|
|
5297
|
+
}
|
|
5298
|
+
catch { }
|
|
5299
|
+
return;
|
|
5300
|
+
}
|
|
5301
|
+
const wid = existsSync(join(this.instanceDir, "window-id"))
|
|
5302
|
+
? readFileSync(join(this.instanceDir, "window-id"), "utf-8").trim() : "";
|
|
5303
|
+
if (wid && this.controlClient) {
|
|
5304
|
+
await this.controlClient.waitForIdle(wid, 120_000);
|
|
5305
|
+
}
|
|
5306
|
+
else {
|
|
5307
|
+
await new Promise(r => setTimeout(r, 5000));
|
|
5308
|
+
}
|
|
5309
|
+
// This path only runs when pasteQueueDepth > 0 — i.e. exactly when a real
|
|
5310
|
+
// delivery is already in flight or queued. Without the lock the notice and
|
|
5311
|
+
// that delivery race into the same pane.
|
|
5312
|
+
await this.paneWriteLock.run(async () => {
|
|
5313
|
+
await this.tmux?.pasteText(buildInstructionReloadNotice(this.backend?.binaryName ?? "unknown", this.name, this.instanceDir), this.systemPasteOptions());
|
|
5314
|
+
});
|
|
5315
|
+
// Record the value the agent has now been told about so the next
|
|
5316
|
+
// unchanged restart skips the reload.
|
|
5317
|
+
try {
|
|
5318
|
+
writeFileSync(join(this.instanceDir, "prev-instructions"), this.lastBuiltInstructions);
|
|
5319
|
+
}
|
|
5320
|
+
catch { /* best effort */ }
|
|
5321
|
+
this.logger.debug("Warmup sent after idle");
|
|
5322
|
+
}
|
|
5323
|
+
catch { /* non-fatal */ }
|
|
5324
|
+
}
|
|
5273
5325
|
async trySpawnInsideGate(reuseWindow = false, startupTimeoutMs) {
|
|
5274
5326
|
const backendConfig = this.buildBackendConfig();
|
|
5275
5327
|
// Compare freshly-built instructions against the last value the agent was
|
|
@@ -5298,7 +5350,7 @@ export class Daemon extends EventEmitter {
|
|
|
5298
5350
|
// For backends that don't re-read instructions on resume (kiro/codex/
|
|
5299
5351
|
// gemini), also notify the agent on next message instead of forcing a new
|
|
5300
5352
|
// session. Resume is preserved so context isn't lost.
|
|
5301
|
-
if (!backendConfig.skipResume &&
|
|
5353
|
+
if (!backendConfig.skipResume && backendNeedsPaneReloadNotice(this.backend) && this.warmupNeeded) {
|
|
5302
5354
|
if (prev) {
|
|
5303
5355
|
this.logger.info("Instructions changed — will notify agent on next message");
|
|
5304
5356
|
this.pendingInstructionsNotice = true;
|