@synap-core/eve 0.1.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.
Files changed (64) hide show
  1. package/README.md +251 -0
  2. package/dist/add-R6RGUYER.js +22 -0
  3. package/dist/add-R6RGUYER.js.map +1 -0
  4. package/dist/auth-7FFZNARZ-4OIRGZ7R.js +31 -0
  5. package/dist/auth-7FFZNARZ-4OIRGZ7R.js.map +1 -0
  6. package/dist/chunk-22RIHU4J.js +975 -0
  7. package/dist/chunk-22RIHU4J.js.map +1 -0
  8. package/dist/chunk-23XQDB7K.js +1773 -0
  9. package/dist/chunk-23XQDB7K.js.map +1 -0
  10. package/dist/chunk-5TBV2VHZ.js +6067 -0
  11. package/dist/chunk-5TBV2VHZ.js.map +1 -0
  12. package/dist/chunk-D7P3IYYR.js +44 -0
  13. package/dist/chunk-D7P3IYYR.js.map +1 -0
  14. package/dist/chunk-EHPC7CKE.js +757 -0
  15. package/dist/chunk-EHPC7CKE.js.map +1 -0
  16. package/dist/chunk-FAE5UZFE.js +17 -0
  17. package/dist/chunk-FAE5UZFE.js.map +1 -0
  18. package/dist/chunk-HRF6TNXX.js +53 -0
  19. package/dist/chunk-HRF6TNXX.js.map +1 -0
  20. package/dist/chunk-HVJEW7TU.js +495 -0
  21. package/dist/chunk-HVJEW7TU.js.map +1 -0
  22. package/dist/chunk-JO5H5G6U.js +1529 -0
  23. package/dist/chunk-JO5H5G6U.js.map +1 -0
  24. package/dist/chunk-MUEQNBE6.js +1140 -0
  25. package/dist/chunk-MUEQNBE6.js.map +1 -0
  26. package/dist/chunk-O5WTCVMZ.js +3391 -0
  27. package/dist/chunk-O5WTCVMZ.js.map +1 -0
  28. package/dist/chunk-ROKIQIEX.js +65 -0
  29. package/dist/chunk-ROKIQIEX.js.map +1 -0
  30. package/dist/chunk-T7GCAJK5.js +4895 -0
  31. package/dist/chunk-T7GCAJK5.js.map +1 -0
  32. package/dist/chunk-UOQWJ3S4.js +138 -0
  33. package/dist/chunk-UOQWJ3S4.js.map +1 -0
  34. package/dist/chunk-YQWV5W4U.js +3479 -0
  35. package/dist/chunk-YQWV5W4U.js.map +1 -0
  36. package/dist/chunk-ZPDNZRVW.js +272 -0
  37. package/dist/chunk-ZPDNZRVW.js.map +1 -0
  38. package/dist/config-store-KTOWIKAS-XVZHNPKW.js +11 -0
  39. package/dist/config-store-KTOWIKAS-XVZHNPKW.js.map +1 -0
  40. package/dist/dist-2VRFSXMO.js +40 -0
  41. package/dist/dist-2VRFSXMO.js.map +1 -0
  42. package/dist/dist-C2QB4IKT.js +340 -0
  43. package/dist/dist-C2QB4IKT.js.map +1 -0
  44. package/dist/dist-DEIUVZ57.js +299 -0
  45. package/dist/dist-DEIUVZ57.js.map +1 -0
  46. package/dist/dist-DSKHGECB.js +36 -0
  47. package/dist/dist-DSKHGECB.js.map +1 -0
  48. package/dist/dist-GN2DN7CI.js +95 -0
  49. package/dist/dist-GN2DN7CI.js.map +1 -0
  50. package/dist/dist-TZL4XW2R.js +58 -0
  51. package/dist/dist-TZL4XW2R.js.map +1 -0
  52. package/dist/dist-ZP2APOYV.js +53 -0
  53. package/dist/dist-ZP2APOYV.js.map +1 -0
  54. package/dist/index.js +15083 -0
  55. package/dist/index.js.map +1 -0
  56. package/dist/operational-5RT6AZJI-ZEMPD32Q.js +12 -0
  57. package/dist/operational-5RT6AZJI-ZEMPD32Q.js.map +1 -0
  58. package/dist/reconcile-A4I3Z7VX-GQMEN4GC.js +12 -0
  59. package/dist/reconcile-A4I3Z7VX-GQMEN4GC.js.map +1 -0
  60. package/dist/rsshub-GOJBTNOD-UNNVKBFL.js +18 -0
  61. package/dist/rsshub-GOJBTNOD-UNNVKBFL.js.map +1 -0
  62. package/dist/synap-image-install-X36REYQ5-UGO4MAOP.js +17 -0
  63. package/dist/synap-image-install-X36REYQ5-UGO4MAOP.js.map +1 -0
  64. package/package.json +44 -0
@@ -0,0 +1,757 @@
1
+ import { createRequire as __eveCreateRequire } from 'module'; const require = __eveCreateRequire(import.meta.url);
2
+ import {
3
+ execa
4
+ } from "./chunk-22RIHU4J.js";
5
+ import {
6
+ resolveSynapDelegate
7
+ } from "./chunk-HVJEW7TU.js";
8
+ import {
9
+ EntityStateManager,
10
+ configureChannel,
11
+ disableChannel,
12
+ entityStateManager,
13
+ readChannelStatus,
14
+ validateChannelCredentials
15
+ } from "./chunk-5TBV2VHZ.js";
16
+ import {
17
+ resolveSynapUrl
18
+ } from "./chunk-O5WTCVMZ.js";
19
+ import {
20
+ readAgentKeyOrLegacy,
21
+ readEveSecrets,
22
+ writeEveSecrets
23
+ } from "./chunk-T7GCAJK5.js";
24
+
25
+ // ../@eve/arms/dist/index.js
26
+ import { spawn } from "child_process";
27
+ import { setTimeout } from "timers/promises";
28
+ import { createInterface } from "readline";
29
+ var OPENCLAW_CONTAINER = "eve-arms-openclaw";
30
+ var OPENCLAW_PORT = 3e3;
31
+ var OpenClawService = class {
32
+ config = {
33
+ ollamaUrl: "http://eve-brain-ollama:11434",
34
+ model: "llama3.2"
35
+ };
36
+ /**
37
+ * Install OpenClaw container
38
+ */
39
+ async install() {
40
+ console.log("\u{1F4E6} Installing OpenClaw...");
41
+ await this.runDockerCommand([
42
+ "pull",
43
+ "ghcr.io/openclaw/openclaw:latest"
44
+ ]);
45
+ console.log("\u2705 OpenClaw image pulled");
46
+ }
47
+ /**
48
+ * Configure OpenClaw to use Ollama
49
+ */
50
+ async configure(ollamaUrl) {
51
+ this.config.ollamaUrl = ollamaUrl;
52
+ console.log(`\u2699\uFE0F Configured OpenClaw to use Ollama at ${ollamaUrl}`);
53
+ }
54
+ setIntegration(integration) {
55
+ this.config.synapApiUrl = integration.synapApiUrl;
56
+ this.config.synapApiKey = integration.synapApiKey;
57
+ this.config.dokployApiUrl = integration.dokployApiUrl;
58
+ }
59
+ /**
60
+ * Configure messaging platform (Telegram, Signal, Matrix).
61
+ * Writes config and updates running container with env vars.
62
+ */
63
+ async configureMessaging(platform, config) {
64
+ console.log(`Configuring ${platform} messaging...`);
65
+ this.config.messaging = { ...this.config.messaging, enabled: true, platform, ...config };
66
+ console.log(`\u2705 ${platform} messaging configured`);
67
+ }
68
+ /**
69
+ * Configure voice/telephony (Twilio, Signal, self-hosted SIP).
70
+ */
71
+ async configureVoice(config) {
72
+ console.log("Configuring voice/telephony...");
73
+ this.config.voice = { ...this.config.voice, enabled: true, ...config };
74
+ console.log("\u2705 Voice configured");
75
+ }
76
+ /**
77
+ * Start OpenClaw container.
78
+ *
79
+ * Messaging and voice config are read from Eve secrets at start time so
80
+ * that env vars always reflect persisted configuration — not just in-memory
81
+ * state that disappears on restart.
82
+ */
83
+ async start() {
84
+ const isRunning = await this.isRunning();
85
+ if (isRunning) {
86
+ console.log("\u{1F916} OpenClaw is already running");
87
+ return;
88
+ }
89
+ console.log("\u{1F680} Starting OpenClaw...");
90
+ const secrets = await readEveSecrets().catch(() => null);
91
+ const messaging = secrets?.arms?.messaging ?? this.config.messaging;
92
+ const voice = secrets?.arms?.voice ?? this.config.voice;
93
+ await this.runDockerCommand([
94
+ "run",
95
+ "-d",
96
+ "--name",
97
+ OPENCLAW_CONTAINER,
98
+ "--network",
99
+ "eve-network",
100
+ "-p",
101
+ `${OPENCLAW_PORT}:3000`,
102
+ "-e",
103
+ `OLLAMA_URL=${this.config.ollamaUrl}`,
104
+ "-e",
105
+ `DEFAULT_MODEL=${this.config.model}`,
106
+ "-e",
107
+ `SYNAP_API_URL=${this.config.synapApiUrl ?? ""}`,
108
+ "-e",
109
+ `SYNAP_API_KEY=${this.config.synapApiKey ?? ""}`,
110
+ "-e",
111
+ `DOKPLOY_API_URL=${this.config.dokployApiUrl ?? ""}`,
112
+ "-e",
113
+ `MESSAGING_ENABLED=${messaging?.enabled ?? false}`,
114
+ "-e",
115
+ `MESSAGING_PLATFORM=${messaging?.platform ?? ""}`,
116
+ "-e",
117
+ `MESSAGING_BOT_TOKEN=${messaging?.botToken ?? ""}`,
118
+ "-e",
119
+ `VOICE_ENABLED=${voice?.enabled ?? false}`,
120
+ "-e",
121
+ `VOICE_PROVIDER=${voice?.provider ?? ""}`,
122
+ "-e",
123
+ `VOICE_PHONE_NUMBER=${voice?.phoneNumber ?? ""}`,
124
+ "-e",
125
+ `VOICE_SIP_URI=${voice?.sipUri ?? ""}`,
126
+ "-v",
127
+ "eve-arms-openclaw-data:/data",
128
+ "--restart",
129
+ "unless-stopped",
130
+ "ghcr.io/openclaw/openclaw:latest"
131
+ ]);
132
+ await setTimeout(3e3);
133
+ console.log(`\u2705 OpenClaw started on port ${OPENCLAW_PORT}`);
134
+ }
135
+ /**
136
+ * Stop OpenClaw container
137
+ */
138
+ async stop() {
139
+ const isRunning = await this.isRunning();
140
+ if (!isRunning) {
141
+ console.log("\u{1F916} OpenClaw is not running");
142
+ return;
143
+ }
144
+ console.log("\u{1F6D1} Stopping OpenClaw...");
145
+ await this.runDockerCommand(["stop", OPENCLAW_CONTAINER]);
146
+ await this.runDockerCommand(["rm", OPENCLAW_CONTAINER]);
147
+ console.log("\u2705 OpenClaw stopped");
148
+ }
149
+ /**
150
+ * Check if OpenClaw is running
151
+ */
152
+ async isRunning() {
153
+ try {
154
+ const output = await this.runDockerCommand(
155
+ ["ps", "--filter", `name=${OPENCLAW_CONTAINER}`, "--format", "{{.Names}}"],
156
+ true
157
+ );
158
+ return output.includes(OPENCLAW_CONTAINER);
159
+ } catch {
160
+ return false;
161
+ }
162
+ }
163
+ /**
164
+ * Install an MCP server
165
+ */
166
+ async installMCPServer(name, config) {
167
+ console.log(`\u{1F50C} Installing MCP server: ${name}...`);
168
+ const mcpConfig = {
169
+ mcpServers: {
170
+ [name]: config
171
+ }
172
+ };
173
+ const configJson = JSON.stringify(mcpConfig);
174
+ await this.runDockerCommand([
175
+ "exec",
176
+ OPENCLAW_CONTAINER,
177
+ "sh",
178
+ "-c",
179
+ `echo '${configJson}' > /data/mcp-${name}.json`
180
+ ]);
181
+ console.log(`\u2705 MCP server ${name} installed`);
182
+ }
183
+ /**
184
+ * List installed MCP servers
185
+ */
186
+ async listMCPServers() {
187
+ try {
188
+ const output = await this.runDockerCommand(
189
+ ["exec", OPENCLAW_CONTAINER, "ls", "/data/"],
190
+ true
191
+ );
192
+ return output.split("\n").filter((f) => f.startsWith("mcp-") && f.endsWith(".json")).map((f) => f.replace("mcp-", "").replace(".json", ""));
193
+ } catch {
194
+ return [];
195
+ }
196
+ }
197
+ /**
198
+ * Get OpenClaw status
199
+ */
200
+ async getStatus() {
201
+ const running = await this.isRunning();
202
+ return {
203
+ running,
204
+ url: `http://localhost:${OPENCLAW_PORT}`,
205
+ model: this.config.model || "llama3.2"
206
+ };
207
+ }
208
+ /**
209
+ * Run a Docker command and return output
210
+ */
211
+ runDockerCommand(args, returnOutput = false) {
212
+ return new Promise((resolve, reject) => {
213
+ const proc = spawn("docker", args, {
214
+ stdio: returnOutput ? ["ignore", "pipe", "pipe"] : "inherit"
215
+ });
216
+ let output = "";
217
+ if (returnOutput) {
218
+ proc.stdout?.on("data", (data) => {
219
+ output += data.toString();
220
+ });
221
+ }
222
+ proc.on("close", (code) => {
223
+ if (code === 0) {
224
+ resolve(output.trim());
225
+ } else {
226
+ reject(new Error(`Docker command failed with code ${code}`));
227
+ }
228
+ });
229
+ proc.on("error", reject);
230
+ });
231
+ }
232
+ };
233
+ var openclaw = new OpenClawService();
234
+ function installCommand(program) {
235
+ program.command("install").description("Install OpenClaw AI assistant").action(async () => {
236
+ try {
237
+ console.log("\u{1F9BE} Eve Arms - Installing OpenClaw...\n");
238
+ const stateManager = new EntityStateManager();
239
+ const state = await stateManager.getState();
240
+ const brainStatus = state.organs.brain;
241
+ if (brainStatus.state !== "ready") {
242
+ console.error('\u274C Brain is not ready. Please run "eve brain init" first.');
243
+ process.exit(1);
244
+ }
245
+ console.log("\u2705 Brain is ready");
246
+ const synapPod = resolveSynapDelegate();
247
+ if (synapPod) {
248
+ console.log("\u2705 Synap Data Pod detected \u2014 using synap profiles + services\n");
249
+ await execa("bash", [synapPod.synapScript, "profiles", "enable", "openclaw"], {
250
+ cwd: synapPod.repoRoot,
251
+ env: { ...process.env, SYNAP_DEPLOY_DIR: synapPod.deployDir },
252
+ stdio: "inherit"
253
+ });
254
+ await execa("bash", [synapPod.synapScript, "services", "add", "openclaw"], {
255
+ cwd: synapPod.repoRoot,
256
+ env: { ...process.env, SYNAP_DEPLOY_DIR: synapPod.deployDir, SYNAP_ASSUME_YES: "1" },
257
+ stdio: "inherit"
258
+ });
259
+ await stateManager.updateOrgan("arms", "ready");
260
+ await entityStateManager.updateComponentEntry("openclaw", {
261
+ organ: "arms",
262
+ state: "ready",
263
+ version: "0.2.0",
264
+ managedBy: "eve"
265
+ });
266
+ console.log("\n\u{1F389} OpenClaw provisioned via Synap.");
267
+ console.log(" See: synap services status openclaw");
268
+ return;
269
+ }
270
+ if (state.aiModel === "none") {
271
+ console.error('\u274C Ollama is not configured. Please run "eve brain init --with-ai" first.');
272
+ process.exit(1);
273
+ }
274
+ console.log("\u2705 Ollama is configured");
275
+ const openclaw2 = new OpenClawService();
276
+ await openclaw2.install();
277
+ const secrets = await readEveSecrets(process.cwd());
278
+ const ollamaUrl = secrets?.inference?.gatewayUrl ?? secrets?.inference?.ollamaUrl ?? "http://eve-brain-ollama:11434";
279
+ await openclaw2.configure(ollamaUrl);
280
+ const openclawSynapKey = secrets?.arms?.openclaw?.synapApiKey ?? await readAgentKeyOrLegacy("openclaw", process.cwd());
281
+ openclaw2.setIntegration({
282
+ synapApiUrl: resolveSynapUrl(secrets),
283
+ synapApiKey: openclawSynapKey,
284
+ dokployApiUrl: secrets?.builder?.dokployApiUrl
285
+ });
286
+ await openclaw2.start();
287
+ await stateManager.updateOrgan("arms", "ready");
288
+ console.log("\n\u{1F389} OpenClaw installed successfully!");
289
+ console.log(" Access it at: http://localhost:3000");
290
+ console.log("\n Next steps:");
291
+ console.log(" - eve arms mcp list # List MCP servers");
292
+ console.log(" - eve arms mcp preset # Install an MCP server preset");
293
+ console.log(" - eve arms messaging configure # Configure messaging bridge");
294
+ console.log(" - eve arms voice configure # Configure voice/telephony");
295
+ } catch (error) {
296
+ console.error("\u274C Installation failed:", error instanceof Error ? error.message : error);
297
+ process.exit(1);
298
+ }
299
+ });
300
+ }
301
+ function startCommand(program) {
302
+ program.command("start").description("Start OpenClaw AI assistant").action(async () => {
303
+ try {
304
+ console.log("\u{1F680} Starting OpenClaw...\n");
305
+ await openclaw.start();
306
+ const status = await openclaw.getStatus();
307
+ console.log("\n\u{1F389} OpenClaw is ready!");
308
+ console.log(` URL: ${status.url}`);
309
+ console.log(` Model: ${status.model}`);
310
+ } catch (error) {
311
+ console.error("\u274C Failed to start OpenClaw:", error instanceof Error ? error.message : error);
312
+ process.exit(1);
313
+ }
314
+ });
315
+ }
316
+ function stopCommand(program) {
317
+ program.command("stop").description("Stop OpenClaw AI assistant").action(async () => {
318
+ try {
319
+ console.log("\u{1F6D1} Stopping OpenClaw...\n");
320
+ await openclaw.stop();
321
+ console.log("\n\u2705 OpenClaw stopped");
322
+ } catch (error) {
323
+ console.error("\u274C Failed to stop OpenClaw:", error instanceof Error ? error.message : error);
324
+ process.exit(1);
325
+ }
326
+ });
327
+ }
328
+ function mcpCommand(program) {
329
+ const mcp = program.command("mcp").description("Manage MCP (Model Context Protocol) servers");
330
+ mcp.command("list").description("List installed MCP servers").action(async () => {
331
+ try {
332
+ const servers = await openclaw.listMCPServers();
333
+ if (servers.length === 0) {
334
+ console.log("No MCP servers installed");
335
+ console.log("\nInstall one with: eve arms mcp install <name>");
336
+ return;
337
+ }
338
+ console.log("Installed MCP servers:\n");
339
+ servers.forEach((name) => {
340
+ console.log(` \u2022 ${name}`);
341
+ });
342
+ } catch (error) {
343
+ console.error("\u274C Failed to list MCP servers:", error instanceof Error ? error.message : error);
344
+ process.exit(1);
345
+ }
346
+ });
347
+ mcp.command("install <name>").description("Install an MCP server").option("-c, --command <cmd>", "Command to run the MCP server", "npx").option("-a, --args <args>", "Arguments (comma-separated)", "-y,@modelcontextprotocol/server-filesystem").action(async (name, options) => {
348
+ try {
349
+ console.log(`\u{1F50C} Installing MCP server: ${name}...
350
+ `);
351
+ const config = {
352
+ command: options.command,
353
+ args: options.args.split(",")
354
+ };
355
+ await openclaw.installMCPServer(name, config);
356
+ console.log(`
357
+ \u2705 MCP server "${name}" installed`);
358
+ console.log(" Restart OpenClaw to apply changes:");
359
+ console.log(" eve arms stop && eve arms start");
360
+ } catch (error) {
361
+ console.error("\u274C Failed to install MCP server:", error instanceof Error ? error.message : error);
362
+ process.exit(1);
363
+ }
364
+ });
365
+ mcp.command("preset <name>").description("Install a preset MCP server (filesystem, github, postgres, etc.)").action(async (name) => {
366
+ try {
367
+ const presets = {
368
+ filesystem: {
369
+ command: "npx",
370
+ args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user"]
371
+ },
372
+ github: {
373
+ command: "npx",
374
+ args: ["-y", "@modelcontextprotocol/server-github"]
375
+ },
376
+ postgres: {
377
+ command: "npx",
378
+ args: ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/db"]
379
+ },
380
+ sqlite: {
381
+ command: "npx",
382
+ args: ["-y", "@modelcontextprotocol/server-sqlite", "/path/to/db.sqlite"]
383
+ },
384
+ puppeteer: {
385
+ command: "npx",
386
+ args: ["-y", "@modelcontextprotocol/server-puppeteer"]
387
+ }
388
+ };
389
+ const preset = presets[name];
390
+ if (!preset) {
391
+ console.error(`\u274C Unknown preset: ${name}`);
392
+ console.log("\nAvailable presets:");
393
+ Object.keys(presets).forEach((p) => console.log(` \u2022 ${p}`));
394
+ process.exit(1);
395
+ }
396
+ console.log(`\u{1F50C} Installing MCP preset: ${name}...
397
+ `);
398
+ await openclaw.installMCPServer(name, preset);
399
+ console.log(`
400
+ \u2705 MCP preset "${name}" installed`);
401
+ console.log(" Restart OpenClaw to apply changes");
402
+ } catch (error) {
403
+ console.error("\u274C Failed to install MCP preset:", error instanceof Error ? error.message : error);
404
+ process.exit(1);
405
+ }
406
+ });
407
+ }
408
+ var ALL_PLATFORMS = [
409
+ "telegram",
410
+ "discord",
411
+ "whatsapp",
412
+ "signal",
413
+ "matrix",
414
+ "slack"
415
+ ];
416
+ function isKnownPlatform(value) {
417
+ return ALL_PLATFORMS.includes(value);
418
+ }
419
+ function parseRouting(value) {
420
+ if (value === void 0) return void 0;
421
+ if (value === "hermes" || value === "openclaw") return value;
422
+ throw new Error(`--routing must be 'hermes' or 'openclaw' (got: ${value})`);
423
+ }
424
+ function fail(message) {
425
+ console.error(`\u274C ${message}`);
426
+ process.exit(1);
427
+ }
428
+ async function promptValue(question) {
429
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
430
+ return new Promise((resolve) => {
431
+ rl.question(question, (answer) => {
432
+ rl.close();
433
+ resolve(answer.trim());
434
+ });
435
+ });
436
+ }
437
+ function buildInput(platform, opts) {
438
+ switch (platform) {
439
+ case "telegram": {
440
+ if (!opts.token) {
441
+ fail("Telegram requires --token <botToken>. Get it from @BotFather on Telegram.");
442
+ }
443
+ return {
444
+ platform: "telegram",
445
+ botToken: opts.token,
446
+ ...opts.webhookSecret ? { webhookSecret: opts.webhookSecret } : {}
447
+ };
448
+ }
449
+ case "discord": {
450
+ if (!opts.token) {
451
+ fail("Discord requires --token <botToken>. Get it from the Discord Developer Portal.");
452
+ }
453
+ return {
454
+ platform: "discord",
455
+ botToken: opts.token,
456
+ ...opts.guildId ? { guildId: opts.guildId } : {},
457
+ ...opts.appId ? { applicationId: opts.appId } : {}
458
+ };
459
+ }
460
+ case "slack": {
461
+ if (!opts.token) fail("Slack requires --token <botToken>.");
462
+ if (!opts.signingSecret) fail("Slack requires --signing-secret <secret>.");
463
+ return {
464
+ platform: "slack",
465
+ botToken: opts.token,
466
+ signingSecret: opts.signingSecret,
467
+ ...opts.appToken ? { appToken: opts.appToken } : {}
468
+ };
469
+ }
470
+ case "signal": {
471
+ if (!opts.phoneNumber) fail("Signal requires --phone-number <num>.");
472
+ return {
473
+ platform: "signal",
474
+ phoneNumber: opts.phoneNumber,
475
+ ...opts.apiUrl ? { apiUrl: opts.apiUrl } : {}
476
+ };
477
+ }
478
+ case "matrix": {
479
+ if (!opts.homeserverUrl) fail("Matrix requires --homeserver-url <url>.");
480
+ if (!opts.accessToken) fail("Matrix requires --access-token <token>.");
481
+ return {
482
+ platform: "matrix",
483
+ homeserverUrl: opts.homeserverUrl,
484
+ accessToken: opts.accessToken,
485
+ ...opts.roomId ? { roomId: opts.roomId } : {}
486
+ };
487
+ }
488
+ case "whatsapp": {
489
+ if (!opts.phoneNumberId) fail("WhatsApp Cloud API requires --phone-number-id <id>.");
490
+ if (!opts.accessToken) fail("WhatsApp Cloud API requires --access-token <token>.");
491
+ if (!opts.verifyToken) fail("WhatsApp Cloud API requires --verify-token <token>.");
492
+ return {
493
+ platform: "whatsapp",
494
+ mode: "cloud-api",
495
+ phoneNumberId: opts.phoneNumberId,
496
+ accessToken: opts.accessToken,
497
+ verifyToken: opts.verifyToken
498
+ };
499
+ }
500
+ }
501
+ }
502
+ function platformLabel(platform) {
503
+ return platform.charAt(0).toUpperCase() + platform.slice(1);
504
+ }
505
+ function messagingCommand(program) {
506
+ const messaging = program.command("messaging").description(
507
+ "Manage messaging platform credentials (Telegram, Discord, Slack, Signal, Matrix, WhatsApp)"
508
+ );
509
+ messaging.command("status").description("Show current messaging configuration from secrets.json").action(async () => {
510
+ try {
511
+ const rows = await readChannelStatus(process.cwd());
512
+ console.log("Messaging channels (from .eve/secrets/secrets.json):\n");
513
+ const header = ` ${"Platform".padEnd(10)} ${"Enabled".padEnd(8)} ${"Creds".padEnd(7)} Routing`;
514
+ console.log(header);
515
+ console.log(` ${"-".repeat(header.length - 2)}`);
516
+ for (const row of rows) {
517
+ const enabled = row.enabled ? "\u2705 yes" : "\u2014 no";
518
+ const creds = row.hasCredentials ? "\u2705" : "\u2014";
519
+ console.log(
520
+ ` ${row.platform.padEnd(10)} ${enabled.padEnd(8)} ${creds.padEnd(7)} ${row.routing}`
521
+ );
522
+ }
523
+ } catch (error) {
524
+ console.error("\u274C Failed to read messaging status:", error instanceof Error ? error.message : error);
525
+ process.exit(1);
526
+ }
527
+ });
528
+ messaging.command("configure <platform>").description("Configure a messaging platform (telegram, discord, slack, signal, matrix, whatsapp)").option("-t, --token <botToken>", "Bot token (telegram, discord, slack)").option("--webhook-secret <secret>", "Telegram webhook shared secret").option("--guild-id <id>", "Discord guild ID").option("--app-id <id>", "Discord application ID").option("--signing-secret <secret>", "Slack signing secret").option("--app-token <token>", "Slack app-level token (xapp-\u2026)").option("--phone-number <num>", "Signal phone number (E.164)").option("--api-url <url>", "Signal CLI REST API base URL").option("--homeserver-url <url>", "Matrix homeserver URL").option("--access-token <token>", "Matrix or WhatsApp Cloud API access token").option("--room-id <id>", "Matrix room ID").option("--routing <agent>", "Agent that handles this platform: 'hermes' (default) or 'openclaw'").option("--no-validate", "Skip the platform credential probe (use for self-hosted Matrix on private networks)").option("--cloud-api", "WhatsApp Cloud API mode (Meta Graph API \u2014 no browser/QR scan required)").option("--phone-number-id <id>", "WhatsApp Cloud API: Meta phone number ID").option("--verify-token <token>", "WhatsApp Cloud API: webhook verify token").action(async (platformArg, opts) => {
529
+ try {
530
+ if (!isKnownPlatform(platformArg)) {
531
+ fail(
532
+ `Unknown platform '${platformArg}'. Supported: ${ALL_PLATFORMS.join(", ")}`
533
+ );
534
+ }
535
+ const platform = platformArg;
536
+ if (platform === "whatsapp" && !opts.cloudApi) {
537
+ console.log("WhatsApp supports two onboarding paths:");
538
+ console.log("");
539
+ console.log(" --cloud-api Meta WhatsApp Cloud API (recommended)");
540
+ console.log(" Requires a Meta Business account with a verified phone number.");
541
+ console.log(" Run: eve arms messaging configure whatsapp --cloud-api");
542
+ console.log("");
543
+ console.log(" --browser QR-scan via the Agents browser app");
544
+ console.log(' Open the Agents app \u2192 "Connect Channel" \u2192 WhatsApp');
545
+ console.log(" and scan the QR code with WhatsApp mobile");
546
+ console.log(" (Settings \u2192 Linked Devices \u2192 Link a Device).");
547
+ return;
548
+ }
549
+ if (platform === "whatsapp" && opts.cloudApi) {
550
+ if (!opts.phoneNumberId) {
551
+ opts.phoneNumberId = await promptValue("Phone Number ID (from Meta Business Manager): ");
552
+ if (!opts.phoneNumberId) fail("Phone Number ID is required for WhatsApp Cloud API.");
553
+ }
554
+ if (!opts.accessToken) {
555
+ opts.accessToken = await promptValue("Access Token (permanent system user token): ");
556
+ if (!opts.accessToken) fail("Access Token is required for WhatsApp Cloud API.");
557
+ }
558
+ if (!opts.verifyToken) {
559
+ opts.verifyToken = await promptValue("Verify Token (webhook secret you choose): ");
560
+ if (!opts.verifyToken) fail("Verify Token is required for WhatsApp Cloud API.");
561
+ }
562
+ }
563
+ const routing = parseRouting(opts.routing);
564
+ const input = buildInput(platform, opts);
565
+ if (opts.validate !== false) {
566
+ const v = await validateChannelCredentials(input);
567
+ if (!v.ok) {
568
+ fail(
569
+ `${platformLabel(platform)} credential validation failed: ${v.error ?? "unknown error"}.
570
+ Re-run with --no-validate to persist anyway (e.g., self-hosted endpoint not reachable from this host).`
571
+ );
572
+ }
573
+ if (v.skipped) {
574
+ console.log(`\u2139 ${platformLabel(platform)} validation skipped (${v.details ?? "no remote probe"}).`);
575
+ } else {
576
+ console.log(`\u2705 ${platformLabel(platform)} credentials valid (${v.details ?? "authenticated"}).`);
577
+ }
578
+ }
579
+ const result = await configureChannel(process.cwd(), input, routing ? { routing } : {});
580
+ console.log(`\u2705 ${platformLabel(platform)} credentials saved.`);
581
+ console.log(` ${result.reconcileSummary}.`);
582
+ if (!result.wired) {
583
+ console.log(" (Hermes env not regenerated \u2014 install Hermes to activate channel routing.)");
584
+ }
585
+ } catch (error) {
586
+ console.error("\u274C Failed to configure messaging:", error instanceof Error ? error.message : error);
587
+ process.exit(1);
588
+ }
589
+ });
590
+ messaging.command("remove <platform>").description("Disable a messaging platform (credentials kept; set enabled=false)").action(async (platformArg) => {
591
+ try {
592
+ if (!isKnownPlatform(platformArg)) {
593
+ fail(
594
+ `Unknown platform '${platformArg}'. Supported: ${ALL_PLATFORMS.join(", ")}`
595
+ );
596
+ }
597
+ await disableChannel(process.cwd(), platformArg);
598
+ console.log(`\u2705 ${platformLabel(platformArg)} disabled. Credentials retained for re-enable.`);
599
+ } catch (error) {
600
+ console.error("\u274C Failed to remove messaging:", error instanceof Error ? error.message : error);
601
+ process.exit(1);
602
+ }
603
+ });
604
+ }
605
+ function voiceCommand(program) {
606
+ const voice = program.command("voice").description("Manage voice features (transcription, telephony)");
607
+ voice.command("status").description("Show voice feature status (transcription engine + telephony)").action(async () => {
608
+ try {
609
+ const secrets = await readEveSecrets(process.cwd());
610
+ const t = secrets?.arms?.transcription;
611
+ if (!t?.engine) {
612
+ console.log("Transcription engine: not configured");
613
+ console.log(" Run: eve arms voice transcription configure --engine whisper-local");
614
+ } else {
615
+ console.log("Transcription engine:");
616
+ console.log(` Engine: ${t.engine}`);
617
+ if (t.engine === "whisper-local") {
618
+ console.log(` Model size: ${t.modelSize ?? "base"}`);
619
+ }
620
+ if (t.engine === "openai" || t.engine === "deepgram") {
621
+ console.log(` API key: ${t.apiKey ? "*** (set)" : "(not set)"}`);
622
+ }
623
+ if (t.language) console.log(` Language: ${t.language}`);
624
+ }
625
+ const tel = secrets?.arms?.telephony;
626
+ if (!tel?.provider) {
627
+ console.log("\nTelephony: not configured");
628
+ console.log(" Run: eve arms voice configure <provider>");
629
+ } else {
630
+ console.log("\nTelephony:");
631
+ console.log(` Provider: ${tel.provider}`);
632
+ }
633
+ } catch (error) {
634
+ console.error("Failed to read voice config:", error instanceof Error ? error.message : error);
635
+ process.exit(1);
636
+ }
637
+ });
638
+ voice.command("configure <provider>").description("Configure telephony provider (e.g. twilio, vonage)").action(async (provider) => {
639
+ try {
640
+ await writeEveSecrets({
641
+ arms: {
642
+ telephony: { provider }
643
+ }
644
+ }, process.cwd());
645
+ console.log(`Telephony provider configured: ${provider}`);
646
+ } catch (error) {
647
+ console.error("Failed to configure telephony:", error instanceof Error ? error.message : error);
648
+ process.exit(1);
649
+ }
650
+ });
651
+ const transcription = voice.command("transcription").description("Manage voice memo transcription engine (Whisper, OpenAI, Deepgram)");
652
+ transcription.command("status").description("Show current transcription engine configuration").action(async () => {
653
+ try {
654
+ const secrets = await readEveSecrets(process.cwd());
655
+ const t = secrets?.arms?.transcription;
656
+ if (!t?.engine) {
657
+ console.log("Transcription engine: not configured");
658
+ console.log(" Run: eve arms voice transcription configure --engine whisper-local");
659
+ return;
660
+ }
661
+ console.log("Transcription engine:");
662
+ console.log(` Engine: ${t.engine}`);
663
+ if (t.engine === "whisper-local") {
664
+ console.log(` Model size: ${t.modelSize ?? "base"}`);
665
+ }
666
+ if (t.engine === "openai" || t.engine === "deepgram") {
667
+ console.log(` API key: ${t.apiKey ? "*** (set)" : "(not set)"}`);
668
+ }
669
+ if (t.language) console.log(` Language: ${t.language}`);
670
+ } catch (error) {
671
+ console.error("Failed to read transcription config:", error instanceof Error ? error.message : error);
672
+ process.exit(1);
673
+ }
674
+ });
675
+ transcription.command("configure").description("Configure the transcription engine for voice memos").option("-e, --engine <engine>", "Transcription engine: whisper-local, openai, deepgram").option("-m, --model <size>", "Whisper model size (whisper-local only): tiny, base, small, medium, large-v3").option("-k, --api-key <key>", "API key (openai or deepgram engines)").option("-l, --language <lang>", "BCP-47 language code for accuracy (e.g. en, fr)").action(async (opts) => {
676
+ try {
677
+ const validEngines = ["whisper-local", "openai", "deepgram"];
678
+ const validModels = ["tiny", "base", "small", "medium", "large-v3"];
679
+ if (opts.engine && !validEngines.includes(opts.engine)) {
680
+ console.error(`Unknown engine '${opts.engine}'. Choose: ${validEngines.join(", ")}`);
681
+ process.exit(1);
682
+ }
683
+ if (opts.model && !validModels.includes(opts.model)) {
684
+ console.error(`Unknown model '${opts.model}'. Choose: ${validModels.join(", ")}`);
685
+ process.exit(1);
686
+ }
687
+ if ((opts.engine === "openai" || opts.engine === "deepgram") && !opts.apiKey) {
688
+ console.error(`--api-key is required for the ${opts.engine} engine`);
689
+ process.exit(1);
690
+ }
691
+ if (!opts.engine && !opts.model && !opts.apiKey && !opts.language) {
692
+ console.error("No options provided. Use --engine, --model, --api-key, or --language");
693
+ process.exit(1);
694
+ }
695
+ const engine = opts.engine;
696
+ const modelSize = opts.model;
697
+ const { apiKey, language } = opts;
698
+ await writeEveSecrets({
699
+ arms: {
700
+ transcription: {
701
+ ...engine ? { engine } : {},
702
+ ...modelSize ? { modelSize } : {},
703
+ ...apiKey ? { apiKey } : {},
704
+ ...language ? { language } : {}
705
+ }
706
+ }
707
+ }, process.cwd());
708
+ const displayEngine = opts.engine ?? "(unchanged)";
709
+ console.log(`Transcription engine configured: ${displayEngine}`);
710
+ if (opts.engine === "whisper-local") {
711
+ console.log(` Model: ${opts.model ?? "base"}`);
712
+ console.log(" Install whisper: pip install openai-whisper");
713
+ }
714
+ } catch (error) {
715
+ console.error("Failed to configure transcription:", error instanceof Error ? error.message : error);
716
+ process.exit(1);
717
+ }
718
+ });
719
+ }
720
+ function registerArmsCommands(arms) {
721
+ installCommand(arms);
722
+ startCommand(arms);
723
+ stopCommand(arms);
724
+ mcpCommand(arms);
725
+ messagingCommand(arms);
726
+ voiceCommand(arms);
727
+ arms.command("status").description("Check OpenClaw status").action(async () => {
728
+ try {
729
+ const status = await openclaw.getStatus();
730
+ console.log("\u{1F9BE} Arms Status:\n");
731
+ console.log(` Running: ${status.running ? "\u2705 Yes" : "\u274C No"}`);
732
+ console.log(` URL: ${status.url}`);
733
+ console.log(` Model: ${status.model}`);
734
+ } catch (error) {
735
+ console.error("\u274C Failed to get status:", error instanceof Error ? error.message : error);
736
+ process.exit(1);
737
+ }
738
+ });
739
+ }
740
+ function registerCommands(program) {
741
+ const arms = program.command("arms").description("Manage OpenClaw AI assistant and MCP servers");
742
+ registerArmsCommands(arms);
743
+ }
744
+
745
+ export {
746
+ OpenClawService,
747
+ openclaw,
748
+ installCommand,
749
+ startCommand,
750
+ stopCommand,
751
+ mcpCommand,
752
+ messagingCommand,
753
+ voiceCommand,
754
+ registerArmsCommands,
755
+ registerCommands
756
+ };
757
+ //# sourceMappingURL=chunk-EHPC7CKE.js.map