@atom8n/n8n-nodes-langchain 2.5.7 → 2.5.8

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.
Files changed (29) hide show
  1. package/dist/known/nodes.json +24 -0
  2. package/dist/methods/defined.json +3 -0
  3. package/dist/methods/referenced.json +3 -0
  4. package/dist/nodes/agents/OpenClawAgent/OpenClawAgent.node.js +62 -0
  5. package/dist/nodes/agents/OpenClawAgent/OpenClawAgent.node.js.map +1 -0
  6. package/dist/nodes/agents/OpenClawAgent/V1/OpenClawAgentV1.node.js +821 -0
  7. package/dist/nodes/agents/OpenClawAgent/V1/OpenClawAgentV1.node.js.map +1 -0
  8. package/dist/nodes/agents/OpenClawAgent/V2/OpenClawAgentV2.node.js +2059 -0
  9. package/dist/nodes/agents/OpenClawAgent/V2/OpenClawAgentV2.node.js.map +1 -0
  10. package/dist/nodes/agents/OpenClawAgent/channels/TelegramChannel/TelegramChannel.node.js +329 -0
  11. package/dist/nodes/agents/OpenClawAgent/channels/TelegramChannel/TelegramChannel.node.js.map +1 -0
  12. package/dist/nodes/agents/OpenClawAgent/channels/TelegramChannel/telegram-channel.svg +4 -0
  13. package/dist/nodes/agents/OpenClawAgent/channels/WhatsAppChannel/WhatsAppChannel.node.js +108 -0
  14. package/dist/nodes/agents/OpenClawAgent/channels/WhatsAppChannel/WhatsAppChannel.node.js.map +1 -0
  15. package/dist/nodes/agents/OpenClawAgent/channels/WhatsAppChannel/whatsapp-channel.svg +3 -0
  16. package/dist/nodes/agents/OpenClawAgent/mcpServers/OpenClawMcpServer/OpenClawMcpServer.node.js +228 -0
  17. package/dist/nodes/agents/OpenClawAgent/mcpServers/OpenClawMcpServer/OpenClawMcpServer.node.js.map +1 -0
  18. package/dist/nodes/agents/OpenClawAgent/mcpServers/OpenClawMcpServer/openclaw-mcp-server.svg +9 -0
  19. package/dist/nodes/agents/OpenClawAgent/models/OpenCodeFreeModel/OpenCodeFreeModel.node.js +97 -0
  20. package/dist/nodes/agents/OpenClawAgent/models/OpenCodeFreeModel/OpenCodeFreeModel.node.js.map +1 -0
  21. package/dist/nodes/agents/OpenClawAgent/models/OpenCodeFreeModel/opencode-free-model.svg +1 -0
  22. package/dist/nodes/agents/OpenClawAgent/openclaw.svg +8 -0
  23. package/dist/nodes/agents/OpenClawAgent/plugins/OpenClawPlugin/OpenClawPlugin.node.js +261 -0
  24. package/dist/nodes/agents/OpenClawAgent/plugins/OpenClawPlugin/OpenClawPlugin.node.js.map +1 -0
  25. package/dist/nodes/agents/OpenClawAgent/plugins/OpenClawPlugin/openclaw-plugin.svg +3 -0
  26. package/dist/nodes/llms/LmChat9Router/LmChat9Router.node.js +40 -3
  27. package/dist/nodes/llms/LmChat9Router/LmChat9Router.node.js.map +1 -1
  28. package/dist/types/nodes.json +8 -1
  29. package/package.json +17 -11
@@ -0,0 +1,2059 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var OpenClawAgentV2_node_exports = {};
20
+ __export(OpenClawAgentV2_node_exports, {
21
+ OpenClawAgentV2: () => OpenClawAgentV2
22
+ });
23
+ module.exports = __toCommonJS(OpenClawAgentV2_node_exports);
24
+ var import_child_process = require("child_process");
25
+ var import_crypto = require("crypto");
26
+ var import_fs = require("fs");
27
+ var import_path = require("path");
28
+ var import_n8n_workflow = require("n8n-workflow");
29
+ const selectorTypeToParameterName = {
30
+ agent: "agentId",
31
+ sessionId: "sessionId",
32
+ recipient: "to"
33
+ };
34
+ const selectorTypeToCliFlag = {
35
+ agent: "--agent",
36
+ sessionId: "--session-id",
37
+ recipient: "--to"
38
+ };
39
+ const DEFAULT_TIMEOUT_SECONDS = 300;
40
+ const CLI_SHUTDOWN_GRACE_SECONDS = 90;
41
+ const OPENCLAW_CONFIG_PATH_ENV = "OPENCLAW_CONFIG_PATH";
42
+ const OPENCLAW_STATE_DIR_ENV = "OPENCLAW_STATE_DIR";
43
+ const OPENCLAW_OAUTH_DIR_ENV = "OPENCLAW_OAUTH_DIR";
44
+ const OPENCLAW_DEFAULT_ACCOUNT_ID = "default";
45
+ const OPEN_CODE_FREE_MODEL_SOURCE = "opencode-free";
46
+ const OPEN_CODE_FREE_PROVIDER = "opencode";
47
+ const OPEN_CODE_FREE_ENV_VAR = "OPENCODE_API_KEY";
48
+ const OPEN_CODE_FREE_ENV_ALIAS = "OPENCODE_ZEN_API_KEY";
49
+ const OPEN_CODE_FREE_PUBLIC_KEY = "public";
50
+ const NINE_ROUTER_MODEL_SOURCE = "9router";
51
+ const NINE_ROUTER_PROVIDER = "9router";
52
+ const NINE_ROUTER_DEFAULT_BASE_URL = "http://localhost:20128/api/v1";
53
+ const NINE_ROUTER_API = "openai-completions";
54
+ const NINE_ROUTER_CONTEXT_WINDOW = 128e3;
55
+ const NINE_ROUTER_MAX_TOKENS = 32e3;
56
+ const OPENCLAW_TELEGRAM_CHANNEL_NODE_TYPE = "@n8n/n8n-nodes-langchain.openClawTelegramChannel";
57
+ function isObject(value) {
58
+ return typeof value === "object" && value !== null && !Array.isArray(value);
59
+ }
60
+ function getErrorMessage(error) {
61
+ if (error instanceof Error) {
62
+ return error.message;
63
+ }
64
+ return String(error);
65
+ }
66
+ function normalizeOptionalString(value) {
67
+ if (typeof value !== "string") {
68
+ return void 0;
69
+ }
70
+ const trimmed = value.trim();
71
+ return trimmed || void 0;
72
+ }
73
+ function normalizeLowercaseStringOrEmpty(value) {
74
+ return (value ?? "").trim().toLowerCase();
75
+ }
76
+ function normalizeStringOrNumber(value) {
77
+ if (typeof value === "number" && Number.isFinite(value)) {
78
+ return String(value);
79
+ }
80
+ return normalizeOptionalString(value);
81
+ }
82
+ function normalizeTelegramAllowFromEntry(value) {
83
+ const raw = normalizeStringOrNumber(value);
84
+ if (!raw) {
85
+ return void 0;
86
+ }
87
+ const normalized = raw.replace(/^(telegram|tg):/i, "").trim();
88
+ return normalized || void 0;
89
+ }
90
+ function normalizeAllowFromEntries(value) {
91
+ const rawEntries = Array.isArray(value) ? value : typeof value === "string" ? value.split(/[\n,]/) : [];
92
+ const seen = /* @__PURE__ */ new Set();
93
+ const entries = [];
94
+ for (const rawEntry of rawEntries) {
95
+ const entry = normalizeTelegramAllowFromEntry(rawEntry);
96
+ if (!entry || seen.has(entry)) {
97
+ continue;
98
+ }
99
+ seen.add(entry);
100
+ entries.push(entry);
101
+ }
102
+ return entries;
103
+ }
104
+ function getPublishLiteralExpressionValue(value) {
105
+ const trimmed = value.trim();
106
+ if (!trimmed.startsWith("=")) {
107
+ return void 0;
108
+ }
109
+ const expression = trimmed.slice(1).trim();
110
+ if (!expression || expression.startsWith("{{") || expression.includes("$")) {
111
+ return void 0;
112
+ }
113
+ const quotedMatch = expression.match(/^(['"])(.*)\1$/);
114
+ if (quotedMatch) {
115
+ return quotedMatch[2];
116
+ }
117
+ return expression;
118
+ }
119
+ function getObjectKeys(value) {
120
+ if (!isObject(value)) {
121
+ return void 0;
122
+ }
123
+ return Object.keys(value);
124
+ }
125
+ function getModelDataPreview(value) {
126
+ if (value === void 0 || value === null) {
127
+ return void 0;
128
+ }
129
+ if (typeof value === "string") {
130
+ return value.length <= 300 ? value : `${value.slice(0, 300)}...`;
131
+ }
132
+ if (typeof value !== "object") {
133
+ return String(value);
134
+ }
135
+ if (Array.isArray(value)) {
136
+ return `[array length=${value.length}]`;
137
+ }
138
+ if (isObject(value)) {
139
+ const modelId = normalizeOptionalString(value.modelId);
140
+ const modelSource = normalizeOptionalString(value.modelSource);
141
+ const extra = isObject(value.extra) ? value.extra : void 0;
142
+ if (modelId || modelSource || extra) {
143
+ return JSON.stringify({
144
+ modelId,
145
+ modelSource,
146
+ extraKeys: getObjectKeys(extra)
147
+ });
148
+ }
149
+ return `[object keys=${Object.keys(value).slice(0, 20).join(",")}]`;
150
+ }
151
+ return void 0;
152
+ }
153
+ function getModelProvider(modelId) {
154
+ const provider = modelId?.split("/")[0];
155
+ return normalizeOptionalString(provider);
156
+ }
157
+ function parseModelRef(modelId) {
158
+ const [providerPart, ...modelParts] = modelId.split("/");
159
+ const provider = normalizeOptionalString(providerPart)?.toLowerCase();
160
+ const model = normalizeOptionalString(modelParts.join("/"));
161
+ if (!provider || !model) {
162
+ return void 0;
163
+ }
164
+ return { provider, model };
165
+ }
166
+ function isOpenCodeFreeModel(modelConfig, modelId) {
167
+ return modelConfig?.modelSource === OPEN_CODE_FREE_MODEL_SOURCE && normalizeLowercaseStringOrEmpty(getModelProvider(modelId)) === OPEN_CODE_FREE_PROVIDER;
168
+ }
169
+ function hasOpenCodeAuthEnv(env) {
170
+ return normalizeOptionalString(env[OPEN_CODE_FREE_ENV_VAR]) !== void 0 || normalizeOptionalString(env[OPEN_CODE_FREE_ENV_ALIAS]) !== void 0;
171
+ }
172
+ function applyOpenCodeFreeAuthEnv(params) {
173
+ if (!isOpenCodeFreeModel(params.modelConfig, params.modelId)) {
174
+ return {
175
+ applied: false,
176
+ envVar: OPEN_CODE_FREE_ENV_VAR,
177
+ reason: "not-open-code-free"
178
+ };
179
+ }
180
+ if (hasOpenCodeAuthEnv(params.env) || hasOpenCodeAuthEnv(process.env)) {
181
+ return {
182
+ applied: false,
183
+ envVar: OPEN_CODE_FREE_ENV_VAR,
184
+ reason: "existing-auth-env"
185
+ };
186
+ }
187
+ params.env[OPEN_CODE_FREE_ENV_VAR] = OPEN_CODE_FREE_PUBLIC_KEY;
188
+ return {
189
+ applied: true,
190
+ envVar: OPEN_CODE_FREE_ENV_VAR,
191
+ reason: "configured-public-env"
192
+ };
193
+ }
194
+ function getOpenClawConfigPath() {
195
+ const configuredPath = normalizeOptionalString(process.env[OPENCLAW_CONFIG_PATH_ENV]);
196
+ if (configuredPath) {
197
+ return configuredPath;
198
+ }
199
+ const home = getHomeDirectory();
200
+ return home ? (0, import_path.join)(home, ".openclaw", "openclaw.json") : void 0;
201
+ }
202
+ function resolveOpenClawStateDir() {
203
+ const stateDir = normalizeOptionalString(process.env[OPENCLAW_STATE_DIR_ENV]);
204
+ if (stateDir) {
205
+ return stateDir;
206
+ }
207
+ const home = getHomeDirectory();
208
+ return home ? (0, import_path.join)(home, ".openclaw") : void 0;
209
+ }
210
+ function resolveOpenClawCredentialsDir() {
211
+ const oauthDir = normalizeOptionalString(process.env[OPENCLAW_OAUTH_DIR_ENV]);
212
+ if (oauthDir) {
213
+ return oauthDir;
214
+ }
215
+ const stateDir = resolveOpenClawStateDir();
216
+ return stateDir ? (0, import_path.join)(stateDir, "credentials") : void 0;
217
+ }
218
+ function safeFilenameKey(value) {
219
+ return value.trim().toLowerCase().replace(/[\\/:*?"<>|]/g, "_").replace(/\.\./g, "_");
220
+ }
221
+ function getTelegramPairingPath(credentialsDir) {
222
+ return (0, import_path.join)(credentialsDir, "telegram-pairing.json");
223
+ }
224
+ function getTelegramAllowFromPaths(credentialsDir, accountId) {
225
+ const accountPath = (0, import_path.join)(credentialsDir, `telegram-${safeFilenameKey(accountId)}-allowFrom.json`);
226
+ if (accountId === OPENCLAW_DEFAULT_ACCOUNT_ID) {
227
+ return [accountPath, (0, import_path.join)(credentialsDir, "telegram-allowFrom.json")];
228
+ }
229
+ return [accountPath];
230
+ }
231
+ function getTelegramAllowFromWritePath(credentialsDir, accountId) {
232
+ return (0, import_path.join)(credentialsDir, `telegram-${safeFilenameKey(accountId)}-allowFrom.json`);
233
+ }
234
+ function readOpenClawStateJsonFile(filePath) {
235
+ try {
236
+ if (!(0, import_fs.existsSync)(filePath) || !(0, import_fs.statSync)(filePath).isFile()) {
237
+ return void 0;
238
+ }
239
+ return (0, import_n8n_workflow.jsonParse)((0, import_fs.readFileSync)(filePath, "utf8"), {
240
+ acceptJSObject: true,
241
+ repairJSON: true
242
+ });
243
+ } catch (error) {
244
+ console.log("[OpenClawAgentV2] Failed to read Telegram allowFrom source file", {
245
+ filePath,
246
+ error: getErrorMessage(error)
247
+ });
248
+ return void 0;
249
+ }
250
+ }
251
+ function getMetaString(meta, key) {
252
+ return isObject(meta) ? normalizeOptionalString(meta[key]) : void 0;
253
+ }
254
+ function addTelegramAllowFromEntry(entries, seen, value) {
255
+ const entry = normalizeTelegramAllowFromEntry(value);
256
+ if (!entry || seen.has(entry)) {
257
+ return;
258
+ }
259
+ seen.add(entry);
260
+ entries.push(entry);
261
+ }
262
+ function getFallbackTelegramAllowFrom(accountId) {
263
+ const credentialsDir = resolveOpenClawCredentialsDir();
264
+ if (!credentialsDir) {
265
+ return { allowFrom: [], pairingCount: 0, allowFromFileCount: 0 };
266
+ }
267
+ const pairingPath = getTelegramPairingPath(credentialsDir);
268
+ const allowFromPaths = getTelegramAllowFromPaths(credentialsDir, accountId);
269
+ const entries = [];
270
+ const seen = /* @__PURE__ */ new Set();
271
+ let pairingCount = 0;
272
+ let allowFromFileCount = 0;
273
+ const pairingStore = readOpenClawStateJsonFile(pairingPath);
274
+ const requests = isObject(pairingStore) && Array.isArray(pairingStore.requests) ? pairingStore.requests : [];
275
+ for (const request of requests) {
276
+ if (!isObject(request)) {
277
+ continue;
278
+ }
279
+ const requestAccountId = normalizeOpenClawAccountId(getMetaString(request.meta, "accountId")) ?? OPENCLAW_DEFAULT_ACCOUNT_ID;
280
+ if (requestAccountId !== accountId) {
281
+ continue;
282
+ }
283
+ const beforeCount = entries.length;
284
+ addTelegramAllowFromEntry(entries, seen, request.id);
285
+ if (entries.length > beforeCount) {
286
+ pairingCount++;
287
+ }
288
+ }
289
+ for (const allowFromPath of allowFromPaths) {
290
+ const allowFromStore = readOpenClawStateJsonFile(allowFromPath);
291
+ const allowFromEntries = isObject(allowFromStore) && Array.isArray(allowFromStore.allowFrom) ? allowFromStore.allowFrom : [];
292
+ for (const entry of allowFromEntries) {
293
+ const beforeCount = entries.length;
294
+ addTelegramAllowFromEntry(entries, seen, entry);
295
+ if (entries.length > beforeCount) {
296
+ allowFromFileCount++;
297
+ }
298
+ }
299
+ }
300
+ return {
301
+ allowFrom: entries,
302
+ credentialsDir,
303
+ pairingPath,
304
+ allowFromPaths,
305
+ pairingCount,
306
+ allowFromFileCount
307
+ };
308
+ }
309
+ function writeTelegramAllowFromStore(accountId, allowFrom) {
310
+ const credentialsDir = resolveOpenClawCredentialsDir();
311
+ if (!credentialsDir) {
312
+ console.log(
313
+ "[OpenClawAgentV2] Telegram allowFrom store sync skipped: credentials dir unknown",
314
+ {
315
+ accountId,
316
+ allowFromCount: allowFrom.length
317
+ }
318
+ );
319
+ return { changed: false };
320
+ }
321
+ const filePath = getTelegramAllowFromWritePath(credentialsDir, accountId);
322
+ const existingStore = readOpenClawStateJsonFile(filePath);
323
+ const nextStore = isObject(existingStore) ? { ...existingStore, version: 1, allowFrom } : { version: 1, allowFrom };
324
+ const existingJson = isObject(existingStore) ? JSON.stringify(existingStore, null, 2) : void 0;
325
+ const nextJson = JSON.stringify(nextStore, null, 2);
326
+ if (existingJson === nextJson) {
327
+ console.log("[OpenClawAgentV2] Telegram allowFrom store already current", {
328
+ accountId,
329
+ filePath,
330
+ allowFromCount: allowFrom.length
331
+ });
332
+ return { changed: false, filePath };
333
+ }
334
+ (0, import_fs.mkdirSync)((0, import_path.dirname)(filePath), { recursive: true });
335
+ (0, import_fs.writeFileSync)(filePath, `${nextJson}
336
+ `, "utf8");
337
+ console.log("[OpenClawAgentV2] Telegram allowFrom store written", {
338
+ accountId,
339
+ filePath,
340
+ allowFromCount: allowFrom.length
341
+ });
342
+ return { changed: true, filePath };
343
+ }
344
+ function ensureDataObject(parent, key) {
345
+ const existing = parent[key];
346
+ if (isObject(existing)) {
347
+ return existing;
348
+ }
349
+ const next = {};
350
+ parent[key] = next;
351
+ return next;
352
+ }
353
+ function setConfigValue(target, key, value) {
354
+ if (target[key] === value) {
355
+ return false;
356
+ }
357
+ target[key] = value;
358
+ return true;
359
+ }
360
+ function deleteConfigValue(target, key) {
361
+ if (target[key] === void 0) {
362
+ return false;
363
+ }
364
+ delete target[key];
365
+ return true;
366
+ }
367
+ function setOptionalConfigValue(target, key, value) {
368
+ if (value === void 0) {
369
+ return deleteConfigValue(target, key);
370
+ }
371
+ return setConfigValue(target, key, value);
372
+ }
373
+ function setOptionalStringArrayConfigValue(target, key, value) {
374
+ if (value === void 0) {
375
+ return deleteConfigValue(target, key);
376
+ }
377
+ if (value.length === 0) {
378
+ return deleteConfigValue(target, key);
379
+ }
380
+ const existing = target[key];
381
+ if (Array.isArray(existing) && existing.length === value.length && existing.every((entry, index) => entry === value[index])) {
382
+ return false;
383
+ }
384
+ target[key] = value;
385
+ return true;
386
+ }
387
+ function setDefaultConfigValue(target, key, value) {
388
+ if (target[key] !== void 0) {
389
+ return false;
390
+ }
391
+ target[key] = value;
392
+ return true;
393
+ }
394
+ function normalizeOpenClawAccountId(value) {
395
+ const trimmed = normalizeOptionalString(value)?.toLowerCase();
396
+ if (!trimmed) {
397
+ return void 0;
398
+ }
399
+ const normalized = trimmed.replace(/[^a-z0-9_-]+/g, "-").replace(/^-+/, "").replace(/-+$/, "").slice(0, 64);
400
+ if (!normalized || ["__proto__", "constructor", "prototype"].includes(normalized)) {
401
+ return void 0;
402
+ }
403
+ return normalized;
404
+ }
405
+ function normalizeOpenClawMcpServerName(value) {
406
+ const trimmed = normalizeOptionalString(value);
407
+ if (!trimmed) {
408
+ return void 0;
409
+ }
410
+ const normalized = trimmed.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/^-+/, "").replace(/-+$/, "").slice(0, 80);
411
+ if (!normalized || ["__proto__", "constructor", "prototype"].includes(normalized)) {
412
+ return void 0;
413
+ }
414
+ return normalized;
415
+ }
416
+ function isHttpUrl(value) {
417
+ try {
418
+ const parsed = new URL(value);
419
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
420
+ } catch {
421
+ return false;
422
+ }
423
+ }
424
+ function normalizeMcpTransport(value) {
425
+ if (value === "sse" || value === "streamable-http") {
426
+ return value;
427
+ }
428
+ if (value === "http") {
429
+ return "streamable-http";
430
+ }
431
+ return void 0;
432
+ }
433
+ function normalizeMcpHeaders(value) {
434
+ let rawHeaders = value;
435
+ if (typeof value === "string") {
436
+ const trimmed = value.trim();
437
+ if (!trimmed || trimmed === "{}") {
438
+ return void 0;
439
+ }
440
+ rawHeaders = (0, import_n8n_workflow.jsonParse)(trimmed, { acceptJSObject: true, repairJSON: true });
441
+ }
442
+ if (!isObject(rawHeaders)) {
443
+ return void 0;
444
+ }
445
+ const headers = Object.fromEntries(
446
+ Object.entries(rawHeaders).filter(
447
+ (entry) => typeof entry[1] === "string" || typeof entry[1] === "number" || typeof entry[1] === "boolean"
448
+ )
449
+ );
450
+ return Object.keys(headers).length > 0 ? headers : void 0;
451
+ }
452
+ function normalizePositiveInteger(value) {
453
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
454
+ return void 0;
455
+ }
456
+ return Math.floor(value);
457
+ }
458
+ function getActivationVariables(context) {
459
+ const additionalData = context.additionalData;
460
+ return isObject(additionalData?.variables) ? additionalData.variables : {};
461
+ }
462
+ function resolveVariableExpression(value, variables) {
463
+ const trimmed = value.trim();
464
+ const expression = trimmed.startsWith("=") ? trimmed.slice(1).trim() : trimmed;
465
+ const match = expression.match(
466
+ /^\{\{\s*\$vars(?:\.([A-Za-z_][A-Za-z0-9_]*)|\[['"]([^'"]+)['"]\])\s*\}\}$/
467
+ );
468
+ if (!match) {
469
+ return void 0;
470
+ }
471
+ const key = match[1] ?? match[2];
472
+ return key ? variables[key] : void 0;
473
+ }
474
+ function resolvePublishParameterValue(value, variables) {
475
+ if (typeof value !== "string") {
476
+ return value;
477
+ }
478
+ const trimmed = value.trim();
479
+ if (!trimmed.startsWith("=") && !trimmed.startsWith("{{")) {
480
+ return value;
481
+ }
482
+ return resolveVariableExpression(trimmed, variables);
483
+ }
484
+ function getPublishAllowFrom(params) {
485
+ const resolvedValue = resolvePublishParameterValue(params.rawValue, params.variables);
486
+ if (resolvedValue === void 0 && typeof params.rawValue === "string") {
487
+ const literalValue = getPublishLiteralExpressionValue(params.rawValue);
488
+ if (literalValue !== void 0) {
489
+ const literalAllowFrom = normalizeAllowFromEntries(literalValue);
490
+ console.log("OpenClaw publish sync: resolved Telegram allowFrom literal expression", {
491
+ nodeName: params.nodeName,
492
+ rawValue: params.rawValue,
493
+ allowFromCount: literalAllowFrom.length
494
+ });
495
+ return literalAllowFrom;
496
+ }
497
+ const accountId = params.accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID;
498
+ const fallback = getFallbackTelegramAllowFrom(accountId);
499
+ if (fallback.allowFrom.length > 0) {
500
+ console.log("OpenClaw publish sync: using Telegram allowFrom fallback from OpenClaw state", {
501
+ nodeName: params.nodeName,
502
+ accountId,
503
+ credentialsDir: fallback.credentialsDir,
504
+ pairingPath: fallback.pairingPath,
505
+ allowFromPaths: fallback.allowFromPaths,
506
+ pairingCount: fallback.pairingCount,
507
+ allowFromFileCount: fallback.allowFromFileCount,
508
+ allowFromCount: fallback.allowFrom.length
509
+ });
510
+ return fallback.allowFrom;
511
+ }
512
+ console.log("OpenClaw publish sync: Telegram allowFrom expression unresolved, skipping field", {
513
+ nodeName: params.nodeName,
514
+ rawValue: params.rawValue,
515
+ accountId,
516
+ credentialsDir: fallback.credentialsDir,
517
+ pairingPath: fallback.pairingPath,
518
+ allowFromPaths: fallback.allowFromPaths
519
+ });
520
+ return void 0;
521
+ }
522
+ if (resolvedValue === void 0) {
523
+ const accountId = params.accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID;
524
+ const fallback = getFallbackTelegramAllowFrom(accountId);
525
+ if (fallback.allowFrom.length > 0) {
526
+ console.log("OpenClaw publish sync: using Telegram allowFrom fallback from OpenClaw state", {
527
+ nodeName: params.nodeName,
528
+ accountId,
529
+ credentialsDir: fallback.credentialsDir,
530
+ pairingPath: fallback.pairingPath,
531
+ allowFromPaths: fallback.allowFromPaths,
532
+ pairingCount: fallback.pairingCount,
533
+ allowFromFileCount: fallback.allowFromFileCount,
534
+ allowFromCount: fallback.allowFrom.length
535
+ });
536
+ return fallback.allowFrom;
537
+ }
538
+ return void 0;
539
+ }
540
+ const allowFrom = normalizeAllowFromEntries(resolvedValue);
541
+ console.log("OpenClaw publish sync: resolved Telegram allowFrom parameter", {
542
+ nodeName: params.nodeName,
543
+ rawType: typeof params.rawValue,
544
+ resolvedType: Array.isArray(resolvedValue) ? "array" : typeof resolvedValue,
545
+ allowFromCount: allowFrom.length
546
+ });
547
+ return allowFrom;
548
+ }
549
+ function getMcpServerConfigFromParameters(parameters) {
550
+ const serverName = normalizeOptionalString(parameters.serverName);
551
+ const url = normalizeOptionalString(parameters.endpointUrl);
552
+ if (!serverName && !url) {
553
+ return { reason: "not-mcp-server-node" };
554
+ }
555
+ if (!serverName) {
556
+ return { reason: "missing-server-name" };
557
+ }
558
+ if (!url) {
559
+ return { reason: "missing-endpoint-url" };
560
+ }
561
+ const options = isObject(parameters.options) ? parameters.options : {};
562
+ let headers;
563
+ try {
564
+ headers = normalizeMcpHeaders(options.headers);
565
+ } catch (error) {
566
+ return { reason: `invalid-headers:${getErrorMessage(error)}` };
567
+ }
568
+ return {
569
+ config: {
570
+ mcpServerSource: "openclaw",
571
+ serverName,
572
+ url,
573
+ transport: normalizeMcpTransport(parameters.transport),
574
+ headers,
575
+ connectionTimeoutMs: normalizePositiveInteger(options.connectionTimeoutMs)
576
+ }
577
+ };
578
+ }
579
+ function readOpenClawConfig(configPath) {
580
+ if (!(0, import_fs.existsSync)(configPath)) {
581
+ return {};
582
+ }
583
+ const rawConfig = (0, import_fs.readFileSync)(configPath, "utf8").trim();
584
+ if (!rawConfig) {
585
+ return {};
586
+ }
587
+ const parsed = (0, import_n8n_workflow.jsonParse)(rawConfig, { acceptJSObject: true, repairJSON: true });
588
+ if (!isObject(parsed)) {
589
+ throw new import_n8n_workflow.ApplicationError(`OpenClaw config is not an object: ${configPath}`);
590
+ }
591
+ return parsed;
592
+ }
593
+ function syncChannelConfig(params) {
594
+ const configPath = getOpenClawConfigPath();
595
+ if (!configPath) {
596
+ throw new import_n8n_workflow.ApplicationError(
597
+ `Could not determine OpenClaw config path. Set ${OPENCLAW_CONFIG_PATH_ENV} or HOME for the n8n process.`
598
+ );
599
+ }
600
+ const config = readOpenClawConfig(configPath);
601
+ const originalConfigJson = JSON.stringify(config);
602
+ const channels = ensureDataObject(config, "channels");
603
+ const channel = ensureDataObject(channels, params.channelType);
604
+ const accountId = normalizeOpenClawAccountId(params.replyAccount);
605
+ const useAccountTarget = !!accountId && accountId !== OPENCLAW_DEFAULT_ACCOUNT_ID;
606
+ const target = useAccountTarget ? ensureDataObject(ensureDataObject(channel, "accounts"), accountId) : channel;
607
+ const targetPath = useAccountTarget ? `channels.${params.channelType}.accounts.${accountId}` : `channels.${params.channelType}`;
608
+ const dmPolicy = normalizeOptionalString(params.dmPolicy);
609
+ const groupPolicy = normalizeOptionalString(params.groupPolicy);
610
+ const isTelegramChannel = params.channelType === "telegram";
611
+ console.log("[OpenClawAgentV2] syncChannelConfig: start", {
612
+ channelType: params.channelType,
613
+ accountId: accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
614
+ targetPath,
615
+ configPath,
616
+ hasBotToken: !!params.botToken,
617
+ dmPolicy: dmPolicy ?? "(openclaw-default)",
618
+ groupPolicy: groupPolicy ?? "(openclaw-default)",
619
+ allowFromCount: params.allowFrom?.length
620
+ });
621
+ let changed = false;
622
+ changed = setConfigValue(channel, "enabled", true) || changed;
623
+ if (useAccountTarget) {
624
+ changed = setConfigValue(target, "enabled", true) || changed;
625
+ }
626
+ changed = (dmPolicy ? setConfigValue(target, "dmPolicy", dmPolicy) : setDefaultConfigValue(target, "dmPolicy", "pairing")) || changed;
627
+ changed = (groupPolicy ? setConfigValue(target, "groupPolicy", groupPolicy) : setDefaultConfigValue(target, "groupPolicy", "allowlist")) || changed;
628
+ let allowFromStorePath;
629
+ if (params.allowFrom !== void 0) {
630
+ if (isTelegramChannel) {
631
+ const allowFromStoreSync = writeTelegramAllowFromStore(
632
+ accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
633
+ params.allowFrom
634
+ );
635
+ allowFromStorePath = allowFromStoreSync.filePath;
636
+ changed = allowFromStoreSync.changed || changed;
637
+ } else {
638
+ changed = setOptionalStringArrayConfigValue(target, "allowFrom", params.allowFrom) || changed;
639
+ }
640
+ }
641
+ if (isTelegramChannel) {
642
+ changed = deleteConfigValue(target, "allowFrom") || changed;
643
+ }
644
+ if (params.botToken) {
645
+ changed = setConfigValue(target, "botToken", params.botToken) || changed;
646
+ }
647
+ const configChanged = JSON.stringify(config) !== originalConfigJson;
648
+ if (configChanged) {
649
+ (0, import_fs.mkdirSync)((0, import_path.dirname)(configPath), { recursive: true });
650
+ (0, import_fs.writeFileSync)(configPath, `${JSON.stringify(config, null, 2)}
651
+ `, "utf8");
652
+ console.log("[OpenClawAgentV2] syncChannelConfig: openclaw.json written", {
653
+ channelType: params.channelType,
654
+ accountId: accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
655
+ targetPath,
656
+ configPath,
657
+ allowFromCount: params.allowFrom?.length,
658
+ allowFromStorePath
659
+ });
660
+ } else if (changed) {
661
+ console.log("[OpenClawAgentV2] syncChannelConfig: external channel store updated", {
662
+ channelType: params.channelType,
663
+ accountId: accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
664
+ targetPath,
665
+ configPath,
666
+ allowFromCount: params.allowFrom?.length,
667
+ allowFromStorePath
668
+ });
669
+ } else {
670
+ console.log("[OpenClawAgentV2] syncChannelConfig: no changes needed", {
671
+ channelType: params.channelType,
672
+ accountId: accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
673
+ targetPath,
674
+ configPath,
675
+ allowFromCount: params.allowFrom?.length,
676
+ allowFromStorePath
677
+ });
678
+ }
679
+ return { accountId, changed, configPath, targetPath, allowFromStorePath };
680
+ }
681
+ function getNineRouterModelDefinition(model) {
682
+ return {
683
+ id: model,
684
+ name: model === "auto" ? "9Router Auto" : model,
685
+ api: NINE_ROUTER_API,
686
+ reasoning: false,
687
+ input: ["text", "image"],
688
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
689
+ contextWindow: NINE_ROUTER_CONTEXT_WINDOW,
690
+ maxTokens: NINE_ROUTER_MAX_TOKENS
691
+ };
692
+ }
693
+ function syncNineRouterModelConfig(params) {
694
+ if (params.modelConfig?.modelSource !== NINE_ROUTER_MODEL_SOURCE || normalizeLowercaseStringOrEmpty(getModelProvider(params.modelId)) !== NINE_ROUTER_PROVIDER || !params.modelId) {
695
+ return { changed: false, reason: "not-nine-router" };
696
+ }
697
+ const modelRef = parseModelRef(params.modelId);
698
+ if (!modelRef || modelRef.provider !== NINE_ROUTER_PROVIDER) {
699
+ return { changed: false, reason: "invalid-model-id" };
700
+ }
701
+ const configPath = getOpenClawConfigPath();
702
+ if (!configPath) {
703
+ throw new import_n8n_workflow.ApplicationError(
704
+ `Could not determine OpenClaw config path. Set ${OPENCLAW_CONFIG_PATH_ENV} or HOME for the n8n process.`
705
+ );
706
+ }
707
+ const config = readOpenClawConfig(configPath);
708
+ const models = ensureDataObject(config, "models");
709
+ const providers = ensureDataObject(models, "providers");
710
+ const provider = ensureDataObject(providers, NINE_ROUTER_PROVIDER);
711
+ const existingBaseUrl = normalizeOptionalString(provider.baseUrl);
712
+ let changed = false;
713
+ changed = setDefaultConfigValue(
714
+ provider,
715
+ "baseUrl",
716
+ normalizeOptionalString(params.modelConfig.extra?.baseUrl) ?? NINE_ROUTER_DEFAULT_BASE_URL
717
+ ) || changed;
718
+ changed = setConfigValue(provider, "api", NINE_ROUTER_API) || changed;
719
+ let providerModels;
720
+ if (Array.isArray(provider.models)) {
721
+ providerModels = provider.models.filter(isObject);
722
+ if (providerModels.length !== provider.models.length) {
723
+ provider.models = providerModels;
724
+ changed = true;
725
+ }
726
+ } else {
727
+ providerModels = [];
728
+ provider.models = providerModels;
729
+ changed = true;
730
+ }
731
+ const existingModel = providerModels.find(
732
+ (model) => normalizeOptionalString(model.id) === modelRef.model
733
+ );
734
+ if (existingModel) {
735
+ changed = setConfigValue(existingModel, "api", NINE_ROUTER_API) || changed;
736
+ changed = setDefaultConfigValue(existingModel, "name", modelRef.model) || changed;
737
+ changed = setDefaultConfigValue(existingModel, "reasoning", false) || changed;
738
+ changed = setDefaultConfigValue(existingModel, "input", ["text", "image"]) || changed;
739
+ changed = setDefaultConfigValue(existingModel, "cost", {
740
+ input: 0,
741
+ output: 0,
742
+ cacheRead: 0,
743
+ cacheWrite: 0
744
+ }) || changed;
745
+ changed = setDefaultConfigValue(existingModel, "contextWindow", NINE_ROUTER_CONTEXT_WINDOW) || changed;
746
+ changed = setDefaultConfigValue(existingModel, "maxTokens", NINE_ROUTER_MAX_TOKENS) || changed;
747
+ } else {
748
+ providerModels.push(getNineRouterModelDefinition(modelRef.model));
749
+ changed = true;
750
+ }
751
+ const agents = ensureDataObject(config, "agents");
752
+ const defaults = ensureDataObject(agents, "defaults");
753
+ const defaultModels = ensureDataObject(defaults, "models");
754
+ const fullModelRef = `${modelRef.provider}/${modelRef.model}`;
755
+ const existingDefaultModel = defaultModels[fullModelRef];
756
+ if (!isObject(existingDefaultModel)) {
757
+ defaultModels[fullModelRef] = {};
758
+ changed = true;
759
+ }
760
+ if (changed) {
761
+ (0, import_fs.mkdirSync)((0, import_path.dirname)(configPath), { recursive: true });
762
+ (0, import_fs.writeFileSync)(configPath, `${JSON.stringify(config, null, 2)}
763
+ `, "utf8");
764
+ }
765
+ return {
766
+ changed,
767
+ configPath,
768
+ reason: changed ? "updated-provider" : "already-current",
769
+ targetPath: `models.providers.${NINE_ROUTER_PROVIDER}`,
770
+ modelRef: fullModelRef,
771
+ existingBaseUrl
772
+ };
773
+ }
774
+ function syncMcpServerConfig(params) {
775
+ const synced = [];
776
+ const skipped = [];
777
+ if (params.mcpServerConfigs.length === 0) {
778
+ return { changed: false, synced, skipped };
779
+ }
780
+ const configPath = getOpenClawConfigPath();
781
+ if (!configPath) {
782
+ const reason = `Could not determine OpenClaw config path. Set ${OPENCLAW_CONFIG_PATH_ENV} or HOME for the n8n process.`;
783
+ console.log("[OpenClawAgentV2] syncMcpServerConfig: skipped all servers", {
784
+ reason,
785
+ serverCount: params.mcpServerConfigs.length
786
+ });
787
+ return { changed: false, synced, skipped: [reason] };
788
+ }
789
+ console.log("[OpenClawAgentV2] syncMcpServerConfig: start", {
790
+ configPath,
791
+ serverCount: params.mcpServerConfigs.length,
792
+ serverNames: params.mcpServerConfigs.map((server) => server.serverName)
793
+ });
794
+ const config = readOpenClawConfig(configPath);
795
+ const mcp = ensureDataObject(config, "mcp");
796
+ const servers = ensureDataObject(mcp, "servers");
797
+ let changed = false;
798
+ for (const serverConfig of params.mcpServerConfigs) {
799
+ const serverName = normalizeOpenClawMcpServerName(serverConfig.serverName);
800
+ const url = normalizeOptionalString(serverConfig.url);
801
+ if (!serverName) {
802
+ const reason = `invalid-name:${serverConfig.serverName}`;
803
+ console.log("[OpenClawAgentV2] syncMcpServerConfig: skipping server", {
804
+ rawServerName: serverConfig.serverName,
805
+ reason
806
+ });
807
+ skipped.push(reason);
808
+ continue;
809
+ }
810
+ if (!url || !isHttpUrl(url)) {
811
+ const reason = `invalid-url:${serverName}`;
812
+ console.log("[OpenClawAgentV2] syncMcpServerConfig: skipping server", {
813
+ serverName,
814
+ hasUrl: !!url,
815
+ reason
816
+ });
817
+ skipped.push(reason);
818
+ continue;
819
+ }
820
+ const server = ensureDataObject(servers, serverName);
821
+ const transport = normalizeMcpTransport(serverConfig.transport);
822
+ const headers = serverConfig.headers && Object.keys(serverConfig.headers).length > 0 ? serverConfig.headers : void 0;
823
+ const connectionTimeoutMs = normalizePositiveInteger(serverConfig.connectionTimeoutMs);
824
+ changed = setConfigValue(server, "url", url) || changed;
825
+ changed = setOptionalConfigValue(server, "transport", transport) || changed;
826
+ changed = setOptionalConfigValue(server, "headers", headers) || changed;
827
+ changed = setOptionalConfigValue(server, "connectionTimeoutMs", connectionTimeoutMs) || changed;
828
+ changed = deleteConfigValue(server, "command") || changed;
829
+ changed = deleteConfigValue(server, "args") || changed;
830
+ changed = deleteConfigValue(server, "env") || changed;
831
+ changed = deleteConfigValue(server, "cwd") || changed;
832
+ changed = deleteConfigValue(server, "workingDirectory") || changed;
833
+ console.log("[OpenClawAgentV2] syncMcpServerConfig: prepared server", {
834
+ serverName,
835
+ rawServerName: serverConfig.serverName,
836
+ url,
837
+ transport: transport ?? "(openclaw-default)",
838
+ headerKeys: headers ? Object.keys(headers) : [],
839
+ connectionTimeoutMs
840
+ });
841
+ synced.push(serverName);
842
+ }
843
+ if (changed) {
844
+ (0, import_fs.mkdirSync)((0, import_path.dirname)(configPath), { recursive: true });
845
+ (0, import_fs.writeFileSync)(configPath, `${JSON.stringify(config, null, 2)}
846
+ `, "utf8");
847
+ console.log("[OpenClawAgentV2] syncMcpServerConfig: openclaw.json written", {
848
+ configPath,
849
+ synced,
850
+ skipped
851
+ });
852
+ } else {
853
+ console.log("[OpenClawAgentV2] syncMcpServerConfig: no changes needed", {
854
+ configPath,
855
+ synced,
856
+ skipped
857
+ });
858
+ }
859
+ return { changed, configPath, synced, skipped };
860
+ }
861
+ function syncPluginConfig(params) {
862
+ const installed = [];
863
+ const skipped = [];
864
+ const errors = [];
865
+ const configPath = getOpenClawConfigPath();
866
+ let existingInstalls = {};
867
+ let existingLoadPaths = [];
868
+ let existingEntries = {};
869
+ if (configPath) {
870
+ try {
871
+ const config = readOpenClawConfig(configPath);
872
+ const plugins = config.plugins;
873
+ existingInstalls = plugins?.installs ?? {};
874
+ existingLoadPaths = plugins?.load?.paths ?? [];
875
+ existingEntries = plugins?.entries ?? {};
876
+ } catch {
877
+ }
878
+ }
879
+ const resolvedBinary = resolveOpenClawBinary("openclaw");
880
+ const env = createOpenClawProcessEnv(resolvedBinary.pathDirectories, { NODE_NO_WARNINGS: "1" });
881
+ for (const pluginCfg of params.pluginConfigs) {
882
+ if (pluginCfg.pluginSource === "local" && pluginCfg.pluginPath) {
883
+ const pluginPath = pluginCfg.pluginPath;
884
+ const manifestId = pluginCfg.pluginManifest?.id;
885
+ if (manifestId) {
886
+ const isPathLoaded = existingLoadPaths.includes(pluginPath);
887
+ const isEntryEnabled = existingEntries[manifestId]?.enabled === true;
888
+ if (isPathLoaded && isEntryEnabled) {
889
+ console.log("[OpenClawAgentV2] syncPluginConfig: already installed, skipping", {
890
+ manifestId,
891
+ pluginPath
892
+ });
893
+ skipped.push(manifestId);
894
+ continue;
895
+ }
896
+ }
897
+ try {
898
+ const cmd = `${resolvedBinary.binaryPath} plugins install -l ${JSON.stringify(pluginPath)}`;
899
+ console.log("[OpenClawAgentV2] syncPluginConfig: running CLI", { cmd });
900
+ const output = (0, import_child_process.execSync)(cmd, {
901
+ timeout: 3e4,
902
+ encoding: "utf8",
903
+ stdio: ["pipe", "pipe", "pipe"],
904
+ env
905
+ });
906
+ console.log("[OpenClawAgentV2] syncPluginConfig: CLI success", {
907
+ pluginPath,
908
+ manifestId,
909
+ output: output.trim().slice(0, 500)
910
+ });
911
+ installed.push(manifestId ?? pluginPath);
912
+ } catch (cliErr) {
913
+ const errMsg = cliErr instanceof Error ? cliErr.message : String(cliErr);
914
+ const stderr = cliErr && typeof cliErr === "object" && "stderr" in cliErr ? String(cliErr.stderr).trim().slice(0, 500) : void 0;
915
+ console.log("[OpenClawAgentV2] syncPluginConfig: CLI failed", {
916
+ pluginPath,
917
+ error: errMsg.slice(0, 300),
918
+ stderr
919
+ });
920
+ errors.push(`local:${pluginPath}: ${errMsg.slice(0, 200)}`);
921
+ }
922
+ } else if (pluginCfg.pluginSource === "cloud" && pluginCfg.pluginId) {
923
+ const pluginId = pluginCfg.pluginId;
924
+ const existingRecord = existingInstalls[pluginId];
925
+ if (existingRecord?.source === "npm" || existingRecord?.source === "clawhub") {
926
+ console.log("[OpenClawAgentV2] syncPluginConfig: already installed, skipping", {
927
+ pluginId,
928
+ source: existingRecord.source
929
+ });
930
+ skipped.push(pluginId);
931
+ continue;
932
+ }
933
+ const spec = pluginCfg.pluginVersion ? `${pluginId}@${pluginCfg.pluginVersion}` : pluginId;
934
+ try {
935
+ const cmd = `${resolvedBinary.binaryPath} plugins install ${JSON.stringify(spec)}`;
936
+ console.log("[OpenClawAgentV2] syncPluginConfig: running CLI", { cmd });
937
+ const output = (0, import_child_process.execSync)(cmd, {
938
+ timeout: 6e4,
939
+ encoding: "utf8",
940
+ stdio: ["pipe", "pipe", "pipe"],
941
+ env
942
+ });
943
+ console.log("[OpenClawAgentV2] syncPluginConfig: CLI success", {
944
+ pluginId,
945
+ output: output.trim().slice(0, 500)
946
+ });
947
+ installed.push(pluginId);
948
+ } catch (cliErr) {
949
+ const errMsg = cliErr instanceof Error ? cliErr.message : String(cliErr);
950
+ console.log("[OpenClawAgentV2] syncPluginConfig: CLI failed", {
951
+ pluginId,
952
+ error: errMsg.slice(0, 300)
953
+ });
954
+ errors.push(`cloud:${pluginId}: ${errMsg.slice(0, 200)}`);
955
+ }
956
+ }
957
+ }
958
+ console.log("[OpenClawAgentV2] syncPluginConfig: result", {
959
+ pluginCount: params.pluginConfigs.length,
960
+ installedCount: installed.length,
961
+ skippedCount: skipped.length,
962
+ errorCount: errors.length,
963
+ installed: installed.length > 0 ? installed : void 0,
964
+ skipped: skipped.length > 0 ? skipped : void 0,
965
+ errors: errors.length > 0 ? errors : void 0
966
+ });
967
+ return { installed, skipped, errors };
968
+ }
969
+ function parseOpenClawOutput(stdout) {
970
+ const trimmed = stdout.trim();
971
+ if (!trimmed) {
972
+ return {};
973
+ }
974
+ const parsed = (0, import_n8n_workflow.jsonParse)(trimmed);
975
+ if (isObject(parsed)) {
976
+ return parsed;
977
+ }
978
+ return { result: parsed };
979
+ }
980
+ function isUsableFile(filePath) {
981
+ try {
982
+ return (0, import_fs.existsSync)(filePath) && (0, import_fs.statSync)(filePath).isFile();
983
+ } catch {
984
+ return false;
985
+ }
986
+ }
987
+ function getHomeDirectory() {
988
+ return normalizeOptionalString(process.env.HOME) ?? normalizeOptionalString(process.env.USERPROFILE);
989
+ }
990
+ function getDefaultBinarySearchPaths(binaryName) {
991
+ const home = getHomeDirectory();
992
+ const homeCandidates = home ? [
993
+ (0, import_path.join)(home, ".volta", "bin", binaryName),
994
+ (0, import_path.join)(home, ".local", "bin", binaryName),
995
+ (0, import_path.join)(home, ".npm-global", "bin", binaryName),
996
+ (0, import_path.join)(home, ".bun", "bin", binaryName),
997
+ (0, import_path.join)(home, "Library", "pnpm", binaryName)
998
+ ] : [];
999
+ return [
1000
+ normalizeOptionalString(process.env.OPENCLAW_BINARY_PATH),
1001
+ normalizeOptionalString(process.env.OPENCLAW_BIN),
1002
+ ...(process.env.PATH ?? "").split(import_path.delimiter).filter(Boolean).map((pathDirectory) => (0, import_path.join)(pathDirectory, binaryName)),
1003
+ ...homeCandidates,
1004
+ (0, import_path.join)("/opt/homebrew/bin", binaryName),
1005
+ (0, import_path.join)("/usr/local/bin", binaryName)
1006
+ ].filter((candidate) => typeof candidate === "string");
1007
+ }
1008
+ function resolveOpenClawBinary(binaryPath) {
1009
+ if (binaryPath.includes("/") || binaryPath.includes("\\")) {
1010
+ return { binaryPath, pathDirectories: [(0, import_path.dirname)(binaryPath)] };
1011
+ }
1012
+ for (const candidate of getDefaultBinarySearchPaths(binaryPath)) {
1013
+ if (isUsableFile(candidate)) {
1014
+ return { binaryPath: candidate, pathDirectories: [(0, import_path.dirname)(candidate)] };
1015
+ }
1016
+ }
1017
+ return { binaryPath, pathDirectories: [] };
1018
+ }
1019
+ function createOpenClawProcessEnv(pathDirectories, additionalEnv = {}) {
1020
+ const existingPath = process.env.PATH ?? "";
1021
+ const prependedPath = pathDirectories.filter(Boolean).join(import_path.delimiter);
1022
+ const nextPath = prependedPath ? `${prependedPath}${import_path.delimiter}${existingPath}` : existingPath;
1023
+ return { ...process.env, ...additionalEnv, PATH: nextPath };
1024
+ }
1025
+ function killOpenClawProcess(child, signal) {
1026
+ try {
1027
+ if (child.pid && process.platform !== "win32") {
1028
+ process.kill(-child.pid, signal);
1029
+ return;
1030
+ }
1031
+ } catch {
1032
+ }
1033
+ try {
1034
+ child.kill(signal);
1035
+ } catch {
1036
+ }
1037
+ }
1038
+ function summarizeProcessOutput(output) {
1039
+ const trimmed = output.trim();
1040
+ if (!trimmed) return "";
1041
+ const maxLength = 2e3;
1042
+ return trimmed.length <= maxLength ? trimmed : `${trimmed.slice(0, maxLength)}...`;
1043
+ }
1044
+ function getWatchdogTimeoutMs(timeoutSeconds) {
1045
+ return (timeoutSeconds + CLI_SHUTDOWN_GRACE_SECONDS) * 1e3;
1046
+ }
1047
+ function getGatewayCallArgs(params, rpcTimeoutMs) {
1048
+ return [
1049
+ "gateway",
1050
+ "call",
1051
+ "agent",
1052
+ "--expect-final",
1053
+ "--json",
1054
+ "--timeout",
1055
+ String(rpcTimeoutMs),
1056
+ "--params",
1057
+ JSON.stringify(params)
1058
+ ];
1059
+ }
1060
+ function quoteCommandArgument(value) {
1061
+ if (/^[A-Za-z0-9_/:=-]+$/.test(value)) return value;
1062
+ return `'${value.replaceAll("'", "'\\''")}'`;
1063
+ }
1064
+ function getOpenClawCommand(binaryPath, args) {
1065
+ return [binaryPath, ...args].map(quoteCommandArgument).join(" ");
1066
+ }
1067
+ async function runOpenClawCli(params) {
1068
+ return await new Promise((resolve, reject) => {
1069
+ const resolvedBinary = resolveOpenClawBinary(params.binaryPath);
1070
+ const command = getOpenClawCommand(resolvedBinary.binaryPath, params.args);
1071
+ const child = (0, import_child_process.spawn)(resolvedBinary.binaryPath, params.args, {
1072
+ cwd: params.cwd,
1073
+ detached: process.platform !== "win32",
1074
+ stdio: ["ignore", "pipe", "pipe"],
1075
+ env: createOpenClawProcessEnv(resolvedBinary.pathDirectories, params.env)
1076
+ });
1077
+ let stdout = "";
1078
+ let stderr = "";
1079
+ let aborted = false;
1080
+ let timedOut = false;
1081
+ let forceKillTimer;
1082
+ const abortHandler = () => {
1083
+ aborted = true;
1084
+ killOpenClawProcess(child, "SIGTERM");
1085
+ };
1086
+ const timeoutTimer = setTimeout(() => {
1087
+ timedOut = true;
1088
+ killOpenClawProcess(child, "SIGTERM");
1089
+ forceKillTimer = setTimeout(() => {
1090
+ killOpenClawProcess(child, "SIGKILL");
1091
+ }, 5e3);
1092
+ }, params.timeoutMs);
1093
+ params.abortSignal?.addEventListener("abort", abortHandler, { once: true });
1094
+ child.stdout.on("data", (data) => {
1095
+ stdout += data.toString();
1096
+ });
1097
+ child.stderr.on("data", (data) => {
1098
+ stderr += data.toString();
1099
+ });
1100
+ child.on("error", (error) => {
1101
+ clearTimeout(timeoutTimer);
1102
+ if (forceKillTimer) clearTimeout(forceKillTimer);
1103
+ params.abortSignal?.removeEventListener("abort", abortHandler);
1104
+ reject(
1105
+ new Error(
1106
+ `Failed to spawn OpenClaw CLI at "${resolvedBinary.binaryPath}": ${error.message}. Set Options > Binary Path to the full path of the openclaw executable, or set OPENCLAW_BINARY_PATH in the n8n process environment.`
1107
+ )
1108
+ );
1109
+ });
1110
+ child.on("close", (exitCode, signal) => {
1111
+ clearTimeout(timeoutTimer);
1112
+ if (forceKillTimer) clearTimeout(forceKillTimer);
1113
+ params.abortSignal?.removeEventListener("abort", abortHandler);
1114
+ if (aborted) {
1115
+ reject(new Error("OpenClaw CLI execution was cancelled"));
1116
+ return;
1117
+ }
1118
+ if (timedOut) {
1119
+ const stderrSummary = summarizeProcessOutput(stderr);
1120
+ const stdoutSummary = summarizeProcessOutput(stdout);
1121
+ const details = stderrSummary || stdoutSummary ? ` Last output: ${stderrSummary || stdoutSummary}` : "";
1122
+ reject(
1123
+ new Error(
1124
+ `OpenClaw CLI did not finish within ${Math.ceil(params.timeoutMs / 1e3)} seconds and was stopped.${details}`
1125
+ )
1126
+ );
1127
+ return;
1128
+ }
1129
+ resolve({ stdout, stderr, exitCode, signal, command });
1130
+ });
1131
+ });
1132
+ }
1133
+ class OpenClawAgentV2 {
1134
+ constructor(baseDescription) {
1135
+ this.description = {
1136
+ ...baseDescription,
1137
+ version: 2,
1138
+ subtitle: '={{$parameter.selectorType === "agent" ? "Agent: " + $parameter.agentId : $parameter.selectorType === "sessionId" ? "Session: " + $parameter.sessionId : $parameter.selectorType === "recipient" ? "To: " + $parameter.to : "Default route"}}',
1139
+ defaults: {
1140
+ name: "OpenClaw AI Agent"
1141
+ },
1142
+ codex: {
1143
+ alias: ["OpenClaw", "Agent", "Gateway", "Assistant", "Channel"],
1144
+ categories: ["AI"],
1145
+ subcategories: {
1146
+ AI: ["Agents", "Root Nodes"]
1147
+ },
1148
+ resources: {
1149
+ primaryDocumentation: [
1150
+ {
1151
+ url: "https://docs.openclaw.ai/cli/agent"
1152
+ }
1153
+ ]
1154
+ }
1155
+ },
1156
+ inputs: [
1157
+ import_n8n_workflow.NodeConnectionTypes.Main,
1158
+ {
1159
+ type: import_n8n_workflow.NodeConnectionTypes.AiChannel,
1160
+ displayName: "Channel"
1161
+ },
1162
+ {
1163
+ type: import_n8n_workflow.NodeConnectionTypes.AiLanguageModel,
1164
+ displayName: "Model",
1165
+ required: false,
1166
+ maxConnections: 1
1167
+ },
1168
+ {
1169
+ type: import_n8n_workflow.NodeConnectionTypes.AiTool,
1170
+ displayName: "Plugin",
1171
+ required: false
1172
+ },
1173
+ {
1174
+ type: import_n8n_workflow.NodeConnectionTypes.AiTool,
1175
+ displayName: "MCP",
1176
+ required: false
1177
+ }
1178
+ ],
1179
+ outputs: [import_n8n_workflow.NodeConnectionTypes.Main],
1180
+ // No hardcoded credentials — channels provide their own
1181
+ properties: [
1182
+ {
1183
+ displayName: "Requires the OpenClaw CLI to be installed and configured on the n8n host. Connect Channel sub-nodes to configure messaging channels (Telegram, WhatsApp, etc.).",
1184
+ name: "openClawNotice",
1185
+ type: "notice",
1186
+ default: ""
1187
+ },
1188
+ {
1189
+ displayName: "Message",
1190
+ name: "message",
1191
+ type: "string",
1192
+ required: true,
1193
+ default: '={{ $json.chatInput || $json.chat_input || $json.message || $json.text || "" }}',
1194
+ description: "Message body to send to the OpenClaw agent",
1195
+ typeOptions: { rows: 5 }
1196
+ },
1197
+ {
1198
+ displayName: "Route By",
1199
+ name: "selectorType",
1200
+ type: "options",
1201
+ default: "agent",
1202
+ noDataExpression: true,
1203
+ description: "How to target the OpenClaw agent turn",
1204
+ options: [
1205
+ {
1206
+ name: "Agent ID",
1207
+ value: "agent",
1208
+ description: "Run against a configured OpenClaw agent"
1209
+ },
1210
+ {
1211
+ name: "Existing Session ID",
1212
+ value: "sessionId",
1213
+ description: "Continue an existing OpenClaw session"
1214
+ },
1215
+ {
1216
+ name: "Recipient",
1217
+ value: "recipient",
1218
+ description: "Use a recipient/channel target to derive the session"
1219
+ },
1220
+ {
1221
+ name: "OpenClaw Default",
1222
+ value: "default",
1223
+ description: "Let OpenClaw choose its default route"
1224
+ }
1225
+ ]
1226
+ },
1227
+ {
1228
+ displayName: "Agent ID",
1229
+ name: "agentId",
1230
+ type: "string",
1231
+ default: "main",
1232
+ description: "Configured OpenClaw agent ID",
1233
+ displayOptions: { show: { selectorType: ["agent"] } }
1234
+ },
1235
+ {
1236
+ displayName: "Session ID",
1237
+ name: "sessionId",
1238
+ type: "string",
1239
+ default: "",
1240
+ description: "OpenClaw session ID to continue",
1241
+ displayOptions: { show: { selectorType: ["sessionId"] } }
1242
+ },
1243
+ {
1244
+ displayName: "Recipient",
1245
+ name: "to",
1246
+ type: "string",
1247
+ default: "",
1248
+ description: "Recipient or channel target passed to OpenClaw as --to",
1249
+ displayOptions: { show: { selectorType: ["recipient"] } }
1250
+ },
1251
+ {
1252
+ displayName: "Thinking Level",
1253
+ name: "thinking",
1254
+ type: "options",
1255
+ default: "",
1256
+ description: "Optional OpenClaw thinking level override for this run",
1257
+ options: [
1258
+ { name: "Adaptive", value: "adaptive" },
1259
+ { name: "Extra High", value: "xhigh" },
1260
+ { name: "High", value: "high" },
1261
+ { name: "Low", value: "low" },
1262
+ { name: "Max", value: "max" },
1263
+ { name: "Medium", value: "medium" },
1264
+ { name: "Minimal", value: "minimal" },
1265
+ { name: "Off", value: "off" },
1266
+ { name: "Use OpenClaw Default", value: "" }
1267
+ ]
1268
+ },
1269
+ {
1270
+ displayName: "Run Locally",
1271
+ name: "local",
1272
+ type: "boolean",
1273
+ default: false,
1274
+ description: "Whether to force OpenClaw embedded local runtime instead of Gateway mode"
1275
+ },
1276
+ {
1277
+ displayName: "Deliver Reply",
1278
+ name: "deliver",
1279
+ type: "boolean",
1280
+ default: false,
1281
+ description: "Whether OpenClaw should deliver the reply back to the selected channel/target"
1282
+ },
1283
+ {
1284
+ displayName: "Options",
1285
+ name: "options",
1286
+ type: "collection",
1287
+ placeholder: "Add Option",
1288
+ default: {},
1289
+ options: [
1290
+ {
1291
+ displayName: "System Message",
1292
+ name: "systemMessage",
1293
+ type: "string",
1294
+ default: "",
1295
+ description: "Additional system instructions for this OpenClaw run",
1296
+ typeOptions: { rows: 5 }
1297
+ },
1298
+ {
1299
+ displayName: "Binary Path",
1300
+ name: "binaryPath",
1301
+ type: "string",
1302
+ default: "openclaw",
1303
+ description: "Path to the openclaw binary"
1304
+ },
1305
+ {
1306
+ displayName: "Working Directory",
1307
+ name: "workingDirectory",
1308
+ type: "string",
1309
+ default: "",
1310
+ description: "Working directory for the OpenClaw process"
1311
+ },
1312
+ {
1313
+ displayName: "Timeout",
1314
+ name: "timeout",
1315
+ type: "number",
1316
+ default: DEFAULT_TIMEOUT_SECONDS,
1317
+ description: "OpenClaw agent timeout in seconds",
1318
+ typeOptions: { minValue: 1 }
1319
+ },
1320
+ {
1321
+ displayName: "Verbose",
1322
+ name: "verbose",
1323
+ type: "options",
1324
+ default: "",
1325
+ description: "Optional OpenClaw verbose setting",
1326
+ options: [
1327
+ { name: "Full", value: "full" },
1328
+ { name: "Leave Unchanged", value: "" },
1329
+ { name: "Off", value: "off" },
1330
+ { name: "On", value: "on" }
1331
+ ]
1332
+ },
1333
+ {
1334
+ displayName: "Include Raw Output",
1335
+ name: "includeRawOutput",
1336
+ type: "boolean",
1337
+ default: false,
1338
+ description: "Whether to include raw stdout and stderr from the OpenClaw CLI in the output"
1339
+ }
1340
+ ]
1341
+ }
1342
+ ]
1343
+ };
1344
+ }
1345
+ async trigger() {
1346
+ const node = this.getNode();
1347
+ const workflowId = this.getWorkflow().id;
1348
+ const activationMode = this.getActivationMode();
1349
+ console.log("[OpenClawAgentV2] trigger activation registered", {
1350
+ nodeName: node.name,
1351
+ workflowId,
1352
+ activationMode
1353
+ });
1354
+ console.log("OpenClaw publish sync: trigger activated", {
1355
+ workflowId,
1356
+ activationMode,
1357
+ nodeName: node.name
1358
+ });
1359
+ if (activationMode !== "init") {
1360
+ try {
1361
+ const nodeName = node.name;
1362
+ const aiToolParents = this.getParentNodes(nodeName, {
1363
+ includeNodeParameters: true,
1364
+ connectionType: import_n8n_workflow.NodeConnectionTypes.AiTool,
1365
+ depth: 1
1366
+ });
1367
+ const aiChannelParents = this.getParentNodes(nodeName, {
1368
+ includeNodeParameters: true,
1369
+ connectionType: import_n8n_workflow.NodeConnectionTypes.AiChannel,
1370
+ depth: 1
1371
+ });
1372
+ console.log("OpenClaw publish sync: discovered AI tool config sub-nodes", {
1373
+ count: aiToolParents.length,
1374
+ nodes: aiToolParents.map((p) => ({
1375
+ name: p.name,
1376
+ type: p.type,
1377
+ params: p.parameters ? Object.keys(p.parameters) : []
1378
+ }))
1379
+ });
1380
+ console.log("OpenClaw publish sync: discovered AI channel config sub-nodes", {
1381
+ count: aiChannelParents.length,
1382
+ nodes: aiChannelParents.map((p) => ({
1383
+ name: p.name,
1384
+ type: p.type,
1385
+ params: p.parameters ? Object.keys(p.parameters) : [],
1386
+ hasCredentials: !!p.credentials
1387
+ }))
1388
+ });
1389
+ const activationVariables = getActivationVariables(this);
1390
+ const publishChannelConfigs = [];
1391
+ for (const channelNode of aiChannelParents) {
1392
+ const params = channelNode.parameters ?? {};
1393
+ const channelNodeName = channelNode.name;
1394
+ if (channelNode.type !== OPENCLAW_TELEGRAM_CHANNEL_NODE_TYPE) {
1395
+ console.log("OpenClaw publish sync: skipping unsupported channel sub-node", {
1396
+ nodeName: channelNodeName,
1397
+ type: channelNode.type
1398
+ });
1399
+ continue;
1400
+ }
1401
+ const accountId = normalizeOptionalString(
1402
+ resolvePublishParameterValue(params.accountId, activationVariables)
1403
+ ) ?? void 0;
1404
+ const dmPolicy = normalizeOptionalString(
1405
+ resolvePublishParameterValue(params.dmPolicy, activationVariables)
1406
+ ) ?? "pairing";
1407
+ const groupPolicy = normalizeOptionalString(
1408
+ resolvePublishParameterValue(params.groupPolicy, activationVariables)
1409
+ ) ?? "allowlist";
1410
+ const allowFrom = getPublishAllowFrom({
1411
+ rawValue: params.allowFrom,
1412
+ variables: activationVariables,
1413
+ nodeName: channelNodeName,
1414
+ accountId: accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID
1415
+ });
1416
+ publishChannelConfigs.push({
1417
+ channelType: "telegram",
1418
+ accountId,
1419
+ dmPolicy,
1420
+ groupPolicy,
1421
+ allowFrom
1422
+ });
1423
+ console.log("OpenClaw publish sync: prepared Telegram channel config", {
1424
+ nodeName: channelNodeName,
1425
+ accountId: accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
1426
+ dmPolicy,
1427
+ groupPolicy,
1428
+ allowFromCount: allowFrom?.length
1429
+ });
1430
+ }
1431
+ const publishPluginConfigs = [];
1432
+ const publishMcpServerConfigs = [];
1433
+ for (const pluginNode of aiToolParents) {
1434
+ const params = pluginNode.parameters ?? {};
1435
+ const mcpServerConfig = getMcpServerConfigFromParameters(
1436
+ params
1437
+ );
1438
+ if (mcpServerConfig.config) {
1439
+ console.log("OpenClaw publish sync: processing MCP Server sub-node", {
1440
+ type: pluginNode.type,
1441
+ serverName: mcpServerConfig.config.serverName,
1442
+ url: mcpServerConfig.config.url,
1443
+ transport: mcpServerConfig.config.transport ?? "(openclaw-default)",
1444
+ headerKeys: mcpServerConfig.config.headers ? Object.keys(mcpServerConfig.config.headers) : []
1445
+ });
1446
+ publishMcpServerConfigs.push(mcpServerConfig.config);
1447
+ continue;
1448
+ } else if (mcpServerConfig.reason !== "not-mcp-server-node") {
1449
+ console.log("OpenClaw publish sync: skipping MCP Server sub-node", {
1450
+ type: pluginNode.type,
1451
+ reason: mcpServerConfig.reason,
1452
+ params: JSON.stringify(params).slice(0, 300)
1453
+ });
1454
+ continue;
1455
+ }
1456
+ const pluginSource = params.pluginSource || "local";
1457
+ console.log("OpenClaw publish sync: processing plugin sub-node", {
1458
+ type: pluginNode.type,
1459
+ pluginSource,
1460
+ params: JSON.stringify(params).slice(0, 300)
1461
+ });
1462
+ if (pluginSource === "local") {
1463
+ let pluginDirectory = params.pluginDirectory || "";
1464
+ if (pluginDirectory.includes("$workspace.__dirPath") || pluginDirectory.includes("$workspace[")) {
1465
+ const workflowObj = this.workflow;
1466
+ const dirPath = normalizeOptionalString(workflowObj?.workspace?.__dirPath);
1467
+ console.log("OpenClaw publish sync: resolving $workspace.__dirPath expression", {
1468
+ rawValue: pluginDirectory,
1469
+ workspaceAvailable: !!workflowObj?.workspace,
1470
+ dirPath: dirPath ?? "(not set)"
1471
+ });
1472
+ if (dirPath) {
1473
+ pluginDirectory = dirPath;
1474
+ } else {
1475
+ console.log(
1476
+ "OpenClaw publish sync: $workspace.__dirPath is not available, skipping"
1477
+ );
1478
+ continue;
1479
+ }
1480
+ } else if (pluginDirectory.includes("{{") || pluginDirectory.startsWith("=")) {
1481
+ console.log(
1482
+ "OpenClaw publish sync: pluginDirectory is an unresolvable expression, skipping",
1483
+ {
1484
+ rawValue: pluginDirectory
1485
+ }
1486
+ );
1487
+ continue;
1488
+ }
1489
+ pluginDirectory = pluginDirectory.trim();
1490
+ if (!pluginDirectory) {
1491
+ console.log("OpenClaw publish sync: pluginDirectory is empty, skipping");
1492
+ continue;
1493
+ }
1494
+ const manifestPath = (0, import_path.join)(pluginDirectory, "openclaw.plugin.json");
1495
+ let pluginManifest;
1496
+ if ((0, import_fs.existsSync)(manifestPath)) {
1497
+ try {
1498
+ const raw = (0, import_fs.readFileSync)(manifestPath, "utf8").trim();
1499
+ const parsed = JSON.parse(raw);
1500
+ pluginManifest = {
1501
+ id: typeof parsed.id === "string" ? parsed.id : void 0,
1502
+ name: typeof parsed.name === "string" ? parsed.name : void 0,
1503
+ description: typeof parsed.description === "string" ? parsed.description : void 0,
1504
+ version: typeof parsed.version === "string" ? parsed.version : void 0,
1505
+ providers: Array.isArray(parsed.providers) ? parsed.providers.filter(
1506
+ (p) => typeof p === "string"
1507
+ ) : void 0,
1508
+ channels: Array.isArray(parsed.channels) ? parsed.channels.filter(
1509
+ (c) => typeof c === "string"
1510
+ ) : void 0
1511
+ };
1512
+ console.log("OpenClaw publish sync: loaded local manifest", {
1513
+ manifestPath,
1514
+ id: pluginManifest.id,
1515
+ name: pluginManifest.name
1516
+ });
1517
+ } catch (parseErr) {
1518
+ console.log("OpenClaw publish sync: failed to parse manifest", {
1519
+ manifestPath,
1520
+ error: getErrorMessage(parseErr)
1521
+ });
1522
+ }
1523
+ }
1524
+ publishPluginConfigs.push({
1525
+ pluginSource: "local",
1526
+ pluginPath: pluginDirectory,
1527
+ pluginManifest
1528
+ });
1529
+ } else if (pluginSource === "cloud") {
1530
+ const pluginId = (params.pluginId || "").trim();
1531
+ const pluginVersion = (params.pluginVersion || "").trim() || void 0;
1532
+ if (pluginId) {
1533
+ publishPluginConfigs.push({
1534
+ pluginSource: "cloud",
1535
+ pluginId,
1536
+ pluginVersion
1537
+ });
1538
+ }
1539
+ }
1540
+ }
1541
+ if (publishPluginConfigs.length > 0) {
1542
+ try {
1543
+ const syncResult = syncPluginConfig({ pluginConfigs: publishPluginConfigs });
1544
+ console.log("OpenClaw publish sync: plugin config synced on activation", {
1545
+ installedCount: syncResult.installed.length,
1546
+ installed: syncResult.installed,
1547
+ errors: syncResult.errors.length > 0 ? syncResult.errors : void 0,
1548
+ pluginCount: publishPluginConfigs.length
1549
+ });
1550
+ } catch (syncErr) {
1551
+ console.log("OpenClaw publish sync: plugin config sync failed on activation", {
1552
+ error: getErrorMessage(syncErr)
1553
+ });
1554
+ }
1555
+ } else {
1556
+ console.log("OpenClaw publish sync: no plugin configs to sync on activation");
1557
+ }
1558
+ if (publishChannelConfigs.length > 0) {
1559
+ for (const channelConfig of publishChannelConfigs) {
1560
+ try {
1561
+ const syncResult = syncChannelConfig({
1562
+ channelType: channelConfig.channelType,
1563
+ replyAccount: channelConfig.accountId,
1564
+ dmPolicy: channelConfig.dmPolicy,
1565
+ groupPolicy: channelConfig.groupPolicy,
1566
+ allowFrom: channelConfig.allowFrom
1567
+ });
1568
+ console.log("OpenClaw publish sync: channel config synced on activation", {
1569
+ channelType: channelConfig.channelType,
1570
+ changed: syncResult.changed,
1571
+ configPath: syncResult.configPath,
1572
+ targetPath: syncResult.targetPath,
1573
+ accountId: syncResult.accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
1574
+ allowFromCount: channelConfig.allowFrom?.length,
1575
+ allowFromStorePath: syncResult.allowFromStorePath
1576
+ });
1577
+ } catch (syncErr) {
1578
+ console.log("OpenClaw publish sync: channel config sync failed on activation", {
1579
+ channelType: channelConfig.channelType,
1580
+ error: getErrorMessage(syncErr)
1581
+ });
1582
+ }
1583
+ }
1584
+ } else {
1585
+ console.log("OpenClaw publish sync: no channel configs to sync on activation");
1586
+ }
1587
+ if (publishMcpServerConfigs.length > 0) {
1588
+ try {
1589
+ const syncResult = syncMcpServerConfig({
1590
+ mcpServerConfigs: publishMcpServerConfigs
1591
+ });
1592
+ console.log("OpenClaw publish sync: MCP Server config synced on activation", {
1593
+ changed: syncResult.changed,
1594
+ configPath: syncResult.configPath,
1595
+ synced: syncResult.synced,
1596
+ skipped: syncResult.skipped.length > 0 ? syncResult.skipped : void 0,
1597
+ serverCount: publishMcpServerConfigs.length
1598
+ });
1599
+ } catch (syncErr) {
1600
+ console.log("OpenClaw publish sync: MCP Server config sync failed on activation", {
1601
+ error: getErrorMessage(syncErr)
1602
+ });
1603
+ }
1604
+ } else {
1605
+ console.log("OpenClaw publish sync: no MCP Server configs to sync on activation");
1606
+ }
1607
+ } catch (publishErr) {
1608
+ console.log("OpenClaw publish sync: activation-time config sync failed (non-fatal)", {
1609
+ error: getErrorMessage(publishErr)
1610
+ });
1611
+ }
1612
+ }
1613
+ return {
1614
+ closeFunction: async () => {
1615
+ console.log("[OpenClawAgentV2] trigger activation closed", {
1616
+ nodeName: node.name,
1617
+ workflowId
1618
+ });
1619
+ console.log("OpenClaw publish sync: trigger deactivated", {
1620
+ workflowId,
1621
+ nodeName: node.name
1622
+ });
1623
+ }
1624
+ };
1625
+ }
1626
+ async execute() {
1627
+ const items = this.getInputData();
1628
+ const returnData = [];
1629
+ console.log("OpenClaw publish sync: execute started", {
1630
+ itemCount: items.length,
1631
+ nodeName: this.getNode().name,
1632
+ workflowId: this.getWorkflow().id
1633
+ });
1634
+ let channelConfigs = [];
1635
+ try {
1636
+ const channelData = await this.getInputConnectionData(import_n8n_workflow.NodeConnectionTypes.AiChannel, 0);
1637
+ if (Array.isArray(channelData)) {
1638
+ channelConfigs = channelData;
1639
+ } else if (channelData && isObject(channelData)) {
1640
+ channelConfigs = [channelData];
1641
+ }
1642
+ console.log("OpenClaw publish sync: resolved channel candidates", {
1643
+ channelCount: channelConfigs.length,
1644
+ channelTypes: channelConfigs.map((c) => c.channelType),
1645
+ channels: channelConfigs.map((channelConfig) => ({
1646
+ channelType: channelConfig.channelType,
1647
+ accountId: channelConfig.accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
1648
+ dmPolicy: channelConfig.dmPolicy,
1649
+ groupPolicy: channelConfig.groupPolicy,
1650
+ allowFromCount: channelConfig.allowFrom?.length
1651
+ }))
1652
+ });
1653
+ } catch {
1654
+ console.log("OpenClaw publish sync: no channels connected");
1655
+ }
1656
+ let modelConfig;
1657
+ try {
1658
+ const modelData = await this.getInputConnectionData(import_n8n_workflow.NodeConnectionTypes.AiLanguageModel, 0);
1659
+ console.log("[OpenClawAgentV2] Raw model data from getInputConnectionData", {
1660
+ type: typeof modelData,
1661
+ isArray: Array.isArray(modelData),
1662
+ isObject: isObject(modelData),
1663
+ constructorName: modelData && typeof modelData === "object" ? modelData.constructor?.name : void 0,
1664
+ keys: modelData && typeof modelData === "object" && !Array.isArray(modelData) ? Object.keys(modelData) : void 0,
1665
+ preview: getModelDataPreview(modelData)
1666
+ });
1667
+ let candidate = modelData;
1668
+ if (Array.isArray(modelData) && modelData.length > 0) {
1669
+ candidate = modelData[0];
1670
+ console.log("[OpenClawAgentV2] Model data was array, using first element", {
1671
+ arrayLength: modelData.length,
1672
+ elementType: typeof candidate
1673
+ });
1674
+ }
1675
+ if (candidate && isObject(candidate) && typeof candidate.modelId === "string") {
1676
+ modelConfig = candidate;
1677
+ console.log("[OpenClawAgentV2] Model sub-node connected", {
1678
+ modelId: modelConfig.modelId,
1679
+ modelSource: modelConfig.modelSource,
1680
+ extraKeys: getObjectKeys(modelConfig.extra),
1681
+ baseUrl: normalizeOptionalString(modelConfig.extra?.baseUrl),
1682
+ api: normalizeOptionalString(modelConfig.extra?.api)
1683
+ });
1684
+ } else if (candidate) {
1685
+ console.log("[OpenClawAgentV2] Model data received but does not match ModelConfig shape", {
1686
+ candidateType: typeof candidate,
1687
+ isObj: isObject(candidate),
1688
+ hasModelId: isObject(candidate) ? typeof candidate.modelId : "n/a",
1689
+ candidateKeys: isObject(candidate) ? Object.keys(candidate) : [],
1690
+ candidatePreview: getModelDataPreview(candidate)
1691
+ });
1692
+ }
1693
+ } catch (err) {
1694
+ console.log("[OpenClawAgentV2] No Model sub-node connected, using text parameter fallback", {
1695
+ error: err instanceof Error ? err.message : String(err)
1696
+ });
1697
+ }
1698
+ console.log("OpenClaw publish sync: resolved model sync candidates", {
1699
+ hasModelSubNode: !!modelConfig,
1700
+ modelId: modelConfig?.modelId,
1701
+ modelSource: modelConfig?.modelSource ?? "none"
1702
+ });
1703
+ let pluginConfigs = [];
1704
+ let mcpServerConfigs = [];
1705
+ console.log("[OpenClawAgentV2] About to retrieve OpenClaw AiTool sub-node data");
1706
+ try {
1707
+ const pluginData = await this.getInputConnectionData(import_n8n_workflow.NodeConnectionTypes.AiTool, 0);
1708
+ console.log("[OpenClawAgentV2] Raw AiTool data from getInputConnectionData", {
1709
+ type: typeof pluginData,
1710
+ isNull: pluginData === null,
1711
+ isUndefined: pluginData === void 0,
1712
+ isArray: Array.isArray(pluginData),
1713
+ isObject: isObject(pluginData),
1714
+ preview: pluginData ? JSON.stringify(pluginData).slice(0, 500) : "(empty)"
1715
+ });
1716
+ const isPluginConfig = (item) => isObject(item) && typeof item.pluginSource === "string";
1717
+ const isMcpServerConfig = (item) => isObject(item) && item.mcpServerSource === "openclaw" && typeof item.serverName === "string" && typeof item.url === "string";
1718
+ if (Array.isArray(pluginData)) {
1719
+ pluginConfigs = pluginData.filter(isPluginConfig);
1720
+ mcpServerConfigs = pluginData.filter(isMcpServerConfig);
1721
+ } else if (pluginData && isPluginConfig(pluginData)) {
1722
+ pluginConfigs = [pluginData];
1723
+ } else if (pluginData && isMcpServerConfig(pluginData)) {
1724
+ mcpServerConfigs = [pluginData];
1725
+ }
1726
+ if (pluginConfigs.length > 0) {
1727
+ console.log("[OpenClawAgentV2] Plugin sub-nodes connected", {
1728
+ count: pluginConfigs.length,
1729
+ plugins: pluginConfigs.map((p) => ({
1730
+ source: p.pluginSource,
1731
+ path: p.pluginPath,
1732
+ manifestId: p.pluginManifest?.id,
1733
+ manifestName: p.pluginManifest?.name,
1734
+ cloudId: p.pluginId,
1735
+ cloudVersion: p.pluginVersion
1736
+ }))
1737
+ });
1738
+ } else {
1739
+ console.log("[OpenClawAgentV2] No valid Plugin sub-nodes connected");
1740
+ }
1741
+ if (mcpServerConfigs.length > 0) {
1742
+ console.log("[OpenClawAgentV2] MCP Server sub-nodes connected", {
1743
+ count: mcpServerConfigs.length,
1744
+ servers: mcpServerConfigs.map((server) => ({
1745
+ serverName: server.serverName,
1746
+ url: server.url,
1747
+ transport: server.transport ?? "(openclaw-default)",
1748
+ headerKeys: server.headers ? Object.keys(server.headers) : [],
1749
+ connectionTimeoutMs: server.connectionTimeoutMs
1750
+ }))
1751
+ });
1752
+ } else {
1753
+ console.log("[OpenClawAgentV2] No valid MCP Server sub-nodes connected");
1754
+ }
1755
+ } catch (pluginErr) {
1756
+ console.log("[OpenClawAgentV2] OpenClaw AiTool sub-node connection FAILED", {
1757
+ errorType: pluginErr instanceof Error ? pluginErr.constructor.name : typeof pluginErr,
1758
+ errorMessage: pluginErr instanceof Error ? pluginErr.message : String(pluginErr),
1759
+ errorStack: pluginErr instanceof Error ? pluginErr.stack?.split("\n").slice(0, 5).join("\n") : void 0
1760
+ });
1761
+ console.log(
1762
+ "[OpenClawAgentV2] No Plugin or MCP Server sub-nodes connected (AiTool input error)"
1763
+ );
1764
+ }
1765
+ console.log("OpenClaw publish sync: resolved plugin sync candidates", {
1766
+ pluginCount: pluginConfigs.length,
1767
+ localCount: pluginConfigs.filter((p) => p.pluginSource === "local").length,
1768
+ cloudCount: pluginConfigs.filter((p) => p.pluginSource === "cloud").length,
1769
+ manifestIds: pluginConfigs.filter((p) => p.pluginManifest?.id).map((p) => p.pluginManifest?.id),
1770
+ cloudIds: pluginConfigs.filter((p) => p.pluginId).map((p) => p.pluginId)
1771
+ });
1772
+ console.log("OpenClaw publish sync: resolved MCP Server sync candidates", {
1773
+ serverCount: mcpServerConfigs.length,
1774
+ serverNames: mcpServerConfigs.map((server) => server.serverName),
1775
+ transports: mcpServerConfigs.map((server) => server.transport ?? "(openclaw-default)")
1776
+ });
1777
+ if (mcpServerConfigs.length > 0) {
1778
+ try {
1779
+ const syncResult = syncMcpServerConfig({ mcpServerConfigs });
1780
+ console.log("OpenClaw publish sync: MCP Server config sync completed before execute", {
1781
+ changed: syncResult.changed,
1782
+ configPath: syncResult.configPath,
1783
+ synced: syncResult.synced,
1784
+ skipped: syncResult.skipped.length > 0 ? syncResult.skipped : void 0
1785
+ });
1786
+ } catch (mcpSyncErr) {
1787
+ console.log("OpenClaw publish sync: MCP Server config sync failed before execute", {
1788
+ error: getErrorMessage(mcpSyncErr)
1789
+ });
1790
+ }
1791
+ }
1792
+ for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
1793
+ try {
1794
+ const message = normalizeOptionalString(this.getNodeParameter("message", itemIndex));
1795
+ if (!message) {
1796
+ throw new import_n8n_workflow.NodeOperationError(this.getNode(), "Message must not be empty", { itemIndex });
1797
+ }
1798
+ const openClawEnv = {};
1799
+ if (pluginConfigs.length > 0) {
1800
+ const localPlugins = pluginConfigs.filter((p) => p.pluginSource === "local");
1801
+ const cloudPlugins = pluginConfigs.filter((p) => p.pluginSource === "cloud");
1802
+ const pluginPaths = localPlugins.map((p) => p.pluginPath).filter((p) => typeof p === "string" && p.length > 0);
1803
+ const cloudSpecs = cloudPlugins.map((p) => {
1804
+ if (!p.pluginId) return void 0;
1805
+ return p.pluginVersion ? `clawhub:${p.pluginId}@${p.pluginVersion}` : `clawhub:${p.pluginId}`;
1806
+ }).filter((s) => typeof s === "string");
1807
+ if (pluginPaths.length > 0) {
1808
+ openClawEnv.OPENCLAW_PLUGIN_PATHS = pluginPaths.join(";");
1809
+ console.log("[OpenClawAgentV2] Set OPENCLAW_PLUGIN_PATHS env var", {
1810
+ itemIndex,
1811
+ value: openClawEnv.OPENCLAW_PLUGIN_PATHS
1812
+ });
1813
+ }
1814
+ if (cloudSpecs.length > 0) {
1815
+ openClawEnv.OPENCLAW_CLAWHUB_PLUGINS = cloudSpecs.join(";");
1816
+ console.log("[OpenClawAgentV2] Set OPENCLAW_CLAWHUB_PLUGINS env var", {
1817
+ itemIndex,
1818
+ value: openClawEnv.OPENCLAW_CLAWHUB_PLUGINS
1819
+ });
1820
+ }
1821
+ }
1822
+ const telegramChannel = channelConfigs.find((c) => c.channelType === "telegram");
1823
+ const primaryChannel = channelConfigs[0];
1824
+ if (telegramChannel?.botToken) {
1825
+ openClawEnv.TELEGRAM_BOT_TOKEN = telegramChannel.botToken;
1826
+ const telegramSync = syncChannelConfig({
1827
+ channelType: "telegram",
1828
+ botToken: telegramChannel.botToken,
1829
+ replyAccount: telegramChannel.accountId,
1830
+ dmPolicy: telegramChannel.dmPolicy,
1831
+ groupPolicy: telegramChannel.groupPolicy,
1832
+ allowFrom: telegramChannel.allowFrom ?? []
1833
+ });
1834
+ console.log("OpenClaw publish sync: Telegram channel config synced", {
1835
+ itemIndex,
1836
+ changed: telegramSync.changed,
1837
+ configPath: telegramSync.configPath,
1838
+ targetPath: telegramSync.targetPath,
1839
+ accountId: telegramSync.accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID,
1840
+ allowFromCount: telegramChannel.allowFrom?.length ?? 0,
1841
+ allowFromStorePath: telegramSync.allowFromStorePath
1842
+ });
1843
+ }
1844
+ const whatsappChannel = channelConfigs.find((c) => c.channelType === "whatsapp");
1845
+ if (whatsappChannel?.accessToken) {
1846
+ openClawEnv.WHATSAPP_ACCESS_TOKEN = whatsappChannel.accessToken;
1847
+ if (whatsappChannel.phoneNumberId) {
1848
+ openClawEnv.WHATSAPP_PHONE_NUMBER_ID = whatsappChannel.phoneNumberId;
1849
+ }
1850
+ const whatsappSync = syncChannelConfig({
1851
+ channelType: "whatsapp",
1852
+ botToken: whatsappChannel.accessToken,
1853
+ replyAccount: whatsappChannel.accountId
1854
+ });
1855
+ console.log("OpenClaw publish sync: WhatsApp channel config synced", {
1856
+ itemIndex,
1857
+ changed: whatsappSync.changed,
1858
+ configPath: whatsappSync.configPath,
1859
+ targetPath: whatsappSync.targetPath,
1860
+ accountId: whatsappSync.accountId ?? OPENCLAW_DEFAULT_ACCOUNT_ID
1861
+ });
1862
+ }
1863
+ console.log("OpenClaw publish sync: channel config sync completed", {
1864
+ itemIndex,
1865
+ hasTelegram: !!telegramChannel,
1866
+ hasWhatsApp: !!whatsappChannel,
1867
+ channelCount: channelConfigs.length
1868
+ });
1869
+ let args = ["agent", "--message", message, "--json"];
1870
+ let processTimeoutMs;
1871
+ const gatewayParams = {
1872
+ message,
1873
+ idempotencyKey: (0, import_crypto.randomUUID)()
1874
+ };
1875
+ const selectorType = this.getNodeParameter("selectorType", itemIndex);
1876
+ if (selectorType !== "default") {
1877
+ const parameterName = selectorTypeToParameterName[selectorType];
1878
+ const value = normalizeOptionalString(this.getNodeParameter(parameterName, itemIndex));
1879
+ if (!value) {
1880
+ throw new import_n8n_workflow.NodeOperationError(
1881
+ this.getNode(),
1882
+ `${parameterName} must not be empty when Route By is ${selectorType}`,
1883
+ { itemIndex }
1884
+ );
1885
+ }
1886
+ args.push(selectorTypeToCliFlag[selectorType], value);
1887
+ if (selectorType === "agent") {
1888
+ gatewayParams.agentId = value;
1889
+ } else if (selectorType === "sessionId") {
1890
+ gatewayParams.sessionId = value;
1891
+ } else {
1892
+ gatewayParams.to = value;
1893
+ }
1894
+ }
1895
+ const resolvedModel = modelConfig?.modelId;
1896
+ console.log("[OpenClawAgentV2] Model resolution", {
1897
+ itemIndex,
1898
+ connectedModel: modelConfig?.modelId,
1899
+ resolvedModel,
1900
+ modelSource: modelConfig?.modelSource ?? "none"
1901
+ });
1902
+ if (resolvedModel) {
1903
+ args.push("--model", resolvedModel);
1904
+ gatewayParams.model = resolvedModel;
1905
+ }
1906
+ const openCodeFreeAuth = applyOpenCodeFreeAuthEnv({
1907
+ env: openClawEnv,
1908
+ modelConfig,
1909
+ modelId: resolvedModel
1910
+ });
1911
+ console.log("[OpenClawAgentV2] OpenCode free auth env resolution", {
1912
+ itemIndex,
1913
+ resolvedModel,
1914
+ modelSource: modelConfig?.modelSource ?? "text-parameter",
1915
+ applied: openCodeFreeAuth.applied,
1916
+ envVar: openCodeFreeAuth.envVar,
1917
+ reason: openCodeFreeAuth.reason
1918
+ });
1919
+ const nineRouterConfigSync = syncNineRouterModelConfig({
1920
+ modelConfig,
1921
+ modelId: resolvedModel
1922
+ });
1923
+ console.log("[OpenClawAgentV2] 9Router model config sync", {
1924
+ itemIndex,
1925
+ hasModelSubNode: !!modelConfig,
1926
+ resolvedModel,
1927
+ modelSource: modelConfig?.modelSource ?? "text-parameter",
1928
+ selectorType,
1929
+ changed: nineRouterConfigSync.changed,
1930
+ reason: nineRouterConfigSync.reason,
1931
+ targetPath: nineRouterConfigSync.targetPath,
1932
+ modelRef: nineRouterConfigSync.modelRef,
1933
+ configPath: nineRouterConfigSync.configPath,
1934
+ existingBaseUrl: nineRouterConfigSync.existingBaseUrl,
1935
+ restart: "publish-only"
1936
+ });
1937
+ console.log("OpenClaw publish sync: model config sync completed", {
1938
+ itemIndex,
1939
+ resolvedModel,
1940
+ modelSource: modelConfig?.modelSource ?? "text-parameter",
1941
+ syncChanged: nineRouterConfigSync.changed,
1942
+ syncReason: nineRouterConfigSync.reason
1943
+ });
1944
+ const thinking = normalizeOptionalString(this.getNodeParameter("thinking", itemIndex));
1945
+ if (thinking) {
1946
+ args.push("--thinking", thinking);
1947
+ gatewayParams.thinking = thinking;
1948
+ }
1949
+ const runLocally = this.getNodeParameter("local", itemIndex, false) === true;
1950
+ if (runLocally) args.push("--local");
1951
+ const deliverReply = this.getNodeParameter("deliver", itemIndex, false) === true;
1952
+ if (deliverReply) {
1953
+ args.push("--deliver");
1954
+ gatewayParams.deliver = true;
1955
+ }
1956
+ const timeout = Number(
1957
+ this.getNodeParameter("options.timeout", itemIndex, DEFAULT_TIMEOUT_SECONDS)
1958
+ );
1959
+ const timeoutSeconds = Number.isFinite(timeout) && timeout > 0 ? Math.floor(timeout) : DEFAULT_TIMEOUT_SECONDS;
1960
+ args.push("--timeout", String(timeoutSeconds));
1961
+ gatewayParams.timeout = timeoutSeconds;
1962
+ if (deliverReply && primaryChannel) {
1963
+ const replyChannel = primaryChannel.channelType;
1964
+ args.push("--reply-channel", replyChannel);
1965
+ gatewayParams.replyChannel = replyChannel;
1966
+ if (primaryChannel.accountId) {
1967
+ args.push("--reply-account", primaryChannel.accountId);
1968
+ gatewayParams.replyAccountId = primaryChannel.accountId;
1969
+ }
1970
+ }
1971
+ const verbose = normalizeOptionalString(
1972
+ this.getNodeParameter("options.verbose", itemIndex, "")
1973
+ );
1974
+ if (verbose) args.push("--verbose", verbose);
1975
+ const binaryPath = normalizeOptionalString(this.getNodeParameter("options.binaryPath", itemIndex, "")) ?? "openclaw";
1976
+ const workingDirectory = normalizeOptionalString(
1977
+ this.getNodeParameter("options.workingDirectory", itemIndex, "")
1978
+ );
1979
+ if (workingDirectory && (!(0, import_fs.existsSync)(workingDirectory) || !(0, import_fs.statSync)(workingDirectory).isDirectory())) {
1980
+ throw new import_n8n_workflow.NodeOperationError(
1981
+ this.getNode(),
1982
+ `Working directory does not exist or is not a directory: ${workingDirectory}`,
1983
+ { itemIndex }
1984
+ );
1985
+ }
1986
+ const systemMessage = normalizeOptionalString(
1987
+ this.getNodeParameter("options.systemMessage", itemIndex, "")
1988
+ );
1989
+ if (systemMessage) {
1990
+ if (runLocally) {
1991
+ throw new import_n8n_workflow.NodeOperationError(
1992
+ this.getNode(),
1993
+ "System Message is only supported in OpenClaw Gateway mode. Disable Run Locally to use it.",
1994
+ { itemIndex }
1995
+ );
1996
+ }
1997
+ gatewayParams.extraSystemPrompt = systemMessage;
1998
+ const rpcTimeoutMs = getWatchdogTimeoutMs(timeoutSeconds);
1999
+ args = getGatewayCallArgs(gatewayParams, rpcTimeoutMs);
2000
+ processTimeoutMs = rpcTimeoutMs + 1e4;
2001
+ }
2002
+ console.log("OpenClaw publish sync: launching CLI", {
2003
+ itemIndex,
2004
+ binaryPath,
2005
+ argCount: args.length,
2006
+ cwd: workingDirectory ?? "(default)",
2007
+ envKeys: Object.keys(openClawEnv),
2008
+ resolvedModel,
2009
+ pluginCount: pluginConfigs.length,
2010
+ mcpServerCount: mcpServerConfigs.length,
2011
+ channelCount: channelConfigs.length
2012
+ });
2013
+ const result = await runOpenClawCli({
2014
+ binaryPath,
2015
+ args,
2016
+ cwd: workingDirectory,
2017
+ timeoutMs: processTimeoutMs ?? getWatchdogTimeoutMs(timeoutSeconds),
2018
+ env: openClawEnv,
2019
+ abortSignal: this.getExecutionCancelSignal()
2020
+ });
2021
+ console.log("OpenClaw publish sync: CLI execution completed", {
2022
+ itemIndex,
2023
+ exitCode: result.exitCode,
2024
+ signal: result.signal,
2025
+ stdoutLength: result.stdout.length,
2026
+ stderrLength: result.stderr.length
2027
+ });
2028
+ if (result.exitCode !== 0) {
2029
+ throw new import_n8n_workflow.NodeOperationError(
2030
+ this.getNode(),
2031
+ result.stderr.trim() || result.stdout.trim() || `OpenClaw CLI exited with code ${result.exitCode ?? `signal ${result.signal}`}`,
2032
+ { itemIndex }
2033
+ );
2034
+ }
2035
+ const json = parseOpenClawOutput(result.stdout);
2036
+ json.command = result.command;
2037
+ if (this.getNodeParameter("options.includeRawOutput", itemIndex, false) === true) {
2038
+ json.rawOutput = { stdout: result.stdout, stderr: result.stderr };
2039
+ }
2040
+ returnData.push({ json, pairedItem: { item: itemIndex } });
2041
+ } catch (error) {
2042
+ if (this.continueOnFail()) {
2043
+ returnData.push({
2044
+ json: { error: getErrorMessage(error) },
2045
+ pairedItem: { item: itemIndex }
2046
+ });
2047
+ continue;
2048
+ }
2049
+ throw error;
2050
+ }
2051
+ }
2052
+ return [returnData];
2053
+ }
2054
+ }
2055
+ // Annotate the CommonJS export names for ESM import in node:
2056
+ 0 && (module.exports = {
2057
+ OpenClawAgentV2
2058
+ });
2059
+ //# sourceMappingURL=OpenClawAgentV2.node.js.map