@opentrust/cli 7.3.33 → 7.3.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { DashboardClient, loadConfig, saveConfig, clearConfig, } from "../lib/dashboard-client.js";
2
2
  import { getHostInfo, getServicesSnapshot, getSystemMetadata } from "../lib/host-reporter.js";
3
- import { executeHostCommand } from "../lib/command-handler.js";
3
+ import { executeHostCommand, setCommandLogger } from "../lib/command-handler.js";
4
4
  import { projectMode, projectRoot } from "../lib/paths.js";
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
@@ -124,6 +124,7 @@ function stopDaemon() {
124
124
  async function runDaemon(config) {
125
125
  const client = new DashboardClient(config);
126
126
  const log = (msg) => console.log(`[${new Date().toISOString()}] ${msg}`);
127
+ setCommandLogger(log);
127
128
  // Register
128
129
  log("Registering with Dashboard...");
129
130
  const hostInfo = getHostInfo();
@@ -159,23 +160,32 @@ async function runDaemon(config) {
159
160
  const heartbeatTimer = setInterval(heartbeat, HEARTBEAT_INTERVAL);
160
161
  // Command polling
161
162
  const poll = async () => {
163
+ let cmds;
162
164
  try {
163
- const cmds = await client.fetchPendingCommands();
164
- for (const cmd of cmds) {
165
- log(`Executing command: ${cmd.type} (${cmd.id})`);
166
- await client.ackCommand(cmd.id, "running").catch(() => { });
167
- const result = executeHostCommand(cmd);
168
- await client
169
- .ackCommand(cmd.id, result.success ? "completed" : "failed", {
170
- output: result.output,
171
- error: result.error,
172
- })
173
- .catch(() => { });
174
- log(`Command ${cmd.id}: ${result.success ? "completed" : "failed"}`);
175
- }
165
+ cmds = await client.fetchPendingCommands();
176
166
  }
177
167
  catch {
178
- // Dashboard may be unreachable
168
+ return; // Dashboard unreachable
169
+ }
170
+ for (const cmd of cmds) {
171
+ log(`Executing command: ${cmd.type} (${cmd.id})`);
172
+ await client.ackCommand(cmd.id, "running").catch(() => { });
173
+ const progressFn = async (output) => {
174
+ await client.ackCommand(cmd.id, "running", { output }).catch(() => { });
175
+ };
176
+ let result;
177
+ try {
178
+ result = await executeHostCommand(cmd, progressFn);
179
+ }
180
+ catch (err) {
181
+ log(`Command ${cmd.id} threw unexpectedly: ${err.message ?? err}`);
182
+ result = { success: false, error: `Unexpected error: ${(err.message ?? String(err)).slice(0, 500)}` };
183
+ }
184
+ const status = result.success ? "completed" : "failed";
185
+ await client
186
+ .ackCommand(cmd.id, status, { output: result.output, error: result.error })
187
+ .catch((e) => log(`Failed to ack command ${cmd.id}: ${e.message}`));
188
+ log(`Command ${cmd.id}: ${status}`);
179
189
  }
180
190
  };
181
191
  const pollTimer = setInterval(poll, POLL_INTERVAL);
@@ -13,9 +13,9 @@ const SCAFFOLD_PKG = {
13
13
  status: "opentrust status",
14
14
  },
15
15
  dependencies: {
16
- "@opentrust/core": "^7.3.33",
17
- "@opentrust/gateway": "^7.3.33",
18
- "@opentrust/dashboard": "^7.3.33",
16
+ "@opentrust/core": "^7.3.35",
17
+ "@opentrust/gateway": "^7.3.35",
18
+ "@opentrust/dashboard": "^7.3.35",
19
19
  },
20
20
  };
21
21
  const ENV_TEMPLATE = `# OpenTrust Configuration
@@ -1,7 +1,9 @@
1
- import type { HostCommand } from "./dashboard-client.js";
1
+ import { type HostCommand } from "./dashboard-client.js";
2
2
  export interface CommandResult {
3
3
  success: boolean;
4
4
  output?: string;
5
5
  error?: string;
6
6
  }
7
- export declare function executeHostCommand(cmd: HostCommand): CommandResult;
7
+ export type ProgressFn = (output: string) => Promise<void>;
8
+ export declare function setCommandLogger(fn: (msg: string) => void): void;
9
+ export declare function executeHostCommand(cmd: HostCommand, progress?: ProgressFn): Promise<CommandResult>;
@@ -4,6 +4,15 @@ import path from "node:path";
4
4
  import os from "node:os";
5
5
  import { startService, stopService, getStatus, SERVICES } from "./process-manager.js";
6
6
  import { paths, projectRoot, projectMode } from "./paths.js";
7
+ import { loadConfig } from "./dashboard-client.js";
8
+ let _logger = null;
9
+ export function setCommandLogger(fn) { _logger = fn; }
10
+ let _cmdOutput = [];
11
+ function cmdLog(msg) {
12
+ if (_logger)
13
+ _logger(msg);
14
+ _cmdOutput.push(msg);
15
+ }
7
16
  const SERVICE_KEYS = Object.keys(SERVICES);
8
17
  const OPENCLAW_HOME = process.env.OPENCLAW_HOME || path.join(os.homedir(), ".openclaw");
9
18
  function clawExecOpts(timeoutMs = 120_000) {
@@ -16,7 +25,8 @@ function clawExecOpts(timeoutMs = 120_000) {
16
25
  env: { ...restEnv, HOME: os.homedir() },
17
26
  };
18
27
  }
19
- export function executeHostCommand(cmd) {
28
+ export async function executeHostCommand(cmd, progress) {
29
+ _cmdOutput = [];
20
30
  const payload = cmd.payload ?? {};
21
31
  switch (cmd.type) {
22
32
  case "start_service":
@@ -48,7 +58,7 @@ export function executeHostCommand(cmd) {
48
58
  case "upgrade_guards":
49
59
  return handleUpgradeGuards(payload);
50
60
  case "install_openclaw":
51
- return handleInstallOpenclaw(payload);
61
+ return handleInstallOpenclaw(payload, progress);
52
62
  default:
53
63
  return { success: false, error: `Unknown command type: ${cmd.type}` };
54
64
  }
@@ -289,51 +299,116 @@ function handleUpgradeGuards(payload) {
289
299
  };
290
300
  }
291
301
  // ── OpenClaw installation ────────────────────────────
292
- function handleInstallOpenclaw(payload) {
302
+ function findOpenclawBin() {
303
+ const candidates = [
304
+ path.join(os.homedir(), ".local", "bin", "openclaw"),
305
+ "/usr/local/bin/openclaw",
306
+ path.join(os.homedir(), ".openclaw", "bin", "openclaw"),
307
+ ];
308
+ for (const p of candidates) {
309
+ if (fs.existsSync(p))
310
+ return p;
311
+ }
312
+ return "openclaw";
313
+ }
314
+ async function handleInstallOpenclaw(payload, progress) {
293
315
  const config = payload.config;
294
316
  if (!config)
295
317
  return { success: false, error: "Missing config in payload. Configure OpenClaw template in Settings first." };
296
- const results = [];
318
+ const sendProgress = async () => {
319
+ if (progress)
320
+ await progress(_cmdOutput.join("\n")).catch(() => { });
321
+ };
322
+ // Override Guards plugin URLs with the CLI's own connection URL
323
+ const cliConfig = loadConfig();
324
+ if (cliConfig?.dashboardUrl) {
325
+ if (!config.plugins)
326
+ config.plugins = {};
327
+ if (!config.plugins.entries)
328
+ config.plugins.entries = {};
329
+ if (!config.plugins.entries["opentrust-guard"])
330
+ config.plugins.entries["opentrust-guard"] = { enabled: true, config: {} };
331
+ if (!config.plugins.entries["opentrust-guard"].config)
332
+ config.plugins.entries["opentrust-guard"].config = {};
333
+ const gc = config.plugins.entries["opentrust-guard"].config;
334
+ gc.dashboardUrl = cliConfig.dashboardUrl;
335
+ gc.coreUrl = cliConfig.dashboardUrl.replace(/:(\d+)$/, (_, port) => {
336
+ return `:${Number(port) === 53667 ? 53666 : Number(port) - 1}`;
337
+ });
338
+ cmdLog(`Guards URLs → dashboardUrl=${gc.dashboardUrl}, coreUrl=${gc.coreUrl}`);
339
+ }
297
340
  // Step 1: Install OpenClaw via curl
341
+ cmdLog("[1/3] Installing OpenClaw (curl -fsSL https://openclaw.ai/install.sh | bash)...");
342
+ await sendProgress();
298
343
  try {
299
- const output = execSync("curl -fsSL https://openclaw.ai/install.sh | bash", {
344
+ execSync("curl -fsSL https://openclaw.ai/install.sh | bash", {
300
345
  encoding: "utf-8",
301
- timeout: 300_000,
302
- stdio: ["pipe", "pipe", "pipe"],
346
+ timeout: 180_000,
347
+ stdio: ["pipe", "inherit", "inherit"],
303
348
  cwd: os.homedir(),
304
349
  env: { ...process.env, HOME: os.homedir() },
305
350
  shell: "/bin/bash",
306
351
  });
307
- results.push(`Install script: ${output.trim().split("\n").slice(-3).join(" | ")}`);
352
+ cmdLog("[1/3] OpenClaw install script completed");
308
353
  }
309
354
  catch (err) {
310
- const stderr = err.stderr?.toString() || "";
311
- const stdout = err.stdout?.toString() || "";
312
- if (stdout.toLowerCase().includes("already installed") || stdout.toLowerCase().includes("openclaw")) {
313
- results.push(`Install script: ${stdout.trim().split("\n").slice(-2).join(" | ")} (may already be installed)`);
355
+ const code = err.status;
356
+ if (code === 0 || code === null) {
357
+ cmdLog("[1/3] OpenClaw install script finished (exit code ignored)");
314
358
  }
315
359
  else {
316
- return { success: false, error: `Install script failed: ${(stderr || err.message || String(err)).slice(0, 500)}` };
360
+ cmdLog(`[1/3] Install script exited with code ${code}`);
317
361
  }
318
362
  }
363
+ await sendProgress();
319
364
  // Step 2: Write openclaw.json config
365
+ cmdLog("[2/3] Writing ~/.openclaw/openclaw.json ...");
366
+ await sendProgress();
320
367
  try {
321
368
  const clawHome = path.join(os.homedir(), ".openclaw");
322
369
  fs.mkdirSync(clawHome, { recursive: true });
323
370
  const configFile = path.join(clawHome, "openclaw.json");
324
371
  fs.writeFileSync(configFile, JSON.stringify(config, null, 2) + "\n", "utf-8");
325
- results.push(`Config written to ${configFile}`);
372
+ cmdLog(`[2/3] Config written to ${configFile}`);
326
373
  }
327
374
  catch (err) {
328
- return { success: false, error: `Failed to write config: ${(err.message || String(err)).slice(0, 500)}` };
375
+ const msg = `Failed to write config: ${(err.message || String(err)).slice(0, 500)}`;
376
+ cmdLog(`[2/3] ${msg}`);
377
+ await sendProgress();
378
+ return { success: false, output: _cmdOutput.join("\n"), error: msg };
329
379
  }
380
+ await sendProgress();
330
381
  // Step 3: Auto-install Guards plugin
331
- const guardsResult = runClawPluginCmd("openclaw plugins install @opentrust/guards");
332
- if (guardsResult.success) {
333
- results.push(`Guards plugin: installed${guardsResult.output ? ` (${guardsResult.output.split("\n").pop()})` : ""}`);
382
+ const clawBin = findOpenclawBin();
383
+ cmdLog(`[3/3] Installing Guards plugin (${clawBin} plugins install @opentrust/guards)...`);
384
+ await sendProgress();
385
+ try {
386
+ const extraPaths = [
387
+ path.join(os.homedir(), ".local", "bin"),
388
+ path.join(os.homedir(), ".openclaw", "bin"),
389
+ "/usr/local/bin",
390
+ ].join(":");
391
+ const { OPENCLAW_HOME: _, ...restEnv } = process.env;
392
+ execSync(`${clawBin} plugins install @opentrust/guards`, {
393
+ encoding: "utf-8",
394
+ timeout: 180_000,
395
+ stdio: ["pipe", "pipe", "pipe"],
396
+ cwd: os.homedir(),
397
+ env: { ...restEnv, HOME: os.homedir(), PATH: `${extraPaths}:${process.env.PATH ?? ""}` },
398
+ });
399
+ cmdLog("[3/3] Guards plugin installed successfully");
334
400
  }
335
- else {
336
- results.push(`Guards plugin: install failed — ${guardsResult.error?.slice(0, 200) ?? "unknown error"}`);
401
+ catch (err) {
402
+ const stderr = err.stderr?.toString() || "";
403
+ const stdout = err.stdout?.toString() || "";
404
+ if (isOnlyWarnings(stderr) || isOnlyWarnings(stdout + stderr)) {
405
+ cmdLog("[3/3] Guards plugin installed (with warnings)");
406
+ }
407
+ else {
408
+ const errMsg = (stderr || err.message || String(err)).slice(0, 300);
409
+ cmdLog(`[3/3] Guards plugin install failed: ${errMsg}`);
410
+ }
337
411
  }
338
- return { success: true, output: results.join("\n") };
412
+ cmdLog("install_openclaw complete");
413
+ return { success: true, output: _cmdOutput.join("\n") };
339
414
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opentrust/cli",
3
- "version": "7.3.33",
3
+ "version": "7.3.35",
4
4
  "description": "CLI tool to manage OpenTrust AI Agent Runtime Security Platform — setup, start, stop, status, logs",
5
5
  "type": "module",
6
6
  "bin": {