openclaw-service 0.7.0 → 0.7.2
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/dist/index.js +662 -66
- package/dist/index.pkg.cjs +687 -91
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -149,7 +149,7 @@ var init_logger = __esm({
|
|
|
149
149
|
// src/core/openclaw.ts
|
|
150
150
|
import { readFileSync as readFileSync2, existsSync as existsSync3, readdirSync } from "fs";
|
|
151
151
|
import { join as join4 } from "path";
|
|
152
|
-
import { homedir as homedir2 } from "os";
|
|
152
|
+
import { homedir as homedir2, platform } from "os";
|
|
153
153
|
import { execSync } from "child_process";
|
|
154
154
|
import { exec } from "child_process";
|
|
155
155
|
import { promisify } from "util";
|
|
@@ -160,21 +160,23 @@ function getOpenClawHome(profile) {
|
|
|
160
160
|
return join4(homedir2(), ".openclaw");
|
|
161
161
|
}
|
|
162
162
|
function findOpenClawBin() {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
for (const plist of plists) {
|
|
169
|
-
const content = readFileSync2(join4(plistDir, plist), "utf-8");
|
|
170
|
-
const nodeMatch = content.match(
|
|
171
|
-
/<string>(\/[^<]*\/bin\/node)<\/string>/
|
|
163
|
+
if (PLATFORM === "darwin") {
|
|
164
|
+
const plistDir = join4(homedir2(), "Library", "LaunchAgents");
|
|
165
|
+
if (existsSync3(plistDir)) {
|
|
166
|
+
const plists = readdirSync(plistDir).filter(
|
|
167
|
+
(f) => f.includes("openclaw") && f.endsWith(".plist")
|
|
172
168
|
);
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
169
|
+
for (const plist of plists) {
|
|
170
|
+
const content = readFileSync2(join4(plistDir, plist), "utf-8");
|
|
171
|
+
const nodeMatch = content.match(
|
|
172
|
+
/<string>(\/[^<]*\/bin\/node)<\/string>/
|
|
173
|
+
);
|
|
174
|
+
const cliMatch = content.match(
|
|
175
|
+
/<string>(\/[^<]*openclaw[^<]*\.(?:js|mjs))<\/string>/
|
|
176
|
+
);
|
|
177
|
+
if (nodeMatch && cliMatch) {
|
|
178
|
+
return { nodePath: nodeMatch[1], cliBinPath: cliMatch[1] };
|
|
179
|
+
}
|
|
178
180
|
}
|
|
179
181
|
}
|
|
180
182
|
}
|
|
@@ -186,6 +188,7 @@ function findOpenClawBin() {
|
|
|
186
188
|
return null;
|
|
187
189
|
}
|
|
188
190
|
function findLaunchdLabel() {
|
|
191
|
+
if (PLATFORM !== "darwin") return "ai.openclaw.gateway";
|
|
189
192
|
const plistDir = join4(homedir2(), "Library", "LaunchAgents");
|
|
190
193
|
if (!existsSync3(plistDir)) return "ai.openclaw.gateway";
|
|
191
194
|
const plists = readdirSync(plistDir).filter(
|
|
@@ -196,6 +199,18 @@ function findLaunchdLabel() {
|
|
|
196
199
|
}
|
|
197
200
|
return "ai.openclaw.gateway";
|
|
198
201
|
}
|
|
202
|
+
function hasSystemdService() {
|
|
203
|
+
try {
|
|
204
|
+
const { status } = __require("child_process").spawnSync(
|
|
205
|
+
"systemctl",
|
|
206
|
+
["--user", "status", "openclaw"],
|
|
207
|
+
{ stdio: "ignore" }
|
|
208
|
+
);
|
|
209
|
+
return status === 0 || status === 3;
|
|
210
|
+
} catch {
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
199
214
|
function detectOpenClaw(profile = "default") {
|
|
200
215
|
const home = getOpenClawHome(profile);
|
|
201
216
|
const configPath = join4(home, "openclaw.json");
|
|
@@ -291,23 +306,51 @@ async function getGatewayHealth(info) {
|
|
|
291
306
|
}
|
|
292
307
|
}
|
|
293
308
|
function getRestartCommand(info) {
|
|
309
|
+
if (PLATFORM === "win32") {
|
|
310
|
+
throw new Error("Windows native is not supported. Please use WSL 2.");
|
|
311
|
+
}
|
|
312
|
+
if (PLATFORM === "linux") {
|
|
313
|
+
if (hasSystemdService()) {
|
|
314
|
+
return "systemctl --user restart openclaw";
|
|
315
|
+
}
|
|
316
|
+
return `(pgrep -f "openclaw.*gateway" | xargs kill 2>/dev/null || true) && nohup openclaw gateway > /dev/null 2>&1 &`;
|
|
317
|
+
}
|
|
294
318
|
const uid = process.getuid?.() ?? 501;
|
|
295
319
|
return `launchctl kickstart -k gui/${uid}/${info.launchdLabel}`;
|
|
296
320
|
}
|
|
297
321
|
function getStopCommand(info) {
|
|
322
|
+
if (PLATFORM === "win32") {
|
|
323
|
+
throw new Error("Windows native is not supported. Please use WSL 2.");
|
|
324
|
+
}
|
|
325
|
+
if (PLATFORM === "linux") {
|
|
326
|
+
if (hasSystemdService()) {
|
|
327
|
+
return "systemctl --user stop openclaw";
|
|
328
|
+
}
|
|
329
|
+
return `pgrep -f "openclaw.*gateway" | xargs kill 2>/dev/null || true`;
|
|
330
|
+
}
|
|
298
331
|
const uid = process.getuid?.() ?? 501;
|
|
299
332
|
return `launchctl bootout gui/${uid}/${info.launchdLabel} 2>/dev/null || launchctl kill SIGTERM gui/${uid}/${info.launchdLabel} 2>/dev/null || true`;
|
|
300
333
|
}
|
|
301
334
|
function getStartCommand(info) {
|
|
335
|
+
if (PLATFORM === "win32") {
|
|
336
|
+
throw new Error("Windows native is not supported. Please use WSL 2.");
|
|
337
|
+
}
|
|
338
|
+
if (PLATFORM === "linux") {
|
|
339
|
+
if (hasSystemdService()) {
|
|
340
|
+
return "systemctl --user start openclaw";
|
|
341
|
+
}
|
|
342
|
+
return `nohup openclaw gateway > /dev/null 2>&1 &`;
|
|
343
|
+
}
|
|
302
344
|
const uid = process.getuid?.() ?? 501;
|
|
303
345
|
const plistDir = `${process.env.HOME}/Library/LaunchAgents`;
|
|
304
346
|
return `(launchctl bootstrap gui/${uid} ${plistDir}/${info.launchdLabel}.plist 2>/dev/null || true) && launchctl kickstart gui/${uid}/${info.launchdLabel}`;
|
|
305
347
|
}
|
|
306
|
-
var execAsync;
|
|
348
|
+
var execAsync, PLATFORM;
|
|
307
349
|
var init_openclaw = __esm({
|
|
308
350
|
"src/core/openclaw.ts"() {
|
|
309
351
|
"use strict";
|
|
310
352
|
execAsync = promisify(exec);
|
|
353
|
+
PLATFORM = platform();
|
|
311
354
|
}
|
|
312
355
|
});
|
|
313
356
|
|
|
@@ -1339,7 +1382,7 @@ var init_server = __esm({
|
|
|
1339
1382
|
init_process_manager();
|
|
1340
1383
|
init_workspace_scanner();
|
|
1341
1384
|
init_cost_scanner();
|
|
1342
|
-
_PKG_VER = true ? "0.7.
|
|
1385
|
+
_PKG_VER = true ? "0.7.2" : "0.2.1";
|
|
1343
1386
|
pkgVersion = _PKG_VER;
|
|
1344
1387
|
}
|
|
1345
1388
|
});
|
|
@@ -1371,7 +1414,7 @@ var API_SECRET = "qkqms1nURj2S02Q3WqO7GQ";
|
|
|
1371
1414
|
var ENDPOINT = `https://www.google-analytics.com/mp/collect?measurement_id=${MEASUREMENT_ID}&api_secret=${API_SECRET}`;
|
|
1372
1415
|
var TELEMETRY_FILE = join5(APP_HOME, "telemetry.json");
|
|
1373
1416
|
var SESSION_ID = randomUUID();
|
|
1374
|
-
var _version = true ? "0.7.
|
|
1417
|
+
var _version = true ? "0.7.2" : "0.0.0";
|
|
1375
1418
|
function getVersion() {
|
|
1376
1419
|
return _version;
|
|
1377
1420
|
}
|
|
@@ -1880,22 +1923,22 @@ function showLogs(options) {
|
|
|
1880
1923
|
console.log();
|
|
1881
1924
|
}
|
|
1882
1925
|
function showDoctorLogs(maxLines) {
|
|
1883
|
-
const { readdirSync:
|
|
1884
|
-
const { join:
|
|
1926
|
+
const { readdirSync: readdirSync7 } = __require("fs");
|
|
1927
|
+
const { join: join14 } = __require("path");
|
|
1885
1928
|
if (!existsSync10(DOCTOR_LOG_DIR)) {
|
|
1886
1929
|
console.log(chalk6.yellow("No doctor logs found."));
|
|
1887
1930
|
return;
|
|
1888
1931
|
}
|
|
1889
|
-
const files =
|
|
1932
|
+
const files = readdirSync7(DOCTOR_LOG_DIR).filter((f) => f.endsWith(".log")).sort().reverse();
|
|
1890
1933
|
if (files.length === 0) {
|
|
1891
1934
|
console.log(chalk6.yellow("No doctor log files found."));
|
|
1892
1935
|
return;
|
|
1893
1936
|
}
|
|
1894
1937
|
const latest = files[0];
|
|
1895
1938
|
console.log(chalk6.blue.bold(`
|
|
1896
|
-
${
|
|
1939
|
+
${join14(DOCTOR_LOG_DIR, latest)}
|
|
1897
1940
|
`));
|
|
1898
|
-
const content = readFileSync8(
|
|
1941
|
+
const content = readFileSync8(join14(DOCTOR_LOG_DIR, latest), "utf-8");
|
|
1899
1942
|
const lines = content.trim().split("\n");
|
|
1900
1943
|
const tail = lines.slice(-maxLines);
|
|
1901
1944
|
for (const line of tail) {
|
|
@@ -1920,8 +1963,15 @@ init_process_manager();
|
|
|
1920
1963
|
init_logger();
|
|
1921
1964
|
import chalk7 from "chalk";
|
|
1922
1965
|
import { writeFileSync as writeFileSync5, unlinkSync as unlinkSync2 } from "fs";
|
|
1923
|
-
|
|
1966
|
+
import { platform as platform2 } from "os";
|
|
1967
|
+
function showPlatformNote() {
|
|
1968
|
+
if (platform2() === "linux") {
|
|
1969
|
+
console.log(chalk7.cyan("Running on Linux/WSL. Using systemd or direct process management (launchctl not available)."));
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
var _VER = true ? "0.7.2" : void 0;
|
|
1924
1973
|
async function gatewayStart(options) {
|
|
1974
|
+
showPlatformNote();
|
|
1925
1975
|
const config = loadConfig(options.config);
|
|
1926
1976
|
initLogger();
|
|
1927
1977
|
ensureDoctorHome();
|
|
@@ -1943,6 +1993,7 @@ async function gatewayStart(options) {
|
|
|
1943
1993
|
}
|
|
1944
1994
|
}
|
|
1945
1995
|
async function gatewayStop(options) {
|
|
1996
|
+
showPlatformNote();
|
|
1946
1997
|
const config = loadConfig(options.config);
|
|
1947
1998
|
initLogger();
|
|
1948
1999
|
ensureDoctorHome();
|
|
@@ -1962,6 +2013,7 @@ async function gatewayStop(options) {
|
|
|
1962
2013
|
}
|
|
1963
2014
|
}
|
|
1964
2015
|
async function gatewayRestart(options) {
|
|
2016
|
+
showPlatformNote();
|
|
1965
2017
|
const config = loadConfig(options.config);
|
|
1966
2018
|
initLogger();
|
|
1967
2019
|
ensureDoctorHome();
|
|
@@ -1987,12 +2039,25 @@ async function gatewayRestart(options) {
|
|
|
1987
2039
|
init_config();
|
|
1988
2040
|
init_openclaw();
|
|
1989
2041
|
import chalk8 from "chalk";
|
|
1990
|
-
import { existsSync as existsSync12, statSync as statSync3 } from "fs";
|
|
1991
|
-
import { join as join10 } from "path";
|
|
2042
|
+
import { existsSync as existsSync12, statSync as statSync3, readFileSync as readFileSync9, readdirSync as readdirSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync6 } from "fs";
|
|
2043
|
+
import { join as join10, basename as basename2 } from "path";
|
|
1992
2044
|
import { homedir as homedir5 } from "os";
|
|
2045
|
+
import { createInterface } from "readline";
|
|
1993
2046
|
function expandHome2(p) {
|
|
1994
2047
|
return p.startsWith("~/") ? join10(homedir5(), p.slice(2)) : p;
|
|
1995
2048
|
}
|
|
2049
|
+
function getAgentMemoryPaths(agents) {
|
|
2050
|
+
const paths = [];
|
|
2051
|
+
for (const agent of agents) {
|
|
2052
|
+
const ws = agent.workspace;
|
|
2053
|
+
if (!ws) continue;
|
|
2054
|
+
const wsPath = expandHome2(ws);
|
|
2055
|
+
if (existsSync12(wsPath)) {
|
|
2056
|
+
paths.push({ agent: agent.name, dir: wsPath });
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
return paths;
|
|
2060
|
+
}
|
|
1996
2061
|
async function memoryStatus(options) {
|
|
1997
2062
|
const config = loadConfig(options.config);
|
|
1998
2063
|
const info = detectOpenClaw(options.profile ?? config.openclawProfile);
|
|
@@ -2017,11 +2082,54 @@ async function memorySearch(query, options) {
|
|
|
2017
2082
|
console.log(chalk8.bold(`
|
|
2018
2083
|
Searching memory: "${query}"
|
|
2019
2084
|
`));
|
|
2020
|
-
const
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2085
|
+
const agentPaths = getAgentMemoryPaths(info.agents);
|
|
2086
|
+
let found = false;
|
|
2087
|
+
for (const { agent, dir } of agentPaths) {
|
|
2088
|
+
const filesToSearch = [];
|
|
2089
|
+
const memPath = join10(dir, "MEMORY.md");
|
|
2090
|
+
if (existsSync12(memPath)) filesToSearch.push(memPath);
|
|
2091
|
+
const memDir = join10(dir, "memory");
|
|
2092
|
+
if (existsSync12(memDir)) {
|
|
2093
|
+
try {
|
|
2094
|
+
const files = readdirSync5(memDir).filter((f) => f.endsWith(".md"));
|
|
2095
|
+
for (const f of files) {
|
|
2096
|
+
filesToSearch.push(join10(memDir, f));
|
|
2097
|
+
}
|
|
2098
|
+
} catch {
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
for (const filePath of filesToSearch) {
|
|
2102
|
+
try {
|
|
2103
|
+
const content = readFileSync9(filePath, "utf-8");
|
|
2104
|
+
const lines = content.split("\n");
|
|
2105
|
+
const lowerQuery = query.toLowerCase();
|
|
2106
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2107
|
+
if (lines[i].toLowerCase().includes(lowerQuery)) {
|
|
2108
|
+
if (!found) found = true;
|
|
2109
|
+
const relPath = basename2(filePath);
|
|
2110
|
+
const contextStart = Math.max(0, i - 1);
|
|
2111
|
+
const contextEnd = Math.min(lines.length, i + 2);
|
|
2112
|
+
const context = lines.slice(contextStart, contextEnd).map((l, idx) => {
|
|
2113
|
+
const lineNum = contextStart + idx + 1;
|
|
2114
|
+
const prefix = lineNum === i + 1 ? chalk8.yellow("\u2192") : " ";
|
|
2115
|
+
return ` ${prefix} ${chalk8.gray(`${lineNum}:`)} ${l}`;
|
|
2116
|
+
}).join("\n");
|
|
2117
|
+
console.log(` ${chalk8.cyan(agent)} ${chalk8.gray("/")} ${chalk8.white(relPath)}${chalk8.gray(`:${i + 1}`)}`);
|
|
2118
|
+
console.log(context);
|
|
2119
|
+
console.log();
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
} catch {
|
|
2123
|
+
}
|
|
2124
|
+
}
|
|
2125
|
+
}
|
|
2126
|
+
if (!found) {
|
|
2127
|
+
const output = await runOpenClawCmd(info, `memory search "${query}"`);
|
|
2128
|
+
if (output) {
|
|
2129
|
+
console.log(output);
|
|
2130
|
+
} else {
|
|
2131
|
+
console.log(chalk8.yellow(" No results found."));
|
|
2132
|
+
}
|
|
2025
2133
|
}
|
|
2026
2134
|
console.log();
|
|
2027
2135
|
}
|
|
@@ -2040,36 +2148,512 @@ async function memoryCompact(options) {
|
|
|
2040
2148
|
}
|
|
2041
2149
|
console.log();
|
|
2042
2150
|
}
|
|
2151
|
+
async function memoryGc(options) {
|
|
2152
|
+
const config = loadConfig(options.config);
|
|
2153
|
+
const info = detectOpenClaw(options.profile ?? config.openclawProfile);
|
|
2154
|
+
const maxAgeDays = parseInt(options.days ?? "30", 10);
|
|
2155
|
+
const cutoff = Date.now() - maxAgeDays * 24 * 3600 * 1e3;
|
|
2156
|
+
console.log(chalk8.bold(`
|
|
2157
|
+
Memory GC \u2014 removing daily files older than ${maxAgeDays} days
|
|
2158
|
+
`));
|
|
2159
|
+
const agentPaths = getAgentMemoryPaths(info.agents);
|
|
2160
|
+
const filesToDelete = [];
|
|
2161
|
+
const dailyPattern = /^\d{4}-\d{2}-\d{2}\.md$/;
|
|
2162
|
+
for (const { agent, dir } of agentPaths) {
|
|
2163
|
+
const memDir = join10(dir, "memory");
|
|
2164
|
+
if (!existsSync12(memDir)) continue;
|
|
2165
|
+
try {
|
|
2166
|
+
const files = readdirSync5(memDir).filter((f) => dailyPattern.test(f));
|
|
2167
|
+
for (const f of files) {
|
|
2168
|
+
const fpath = join10(memDir, f);
|
|
2169
|
+
try {
|
|
2170
|
+
const stat = statSync3(fpath);
|
|
2171
|
+
if (stat.mtimeMs < cutoff) {
|
|
2172
|
+
filesToDelete.push({ path: fpath, agent, name: f, size: stat.size });
|
|
2173
|
+
}
|
|
2174
|
+
} catch {
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
} catch {
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
if (filesToDelete.length === 0) {
|
|
2181
|
+
console.log(chalk8.green(" No old daily memory files found. Nothing to clean up.\n"));
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
console.log(` Found ${chalk8.yellow(String(filesToDelete.length))} files to remove:
|
|
2185
|
+
`);
|
|
2186
|
+
for (const f of filesToDelete) {
|
|
2187
|
+
const sizeKB = Math.round(f.size / 1024);
|
|
2188
|
+
console.log(` ${chalk8.gray("\u2022")} ${f.agent} / ${f.name} ${chalk8.gray(`(${sizeKB}KB)`)}`);
|
|
2189
|
+
}
|
|
2190
|
+
console.log();
|
|
2191
|
+
const totalKB = Math.round(filesToDelete.reduce((s, f) => s + f.size, 0) / 1024);
|
|
2192
|
+
console.log(` Total: ${chalk8.yellow(`${totalKB}KB`)} across ${filesToDelete.length} files
|
|
2193
|
+
`);
|
|
2194
|
+
if (!options.force) {
|
|
2195
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
2196
|
+
const answer = await new Promise((resolve3) => {
|
|
2197
|
+
rl.question(" Delete these files? [y/N] ", resolve3);
|
|
2198
|
+
});
|
|
2199
|
+
rl.close();
|
|
2200
|
+
if (answer.toLowerCase() !== "y") {
|
|
2201
|
+
console.log(chalk8.gray(" Cancelled.\n"));
|
|
2202
|
+
return;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
let deleted = 0;
|
|
2206
|
+
for (const f of filesToDelete) {
|
|
2207
|
+
try {
|
|
2208
|
+
unlinkSync3(f.path);
|
|
2209
|
+
deleted++;
|
|
2210
|
+
} catch (err) {
|
|
2211
|
+
console.log(chalk8.red(` Failed to delete ${f.name}: ${err}`));
|
|
2212
|
+
}
|
|
2213
|
+
}
|
|
2214
|
+
console.log(chalk8.green(`
|
|
2215
|
+
Deleted ${deleted} files.
|
|
2216
|
+
`));
|
|
2217
|
+
}
|
|
2218
|
+
async function memoryExport(options) {
|
|
2219
|
+
const config = loadConfig(options.config);
|
|
2220
|
+
const info = detectOpenClaw(options.profile ?? config.openclawProfile);
|
|
2221
|
+
const agentPaths = getAgentMemoryPaths(info.agents);
|
|
2222
|
+
const parts = [];
|
|
2223
|
+
parts.push(`# OpenClaw Memory Export`);
|
|
2224
|
+
parts.push(`# Generated: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
2225
|
+
`);
|
|
2226
|
+
for (const { agent, dir } of agentPaths) {
|
|
2227
|
+
const agentParts = [];
|
|
2228
|
+
const memPath = join10(dir, "MEMORY.md");
|
|
2229
|
+
if (existsSync12(memPath)) {
|
|
2230
|
+
try {
|
|
2231
|
+
const content = readFileSync9(memPath, "utf-8");
|
|
2232
|
+
agentParts.push(`### MEMORY.md
|
|
2233
|
+
|
|
2234
|
+
${content}`);
|
|
2235
|
+
} catch {
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
const memDir = join10(dir, "memory");
|
|
2239
|
+
if (existsSync12(memDir)) {
|
|
2240
|
+
try {
|
|
2241
|
+
const files = readdirSync5(memDir).filter((f) => f.endsWith(".md")).sort();
|
|
2242
|
+
for (const f of files) {
|
|
2243
|
+
try {
|
|
2244
|
+
const content = readFileSync9(join10(memDir, f), "utf-8");
|
|
2245
|
+
agentParts.push(`### memory/${f}
|
|
2246
|
+
|
|
2247
|
+
${content}`);
|
|
2248
|
+
} catch {
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
} catch {
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
if (agentParts.length > 0) {
|
|
2255
|
+
parts.push(`## Agent: ${agent}
|
|
2256
|
+
`);
|
|
2257
|
+
parts.push(agentParts.join("\n---\n\n"));
|
|
2258
|
+
parts.push("");
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
if (parts.length <= 2) {
|
|
2262
|
+
console.log(chalk8.yellow("\n No memory files found to export.\n"));
|
|
2263
|
+
return;
|
|
2264
|
+
}
|
|
2265
|
+
const result = parts.join("\n");
|
|
2266
|
+
if (options.output) {
|
|
2267
|
+
writeFileSync6(options.output, result, "utf-8");
|
|
2268
|
+
console.log(chalk8.green(`
|
|
2269
|
+
Exported memory to ${options.output}
|
|
2270
|
+
`));
|
|
2271
|
+
} else {
|
|
2272
|
+
console.log(result);
|
|
2273
|
+
}
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
// src/commands/cost.ts
|
|
2277
|
+
init_config();
|
|
2278
|
+
init_openclaw();
|
|
2279
|
+
import chalk9 from "chalk";
|
|
2280
|
+
import { existsSync as existsSync13, readdirSync as readdirSync6, readFileSync as readFileSync10, statSync as statSync4 } from "fs";
|
|
2281
|
+
import { join as join11 } from "path";
|
|
2282
|
+
import { homedir as homedir6 } from "os";
|
|
2283
|
+
var RATES = {
|
|
2284
|
+
"claude-opus-4": { input: 15, output: 75 },
|
|
2285
|
+
"claude-sonnet-4": { input: 3, output: 15 },
|
|
2286
|
+
"claude-haiku-3-5": { input: 0.8, output: 4 },
|
|
2287
|
+
"gpt-4o": { input: 2.5, output: 10 },
|
|
2288
|
+
"gpt-4o-mini": { input: 0.15, output: 0.6 }
|
|
2289
|
+
};
|
|
2290
|
+
var DEFAULT_RATE = { input: 3, output: 15 };
|
|
2291
|
+
function getRate(model) {
|
|
2292
|
+
if (RATES[model]) return RATES[model];
|
|
2293
|
+
for (const [key, rate] of Object.entries(RATES)) {
|
|
2294
|
+
if (model.startsWith(key)) return rate;
|
|
2295
|
+
}
|
|
2296
|
+
return DEFAULT_RATE;
|
|
2297
|
+
}
|
|
2298
|
+
function calcCost(model, inputTokens, outputTokens) {
|
|
2299
|
+
const rate = getRate(model);
|
|
2300
|
+
return (inputTokens * rate.input + outputTokens * rate.output) / 1e6;
|
|
2301
|
+
}
|
|
2302
|
+
function expandHome3(p) {
|
|
2303
|
+
return p.startsWith("~/") ? join11(homedir6(), p.slice(2)) : p;
|
|
2304
|
+
}
|
|
2305
|
+
function scanSessionFiles(agents, sinceDays) {
|
|
2306
|
+
const entries = [];
|
|
2307
|
+
const cutoff = Date.now() - sinceDays * 24 * 3600 * 1e3;
|
|
2308
|
+
for (const agent of agents) {
|
|
2309
|
+
const searchPaths = [];
|
|
2310
|
+
searchPaths.push(join11(homedir6(), ".openclaw", "agents", agent.id, "sessions"));
|
|
2311
|
+
if (agent.workspace) {
|
|
2312
|
+
const ws = expandHome3(agent.workspace);
|
|
2313
|
+
searchPaths.push(join11(ws, "sessions"));
|
|
2314
|
+
searchPaths.push(join11(ws, "logs"));
|
|
2315
|
+
}
|
|
2316
|
+
for (const sessDir of searchPaths) {
|
|
2317
|
+
if (!existsSync13(sessDir)) continue;
|
|
2318
|
+
const files = readdirSync6(sessDir).filter((f) => f.endsWith(".jsonl") || f.endsWith(".json"));
|
|
2319
|
+
for (const file of files) {
|
|
2320
|
+
const fpath = join11(sessDir, file);
|
|
2321
|
+
try {
|
|
2322
|
+
const mtime = statSync4(fpath).mtimeMs;
|
|
2323
|
+
if (mtime < cutoff) continue;
|
|
2324
|
+
} catch {
|
|
2325
|
+
continue;
|
|
2326
|
+
}
|
|
2327
|
+
try {
|
|
2328
|
+
const lines = readFileSync10(fpath, "utf-8").split("\n").filter(Boolean);
|
|
2329
|
+
for (const line of lines) {
|
|
2330
|
+
try {
|
|
2331
|
+
const msg = JSON.parse(line);
|
|
2332
|
+
if (msg.type !== "message" || !msg.message?.usage) continue;
|
|
2333
|
+
const usage = msg.message.usage;
|
|
2334
|
+
const ts = msg.timestamp ? new Date(msg.timestamp).getTime() : msg.message?.timestamp ?? 0;
|
|
2335
|
+
if (ts < cutoff) continue;
|
|
2336
|
+
const model = msg.message?.model ?? msg.model ?? "unknown";
|
|
2337
|
+
const inputTokens = usage.input_tokens ?? usage.inputTokens ?? 0;
|
|
2338
|
+
const outputTokens = usage.output_tokens ?? usage.outputTokens ?? 0;
|
|
2339
|
+
if (inputTokens === 0 && outputTokens === 0) continue;
|
|
2340
|
+
entries.push({
|
|
2341
|
+
model,
|
|
2342
|
+
inputTokens,
|
|
2343
|
+
outputTokens,
|
|
2344
|
+
timestamp: ts,
|
|
2345
|
+
agentName: agent.name,
|
|
2346
|
+
agentId: agent.id
|
|
2347
|
+
});
|
|
2348
|
+
} catch {
|
|
2349
|
+
}
|
|
2350
|
+
}
|
|
2351
|
+
} catch {
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
}
|
|
2356
|
+
const globalLogDir = join11(homedir6(), ".openclaw", "logs");
|
|
2357
|
+
if (existsSync13(globalLogDir)) {
|
|
2358
|
+
const files = readdirSync6(globalLogDir).filter((f) => f.endsWith(".jsonl"));
|
|
2359
|
+
for (const file of files) {
|
|
2360
|
+
const fpath = join11(globalLogDir, file);
|
|
2361
|
+
try {
|
|
2362
|
+
const mtime = statSync4(fpath).mtimeMs;
|
|
2363
|
+
if (mtime < cutoff) continue;
|
|
2364
|
+
} catch {
|
|
2365
|
+
continue;
|
|
2366
|
+
}
|
|
2367
|
+
try {
|
|
2368
|
+
const lines = readFileSync10(fpath, "utf-8").split("\n").filter(Boolean);
|
|
2369
|
+
for (const line of lines) {
|
|
2370
|
+
try {
|
|
2371
|
+
const msg = JSON.parse(line);
|
|
2372
|
+
if (msg.type !== "message" || !msg.message?.usage) continue;
|
|
2373
|
+
const usage = msg.message.usage;
|
|
2374
|
+
const ts = msg.timestamp ? new Date(msg.timestamp).getTime() : msg.message?.timestamp ?? 0;
|
|
2375
|
+
if (ts < cutoff) continue;
|
|
2376
|
+
const model = msg.message?.model ?? msg.model ?? "unknown";
|
|
2377
|
+
const inputTokens = usage.input_tokens ?? usage.inputTokens ?? 0;
|
|
2378
|
+
const outputTokens = usage.output_tokens ?? usage.outputTokens ?? 0;
|
|
2379
|
+
if (inputTokens === 0 && outputTokens === 0) continue;
|
|
2380
|
+
const agentId = msg.agentId ?? msg.message?.agentId ?? "unknown";
|
|
2381
|
+
const agentName = msg.agentName ?? msg.message?.agentName ?? agentId;
|
|
2382
|
+
entries.push({ model, inputTokens, outputTokens, timestamp: ts, agentName, agentId });
|
|
2383
|
+
} catch {
|
|
2384
|
+
}
|
|
2385
|
+
}
|
|
2386
|
+
} catch {
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
}
|
|
2390
|
+
return entries;
|
|
2391
|
+
}
|
|
2392
|
+
function formatCost(cost) {
|
|
2393
|
+
if (cost < 0.01) return `$${cost.toFixed(4)}`;
|
|
2394
|
+
return `$${cost.toFixed(2)}`;
|
|
2395
|
+
}
|
|
2396
|
+
function formatTokens(n) {
|
|
2397
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
2398
|
+
if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
|
|
2399
|
+
return String(n);
|
|
2400
|
+
}
|
|
2401
|
+
async function showCost(options) {
|
|
2402
|
+
const config = loadConfig(options.config);
|
|
2403
|
+
const info = detectOpenClaw(options.profile ?? config.openclawProfile);
|
|
2404
|
+
const days = parseInt(options.days ?? "30", 10);
|
|
2405
|
+
if (info.agents.length === 0) {
|
|
2406
|
+
console.log(chalk9.yellow("\n No agents found in openclaw config."));
|
|
2407
|
+
console.log(chalk9.gray(" Make sure openclaw is installed and configured.\n"));
|
|
2408
|
+
return;
|
|
2409
|
+
}
|
|
2410
|
+
const entries = scanSessionFiles(
|
|
2411
|
+
info.agents.map((a) => ({ id: a.id, name: a.name, workspace: a.workspace })),
|
|
2412
|
+
days
|
|
2413
|
+
);
|
|
2414
|
+
if (entries.length === 0) {
|
|
2415
|
+
console.log(chalk9.yellow("\n No session logs found."));
|
|
2416
|
+
console.log(chalk9.gray(" OpenClaw stores session logs in:"));
|
|
2417
|
+
console.log(chalk9.gray(` ~/.openclaw/agents/<agent-id>/sessions/`));
|
|
2418
|
+
console.log(chalk9.gray(` ~/.openclaw/logs/
|
|
2419
|
+
`));
|
|
2420
|
+
return;
|
|
2421
|
+
}
|
|
2422
|
+
const now = Date.now();
|
|
2423
|
+
const todayStart = /* @__PURE__ */ new Date();
|
|
2424
|
+
todayStart.setHours(0, 0, 0, 0);
|
|
2425
|
+
const weekStart = now - 7 * 24 * 3600 * 1e3;
|
|
2426
|
+
const monthStart = now - 30 * 24 * 3600 * 1e3;
|
|
2427
|
+
const byAgent = {};
|
|
2428
|
+
const byModel = {};
|
|
2429
|
+
for (const e of entries) {
|
|
2430
|
+
const cost = calcCost(e.model, e.inputTokens, e.outputTokens);
|
|
2431
|
+
if (!byAgent[e.agentName]) byAgent[e.agentName] = { today: 0, week: 0, month: 0, tokens: 0 };
|
|
2432
|
+
const ag = byAgent[e.agentName];
|
|
2433
|
+
ag.tokens += e.inputTokens + e.outputTokens;
|
|
2434
|
+
if (e.timestamp >= monthStart) ag.month += cost;
|
|
2435
|
+
if (e.timestamp >= weekStart) ag.week += cost;
|
|
2436
|
+
if (e.timestamp >= todayStart.getTime()) ag.today += cost;
|
|
2437
|
+
if (!byModel[e.model]) byModel[e.model] = { today: 0, week: 0, month: 0, input: 0, output: 0 };
|
|
2438
|
+
const md = byModel[e.model];
|
|
2439
|
+
md.input += e.inputTokens;
|
|
2440
|
+
md.output += e.outputTokens;
|
|
2441
|
+
if (e.timestamp >= monthStart) md.month += cost;
|
|
2442
|
+
if (e.timestamp >= weekStart) md.week += cost;
|
|
2443
|
+
if (e.timestamp >= todayStart.getTime()) md.today += cost;
|
|
2444
|
+
}
|
|
2445
|
+
const totalToday = Object.values(byAgent).reduce((s, a) => s + a.today, 0);
|
|
2446
|
+
const totalWeek = Object.values(byAgent).reduce((s, a) => s + a.week, 0);
|
|
2447
|
+
const totalMonth = Object.values(byAgent).reduce((s, a) => s + a.month, 0);
|
|
2448
|
+
if (options.json) {
|
|
2449
|
+
console.log(JSON.stringify({
|
|
2450
|
+
period: { days },
|
|
2451
|
+
summary: { today: totalToday, week: totalWeek, month: totalMonth, currency: "USD" },
|
|
2452
|
+
byAgent: Object.entries(byAgent).map(([name, v]) => ({ name, ...v })),
|
|
2453
|
+
byModel: Object.entries(byModel).map(([model, v]) => ({ model, ...v })),
|
|
2454
|
+
entries: entries.length
|
|
2455
|
+
}, null, 2));
|
|
2456
|
+
return;
|
|
2457
|
+
}
|
|
2458
|
+
console.log(chalk9.bold("\n Token Cost Summary\n"));
|
|
2459
|
+
console.log(` ${"Period".padEnd(14)} ${"Cost".padStart(10)}`);
|
|
2460
|
+
console.log(` ${"\u2500".repeat(14)} ${"\u2500".repeat(10)}`);
|
|
2461
|
+
console.log(` ${"Today".padEnd(14)} ${chalk9.green(formatCost(totalToday).padStart(10))}`);
|
|
2462
|
+
console.log(` ${"This week".padEnd(14)} ${chalk9.cyan(formatCost(totalWeek).padStart(10))}`);
|
|
2463
|
+
console.log(` ${"Last 30 days".padEnd(14)} ${chalk9.yellow(formatCost(totalMonth).padStart(10))}`);
|
|
2464
|
+
const agentEntries = Object.entries(byAgent).sort((a, b) => b[1].month - a[1].month);
|
|
2465
|
+
if (agentEntries.length > 0) {
|
|
2466
|
+
console.log(chalk9.bold("\n By Agent\n"));
|
|
2467
|
+
console.log(` ${"Agent".padEnd(20)} ${"Today".padStart(10)} ${"Week".padStart(10)} ${"Month".padStart(10)} ${"Tokens".padStart(10)}`);
|
|
2468
|
+
console.log(` ${"\u2500".repeat(20)} ${"\u2500".repeat(10)} ${"\u2500".repeat(10)} ${"\u2500".repeat(10)} ${"\u2500".repeat(10)}`);
|
|
2469
|
+
for (const [name, v] of agentEntries) {
|
|
2470
|
+
console.log(` ${name.padEnd(20)} ${formatCost(v.today).padStart(10)} ${formatCost(v.week).padStart(10)} ${formatCost(v.month).padStart(10)} ${chalk9.gray(formatTokens(v.tokens).padStart(10))}`);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
const modelEntries = Object.entries(byModel).sort((a, b) => b[1].month - a[1].month);
|
|
2474
|
+
if (modelEntries.length > 0) {
|
|
2475
|
+
console.log(chalk9.bold("\n By Model\n"));
|
|
2476
|
+
console.log(` ${"Model".padEnd(24)} ${"Today".padStart(10)} ${"Week".padStart(10)} ${"Month".padStart(10)} ${"In Tokens".padStart(10)} ${"Out Tokens".padStart(10)}`);
|
|
2477
|
+
console.log(` ${"\u2500".repeat(24)} ${"\u2500".repeat(10)} ${"\u2500".repeat(10)} ${"\u2500".repeat(10)} ${"\u2500".repeat(10)} ${"\u2500".repeat(10)}`);
|
|
2478
|
+
for (const [model, v] of modelEntries) {
|
|
2479
|
+
console.log(` ${model.padEnd(24)} ${formatCost(v.today).padStart(10)} ${formatCost(v.week).padStart(10)} ${formatCost(v.month).padStart(10)} ${chalk9.gray(formatTokens(v.input).padStart(10))} ${chalk9.gray(formatTokens(v.output).padStart(10))}`);
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
console.log();
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
// src/commands/mcp.ts
|
|
2486
|
+
import chalk10 from "chalk";
|
|
2487
|
+
import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
|
|
2488
|
+
import { join as join12 } from "path";
|
|
2489
|
+
import { homedir as homedir7 } from "os";
|
|
2490
|
+
import { execSync as execSync3 } from "child_process";
|
|
2491
|
+
var CONFIG_LOCATIONS = [
|
|
2492
|
+
{ path: join12(homedir7(), ".config", "claude", "claude_desktop_config.json"), label: "Claude Desktop" },
|
|
2493
|
+
{ path: join12(homedir7(), "Library", "Application Support", "Claude", "claude_desktop_config.json"), label: "Claude Desktop (macOS)" },
|
|
2494
|
+
{ path: join12(homedir7(), ".config", "cursor", "mcp.json"), label: "Cursor" },
|
|
2495
|
+
{ path: join12(homedir7(), ".openclaw", "config.yaml"), label: "OpenClaw" },
|
|
2496
|
+
{ path: join12(homedir7(), ".openclaw", "mcp.json"), label: "OpenClaw MCP" }
|
|
2497
|
+
];
|
|
2498
|
+
function findMcpConfigs() {
|
|
2499
|
+
const servers = [];
|
|
2500
|
+
for (const loc of CONFIG_LOCATIONS) {
|
|
2501
|
+
if (!existsSync14(loc.path)) continue;
|
|
2502
|
+
try {
|
|
2503
|
+
const raw = readFileSync11(loc.path, "utf-8");
|
|
2504
|
+
if (loc.path.endsWith(".yaml") || loc.path.endsWith(".yml")) {
|
|
2505
|
+
const mcpMatch = raw.match(/mcp_servers:\s*\n([\s\S]*?)(?:\n\w|\n*$)/);
|
|
2506
|
+
if (mcpMatch) {
|
|
2507
|
+
const lines = mcpMatch[1].split("\n");
|
|
2508
|
+
for (const line of lines) {
|
|
2509
|
+
const nameMatch = line.match(/^\s+-\s+name:\s*(.+)/);
|
|
2510
|
+
if (nameMatch) {
|
|
2511
|
+
servers.push({
|
|
2512
|
+
name: nameMatch[1].trim(),
|
|
2513
|
+
type: "unknown",
|
|
2514
|
+
source: loc.label,
|
|
2515
|
+
status: "UNKNOWN"
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2520
|
+
continue;
|
|
2521
|
+
}
|
|
2522
|
+
const config = JSON.parse(raw);
|
|
2523
|
+
const mcpServers = config.mcpServers ?? config.mcp_servers ?? config.servers ?? {};
|
|
2524
|
+
for (const [name, def] of Object.entries(mcpServers)) {
|
|
2525
|
+
const d = def;
|
|
2526
|
+
const server = {
|
|
2527
|
+
name,
|
|
2528
|
+
type: d.command ? "stdio" : d.url ? "http" : "unknown",
|
|
2529
|
+
command: d.command,
|
|
2530
|
+
url: d.url,
|
|
2531
|
+
args: d.args,
|
|
2532
|
+
env: d.env,
|
|
2533
|
+
source: loc.label,
|
|
2534
|
+
status: "UNKNOWN"
|
|
2535
|
+
};
|
|
2536
|
+
if (server.type === "stdio" && server.command) {
|
|
2537
|
+
server.status = checkProcessRunning(server.command) ? "RUNNING" : "STOPPED";
|
|
2538
|
+
} else if (server.type === "http") {
|
|
2539
|
+
server.status = "UNKNOWN";
|
|
2540
|
+
}
|
|
2541
|
+
servers.push(server);
|
|
2542
|
+
}
|
|
2543
|
+
} catch {
|
|
2544
|
+
}
|
|
2545
|
+
}
|
|
2546
|
+
return servers;
|
|
2547
|
+
}
|
|
2548
|
+
function checkProcessRunning(command) {
|
|
2549
|
+
try {
|
|
2550
|
+
const baseName = command.split("/").pop() ?? command;
|
|
2551
|
+
const result = execSync3(`pgrep -f "${baseName}"`, { encoding: "utf-8", timeout: 3e3 });
|
|
2552
|
+
return result.trim().length > 0;
|
|
2553
|
+
} catch {
|
|
2554
|
+
return false;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2557
|
+
function statusColor(status) {
|
|
2558
|
+
switch (status) {
|
|
2559
|
+
case "RUNNING":
|
|
2560
|
+
return chalk10.green(status);
|
|
2561
|
+
case "STOPPED":
|
|
2562
|
+
return chalk10.red(status);
|
|
2563
|
+
default:
|
|
2564
|
+
return chalk10.gray(status);
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
async function mcpList() {
|
|
2568
|
+
const servers = findMcpConfigs();
|
|
2569
|
+
if (servers.length === 0) {
|
|
2570
|
+
console.log(chalk10.yellow("\n No MCP server configurations found."));
|
|
2571
|
+
console.log(chalk10.gray(" Checked:"));
|
|
2572
|
+
for (const loc of CONFIG_LOCATIONS) {
|
|
2573
|
+
console.log(chalk10.gray(` ${loc.path}`));
|
|
2574
|
+
}
|
|
2575
|
+
console.log(chalk10.gray("\n Configure MCP servers in Claude Desktop:"));
|
|
2576
|
+
console.log(chalk10.gray(` ${CONFIG_LOCATIONS[0].path}
|
|
2577
|
+
`));
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2580
|
+
console.log(chalk10.bold("\n MCP Servers\n"));
|
|
2581
|
+
console.log(` ${"Name".padEnd(24)} ${"Type".padEnd(8)} ${"Status".padEnd(12)} ${"Source".padEnd(20)} ${"Command/URL"}`);
|
|
2582
|
+
console.log(` ${"\u2500".repeat(24)} ${"\u2500".repeat(8)} ${"\u2500".repeat(12)} ${"\u2500".repeat(20)} ${"\u2500".repeat(30)}`);
|
|
2583
|
+
for (const s of servers) {
|
|
2584
|
+
const endpoint = s.command ? `${s.command}${s.args?.length ? " " + s.args.join(" ") : ""}` : s.url ?? "";
|
|
2585
|
+
const truncEndpoint = endpoint.length > 50 ? endpoint.slice(0, 47) + "..." : endpoint;
|
|
2586
|
+
console.log(
|
|
2587
|
+
` ${s.name.padEnd(24)} ${s.type.padEnd(8)} ${statusColor(s.status).padEnd(12 + 10)} ${chalk10.gray(s.source.padEnd(20))} ${chalk10.gray(truncEndpoint)}`
|
|
2588
|
+
);
|
|
2589
|
+
}
|
|
2590
|
+
console.log();
|
|
2591
|
+
}
|
|
2592
|
+
async function mcpStatus(name) {
|
|
2593
|
+
const servers = findMcpConfigs();
|
|
2594
|
+
const server = servers.find((s) => s.name === name);
|
|
2595
|
+
if (!server) {
|
|
2596
|
+
console.log(chalk10.red(`
|
|
2597
|
+
MCP server "${name}" not found.`));
|
|
2598
|
+
const available = servers.map((s) => s.name).join(", ");
|
|
2599
|
+
if (available) {
|
|
2600
|
+
console.log(chalk10.gray(` Available: ${available}
|
|
2601
|
+
`));
|
|
2602
|
+
} else {
|
|
2603
|
+
console.log(chalk10.gray(" No MCP servers configured.\n"));
|
|
2604
|
+
}
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
console.log(chalk10.bold(`
|
|
2608
|
+
MCP Server: ${server.name}
|
|
2609
|
+
`));
|
|
2610
|
+
console.log(` Status: ${statusColor(server.status)}`);
|
|
2611
|
+
console.log(` Type: ${server.type}`);
|
|
2612
|
+
console.log(` Source: ${chalk10.gray(server.source)}`);
|
|
2613
|
+
if (server.command) {
|
|
2614
|
+
console.log(` Command: ${server.command}`);
|
|
2615
|
+
if (server.args?.length) {
|
|
2616
|
+
console.log(` Args: ${server.args.join(" ")}`);
|
|
2617
|
+
}
|
|
2618
|
+
}
|
|
2619
|
+
if (server.url) {
|
|
2620
|
+
console.log(` URL: ${server.url}`);
|
|
2621
|
+
}
|
|
2622
|
+
if (server.env && Object.keys(server.env).length > 0) {
|
|
2623
|
+
console.log(` Env: ${Object.keys(server.env).join(", ")}`);
|
|
2624
|
+
}
|
|
2625
|
+
console.log();
|
|
2626
|
+
}
|
|
2043
2627
|
|
|
2044
2628
|
// src/index.ts
|
|
2045
2629
|
init_server();
|
|
2046
2630
|
init_openclaw();
|
|
2047
2631
|
|
|
2048
2632
|
// src/commands/telemetry.ts
|
|
2049
|
-
import
|
|
2633
|
+
import chalk11 from "chalk";
|
|
2050
2634
|
function telemetryOn() {
|
|
2051
2635
|
setOptOut(false);
|
|
2052
|
-
console.log(
|
|
2636
|
+
console.log(chalk11.green("\u2713 Telemetry enabled. Thanks for helping improve OpenClaw!"));
|
|
2053
2637
|
}
|
|
2054
2638
|
function telemetryOff() {
|
|
2055
2639
|
setOptOut(true);
|
|
2056
|
-
console.log(
|
|
2640
|
+
console.log(chalk11.yellow("\u2713 Telemetry disabled. Set OPENCLAW_NO_TELEMETRY=1 to suppress permanently."));
|
|
2057
2641
|
}
|
|
2058
2642
|
function telemetryStatus() {
|
|
2059
2643
|
const { optOut, clientId } = getTelemetryStatus();
|
|
2060
|
-
const status = optOut ?
|
|
2644
|
+
const status = optOut ? chalk11.red("disabled") : chalk11.green("enabled");
|
|
2061
2645
|
console.log(`Telemetry: ${status}`);
|
|
2062
|
-
console.log(`Client ID: ${
|
|
2646
|
+
console.log(`Client ID: ${chalk11.dim(clientId)}`);
|
|
2063
2647
|
console.log();
|
|
2064
|
-
console.log(
|
|
2065
|
-
console.log(
|
|
2648
|
+
console.log(chalk11.dim("Toggle: openclaw telemetry on/off"));
|
|
2649
|
+
console.log(chalk11.dim("Env: OPENCLAW_NO_TELEMETRY=1"));
|
|
2066
2650
|
}
|
|
2067
2651
|
|
|
2068
2652
|
// src/commands/remote.ts
|
|
2069
2653
|
init_config();
|
|
2070
|
-
import
|
|
2071
|
-
import { readFileSync as
|
|
2072
|
-
import { join as
|
|
2654
|
+
import chalk12 from "chalk";
|
|
2655
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, existsSync as existsSync15, mkdirSync as mkdirSync3 } from "fs";
|
|
2656
|
+
import { join as join13 } from "path";
|
|
2073
2657
|
import { randomUUID as randomUUID2, randomBytes, createHash as createHash2 } from "crypto";
|
|
2074
2658
|
import { createServer as createServer2 } from "http";
|
|
2075
2659
|
import { exec as exec3 } from "child_process";
|
|
@@ -2087,11 +2671,11 @@ async function proxyFetch(url, init) {
|
|
|
2087
2671
|
return fetch(url, init);
|
|
2088
2672
|
}
|
|
2089
2673
|
var REMOTE_API_URL = "https://api.openclaw-cli.app";
|
|
2090
|
-
var REMOTE_CONFIG_FILE =
|
|
2674
|
+
var REMOTE_CONFIG_FILE = join13(DOCTOR_HOME, "remote.json");
|
|
2091
2675
|
function loadRemoteConfig() {
|
|
2092
2676
|
try {
|
|
2093
|
-
if (
|
|
2094
|
-
return JSON.parse(
|
|
2677
|
+
if (existsSync15(REMOTE_CONFIG_FILE)) {
|
|
2678
|
+
return JSON.parse(readFileSync12(REMOTE_CONFIG_FILE, "utf-8"));
|
|
2095
2679
|
}
|
|
2096
2680
|
} catch {
|
|
2097
2681
|
}
|
|
@@ -2104,9 +2688,9 @@ function loadRemoteConfig() {
|
|
|
2104
2688
|
};
|
|
2105
2689
|
}
|
|
2106
2690
|
function saveRemoteConfig(config) {
|
|
2107
|
-
const dir =
|
|
2108
|
-
if (!
|
|
2109
|
-
|
|
2691
|
+
const dir = join13(REMOTE_CONFIG_FILE, "..");
|
|
2692
|
+
if (!existsSync15(dir)) mkdirSync3(dir, { recursive: true });
|
|
2693
|
+
writeFileSync7(REMOTE_CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
2110
2694
|
}
|
|
2111
2695
|
var OAUTH_CLIENT_ID = Buffer.from(
|
|
2112
2696
|
"MjM5NDk1OTI0Nzk4LTJtZWFhaTllcjZybTR1bnN0bW4zZmRldHRqZHM2bGJjLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29t",
|
|
@@ -2196,8 +2780,8 @@ function waitForOAuthCallback(codeVerifier) {
|
|
|
2196
2780
|
}
|
|
2197
2781
|
async function remoteLogin(_options) {
|
|
2198
2782
|
const config = loadRemoteConfig();
|
|
2199
|
-
console.log(
|
|
2200
|
-
console.log(
|
|
2783
|
+
console.log(chalk12.cyan.bold("\n Remote Monitoring Login\n"));
|
|
2784
|
+
console.log(chalk12.gray(" Opening browser for Google sign-in...\n"));
|
|
2201
2785
|
const codeVerifier = generateCodeVerifier();
|
|
2202
2786
|
const codeChallenge = generateCodeChallenge(codeVerifier);
|
|
2203
2787
|
const authUrl = OAUTH_AUTH_ENDPOINT + "?" + new URLSearchParams({
|
|
@@ -2217,11 +2801,11 @@ async function remoteLogin(_options) {
|
|
|
2217
2801
|
idToken = result.idToken;
|
|
2218
2802
|
email = result.email;
|
|
2219
2803
|
} catch (err) {
|
|
2220
|
-
console.log(
|
|
2804
|
+
console.log(chalk12.red(` ${String(err)}`));
|
|
2221
2805
|
await trackCommand("remote login", false, getVersion());
|
|
2222
2806
|
return;
|
|
2223
2807
|
}
|
|
2224
|
-
console.log(
|
|
2808
|
+
console.log(chalk12.gray(" Registering this machine..."));
|
|
2225
2809
|
try {
|
|
2226
2810
|
const host = hostname();
|
|
2227
2811
|
const os = process.platform + "/" + process.arch;
|
|
@@ -2239,7 +2823,7 @@ async function remoteLogin(_options) {
|
|
|
2239
2823
|
clearTimeout(timer);
|
|
2240
2824
|
if (!res.ok) {
|
|
2241
2825
|
const err = await res.text();
|
|
2242
|
-
console.log(
|
|
2826
|
+
console.log(chalk12.red(` Registration failed: ${res.status} ${err}`));
|
|
2243
2827
|
return;
|
|
2244
2828
|
}
|
|
2245
2829
|
const data = await res.json();
|
|
@@ -2248,15 +2832,15 @@ async function remoteLogin(_options) {
|
|
|
2248
2832
|
config.enabled = true;
|
|
2249
2833
|
config.reportUrl = REMOTE_API_URL + "/v1/report";
|
|
2250
2834
|
saveRemoteConfig(config);
|
|
2251
|
-
console.log(
|
|
2835
|
+
console.log(chalk12.green.bold(`
|
|
2252
2836
|
Logged in as ${email}`));
|
|
2253
|
-
console.log(
|
|
2837
|
+
console.log(chalk12.gray(` Machine registered: ${host}`));
|
|
2254
2838
|
console.log(
|
|
2255
|
-
|
|
2839
|
+
chalk12.gray(" Remote monitoring ready. Run: openclaw-cli remote enable\n")
|
|
2256
2840
|
);
|
|
2257
2841
|
await trackCommand("remote login", true, getVersion());
|
|
2258
2842
|
} catch (err) {
|
|
2259
|
-
console.log(
|
|
2843
|
+
console.log(chalk12.red(` Error: ${err}`));
|
|
2260
2844
|
await trackCommand("remote login", false, getVersion());
|
|
2261
2845
|
}
|
|
2262
2846
|
}
|
|
@@ -2264,47 +2848,47 @@ async function remoteEnable(_options) {
|
|
|
2264
2848
|
const config = loadRemoteConfig();
|
|
2265
2849
|
if (!config.machineToken) {
|
|
2266
2850
|
console.log(
|
|
2267
|
-
|
|
2851
|
+
chalk12.red(" \u2717 Not logged in. Run: openclaw-cli remote login")
|
|
2268
2852
|
);
|
|
2269
2853
|
await trackCommand("remote enable", false, getVersion());
|
|
2270
2854
|
return;
|
|
2271
2855
|
}
|
|
2272
2856
|
config.enabled = true;
|
|
2273
2857
|
saveRemoteConfig(config);
|
|
2274
|
-
console.log(
|
|
2858
|
+
console.log(chalk12.green(" Remote reporting enabled."));
|
|
2275
2859
|
await trackCommand("remote enable", true, getVersion());
|
|
2276
2860
|
}
|
|
2277
2861
|
async function remoteDisable(_options) {
|
|
2278
2862
|
const config = loadRemoteConfig();
|
|
2279
2863
|
config.enabled = false;
|
|
2280
2864
|
saveRemoteConfig(config);
|
|
2281
|
-
console.log(
|
|
2865
|
+
console.log(chalk12.yellow(" Remote reporting disabled."));
|
|
2282
2866
|
await trackCommand("remote disable", true, getVersion());
|
|
2283
2867
|
}
|
|
2284
2868
|
async function remoteStatus(_options) {
|
|
2285
2869
|
await trackCommand("remote status", true, getVersion());
|
|
2286
2870
|
const config = loadRemoteConfig();
|
|
2287
|
-
console.log(
|
|
2871
|
+
console.log(chalk12.cyan.bold("\n Remote Monitoring Status\n"));
|
|
2288
2872
|
console.log(
|
|
2289
|
-
` Enabled: ${config.enabled ?
|
|
2873
|
+
` Enabled: ${config.enabled ? chalk12.green("yes") : chalk12.gray("no")}`
|
|
2290
2874
|
);
|
|
2291
2875
|
console.log(
|
|
2292
|
-
` Machine ID: ${
|
|
2876
|
+
` Machine ID: ${chalk12.white(config.machineId || "(none)")}`
|
|
2293
2877
|
);
|
|
2294
2878
|
console.log(
|
|
2295
|
-
` Token: ${config.machineToken ?
|
|
2879
|
+
` Token: ${config.machineToken ? chalk12.green("configured") : chalk12.red("not set")}`
|
|
2296
2880
|
);
|
|
2297
2881
|
console.log(
|
|
2298
|
-
` Report URL: ${
|
|
2882
|
+
` Report URL: ${chalk12.gray(config.reportUrl)}`
|
|
2299
2883
|
);
|
|
2300
2884
|
console.log(
|
|
2301
|
-
` Last Report: ${config.lastReport ?
|
|
2885
|
+
` Last Report: ${config.lastReport ? chalk12.gray(config.lastReport) : chalk12.gray("never")}`
|
|
2302
2886
|
);
|
|
2303
2887
|
console.log();
|
|
2304
2888
|
}
|
|
2305
2889
|
|
|
2306
2890
|
// src/index.ts
|
|
2307
|
-
var _PKG_VER2 = true ? "0.7.
|
|
2891
|
+
var _PKG_VER2 = true ? "0.7.2" : "0.2.1";
|
|
2308
2892
|
var version = _PKG_VER2;
|
|
2309
2893
|
printFirstRunNotice();
|
|
2310
2894
|
var program = new Command();
|
|
@@ -2329,6 +2913,12 @@ var gw = program.command("gateway").description("Manage the OpenClaw gateway ser
|
|
|
2329
2913
|
addGlobalOpts(gw.command("start").description("Start the gateway")).action(gatewayStart);
|
|
2330
2914
|
addGlobalOpts(gw.command("stop").description("Stop the gateway")).action(gatewayStop);
|
|
2331
2915
|
addGlobalOpts(gw.command("restart").description("Restart the gateway")).action(gatewayRestart);
|
|
2916
|
+
addGlobalOpts(
|
|
2917
|
+
program.command("cost").description("Show token usage and cost summary per agent/model").option("--json", "Machine-readable JSON output").option("--days <n>", "Limit date range (default: 30)")
|
|
2918
|
+
).action(showCost);
|
|
2919
|
+
var mcp = program.command("mcp").description("Manage local MCP (Model Context Protocol) servers");
|
|
2920
|
+
mcp.command("list").description("List configured MCP servers and their status").action(mcpList);
|
|
2921
|
+
mcp.command("status").description("Show detailed info for an MCP server").argument("<name>", "Server name").action(mcpStatus);
|
|
2332
2922
|
var tele = program.command("telemetry").description("Manage anonymous usage telemetry");
|
|
2333
2923
|
tele.command("on").description("Enable telemetry").action(telemetryOn);
|
|
2334
2924
|
tele.command("off").description("Disable telemetry").action(telemetryOff);
|
|
@@ -2341,6 +2931,12 @@ addGlobalOpts(
|
|
|
2341
2931
|
addGlobalOpts(
|
|
2342
2932
|
mem.command("compact").description("Compact agent memory (proxies to openclaw memory compact)").option("--dry-run", "Preview without applying")
|
|
2343
2933
|
).action(memoryCompact);
|
|
2934
|
+
addGlobalOpts(
|
|
2935
|
+
mem.command("gc").description("Remove old daily memory files").option("--days <n>", "Max age in days (default: 30)").option("--force", "Skip confirmation prompt")
|
|
2936
|
+
).action(memoryGc);
|
|
2937
|
+
addGlobalOpts(
|
|
2938
|
+
mem.command("export").description("Export all memory files to a single markdown file").option("-o, --output <file>", "Output file (default: stdout)")
|
|
2939
|
+
).action(memoryExport);
|
|
2344
2940
|
var remote = program.command("remote").description("Remote monitoring \u2014 report gateway status to openclaw-cli.app");
|
|
2345
2941
|
addGlobalOpts(remote.command("login").description("Authenticate and register this machine")).action(remoteLogin);
|
|
2346
2942
|
addGlobalOpts(remote.command("enable").description("Enable remote reporting")).action(remoteEnable);
|