openclaw-service 0.6.2 → 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 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
- const plistDir = join4(homedir2(), "Library", "LaunchAgents");
164
- if (existsSync3(plistDir)) {
165
- const plists = readdirSync(plistDir).filter(
166
- (f) => f.includes("openclaw") && f.endsWith(".plist")
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 cliMatch = content.match(
174
- /<string>(\/[^<]*openclaw[^<]*\.(?:js|mjs))<\/string>/
175
- );
176
- if (nodeMatch && cliMatch) {
177
- return { nodePath: nodeMatch[1], cliBinPath: cliMatch[1] };
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.6.2" : "0.2.1";
1385
+ _PKG_VER = true ? "0.7.2" : "0.2.1";
1343
1386
  pkgVersion = _PKG_VER;
1344
1387
  }
1345
1388
  });
@@ -1370,6 +1413,11 @@ var MEASUREMENT_ID = "G-B46J8RT804";
1370
1413
  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");
1416
+ var SESSION_ID = randomUUID();
1417
+ var _version = true ? "0.7.2" : "0.0.0";
1418
+ function getVersion() {
1419
+ return _version;
1420
+ }
1373
1421
  function loadState() {
1374
1422
  if (existsSync4(TELEMETRY_FILE)) {
1375
1423
  try {
@@ -1436,6 +1484,11 @@ function printFirstRunNotice() {
1436
1484
  process.stderr.write(
1437
1485
  "\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"
1438
1486
  );
1487
+ track("app_first_run", {
1488
+ platform: "cli",
1489
+ version: getVersion(),
1490
+ os: process.platform
1491
+ });
1439
1492
  }
1440
1493
  async function track(eventName, opts) {
1441
1494
  if (isOptedOut()) return;
@@ -1448,14 +1501,18 @@ async function track(eventName, opts) {
1448
1501
  const params = {
1449
1502
  platform: opts.platform,
1450
1503
  engagement_time_msec: 1,
1504
+ session_id: SESSION_ID,
1505
+ app_version: opts.version ?? _version,
1506
+ node_version: process.version,
1507
+ os_type: opts.os ?? process.platform,
1508
+ arch: process.arch,
1451
1509
  ...opts.command !== void 0 && { command: opts.command },
1452
1510
  ...opts.success !== void 0 && { success: opts.success ? 1 : 0 },
1453
- ...opts.version !== void 0 && { app_version: opts.version },
1454
- ...opts.os !== void 0 && { os_type: opts.os },
1455
1511
  ...opts.extra
1456
1512
  };
1457
1513
  const payload = {
1458
1514
  client_id: state.client_id,
1515
+ user_id: state.client_id,
1459
1516
  non_personalized_ads: true,
1460
1517
  events: [
1461
1518
  {
@@ -1866,22 +1923,22 @@ function showLogs(options) {
1866
1923
  console.log();
1867
1924
  }
1868
1925
  function showDoctorLogs(maxLines) {
1869
- const { readdirSync: readdirSync5 } = __require("fs");
1870
- const { join: join12 } = __require("path");
1926
+ const { readdirSync: readdirSync7 } = __require("fs");
1927
+ const { join: join14 } = __require("path");
1871
1928
  if (!existsSync10(DOCTOR_LOG_DIR)) {
1872
1929
  console.log(chalk6.yellow("No doctor logs found."));
1873
1930
  return;
1874
1931
  }
1875
- const files = readdirSync5(DOCTOR_LOG_DIR).filter((f) => f.endsWith(".log")).sort().reverse();
1932
+ const files = readdirSync7(DOCTOR_LOG_DIR).filter((f) => f.endsWith(".log")).sort().reverse();
1876
1933
  if (files.length === 0) {
1877
1934
  console.log(chalk6.yellow("No doctor log files found."));
1878
1935
  return;
1879
1936
  }
1880
1937
  const latest = files[0];
1881
1938
  console.log(chalk6.blue.bold(`
1882
- ${join12(DOCTOR_LOG_DIR, latest)}
1939
+ ${join14(DOCTOR_LOG_DIR, latest)}
1883
1940
  `));
1884
- const content = readFileSync8(join12(DOCTOR_LOG_DIR, latest), "utf-8");
1941
+ const content = readFileSync8(join14(DOCTOR_LOG_DIR, latest), "utf-8");
1885
1942
  const lines = content.trim().split("\n");
1886
1943
  const tail = lines.slice(-maxLines);
1887
1944
  for (const line of tail) {
@@ -1906,8 +1963,15 @@ init_process_manager();
1906
1963
  init_logger();
1907
1964
  import chalk7 from "chalk";
1908
1965
  import { writeFileSync as writeFileSync5, unlinkSync as unlinkSync2 } from "fs";
1909
- var _VER = true ? "0.6.2" : void 0;
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;
1910
1973
  async function gatewayStart(options) {
1974
+ showPlatformNote();
1911
1975
  const config = loadConfig(options.config);
1912
1976
  initLogger();
1913
1977
  ensureDoctorHome();
@@ -1929,6 +1993,7 @@ async function gatewayStart(options) {
1929
1993
  }
1930
1994
  }
1931
1995
  async function gatewayStop(options) {
1996
+ showPlatformNote();
1932
1997
  const config = loadConfig(options.config);
1933
1998
  initLogger();
1934
1999
  ensureDoctorHome();
@@ -1948,6 +2013,7 @@ async function gatewayStop(options) {
1948
2013
  }
1949
2014
  }
1950
2015
  async function gatewayRestart(options) {
2016
+ showPlatformNote();
1951
2017
  const config = loadConfig(options.config);
1952
2018
  initLogger();
1953
2019
  ensureDoctorHome();
@@ -1973,12 +2039,25 @@ async function gatewayRestart(options) {
1973
2039
  init_config();
1974
2040
  init_openclaw();
1975
2041
  import chalk8 from "chalk";
1976
- import { existsSync as existsSync12, statSync as statSync3 } from "fs";
1977
- 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";
1978
2044
  import { homedir as homedir5 } from "os";
2045
+ import { createInterface } from "readline";
1979
2046
  function expandHome2(p) {
1980
2047
  return p.startsWith("~/") ? join10(homedir5(), p.slice(2)) : p;
1981
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
+ }
1982
2061
  async function memoryStatus(options) {
1983
2062
  const config = loadConfig(options.config);
1984
2063
  const info = detectOpenClaw(options.profile ?? config.openclawProfile);
@@ -2003,11 +2082,54 @@ async function memorySearch(query, options) {
2003
2082
  console.log(chalk8.bold(`
2004
2083
  Searching memory: "${query}"
2005
2084
  `));
2006
- const output = await runOpenClawCmd(info, `memory search "${query}"`);
2007
- if (output) {
2008
- console.log(output);
2009
- } else {
2010
- console.log(chalk8.yellow(" No results or openclaw memory search unavailable"));
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
+ }
2011
2133
  }
2012
2134
  console.log();
2013
2135
  }
@@ -2026,36 +2148,512 @@ async function memoryCompact(options) {
2026
2148
  }
2027
2149
  console.log();
2028
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
+ }
2029
2627
 
2030
2628
  // src/index.ts
2031
2629
  init_server();
2032
2630
  init_openclaw();
2033
2631
 
2034
2632
  // src/commands/telemetry.ts
2035
- import chalk9 from "chalk";
2633
+ import chalk11 from "chalk";
2036
2634
  function telemetryOn() {
2037
2635
  setOptOut(false);
2038
- console.log(chalk9.green("\u2713 Telemetry enabled. Thanks for helping improve OpenClaw!"));
2636
+ console.log(chalk11.green("\u2713 Telemetry enabled. Thanks for helping improve OpenClaw!"));
2039
2637
  }
2040
2638
  function telemetryOff() {
2041
2639
  setOptOut(true);
2042
- console.log(chalk9.yellow("\u2713 Telemetry disabled. Set OPENCLAW_NO_TELEMETRY=1 to suppress permanently."));
2640
+ console.log(chalk11.yellow("\u2713 Telemetry disabled. Set OPENCLAW_NO_TELEMETRY=1 to suppress permanently."));
2043
2641
  }
2044
2642
  function telemetryStatus() {
2045
2643
  const { optOut, clientId } = getTelemetryStatus();
2046
- const status = optOut ? chalk9.red("disabled") : chalk9.green("enabled");
2644
+ const status = optOut ? chalk11.red("disabled") : chalk11.green("enabled");
2047
2645
  console.log(`Telemetry: ${status}`);
2048
- console.log(`Client ID: ${chalk9.dim(clientId)}`);
2646
+ console.log(`Client ID: ${chalk11.dim(clientId)}`);
2049
2647
  console.log();
2050
- console.log(chalk9.dim("Toggle: openclaw telemetry on/off"));
2051
- console.log(chalk9.dim("Env: OPENCLAW_NO_TELEMETRY=1"));
2648
+ console.log(chalk11.dim("Toggle: openclaw telemetry on/off"));
2649
+ console.log(chalk11.dim("Env: OPENCLAW_NO_TELEMETRY=1"));
2052
2650
  }
2053
2651
 
2054
2652
  // src/commands/remote.ts
2055
2653
  init_config();
2056
- import chalk10 from "chalk";
2057
- import { readFileSync as readFileSync10, writeFileSync as writeFileSync6, existsSync as existsSync13, mkdirSync as mkdirSync3 } from "fs";
2058
- import { join as join11 } from "path";
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";
2059
2657
  import { randomUUID as randomUUID2, randomBytes, createHash as createHash2 } from "crypto";
2060
2658
  import { createServer as createServer2 } from "http";
2061
2659
  import { exec as exec3 } from "child_process";
@@ -2073,11 +2671,11 @@ async function proxyFetch(url, init) {
2073
2671
  return fetch(url, init);
2074
2672
  }
2075
2673
  var REMOTE_API_URL = "https://api.openclaw-cli.app";
2076
- var REMOTE_CONFIG_FILE = join11(DOCTOR_HOME, "remote.json");
2674
+ var REMOTE_CONFIG_FILE = join13(DOCTOR_HOME, "remote.json");
2077
2675
  function loadRemoteConfig() {
2078
2676
  try {
2079
- if (existsSync13(REMOTE_CONFIG_FILE)) {
2080
- return JSON.parse(readFileSync10(REMOTE_CONFIG_FILE, "utf-8"));
2677
+ if (existsSync15(REMOTE_CONFIG_FILE)) {
2678
+ return JSON.parse(readFileSync12(REMOTE_CONFIG_FILE, "utf-8"));
2081
2679
  }
2082
2680
  } catch {
2083
2681
  }
@@ -2090,9 +2688,9 @@ function loadRemoteConfig() {
2090
2688
  };
2091
2689
  }
2092
2690
  function saveRemoteConfig(config) {
2093
- const dir = join11(REMOTE_CONFIG_FILE, "..");
2094
- if (!existsSync13(dir)) mkdirSync3(dir, { recursive: true });
2095
- writeFileSync6(REMOTE_CONFIG_FILE, JSON.stringify(config, null, 2));
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));
2096
2694
  }
2097
2695
  var OAUTH_CLIENT_ID = Buffer.from(
2098
2696
  "MjM5NDk1OTI0Nzk4LTJtZWFhaTllcjZybTR1bnN0bW4zZmRldHRqZHM2bGJjLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29t",
@@ -2182,8 +2780,8 @@ function waitForOAuthCallback(codeVerifier) {
2182
2780
  }
2183
2781
  async function remoteLogin(_options) {
2184
2782
  const config = loadRemoteConfig();
2185
- console.log(chalk10.cyan.bold("\n Remote Monitoring Login\n"));
2186
- console.log(chalk10.gray(" Opening browser for Google sign-in...\n"));
2783
+ console.log(chalk12.cyan.bold("\n Remote Monitoring Login\n"));
2784
+ console.log(chalk12.gray(" Opening browser for Google sign-in...\n"));
2187
2785
  const codeVerifier = generateCodeVerifier();
2188
2786
  const codeChallenge = generateCodeChallenge(codeVerifier);
2189
2787
  const authUrl = OAUTH_AUTH_ENDPOINT + "?" + new URLSearchParams({
@@ -2203,10 +2801,11 @@ async function remoteLogin(_options) {
2203
2801
  idToken = result.idToken;
2204
2802
  email = result.email;
2205
2803
  } catch (err) {
2206
- console.log(chalk10.red(` ${String(err)}`));
2804
+ console.log(chalk12.red(` ${String(err)}`));
2805
+ await trackCommand("remote login", false, getVersion());
2207
2806
  return;
2208
2807
  }
2209
- console.log(chalk10.gray(" Registering this machine..."));
2808
+ console.log(chalk12.gray(" Registering this machine..."));
2210
2809
  try {
2211
2810
  const host = hostname();
2212
2811
  const os = process.platform + "/" + process.arch;
@@ -2224,7 +2823,7 @@ async function remoteLogin(_options) {
2224
2823
  clearTimeout(timer);
2225
2824
  if (!res.ok) {
2226
2825
  const err = await res.text();
2227
- console.log(chalk10.red(` Registration failed: ${res.status} ${err}`));
2826
+ console.log(chalk12.red(` Registration failed: ${res.status} ${err}`));
2228
2827
  return;
2229
2828
  }
2230
2829
  const data = await res.json();
@@ -2233,57 +2832,63 @@ async function remoteLogin(_options) {
2233
2832
  config.enabled = true;
2234
2833
  config.reportUrl = REMOTE_API_URL + "/v1/report";
2235
2834
  saveRemoteConfig(config);
2236
- console.log(chalk10.green.bold(`
2835
+ console.log(chalk12.green.bold(`
2237
2836
  Logged in as ${email}`));
2238
- console.log(chalk10.gray(` Machine registered: ${host}`));
2837
+ console.log(chalk12.gray(` Machine registered: ${host}`));
2239
2838
  console.log(
2240
- chalk10.gray(" Remote monitoring ready. Run: openclaw-cli remote enable\n")
2839
+ chalk12.gray(" Remote monitoring ready. Run: openclaw-cli remote enable\n")
2241
2840
  );
2841
+ await trackCommand("remote login", true, getVersion());
2242
2842
  } catch (err) {
2243
- console.log(chalk10.red(` Error: ${err}`));
2843
+ console.log(chalk12.red(` Error: ${err}`));
2844
+ await trackCommand("remote login", false, getVersion());
2244
2845
  }
2245
2846
  }
2246
2847
  async function remoteEnable(_options) {
2247
2848
  const config = loadRemoteConfig();
2248
2849
  if (!config.machineToken) {
2249
2850
  console.log(
2250
- chalk10.red(" \u2717 Not logged in. Run: openclaw-cli remote login")
2851
+ chalk12.red(" \u2717 Not logged in. Run: openclaw-cli remote login")
2251
2852
  );
2853
+ await trackCommand("remote enable", false, getVersion());
2252
2854
  return;
2253
2855
  }
2254
2856
  config.enabled = true;
2255
2857
  saveRemoteConfig(config);
2256
- console.log(chalk10.green(" Remote reporting enabled."));
2858
+ console.log(chalk12.green(" Remote reporting enabled."));
2859
+ await trackCommand("remote enable", true, getVersion());
2257
2860
  }
2258
2861
  async function remoteDisable(_options) {
2259
2862
  const config = loadRemoteConfig();
2260
2863
  config.enabled = false;
2261
2864
  saveRemoteConfig(config);
2262
- console.log(chalk10.yellow(" Remote reporting disabled."));
2865
+ console.log(chalk12.yellow(" Remote reporting disabled."));
2866
+ await trackCommand("remote disable", true, getVersion());
2263
2867
  }
2264
2868
  async function remoteStatus(_options) {
2869
+ await trackCommand("remote status", true, getVersion());
2265
2870
  const config = loadRemoteConfig();
2266
- console.log(chalk10.cyan.bold("\n Remote Monitoring Status\n"));
2871
+ console.log(chalk12.cyan.bold("\n Remote Monitoring Status\n"));
2267
2872
  console.log(
2268
- ` Enabled: ${config.enabled ? chalk10.green("yes") : chalk10.gray("no")}`
2873
+ ` Enabled: ${config.enabled ? chalk12.green("yes") : chalk12.gray("no")}`
2269
2874
  );
2270
2875
  console.log(
2271
- ` Machine ID: ${chalk10.white(config.machineId || "(none)")}`
2876
+ ` Machine ID: ${chalk12.white(config.machineId || "(none)")}`
2272
2877
  );
2273
2878
  console.log(
2274
- ` Token: ${config.machineToken ? chalk10.green("configured") : chalk10.red("not set")}`
2879
+ ` Token: ${config.machineToken ? chalk12.green("configured") : chalk12.red("not set")}`
2275
2880
  );
2276
2881
  console.log(
2277
- ` Report URL: ${chalk10.gray(config.reportUrl)}`
2882
+ ` Report URL: ${chalk12.gray(config.reportUrl)}`
2278
2883
  );
2279
2884
  console.log(
2280
- ` Last Report: ${config.lastReport ? chalk10.gray(config.lastReport) : chalk10.gray("never")}`
2885
+ ` Last Report: ${config.lastReport ? chalk12.gray(config.lastReport) : chalk12.gray("never")}`
2281
2886
  );
2282
2887
  console.log();
2283
2888
  }
2284
2889
 
2285
2890
  // src/index.ts
2286
- var _PKG_VER2 = true ? "0.6.2" : "0.2.1";
2891
+ var _PKG_VER2 = true ? "0.7.2" : "0.2.1";
2287
2892
  var version = _PKG_VER2;
2288
2893
  printFirstRunNotice();
2289
2894
  var program = new Command();
@@ -2308,6 +2913,12 @@ var gw = program.command("gateway").description("Manage the OpenClaw gateway ser
2308
2913
  addGlobalOpts(gw.command("start").description("Start the gateway")).action(gatewayStart);
2309
2914
  addGlobalOpts(gw.command("stop").description("Stop the gateway")).action(gatewayStop);
2310
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);
2311
2922
  var tele = program.command("telemetry").description("Manage anonymous usage telemetry");
2312
2923
  tele.command("on").description("Enable telemetry").action(telemetryOn);
2313
2924
  tele.command("off").description("Disable telemetry").action(telemetryOff);
@@ -2320,6 +2931,12 @@ addGlobalOpts(
2320
2931
  addGlobalOpts(
2321
2932
  mem.command("compact").description("Compact agent memory (proxies to openclaw memory compact)").option("--dry-run", "Preview without applying")
2322
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);
2323
2940
  var remote = program.command("remote").description("Remote monitoring \u2014 report gateway status to openclaw-cli.app");
2324
2941
  addGlobalOpts(remote.command("login").description("Authenticate and register this machine")).action(remoteLogin);
2325
2942
  addGlobalOpts(remote.command("enable").description("Enable remote reporting")).action(remoteEnable);