@songsid/agend 2.1.1-beta.2 → 2.1.1-beta.21
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/README.md +1 -0
- package/README.zh-TW.md +1 -0
- package/dist/access-path.js +15 -6
- package/dist/access-path.js.map +1 -1
- package/dist/agent-cli-instructions.md +9 -0
- package/dist/backend/antigravity.d.ts +4 -1
- package/dist/backend/antigravity.js +24 -13
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/claude-code.d.ts +37 -0
- package/dist/backend/claude-code.js +47 -8
- package/dist/backend/claude-code.js.map +1 -1
- package/dist/backend/codex.d.ts +17 -0
- package/dist/backend/codex.js +279 -62
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/gemini-cli.js +4 -7
- package/dist/backend/gemini-cli.js.map +1 -1
- package/dist/backend/grok.d.ts +24 -0
- package/dist/backend/grok.js +57 -8
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.d.ts +27 -0
- package/dist/backend/kiro.js +96 -15
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/opencode.js +4 -7
- package/dist/backend/opencode.js.map +1 -1
- package/dist/backend/types.d.ts +44 -0
- package/dist/backend/types.js +3 -3
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.d.ts +15 -0
- package/dist/channel/adapters/discord.js +94 -6
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.d.ts +21 -0
- package/dist/channel/adapters/telegram.js +132 -15
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/ipc-bridge.d.ts +17 -1
- package/dist/channel/ipc-bridge.js +53 -17
- package/dist/channel/ipc-bridge.js.map +1 -1
- package/dist/channel/ipc-timeouts.d.ts +40 -0
- package/dist/channel/ipc-timeouts.js +58 -0
- package/dist/channel/ipc-timeouts.js.map +1 -0
- package/dist/channel/mcp-server.js +30 -14
- package/dist/channel/mcp-server.js.map +1 -1
- package/dist/channel/mcp-tools.js +28 -1
- package/dist/channel/mcp-tools.js.map +1 -1
- package/dist/channel/message-queue.d.ts +1 -0
- package/dist/channel/message-queue.js +49 -17
- package/dist/channel/message-queue.js.map +1 -1
- package/dist/channel/reconnect-backoff.d.ts +17 -0
- package/dist/channel/reconnect-backoff.js +21 -0
- package/dist/channel/reconnect-backoff.js.map +1 -0
- package/dist/channel/types.d.ts +29 -0
- package/dist/classic-channel-manager.js +1 -5
- package/dist/classic-channel-manager.js.map +1 -1
- package/dist/cli.js +148 -60
- package/dist/cli.js.map +1 -1
- package/dist/completion.d.ts +27 -0
- package/dist/completion.js +121 -0
- package/dist/completion.js.map +1 -0
- package/dist/config-validator.js +27 -0
- package/dist/config-validator.js.map +1 -1
- package/dist/config.js +6 -0
- package/dist/config.js.map +1 -1
- package/dist/cost-guard.d.ts +3 -1
- package/dist/cost-guard.js +3 -1
- package/dist/cost-guard.js.map +1 -1
- package/dist/daemon.d.ts +230 -13
- package/dist/daemon.js +975 -335
- package/dist/daemon.js.map +1 -1
- package/dist/event-log.d.ts +31 -0
- package/dist/event-log.js +96 -0
- package/dist/event-log.js.map +1 -1
- package/dist/fleet-context.d.ts +2 -0
- package/dist/fleet-manager.d.ts +209 -4
- package/dist/fleet-manager.js +813 -84
- package/dist/fleet-manager.js.map +1 -1
- package/dist/general-knowledge/skills/cross-instance-messaging/SKILL.md +22 -0
- package/dist/general-knowledge/skills/model-discovery/SKILL.md +14 -23
- package/dist/general-knowledge/skills/session-management/SKILL.md +15 -34
- package/dist/hang-detector.d.ts +19 -13
- package/dist/hang-detector.js +19 -49
- package/dist/hang-detector.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +21 -1
- package/dist/instance-lifecycle.js +141 -7
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +5 -0
- package/dist/instructions.js +10 -5
- package/dist/instructions.js.map +1 -1
- package/dist/locale.js +3 -0
- package/dist/locale.js.map +1 -1
- package/dist/logger.js +14 -0
- package/dist/logger.js.map +1 -1
- package/dist/mcp-liveness.d.ts +21 -0
- package/dist/mcp-liveness.js +27 -0
- package/dist/mcp-liveness.js.map +1 -0
- package/dist/outbound-handlers.d.ts +16 -0
- package/dist/outbound-handlers.js +121 -27
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/outbound-schemas.d.ts +7 -2
- package/dist/outbound-schemas.js +13 -2
- package/dist/outbound-schemas.js.map +1 -1
- package/dist/pane-write-lock.d.ts +48 -0
- package/dist/pane-write-lock.js +73 -0
- package/dist/pane-write-lock.js.map +1 -0
- package/dist/process-memory.d.ts +31 -0
- package/dist/process-memory.js +79 -0
- package/dist/process-memory.js.map +1 -0
- package/dist/quickstart.js +17 -16
- package/dist/quickstart.js.map +1 -1
- package/dist/scheduler/db.js +3 -0
- package/dist/scheduler/db.js.map +1 -1
- package/dist/sd-notify.d.ts +45 -0
- package/dist/sd-notify.js +74 -3
- package/dist/sd-notify.js.map +1 -1
- package/dist/secret-file.d.ts +33 -0
- package/dist/secret-file.js +36 -0
- package/dist/secret-file.js.map +1 -0
- package/dist/setup-wizard.js +9 -7
- package/dist/setup-wizard.js.map +1 -1
- package/dist/tmux-control.d.ts +58 -5
- package/dist/tmux-control.js +107 -13
- package/dist/tmux-control.js.map +1 -1
- package/dist/tmux-manager.d.ts +47 -2
- package/dist/tmux-manager.js +103 -8
- package/dist/tmux-manager.js.map +1 -1
- package/dist/topic-commands.d.ts +43 -1
- package/dist/topic-commands.js +196 -66
- package/dist/topic-commands.js.map +1 -1
- package/dist/tui-glyphs.d.ts +25 -0
- package/dist/tui-glyphs.js +26 -0
- package/dist/tui-glyphs.js.map +1 -0
- package/dist/types.d.ts +19 -0
- package/dist/ui/view.html +291 -33
- package/dist/update-check.d.ts +22 -0
- package/dist/update-check.js +44 -0
- package/dist/update-check.js.map +1 -0
- package/dist/usage/providers.d.ts +50 -0
- package/dist/usage/providers.js +611 -0
- package/dist/usage/providers.js.map +1 -0
- package/dist/usage/usage-api.d.ts +50 -0
- package/dist/usage/usage-api.js +111 -0
- package/dist/usage/usage-api.js.map +1 -0
- package/dist/view-api.d.ts +10 -0
- package/dist/view-api.js +67 -14
- package/dist/view-api.js.map +1 -1
- package/dist/web-api.js +5 -2
- package/dist/web-api.js.map +1 -1
- package/package.json +4 -1
- package/templates/systemd.service.ejs +9 -1
- package/dist/channel/tool-tracker.d.ts +0 -13
- package/dist/channel/tool-tracker.js +0 -58
- package/dist/channel/tool-tracker.js.map +0 -1
- package/dist/daemon-entry.d.ts +0 -1
- package/dist/daemon-entry.js +0 -30
- package/dist/daemon-entry.js.map +0 -1
- package/dist/fleet-system-prompt.d.ts +0 -11
- package/dist/fleet-system-prompt.js +0 -61
- package/dist/fleet-system-prompt.js.map +0 -1
package/dist/event-log.js
CHANGED
|
@@ -13,6 +13,10 @@ export class EventLog {
|
|
|
13
13
|
constructor(dbPath) {
|
|
14
14
|
this.db = new Database(dbPath);
|
|
15
15
|
this.db.pragma("journal_mode = WAL");
|
|
16
|
+
// The fleet writes this file while `agend events` / `agend activity` read it
|
|
17
|
+
// from a separate process. Without a busy timeout, either side raises
|
|
18
|
+
// SQLITE_BUSY immediately instead of waiting for the other's write to finish.
|
|
19
|
+
this.db.pragma("busy_timeout = 5000");
|
|
16
20
|
this.db.exec(`
|
|
17
21
|
CREATE TABLE IF NOT EXISTS events (
|
|
18
22
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -25,6 +29,24 @@ export class EventLog {
|
|
|
25
29
|
CREATE INDEX IF NOT EXISTS idx_events_type ON events(event_type, created_at);
|
|
26
30
|
`);
|
|
27
31
|
this.insertStmt = this.db.prepare("INSERT INTO events (instance_name, event_type, payload) VALUES (?, ?, ?)");
|
|
32
|
+
// Reaction queue (#432 rework of #408/#413). A reaction is context, not a
|
|
33
|
+
// message: it no longer triggers an agent turn. It waits here until the next
|
|
34
|
+
// REAL message to the same instance, rides in as one compact context line,
|
|
35
|
+
// and is then marked consumed. consumed_at stays (rather than DELETE) so a
|
|
36
|
+
// delivery that fails after summarising does not lose the reactions — they
|
|
37
|
+
// are only marked once the message actually went out.
|
|
38
|
+
this.db.exec(`
|
|
39
|
+
CREATE TABLE IF NOT EXISTS reactions (
|
|
40
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
41
|
+
instance_name TEXT NOT NULL,
|
|
42
|
+
message_id TEXT NOT NULL,
|
|
43
|
+
username TEXT NOT NULL,
|
|
44
|
+
emoji TEXT NOT NULL,
|
|
45
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
46
|
+
consumed_at TEXT
|
|
47
|
+
);
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_reactions_pending ON reactions(instance_name, consumed_at);
|
|
49
|
+
`);
|
|
28
50
|
// Activity log for visualization
|
|
29
51
|
this.db.exec(`
|
|
30
52
|
CREATE TABLE IF NOT EXISTS activity (
|
|
@@ -92,6 +114,80 @@ export class EventLog {
|
|
|
92
114
|
this.db
|
|
93
115
|
.prepare("DELETE FROM activity WHERE timestamp < datetime('now', ?)")
|
|
94
116
|
.run(`-${days} days`);
|
|
117
|
+
// Reactions have their own, shorter horizon: after REACTION_RETENTION_DAYS a
|
|
118
|
+
// pending reaction is stale context nobody should be shown, consumed or not.
|
|
119
|
+
this.db
|
|
120
|
+
.prepare("DELETE FROM reactions WHERE created_at < datetime('now', ?)")
|
|
121
|
+
.run(`-${EventLog.REACTION_RETENTION_DAYS} days`);
|
|
122
|
+
}
|
|
123
|
+
static REACTION_RETENTION_DAYS = 7;
|
|
124
|
+
/** Queue a reaction for the instance's next real message. */
|
|
125
|
+
addReaction(instance, messageId, username, emoji) {
|
|
126
|
+
this.db
|
|
127
|
+
.prepare("INSERT INTO reactions (instance_name, message_id, username, emoji) VALUES (?, ?, ?, ?)")
|
|
128
|
+
.run(instance, messageId, username, emoji);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* A withdrawn reaction is withdrawn context. Deleting the matching pending row
|
|
132
|
+
* (newest first, one per removal) means an add-then-remove nets out to nothing,
|
|
133
|
+
* instead of reporting a 👍 the user visibly took back. Already-consumed rows
|
|
134
|
+
* are left alone — the agent has seen those; history does not un-happen.
|
|
135
|
+
*/
|
|
136
|
+
removeReaction(instance, messageId, username, emoji) {
|
|
137
|
+
this.db
|
|
138
|
+
.prepare(`DELETE FROM reactions WHERE id = (
|
|
139
|
+
SELECT id FROM reactions
|
|
140
|
+
WHERE instance_name = ? AND message_id = ? AND username = ? AND emoji = ? AND consumed_at IS NULL
|
|
141
|
+
ORDER BY id DESC LIMIT 1
|
|
142
|
+
)`)
|
|
143
|
+
.run(instance, messageId, username, emoji);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Pending reactions as compact context, grouped by the message they landed on:
|
|
147
|
+
*
|
|
148
|
+
* msg 1532964272244523028: 👍×2 from hanhanv, ❓ from user2 | msg 1532965…: 👍 from hanhanv
|
|
149
|
+
*
|
|
150
|
+
* The message id is the point (#433): the agent's inbound blocks render each of
|
|
151
|
+
* its own messages' ids, so carrying the id is what lets it tell WHICH of its
|
|
152
|
+
* messages was reacted to. Within a message, duplicates of the same emoji from
|
|
153
|
+
* the same user collapse to ×N (a re-added reaction is not new information).
|
|
154
|
+
*
|
|
155
|
+
* Returns null (not an empty string) when there is nothing pending, so callers
|
|
156
|
+
* add zero context in the common case. `maxId` is what the caller hands back to
|
|
157
|
+
* markReactionsConsumed — bounding by id keeps a reaction that arrives DURING
|
|
158
|
+
* delivery pending for the next message instead of being silently eaten.
|
|
159
|
+
*/
|
|
160
|
+
pendingReactions(instance) {
|
|
161
|
+
const rows = this.db
|
|
162
|
+
.prepare("SELECT id, message_id, username, emoji FROM reactions WHERE instance_name = ? AND consumed_at IS NULL ORDER BY id")
|
|
163
|
+
.all(instance);
|
|
164
|
+
if (rows.length === 0)
|
|
165
|
+
return null;
|
|
166
|
+
// message_id → (emoji+user → count), both insertion-ordered so the summary
|
|
167
|
+
// reads in arrival order.
|
|
168
|
+
const byMessage = new Map();
|
|
169
|
+
for (const row of rows) {
|
|
170
|
+
const counts = byMessage.get(row.message_id) ?? new Map();
|
|
171
|
+
const key = `${row.emoji}\u0000${row.username}`;
|
|
172
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
173
|
+
byMessage.set(row.message_id, counts);
|
|
174
|
+
}
|
|
175
|
+
const groups = [];
|
|
176
|
+
for (const [messageId, counts] of byMessage) {
|
|
177
|
+
const parts = [];
|
|
178
|
+
for (const [key, count] of counts) {
|
|
179
|
+
const [emoji, username] = key.split("\u0000");
|
|
180
|
+
parts.push(count > 1 ? `${emoji}×${count} from ${username}` : `${emoji} from ${username}`);
|
|
181
|
+
}
|
|
182
|
+
groups.push(`msg ${messageId}: ${parts.join(", ")}`);
|
|
183
|
+
}
|
|
184
|
+
return { summary: groups.join(" | "), maxId: rows[rows.length - 1].id };
|
|
185
|
+
}
|
|
186
|
+
/** Mark reactions up to `maxId` as shown. Call only after the delivery succeeded. */
|
|
187
|
+
markReactionsConsumed(instance, maxId) {
|
|
188
|
+
this.db
|
|
189
|
+
.prepare("UPDATE reactions SET consumed_at = datetime('now') WHERE instance_name = ? AND id <= ? AND consumed_at IS NULL")
|
|
190
|
+
.run(instance, maxId);
|
|
95
191
|
}
|
|
96
192
|
close() {
|
|
97
193
|
this.db.close();
|
package/dist/event-log.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-log.js","sourceRoot":"","sources":["../src/event-log.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"event-log.js","sourceRoot":"","sources":["../src/event-log.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAmCtC,SAAS,aAAa,CAAC,CAAS;IAC9B,IAAI,CAAC;QAAC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAA4B,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC;QAAC,OAAO,IAAI,CAAC;IAAC,CAAC;AACjF,CAAC;AAED,MAAM,OAAO,QAAQ;IACX,EAAE,CAAoB;IACtB,UAAU,CAAqB;IAEvC,YAAY,MAAc;QACxB,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACrC,6EAA6E;QAC7E,sEAAsE;QACtE,8EAA8E;QAC9E,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,qBAAqB,CAAC,CAAC;QACtC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;KAUZ,CAAC,CAAC;QACH,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,0EAA0E,CAAC,CAAC;QAE9G,0EAA0E;QAC1E,6EAA6E;QAC7E,2EAA2E;QAC3E,2EAA2E;QAC3E,2EAA2E;QAC3E,sDAAsD;QACtD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;KAWZ,CAAC,CAAC;QAEH,iCAAiC;QACjC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;KAWZ,CAAC,CAAC;IACL,CAAC;IAED,MAAM,CAAC,QAAgB,EAAE,IAAY,EAAE,OAAiC;QACtE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACxF,CAAC;IAED,KAAK,CAAC,OAAkB,EAAE;QACxB,MAAM,UAAU,GAAa,EAAE,CAAC;QAChC,MAAM,MAAM,GAAc,EAAE,CAAC;QAE7B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,UAAU,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;YACrC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7B,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,UAAU,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,UAAU,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QAED,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/E,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,wBAAwB,KAAK,mCAAmC,CAAC;QAC7E,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEnB,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAkB,CAAC;QAClE,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtB,GAAG,CAAC;YACJ,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI;SAC7D,CAAC,CAAC,CAAC;IACN,CAAC;IAED,iEAAiE;IAEjE,WAAW,CAAC,KAAa,EAAE,MAAc,EAAE,OAAe,EAAE,QAAiB,EAAE,MAAe;QAC5F,IAAI,CAAC,EAAE,CAAC,OAAO,CACb,wFAAwF,CACzF,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,IAAI,IAAI,EAAE,OAAO,EAAE,MAAM,IAAI,IAAI,CAAC,CAAC;IAClE,CAAC;IAED,YAAY,CAAC,IAAyC;QACpD,IAAI,GAAG,GAAG,wBAAwB,CAAC;QACnC,MAAM,MAAM,GAAc,EAAE,CAAC;QAC7B,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;YAChB,GAAG,IAAI,uBAAuB,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,GAAG,IAAI,yBAAyB,CAAC;QACjC,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;YAAC,GAAG,IAAI,UAAU,CAAC;YAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAAC,CAAC;QAChE,OAAO,IAAI,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,MAAM,CAAkB,CAAC;IAC9D,CAAC;IAED,KAAK,CAAC,IAAY;QAChB,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,0DAA0D,CAAC;aACnE,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC;QACxB,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,2DAA2D,CAAC;aACpE,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC;QACxB,6EAA6E;QAC7E,6EAA6E;QAC7E,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,6DAA6D,CAAC;aACtE,GAAG,CAAC,IAAI,QAAQ,CAAC,uBAAuB,OAAO,CAAC,CAAC;IACtD,CAAC;IAEO,MAAM,CAAC,uBAAuB,GAAG,CAAC,CAAC;IAE3C,6DAA6D;IAC7D,WAAW,CAAC,QAAgB,EAAE,SAAiB,EAAE,QAAgB,EAAE,KAAa;QAC9E,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,wFAAwF,CAAC;aACjG,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;OAKG;IACH,cAAc,CAAC,QAAgB,EAAE,SAAiB,EAAE,QAAgB,EAAE,KAAa;QACjF,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC;;;;QAIP,CAAC;aACF,GAAG,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;;;;;;;;OAcG;IACH,gBAAgB,CAAC,QAAgB;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE;aACjB,OAAO,CAAC,mHAAmH,CAAC;aAC5H,GAAG,CAAC,QAAQ,CAA+E,CAAC;QAC/F,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEnC,2EAA2E;QAC3E,0BAA0B;QAC1B,MAAM,SAAS,GAAG,IAAI,GAAG,EAA+B,CAAC;QACzD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,IAAI,GAAG,EAAkB,CAAC;YAC1E,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,KAAK,SAAS,GAAG,CAAC,QAAQ,EAAE,CAAC;YAChD,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5C,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC;QAED,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,KAAK,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;YAC5C,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;gBAClC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;gBAC9C,KAAK,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,IAAI,KAAK,SAAS,QAAQ,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,SAAS,QAAQ,EAAE,CAAC,CAAC;YAC7F,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvD,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IAC1E,CAAC;IAED,qFAAqF;IACrF,qBAAqB,CAAC,QAAgB,EAAE,KAAa;QACnD,IAAI,CAAC,EAAE;aACJ,OAAO,CAAC,gHAAgH,CAAC;aACzH,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC"}
|
package/dist/fleet-context.d.ts
CHANGED
|
@@ -75,6 +75,8 @@ export interface FleetContext {
|
|
|
75
75
|
lastError?: string;
|
|
76
76
|
}>;
|
|
77
77
|
getInstanceExecutionState?(name: string): "idle" | "working" | "stuck" | "paused" | null;
|
|
78
|
+
/** Human-readable effective model for an instance (resolves inherited defaults). */
|
|
79
|
+
modelDisplayForInstance?(name: string): string;
|
|
78
80
|
/**
|
|
79
81
|
* Show a model-selection inline keyboard for the given instance in a TG topic.
|
|
80
82
|
* Returns a fallback text message if no model list is available (caller should send it).
|
package/dist/fleet-manager.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FleetMemory } from "./process-memory.js";
|
|
1
2
|
import type { FleetConfig, RawFleetConfig, InstanceConfig } from "./types.js";
|
|
2
3
|
import { type RouteTarget } from "./fleet-context.js";
|
|
3
4
|
import { EventLog } from "./event-log.js";
|
|
@@ -48,7 +49,7 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
48
49
|
private static sighupHandlerInstalled;
|
|
49
50
|
private children;
|
|
50
51
|
readonly lifecycle: InstanceLifecycle;
|
|
51
|
-
/**
|
|
52
|
+
/** Live view of lifecycle.daemons — used throughout; not deprecated. */
|
|
52
53
|
get daemons(): Map<string, import("./daemon.js").Daemon>;
|
|
53
54
|
fleetConfig: FleetConfig | null;
|
|
54
55
|
private rawFleetConfig;
|
|
@@ -98,6 +99,10 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
98
99
|
private instanceIdleWaiters;
|
|
99
100
|
private lastInboundUser;
|
|
100
101
|
private cancelButtons;
|
|
102
|
+
/** instanceName → what it is doing right now, when the backend can tell us. */
|
|
103
|
+
private instanceActivity;
|
|
104
|
+
/** instanceName → tail of deliveries waiting for its IPC to come back. */
|
|
105
|
+
private ipcWaitTails;
|
|
101
106
|
private lastInboundMsg;
|
|
102
107
|
private topicArchiver;
|
|
103
108
|
controlClient: TmuxControlClient | null;
|
|
@@ -107,12 +112,20 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
107
112
|
private pendingModelSelects;
|
|
108
113
|
private failoverActive;
|
|
109
114
|
readonly ipcStoppingInstances: Set<string>;
|
|
115
|
+
/** Coalesce concurrent connection attempts for the same daemon socket. */
|
|
116
|
+
private ipcConnectInFlight;
|
|
117
|
+
/** At most one reconnect/backoff loop may exist per instance. */
|
|
118
|
+
private ipcReconnectInFlight;
|
|
110
119
|
private adapterRestarting;
|
|
111
120
|
private adapterState;
|
|
112
121
|
private collabInstances;
|
|
113
122
|
private healthServer;
|
|
114
123
|
private healthPortRetried;
|
|
115
124
|
private updateCheckTimer;
|
|
125
|
+
private eventLogPruneTimer;
|
|
126
|
+
private logRotateTimer;
|
|
127
|
+
/** Days of event/activity history to keep. */
|
|
128
|
+
private static readonly EVENT_LOG_RETENTION_DAYS;
|
|
116
129
|
private watchdogTimer;
|
|
117
130
|
private startedAt;
|
|
118
131
|
private mirrorBuffer;
|
|
@@ -193,6 +206,25 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
193
206
|
private enforceWarmCap;
|
|
194
207
|
private waitForInstanceIdle;
|
|
195
208
|
private deliverWithIdleGate;
|
|
209
|
+
/**
|
|
210
|
+
* Hand a payload to an instance's IPC, waiting out a *transient* disconnect.
|
|
211
|
+
*
|
|
212
|
+
* A daemon that is restarting — `/restart`, crash recovery, a model switch —
|
|
213
|
+
* drops its socket for a few seconds. Any message arriving in that window used
|
|
214
|
+
* to fail instantly: the caller logged a warning, put ❌ on the user's message,
|
|
215
|
+
* and the message was gone. The user had to notice the ❌ and retype it. That is
|
|
216
|
+
* the "instance 訊息不容易掉" goal failing on the most predictable event there is.
|
|
217
|
+
*
|
|
218
|
+
* The wait is bounded. If the instance is genuinely down, this still throws and
|
|
219
|
+
* the ❌ still appears — just for a real failure rather than a restart.
|
|
220
|
+
*
|
|
221
|
+
* Ordering is preserved by serialising behind any waiter already queued for this
|
|
222
|
+
* instance, *including* when the socket happens to be up: otherwise a message
|
|
223
|
+
* arriving after the reconnect could overtake one that has been waiting for it.
|
|
224
|
+
*/
|
|
225
|
+
private sendWhenConnected;
|
|
226
|
+
/** Poll for the instance's IPC to come back, then send. Throws if it does not. */
|
|
227
|
+
private sendAfterIpcReturns;
|
|
196
228
|
/** Single delivery facade: wake paused CLIs and serialize non-user work behind idle. */
|
|
197
229
|
deliverToInstance(instanceName: string, payload: Record<string, unknown>, options?: DeliveryOptions): Promise<void>;
|
|
198
230
|
/** Fleet admin is an explicit config allowlist entry, not merely an open/paired user. */
|
|
@@ -200,7 +232,7 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
200
232
|
changeInstancePauseState(name: string, action: "pause" | "wake"): Promise<"paused" | "awake" | "not_idle">;
|
|
201
233
|
/** Apply a Settings edit to a ClassicBot channel without waiting for the poller. */
|
|
202
234
|
restartClassicInstanceFromSettings(instanceName: string): Promise<void>;
|
|
203
|
-
startInstance(name: string, config: InstanceConfig, topicMode: boolean): Promise<void>;
|
|
235
|
+
startInstance(name: string, config: InstanceConfig, topicMode: boolean, kind?: "fleet-topic" | "classic"): Promise<void>;
|
|
204
236
|
/** Recreate a daemon for a marker-only paused instance after an explicit wake/delivery. */
|
|
205
237
|
startPersistedPausedInstance(name: string): Promise<void>;
|
|
206
238
|
/**
|
|
@@ -247,18 +279,73 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
247
279
|
retryCount: number;
|
|
248
280
|
lastError?: string;
|
|
249
281
|
}>;
|
|
282
|
+
/**
|
|
283
|
+
* Real, checkable fleet health for `/health` and the operator.
|
|
284
|
+
*
|
|
285
|
+
* `status` is:
|
|
286
|
+
* - `ok` — at least one adapter connected and every configured instance
|
|
287
|
+
* that should be running is running
|
|
288
|
+
* - `degraded` — reachable, but something the operator should look at (an
|
|
289
|
+
* adapter retrying, an instance crashed or stopped)
|
|
290
|
+
* - `down` — the fleet cannot do its job: no adapter is connected, so no
|
|
291
|
+
* message can arrive or be answered
|
|
292
|
+
*
|
|
293
|
+
* Deliberately does NOT gate the systemd watchdog — see the comment at the
|
|
294
|
+
* WATCHDOG timer for why.
|
|
295
|
+
*/
|
|
296
|
+
getFleetHealth(): {
|
|
297
|
+
status: "ok" | "degraded" | "down";
|
|
298
|
+
uptime: number;
|
|
299
|
+
instances: {
|
|
300
|
+
configured: number;
|
|
301
|
+
running: number;
|
|
302
|
+
crashed: number;
|
|
303
|
+
paused: number;
|
|
304
|
+
stopped: number;
|
|
305
|
+
};
|
|
306
|
+
adapters: {
|
|
307
|
+
total: number;
|
|
308
|
+
connected: number;
|
|
309
|
+
states: Record<string, string>;
|
|
310
|
+
};
|
|
311
|
+
startupComplete: boolean;
|
|
312
|
+
/** See process-memory.ts: the fleet process and the whole service cgroup are
|
|
313
|
+
* reported separately because they differ by ~60x and only one of them can
|
|
314
|
+
* show a fleet-manager leak. */
|
|
315
|
+
memory: FleetMemory;
|
|
316
|
+
problems: string[];
|
|
317
|
+
};
|
|
250
318
|
/** Start the primary adapter (backward-compatible, sets this.adapter) */
|
|
251
319
|
private startSingleAdapter;
|
|
252
320
|
/** Start an additional (non-primary) adapter */
|
|
253
321
|
private startAdditionalAdapter;
|
|
254
322
|
/** Connect IPC to a single instance with all handlers */
|
|
255
323
|
connectIpcToInstance(name: string): Promise<void>;
|
|
324
|
+
private connectIpcToInstanceInternal;
|
|
256
325
|
/** Attempt IPC reconnection with exponential backoff */
|
|
257
326
|
private ipcReconnect;
|
|
327
|
+
private runIpcReconnect;
|
|
258
328
|
/** Restart a channel adapter after fatal error with infinite retry + 60s cap */
|
|
259
329
|
private restartAdapter;
|
|
260
330
|
/** Handle inbound message — transcribe voice if present, then route */
|
|
261
331
|
private findGeneralInstance;
|
|
332
|
+
/**
|
|
333
|
+
* A user reacted to one of the bot's messages (#408).
|
|
334
|
+
*
|
|
335
|
+
* A reaction is context, not a message (#432, reworking #413): it never triggers
|
|
336
|
+
* an agent turn and never wakes anything. It is queued in the event log and rides
|
|
337
|
+
* into the instance's NEXT real message as one compact leading line —
|
|
338
|
+
* `[Recent reactions: 👍×2 from hanhanv]` — after which it is marked consumed.
|
|
339
|
+
* No pending reactions → no line → zero context spent, which is the common case.
|
|
340
|
+
*/
|
|
341
|
+
private handleInboundReaction;
|
|
342
|
+
/**
|
|
343
|
+
* The queued-reaction summary for an instance's next real message, or {} when
|
|
344
|
+
* nothing is pending (the common case must add zero context). The consume
|
|
345
|
+
* callback is separate from the fetch so reactions are only marked once the
|
|
346
|
+
* message actually went out — a failed delivery keeps them queued.
|
|
347
|
+
*/
|
|
348
|
+
private pendingReactionsMeta;
|
|
262
349
|
private handleInboundMessage;
|
|
263
350
|
/** Handle outbound tool calls from a daemon instance */
|
|
264
351
|
/** Warn (but don't block) when rate limits are high. 30-min debounce per instance. */
|
|
@@ -307,6 +394,68 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
307
394
|
private static FAILOVER_RECOVER_PCT;
|
|
308
395
|
checkModelFailover(name: string, fiveHourPct: number): void;
|
|
309
396
|
toggleFleetCollab(instanceName: string): boolean;
|
|
397
|
+
/**
|
|
398
|
+
* Open the event log, tolerating a corrupt file.
|
|
399
|
+
*
|
|
400
|
+
* `events.db` holds history only — event rows and the activity feed. Nothing the
|
|
401
|
+
* fleet needs to run depends on it, and every consumer already uses
|
|
402
|
+
* `this.eventLog?.`. An unguarded `new EventLog(...)` here meant a corrupt or
|
|
403
|
+
* unreadable history file (a truncated WAL after a hard kill, a full disk)
|
|
404
|
+
* threw during startAll and the WHOLE FLEET FAILED TO BOOT — trading every
|
|
405
|
+
* running agent for a file whose only job is reporting.
|
|
406
|
+
*
|
|
407
|
+
* So: try, move a bad file aside and retry once with a fresh one, and if even
|
|
408
|
+
* that fails carry on without an event log.
|
|
409
|
+
*/
|
|
410
|
+
/**
|
|
411
|
+
* Run `agend backend doctor` for the fleet's default backend and return its
|
|
412
|
+
* cleaned output.
|
|
413
|
+
*
|
|
414
|
+
* Async on purpose: this was `execSync` with a 30s timeout, reachable by any
|
|
415
|
+
* allowlisted user through `/doctor`. While it ran, the entire fleet event loop
|
|
416
|
+
* was frozen — no IPC, no adapter, no message delivery, no health responses,
|
|
417
|
+
* and critically no WATCHDOG ping, so a slow doctor could push past
|
|
418
|
+
* WatchdogSec and have systemd SIGABRT the fleet.
|
|
419
|
+
*/
|
|
420
|
+
private runBackendDoctor;
|
|
421
|
+
/** Drop event/activity rows older than the retention window. Best-effort. */
|
|
422
|
+
/**
|
|
423
|
+
* Cap every instance's pipe-pane log, walking the instances **directory** rather
|
|
424
|
+
* than the config.
|
|
425
|
+
*
|
|
426
|
+
* A running instance rotates its own log on each health tick, so the ones that
|
|
427
|
+
* need this are the ones nothing else looks at:
|
|
428
|
+
*
|
|
429
|
+
* - deleted instances, whose directory outlives the config entry. Nothing ever
|
|
430
|
+
* touched these again. On the machine this was found on, one held 122 MB and
|
|
431
|
+
* another 74 MB, out of 622 MB of pipe-pane logs in total.
|
|
432
|
+
* - classic instances, which live in classicChannels, not fleetConfig.instances,
|
|
433
|
+
* and so were never in the old config-driven loop at all.
|
|
434
|
+
* - stopped instances, which have no health tick running.
|
|
435
|
+
*
|
|
436
|
+
* pipe-pane writes raw TUI output, so a wedged splash screen can emit ANSI frames
|
|
437
|
+
* at animation rate. Unbounded growth here fills the disk, which takes the whole
|
|
438
|
+
* fleet down rather than one instance.
|
|
439
|
+
*/
|
|
440
|
+
private rotateAllInstanceLogs;
|
|
441
|
+
private pruneEventLog;
|
|
442
|
+
private openEventLog;
|
|
443
|
+
/**
|
|
444
|
+
* Report a fleet-level fault (not attributable to one instance) to the General
|
|
445
|
+
* topic, so the operator learns about it without reading daemon.log.
|
|
446
|
+
*
|
|
447
|
+
* Throttled per distinct message: an unhandled rejection typically comes from a
|
|
448
|
+
* loop (a poller, a repeating timer), and one channel message per occurrence
|
|
449
|
+
* would bury the topic — which is worse than silence. First occurrence goes out
|
|
450
|
+
* immediately, repeats are suppressed for THROTTLE_MS and then re-sent with a
|
|
451
|
+
* count.
|
|
452
|
+
*
|
|
453
|
+
* The log line is written by the caller regardless: if every adapter is down,
|
|
454
|
+
* the only notification path is the one that is broken.
|
|
455
|
+
*/
|
|
456
|
+
notifyFleetError(text: string): void;
|
|
457
|
+
private static readonly FLEET_ERROR_THROTTLE_MS;
|
|
458
|
+
private fleetErrorNotices;
|
|
310
459
|
notifyInstanceTopic(instanceName: string, text: string, extraOpts?: import("./channel/types.js").SendOpts): void;
|
|
311
460
|
/** Send a "🛑 Cancel" button to the instance's topic/channel after delivery. */
|
|
312
461
|
/**
|
|
@@ -318,6 +467,40 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
318
467
|
/** Whether the instance currently has at least one live cancel button. */
|
|
319
468
|
private hasCancelButton;
|
|
320
469
|
sendCancelButton(instanceName: string, correlationId?: string): Promise<void>;
|
|
470
|
+
/**
|
|
471
|
+
* The cancel button's text for a given elapsed time.
|
|
472
|
+
*
|
|
473
|
+
* Below the threshold it keeps the original wording, so a normal quick answer
|
|
474
|
+
* looks exactly as it did before. Past it, the button doubles as the live
|
|
475
|
+
* progress indicator (#409) — the channel showed nothing at all during long work,
|
|
476
|
+
* and once the agent had replied once there was no sign it was still going.
|
|
477
|
+
*/
|
|
478
|
+
static progressText(elapsedMs: number, activity?: string | null): string;
|
|
479
|
+
/**
|
|
480
|
+
* Make a tool summary safe to paste into a channel message.
|
|
481
|
+
*
|
|
482
|
+
* The text is agent-controlled (it is built from tool inputs — file paths,
|
|
483
|
+
* shell commands), so it gets flattened to one line, capped, and stripped of
|
|
484
|
+
* the two Discord mass-mention triggers. Neither channel renders it with a
|
|
485
|
+
* parse mode, so no markup escaping is needed beyond that.
|
|
486
|
+
*/
|
|
487
|
+
private static sanitizeActivity;
|
|
488
|
+
/**
|
|
489
|
+
* Remember what an instance is currently doing, for the progress line.
|
|
490
|
+
*
|
|
491
|
+
* Best-effort by design: only backends that expose a live activity feed report
|
|
492
|
+
* anything, and the progress line simply omits the detail for the rest. It is
|
|
493
|
+
* never used to decide anything — purely what the user is shown.
|
|
494
|
+
*/
|
|
495
|
+
private cacheInstanceActivity;
|
|
496
|
+
/**
|
|
497
|
+
* Refresh the button's text in place while the instance keeps working.
|
|
498
|
+
*
|
|
499
|
+
* Uses `editAlert`, NOT `editMessage`: on Telegram the latter omits reply_markup,
|
|
500
|
+
* and the Bot API treats that as "clear the keyboard" — so editing with it would
|
|
501
|
+
* delete the very cancel button this is trying to keep alive.
|
|
502
|
+
*/
|
|
503
|
+
private startProgressTicker;
|
|
321
504
|
/** Retire (delete) every cancel button belonging to an instance. */
|
|
322
505
|
private retireInstanceButtons;
|
|
323
506
|
/** Begin retiring one button (delete + bounded retry on failure). Idempotent:
|
|
@@ -388,8 +571,20 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
388
571
|
private cliEnvPath;
|
|
389
572
|
/** Read the cached CLI env for a backend, or null if missing/stale/unparseable. */
|
|
390
573
|
private readCliEnv;
|
|
391
|
-
/**
|
|
392
|
-
|
|
574
|
+
/**
|
|
575
|
+
* Resolve the effective model for a fleet or ClassicBot instance, plus where it
|
|
576
|
+
* came from. Single source of truth for `/model` and `/ctx` — precedence:
|
|
577
|
+
* per-instance → fleet defaults → classic channel → CLI's own default (from the
|
|
578
|
+
* cli-env probe cache) → unresolved.
|
|
579
|
+
*/
|
|
580
|
+
resolveInstanceModel(instanceName: string): {
|
|
581
|
+
model: string;
|
|
582
|
+
source: "instance" | "fleet-default" | "classic" | "cli-default" | "unresolved";
|
|
583
|
+
display: string;
|
|
584
|
+
reason?: string;
|
|
585
|
+
};
|
|
586
|
+
/** Human-readable effective model, e.g. `auto (default)`. Used by /ctx. */
|
|
587
|
+
modelDisplayForInstance(instanceName: string): string;
|
|
393
588
|
private modelChoiceLabel;
|
|
394
589
|
/** Probe one backend's CLI env and cache it. Best-effort; never throws. */
|
|
395
590
|
private probeBackend;
|
|
@@ -429,7 +624,17 @@ export declare class FleetManager implements FleetContext, LifecycleContext, Arc
|
|
|
429
624
|
handleClassicStart(channelId: string, channelName: string, userId: string, guildId?: string, adapterId?: string, backend?: string): Promise<string>;
|
|
430
625
|
/** Handle /stop slash command — unregister classic channel */
|
|
431
626
|
handleClassicStop(channelId: string, adapterId?: string): Promise<string>;
|
|
627
|
+
/**
|
|
628
|
+
* Idempotent while in flight: SIGINT and SIGTERM share one handler and the
|
|
629
|
+
* uncaughtException path calls this too, so overlapping runs were possible —
|
|
630
|
+
* each snapshotting the daemon map and calling stop() on the same daemons
|
|
631
|
+
* concurrently. Deliberately NOT `async`, so callers receive the same promise
|
|
632
|
+
* object rather than a fresh wrapper around it. The latch clears when the run
|
|
633
|
+
* settles, so a later genuine stop (after a restart) still does the work.
|
|
634
|
+
*/
|
|
432
635
|
stopAll(): Promise<void>;
|
|
636
|
+
private stopAllInFlight;
|
|
637
|
+
private doStopAll;
|
|
433
638
|
/**
|
|
434
639
|
* Prune stale external sessions by re-querying each daemon for live sessions.
|
|
435
640
|
* Sessions in the registry that are no longer reported by any daemon are removed.
|