@slock-ai/daemon 0.29.0 → 0.29.1-alpha.0
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/index.js +280 -10
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -6,30 +6,44 @@ import os2 from "os";
|
|
|
6
6
|
import { createRequire } from "module";
|
|
7
7
|
import { execSync as execSync2 } from "child_process";
|
|
8
8
|
import { accessSync } from "fs";
|
|
9
|
+
import { readFile as readFile2, readdir as readdir2, stat as stat2, mkdir as mkdir2, appendFile } from "fs/promises";
|
|
9
10
|
import { fileURLToPath } from "url";
|
|
10
11
|
|
|
11
12
|
// src/connection.ts
|
|
12
13
|
import WebSocket from "ws";
|
|
14
|
+
var systemClock = {
|
|
15
|
+
now: () => Date.now(),
|
|
16
|
+
setTimeout: (fn, ms) => setTimeout(fn, ms),
|
|
17
|
+
clearTimeout: (timer) => clearTimeout(timer)
|
|
18
|
+
};
|
|
19
|
+
var INBOUND_WATCHDOG_MS = 7e4;
|
|
13
20
|
var DaemonConnection = class {
|
|
14
21
|
ws = null;
|
|
15
22
|
options;
|
|
23
|
+
clock;
|
|
16
24
|
reconnectTimer = null;
|
|
17
|
-
|
|
25
|
+
watchdogTimer = null;
|
|
26
|
+
reconnectDelay;
|
|
18
27
|
maxReconnectDelay = 3e4;
|
|
19
28
|
shouldConnect = true;
|
|
20
29
|
reconnectAttempt = 0;
|
|
21
30
|
lastDroppedSendLogAt = 0;
|
|
22
31
|
constructor(options) {
|
|
23
32
|
this.options = options;
|
|
33
|
+
this.clock = options.clock ?? systemClock;
|
|
34
|
+
this.reconnectDelay = options.minReconnectDelayMs ?? 1e3;
|
|
24
35
|
}
|
|
25
36
|
connect() {
|
|
26
37
|
this.shouldConnect = true;
|
|
38
|
+
if (this.reconnectTimer) return;
|
|
39
|
+
if (this.ws && this.ws.readyState !== WebSocket.CLOSED) return;
|
|
27
40
|
this.doConnect();
|
|
28
41
|
}
|
|
29
42
|
disconnect() {
|
|
30
43
|
this.shouldConnect = false;
|
|
44
|
+
this.clearWatchdog();
|
|
31
45
|
if (this.reconnectTimer) {
|
|
32
|
-
clearTimeout(this.reconnectTimer);
|
|
46
|
+
this.clock.clearTimeout(this.reconnectTimer);
|
|
33
47
|
this.reconnectTimer = null;
|
|
34
48
|
}
|
|
35
49
|
if (this.ws) {
|
|
@@ -43,7 +57,7 @@ var DaemonConnection = class {
|
|
|
43
57
|
this.ws.send(JSON.stringify(msg));
|
|
44
58
|
return;
|
|
45
59
|
}
|
|
46
|
-
const now =
|
|
60
|
+
const now = this.clock.now();
|
|
47
61
|
if (now - this.lastDroppedSendLogAt > 5e3) {
|
|
48
62
|
this.lastDroppedSendLogAt = now;
|
|
49
63
|
console.warn(`[Daemon] Dropping outbound message while disconnected: ${msg.type}`);
|
|
@@ -54,16 +68,23 @@ var DaemonConnection = class {
|
|
|
54
68
|
}
|
|
55
69
|
doConnect() {
|
|
56
70
|
if (!this.shouldConnect) return;
|
|
71
|
+
if (this.ws && this.ws.readyState !== WebSocket.CLOSED) return;
|
|
57
72
|
const wsUrl = this.options.serverUrl.replace(/^http/, "ws") + `/daemon/connect?key=${this.options.apiKey}`;
|
|
58
73
|
console.log(`[Daemon] Connecting to ${this.options.serverUrl}...`);
|
|
59
|
-
|
|
60
|
-
this.ws
|
|
74
|
+
const ws = this.options.wsFactory ? this.options.wsFactory(wsUrl) : new WebSocket(wsUrl);
|
|
75
|
+
this.ws = ws;
|
|
76
|
+
ws.on("open", () => {
|
|
77
|
+
if (this.ws !== ws) return;
|
|
78
|
+
if (!this.shouldConnect) return;
|
|
61
79
|
console.log("[Daemon] Connected to server");
|
|
62
80
|
this.reconnectAttempt = 0;
|
|
63
|
-
this.reconnectDelay = 1e3;
|
|
81
|
+
this.reconnectDelay = this.options.minReconnectDelayMs ?? 1e3;
|
|
82
|
+
this.resetWatchdog();
|
|
64
83
|
this.options.onConnect();
|
|
65
84
|
});
|
|
66
|
-
|
|
85
|
+
ws.on("message", (data) => {
|
|
86
|
+
if (this.ws !== ws) return;
|
|
87
|
+
this.resetWatchdog();
|
|
67
88
|
try {
|
|
68
89
|
const msg = JSON.parse(data.toString());
|
|
69
90
|
this.options.onMessage(msg);
|
|
@@ -71,7 +92,10 @@ var DaemonConnection = class {
|
|
|
71
92
|
console.error("[Daemon] Invalid message from server:", err);
|
|
72
93
|
}
|
|
73
94
|
});
|
|
74
|
-
|
|
95
|
+
ws.on("close", (code, reasonBuffer) => {
|
|
96
|
+
if (this.ws !== ws) return;
|
|
97
|
+
this.ws = null;
|
|
98
|
+
this.clearWatchdog();
|
|
75
99
|
const reason = reasonBuffer.toString("utf8");
|
|
76
100
|
console.log(
|
|
77
101
|
`[Daemon] Disconnected from server (code=${code}, reason=${JSON.stringify(reason)}, reconnecting=${this.shouldConnect})`
|
|
@@ -79,7 +103,8 @@ var DaemonConnection = class {
|
|
|
79
103
|
this.options.onDisconnect();
|
|
80
104
|
this.scheduleReconnect();
|
|
81
105
|
});
|
|
82
|
-
|
|
106
|
+
ws.on("error", (err) => {
|
|
107
|
+
if (this.ws !== ws) return;
|
|
83
108
|
console.error("[Daemon] WebSocket error:", err.message);
|
|
84
109
|
});
|
|
85
110
|
}
|
|
@@ -88,12 +113,29 @@ var DaemonConnection = class {
|
|
|
88
113
|
if (this.reconnectTimer) return;
|
|
89
114
|
this.reconnectAttempt += 1;
|
|
90
115
|
console.log(`[Daemon] Reconnecting to server in ${this.reconnectDelay}ms (attempt ${this.reconnectAttempt})`);
|
|
91
|
-
this.reconnectTimer = setTimeout(() => {
|
|
116
|
+
this.reconnectTimer = this.clock.setTimeout(() => {
|
|
92
117
|
this.reconnectTimer = null;
|
|
93
118
|
this.doConnect();
|
|
94
119
|
}, this.reconnectDelay);
|
|
95
120
|
this.reconnectDelay = Math.min(this.reconnectDelay * 2, this.maxReconnectDelay);
|
|
96
121
|
}
|
|
122
|
+
resetWatchdog() {
|
|
123
|
+
this.clearWatchdog();
|
|
124
|
+
const ms = this.options.inboundWatchdogMs ?? INBOUND_WATCHDOG_MS;
|
|
125
|
+
this.watchdogTimer = this.clock.setTimeout(() => {
|
|
126
|
+
console.warn(`[Daemon] No inbound traffic for ${ms / 1e3}s \u2014 forcing reconnect`);
|
|
127
|
+
try {
|
|
128
|
+
this.ws?.terminate();
|
|
129
|
+
} catch {
|
|
130
|
+
}
|
|
131
|
+
}, ms);
|
|
132
|
+
}
|
|
133
|
+
clearWatchdog() {
|
|
134
|
+
if (this.watchdogTimer) {
|
|
135
|
+
this.clock.clearTimeout(this.watchdogTimer);
|
|
136
|
+
this.watchdogTimer = null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
97
139
|
};
|
|
98
140
|
|
|
99
141
|
// src/agentProcessManager.ts
|
|
@@ -1288,6 +1330,19 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1288
1330
|
getRunningAgentIds() {
|
|
1289
1331
|
return [...this.agents.keys()];
|
|
1290
1332
|
}
|
|
1333
|
+
getDataDir() {
|
|
1334
|
+
return this.dataDir;
|
|
1335
|
+
}
|
|
1336
|
+
getAgentSessionId(agentId) {
|
|
1337
|
+
return this.agents.get(agentId)?.sessionId ?? null;
|
|
1338
|
+
}
|
|
1339
|
+
getIdleAgentSessionIds() {
|
|
1340
|
+
const result = [];
|
|
1341
|
+
for (const [agentId, { sessionId }] of this.idleAgentConfigs) {
|
|
1342
|
+
if (sessionId) result.push({ agentId, sessionId });
|
|
1343
|
+
}
|
|
1344
|
+
return result;
|
|
1345
|
+
}
|
|
1291
1346
|
// Machine-level workspace scanning
|
|
1292
1347
|
async scanAllWorkspaces() {
|
|
1293
1348
|
const results = [];
|
|
@@ -1532,6 +1587,11 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1532
1587
|
case "session_init":
|
|
1533
1588
|
if (ap) ap.sessionId = event.sessionId;
|
|
1534
1589
|
this.sendToServer({ type: "agent:session", agentId, sessionId: event.sessionId });
|
|
1590
|
+
writeFile(
|
|
1591
|
+
path3.join(this.dataDir, agentId, "session-meta.json"),
|
|
1592
|
+
JSON.stringify({ sessionId: event.sessionId, updatedAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
1593
|
+
).catch(() => {
|
|
1594
|
+
});
|
|
1535
1595
|
break;
|
|
1536
1596
|
case "thinking": {
|
|
1537
1597
|
const text = event.text.length > MAX_TRAJECTORY_TEXT ? event.text.slice(0, MAX_TRAJECTORY_TEXT) + "\u2026" : event.text;
|
|
@@ -1568,6 +1628,11 @@ Note: While you are busy, you may receive [System notification: ...] messages ab
|
|
|
1568
1628
|
}
|
|
1569
1629
|
if (event.sessionId) {
|
|
1570
1630
|
this.sendToServer({ type: "agent:session", agentId, sessionId: event.sessionId });
|
|
1631
|
+
writeFile(
|
|
1632
|
+
path3.join(this.dataDir, agentId, "session-meta.json"),
|
|
1633
|
+
JSON.stringify({ sessionId: event.sessionId, updatedAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
1634
|
+
).catch(() => {
|
|
1635
|
+
});
|
|
1571
1636
|
}
|
|
1572
1637
|
break;
|
|
1573
1638
|
case "error": {
|
|
@@ -1702,6 +1767,47 @@ var RUNTIMES = [
|
|
|
1702
1767
|
// src/index.ts
|
|
1703
1768
|
var require2 = createRequire(import.meta.url);
|
|
1704
1769
|
var DAEMON_VERSION = require2("../package.json").version;
|
|
1770
|
+
var LOG_DIR = path4.join(os2.homedir(), ".slock", "logs");
|
|
1771
|
+
var LOG_FILE = path4.join(LOG_DIR, "daemon.log");
|
|
1772
|
+
var MAX_LOG_BYTES = 5 * 1024 * 1024;
|
|
1773
|
+
async function initLogFile() {
|
|
1774
|
+
try {
|
|
1775
|
+
await mkdir2(LOG_DIR, { recursive: true });
|
|
1776
|
+
try {
|
|
1777
|
+
const s = await stat2(LOG_FILE);
|
|
1778
|
+
if (s.size > MAX_LOG_BYTES) {
|
|
1779
|
+
const content = await readFile2(LOG_FILE, "utf-8");
|
|
1780
|
+
const trimmed = content.slice(Math.floor(content.length / 2));
|
|
1781
|
+
await appendFile(LOG_FILE, "");
|
|
1782
|
+
const { writeFile: writeFile2 } = await import("fs/promises");
|
|
1783
|
+
await writeFile2(LOG_FILE, trimmed);
|
|
1784
|
+
}
|
|
1785
|
+
} catch {
|
|
1786
|
+
}
|
|
1787
|
+
} catch {
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
function logLine(level, ...args2) {
|
|
1791
|
+
const line = `${(/* @__PURE__ */ new Date()).toISOString()} [${level}] ${args2.map(String).join(" ")}
|
|
1792
|
+
`;
|
|
1793
|
+
appendFile(LOG_FILE, line).catch(() => {
|
|
1794
|
+
});
|
|
1795
|
+
}
|
|
1796
|
+
var _origLog = console.log.bind(console);
|
|
1797
|
+
var _origErr = console.error.bind(console);
|
|
1798
|
+
var _origWarn = console.warn.bind(console);
|
|
1799
|
+
console.log = (...args2) => {
|
|
1800
|
+
_origLog(...args2);
|
|
1801
|
+
logLine("INFO", ...args2);
|
|
1802
|
+
};
|
|
1803
|
+
console.error = (...args2) => {
|
|
1804
|
+
_origErr(...args2);
|
|
1805
|
+
logLine("ERROR", ...args2);
|
|
1806
|
+
};
|
|
1807
|
+
console.warn = (...args2) => {
|
|
1808
|
+
_origWarn(...args2);
|
|
1809
|
+
logLine("WARN", ...args2);
|
|
1810
|
+
};
|
|
1705
1811
|
function formatChannelTarget(msg) {
|
|
1706
1812
|
return msg.message.channel_type === "dm" ? `dm:@${msg.message.channel_name}` : `#${msg.message.channel_name}`;
|
|
1707
1813
|
}
|
|
@@ -1723,6 +1829,8 @@ function summarizeIncomingMessage(msg) {
|
|
|
1723
1829
|
return `(agent=${msg.agentId}, runtime=${msg.runtime || "auto"})`;
|
|
1724
1830
|
case "machine:workspace:delete":
|
|
1725
1831
|
return `(directory=${msg.directoryName})`;
|
|
1832
|
+
case "machine:feedback:collect":
|
|
1833
|
+
return `(reportId=${msg.reportId}, agents=${msg.agents.length})`;
|
|
1726
1834
|
default:
|
|
1727
1835
|
return "";
|
|
1728
1836
|
}
|
|
@@ -1758,6 +1866,126 @@ try {
|
|
|
1758
1866
|
chatBridgePath = path4.resolve(__dirname, "chat-bridge.ts");
|
|
1759
1867
|
}
|
|
1760
1868
|
var connection;
|
|
1869
|
+
async function collectAndUploadAgent(opts) {
|
|
1870
|
+
const { agentId, reportAgentId, uploadUrl, authToken, timeRangeHours, includeSessionFiles, includeDaemonLogs, includeWorkspaceSnapshot, dataDir } = opts;
|
|
1871
|
+
const sinceMs = Date.now() - timeRangeHours * 60 * 60 * 1e3;
|
|
1872
|
+
let bytesUploaded = 0;
|
|
1873
|
+
let anyUploadFailed = false;
|
|
1874
|
+
try {
|
|
1875
|
+
const agentDir = path4.join(dataDir, agentId);
|
|
1876
|
+
let sessionId = opts.sessionId;
|
|
1877
|
+
try {
|
|
1878
|
+
const meta = JSON.parse(await readFile2(path4.join(agentDir, "session-meta.json"), "utf-8"));
|
|
1879
|
+
if (meta.sessionId) sessionId = meta.sessionId;
|
|
1880
|
+
} catch {
|
|
1881
|
+
}
|
|
1882
|
+
const filesToUpload = [];
|
|
1883
|
+
if (includeSessionFiles && sessionId) {
|
|
1884
|
+
const claudeProjectsDir = path4.join(os2.homedir(), ".claude", "projects");
|
|
1885
|
+
try {
|
|
1886
|
+
const projectDirs = await readdir2(claudeProjectsDir, { withFileTypes: true });
|
|
1887
|
+
for (const pd of projectDirs) {
|
|
1888
|
+
if (!pd.isDirectory()) continue;
|
|
1889
|
+
const pdPath = path4.join(claudeProjectsDir, pd.name);
|
|
1890
|
+
const files = await readdir2(pdPath, { withFileTypes: true });
|
|
1891
|
+
for (const f of files) {
|
|
1892
|
+
if (!f.isFile() || !f.name.endsWith(".jsonl")) continue;
|
|
1893
|
+
if (!f.name.startsWith(sessionId)) continue;
|
|
1894
|
+
const filePath = path4.join(pdPath, f.name);
|
|
1895
|
+
const raw = await readFile2(filePath, "utf-8");
|
|
1896
|
+
const filteredLines = raw.split("\n").filter((line) => {
|
|
1897
|
+
if (!line.trim()) return false;
|
|
1898
|
+
try {
|
|
1899
|
+
const obj = JSON.parse(line);
|
|
1900
|
+
if (!obj.timestamp) return true;
|
|
1901
|
+
return new Date(obj.timestamp).getTime() >= sinceMs;
|
|
1902
|
+
} catch {
|
|
1903
|
+
return false;
|
|
1904
|
+
}
|
|
1905
|
+
}).join("\n");
|
|
1906
|
+
if (!filteredLines.trim()) continue;
|
|
1907
|
+
filesToUpload.push({ filename: f.name, data: Buffer.from(filteredLines), kind: "session_jsonl" });
|
|
1908
|
+
}
|
|
1909
|
+
}
|
|
1910
|
+
} catch {
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1913
|
+
if (includeDaemonLogs) {
|
|
1914
|
+
try {
|
|
1915
|
+
const raw = await readFile2(LOG_FILE, "utf-8");
|
|
1916
|
+
const filtered = raw.split("\n").filter((line) => {
|
|
1917
|
+
if (!line.trim()) return false;
|
|
1918
|
+
const ts = line.slice(0, 24);
|
|
1919
|
+
return new Date(ts).getTime() >= sinceMs;
|
|
1920
|
+
}).join("\n");
|
|
1921
|
+
if (filtered.trim()) {
|
|
1922
|
+
filesToUpload.push({ filename: "daemon.log", data: Buffer.from(filtered), kind: "daemon_log" });
|
|
1923
|
+
}
|
|
1924
|
+
} catch {
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
if (includeWorkspaceSnapshot) {
|
|
1928
|
+
try {
|
|
1929
|
+
const agentStat = await stat2(agentDir);
|
|
1930
|
+
if (agentStat.isDirectory()) {
|
|
1931
|
+
const files = await readdir2(agentDir, { withFileTypes: true });
|
|
1932
|
+
for (const f of files) {
|
|
1933
|
+
if (!f.isFile()) continue;
|
|
1934
|
+
if (f.name === "session-meta.json") continue;
|
|
1935
|
+
const filePath = path4.join(agentDir, f.name);
|
|
1936
|
+
const s = await stat2(filePath);
|
|
1937
|
+
if (s.size > 1024 * 1024) continue;
|
|
1938
|
+
const data = await readFile2(filePath);
|
|
1939
|
+
filesToUpload.push({ filename: f.name, data, kind: "runtime_log" });
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
} catch {
|
|
1943
|
+
}
|
|
1944
|
+
}
|
|
1945
|
+
const manifest = {
|
|
1946
|
+
reportAgentId,
|
|
1947
|
+
agentId,
|
|
1948
|
+
sessionId,
|
|
1949
|
+
runtime: opts.runtime,
|
|
1950
|
+
daemonVersion: DAEMON_VERSION,
|
|
1951
|
+
hostname: os2.hostname(),
|
|
1952
|
+
os: `${os2.platform()} ${os2.arch()}`,
|
|
1953
|
+
collectedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1954
|
+
timeRangeHours,
|
|
1955
|
+
includeSessionFiles,
|
|
1956
|
+
includeDaemonLogs,
|
|
1957
|
+
includeWorkspaceSnapshot,
|
|
1958
|
+
artifactCount: filesToUpload.length
|
|
1959
|
+
};
|
|
1960
|
+
filesToUpload.unshift({ filename: "manifest.json", data: Buffer.from(JSON.stringify(manifest, null, 2)), kind: "manifest" });
|
|
1961
|
+
for (const file of filesToUpload) {
|
|
1962
|
+
const formData = new FormData();
|
|
1963
|
+
formData.append("reportAgentId", reportAgentId);
|
|
1964
|
+
formData.append("kind", file.kind);
|
|
1965
|
+
formData.append("filename", file.filename);
|
|
1966
|
+
formData.append("file", new Blob([new Uint8Array(file.data)]), file.filename);
|
|
1967
|
+
const resp = await fetch(uploadUrl, {
|
|
1968
|
+
method: "POST",
|
|
1969
|
+
headers: { Authorization: `Bearer ${authToken}` },
|
|
1970
|
+
body: formData
|
|
1971
|
+
});
|
|
1972
|
+
if (resp.ok) {
|
|
1973
|
+
bytesUploaded += file.data.length;
|
|
1974
|
+
} else {
|
|
1975
|
+
console.warn(`[Feedback] Upload failed for ${file.filename}: ${resp.status}`);
|
|
1976
|
+
anyUploadFailed = true;
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
if (anyUploadFailed) {
|
|
1980
|
+
return { reportAgentId, status: "error", daemonVersion: DAEMON_VERSION, error: "One or more files failed to upload", bytesUploaded };
|
|
1981
|
+
}
|
|
1982
|
+
return { reportAgentId, status: "collected", daemonVersion: DAEMON_VERSION, bytesUploaded };
|
|
1983
|
+
} catch (err) {
|
|
1984
|
+
const error = err instanceof Error ? err.message : String(err);
|
|
1985
|
+
console.error(`[Feedback] Collection failed for agent ${agentId}:`, error);
|
|
1986
|
+
return { reportAgentId, status: "error", daemonVersion: DAEMON_VERSION, error };
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1761
1989
|
var agentManager = new AgentProcessManager(chatBridgePath, (msg) => {
|
|
1762
1990
|
connection.send(msg);
|
|
1763
1991
|
}, apiKey);
|
|
@@ -1837,6 +2065,37 @@ connection = new DaemonConnection({
|
|
|
1837
2065
|
case "ping":
|
|
1838
2066
|
connection.send({ type: "pong" });
|
|
1839
2067
|
break;
|
|
2068
|
+
case "machine:feedback:collect": {
|
|
2069
|
+
const { reportId, agents, timeRangeHours, includeSessionFiles, includeDaemonLogs, includeWorkspaceSnapshot, uploadUrl, authToken } = msg;
|
|
2070
|
+
console.log(`[Daemon] Collecting feedback for report ${reportId} (${agents.length} agents)`);
|
|
2071
|
+
const dataDir = agentManager.getDataDir();
|
|
2072
|
+
Promise.all(agents.map(
|
|
2073
|
+
(agent) => collectAndUploadAgent({
|
|
2074
|
+
agentId: agent.agentId,
|
|
2075
|
+
reportAgentId: agent.reportAgentId,
|
|
2076
|
+
runtime: agent.runtime,
|
|
2077
|
+
sessionId: agent.sessionId,
|
|
2078
|
+
uploadUrl,
|
|
2079
|
+
authToken,
|
|
2080
|
+
timeRangeHours,
|
|
2081
|
+
includeSessionFiles,
|
|
2082
|
+
includeDaemonLogs,
|
|
2083
|
+
includeWorkspaceSnapshot: includeWorkspaceSnapshot ?? false,
|
|
2084
|
+
dataDir
|
|
2085
|
+
})
|
|
2086
|
+
)).then((agentResults) => {
|
|
2087
|
+
connection.send({ type: "machine:feedback:result", reportId, agentResults });
|
|
2088
|
+
}).catch((err) => {
|
|
2089
|
+
console.error(`[Daemon] Feedback collection failed for report ${reportId}:`, err);
|
|
2090
|
+
const agentResults = agents.map((a) => ({
|
|
2091
|
+
reportAgentId: a.reportAgentId,
|
|
2092
|
+
status: "error",
|
|
2093
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2094
|
+
}));
|
|
2095
|
+
connection.send({ type: "machine:feedback:result", reportId, agentResults });
|
|
2096
|
+
});
|
|
2097
|
+
break;
|
|
2098
|
+
}
|
|
1840
2099
|
}
|
|
1841
2100
|
},
|
|
1842
2101
|
onConnect: () => {
|
|
@@ -1851,11 +2110,22 @@ connection = new DaemonConnection({
|
|
|
1851
2110
|
os: `${os2.platform()} ${os2.arch()}`,
|
|
1852
2111
|
daemonVersion: DAEMON_VERSION
|
|
1853
2112
|
});
|
|
2113
|
+
for (const agentId of agentManager.getRunningAgentIds()) {
|
|
2114
|
+
const sessionId = agentManager.getAgentSessionId(agentId);
|
|
2115
|
+
if (sessionId) {
|
|
2116
|
+
connection.send({ type: "agent:session", agentId, sessionId });
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
for (const { agentId, sessionId } of agentManager.getIdleAgentSessionIds()) {
|
|
2120
|
+
connection.send({ type: "agent:session", agentId, sessionId });
|
|
2121
|
+
}
|
|
1854
2122
|
},
|
|
1855
2123
|
onDisconnect: () => {
|
|
1856
2124
|
console.log("[Daemon] Lost connection \u2014 agents continue running locally");
|
|
1857
2125
|
}
|
|
1858
2126
|
});
|
|
2127
|
+
initLogFile().catch(() => {
|
|
2128
|
+
});
|
|
1859
2129
|
console.log("[Slock Daemon] Starting...");
|
|
1860
2130
|
connection.connect();
|
|
1861
2131
|
var shutdown = async () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slock-ai/daemon",
|
|
3
|
-
"version": "0.29.0",
|
|
3
|
+
"version": "0.29.1-alpha.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"slock-daemon": "dist/index.js"
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"dev": "tsx watch src/index.ts",
|
|
33
33
|
"start": "tsx src/index.ts",
|
|
34
34
|
"build": "tsup",
|
|
35
|
-
"test": "node --import tsx --test src/**/*.test.ts",
|
|
35
|
+
"test": "node --import tsx --test --test-force-exit 'src/**/*.test.ts'",
|
|
36
36
|
"typecheck": "tsc --noEmit",
|
|
37
37
|
"release:patch": "npm version patch --no-git-tag-version && cd ../.. && pnpm install --lockfile-only && git add packages/daemon/package.json pnpm-lock.yaml && git commit -m \"chore: bump @slock-ai/daemon to v$(node -p \"require('./packages/daemon/package.json').version\")\" && git tag daemon-v$(node -p \"require('./packages/daemon/package.json').version\") && git push && git push --tags",
|
|
38
38
|
"release:minor": "npm version minor --no-git-tag-version && cd ../.. && pnpm install --lockfile-only && git add packages/daemon/package.json pnpm-lock.yaml && git commit -m \"chore: bump @slock-ai/daemon to v$(node -p \"require('./packages/daemon/package.json').version\")\" && git tag daemon-v$(node -p \"require('./packages/daemon/package.json').version\") && git push && git push --tags",
|