@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/fleet-manager.js
CHANGED
|
@@ -163,6 +163,10 @@ export class FleetManager {
|
|
|
163
163
|
failoverActive = new Map(); // instance → current failover model
|
|
164
164
|
// IPC reconnect: tracks instances being intentionally stopped (skip reconnect)
|
|
165
165
|
ipcStoppingInstances = new Set();
|
|
166
|
+
/** Coalesce concurrent connection attempts for the same daemon socket. */
|
|
167
|
+
ipcConnectInFlight = new Map();
|
|
168
|
+
/** At most one reconnect/backoff loop may exist per instance. */
|
|
169
|
+
ipcReconnectInFlight = new Map();
|
|
166
170
|
// Adapter restart: prevents re-entrant restart attempts
|
|
167
171
|
adapterRestarting = new Set();
|
|
168
172
|
// Adapter isolation: track state per adapter for retry + visibility
|
|
@@ -651,7 +655,7 @@ export class FleetManager {
|
|
|
651
655
|
await new Promise(resolve => setTimeout(resolve, 250));
|
|
652
656
|
await this.startClassicInstance(instanceName, this.classicChannels.getBackendByInstance(instanceName, this.fleetConfig?.defaults?.backend), this.classicChannels.getPreTaskCommand(channel.channelId, channel.adapterId), this.classicChannels.getModel(channel.channelId, channel.adapterId, this.fleetConfig?.defaults?.model), this.classicChannels.getAutoPauseAfter(channel.channelId, channel.adapterId, this.fleetConfig?.defaults?.auto_pause_after));
|
|
653
657
|
}
|
|
654
|
-
async startInstance(name, config, topicMode) {
|
|
658
|
+
async startInstance(name, config, topicMode, kind = "fleet-topic") {
|
|
655
659
|
if (this.lifecycle.isPaused(name)) {
|
|
656
660
|
this.logger.info({ name }, "Persisted paused instance — skipping startup");
|
|
657
661
|
return;
|
|
@@ -667,7 +671,11 @@ export class FleetManager {
|
|
|
667
671
|
this.ensureGeneralInstructions(config.working_directory, config.backend);
|
|
668
672
|
}
|
|
669
673
|
this.instanceProcessStatus.delete(name);
|
|
670
|
-
await this.lifecycle.start(name, config, topicMode
|
|
674
|
+
await this.lifecycle.start(name, config, topicMode, {
|
|
675
|
+
kind,
|
|
676
|
+
backend: config.backend ?? this.fleetConfig?.defaults?.backend ?? "claude-code",
|
|
677
|
+
model: this.resolveInstanceModel(name).display,
|
|
678
|
+
});
|
|
671
679
|
// Auto-connect IPC — daemon.start() ensures socket is ready before resolving
|
|
672
680
|
await this.connectIpcToInstance(name);
|
|
673
681
|
}
|
|
@@ -978,6 +986,11 @@ export class FleetManager {
|
|
|
978
986
|
// Rotate fleet.log daily too (besides the startup size check above), so a
|
|
979
987
|
// long-running fleet doesn't accumulate an unbounded log.
|
|
980
988
|
rotateLogIfNeeded(join(this.dataDir, "fleet.log"));
|
|
989
|
+
// Instance output.log is pipe-pane (TUI ANSI). Daemon health ticks also
|
|
990
|
+
// rotate it; this is the daily safety net for idle/stopped instances.
|
|
991
|
+
for (const name of Object.keys(this.fleetConfig?.instances ?? {})) {
|
|
992
|
+
rotateLogIfNeeded(join(this.dataDir, "instances", name, "output.log"));
|
|
993
|
+
}
|
|
981
994
|
}, () => {
|
|
982
995
|
const instances = Object.keys(this.fleetConfig?.instances ?? {});
|
|
983
996
|
const costMap = new Map();
|
|
@@ -1931,19 +1944,38 @@ export class FleetManager {
|
|
|
1931
1944
|
this.logger.info({ adapterId, type: channelConfig.type }, "Additional adapter started");
|
|
1932
1945
|
}
|
|
1933
1946
|
/** Connect IPC to a single instance with all handlers */
|
|
1934
|
-
|
|
1947
|
+
connectIpcToInstance(name) {
|
|
1948
|
+
const inFlight = this.ipcConnectInFlight.get(name);
|
|
1949
|
+
if (inFlight)
|
|
1950
|
+
return inFlight;
|
|
1951
|
+
const connection = this.connectIpcToInstanceInternal(name)
|
|
1952
|
+
.finally(() => {
|
|
1953
|
+
if (this.ipcConnectInFlight.get(name) === connection) {
|
|
1954
|
+
this.ipcConnectInFlight.delete(name);
|
|
1955
|
+
}
|
|
1956
|
+
});
|
|
1957
|
+
this.ipcConnectInFlight.set(name, connection);
|
|
1958
|
+
return connection;
|
|
1959
|
+
}
|
|
1960
|
+
async connectIpcToInstanceInternal(name) {
|
|
1935
1961
|
// Close existing client to prevent socket leak on reconnect
|
|
1936
1962
|
const existing = this.instanceIpcClients.get(name);
|
|
1937
1963
|
if (existing) {
|
|
1938
|
-
|
|
1964
|
+
// Remove application listeners before destroying the socket. Even if a
|
|
1965
|
+
// future regression creates two clients, the replaced one cannot keep
|
|
1966
|
+
// handling fleet_outbound messages as an orphan.
|
|
1967
|
+
existing.removeAllListeners();
|
|
1939
1968
|
try {
|
|
1940
|
-
existing.close();
|
|
1969
|
+
await existing.close();
|
|
1941
1970
|
}
|
|
1942
1971
|
catch (err) {
|
|
1943
1972
|
this.logger.debug({ err, name }, "IPC client close failed (likely already closed)");
|
|
1944
1973
|
}
|
|
1945
|
-
|
|
1946
|
-
|
|
1974
|
+
finally {
|
|
1975
|
+
if (this.instanceIpcClients.get(name) === existing) {
|
|
1976
|
+
this.instanceIpcClients.delete(name);
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1947
1979
|
}
|
|
1948
1980
|
const sockPath = join(this.getInstanceDir(name), "channel.sock");
|
|
1949
1981
|
if (!existsSync(sockPath))
|
|
@@ -2021,6 +2053,10 @@ export class FleetManager {
|
|
|
2021
2053
|
}
|
|
2022
2054
|
// Auto-reconnect on disconnect (unless intentionally stopping)
|
|
2023
2055
|
ipc.on("disconnect", () => {
|
|
2056
|
+
// A delayed event from a replaced/stale client must never delete the
|
|
2057
|
+
// current connection or start another reconnect loop.
|
|
2058
|
+
if (this.instanceIpcClients.get(name) !== ipc)
|
|
2059
|
+
return;
|
|
2024
2060
|
this.instanceIpcClients.delete(name);
|
|
2025
2061
|
if (this.ipcStoppingInstances.has(name))
|
|
2026
2062
|
return;
|
|
@@ -2032,7 +2068,20 @@ export class FleetManager {
|
|
|
2032
2068
|
}
|
|
2033
2069
|
}
|
|
2034
2070
|
/** Attempt IPC reconnection with exponential backoff */
|
|
2035
|
-
|
|
2071
|
+
ipcReconnect(name) {
|
|
2072
|
+
const inFlight = this.ipcReconnectInFlight.get(name);
|
|
2073
|
+
if (inFlight)
|
|
2074
|
+
return inFlight;
|
|
2075
|
+
const reconnect = this.runIpcReconnect(name)
|
|
2076
|
+
.finally(() => {
|
|
2077
|
+
if (this.ipcReconnectInFlight.get(name) === reconnect) {
|
|
2078
|
+
this.ipcReconnectInFlight.delete(name);
|
|
2079
|
+
}
|
|
2080
|
+
});
|
|
2081
|
+
this.ipcReconnectInFlight.set(name, reconnect);
|
|
2082
|
+
return reconnect;
|
|
2083
|
+
}
|
|
2084
|
+
async runIpcReconnect(name) {
|
|
2036
2085
|
for (let attempt = 1;; attempt++) {
|
|
2037
2086
|
if (this.ipcStoppingInstances.has(name) || !this.daemons.has(name))
|
|
2038
2087
|
return;
|
|
@@ -4771,7 +4820,7 @@ When users create specialized instances, suggest these configurations:
|
|
|
4771
4820
|
...(preTaskCommand ? { pre_task_command: preTaskCommand } : {}),
|
|
4772
4821
|
};
|
|
4773
4822
|
const topicMode = this.fleetConfig?.channel?.mode === "topic";
|
|
4774
|
-
await this.startInstance(instanceName, config, topicMode);
|
|
4823
|
+
await this.startInstance(instanceName, config, topicMode, "classic");
|
|
4775
4824
|
}
|
|
4776
4825
|
/** Handle /start slash command — register classic channel */
|
|
4777
4826
|
async handleClassicStart(channelId, channelName, userId, guildId, adapterId, backend) {
|