@clawops/cli 1.1.0 → 1.2.1

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 (39) hide show
  1. package/README.md +115 -44
  2. package/dist/apply-KBF7OPWL.js +14 -0
  3. package/dist/{automation-JG2YBEL7.js → automation-RULUSJBW.js} +2 -2
  4. package/dist/{aws-A3323GNM.js → aws-KQBWY43W.js} +12 -10
  5. package/dist/{azure-LNWBK2ZI.js → azure-4EJFVJZL.js} +4 -3
  6. package/dist/{bootstrap-7ZS2GLFJ.js → bootstrap-UYCOEJQX.js} +48 -12
  7. package/dist/{chunk-LT24GUUO.js → chunk-3QJBNAHW.js} +1 -1
  8. package/dist/{chunk-BA6MDFZK.js → chunk-4U3LTLWZ.js} +2 -83
  9. package/dist/{chunk-PERSDQMT.js → chunk-ACYJBSLJ.js} +7 -7
  10. package/dist/chunk-BOPSG2LI.js +77 -0
  11. package/dist/{chunk-PRYLTCS4.js → chunk-BRPU7AQC.js} +1 -1
  12. package/dist/{chunk-ALSUDYA7.js → chunk-CX5SL5HP.js} +1 -1
  13. package/dist/{chunk-ZSE4QRKE.js → chunk-KGXPLI7W.js} +19 -1
  14. package/dist/chunk-LU63NZD3.js +116 -0
  15. package/dist/chunk-OIGTOLB3.js +99 -0
  16. package/dist/chunk-QJ6ERXHN.js +266 -0
  17. package/dist/{chunk-D4UAHAKI.js → chunk-SSB6SGPQ.js} +10 -6
  18. package/dist/chunk-UDNZUSKA.js +97 -0
  19. package/dist/chunk-ZVOEQCNW.js +92 -0
  20. package/dist/cli.js +1340 -115
  21. package/dist/context-VUAYRAJY.js +10 -0
  22. package/dist/errors-OK47MQFD.js +21 -0
  23. package/dist/{gcp-OHWCTFLL.js → gcp-SKURG3L6.js} +4 -3
  24. package/dist/generate-PZPLG3ZM.js +14 -0
  25. package/dist/js-yaml-PTEEG4FO.js +2647 -0
  26. package/dist/mcp-apps-KY44ED3Y.js +11 -0
  27. package/dist/{outputs-6DAVEEAZ.js → outputs-DJHBY7EE.js} +2 -2
  28. package/dist/{package-FA6UOG2I.js → package-SE3M4NJA.js} +1 -1
  29. package/dist/{pool-FAVU7WCW.js → pool-FBFHATDG.js} +3 -2
  30. package/dist/remote-config-JQ77SRC2.js +21 -0
  31. package/dist/secrets-SVZWNAPK.js +7 -0
  32. package/dist/{server-V5ZFL76Y.js → server-4DNHLGEG.js} +64 -150
  33. package/dist/ssh-IQXNME3D.js +8 -0
  34. package/dist/{store-ARJ2EO6L.js → store-SDUR52Z5.js} +2 -2
  35. package/package.json +1 -1
  36. package/dist/apply-DPS23GLL.js +0 -12
  37. package/dist/chunk-UCIVU24B.js +0 -56
  38. package/dist/context-T52JWL3P.js +0 -10
  39. package/dist/generate-55MITRXU.js +0 -14
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/plan/remote-config.ts
4
+ var OPENCLAW_CONFIG_LINUX = "/home/clawops/openclaw.json";
5
+ var OPENCLAW_CONFIG_MACOS = "~/.config/openclaw/config.json";
6
+ var OPENCLAW_CONFIG = OPENCLAW_CONFIG_LINUX;
7
+ var OPENCLAW_TMP = "/tmp/clawops-config.json.tmp";
8
+ async function detectOS(session, signal) {
9
+ const result = await session.exec("uname -s", signal);
10
+ return result.stdout.trim() === "Darwin" ? "Darwin" : "Linux";
11
+ }
12
+ function configPathForOS(os) {
13
+ return os === "Darwin" ? OPENCLAW_CONFIG_MACOS : OPENCLAW_CONFIG_LINUX;
14
+ }
15
+ async function execWithFallbackSudo(session, cmd, signal) {
16
+ const result = await session.exec(cmd, signal);
17
+ if (result.code === 0) return result;
18
+ return session.exec(`sudo -n bash -c "${cmd}"`, signal);
19
+ }
20
+ async function readRemoteConfig(session, signal) {
21
+ const os = await detectOS(session, signal);
22
+ const configPath = configPathForOS(os);
23
+ const result = await session.exec(`cat ${configPath}`, signal);
24
+ if (result.code !== 0) {
25
+ throw new Error(`Cannot read ${configPath}: ${result.stderr}`);
26
+ }
27
+ try {
28
+ return JSON.parse(result.stdout);
29
+ } catch {
30
+ throw new Error(`Cannot parse ${configPath}: invalid JSON`);
31
+ }
32
+ }
33
+ async function atomicWriteConfig(session, cfg, signal) {
34
+ const os = await detectOS(session, signal);
35
+ const configPath = configPathForOS(os);
36
+ const json = JSON.stringify(cfg, null, 2);
37
+ const b64 = Buffer.from(json, "utf-8").toString("base64");
38
+ const chown = os === "Linux" ? ` && chown clawops:clawops ${configPath}` : "";
39
+ const cmd = `echo '${b64}' | base64 -d > ${OPENCLAW_TMP} && mv ${OPENCLAW_TMP} ${configPath}` + chown;
40
+ const result = os === "Darwin" ? await session.exec(cmd, signal) : await execWithFallbackSudo(session, cmd, signal);
41
+ if (result.code !== 0) {
42
+ throw new Error(`Failed to write config: ${result.stderr}`);
43
+ }
44
+ }
45
+ async function restartGateway(session, signal) {
46
+ const os = await detectOS(session, signal);
47
+ const configPath = configPathForOS(os);
48
+ const pathPrefix = os === "Darwin" ? 'export PATH="/usr/local/bin:/opt/homebrew/bin:/Applications/Docker.app/Contents/Resources/bin:$PATH" && ' : "";
49
+ const imgCmd = `${pathPrefix}docker inspect openclaw --format '{{.Config.Image}}' 2>/dev/null || echo 'ghcr.io/openclaw/openclaw:latest'`;
50
+ const imgResult = os === "Darwin" ? await session.exec(imgCmd, signal) : await execWithFallbackSudo(session, imgCmd, signal);
51
+ const image = imgResult.stdout.trim();
52
+ const cfgResult = await session.exec(`cat ${configPath}`, signal);
53
+ let gatewayCmd = "node openclaw.mjs gateway run --allow-unconfigured";
54
+ try {
55
+ const cfg = JSON.parse(cfgResult.stdout);
56
+ const token = cfg?.["gateway"]?.["auth"];
57
+ const tokenVal = token?.["token"];
58
+ if (tokenVal) {
59
+ gatewayCmd = `node openclaw.mjs gateway run --allow-unconfigured --token '${tokenVal}'`;
60
+ }
61
+ } catch {
62
+ }
63
+ const restartCmd = pathPrefix + [
64
+ "docker stop openclaw 2>/dev/null || true",
65
+ "docker rm openclaw 2>/dev/null || true",
66
+ `docker run -d --name openclaw --restart unless-stopped -p 18789:18789 -v ${configPath}:/app/config.json:ro ${image} ${gatewayCmd}`
67
+ ].join(" && ");
68
+ const result = os === "Darwin" ? await session.exec(restartCmd, signal) : await execWithFallbackSudo(session, restartCmd, signal);
69
+ if (result.code !== 0) {
70
+ throw new Error(`Gateway restart failed: ${result.stderr}`);
71
+ }
72
+ }
73
+ function deepMerge(base, overlay) {
74
+ const result = { ...base };
75
+ for (const [key, val] of Object.entries(overlay)) {
76
+ if (val !== null && typeof val === "object" && !Array.isArray(val) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) {
77
+ result[key] = deepMerge(
78
+ result[key],
79
+ val
80
+ );
81
+ } else {
82
+ result[key] = val;
83
+ }
84
+ }
85
+ return result;
86
+ }
87
+
88
+ export {
89
+ OPENCLAW_CONFIG_LINUX,
90
+ OPENCLAW_CONFIG_MACOS,
91
+ OPENCLAW_CONFIG,
92
+ OPENCLAW_TMP,
93
+ readRemoteConfig,
94
+ atomicWriteConfig,
95
+ restartGateway,
96
+ deepMerge
97
+ };
@@ -0,0 +1,92 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ connect
4
+ } from "./chunk-4U3LTLWZ.js";
5
+ import {
6
+ NetworkError
7
+ } from "./chunk-KGXPLI7W.js";
8
+
9
+ // src/transport/pool.ts
10
+ var IDLE_TTL_MS = 5 * 60 * 1e3;
11
+ var MAX_PER_HOST = 4;
12
+ var CLEANUP_INTERVAL_MS = 3e4;
13
+ var pool = /* @__PURE__ */ new Map();
14
+ var cleanupTimer = null;
15
+ function poolKey(opts) {
16
+ return `${opts.user}@${opts.host}:${opts.port}`;
17
+ }
18
+ function startCleanupTimer() {
19
+ if (cleanupTimer) return;
20
+ cleanupTimer = setInterval(() => {
21
+ const now = Date.now();
22
+ for (const [key, entries] of pool) {
23
+ const active = entries.filter((e) => {
24
+ if (!e.inUse && now - e.lastUsed > IDLE_TTL_MS) {
25
+ e.session.close();
26
+ return false;
27
+ }
28
+ return true;
29
+ });
30
+ if (active.length === 0) {
31
+ pool.delete(key);
32
+ } else {
33
+ pool.set(key, active);
34
+ }
35
+ }
36
+ if (pool.size === 0 && cleanupTimer) {
37
+ clearInterval(cleanupTimer);
38
+ cleanupTimer = null;
39
+ }
40
+ }, CLEANUP_INTERVAL_MS);
41
+ cleanupTimer.unref();
42
+ }
43
+ async function acquireSession(opts) {
44
+ const key = poolKey(opts);
45
+ const entries = pool.get(key) ?? [];
46
+ const idle = entries.find((e) => !e.inUse);
47
+ if (idle) {
48
+ idle.inUse = true;
49
+ idle.lastUsed = Date.now();
50
+ return {
51
+ session: idle.session,
52
+ release() {
53
+ idle.inUse = false;
54
+ idle.lastUsed = Date.now();
55
+ }
56
+ };
57
+ }
58
+ if (entries.length >= MAX_PER_HOST) {
59
+ throw new NetworkError(
60
+ `SSH connection pool exhausted for ${key} (max ${MAX_PER_HOST} concurrent connections).`
61
+ );
62
+ }
63
+ const session = await connect(opts);
64
+ const entry = { session, hostKey: key, lastUsed: Date.now(), inUse: true };
65
+ entries.push(entry);
66
+ pool.set(key, entries);
67
+ startCleanupTimer();
68
+ return {
69
+ session,
70
+ release() {
71
+ entry.inUse = false;
72
+ entry.lastUsed = Date.now();
73
+ }
74
+ };
75
+ }
76
+ function drainPool() {
77
+ for (const entries of pool.values()) {
78
+ for (const e of entries) {
79
+ e.session.close();
80
+ }
81
+ }
82
+ pool.clear();
83
+ if (cleanupTimer) {
84
+ clearInterval(cleanupTimer);
85
+ cleanupTimer = null;
86
+ }
87
+ }
88
+
89
+ export {
90
+ acquireSession,
91
+ drainPool
92
+ };