openclaw-manager 0.1.1 → 0.1.3
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.
- package/bin/commands/start.js +108 -0
- package/bin/commands/stop-all.js +82 -0
- package/bin/commands/stop.js +63 -0
- package/bin/lib/args.js +87 -0
- package/bin/lib/banner.js +13 -0
- package/bin/lib/config.js +74 -0
- package/bin/lib/help.js +9 -0
- package/bin/lib/paths.js +6 -0
- package/bin/lib/pids.js +22 -0
- package/bin/lib/system.js +31 -0
- package/bin/lib/types.js +1 -0
- package/bin/lib/version.js +17 -0
- package/bin/openclaw-manager.js +44 -190
- package/dist/lib/commands.js +2 -2
- package/dist/services/jobs.service.js +2 -2
- package/package.json +12 -2
- package/web-dist/assets/{index-BabnD_ew.js → index-C_m7eOq1.js} +2 -2
- package/web-dist/docker.sh +7 -7
- package/web-dist/index.html +2 -2
- package/web-dist/install.ps1 +1 -1
- package/web-dist/install.sh +2 -2
package/bin/openclaw-manager.js
CHANGED
|
@@ -1,198 +1,52 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { randomBytes, scryptSync } from "node:crypto";
|
|
3
|
-
import { spawn } from "node:child_process";
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import os from "node:os";
|
|
6
|
-
import path from "node:path";
|
|
7
2
|
import process from "node:process";
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
|
|
3
|
+
import { parseArgs } from "./lib/args.js";
|
|
4
|
+
import { printHelp, printWelcome } from "./lib/help.js";
|
|
5
|
+
import { readPackageVersion } from "./lib/version.js";
|
|
6
|
+
import { startManager } from "./commands/start.js";
|
|
7
|
+
import { stopManager } from "./commands/stop.js";
|
|
8
|
+
import { stopAll } from "./commands/stop-all.js";
|
|
11
9
|
const args = process.argv.slice(2);
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
void start();
|
|
31
|
-
|
|
32
|
-
async function start() {
|
|
33
|
-
const apiPort = process.env.MANAGER_API_PORT ?? "17321";
|
|
34
|
-
const apiHost = process.env.MANAGER_API_HOST ?? "0.0.0.0";
|
|
35
|
-
const configDir = process.env.MANAGER_CONFIG_DIR ?? path.join(os.homedir(), ".openclaw-manager");
|
|
36
|
-
const configPath =
|
|
37
|
-
process.env.MANAGER_CONFIG_PATH ?? path.join(configDir, "config.json");
|
|
38
|
-
const logPath =
|
|
39
|
-
process.env.MANAGER_LOG_PATH ?? path.join(configDir, "openclaw-manager.log");
|
|
40
|
-
const errorLogPath =
|
|
41
|
-
process.env.MANAGER_ERROR_LOG_PATH ??
|
|
42
|
-
path.join(configDir, "openclaw-manager.error.log");
|
|
43
|
-
const pidPath = path.join(configDir, "manager.pid");
|
|
44
|
-
|
|
45
|
-
ensureDir(configDir);
|
|
46
|
-
ensureDir(path.dirname(logPath));
|
|
47
|
-
ensureDir(path.dirname(errorLogPath));
|
|
48
|
-
|
|
49
|
-
if (isRunning(pidPath)) {
|
|
50
|
-
const pid = fs.readFileSync(pidPath, "utf-8").trim();
|
|
51
|
-
console.log(`[manager] Already running (pid: ${pid}).`);
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
if (!fs.existsSync(configPath)) {
|
|
56
|
-
const username =
|
|
57
|
-
process.env.MANAGER_ADMIN_USER ??
|
|
58
|
-
process.env.OPENCLAW_MANAGER_ADMIN_USER ??
|
|
59
|
-
(await promptLine("Admin username: "));
|
|
60
|
-
const password =
|
|
61
|
-
process.env.MANAGER_ADMIN_PASS ??
|
|
62
|
-
process.env.OPENCLAW_MANAGER_ADMIN_PASS ??
|
|
63
|
-
(await promptSecret("Admin password: "));
|
|
64
|
-
if (!username || !password) {
|
|
65
|
-
console.error("[manager] Admin username/password is required.");
|
|
66
|
-
process.exit(1);
|
|
10
|
+
const parsed = parseArgs(args);
|
|
11
|
+
const cmd = parsed.command;
|
|
12
|
+
if (parsed.flags.help || cmd === "help") {
|
|
13
|
+
printHelp();
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
if (parsed.flags.version) {
|
|
17
|
+
console.log(`openclaw-manager ${readPackageVersion()}`);
|
|
18
|
+
process.exit(0);
|
|
19
|
+
}
|
|
20
|
+
if (!cmd) {
|
|
21
|
+
printWelcome();
|
|
22
|
+
process.exit(0);
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
if (cmd === "start") {
|
|
26
|
+
await startManager(parsed.flags);
|
|
67
27
|
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
...process.env,
|
|
86
|
-
MANAGER_API_HOST: apiHost,
|
|
87
|
-
MANAGER_API_PORT: apiPort,
|
|
88
|
-
MANAGER_WEB_DIST: webDist,
|
|
89
|
-
MANAGER_CONFIG_PATH: configPath
|
|
90
|
-
},
|
|
91
|
-
detached: true,
|
|
92
|
-
stdio: ["ignore", out, err]
|
|
93
|
-
});
|
|
94
|
-
child.unref();
|
|
95
|
-
|
|
96
|
-
fs.writeFileSync(pidPath, String(child.pid), "utf-8");
|
|
97
|
-
|
|
98
|
-
const lanIp = resolveLanIp();
|
|
99
|
-
console.log(`[manager] Started (pid: ${child.pid}).`);
|
|
100
|
-
console.log(`[manager] Log: ${logPath}`);
|
|
101
|
-
console.log(`[manager] Error log: ${errorLogPath}`);
|
|
102
|
-
console.log(`[manager] Open (local): http://localhost:${apiPort}`);
|
|
103
|
-
console.log(`[manager] Open (local): http://127.0.0.1:${apiPort}`);
|
|
104
|
-
if (lanIp) {
|
|
105
|
-
console.log(`[manager] Open (LAN): http://${lanIp}:${apiPort}`);
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function ensureDir(dir) {
|
|
110
|
-
if (!dir) return;
|
|
111
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function isRunning(pidPath) {
|
|
115
|
-
if (!fs.existsSync(pidPath)) return false;
|
|
116
|
-
const raw = fs.readFileSync(pidPath, "utf-8").trim();
|
|
117
|
-
const pid = Number(raw);
|
|
118
|
-
if (!pid) return false;
|
|
119
|
-
try {
|
|
120
|
-
process.kill(pid, 0);
|
|
121
|
-
return true;
|
|
122
|
-
} catch {
|
|
123
|
-
return false;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function writeAdminConfig(configPath, username, password) {
|
|
128
|
-
const salt = randomBytes(16).toString("base64");
|
|
129
|
-
const hash = scryptSync(password, salt, 64).toString("base64");
|
|
130
|
-
const payload = {
|
|
131
|
-
auth: {
|
|
132
|
-
username,
|
|
133
|
-
salt,
|
|
134
|
-
hash
|
|
135
|
-
},
|
|
136
|
-
createdAt: new Date().toISOString()
|
|
137
|
-
};
|
|
138
|
-
ensureDir(path.dirname(configPath));
|
|
139
|
-
fs.writeFileSync(configPath, JSON.stringify(payload, null, 2));
|
|
140
|
-
console.log(`[manager] Admin config saved to ${configPath}`);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
async function promptLine(prompt) {
|
|
144
|
-
if (!process.stdin.isTTY) return "";
|
|
145
|
-
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
146
|
-
const answer = await new Promise((resolve) => rl.question(prompt, resolve));
|
|
147
|
-
rl.close();
|
|
148
|
-
return String(answer).trim();
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
async function promptSecret(prompt) {
|
|
152
|
-
if (!process.stdin.isTTY) return "";
|
|
153
|
-
return new Promise((resolve) => {
|
|
154
|
-
const stdin = process.stdin;
|
|
155
|
-
const stdout = process.stdout;
|
|
156
|
-
let value = "";
|
|
157
|
-
stdout.write(prompt);
|
|
158
|
-
stdin.setRawMode(true);
|
|
159
|
-
stdin.resume();
|
|
160
|
-
const onData = (data) => {
|
|
161
|
-
const char = data.toString();
|
|
162
|
-
if (char === "\n" || char === "\r") {
|
|
163
|
-
stdout.write("\n");
|
|
164
|
-
stdin.setRawMode(false);
|
|
165
|
-
stdin.pause();
|
|
166
|
-
stdin.removeListener("data", onData);
|
|
167
|
-
resolve(value.trim());
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (char === "\u0003") {
|
|
28
|
+
else if (cmd === "stop") {
|
|
29
|
+
const result = stopManager(parsed.flags);
|
|
30
|
+
for (const line of result.messages)
|
|
31
|
+
console.log(line);
|
|
32
|
+
if (!result.ok)
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
else if (cmd === "stop-all") {
|
|
36
|
+
const result = stopAll(parsed.flags);
|
|
37
|
+
for (const line of result.messages)
|
|
38
|
+
console.log(line);
|
|
39
|
+
if (!result.ok)
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
console.error(`[manager] Unknown command: ${cmd}`);
|
|
44
|
+
printHelp();
|
|
171
45
|
process.exit(1);
|
|
172
|
-
}
|
|
173
|
-
value += char;
|
|
174
|
-
};
|
|
175
|
-
stdin.on("data", onData);
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
function resolveLanIp() {
|
|
180
|
-
const nets = os.networkInterfaces();
|
|
181
|
-
for (const name of Object.keys(nets)) {
|
|
182
|
-
for (const net of nets[name] ?? []) {
|
|
183
|
-
if (net.family === "IPv4" && !net.internal) {
|
|
184
|
-
return net.address;
|
|
185
|
-
}
|
|
186
46
|
}
|
|
187
|
-
}
|
|
188
|
-
return null;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
function resolvePackageRoot() {
|
|
192
|
-
const filePath = fileURLToPath(import.meta.url);
|
|
193
|
-
return path.resolve(path.dirname(filePath), "..");
|
|
194
47
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
48
|
+
catch (err) {
|
|
49
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
50
|
+
console.error(message);
|
|
51
|
+
process.exit(1);
|
|
198
52
|
}
|
package/dist/lib/commands.js
CHANGED
|
@@ -3,8 +3,8 @@ export function buildCommandRegistry(root) {
|
|
|
3
3
|
return [
|
|
4
4
|
{
|
|
5
5
|
id: "install-cli",
|
|
6
|
-
title: "Install
|
|
7
|
-
description: "Install the latest
|
|
6
|
+
title: "Install OpenClaw CLI",
|
|
7
|
+
description: "Install the latest OpenClaw CLI (may require sudo)",
|
|
8
8
|
command: "npm",
|
|
9
9
|
args: ["i", "-g", "clawdbot@latest"],
|
|
10
10
|
cwd: root,
|
|
@@ -8,9 +8,9 @@ const DEFAULT_PAIRING_WAIT_TIMEOUT_MS = 180_000;
|
|
|
8
8
|
const DEFAULT_PAIRING_POLL_MS = 3000;
|
|
9
9
|
const DEFAULT_PAIRING_APPROVE_TIMEOUT_MS = 8000;
|
|
10
10
|
export function createCliInstallJob(deps) {
|
|
11
|
-
const job = deps.jobStore.createJob("Install
|
|
11
|
+
const job = deps.jobStore.createJob("Install OpenClaw CLI");
|
|
12
12
|
deps.jobStore.startJob(job.id);
|
|
13
|
-
deps.jobStore.appendLog(job.id, "开始安装
|
|
13
|
+
deps.jobStore.appendLog(job.id, "开始安装 OpenClaw CLI...");
|
|
14
14
|
const timeoutMs = parsePositiveInt(process.env.MANAGER_CLI_INSTALL_TIMEOUT_MS) ?? 600_000;
|
|
15
15
|
void (async () => {
|
|
16
16
|
const current = await getCliStatus(deps.runCommand);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-manager",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"openclaw-manager": "bin/openclaw-manager.js"
|
|
@@ -13,6 +13,16 @@
|
|
|
13
13
|
],
|
|
14
14
|
"dependencies": {
|
|
15
15
|
"@hono/node-server": "1.13.1",
|
|
16
|
-
"hono": "4.11.4"
|
|
16
|
+
"hono": "4.11.4",
|
|
17
|
+
"prompts": "^2.4.2"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/prompts": "2.4.9",
|
|
21
|
+
"@types/node": "25.0.10",
|
|
22
|
+
"typescript": "5.9.3"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc -p tsconfig.json",
|
|
26
|
+
"lint": "tsc -p tsconfig.json --noEmit"
|
|
17
27
|
}
|
|
18
28
|
}
|