openclaw-helper 0.3.5 → 0.4.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.
|
@@ -514,7 +514,7 @@ function scanCosts(agents) {
|
|
|
514
514
|
}
|
|
515
515
|
|
|
516
516
|
// src/dashboard/server.ts
|
|
517
|
-
var _PKG_VER = true ? "0.
|
|
517
|
+
var _PKG_VER = true ? "0.4.0" : "0.2.1";
|
|
518
518
|
var pkgVersion = _PKG_VER;
|
|
519
519
|
function readDoctorLogs(maxLines = 50) {
|
|
520
520
|
if (!existsSync6(DOCTOR_LOG_DIR)) return [];
|
|
@@ -614,6 +614,11 @@ function renderShell() {
|
|
|
614
614
|
<span class="status-dot" :style="'background:' + statusColor"></span>
|
|
615
615
|
<span class="status-label" :style="'color:' + statusColor" x-text="statusText"></span>
|
|
616
616
|
</div>
|
|
617
|
+
<div class="nav-actions" style="display:flex;gap:0.5rem;align-items:center;">
|
|
618
|
+
<button class="btn" style="background:#00A67E;color:#fff;padding:0.35rem 0.75rem;font-size:0.75rem;" :disabled="actionLoading" @click="doStart()">\u25B6 Start</button>
|
|
619
|
+
<button class="btn btn-blue" style="padding:0.35rem 0.75rem;font-size:0.75rem;" :disabled="actionLoading" @click="doRestart()">\u21BA Restart</button>
|
|
620
|
+
<button class="btn" style="background:#ef4444;color:#fff;padding:0.35rem 0.75rem;font-size:0.75rem;" :disabled="actionLoading" @click="doStop()">\u25A0 Stop</button>
|
|
621
|
+
</div>
|
|
617
622
|
<div class="nav-right" x-text="lastCheck ? 'Updated ' + lastCheck : 'Loading...'"></div>
|
|
618
623
|
</div>
|
|
619
624
|
|
|
@@ -941,6 +946,34 @@ function renderShell() {
|
|
|
941
946
|
this.actionLoading = false;
|
|
942
947
|
},
|
|
943
948
|
|
|
949
|
+
async doStart() {
|
|
950
|
+
this.actionLoading = true;
|
|
951
|
+
this.actionResult = '';
|
|
952
|
+
try {
|
|
953
|
+
const res = await fetch('/api/gateway/start', { method: 'POST' });
|
|
954
|
+
const d = await res.json();
|
|
955
|
+
this.actionResult = d.success ? 'Gateway started.' : ('Start failed: ' + (d.message ?? 'unknown'));
|
|
956
|
+
await this.refresh();
|
|
957
|
+
} catch (e) {
|
|
958
|
+
this.actionResult = 'Request failed: ' + e.message;
|
|
959
|
+
}
|
|
960
|
+
this.actionLoading = false;
|
|
961
|
+
},
|
|
962
|
+
|
|
963
|
+
async doStop() {
|
|
964
|
+
this.actionLoading = true;
|
|
965
|
+
this.actionResult = '';
|
|
966
|
+
try {
|
|
967
|
+
const res = await fetch('/api/gateway/stop', { method: 'POST' });
|
|
968
|
+
const d = await res.json();
|
|
969
|
+
this.actionResult = d.success ? 'Gateway stopped.' : ('Stop failed: ' + (d.message ?? 'unknown'));
|
|
970
|
+
await this.refresh();
|
|
971
|
+
} catch (e) {
|
|
972
|
+
this.actionResult = 'Request failed: ' + e.message;
|
|
973
|
+
}
|
|
974
|
+
this.actionLoading = false;
|
|
975
|
+
},
|
|
976
|
+
|
|
944
977
|
async doDoctor() {
|
|
945
978
|
this.actionLoading = true;
|
|
946
979
|
this.actionResult = '';
|
|
@@ -1011,6 +1044,26 @@ async function handleApiRestart(info, res) {
|
|
|
1011
1044
|
res.end(JSON.stringify({ success: false, message: String(err) }));
|
|
1012
1045
|
}
|
|
1013
1046
|
}
|
|
1047
|
+
async function handleApiGatewayStart(info, res) {
|
|
1048
|
+
try {
|
|
1049
|
+
const result = await startGateway(info);
|
|
1050
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1051
|
+
res.end(JSON.stringify({ success: result.success, message: result.output ?? result.error ?? "" }));
|
|
1052
|
+
} catch (err) {
|
|
1053
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1054
|
+
res.end(JSON.stringify({ success: false, message: String(err) }));
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
async function handleApiGatewayStop(info, res) {
|
|
1058
|
+
try {
|
|
1059
|
+
const result = await stopGateway(info);
|
|
1060
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1061
|
+
res.end(JSON.stringify({ success: result.success, message: result.output ?? result.error ?? "" }));
|
|
1062
|
+
} catch (err) {
|
|
1063
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
1064
|
+
res.end(JSON.stringify({ success: false, message: String(err) }));
|
|
1065
|
+
}
|
|
1066
|
+
}
|
|
1014
1067
|
async function handleApiDoctor(info, res) {
|
|
1015
1068
|
try {
|
|
1016
1069
|
const output = await runOpenClawCmd(info, "doctor --non-interactive");
|
|
@@ -1055,6 +1108,10 @@ function startDashboard(options) {
|
|
|
1055
1108
|
handleApiLogs(res);
|
|
1056
1109
|
} else if (method === "POST" && url === "/api/restart") {
|
|
1057
1110
|
await handleApiRestart(info, res);
|
|
1111
|
+
} else if (method === "POST" && url === "/api/gateway/start") {
|
|
1112
|
+
await handleApiGatewayStart(info, res);
|
|
1113
|
+
} else if (method === "POST" && url === "/api/gateway/stop") {
|
|
1114
|
+
await handleApiGatewayStop(info, res);
|
|
1058
1115
|
} else if (method === "POST" && url === "/api/doctor") {
|
|
1059
1116
|
await handleApiDoctor(info, res);
|
|
1060
1117
|
} else {
|
|
@@ -1073,6 +1130,7 @@ function startDashboard(options) {
|
|
|
1073
1130
|
export {
|
|
1074
1131
|
__require,
|
|
1075
1132
|
BINARY_NAME,
|
|
1133
|
+
APP_HOME,
|
|
1076
1134
|
DISPLAY_NAME,
|
|
1077
1135
|
DOCTOR_LOG_DIR,
|
|
1078
1136
|
PID_FILE,
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
APP_HOME,
|
|
3
4
|
BINARY_NAME,
|
|
4
5
|
DISPLAY_NAME,
|
|
5
6
|
DOCTOR_LOG_DIR,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
startDashboard,
|
|
18
19
|
startGateway,
|
|
19
20
|
stopGateway
|
|
20
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-UXL57WT4.js";
|
|
21
22
|
|
|
22
23
|
// src/index.ts
|
|
23
24
|
import { spawnSync } from "child_process";
|
|
@@ -25,9 +26,137 @@ import { Command } from "commander";
|
|
|
25
26
|
|
|
26
27
|
// src/commands/watch.ts
|
|
27
28
|
import { spawn } from "child_process";
|
|
28
|
-
import { writeFileSync, readFileSync, existsSync, unlinkSync, openSync } from "fs";
|
|
29
|
+
import { writeFileSync as writeFileSync2, readFileSync as readFileSync2, existsSync as existsSync2, unlinkSync, openSync } from "fs";
|
|
29
30
|
import chalk from "chalk";
|
|
31
|
+
import { join as join2 } from "path";
|
|
32
|
+
|
|
33
|
+
// src/telemetry.ts
|
|
34
|
+
import { createHash, randomUUID } from "crypto";
|
|
35
|
+
import { execSync } from "child_process";
|
|
36
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
30
37
|
import { join } from "path";
|
|
38
|
+
var MEASUREMENT_ID = "G-B46J8RT804";
|
|
39
|
+
var API_SECRET = "qkqms1nURj2S02Q3WqO7GQ";
|
|
40
|
+
var ENDPOINT = `https://www.google-analytics.com/mp/collect?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`;
|
|
41
|
+
var TELEMETRY_FILE = join(APP_HOME, "telemetry.json");
|
|
42
|
+
function loadState() {
|
|
43
|
+
if (existsSync(TELEMETRY_FILE)) {
|
|
44
|
+
try {
|
|
45
|
+
return JSON.parse(readFileSync(TELEMETRY_FILE, "utf-8"));
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const state = {
|
|
50
|
+
client_id: resolveClientId(),
|
|
51
|
+
opt_out: false,
|
|
52
|
+
first_run_notified: false
|
|
53
|
+
};
|
|
54
|
+
saveState(state);
|
|
55
|
+
return state;
|
|
56
|
+
}
|
|
57
|
+
function saveState(state) {
|
|
58
|
+
try {
|
|
59
|
+
writeFileSync(TELEMETRY_FILE, JSON.stringify(state, null, 2) + "\n");
|
|
60
|
+
} catch {
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function sha256(input) {
|
|
64
|
+
return createHash("sha256").update(input).digest("hex");
|
|
65
|
+
}
|
|
66
|
+
function tryExec(cmd) {
|
|
67
|
+
try {
|
|
68
|
+
return execSync(cmd, { stdio: ["ignore", "pipe", "ignore"], timeout: 2e3 }).toString().trim();
|
|
69
|
+
} catch {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function resolveClientId() {
|
|
74
|
+
const gitEmail = tryExec("git config --global user.email");
|
|
75
|
+
if (gitEmail && gitEmail.includes("@")) return "git:" + sha256(gitEmail);
|
|
76
|
+
const npmEmail = tryExec("npm config get email");
|
|
77
|
+
if (npmEmail && npmEmail.includes("@")) return "npm:" + sha256(npmEmail);
|
|
78
|
+
return "anon:" + randomUUID();
|
|
79
|
+
}
|
|
80
|
+
function isOptedOut() {
|
|
81
|
+
if (process.env.OPENCLAW_NO_TELEMETRY === "1") return true;
|
|
82
|
+
if (process.env.DO_NOT_TRACK === "1") return true;
|
|
83
|
+
if (process.env.CI) return true;
|
|
84
|
+
try {
|
|
85
|
+
const state = loadState();
|
|
86
|
+
return state.opt_out;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function setOptOut(value) {
|
|
92
|
+
const state = loadState();
|
|
93
|
+
state.opt_out = value;
|
|
94
|
+
saveState(state);
|
|
95
|
+
}
|
|
96
|
+
function getTelemetryStatus() {
|
|
97
|
+
const state = loadState();
|
|
98
|
+
return { optOut: state.opt_out, clientId: state.client_id };
|
|
99
|
+
}
|
|
100
|
+
function printFirstRunNotice() {
|
|
101
|
+
const state = loadState();
|
|
102
|
+
if (state.first_run_notified || state.opt_out) return;
|
|
103
|
+
state.first_run_notified = true;
|
|
104
|
+
saveState(state);
|
|
105
|
+
process.stderr.write(
|
|
106
|
+
"\n \u{1F4CA} OpenClaw collects anonymous usage data to improve the product.\n To opt out: openclaw telemetry off (or set OPENCLAW_NO_TELEMETRY=1)\n\n"
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
async function track(eventName, opts) {
|
|
110
|
+
if (isOptedOut()) return;
|
|
111
|
+
let state;
|
|
112
|
+
try {
|
|
113
|
+
state = loadState();
|
|
114
|
+
} catch {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const params = {
|
|
118
|
+
platform: opts.platform,
|
|
119
|
+
engagement_time_msec: 1,
|
|
120
|
+
...opts.command !== void 0 && { command: opts.command },
|
|
121
|
+
...opts.success !== void 0 && { success: opts.success ? 1 : 0 },
|
|
122
|
+
...opts.version !== void 0 && { app_version: opts.version },
|
|
123
|
+
...opts.os !== void 0 && { os_type: opts.os },
|
|
124
|
+
...opts.extra
|
|
125
|
+
};
|
|
126
|
+
const payload = {
|
|
127
|
+
client_id: state.client_id,
|
|
128
|
+
non_personalized_ads: true,
|
|
129
|
+
events: [
|
|
130
|
+
{
|
|
131
|
+
name: eventName,
|
|
132
|
+
params
|
|
133
|
+
}
|
|
134
|
+
]
|
|
135
|
+
};
|
|
136
|
+
try {
|
|
137
|
+
const controller = new AbortController();
|
|
138
|
+
const timer = setTimeout(() => controller.abort(), 3e3);
|
|
139
|
+
await fetch(ENDPOINT, {
|
|
140
|
+
method: "POST",
|
|
141
|
+
headers: { "Content-Type": "application/json" },
|
|
142
|
+
body: JSON.stringify(payload),
|
|
143
|
+
signal: controller.signal
|
|
144
|
+
});
|
|
145
|
+
clearTimeout(timer);
|
|
146
|
+
} catch {
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function trackCommand(command, success, version2) {
|
|
150
|
+
await track("cli_command", {
|
|
151
|
+
platform: "cli",
|
|
152
|
+
command,
|
|
153
|
+
success,
|
|
154
|
+
version: version2,
|
|
155
|
+
os: process.platform
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/commands/watch.ts
|
|
31
160
|
async function watchDaemon(options) {
|
|
32
161
|
if (options.daemon) {
|
|
33
162
|
return daemonize(options);
|
|
@@ -36,14 +165,16 @@ async function watchDaemon(options) {
|
|
|
36
165
|
initLogger();
|
|
37
166
|
ensureDoctorHome();
|
|
38
167
|
const info = detectOpenClaw(options.profile ?? config.openclawProfile);
|
|
39
|
-
|
|
168
|
+
writeFileSync2(PID_FILE, String(process.pid));
|
|
169
|
+
trackCommand("watch start", true).catch(() => {
|
|
170
|
+
});
|
|
40
171
|
log("info", "OpenClaw Doctor started (foreground)");
|
|
41
172
|
log("info", `Gateway port: ${info.gatewayPort}`);
|
|
42
173
|
log("info", `Channels: ${info.channels.join(", ") || "none detected"}`);
|
|
43
174
|
log("info", `Check interval: ${config.checkInterval}s`);
|
|
44
175
|
log("info", `PID: ${process.pid}`);
|
|
45
176
|
if (options.dashboard) {
|
|
46
|
-
const { startDashboard: startDashboard2 } = await import("./server-
|
|
177
|
+
const { startDashboard: startDashboard2 } = await import("./server-GZ3MD6AH.js");
|
|
47
178
|
startDashboard2({ config: options.config });
|
|
48
179
|
}
|
|
49
180
|
const throttle = new RestartThrottle(config.maxRestartsPerHour);
|
|
@@ -105,8 +236,8 @@ function daemonize(options) {
|
|
|
105
236
|
(a) => a !== "-d" && a !== "--daemon"
|
|
106
237
|
);
|
|
107
238
|
const fullArgs = [...execArgv, ...scriptArgs];
|
|
108
|
-
const outLog =
|
|
109
|
-
const errLog =
|
|
239
|
+
const outLog = join2(DOCTOR_LOG_DIR, "daemon.out.log");
|
|
240
|
+
const errLog = join2(DOCTOR_LOG_DIR, "daemon.err.log");
|
|
110
241
|
const out = openSync(outLog, "a");
|
|
111
242
|
const err = openSync(errLog, "a");
|
|
112
243
|
const child = spawn(process.execPath, fullArgs, {
|
|
@@ -115,7 +246,7 @@ function daemonize(options) {
|
|
|
115
246
|
env: { ...process.env, OPENCLAW_DOCTOR_DAEMON: "1" }
|
|
116
247
|
});
|
|
117
248
|
const pid = child.pid;
|
|
118
|
-
|
|
249
|
+
writeFileSync2(PID_FILE, String(pid));
|
|
119
250
|
child.unref();
|
|
120
251
|
console.log(chalk.green(`Doctor started in background (PID ${pid})`));
|
|
121
252
|
console.log(chalk.gray(` Logs: ${outLog}`));
|
|
@@ -138,8 +269,12 @@ async function stopDaemon(options) {
|
|
|
138
269
|
try {
|
|
139
270
|
process.kill(pid, "SIGTERM");
|
|
140
271
|
console.log(chalk.green(`Doctor stopped (PID ${pid})`));
|
|
272
|
+
trackCommand("watch stop", true).catch(() => {
|
|
273
|
+
});
|
|
141
274
|
} catch (err) {
|
|
142
275
|
console.log(chalk.red(`Failed to stop Doctor (PID ${pid}): ${err}`));
|
|
276
|
+
trackCommand("watch stop", false).catch(() => {
|
|
277
|
+
});
|
|
143
278
|
}
|
|
144
279
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
145
280
|
try {
|
|
@@ -148,8 +283,8 @@ async function stopDaemon(options) {
|
|
|
148
283
|
}
|
|
149
284
|
}
|
|
150
285
|
function readDaemonPid() {
|
|
151
|
-
if (!
|
|
152
|
-
const raw =
|
|
286
|
+
if (!existsSync2(PID_FILE)) return null;
|
|
287
|
+
const raw = readFileSync2(PID_FILE, "utf-8").trim();
|
|
153
288
|
const pid = parseInt(raw, 10);
|
|
154
289
|
return isNaN(pid) ? null : pid;
|
|
155
290
|
}
|
|
@@ -224,17 +359,19 @@ async function showStatus(options) {
|
|
|
224
359
|
console.log(chalk2.gray(` OpenClaw ${info.version ?? "unknown"}`));
|
|
225
360
|
console.log(chalk2.gray(` Config: ${info.configPath}`));
|
|
226
361
|
console.log();
|
|
362
|
+
trackCommand("status", true).catch(() => {
|
|
363
|
+
});
|
|
227
364
|
process.exit(result.healthy ? 0 : 1);
|
|
228
365
|
}
|
|
229
366
|
|
|
230
367
|
// src/commands/doctor.ts
|
|
231
|
-
import { readFileSync as
|
|
368
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3 } from "fs";
|
|
232
369
|
import chalk3 from "chalk";
|
|
233
370
|
function findConfigIssues(configPath) {
|
|
234
|
-
if (!
|
|
371
|
+
if (!existsSync3(configPath)) return [];
|
|
235
372
|
let raw;
|
|
236
373
|
try {
|
|
237
|
-
raw = JSON.parse(
|
|
374
|
+
raw = JSON.parse(readFileSync3(configPath, "utf-8"));
|
|
238
375
|
} catch {
|
|
239
376
|
return [{ path: "root", message: "Config file is not valid JSON", fix: () => {
|
|
240
377
|
} }];
|
|
@@ -261,7 +398,7 @@ function findConfigIssues(configPath) {
|
|
|
261
398
|
const origFix = originalFixes[i];
|
|
262
399
|
issues[i].fix = () => {
|
|
263
400
|
origFix();
|
|
264
|
-
|
|
401
|
+
writeFileSync3(configPath, JSON.stringify(raw, null, 2) + "\n");
|
|
265
402
|
};
|
|
266
403
|
}
|
|
267
404
|
}
|
|
@@ -346,11 +483,13 @@ async function runDoctor(options) {
|
|
|
346
483
|
console.log(chalk3.green(" Gateway healthy \u2014 no repair needed"));
|
|
347
484
|
}
|
|
348
485
|
}
|
|
486
|
+
trackCommand("doctor", true).catch(() => {
|
|
487
|
+
});
|
|
349
488
|
console.log();
|
|
350
489
|
}
|
|
351
490
|
|
|
352
491
|
// src/commands/logs.ts
|
|
353
|
-
import { readFileSync as
|
|
492
|
+
import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
|
|
354
493
|
import chalk4 from "chalk";
|
|
355
494
|
function showLogs(options) {
|
|
356
495
|
const config = loadConfig(options.config);
|
|
@@ -361,14 +500,14 @@ function showLogs(options) {
|
|
|
361
500
|
}
|
|
362
501
|
const info = detectOpenClaw(options.profile ?? config.openclawProfile);
|
|
363
502
|
const logFile = options.error ? `${info.logDir}/gateway.err.log` : `${info.logDir}/gateway.log`;
|
|
364
|
-
if (!
|
|
503
|
+
if (!existsSync4(logFile)) {
|
|
365
504
|
console.log(chalk4.yellow(`Log file not found: ${logFile}`));
|
|
366
505
|
return;
|
|
367
506
|
}
|
|
368
507
|
console.log(chalk4.blue.bold(`
|
|
369
508
|
${logFile}
|
|
370
509
|
`));
|
|
371
|
-
const content =
|
|
510
|
+
const content = readFileSync4(logFile, "utf-8");
|
|
372
511
|
const lines = content.trim().split("\n");
|
|
373
512
|
const tail = lines.slice(-maxLines);
|
|
374
513
|
for (const line of tail) {
|
|
@@ -384,8 +523,8 @@ function showLogs(options) {
|
|
|
384
523
|
}
|
|
385
524
|
function showDoctorLogs(maxLines) {
|
|
386
525
|
const { readdirSync } = __require("fs");
|
|
387
|
-
const { join:
|
|
388
|
-
if (!
|
|
526
|
+
const { join: join4 } = __require("path");
|
|
527
|
+
if (!existsSync4(DOCTOR_LOG_DIR)) {
|
|
389
528
|
console.log(chalk4.yellow("No doctor logs found."));
|
|
390
529
|
return;
|
|
391
530
|
}
|
|
@@ -396,9 +535,9 @@ function showDoctorLogs(maxLines) {
|
|
|
396
535
|
}
|
|
397
536
|
const latest = files[0];
|
|
398
537
|
console.log(chalk4.blue.bold(`
|
|
399
|
-
${
|
|
538
|
+
${join4(DOCTOR_LOG_DIR, latest)}
|
|
400
539
|
`));
|
|
401
|
-
const content =
|
|
540
|
+
const content = readFileSync4(join4(DOCTOR_LOG_DIR, latest), "utf-8");
|
|
402
541
|
const lines = content.trim().split("\n");
|
|
403
542
|
const tail = lines.slice(-maxLines);
|
|
404
543
|
for (const line of tail) {
|
|
@@ -417,6 +556,7 @@ function showDoctorLogs(maxLines) {
|
|
|
417
556
|
|
|
418
557
|
// src/commands/gateway.ts
|
|
419
558
|
import chalk5 from "chalk";
|
|
559
|
+
var _VER = true ? "0.4.0" : void 0;
|
|
420
560
|
async function gatewayStart(options) {
|
|
421
561
|
const config = loadConfig(options.config);
|
|
422
562
|
initLogger();
|
|
@@ -424,8 +564,12 @@ async function gatewayStart(options) {
|
|
|
424
564
|
const result = await startGateway(info);
|
|
425
565
|
if (result.success) {
|
|
426
566
|
console.log(chalk5.green("Gateway started"));
|
|
567
|
+
trackCommand("gateway start", true, _VER).catch(() => {
|
|
568
|
+
});
|
|
427
569
|
} else {
|
|
428
570
|
console.log(chalk5.red(`Failed to start gateway: ${result.error}`));
|
|
571
|
+
trackCommand("gateway start", false, _VER).catch(() => {
|
|
572
|
+
});
|
|
429
573
|
process.exit(1);
|
|
430
574
|
}
|
|
431
575
|
}
|
|
@@ -436,8 +580,12 @@ async function gatewayStop(options) {
|
|
|
436
580
|
const result = await stopGateway(info);
|
|
437
581
|
if (result.success) {
|
|
438
582
|
console.log(chalk5.green("Gateway stopped"));
|
|
583
|
+
trackCommand("gateway stop", true, _VER).catch(() => {
|
|
584
|
+
});
|
|
439
585
|
} else {
|
|
440
586
|
console.log(chalk5.red(`Failed to stop gateway: ${result.error}`));
|
|
587
|
+
trackCommand("gateway stop", false, _VER).catch(() => {
|
|
588
|
+
});
|
|
441
589
|
process.exit(1);
|
|
442
590
|
}
|
|
443
591
|
}
|
|
@@ -448,19 +596,23 @@ async function gatewayRestart(options) {
|
|
|
448
596
|
const result = await restartGateway(info);
|
|
449
597
|
if (result.success) {
|
|
450
598
|
console.log(chalk5.green("Gateway restarted"));
|
|
599
|
+
trackCommand("gateway restart", true, _VER).catch(() => {
|
|
600
|
+
});
|
|
451
601
|
} else {
|
|
452
602
|
console.log(chalk5.red(`Failed to restart gateway: ${result.error}`));
|
|
603
|
+
trackCommand("gateway restart", false, _VER).catch(() => {
|
|
604
|
+
});
|
|
453
605
|
process.exit(1);
|
|
454
606
|
}
|
|
455
607
|
}
|
|
456
608
|
|
|
457
609
|
// src/commands/memory.ts
|
|
458
610
|
import chalk6 from "chalk";
|
|
459
|
-
import { existsSync as
|
|
460
|
-
import { join as
|
|
611
|
+
import { existsSync as existsSync5, statSync } from "fs";
|
|
612
|
+
import { join as join3 } from "path";
|
|
461
613
|
import { homedir } from "os";
|
|
462
614
|
function expandHome(p) {
|
|
463
|
-
return p.startsWith("~/") ?
|
|
615
|
+
return p.startsWith("~/") ? join3(homedir(), p.slice(2)) : p;
|
|
464
616
|
}
|
|
465
617
|
async function memoryStatus(options) {
|
|
466
618
|
const config = loadConfig(options.config);
|
|
@@ -470,8 +622,8 @@ async function memoryStatus(options) {
|
|
|
470
622
|
const ws = agent.workspace;
|
|
471
623
|
if (!ws) continue;
|
|
472
624
|
const wsPath = expandHome(ws);
|
|
473
|
-
const memPath =
|
|
474
|
-
const exists =
|
|
625
|
+
const memPath = join3(wsPath, "MEMORY.md");
|
|
626
|
+
const exists = existsSync5(memPath);
|
|
475
627
|
const sizeKB = exists ? Math.round(statSync(memPath).size / 1024) : 0;
|
|
476
628
|
const warn = sizeKB > 50;
|
|
477
629
|
const indicator = warn ? chalk6.yellow("\u26A0") : chalk6.green("\u2713");
|
|
@@ -510,9 +662,30 @@ async function memoryCompact(options) {
|
|
|
510
662
|
console.log();
|
|
511
663
|
}
|
|
512
664
|
|
|
665
|
+
// src/commands/telemetry.ts
|
|
666
|
+
import chalk7 from "chalk";
|
|
667
|
+
function telemetryOn() {
|
|
668
|
+
setOptOut(false);
|
|
669
|
+
console.log(chalk7.green("\u2713 Telemetry enabled. Thanks for helping improve OpenClaw!"));
|
|
670
|
+
}
|
|
671
|
+
function telemetryOff() {
|
|
672
|
+
setOptOut(true);
|
|
673
|
+
console.log(chalk7.yellow("\u2713 Telemetry disabled. Set OPENCLAW_NO_TELEMETRY=1 to suppress permanently."));
|
|
674
|
+
}
|
|
675
|
+
function telemetryStatus() {
|
|
676
|
+
const { optOut, clientId } = getTelemetryStatus();
|
|
677
|
+
const status = optOut ? chalk7.red("disabled") : chalk7.green("enabled");
|
|
678
|
+
console.log(`Telemetry: ${status}`);
|
|
679
|
+
console.log(`Client ID: ${chalk7.dim(clientId)}`);
|
|
680
|
+
console.log();
|
|
681
|
+
console.log(chalk7.dim("Toggle: openclaw telemetry on/off"));
|
|
682
|
+
console.log(chalk7.dim("Env: OPENCLAW_NO_TELEMETRY=1"));
|
|
683
|
+
}
|
|
684
|
+
|
|
513
685
|
// src/index.ts
|
|
514
|
-
var _PKG_VER = true ? "0.
|
|
686
|
+
var _PKG_VER = true ? "0.4.0" : "0.2.1";
|
|
515
687
|
var version = _PKG_VER;
|
|
688
|
+
printFirstRunNotice();
|
|
516
689
|
var program = new Command();
|
|
517
690
|
program.name(BINARY_NAME).description(`${DISPLAY_NAME} \u2014 health monitor and management for OpenClaw services`).version(version);
|
|
518
691
|
var addGlobalOpts = (cmd) => cmd.option("-c, --config <path>", "Path to config file").option("--profile <name>", "OpenClaw profile (default, dev, ...)", "default");
|
|
@@ -535,6 +708,10 @@ var gw = program.command("gateway").description("Manage the OpenClaw gateway ser
|
|
|
535
708
|
addGlobalOpts(gw.command("start").description("Start the gateway")).action(gatewayStart);
|
|
536
709
|
addGlobalOpts(gw.command("stop").description("Stop the gateway")).action(gatewayStop);
|
|
537
710
|
addGlobalOpts(gw.command("restart").description("Restart the gateway")).action(gatewayRestart);
|
|
711
|
+
var tele = program.command("telemetry").description("Manage anonymous usage telemetry");
|
|
712
|
+
tele.command("on").description("Enable telemetry").action(telemetryOn);
|
|
713
|
+
tele.command("off").description("Disable telemetry").action(telemetryOff);
|
|
714
|
+
tele.command("status").description("Show telemetry status").action(telemetryStatus);
|
|
538
715
|
var mem = program.command("memory").description("Memory file health and management");
|
|
539
716
|
addGlobalOpts(mem.command("status").description("Show MEMORY.md size and health per agent")).action(memoryStatus);
|
|
540
717
|
addGlobalOpts(
|