@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.
@@ -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(path4) {
382
+ async ensureFreshToken(path5) {
371
383
  if (!this.token || !this.getRefreshToken)
372
384
  return;
373
- const pathSuffix = path4.replace(/^\/api\/v1/, "");
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, path4, body, query, retried = false, opts) {
417
+ async request(method, path5, body, query, retried = false, opts) {
406
418
  if (!retried) {
407
- await this.ensureFreshToken(path4);
419
+ await this.ensureFreshToken(path5);
408
420
  }
409
- let url = `${this.baseUrl}${path4}`;
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 = path4.replace(/^\/api\/v1/, "");
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, path4, body, query, true, opts);
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, path4, body, retried = false) {
488
+ async multipartRequest(method, path5, body, retried = false) {
477
489
  if (!retried) {
478
- await this.ensureFreshToken(path4);
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}${path4}`, {
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 = path4.replace(/^\/api\/v1/, "");
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, path4, body, true);
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
- const res = await this.request("GET", ENDPOINTS.AGENT_SESSIONS(orgId, agentId), void 0, params);
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
- const res = await this.request("GET", ENDPOINTS.AGENT_SESSION_STEPS(orgId, agentId, sessionId), void 0, params);
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, path4) {
1338
- return this.request("GET", ENDPOINTS.WIKI_ACCESS_STATUS(orgId, wikiId), void 0, path4 ? { path: path4 } : 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, path4, params) {
1348
- return this.request("GET", ENDPOINTS.WIKI_FILE_COMMITS(orgId, wikiId), void 0, { path: path4, ...params });
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, path4, ref) {
1351
- return this.request("GET", ENDPOINTS.WIKI_BLAME(orgId, wikiId), void 0, { path: path4, ref });
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 path2 from "node:path";
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
- if ("ANTHROPIC_AUTH_TOKEN" in env) {
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, log) {
2092
+ constructor(config, client, log2) {
2029
2093
  this.config = config;
2030
2094
  this.client = client;
2031
- this.log = 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 this.fullReconcile();
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 = path2.join(root, "agents");
2198
- const flatWorkspace = path2.join(root, "workspace");
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 = path2.join(root, "sessions");
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 = path2.join(agentsDir, targetId);
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 = path2.join(root, sub);
2299
+ const src = path3.join(root, sub);
2224
2300
  if (fs2.existsSync(src)) {
2225
- fs2.renameSync(src, path2.join(targetDir, sub));
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 = path2.resolve(sharedClaudeCredentialsFileFor(this.config.rootClaudeHome));
2513
+ const sharedCredentials = path3.resolve(sharedClaudeCredentialsFileFor(this.config.rootClaudeHome));
2413
2514
  const agentCredentials = agentClaudeCredentialsFileFor(agentClaudeHome);
2414
- const agentCredentialsDir = path2.dirname(agentCredentials);
2415
- fs2.mkdirSync(path2.dirname(sharedCredentials), { recursive: true });
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 (path2.resolve(agentCredentialsDir, currentTarget) === sharedCredentials) {
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 path3 from "node:path";
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 path3.join(os2.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
2578
+ return path4.join(os2.homedir(), "Library", "LaunchAgents", `${PLIST_LABEL}.plist`);
2478
2579
  }
2479
2580
  function systemdUnitPath() {
2480
- return path3.join(os2.homedir(), ".config", "systemd", "user", "parall-daemon.service");
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 = path3.join(os2.homedir(), "Library", "Logs", "parall-daemon.log");
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 = path3.dirname(plistPath());
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 = path3.dirname(systemdUnitPath());
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 = path3.join(os2.homedir(), "Library", "Logs", "parall-daemon.log");
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
- function createLogger(prefix) {
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, log, signal) {
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, log);
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
- log.error(`supervisor crashed: ${String(err)}`);
2824
+ log2.error(`supervisor crashed: ${String(err)}`);
2730
2825
  try {
2731
2826
  await supervisor.stop();
2732
2827
  } catch (stopErr) {
2733
- log.warn(`supervisor.stop() after crash threw: ${String(stopErr)}`);
2828
+ log2.warn(`supervisor.stop() after crash threw: ${String(stopErr)}`);
2734
2829
  }
2735
2830
  if (config.supervisorRestartBackoffMs === 0) {
2736
- log.error("supervisor keepalive disabled (PRLL_DAEMON_SUPERVISOR_RESTART_BACKOFF_MS=0) \u2014 exiting");
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
- log.warn(`restarting supervisor in ${delay}ms (attempt ${attempt})`);
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
- console.error(`[daemon] fatal: ${formatError(err)}`);
2874
+ log.error(`fatal: ${formatError(err)}`);
2781
2875
  process.exitCode = 1;
2782
2876
  });
2783
2877
  }).catch((err) => {
2784
- console.error(`[daemon] fatal: ${formatError(err)}`);
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
- console.log(`Installing Parall plugin from ${pluginArchive}...`);
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
- console.error(`ERROR: Failed to install Parall plugin: ${String(err)}`);
52
+ log.error(`Failed to install Parall plugin: ${String(err)}`);
45
53
  process.exit(1);
46
54
  }
47
55
  } else {
48
- console.warn(`Plugin archive not found at ${pluginArchive} \u2014 assuming plugin is already installed.`);
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
- console.log(`Platform config pre-seeded (model: ${String(model)}).`);
176
+ log.info(`Platform config pre-seeded (model: ${String(model)}).`);
169
177
  } catch (err) {
170
- console.warn(`Platform config pre-seed skipped: ${String(err)}`);
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
- console.log("Starting OpenClaw gateway...");
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,