@parall/daemon 1.28.1 → 1.29.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/bundle/manifest.json +10 -10
- package/bundle/parall-claude-agent.js +107 -86
- package/bundle/parall-codex-agent.js +130 -101
- package/bundle/parall-daemon.js +161 -67
- package/bundle/parall-openclaw-agent.js +22 -14
- package/dist/index.js +4 -10
- package/dist/runtimes.d.ts +8 -1
- package/dist/runtimes.d.ts.map +1 -1
- package/dist/runtimes.js +49 -3
- package/dist/supervisor.d.ts +5 -6
- package/dist/supervisor.d.ts.map +1 -1
- package/dist/supervisor.js +41 -2
- package/package.json +7 -5
package/bundle/parall-daemon.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// ts/agent-core/dist/logger.js
|
|
4
|
+
function createLogger(prefix) {
|
|
5
|
+
return {
|
|
6
|
+
info: (msg) => console.log(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
|
|
7
|
+
warn: (msg) => console.warn(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`),
|
|
8
|
+
error: (msg) => console.error(`${(/* @__PURE__ */ new Date()).toISOString()} [${prefix}] ${msg}`)
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
|
|
3
12
|
// ts/sdk/dist/constants.js
|
|
4
13
|
var API_BASE = "/api/v1";
|
|
5
14
|
var WIKI_BASE = "/wiki/v1";
|
|
@@ -46,7 +55,6 @@ var ENDPOINTS = {
|
|
|
46
55
|
CHAT_MESSAGES: (orgId, chatId) => `${API_BASE}/orgs/${orgId}/chats/${chatId}/messages`,
|
|
47
56
|
// Messages (global, by message ID)
|
|
48
57
|
MESSAGE: (id) => `${API_BASE}/messages/${id}`,
|
|
49
|
-
MESSAGE_PATCHES: (id) => `${API_BASE}/messages/${id}/patches`,
|
|
50
58
|
MESSAGE_REPLIES: (id) => `${API_BASE}/messages/${id}/replies`,
|
|
51
59
|
// Upload (org-scoped)
|
|
52
60
|
UPLOAD_PRESIGN: (orgId) => `${API_BASE}/orgs/${orgId}/upload/presign`,
|
|
@@ -73,6 +81,7 @@ var ENDPOINTS = {
|
|
|
73
81
|
AGENT_SESSION: (orgId, agentId, sessionId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions/${sessionId}`,
|
|
74
82
|
AGENT_SESSION_STEPS: (orgId, agentId, sessionId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions/${sessionId}/steps`,
|
|
75
83
|
AGENT_SESSION_STEP: (orgId, agentId, sessionId, stepId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/sessions/${sessionId}/steps/${stepId}`,
|
|
84
|
+
AGENT_STEP_BY_ID: (orgId, stepId) => `${API_BASE}/orgs/${orgId}/agent-steps/${stepId}`,
|
|
76
85
|
AGENT_TASKS: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/tasks`,
|
|
77
86
|
AGENT_RUNTIME_AUTH: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/runtime-auth`,
|
|
78
87
|
AGENT_RUNTIME_AUTH_SESSIONS: (orgId, agentId) => `${API_BASE}/orgs/${orgId}/agents/${agentId}/runtime-auth-sessions`,
|
|
@@ -97,9 +106,12 @@ var ENDPOINTS = {
|
|
|
97
106
|
// Attach/Detach bind an agent to/from a daemon Machine.
|
|
98
107
|
MACHINE_ATTACH_AGENT: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}`,
|
|
99
108
|
MACHINE_DETACH_AGENT: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}`,
|
|
109
|
+
MACHINE_LLM_SOURCE: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/llm-source`,
|
|
100
110
|
MACHINE_RUNTIME_AUTH: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth`,
|
|
101
111
|
MACHINE_KEYS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys`,
|
|
102
112
|
MACHINE_KEY: (orgId, machineId, keyId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys/${keyId}`,
|
|
113
|
+
MACHINE_RUNTIME_AUTH_SESSIONS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth-sessions`,
|
|
114
|
+
MACHINE_RUNTIME_AUTH_SESSION_COMPLETE: (orgId, machineId, sessionId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth-sessions/${sessionId}/complete`,
|
|
103
115
|
// Machine self-control-plane (mck_-scoped). The bearer token implicitly
|
|
104
116
|
// identifies the Machine, so there is no `:mid` URL parameter — these are
|
|
105
117
|
// "self" routes called by the daemon for its own host.
|
|
@@ -367,10 +379,10 @@ var ParallClient = class _ParallClient {
|
|
|
367
379
|
* REFRESH_THRESHOLD_S, refresh it **before** sending the request.
|
|
368
380
|
* No-op when the token is still fresh, missing, or un-parseable.
|
|
369
381
|
*/
|
|
370
|
-
async ensureFreshToken(
|
|
382
|
+
async ensureFreshToken(path5) {
|
|
371
383
|
if (!this.token || !this.getRefreshToken)
|
|
372
384
|
return;
|
|
373
|
-
const pathSuffix =
|
|
385
|
+
const pathSuffix = path5.replace(/^\/api\/v1/, "");
|
|
374
386
|
if (_ParallClient.AUTH_PATHS.has(pathSuffix))
|
|
375
387
|
return;
|
|
376
388
|
const exp = _ParallClient.decodeJwtExp(this.token);
|
|
@@ -402,11 +414,11 @@ var ParallClient = class _ParallClient {
|
|
|
402
414
|
this.refreshPromise = null;
|
|
403
415
|
}
|
|
404
416
|
}
|
|
405
|
-
async request(method,
|
|
417
|
+
async request(method, path5, body, query, retried = false, opts) {
|
|
406
418
|
if (!retried) {
|
|
407
|
-
await this.ensureFreshToken(
|
|
419
|
+
await this.ensureFreshToken(path5);
|
|
408
420
|
}
|
|
409
|
-
let url = `${this.baseUrl}${
|
|
421
|
+
let url = `${this.baseUrl}${path5}`;
|
|
410
422
|
if (query) {
|
|
411
423
|
const params = new URLSearchParams();
|
|
412
424
|
for (const [key, value] of Object.entries(query)) {
|
|
@@ -431,12 +443,12 @@ var ParallClient = class _ParallClient {
|
|
|
431
443
|
throw _ParallClient.normalizeFetchError(err);
|
|
432
444
|
}
|
|
433
445
|
if (res.status === 401) {
|
|
434
|
-
const pathSuffix =
|
|
446
|
+
const pathSuffix = path5.replace(/^\/api\/v1/, "");
|
|
435
447
|
const isAuthPath = _ParallClient.AUTH_PATHS.has(pathSuffix);
|
|
436
448
|
if (!retried && !isAuthPath && this.getRefreshToken) {
|
|
437
449
|
const refreshed = await this.tryRefresh();
|
|
438
450
|
if (refreshed) {
|
|
439
|
-
return this.request(method,
|
|
451
|
+
return this.request(method, path5, body, query, true, opts);
|
|
440
452
|
}
|
|
441
453
|
}
|
|
442
454
|
if (this.onTokenExpired && !isAuthPath) {
|
|
@@ -473,15 +485,15 @@ var ParallClient = class _ParallClient {
|
|
|
473
485
|
* hit the 100 MiB cap, so a longer 5-minute timeout is used so a
|
|
474
486
|
* 50 MiB blob on a slow connection doesn't get chopped at 15 s.
|
|
475
487
|
*/
|
|
476
|
-
async multipartRequest(method,
|
|
488
|
+
async multipartRequest(method, path5, body, retried = false) {
|
|
477
489
|
if (!retried) {
|
|
478
|
-
await this.ensureFreshToken(
|
|
490
|
+
await this.ensureFreshToken(path5);
|
|
479
491
|
}
|
|
480
492
|
const { "Content-Type": _drop, ...headers } = this.buildHeaders();
|
|
481
493
|
void _drop;
|
|
482
494
|
let res;
|
|
483
495
|
try {
|
|
484
|
-
res = await fetch(`${this.baseUrl}${
|
|
496
|
+
res = await fetch(`${this.baseUrl}${path5}`, {
|
|
485
497
|
method,
|
|
486
498
|
headers,
|
|
487
499
|
body,
|
|
@@ -491,12 +503,12 @@ var ParallClient = class _ParallClient {
|
|
|
491
503
|
throw _ParallClient.normalizeFetchError(err);
|
|
492
504
|
}
|
|
493
505
|
if (res.status === 401) {
|
|
494
|
-
const pathSuffix =
|
|
506
|
+
const pathSuffix = path5.replace(/^\/api\/v1/, "");
|
|
495
507
|
const isAuthPath = _ParallClient.AUTH_PATHS.has(pathSuffix);
|
|
496
508
|
if (!retried && !isAuthPath && this.getRefreshToken) {
|
|
497
509
|
const refreshed = await this.tryRefresh();
|
|
498
510
|
if (refreshed) {
|
|
499
|
-
return this.multipartRequest(method,
|
|
511
|
+
return this.multipartRequest(method, path5, body, true);
|
|
500
512
|
}
|
|
501
513
|
}
|
|
502
514
|
if (this.onTokenExpired && !isAuthPath) {
|
|
@@ -740,9 +752,6 @@ var ParallClient = class _ParallClient {
|
|
|
740
752
|
async deleteMessage(id) {
|
|
741
753
|
return this.request("DELETE", ENDPOINTS.MESSAGE(id));
|
|
742
754
|
}
|
|
743
|
-
async patchMessage(id, req) {
|
|
744
|
-
return this.request("POST", ENDPOINTS.MESSAGE_PATCHES(id), req);
|
|
745
|
-
}
|
|
746
755
|
async getMessageReplies(id, params) {
|
|
747
756
|
return this.request("GET", ENDPOINTS.MESSAGE_REPLIES(id), void 0, params);
|
|
748
757
|
}
|
|
@@ -835,8 +844,7 @@ var ParallClient = class _ParallClient {
|
|
|
835
844
|
* @param params.status - Comma-separated status filter (e.g., `'open'`).
|
|
836
845
|
*/
|
|
837
846
|
async getAgentSessions(orgId, agentId, params) {
|
|
838
|
-
|
|
839
|
-
return res.data;
|
|
847
|
+
return this.request("GET", ENDPOINTS.AGENT_SESSIONS(orgId, agentId), void 0, params);
|
|
840
848
|
}
|
|
841
849
|
async getAgentSession(orgId, agentId, sessionId) {
|
|
842
850
|
return this.request("GET", ENDPOINTS.AGENT_SESSION(orgId, agentId, sessionId));
|
|
@@ -848,12 +856,14 @@ var ParallClient = class _ParallClient {
|
|
|
848
856
|
return this.request("POST", ENDPOINTS.AGENT_SESSION_STEPS(orgId, agentId, sessionId), req);
|
|
849
857
|
}
|
|
850
858
|
async getAgentSessionSteps(orgId, agentId, sessionId, params) {
|
|
851
|
-
|
|
852
|
-
return res.data;
|
|
859
|
+
return this.request("GET", ENDPOINTS.AGENT_SESSION_STEPS(orgId, agentId, sessionId), void 0, params);
|
|
853
860
|
}
|
|
854
861
|
async getAgentSessionStep(orgId, agentId, sessionId, stepId) {
|
|
855
862
|
return this.request("GET", ENDPOINTS.AGENT_SESSION_STEP(orgId, agentId, sessionId, stepId));
|
|
856
863
|
}
|
|
864
|
+
async getAgentStepById(orgId, stepId) {
|
|
865
|
+
return this.request("GET", ENDPOINTS.AGENT_STEP_BY_ID(orgId, stepId));
|
|
866
|
+
}
|
|
857
867
|
// ---- Agent runtime auth (hosted Claude OAuth) ----
|
|
858
868
|
async getAgentRuntimeAuth(orgId, agentId) {
|
|
859
869
|
return this.request("GET", ENDPOINTS.AGENT_RUNTIME_AUTH(orgId, agentId));
|
|
@@ -950,10 +960,22 @@ var ParallClient = class _ParallClient {
|
|
|
950
960
|
async detachAgent(orgId, machineId, agentId) {
|
|
951
961
|
return this.request("DELETE", ENDPOINTS.MACHINE_DETACH_AGENT(orgId, machineId, agentId));
|
|
952
962
|
}
|
|
963
|
+
async patchMachineLLMSource(orgId, machineId, llmSource2) {
|
|
964
|
+
return this.request("PATCH", ENDPOINTS.MACHINE_LLM_SOURCE(orgId, machineId), { llm_source: llmSource2 });
|
|
965
|
+
}
|
|
953
966
|
/** Get machine-level runtime auth state. */
|
|
954
967
|
async getMachineRuntimeAuth(orgId, machineId) {
|
|
955
968
|
return this.request("GET", ENDPOINTS.MACHINE_RUNTIME_AUTH(orgId, machineId));
|
|
956
969
|
}
|
|
970
|
+
async startMachineRuntimeAuthSession(orgId, machineId, req = {}) {
|
|
971
|
+
return this.request("POST", ENDPOINTS.MACHINE_RUNTIME_AUTH_SESSIONS(orgId, machineId), req);
|
|
972
|
+
}
|
|
973
|
+
async completeMachineRuntimeAuthSession(orgId, machineId, sessionId, req) {
|
|
974
|
+
return this.request("POST", ENDPOINTS.MACHINE_RUNTIME_AUTH_SESSION_COMPLETE(orgId, machineId, sessionId), req);
|
|
975
|
+
}
|
|
976
|
+
async disconnectMachineRuntimeAuth(orgId, machineId) {
|
|
977
|
+
return this.request("DELETE", ENDPOINTS.MACHINE_RUNTIME_AUTH(orgId, machineId));
|
|
978
|
+
}
|
|
957
979
|
// ---- Machine self-control-plane (mck_-scoped) ----
|
|
958
980
|
//
|
|
959
981
|
// The four methods below are intended to be called from a daemon-mode
|
|
@@ -1334,8 +1356,8 @@ var ParallClient = class _ParallClient {
|
|
|
1334
1356
|
async deleteWikiPathScope(orgId, wikiId, scopeId) {
|
|
1335
1357
|
await this.request("DELETE", ENDPOINTS.WIKI_PATH_SCOPE(orgId, wikiId, scopeId));
|
|
1336
1358
|
}
|
|
1337
|
-
async getWikiAccessStatus(orgId, wikiId,
|
|
1338
|
-
return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0,
|
|
1359
|
+
async getWikiAccessStatus(orgId, wikiId, path5) {
|
|
1360
|
+
return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path5 ? { path: path5 } : void 0);
|
|
1339
1361
|
}
|
|
1340
1362
|
async createWikiAccessRequest(orgId, wikiId, data) {
|
|
1341
1363
|
await this.request("POST", ENDPOINTS.WIKI_ACCESS_REQUESTS(orgId, wikiId), data);
|
|
@@ -1344,11 +1366,11 @@ var ParallClient = class _ParallClient {
|
|
|
1344
1366
|
async getWikiCommits(orgId, wikiId, params) {
|
|
1345
1367
|
return this.request("GET", ENDPOINTS.WIKI_COMMITS(orgId, wikiId), void 0, params);
|
|
1346
1368
|
}
|
|
1347
|
-
async getWikiFileCommits(orgId, wikiId,
|
|
1348
|
-
return this.request("GET", ENDPOINTS.WIKI_FILE_COMMITS(orgId, wikiId), void 0, { path:
|
|
1369
|
+
async getWikiFileCommits(orgId, wikiId, path5, params) {
|
|
1370
|
+
return this.request("GET", ENDPOINTS.WIKI_FILE_COMMITS(orgId, wikiId), void 0, { path: path5, ...params });
|
|
1349
1371
|
}
|
|
1350
|
-
async getWikiBlame(orgId, wikiId,
|
|
1351
|
-
return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path:
|
|
1372
|
+
async getWikiBlame(orgId, wikiId, path5, ref) {
|
|
1373
|
+
return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path5, ref });
|
|
1352
1374
|
}
|
|
1353
1375
|
// ---- Wiki Operations (audit log) ----
|
|
1354
1376
|
async getWikiOperations(orgId, wikiId, params) {
|
|
@@ -1917,13 +1939,31 @@ function resolveWsUrl(apiUrl, explicitWsUrl) {
|
|
|
1917
1939
|
// ts/daemon/dist/supervisor.js
|
|
1918
1940
|
import { spawn } from "node:child_process";
|
|
1919
1941
|
import * as fs2 from "node:fs";
|
|
1920
|
-
import * as
|
|
1942
|
+
import * as path3 from "node:path";
|
|
1921
1943
|
|
|
1922
1944
|
// ts/daemon/dist/runtimes.js
|
|
1945
|
+
import * as path2 from "node:path";
|
|
1946
|
+
function llmSource(pc) {
|
|
1947
|
+
if (pc?.llm_source)
|
|
1948
|
+
return pc.llm_source;
|
|
1949
|
+
if (pc?.openai_api_key || pc?.openai_base_url || pc?.anthropic_auth_token || pc?.anthropic_base_url) {
|
|
1950
|
+
return "custom";
|
|
1951
|
+
}
|
|
1952
|
+
return "parall";
|
|
1953
|
+
}
|
|
1954
|
+
function clearAllProviderCreds(env) {
|
|
1955
|
+
delete env.ANTHROPIC_AUTH_TOKEN;
|
|
1956
|
+
delete env.ANTHROPIC_BASE_URL;
|
|
1957
|
+
delete env.ANTHROPIC_API_KEY;
|
|
1958
|
+
delete env.OPENAI_API_KEY;
|
|
1959
|
+
delete env.OPENAI_BASE_URL;
|
|
1960
|
+
delete env.PRLL_CLAUDE_ALLOW_API_KEY;
|
|
1961
|
+
}
|
|
1923
1962
|
var claudeCodeAdapter = {
|
|
1924
1963
|
bin: "parall-claude-agent",
|
|
1925
|
-
buildEnv(baseEnv, agentId, orgId, apiKey, dirs) {
|
|
1964
|
+
buildEnv(baseEnv, agentId, orgId, apiKey, dirs, pc) {
|
|
1926
1965
|
const env = { ...baseEnv };
|
|
1966
|
+
clearAllProviderCreds(env);
|
|
1927
1967
|
env.PRLL_API_KEY = apiKey;
|
|
1928
1968
|
env.PRLL_ORG_ID = orgId;
|
|
1929
1969
|
env.AGENT_ID = agentId;
|
|
@@ -1931,8 +1971,18 @@ var claudeCodeAdapter = {
|
|
|
1931
1971
|
env.PRLL_CLAUDE_HOME = dirs.claudeHome;
|
|
1932
1972
|
env.PRLL_CLAUDE_STATE_DIR = dirs.stateDir;
|
|
1933
1973
|
env.PRLL_CLAUDE_WORKSPACE_DIR = dirs.workspaceDir;
|
|
1934
|
-
|
|
1974
|
+
const source = llmSource(pc);
|
|
1975
|
+
if (source === "parall") {
|
|
1935
1976
|
env.ANTHROPIC_AUTH_TOKEN = apiKey;
|
|
1977
|
+
env.ANTHROPIC_BASE_URL = `${baseEnv.PRLL_API_URL}/api/llm`;
|
|
1978
|
+
env.PRLL_CLAUDE_ALLOW_API_KEY = "1";
|
|
1979
|
+
} else if (source === "custom") {
|
|
1980
|
+
if (pc?.anthropic_auth_token) {
|
|
1981
|
+
env.ANTHROPIC_AUTH_TOKEN = pc.anthropic_auth_token;
|
|
1982
|
+
env.PRLL_CLAUDE_ALLOW_API_KEY = "1";
|
|
1983
|
+
}
|
|
1984
|
+
if (pc?.anthropic_base_url)
|
|
1985
|
+
env.ANTHROPIC_BASE_URL = pc.anthropic_base_url;
|
|
1936
1986
|
}
|
|
1937
1987
|
delete env.PRLL_DAEMON_MODE;
|
|
1938
1988
|
return env;
|
|
@@ -1940,14 +1990,26 @@ var claudeCodeAdapter = {
|
|
|
1940
1990
|
};
|
|
1941
1991
|
var codexAdapter = {
|
|
1942
1992
|
bin: "parall-codex-agent",
|
|
1943
|
-
buildEnv(baseEnv, agentId, orgId, apiKey, dirs) {
|
|
1993
|
+
buildEnv(baseEnv, agentId, orgId, apiKey, dirs, pc) {
|
|
1944
1994
|
const env = { ...baseEnv };
|
|
1995
|
+
clearAllProviderCreds(env);
|
|
1945
1996
|
env.PRLL_API_KEY = apiKey;
|
|
1946
1997
|
env.PRLL_ORG_ID = orgId;
|
|
1947
1998
|
env.AGENT_ID = agentId;
|
|
1948
1999
|
env.PRLL_AGENT_ID = agentId;
|
|
1949
2000
|
env.PRLL_CODEX_STATE_DIR = dirs.stateDir;
|
|
1950
2001
|
env.PRLL_CODEX_WORKSPACE_DIR = dirs.workspaceDir;
|
|
2002
|
+
env.PRLL_CODEX_HOME = path2.join(dirs.stateDir, ".codex");
|
|
2003
|
+
const source = llmSource(pc);
|
|
2004
|
+
if (source === "parall") {
|
|
2005
|
+
env.OPENAI_API_KEY = apiKey;
|
|
2006
|
+
env.OPENAI_BASE_URL = `${baseEnv.PRLL_API_URL}/api/llm/v1`;
|
|
2007
|
+
} else if (source === "custom") {
|
|
2008
|
+
if (pc?.openai_api_key)
|
|
2009
|
+
env.OPENAI_API_KEY = pc.openai_api_key;
|
|
2010
|
+
if (pc?.openai_base_url)
|
|
2011
|
+
env.OPENAI_BASE_URL = pc.openai_base_url;
|
|
2012
|
+
}
|
|
1951
2013
|
delete env.PRLL_DAEMON_MODE;
|
|
1952
2014
|
return env;
|
|
1953
2015
|
}
|
|
@@ -1970,6 +2032,7 @@ var openclawAdapter = {
|
|
|
1970
2032
|
bin: "parall-openclaw-agent",
|
|
1971
2033
|
buildEnv(baseEnv, agentId, orgId, apiKey, dirs) {
|
|
1972
2034
|
const env = { ...baseEnv };
|
|
2035
|
+
clearAllProviderCreds(env);
|
|
1973
2036
|
env.PRLL_API_KEY = apiKey;
|
|
1974
2037
|
env.PRLL_ORG_ID = orgId;
|
|
1975
2038
|
env.AGENT_ID = agentId;
|
|
@@ -2024,11 +2087,12 @@ var DaemonSupervisor = class {
|
|
|
2024
2087
|
ws = null;
|
|
2025
2088
|
running = false;
|
|
2026
2089
|
machineOrgId = null;
|
|
2090
|
+
machineLlmSource = "parall";
|
|
2027
2091
|
stopResolve = null;
|
|
2028
|
-
constructor(config, client,
|
|
2092
|
+
constructor(config, client, log2) {
|
|
2029
2093
|
this.config = config;
|
|
2030
2094
|
this.client = client;
|
|
2031
|
-
this.log =
|
|
2095
|
+
this.log = log2;
|
|
2032
2096
|
}
|
|
2033
2097
|
/** Start the supervisor. Returns a promise that resolves on `stop()`. */
|
|
2034
2098
|
async run(signal) {
|
|
@@ -2059,7 +2123,10 @@ var DaemonSupervisor = class {
|
|
|
2059
2123
|
});
|
|
2060
2124
|
this.ws.on("machine.hello", (_data) => {
|
|
2061
2125
|
this.log.info("machine WS connected (machine.hello)");
|
|
2062
|
-
void
|
|
2126
|
+
void (async () => {
|
|
2127
|
+
await this.refreshMachineConfig();
|
|
2128
|
+
await this.fullReconcile();
|
|
2129
|
+
})();
|
|
2063
2130
|
});
|
|
2064
2131
|
this.ws.on("machine.agent.attached", (data) => {
|
|
2065
2132
|
this.log.info(`WS: agent ${data.agent_id} attached`);
|
|
@@ -2069,6 +2136,14 @@ var DaemonSupervisor = class {
|
|
|
2069
2136
|
this.log.info(`WS: agent ${data.agent_id} detached`);
|
|
2070
2137
|
void this.handleAgentDetached(data.agent_id);
|
|
2071
2138
|
});
|
|
2139
|
+
this.ws.on("machine.config.updated", (data) => {
|
|
2140
|
+
const newSource = data.llm_source ?? "parall";
|
|
2141
|
+
if (newSource !== this.machineLlmSource) {
|
|
2142
|
+
this.log.info(`WS: llm_source changed ${this.machineLlmSource} \u2192 ${newSource}, respawning all agents`);
|
|
2143
|
+
this.machineLlmSource = newSource;
|
|
2144
|
+
void this.respawnAllChildren();
|
|
2145
|
+
}
|
|
2146
|
+
});
|
|
2072
2147
|
this.ws.on("machine.stop", (data) => {
|
|
2073
2148
|
this.log.info(`WS: machine.stop received (reason=${data.reason ?? "none"})`);
|
|
2074
2149
|
void this.stop();
|
|
@@ -2117,6 +2192,7 @@ var DaemonSupervisor = class {
|
|
|
2117
2192
|
try {
|
|
2118
2193
|
const machine = await this.client.getMachineSelf();
|
|
2119
2194
|
this.machineOrgId = machine.org_id;
|
|
2195
|
+
this.machineLlmSource = machine.llm_source ?? "parall";
|
|
2120
2196
|
this.log.info(`daemon online \u2014 machine_id=${machine.id} org=${machine.org_id} label=${machine.label}`);
|
|
2121
2197
|
return true;
|
|
2122
2198
|
} catch (err) {
|
|
@@ -2194,12 +2270,12 @@ var DaemonSupervisor = class {
|
|
|
2194
2270
|
*/
|
|
2195
2271
|
migrateFlatLayout() {
|
|
2196
2272
|
const root = this.config.rootStateDir;
|
|
2197
|
-
const agentsDir =
|
|
2198
|
-
const flatWorkspace =
|
|
2273
|
+
const agentsDir = path3.join(root, "agents");
|
|
2274
|
+
const flatWorkspace = path3.join(root, "workspace");
|
|
2199
2275
|
if (!fs2.existsSync(flatWorkspace) || fs2.existsSync(agentsDir))
|
|
2200
2276
|
return;
|
|
2201
2277
|
let ownerAgentId;
|
|
2202
|
-
const sessionsDir =
|
|
2278
|
+
const sessionsDir = path3.join(root, "sessions");
|
|
2203
2279
|
if (fs2.existsSync(sessionsDir)) {
|
|
2204
2280
|
try {
|
|
2205
2281
|
for (const file of fs2.readdirSync(sessionsDir)) {
|
|
@@ -2216,13 +2292,13 @@ var DaemonSupervisor = class {
|
|
|
2216
2292
|
}
|
|
2217
2293
|
}
|
|
2218
2294
|
const targetId = ownerAgentId ?? "_orphan";
|
|
2219
|
-
const targetDir =
|
|
2295
|
+
const targetDir = path3.join(agentsDir, targetId);
|
|
2220
2296
|
try {
|
|
2221
2297
|
fs2.mkdirSync(targetDir, { recursive: true });
|
|
2222
2298
|
for (const sub of ["workspace", "sessions", "dispatch-context"]) {
|
|
2223
|
-
const src =
|
|
2299
|
+
const src = path3.join(root, sub);
|
|
2224
2300
|
if (fs2.existsSync(src)) {
|
|
2225
|
-
fs2.renameSync(src,
|
|
2301
|
+
fs2.renameSync(src, path3.join(targetDir, sub));
|
|
2226
2302
|
}
|
|
2227
2303
|
}
|
|
2228
2304
|
this.log.info(`migrated legacy flat state \u2192 agents/${targetId}/`);
|
|
@@ -2271,6 +2347,30 @@ var DaemonSupervisor = class {
|
|
|
2271
2347
|
this.children.delete(agentId);
|
|
2272
2348
|
}
|
|
2273
2349
|
// ---- Spawn / restart ----
|
|
2350
|
+
async refreshMachineConfig() {
|
|
2351
|
+
try {
|
|
2352
|
+
const machine = await this.client.getMachineSelf();
|
|
2353
|
+
const newSource = machine.llm_source ?? "parall";
|
|
2354
|
+
if (newSource !== this.machineLlmSource) {
|
|
2355
|
+
this.log.info(`machine config refreshed: llm_source ${this.machineLlmSource} \u2192 ${newSource}`);
|
|
2356
|
+
this.machineLlmSource = newSource;
|
|
2357
|
+
await this.respawnAllChildren();
|
|
2358
|
+
}
|
|
2359
|
+
} catch (err) {
|
|
2360
|
+
this.log.warn(`refreshMachineConfig failed: ${String(err)}`);
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
async respawnAllChildren() {
|
|
2364
|
+
const states = [...this.children.values()];
|
|
2365
|
+
for (const state of states) {
|
|
2366
|
+
await this.terminateChild(state);
|
|
2367
|
+
}
|
|
2368
|
+
for (const state of states) {
|
|
2369
|
+
if (!state.shuttingDown && this.running) {
|
|
2370
|
+
await this.restartChildNow(state, "llm_source changed");
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
}
|
|
2274
2374
|
async restartChildNow(state, reason) {
|
|
2275
2375
|
if (!this.running || state.shuttingDown || state.child || state.restartTimer) {
|
|
2276
2376
|
return;
|
|
@@ -2315,6 +2415,7 @@ var DaemonSupervisor = class {
|
|
|
2315
2415
|
runtimeType,
|
|
2316
2416
|
workspacePath: workspaceDir,
|
|
2317
2417
|
claudeHome,
|
|
2418
|
+
providerConfig: attached.provider_config ?? { llm_source: this.machineLlmSource },
|
|
2318
2419
|
child: null,
|
|
2319
2420
|
credential,
|
|
2320
2421
|
restartAttempts: 0,
|
|
@@ -2338,7 +2439,7 @@ var DaemonSupervisor = class {
|
|
|
2338
2439
|
workspaceDir: state.workspacePath,
|
|
2339
2440
|
claudeHome: state.claudeHome
|
|
2340
2441
|
};
|
|
2341
|
-
const env = adapter.buildEnv({ ...process.env, PRLL_API_URL: this.config.apiUrl }, state.agentId, state.orgId, state.credential.api_key, dirs);
|
|
2442
|
+
const env = adapter.buildEnv({ ...process.env, PRLL_API_URL: this.config.apiUrl }, state.agentId, state.orgId, state.credential.api_key, dirs, state.providerConfig);
|
|
2342
2443
|
this.log.info(`spawning agent ${state.agentId} runtime=${state.runtimeType} bin=${adapter.bin} (attempt ${state.restartAttempts + 1})`);
|
|
2343
2444
|
const child = spawn(adapter.bin, [], {
|
|
2344
2445
|
env,
|
|
@@ -2409,16 +2510,16 @@ var DaemonSupervisor = class {
|
|
|
2409
2510
|
});
|
|
2410
2511
|
}
|
|
2411
2512
|
ensureSharedCredentialLink(agentClaudeHome, agentId) {
|
|
2412
|
-
const sharedCredentials =
|
|
2513
|
+
const sharedCredentials = path3.resolve(sharedClaudeCredentialsFileFor(this.config.rootClaudeHome));
|
|
2413
2514
|
const agentCredentials = agentClaudeCredentialsFileFor(agentClaudeHome);
|
|
2414
|
-
const agentCredentialsDir =
|
|
2415
|
-
fs2.mkdirSync(
|
|
2515
|
+
const agentCredentialsDir = path3.dirname(agentCredentials);
|
|
2516
|
+
fs2.mkdirSync(path3.dirname(sharedCredentials), { recursive: true });
|
|
2416
2517
|
fs2.mkdirSync(agentCredentialsDir, { recursive: true });
|
|
2417
2518
|
try {
|
|
2418
2519
|
const existing = fs2.lstatSync(agentCredentials);
|
|
2419
2520
|
if (existing.isSymbolicLink()) {
|
|
2420
2521
|
const currentTarget = fs2.readlinkSync(agentCredentials);
|
|
2421
|
-
if (
|
|
2522
|
+
if (path3.resolve(agentCredentialsDir, currentTarget) === sharedCredentials) {
|
|
2422
2523
|
return;
|
|
2423
2524
|
}
|
|
2424
2525
|
fs2.unlinkSync(agentCredentials);
|
|
@@ -2439,7 +2540,7 @@ var DaemonSupervisor = class {
|
|
|
2439
2540
|
|
|
2440
2541
|
// ts/daemon/dist/cli.js
|
|
2441
2542
|
import * as fs3 from "node:fs";
|
|
2442
|
-
import * as
|
|
2543
|
+
import * as path4 from "node:path";
|
|
2443
2544
|
import * as os2 from "node:os";
|
|
2444
2545
|
import * as readline from "node:readline";
|
|
2445
2546
|
import { spawn as spawn2, execSync } from "node:child_process";
|
|
@@ -2474,10 +2575,10 @@ function isLinux() {
|
|
|
2474
2575
|
}
|
|
2475
2576
|
var PLIST_LABEL = "com.parall.daemon";
|
|
2476
2577
|
function plistPath() {
|
|
2477
|
-
return
|
|
2578
|
+
return path4.join(os2.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
|
|
2478
2579
|
}
|
|
2479
2580
|
function systemdUnitPath() {
|
|
2480
|
-
return
|
|
2581
|
+
return path4.join(os2.homedir(), ".config", "systemd", "user", "parall-daemon.service");
|
|
2481
2582
|
}
|
|
2482
2583
|
function getDaemonBin() {
|
|
2483
2584
|
try {
|
|
@@ -2487,7 +2588,7 @@ function getDaemonBin() {
|
|
|
2487
2588
|
}
|
|
2488
2589
|
}
|
|
2489
2590
|
function generatePlist(daemonBin) {
|
|
2490
|
-
const logPath =
|
|
2591
|
+
const logPath = path4.join(os2.homedir(), "Library", "Logs", "parall-daemon.log");
|
|
2491
2592
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
2492
2593
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
2493
2594
|
<plist version="1.0">
|
|
@@ -2534,14 +2635,14 @@ function installService() {
|
|
|
2534
2635
|
}
|
|
2535
2636
|
const bin = getDaemonBin();
|
|
2536
2637
|
if (isMacOS()) {
|
|
2537
|
-
const dir =
|
|
2638
|
+
const dir = path4.dirname(plistPath());
|
|
2538
2639
|
fs3.mkdirSync(dir, { recursive: true });
|
|
2539
2640
|
fs3.writeFileSync(plistPath(), generatePlist(bin));
|
|
2540
2641
|
execSync(`launchctl bootout gui/$(id -u) ${plistPath()} 2>/dev/null || true`);
|
|
2541
2642
|
execSync(`launchctl bootstrap gui/$(id -u) ${plistPath()}`);
|
|
2542
2643
|
console.log(`launchd agent installed: ${plistPath()}`);
|
|
2543
2644
|
} else if (isLinux()) {
|
|
2544
|
-
const dir =
|
|
2645
|
+
const dir = path4.dirname(systemdUnitPath());
|
|
2545
2646
|
fs3.mkdirSync(dir, { recursive: true });
|
|
2546
2647
|
fs3.writeFileSync(systemdUnitPath(), generateSystemdUnit(bin));
|
|
2547
2648
|
execSync("systemctl --user daemon-reload");
|
|
@@ -2610,7 +2711,7 @@ function cmdLogs(lines) {
|
|
|
2610
2711
|
child2.on("exit", (code) => process.exit(code ?? 0));
|
|
2611
2712
|
return;
|
|
2612
2713
|
}
|
|
2613
|
-
const logPath =
|
|
2714
|
+
const logPath = path4.join(os2.homedir(), "Library", "Logs", "parall-daemon.log");
|
|
2614
2715
|
if (!fs3.existsSync(logPath)) {
|
|
2615
2716
|
console.log("No log file found at", logPath);
|
|
2616
2717
|
return;
|
|
@@ -2704,41 +2805,35 @@ async function runCLI(args) {
|
|
|
2704
2805
|
}
|
|
2705
2806
|
|
|
2706
2807
|
// ts/daemon/dist/index.js
|
|
2707
|
-
|
|
2708
|
-
return {
|
|
2709
|
-
info: (msg) => console.log(`[${prefix}] ${msg}`),
|
|
2710
|
-
warn: (msg) => console.warn(`[${prefix}] ${msg}`),
|
|
2711
|
-
error: (msg) => console.error(`[${prefix}] ${msg}`)
|
|
2712
|
-
};
|
|
2713
|
-
}
|
|
2808
|
+
var log = createLogger("daemon");
|
|
2714
2809
|
function formatError(reason) {
|
|
2715
2810
|
if (reason instanceof Error) {
|
|
2716
2811
|
return reason.stack ?? reason.message;
|
|
2717
2812
|
}
|
|
2718
2813
|
return String(reason);
|
|
2719
2814
|
}
|
|
2720
|
-
async function runForever(config, client,
|
|
2815
|
+
async function runForever(config, client, log2, signal) {
|
|
2721
2816
|
let attempt = 0;
|
|
2722
2817
|
while (!signal.aborted) {
|
|
2723
|
-
const supervisor = new DaemonSupervisor(config, client,
|
|
2818
|
+
const supervisor = new DaemonSupervisor(config, client, log2);
|
|
2724
2819
|
try {
|
|
2725
2820
|
await supervisor.run(signal);
|
|
2726
2821
|
await supervisor.stop();
|
|
2727
2822
|
return;
|
|
2728
2823
|
} catch (err) {
|
|
2729
|
-
|
|
2824
|
+
log2.error(`supervisor crashed: ${String(err)}`);
|
|
2730
2825
|
try {
|
|
2731
2826
|
await supervisor.stop();
|
|
2732
2827
|
} catch (stopErr) {
|
|
2733
|
-
|
|
2828
|
+
log2.warn(`supervisor.stop() after crash threw: ${String(stopErr)}`);
|
|
2734
2829
|
}
|
|
2735
2830
|
if (config.supervisorRestartBackoffMs === 0) {
|
|
2736
|
-
|
|
2831
|
+
log2.error("supervisor keepalive disabled (PRLL_DAEMON_SUPERVISOR_RESTART_BACKOFF_MS=0) \u2014 exiting");
|
|
2737
2832
|
throw err;
|
|
2738
2833
|
}
|
|
2739
2834
|
const delay = Math.min(config.supervisorRestartBackoffMs * Math.pow(2, attempt), config.supervisorRestartBackoffMaxMs);
|
|
2740
2835
|
attempt += 1;
|
|
2741
|
-
|
|
2836
|
+
log2.warn(`restarting supervisor in ${delay}ms (attempt ${attempt})`);
|
|
2742
2837
|
const slept = await sleepCancellable(delay, signal);
|
|
2743
2838
|
if (!slept)
|
|
2744
2839
|
return;
|
|
@@ -2747,7 +2842,6 @@ async function runForever(config, client, log, signal) {
|
|
|
2747
2842
|
}
|
|
2748
2843
|
async function main() {
|
|
2749
2844
|
const config = resolveClaudeDaemonConfig(process.env);
|
|
2750
|
-
const log = createLogger("daemon");
|
|
2751
2845
|
log.info(`boot: api=${config.apiUrl} pollMs=${config.pollIntervalMs} heartbeatMs=${config.heartbeatIntervalMs} agentBin=${config.agentBin}`);
|
|
2752
2846
|
log.info(`keepalive: bootstrapBackoffMs=${config.bootstrapBackoffMs} supervisorRestartBackoffMs=${config.supervisorRestartBackoffMs}`);
|
|
2753
2847
|
const client = new ParallClient({
|
|
@@ -2777,10 +2871,10 @@ runCLI(cliArgs).then((result) => {
|
|
|
2777
2871
|
if (result === "handled")
|
|
2778
2872
|
return;
|
|
2779
2873
|
main().catch((err) => {
|
|
2780
|
-
|
|
2874
|
+
log.error(`fatal: ${formatError(err)}`);
|
|
2781
2875
|
process.exitCode = 1;
|
|
2782
2876
|
});
|
|
2783
2877
|
}).catch((err) => {
|
|
2784
|
-
|
|
2878
|
+
log.error(`fatal: ${formatError(err)}`);
|
|
2785
2879
|
process.exitCode = 1;
|
|
2786
2880
|
});
|
|
@@ -4,6 +4,22 @@
|
|
|
4
4
|
import { execFileSync, spawn } from "node:child_process";
|
|
5
5
|
import * as fs from "node:fs";
|
|
6
6
|
import * as path from "node:path";
|
|
7
|
+
function ts() {
|
|
8
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
9
|
+
}
|
|
10
|
+
var log = {
|
|
11
|
+
info: (msg) => console.log(`${ts()} [openclaw-agent] ${msg}`),
|
|
12
|
+
warn: (msg) => console.warn(`${ts()} [openclaw-agent] ${msg}`),
|
|
13
|
+
error: (msg) => console.error(`${ts()} [openclaw-agent] ${msg}`)
|
|
14
|
+
};
|
|
15
|
+
function env(name) {
|
|
16
|
+
const v = process.env[name]?.trim();
|
|
17
|
+
if (!v) {
|
|
18
|
+
log.error(`Missing required environment variable: ${name}`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
return v;
|
|
22
|
+
}
|
|
7
23
|
var PRLL_API_URL = env("PRLL_API_URL");
|
|
8
24
|
var PRLL_API_KEY = env("PRLL_API_KEY");
|
|
9
25
|
var PRLL_ORG_ID = env("PRLL_ORG_ID");
|
|
@@ -12,14 +28,6 @@ var PRLL_WS_URL = process.env.PRLL_WS_URL?.trim() || "";
|
|
|
12
28
|
var PRLL_SWIMLANE_NAME = process.env.PRLL_SWIMLANE_NAME?.trim() || "";
|
|
13
29
|
var gatewayPort = process.env.OPENCLAW_GATEWAY_PORT?.trim() || "0";
|
|
14
30
|
var pluginArchive = process.env.PRLL_OPENCLAW_PLUGIN_ARCHIVE?.trim() || "/opt/parall-plugin/parall-plugin.tgz";
|
|
15
|
-
function env(name) {
|
|
16
|
-
const v = process.env[name]?.trim();
|
|
17
|
-
if (!v) {
|
|
18
|
-
console.error(`ERROR: Missing required environment variable: ${name}`);
|
|
19
|
-
process.exit(1);
|
|
20
|
-
}
|
|
21
|
-
return v;
|
|
22
|
-
}
|
|
23
31
|
var openclawStateDir = path.join(stateDir, ".openclaw");
|
|
24
32
|
var configPath = path.join(openclawStateDir, "openclaw.json");
|
|
25
33
|
fs.mkdirSync(path.join(openclawStateDir, "sessions"), { recursive: true });
|
|
@@ -27,7 +35,7 @@ fs.mkdirSync(path.join(openclawStateDir, "workspace"), { recursive: true });
|
|
|
27
35
|
if (fs.existsSync(pluginArchive)) {
|
|
28
36
|
const legacyExtDir = path.join(openclawStateDir, "extensions", "parall");
|
|
29
37
|
fs.rmSync(legacyExtDir, { recursive: true, force: true });
|
|
30
|
-
|
|
38
|
+
log.info(`Installing Parall plugin from ${pluginArchive}...`);
|
|
31
39
|
try {
|
|
32
40
|
execFileSync("openclaw", [
|
|
33
41
|
"plugins",
|
|
@@ -41,11 +49,11 @@ if (fs.existsSync(pluginArchive)) {
|
|
|
41
49
|
timeout: 6e4
|
|
42
50
|
});
|
|
43
51
|
} catch (err) {
|
|
44
|
-
|
|
52
|
+
log.error(`Failed to install Parall plugin: ${String(err)}`);
|
|
45
53
|
process.exit(1);
|
|
46
54
|
}
|
|
47
55
|
} else {
|
|
48
|
-
|
|
56
|
+
log.warn(`Plugin archive not found at ${pluginArchive} \u2014 assuming plugin is already installed.`);
|
|
49
57
|
}
|
|
50
58
|
writeOpenclawConfig();
|
|
51
59
|
function writeOpenclawConfig() {
|
|
@@ -165,9 +173,9 @@ async function preseedPlatformConfig() {
|
|
|
165
173
|
fs.writeFileSync(tmp, JSON.stringify(cfg, null, 2));
|
|
166
174
|
fs.renameSync(tmp, configPath);
|
|
167
175
|
const model = cfg.agents?.defaults?.model ?? "none";
|
|
168
|
-
|
|
176
|
+
log.info(`Platform config pre-seeded (model: ${String(model)}).`);
|
|
169
177
|
} catch (err) {
|
|
170
|
-
|
|
178
|
+
log.warn(`Platform config pre-seed skipped: ${String(err)}`);
|
|
171
179
|
}
|
|
172
180
|
}
|
|
173
181
|
try {
|
|
@@ -178,7 +186,7 @@ try {
|
|
|
178
186
|
});
|
|
179
187
|
} catch {
|
|
180
188
|
}
|
|
181
|
-
|
|
189
|
+
log.info("Starting OpenClaw gateway...");
|
|
182
190
|
var workspaceDir = process.env.PRLL_OPENCLAW_WORKSPACE_DIR?.trim() || "";
|
|
183
191
|
var gatewayEnv = {
|
|
184
192
|
...process.env,
|