@songsid/agend 2.1.1 → 2.1.2-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/antigravity.js +4 -2
- package/dist/backend/antigravity.js.map +1 -1
- package/dist/backend/codex.d.ts +16 -0
- package/dist/backend/codex.js +226 -56
- package/dist/backend/codex.js.map +1 -1
- package/dist/backend/grok.js +20 -0
- package/dist/backend/grok.js.map +1 -1
- package/dist/backend/kiro.js +6 -2
- package/dist/backend/kiro.js.map +1 -1
- package/dist/backend/types.d.ts +7 -0
- package/dist/backend/types.js.map +1 -1
- package/dist/channel/adapters/discord.js +4 -5
- package/dist/channel/adapters/discord.js.map +1 -1
- package/dist/channel/adapters/telegram.js +50 -15
- package/dist/channel/adapters/telegram.js.map +1 -1
- package/dist/channel/ipc-bridge.d.ts +8 -0
- package/dist/channel/ipc-bridge.js +41 -14
- package/dist/channel/ipc-bridge.js.map +1 -1
- package/dist/channel/mcp-server.js +5 -0
- package/dist/channel/mcp-server.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/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/daemon.d.ts +11 -8
- package/dist/daemon.js +56 -16
- package/dist/daemon.js.map +1 -1
- package/dist/fleet-manager.d.ts +7 -1
- package/dist/fleet-manager.js +58 -9
- package/dist/fleet-manager.js.map +1 -1
- package/dist/instance-lifecycle.d.ts +2 -1
- package/dist/instance-lifecycle.js +6 -2
- package/dist/instance-lifecycle.js.map +1 -1
- package/dist/instructions.d.ts +5 -0
- package/dist/instructions.js +9 -11
- package/dist/instructions.js.map +1 -1
- package/dist/logger.js +14 -0
- package/dist/logger.js.map +1 -1
- package/dist/outbound-handlers.d.ts +9 -0
- package/dist/outbound-handlers.js +46 -26
- package/dist/outbound-handlers.js.map +1 -1
- package/dist/topic-commands.d.ts +1 -1
- package/dist/topic-commands.js +11 -2
- package/dist/topic-commands.js.map +1 -1
- package/dist/tui-glyphs.d.ts +21 -0
- package/dist/tui-glyphs.js +22 -0
- package/dist/tui-glyphs.js.map +1 -0
- package/dist/view-api.d.ts +3 -0
- package/dist/view-api.js +6 -2
- package/dist/view-api.js.map +1 -1
- package/package.json +1 -1
package/dist/daemon.js
CHANGED
|
@@ -3,6 +3,7 @@ import { mkdirSync, writeFileSync, readFileSync, existsSync, unlinkSync, rmSync,
|
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { createHash, randomBytes } from "node:crypto";
|
|
5
5
|
import { EventEmitter } from "node:events";
|
|
6
|
+
import { rotateLogIfNeeded } from "./logger.js";
|
|
6
7
|
import { clearPausedMarker, writePausedMarker } from "./pause-marker.js";
|
|
7
8
|
import { TmuxManager, resolveTmuxLogicalSize } from "./tmux-manager.js";
|
|
8
9
|
import { TranscriptMonitor } from "./transcript-monitor.js";
|
|
@@ -244,6 +245,7 @@ export class Daemon extends EventEmitter {
|
|
|
244
245
|
topicMode;
|
|
245
246
|
backend;
|
|
246
247
|
controlClient;
|
|
248
|
+
runtimeIdentity;
|
|
247
249
|
logger;
|
|
248
250
|
tmuxSessionName;
|
|
249
251
|
tmux = null;
|
|
@@ -371,7 +373,7 @@ export class Daemon extends EventEmitter {
|
|
|
371
373
|
this.errorRecoveryDeadlineAt = 0;
|
|
372
374
|
this.activeErrorPatternKey = null;
|
|
373
375
|
}
|
|
374
|
-
constructor(name, config, instanceDir, topicMode = false, backend, controlClient, rootLogger) {
|
|
376
|
+
constructor(name, config, instanceDir, topicMode = false, backend, controlClient, rootLogger, runtimeIdentity) {
|
|
375
377
|
super();
|
|
376
378
|
this.name = name;
|
|
377
379
|
this.config = config;
|
|
@@ -379,8 +381,14 @@ export class Daemon extends EventEmitter {
|
|
|
379
381
|
this.topicMode = topicMode;
|
|
380
382
|
this.backend = backend;
|
|
381
383
|
this.controlClient = controlClient;
|
|
384
|
+
this.runtimeIdentity = runtimeIdentity;
|
|
382
385
|
if (!rootLogger)
|
|
383
386
|
throw new Error("Daemon requires a shared root logger");
|
|
387
|
+
this.runtimeIdentity ??= {
|
|
388
|
+
kind: "fleet-topic",
|
|
389
|
+
backend: config.backend ?? backend?.binaryName ?? "unknown",
|
|
390
|
+
model: config.model ?? "default",
|
|
391
|
+
};
|
|
384
392
|
this.logger = rootLogger.child({ instance: name }, { level: config.log_level });
|
|
385
393
|
this.tmuxSessionName = getTmuxSession();
|
|
386
394
|
this.messageBus = new MessageBus();
|
|
@@ -612,8 +620,12 @@ export class Daemon extends EventEmitter {
|
|
|
612
620
|
catch { /* non-fatal */ }
|
|
613
621
|
})();
|
|
614
622
|
if (!this.config.lightweight) {
|
|
615
|
-
// 3. Pipe-pane for prompt detection
|
|
623
|
+
// 3. Pipe-pane for prompt detection. Rotate first so a ballooned log from a
|
|
624
|
+
// previous stuck splash (hundreds of MB of ANSI frames) is truncated before
|
|
625
|
+
// we attach — pipe-pane uses `cat >>` on the same inode, so copytruncate
|
|
626
|
+
// keeps the writer attached after size resets.
|
|
616
627
|
const outputLog = join(this.instanceDir, "output.log");
|
|
628
|
+
rotateLogIfNeeded(outputLog);
|
|
617
629
|
await this.tmux.pipeOutput(outputLog).catch(() => { });
|
|
618
630
|
// 4. Transcript monitor
|
|
619
631
|
this.transcriptMonitor = new TranscriptMonitor(this.instanceDir, this.logger);
|
|
@@ -716,6 +728,11 @@ export class Daemon extends EventEmitter {
|
|
|
716
728
|
return;
|
|
717
729
|
}
|
|
718
730
|
if (paneStatus?.alive) {
|
|
731
|
+
// Instance output.log is fed by tmux pipe-pane and was previously never
|
|
732
|
+
// rotated (only fleet.log / daemon.log were). Cap growth every tick.
|
|
733
|
+
if (!this.config.lightweight) {
|
|
734
|
+
rotateLogIfNeeded(join(this.instanceDir, "output.log"));
|
|
735
|
+
}
|
|
719
736
|
scheduleNext();
|
|
720
737
|
return;
|
|
721
738
|
}
|
|
@@ -1755,18 +1772,19 @@ export class Daemon extends EventEmitter {
|
|
|
1755
1772
|
}
|
|
1756
1773
|
/**
|
|
1757
1774
|
* Deliver a single message and drive its status reactions:
|
|
1758
|
-
* ⏳ message_queued — CLI busy; queued
|
|
1775
|
+
* ⏳ message_queued — CLI busy; queued locally or by the backend
|
|
1759
1776
|
* 👀 message_delivered — pasted + Enter sent; agent now has it
|
|
1760
|
-
* ✅ message_confirmed —
|
|
1777
|
+
* ✅ message_confirmed — processing observed, or native queue handoff succeeded
|
|
1761
1778
|
* ❌ message_failed — tmux window gone, paste retries exhausted
|
|
1762
1779
|
* Returns true once the message is in the CLI, false only on real delivery failure.
|
|
1763
1780
|
*
|
|
1764
1781
|
* Bug A (silent message loss): paste failures retry with backoff (window recovery)
|
|
1765
1782
|
* and emit `message_failed` if all attempts fail.
|
|
1766
|
-
* Busy handling (UX):
|
|
1767
|
-
*
|
|
1768
|
-
*
|
|
1769
|
-
*
|
|
1783
|
+
* Busy handling (UX): backends without a native input queue show ⏳ and wait for
|
|
1784
|
+
* idle indefinitely (a genuinely hung CLI is the hang detector's job). Backends
|
|
1785
|
+
* that explicitly support queued input receive one complete paste+Enter transaction
|
|
1786
|
+
* immediately and own the application-level queue themselves. The pasteLock remains
|
|
1787
|
+
* serial in both cases so separate PTY writes can never overlap.
|
|
1770
1788
|
*/
|
|
1771
1789
|
async deliverMessage(formatted, status) {
|
|
1772
1790
|
// Sanitize unclosed code fences — they cause CLI to wait for closure on Enter
|
|
@@ -1776,12 +1794,22 @@ export class Daemon extends EventEmitter {
|
|
|
1776
1794
|
formatted = formatted.replace(/```/g, "");
|
|
1777
1795
|
}
|
|
1778
1796
|
let windowId = this.getWindowId();
|
|
1779
|
-
|
|
1797
|
+
const supportsQueuedInput = this.backend?.supportsQueuedInput?.() === true;
|
|
1798
|
+
let handingOffToNativeQueue = false;
|
|
1799
|
+
// If the CLI is busy, either hand the complete submission to its native input
|
|
1800
|
+
// queue or wait for idle. Native queue support is an explicit backend capability:
|
|
1801
|
+
// normal Enter input has steering/interrupt semantics in several other CLIs.
|
|
1780
1802
|
if (windowId && this.controlClient && !this.controlClient.isIdle(windowId)) {
|
|
1781
1803
|
if (status)
|
|
1782
1804
|
this.emit("message_queued", status);
|
|
1783
|
-
|
|
1784
|
-
|
|
1805
|
+
if (supportsQueuedInput) {
|
|
1806
|
+
handingOffToNativeQueue = true;
|
|
1807
|
+
this.logger.debug("CLI busy — handing message to backend-native input queue");
|
|
1808
|
+
}
|
|
1809
|
+
else {
|
|
1810
|
+
this.logger.debug("CLI busy — queuing message until idle");
|
|
1811
|
+
await this.controlClient.waitUntilIdle(windowId);
|
|
1812
|
+
}
|
|
1785
1813
|
}
|
|
1786
1814
|
// Bug A: paste with backoff. Transient failures are usually a stale window id
|
|
1787
1815
|
// after a crash/respawn — recover by name and retry (max 3 attempts, 2s apart).
|
|
@@ -1807,10 +1835,15 @@ export class Daemon extends EventEmitter {
|
|
|
1807
1835
|
await this.tmux.sendSpecialKey("Enter");
|
|
1808
1836
|
if (status)
|
|
1809
1837
|
this.emit("message_delivered", status); // 👀
|
|
1810
|
-
//
|
|
1811
|
-
//
|
|
1812
|
-
//
|
|
1813
|
-
|
|
1838
|
+
// A busy queue-capable CLI does not necessarily emit output when it accepts
|
|
1839
|
+
// queued input. Treat the successful paste+Enter as the handoff confirmation;
|
|
1840
|
+
// probing for idle→busy would time out and a second bare Enter could mutate
|
|
1841
|
+
// the queue/TUI state. Idle submissions retain the swallowed-Enter safeguard.
|
|
1842
|
+
if (handingOffToNativeQueue) {
|
|
1843
|
+
if (status)
|
|
1844
|
+
this.emit("message_confirmed", status); // ✅ native queue accepted
|
|
1845
|
+
}
|
|
1846
|
+
else if (windowId && this.controlClient) {
|
|
1814
1847
|
let becameBusy = await this.confirmBusyAfterEnter(windowId, enterAt);
|
|
1815
1848
|
if (!becameBusy) {
|
|
1816
1849
|
this.logger.warn("No idle→busy transition after Enter — re-sending Enter once");
|
|
@@ -2124,6 +2157,9 @@ export class Daemon extends EventEmitter {
|
|
|
2124
2157
|
AGEND_SOCKET_PATH: sockPath,
|
|
2125
2158
|
AGEND_INSTANCE_NAME: this.name,
|
|
2126
2159
|
AGEND_WORKING_DIR: this.config.working_directory,
|
|
2160
|
+
AGEND_INSTANCE_KIND: this.runtimeIdentity?.kind ?? "fleet-topic",
|
|
2161
|
+
AGEND_BACKEND: this.runtimeIdentity?.backend ?? this.config.backend ?? this.backend?.binaryName ?? "unknown",
|
|
2162
|
+
AGEND_MODEL: this.runtimeIdentity?.model ?? this.config.model ?? "default",
|
|
2127
2163
|
};
|
|
2128
2164
|
if (this.config.tool_set)
|
|
2129
2165
|
mcpEnv.AGEND_TOOL_SET = this.config.tool_set;
|
|
@@ -2159,6 +2195,7 @@ export class Daemon extends EventEmitter {
|
|
|
2159
2195
|
instructions = buildFleetInstructions({
|
|
2160
2196
|
instanceName: this.name,
|
|
2161
2197
|
workingDirectory: this.config.working_directory,
|
|
2198
|
+
runtimeIdentity: this.runtimeIdentity,
|
|
2162
2199
|
displayName: this.config.display_name,
|
|
2163
2200
|
description: this.config.description,
|
|
2164
2201
|
customPrompt: resolvedCustomPrompt,
|
|
@@ -2171,6 +2208,7 @@ export class Daemon extends EventEmitter {
|
|
|
2171
2208
|
instructions = buildFleetInstructions({
|
|
2172
2209
|
instanceName: this.name,
|
|
2173
2210
|
workingDirectory: this.config.working_directory,
|
|
2211
|
+
runtimeIdentity: this.runtimeIdentity,
|
|
2174
2212
|
displayName: this.config.display_name,
|
|
2175
2213
|
description: this.config.description,
|
|
2176
2214
|
customPrompt: resolvedCustomPrompt,
|
|
@@ -2366,7 +2404,9 @@ export class Daemon extends EventEmitter {
|
|
|
2366
2404
|
this.logger.warn({ err }, "Failed to set remain-on-exit — exit codes will not be captured");
|
|
2367
2405
|
});
|
|
2368
2406
|
if (reuseWindow && !this.config.lightweight) {
|
|
2369
|
-
|
|
2407
|
+
const outputLog = join(this.instanceDir, "output.log");
|
|
2408
|
+
rotateLogIfNeeded(outputLog);
|
|
2409
|
+
await this.tmux.pipeOutput(outputLog).catch(err => {
|
|
2370
2410
|
this.logger.warn({ err }, "Failed to restore pipe-pane after wake");
|
|
2371
2411
|
});
|
|
2372
2412
|
}
|